|
|
1.1 ! root 1: /* ! 2: * ftw - file tree walk ! 3: * ! 4: * int ftw (path, fn, depth) char *path; int (*fn)(); int depth; ! 5: * ! 6: * Given a path name, ftw starts from the file given by that path ! 7: * name and visits each file and directory in the tree beneath ! 8: * that file. If a single file has multiple links within the ! 9: * structure, it will be visited once for each such link. ! 10: * For each object visited, fn is called with three arguments. ! 11: * The first contains the path name of the object, the second ! 12: * contains a pointer to a stat buffer which will usually hold ! 13: * appropriate information for the object and the third will contain ! 14: * an integer value giving additional information about the ! 15: * object, as follows: ! 16: * ! 17: * FTW_F The object is a file for which stat was ! 18: * successful. It does not guarantee that the ! 19: * file can actually be read. ! 20: * ! 21: * FTW_D The object is a directory for which stat and ! 22: * open for read were both successful. ! 23: * ! 24: * FTW_DNR The object is a directory for which stat ! 25: * succeeded, but which cannot be read. Because ! 26: * the directory cannot be read, fn will not be ! 27: * called for any descendants of this directory. ! 28: * ! 29: * FTW_NS Stat failed on the object because of lack of ! 30: * appropriate permission. This indication will ! 31: * be given, for example, for each file in a directory ! 32: * with read but no execute permission. Because ! 33: * stat failed, it is not possible to determine ! 34: * whether this object is a file or a directory. ! 35: * the stat buffer passed to fn will contain garbage. ! 36: * Stat failure for any reason other than lack of ! 37: * permission will be considered an error and will ! 38: * cause ftw to stop and return -1 to its caller. ! 39: * ! 40: * If fn returns nonzero, ftw stops and returns the same value ! 41: * to its caller. If ftw gets into other trouble along the way, ! 42: * it returns -1 and leaves an indication of the cause in errno. ! 43: * ! 44: * The third argument to ftw does not limit the depth to which ! 45: * ftw will go. Rather, it limits the depth to which ftw will ! 46: * go before it starts recycling file descriptors. In general, ! 47: * it is necessary to use a file descriptor for each level of the ! 48: * tree, but they can be recycled for deep trees by saving the position, ! 49: * closing, re-opening, and seeking. It is possible to start ! 50: * recycling file descriptors by sensing when we have run out, but ! 51: * in general this will not be terribly useful if fn expects to be ! 52: * able to open files. We could also figure out how many file descriptors ! 53: * are available and guarantee a certain number to fn, but we would not ! 54: * know how many to guarantee, and we do not want to impose the extra ! 55: * overhead on a caller who knows how many are available without ! 56: * having to figure it out. ! 57: * ! 58: * It is possible for ftw to die with a memory fault in the event ! 59: * of a file system so deeply nested that the stack overflows. ! 60: */ ! 61: ! 62: #include <sys/types.h> ! 63: #include <sys/stat.h> ! 64: #include <sys/dir.h> ! 65: #include <errno.h> ! 66: #include <ftw.h> ! 67: ! 68: #define NULL 0 ! 69: ! 70: char *malloc(), *strcpy(); ! 71: long lseek(); ! 72: extern int errno; ! 73: ! 74: int ! 75: ftw (path, fn, depth) ! 76: char *path; ! 77: int (*fn)(); ! 78: int depth; ! 79: { ! 80: int rc, rl, n, fd; ! 81: char *subpath, *component; ! 82: struct stat sb; ! 83: struct direct dir; ! 84: ! 85: /* Try to get file status. If unsuccessful, errno will say why. */ ! 86: if (stat (path, &sb) < 0) ! 87: return errno == EACCES? (*fn) (path, &sb, FTW_NS): -1; ! 88: ! 89: /* ! 90: * The stat succeeded, so we know the object exists. ! 91: * If not a directory, call the user function and return. ! 92: */ ! 93: if ((sb.st_mode & S_IFMT) != S_IFDIR) ! 94: return (*fn) (path, &sb, FTW_F); ! 95: ! 96: /* ! 97: * The object was a directory. ! 98: * ! 99: * Open a file to read the directory ! 100: */ ! 101: fd = open (path, 0); ! 102: ! 103: /* ! 104: * Call the user function, telling it whether ! 105: * the directory can be read. If it can't be read ! 106: * call the user function or indicate an error, ! 107: * depending on the reason it couldn't be read. ! 108: */ ! 109: if (fd < 0) ! 110: return errno == EACCES? (*fn) (path, &sb, FTW_DNR): -1; ! 111: ! 112: /* We could read the directory. Call user function. */ ! 113: rc = (*fn) (path, &sb, FTW_D); ! 114: if (rc != 0) ! 115: return rc; ! 116: ! 117: /* Allocate a buffer to hold generated pathnames. */ ! 118: n = strlen (path); ! 119: subpath = malloc ((unsigned) (n + DIRSIZ + 2)); ! 120: if (subpath == NULL) { ! 121: (void) close (fd); ! 122: errno = ENOMEM; ! 123: return -1; ! 124: } ! 125: ! 126: /* Create a prefix to which we will append component names */ ! 127: (void) strcpy (subpath, path); ! 128: if (subpath[0] != '\0' && subpath[n - 1] != '/') ! 129: subpath[n++] = '/'; ! 130: component = &subpath[n]; ! 131: ! 132: /* ! 133: * Read the directory one component at a time. ! 134: * We must ignore "." and "..", but other than that, ! 135: * just create a path name and call self to check it out. ! 136: */ ! 137: while ((rl = iread (fd, (char *) &dir, sizeof(struct direct))) ! 138: == sizeof(struct direct)) { ! 139: if (dir.d_ino != 0 ! 140: && strcmp (dir.d_name, ".") != 0 ! 141: && strcmp (dir.d_name, "..") != 0) { ! 142: int i; ! 143: char *p, *q; ! 144: long here; ! 145: ! 146: /* Append the component name to the working path */ ! 147: p = component; ! 148: q = dir.d_name; ! 149: for (i = 0; i < DIRSIZ && *q != '\0'; i++) ! 150: *p++ = *q++; ! 151: *p = '\0'; ! 152: ! 153: /* ! 154: * If we are about to exceed our depth, ! 155: * remember where we are and close the file. ! 156: */ ! 157: if (depth <= 1) { ! 158: here = lseek (fd, 0L, 1); ! 159: if (close (fd) < 0) { ! 160: free (subpath); ! 161: return -1; ! 162: } ! 163: } ! 164: ! 165: /* ! 166: * Do a recursive call to process the file. ! 167: * (watch this, sports fans) ! 168: */ ! 169: rc = ftw (subpath, fn, depth - 1); ! 170: if (rc != 0) { ! 171: free (subpath); ! 172: if (depth > 1) ! 173: (void) close (fd); ! 174: return rc; ! 175: } ! 176: ! 177: /* ! 178: * If we closed the file, try to reopen it. ! 179: */ ! 180: if (depth <= 1) { ! 181: fd = open (path, 0); ! 182: if (fd < 0) { ! 183: free (subpath); ! 184: return -1; ! 185: } ! 186: if (lseek (fd, here, 0) < 0) { ! 187: (void) close (fd); ! 188: free (subpath); ! 189: return -1; ! 190: } ! 191: } ! 192: } ! 193: } ! 194: ! 195: /* ! 196: * We got out of the subdirectory loop. The return from the ! 197: * final iread is in rl. Clean up and then check if the final ! 198: * iread was successful. If not, give an error return. ! 199: */ ! 200: free (subpath); ! 201: if (close (fd) < 0 || rl != 0) ! 202: return -1; ! 203: return 0; ! 204: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.