home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright 1989 BBN Systems and Technologies Corporation.
- ** All Rights Reserved.
- ** This is free software, and may be distributed under the terms of the
- ** GNU Public License; see the file COPYING for more details.
- **
- ** File routines for the CODA server.
- */
- #include "server.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <a.out.h>
- #ifdef RCSID
- static char RCS[] =
- "$Header: file.c,v 2.0 90/03/23 14:41:23 rsalz Exp $";
- #endif /* RCSID */
-
- STATIC int RootLen; /* Length of the root string */
- STATIC int ScanCount; /* How much have we looked at? */
-
- /*
- ** Yet another routine to walk through a directory tree. It is similar
- ** to ftw(3), but different. It is not based on licensed code.
- */
- STATIC int
- FileWalk(Path, Predicate, Depth, UserData)
- char *Path;
- int (*Predicate)();
- int Depth;
- char *UserData;
- {
- register DIR *Dp;
- register char *p;
- register int i;
- struct direct *E;
- struct stat Sb;
- long cookie;
- char fullpath[MAXPATH];
-
- /* If we can't stat, pass it to the user but go no further. */
- if (stat(Path, &Sb) < 0) {
- (void)(*Predicate)(Path, (struct stat *)NULL, UserData);
- return FW_NOFURTHER;
- }
-
- /* Call the user's function. */
- switch ((*Predicate)(Path, &Sb, UserData)) {
- default:
- case FW_NOFURTHER:
- return FW_NOFURTHER;
- case FW_EXIT:
- return FW_EXIT;
- case FW_PROCEED:
- if ((Sb.st_mode & S_IFMT) != S_IFDIR)
- return FW_PROCEED;
- break;
- }
-
- /* Open directory; and if we can't tell the user so. */
- if ((Dp = opendir(Path)) == NULL)
- return FW_NOFURTHER;
-
- /* For speed, remember where the last component starts. */
- i = strlen(Path);
- (void)strcpy(fullpath, Path);
- p = &fullpath[i];
- if (i && p[-1] != '/')
- *p++ = '/';
-
- /* Read all entries in the directory. */
- while (E = readdir(Dp)) {
- if (EQ(E->d_name, ".") || EQ(E->d_name, ".."))
- continue;
-
- /* If going too deep, remember our state and recycle. */
- if (Depth <= 1) {
- cookie = telldir(Dp);
- (void)closedir(Dp);
- Dp = NULL;
- }
-
- /* Process the entry. */
- (void)strcpy(p, E->d_name);
- if (FileWalk(fullpath, Predicate, Depth - 1, UserData) == FW_EXIT) {
- /* User's finished; clean up. */
- if (Dp)
- (void)closedir(Dp);
- return FW_EXIT;
- }
-
- /* Reopen the directory if necessary. */
- if (Dp == NULL) {
- if ((Dp = opendir(Path)) == NULL)
- /* WTF? */
- return FW_NOFURTHER;
- seekdir(Dp, cookie);
- }
- }
-
- /* Clean up. */
- (void)closedir(Dp);
- return FW_PROCEED;
- }
-
-
- /*
- ** Do shell-style pattern matching for ?, \, [], and * characters.
- ** Might not be robust in face of malformed patterns; e.g., "foo[a-"
- ** could cause a segmentation violation.
- **
- ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
- */
- STATIC int
- Star(s, p)
- register char *s;
- register char *p;
- {
- STATIC int Match();
-
- while (Match(s, p) == FALSE)
- if (*++s == '\0')
- return FALSE;
- return TRUE;
- }
-
- STATIC int
- Match(s, p)
- register char *s;
- register char *p;
- {
- register int last;
- register int matched;
- register int reverse;
-
- for ( ; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* FALLTHROUGH */
- default:
- if (*s != *p)
- return FALSE;
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return FALSE;
- continue;
- case '*':
- /* Trailing star matches everything. */
- return *++p ? Star(s, p) : TRUE;
- case '[':
- /* [^....] means inverse character class. */
- if (reverse = p[1] == '^')
- p++;
- for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = TRUE;
- if (matched == reverse)
- return FALSE;
- continue;
- }
-
- return *s == '\0';
- }
-
-
- /*
- ** Return TRUE if a file is an "a.out" file.
- */
- STATIC int
- IsBinaryFile(Path)
- char *Path;
- {
- FILE *F;
- struct exec Head;
-
- if ((F = fopen(Path, "r")) == NULL
- || fread((char *)&Head, sizeof Head, 1, F) != 1)
- return FALSE;
- (void)fclose(F);
- switch (Head.a_magic) {
- default:
- return FALSE;
- #ifdef OMAGIC
- case OMAGIC:
- return TRUE;
- #endif /* OMAGIC */
- #ifdef NMAGIC
- case NMAGIC:
- return TRUE;
- #endif /* NMAGIC */
- #ifdef ZMAGIC
- case ZMAGIC:
- return TRUE;
- #endif /* ZMAGIC */
- }
- }
-
-
- /*
- ** This is the predicate for the file walker. It gets passed the
- ** current EXCEPTION block, to see if the Path is something we want
- ** to add to our list or not.
- */
- STATIC int
- Adder(Path, Sb, UserData)
- char *Path;
- struct stat *Sb;
- char *UserData;
- {
- register EXCEPTION *E;
- register STRLIST *S;
- register char *tail;
-
- /* Silently skip bogus entries. */
- if (Sb == NULL)
- return FW_NOFURTHER;
-
- if (++ScanCount == SCAN_PING) {
- Message("Still scanning...");
- ScanCount = 0;
- }
-
- /* Get last component. */
- if (tail = strrchr(Path, '/'))
- tail++;
- else
- tail = Path;
-
- switch (Sb->st_mode & S_IFMT) {
- default:
- /* Something we don't handle. */
- return FW_PROCEED;
- case S_IFDIR:
- /* Look through all "directory" exceptions; if we find one for
- * the client's host, go no further. */
- for (E = (EXCEPTION *)UserData; E; E = E->Next)
- if (E->Directory && HostIsInClass(TheHost, E->Class))
- for (S = E->Value; S; S = S->Next) {
- if (*S->Value == '^' && Match(Path, &S->Value[1]))
- return FW_NOFURTHER;
- if (*S->Value != '^' && Match(tail, S->Value))
- return FW_NOFURTHER;
- }
- /* Make sure the user can hack on it. */
- Sb->st_mode |= S_IREAD | S_IWRITE | S_IEXEC;
- break;
- case S_IFREG:
- /* Normal file; if we don't want it, we still keep going. */
- for (E = (EXCEPTION *)UserData; E; E = E->Next)
- if (!E->Directory && HostIsInClass(TheHost, E->Class))
- for (S = E->Value; S; S = S->Next) {
- if (*S->Value == '^' && Match(Path, &S->Value[1]))
- return FW_PROCEED;
- if (*S->Value != '^' && Match(tail, S->Value))
- return FW_PROCEED;
- }
- if (!AllowBinaries && IsBinaryFile(Path))
- return FW_PROCEED;
- break;
- }
-
- /* Add the item, tell the Walker to keep going. */
- if (strlen(Path) > RootLen
- && Path[RootLen] == '/'
- && strncmp(Path, TheRoot, RootLen) == 0)
- Path += RootLen + 1;
- AddItemToList(Path, Sb);
- return FW_PROCEED;
- }
-
-
- /*
- ** Give status information on all the files in a block.
- */
- STATIC int
- ListFilesInBlock(B)
- BLOCK *B;
- {
- register DIRLIST *D;
- register char *p;
- struct stat Sb;
- char fullpath[MAXPATH];
-
- /* Does the host get this block? */
- if (!HostIsInClass(TheHost, B->Class))
- return FALSE;
-
- /* Loop over all directories in this block. */
- for (ScanCount = 0, D = B->Directories; D; D = D->Next) {
- /* Build the pathname. */
- if (*D->Value == '/')
- p = D->Value;
- else {
- (void)sprintf(fullpath, "%s/%s", TheRoot, D->Value);
- p = fullpath;
- }
- if (!D->Directory)
- (void)FileWalk(p, Adder, FASTDEPTH, (char *)D->Exceptions);
- else if (stat(p, &Sb) >= 0)
- /* Ignore exceptions? */
- AddItemToList(D->Value, &Sb);
- else
- /* Silently skip bogus files. */
- ;
- }
-
- /* Done. */
- return TRUE;
- }
-
-
- /*
- ** List all the files in the block.
- */
- void
- ListFiles(p)
- char *p;
- {
- register BLOCK *B;
- register ITEM *I;
- register ITEM *Iend;
- char buff[SIZE];
-
- ResetItem();
- RootLen = strlen(TheRoot);
-
- if (*p) {
- if ((B = FindBlock(p)) == NULL) {
- Nack("No such block");
- return;
- }
- if (!ListFilesInBlock(B)) {
- Nack("Host doesn't get that block");
- return;
- }
- }
- else
- /* List all blocks. */
- for (B = BaseBlock.Next; B; B = B->Next)
- if (!B->Excluded)
- (void)ListFilesInBlock(B);
-
- SortItem();
- for (I = BaseItem, Iend = &BaseItem[NumItem]; I < Iend; I++) {
- (void)sprintf(buff, "ITEM W=%c N=%s U=%d G=%d M=%d S=%ld T=%ld",
- I->Directory ? 'd' : 'f', I->Name, I->Uid,
- I->Gid, I->Mode, (long)I->Size, (long)I->Time);
- Data(buff);
- }
-
- (void)sprintf(buff, "Found %d files", NumItem);
- Ack(buff);
- }
-
-
- /*
- ** Send one file down the pipe.
- */
- void
- SendFile(Name)
- char *Name;
- {
- register FILE *F;
- register int C;
- ITEM *I;
- char fullpath[MAXPATH];
-
- /* Can client get it? */
- if ((I = FindItem(Name)) == NULL) {
- Nack("File not found");
- return;
- }
-
- /* Open it, dealing with relative pathnames. */
- if (Name[0] == '/')
- F = fopen(Name, "r");
- else {
- (void)sprintf(fullpath, "%s/%s", TheRoot, Name);
- F = fopen(fullpath, "r");
- }
- if (F == NULL) {
- Nack((char *)NULL);
- return;
- }
-
- /* Send it. */
- Ack(Name);
- while ((C = getc(F)) != EOF)
- (void)putchar(C);
- (void)fclose(F);
- #ifdef VERBOSE_LOG
- LogSentItem(I);
- #else
- # ifdef lint
- I = I;
- # endif /* lint */
- #endif /* VERBOSE_LOG */
- Ack((char *)NULL);
- }
-