home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / coda / part02.Z / part02 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-08  |  8.7 KB  |  405 lines

  1. /*
  2. **  Copyright 1989 BBN Systems and Technologies Corporation.
  3. **  All Rights Reserved.
  4. **  This is free software, and may be distributed under the terms of the
  5. **  GNU Public License; see the file COPYING for more details.
  6. **
  7. **  File routines for the CODA server.
  8. */
  9. #include "server.h"
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <sys/dir.h>
  13. #include <a.out.h>
  14. #ifdef    RCSID
  15. static char RCS[] =
  16.     "$Header: file.c,v 2.0 90/03/23 14:41:23 rsalz Exp $";
  17. #endif    /* RCSID */
  18.  
  19. STATIC int    RootLen;        /* Length of the root string    */
  20. STATIC int    ScanCount;        /* How much have we looked at?    */
  21.  
  22. /*
  23. **  Yet another routine to walk through a directory tree.  It is similar
  24. **  to ftw(3), but different.  It is not based on licensed code.
  25. */
  26. STATIC int
  27. FileWalk(Path, Predicate, Depth, UserData)
  28.     char        *Path;
  29.     int            (*Predicate)();
  30.     int            Depth;
  31.     char        *UserData;
  32. {
  33.     register DIR    *Dp;
  34.     register char    *p;
  35.     register int    i;
  36.     struct direct    *E;
  37.     struct stat        Sb;
  38.     long        cookie;
  39.     char        fullpath[MAXPATH];
  40.  
  41.     /* If we can't stat, pass it to the user but go no further. */
  42.     if (stat(Path, &Sb) < 0) {
  43.     (void)(*Predicate)(Path, (struct stat *)NULL, UserData);
  44.     return FW_NOFURTHER;
  45.     }
  46.  
  47.     /* Call the user's function. */
  48.     switch ((*Predicate)(Path, &Sb, UserData)) {
  49.     default:
  50.     case FW_NOFURTHER:
  51.     return FW_NOFURTHER;
  52.     case FW_EXIT:
  53.     return FW_EXIT;
  54.     case FW_PROCEED:
  55.     if ((Sb.st_mode & S_IFMT) != S_IFDIR)
  56.         return FW_PROCEED;
  57.     break;
  58.     }
  59.  
  60.     /* Open directory; and if we can't tell the user so. */
  61.     if ((Dp = opendir(Path)) == NULL)
  62.     return FW_NOFURTHER;
  63.  
  64.     /* For speed, remember where the last component starts. */
  65.     i = strlen(Path);
  66.     (void)strcpy(fullpath, Path);
  67.     p = &fullpath[i];
  68.     if (i && p[-1] != '/')
  69.     *p++ = '/';
  70.  
  71.     /* Read all entries in the directory. */
  72.     while (E = readdir(Dp)) {
  73.     if (EQ(E->d_name, ".") || EQ(E->d_name, ".."))
  74.         continue;
  75.  
  76.     /* If going too deep, remember our state and recycle. */
  77.     if (Depth <= 1) {
  78.         cookie = telldir(Dp);
  79.         (void)closedir(Dp);
  80.         Dp = NULL;
  81.     }
  82.  
  83.     /* Process the entry. */
  84.     (void)strcpy(p, E->d_name);
  85.     if (FileWalk(fullpath, Predicate, Depth - 1, UserData) == FW_EXIT) {
  86.         /* User's finished; clean up. */
  87.         if (Dp)
  88.         (void)closedir(Dp);
  89.         return FW_EXIT;
  90.     }
  91.  
  92.     /* Reopen the directory if necessary. */
  93.     if (Dp == NULL) {
  94.         if ((Dp = opendir(Path)) == NULL)
  95.         /* WTF? */
  96.         return FW_NOFURTHER;
  97.         seekdir(Dp, cookie);
  98.     }
  99.     }
  100.  
  101.     /* Clean up. */
  102.     (void)closedir(Dp);
  103.     return FW_PROCEED;
  104. }
  105.  
  106.  
  107. /*
  108. **  Do shell-style pattern matching for ?, \, [], and * characters.
  109. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  110. **  could cause a segmentation violation.
  111. **
  112. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  113. */
  114. STATIC int
  115. Star(s, p)
  116.     register char    *s;
  117.     register char    *p;
  118. {
  119.     STATIC int        Match();
  120.  
  121.     while (Match(s, p) == FALSE)
  122.     if (*++s == '\0')
  123.         return FALSE;
  124.     return TRUE;
  125. }
  126.  
  127. STATIC int
  128. Match(s, p)
  129.     register char    *s;
  130.     register char    *p;
  131. {
  132.     register int    last;
  133.     register int    matched;
  134.     register int    reverse;
  135.  
  136.     for ( ; *p; s++, p++)
  137.     switch (*p) {
  138.     case '\\':
  139.         /* Literal match with following character. */
  140.         p++;
  141.         /* FALLTHROUGH */
  142.     default:
  143.         if (*s != *p)
  144.         return FALSE;
  145.         continue;
  146.     case '?':
  147.         /* Match anything. */
  148.         if (*s == '\0')
  149.         return FALSE;
  150.         continue;
  151.     case '*':
  152.         /* Trailing star matches everything. */
  153.         return *++p ? Star(s, p) : TRUE;
  154.     case '[':
  155.         /* [^....] means inverse character class. */
  156.         if (reverse = p[1] == '^')
  157.         p++;
  158.         for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
  159.         /* This next line requires a good C compiler. */
  160.         if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  161.             matched = TRUE;
  162.         if (matched == reverse)
  163.         return FALSE;
  164.         continue;
  165.     }
  166.  
  167.     return *s == '\0';
  168. }
  169.  
  170.  
  171. /*
  172. **  Return TRUE if a file is an "a.out" file.
  173. */
  174. STATIC int
  175. IsBinaryFile(Path)
  176.     char    *Path;
  177. {
  178.     FILE    *F;
  179.     struct exec    Head;
  180.  
  181.     if ((F = fopen(Path, "r")) == NULL
  182.      || fread((char *)&Head, sizeof Head, 1, F) != 1)
  183.     return FALSE;
  184.     (void)fclose(F);
  185.     switch (Head.a_magic) {
  186.     default:
  187.     return FALSE;
  188. #ifdef    OMAGIC
  189.     case OMAGIC:
  190.     return TRUE;
  191. #endif    /* OMAGIC */
  192. #ifdef    NMAGIC
  193.     case NMAGIC:
  194.     return TRUE;
  195. #endif    /* NMAGIC */
  196. #ifdef    ZMAGIC
  197.     case ZMAGIC:
  198.     return TRUE;
  199. #endif    /* ZMAGIC */
  200.     }
  201. }
  202.  
  203.  
  204. /*
  205. **  This is the predicate for the file walker.  It gets passed the
  206. **  current EXCEPTION block, to see if the Path is something we want
  207. **  to add to our list or not.
  208. */
  209. STATIC int
  210. Adder(Path, Sb, UserData)
  211.     char        *Path;
  212.     struct stat        *Sb;
  213.     char        *UserData;
  214. {
  215.     register EXCEPTION    *E;
  216.     register STRLIST    *S;
  217.     register char    *tail;
  218.  
  219.     /* Silently skip bogus entries. */
  220.     if (Sb == NULL)
  221.     return FW_NOFURTHER;
  222.  
  223.     if (++ScanCount == SCAN_PING) {
  224.     Message("Still scanning...");
  225.     ScanCount = 0;
  226.     }
  227.  
  228.     /* Get last component. */
  229.     if (tail = strrchr(Path, '/'))
  230.     tail++;
  231.     else
  232.     tail = Path;
  233.  
  234.     switch (Sb->st_mode & S_IFMT) {
  235.     default:
  236.     /* Something we don't handle. */
  237.     return FW_PROCEED;
  238.     case S_IFDIR:
  239.     /* Look through all "directory" exceptions; if we find one for
  240.      * the client's host, go no further. */
  241.     for (E = (EXCEPTION *)UserData; E; E = E->Next)
  242.         if (E->Directory && HostIsInClass(TheHost, E->Class))
  243.         for (S = E->Value; S; S = S->Next) {
  244.             if (*S->Value == '^' && Match(Path, &S->Value[1]))
  245.             return FW_NOFURTHER;
  246.             if (*S->Value != '^' && Match(tail, S->Value))
  247.             return FW_NOFURTHER;
  248.         }
  249.     /* Make sure the user can hack on it. */
  250.     Sb->st_mode |= S_IREAD | S_IWRITE | S_IEXEC;
  251.         break;
  252.     case S_IFREG:
  253.     /* Normal file; if we don't want it, we still keep going. */
  254.     for (E = (EXCEPTION *)UserData; E; E = E->Next)
  255.         if (!E->Directory && HostIsInClass(TheHost, E->Class))
  256.         for (S = E->Value; S; S = S->Next) {
  257.             if (*S->Value == '^' && Match(Path, &S->Value[1]))
  258.             return FW_PROCEED;
  259.             if (*S->Value != '^' && Match(tail, S->Value))
  260.             return FW_PROCEED;
  261.         }
  262.     if (!AllowBinaries && IsBinaryFile(Path))
  263.         return FW_PROCEED;
  264.     break;
  265.     }
  266.  
  267.     /* Add the item, tell the Walker to keep going. */
  268.     if (strlen(Path) > RootLen
  269.      && Path[RootLen] == '/'
  270.      && strncmp(Path, TheRoot, RootLen) == 0)
  271.     Path += RootLen + 1;
  272.     AddItemToList(Path, Sb);
  273.     return FW_PROCEED;
  274. }
  275.  
  276.  
  277. /*
  278. **  Give status information on all the files in a block.
  279. */
  280. STATIC int
  281. ListFilesInBlock(B)
  282.     BLOCK        *B;
  283. {
  284.     register DIRLIST    *D;
  285.     register char    *p;
  286.     struct stat        Sb;
  287.     char        fullpath[MAXPATH];
  288.  
  289.     /* Does the host get this block? */
  290.     if (!HostIsInClass(TheHost, B->Class))
  291.     return FALSE;
  292.  
  293.     /* Loop over all directories in this block. */
  294.     for (ScanCount = 0, D = B->Directories; D; D = D->Next) {
  295.     /* Build the pathname. */
  296.     if (*D->Value == '/')
  297.         p = D->Value;
  298.     else {
  299.         (void)sprintf(fullpath, "%s/%s", TheRoot, D->Value);
  300.         p = fullpath;
  301.     }
  302.     if (!D->Directory)
  303.         (void)FileWalk(p, Adder, FASTDEPTH, (char *)D->Exceptions);
  304.     else if (stat(p, &Sb) >= 0)
  305.         /* Ignore exceptions? */
  306.         AddItemToList(D->Value, &Sb);
  307.     else
  308.         /* Silently skip bogus files. */
  309.         ;
  310.     }
  311.  
  312.     /* Done. */
  313.     return TRUE;
  314. }
  315.  
  316.  
  317. /*
  318. **  List all the files in the block.
  319. */
  320. void
  321. ListFiles(p)
  322.     char        *p;
  323. {
  324.     register BLOCK    *B;
  325.     register ITEM    *I;
  326.     register ITEM    *Iend;
  327.     char        buff[SIZE];
  328.  
  329.     ResetItem();
  330.     RootLen = strlen(TheRoot);
  331.  
  332.     if (*p) {
  333.     if ((B = FindBlock(p)) == NULL) {
  334.         Nack("No such block");
  335.         return;
  336.     }
  337.     if (!ListFilesInBlock(B)) {
  338.         Nack("Host doesn't get that block");
  339.         return;
  340.     }
  341.     }
  342.     else
  343.     /* List all blocks. */
  344.     for (B = BaseBlock.Next; B; B = B->Next)
  345.         if (!B->Excluded)
  346.         (void)ListFilesInBlock(B);
  347.  
  348.     SortItem();
  349.     for (I = BaseItem, Iend = &BaseItem[NumItem]; I < Iend; I++) {
  350.     (void)sprintf(buff, "ITEM W=%c N=%s U=%d G=%d M=%d S=%ld T=%ld",
  351.             I->Directory ? 'd' : 'f', I->Name, I->Uid,
  352.             I->Gid, I->Mode, (long)I->Size, (long)I->Time);
  353.     Data(buff);
  354.     }
  355.  
  356.     (void)sprintf(buff, "Found %d files", NumItem);
  357.     Ack(buff);
  358. }
  359.  
  360.  
  361. /*
  362. **  Send one file down the pipe.
  363. */
  364. void
  365. SendFile(Name)
  366.     char        *Name;
  367. {
  368.     register FILE    *F;
  369.     register int    C;
  370.     ITEM        *I;
  371.     char        fullpath[MAXPATH];
  372.  
  373.     /* Can client get it? */
  374.     if ((I = FindItem(Name)) == NULL) {
  375.     Nack("File not found");
  376.     return;
  377.     }
  378.  
  379.     /* Open it, dealing with relative pathnames. */
  380.     if (Name[0] == '/')
  381.     F = fopen(Name, "r");
  382.     else {
  383.     (void)sprintf(fullpath, "%s/%s", TheRoot, Name);
  384.     F = fopen(fullpath, "r");
  385.     }
  386.     if (F == NULL) {
  387.     Nack((char *)NULL);
  388.     return;
  389.     }
  390.  
  391.     /* Send it. */
  392.     Ack(Name);
  393.     while ((C = getc(F)) != EOF)
  394.     (void)putchar(C);
  395.     (void)fclose(F);
  396. #ifdef    VERBOSE_LOG
  397.     LogSentItem(I);
  398. #else
  399. # ifdef    lint
  400.     I = I;
  401. # endif    /* lint */
  402. #endif    /* VERBOSE_LOG */
  403.     Ack((char *)NULL);
  404. }
  405.