/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* * Recursively descent the directory hierarchy rooted in DIR, * calling FUNC for each object in the hierarchy. We cannot * use ftw(), because it uses some non-ANSI functions which * will pollute ANSI namespace, while we need this function * in some ANSI functions (e.g., rename()). Thus, this function * is closely modeled on ftw(), but uses DOS directory search * functions and structures instead of opendir()/readdir()/stat(). * * Copyright (c) 1995, 1996 Eli Zaretskii * * This software may be used freely as long as this copyright notice is * left intact. There is no warranty on this software. * */ #include #include #include #include #include #include #define FA_ALL (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_LABEL|FA_DIREC|FA_ARCH) int __file_tree_walk(const char *dir, int (*func)(const char *, const struct ffblk *)) { struct ffblk ff; char searchspec[FILENAME_MAX]; char found[FILENAME_MAX], *dir_end; int e = errno; if (dir == 0 || func == 0) { errno = EFAULT; return -1; } if (*dir == '\0') { errno = ENOENT; return -1; } /* Construct the search spec for findfirst(). Treat ``d:'' as ``d:.''. */ strcpy(searchspec, dir); dir_end = searchspec + strlen(searchspec) - 1; if (*dir_end == ':') { *++dir_end = '.'; *++dir_end = '\0'; } else if (*dir_end == '/' || *dir_end == '\\') *dir_end = '\0'; else ++dir_end; strcpy(dir_end, "/*.*"); /* Prepare the buffer where the full pathname of the found files will be placed. */ strcpy(found, dir); dir_end = found + strlen(found) - 1; if (*dir_end == ':') { *++dir_end = '.'; dir_end[1] = '\0'; } if (*dir_end != '/' && *dir_end != '\\') { /* Try to preserve user's forward/backward slash style. */ *++dir_end = strchr(found, '\\') == 0 ? '/': '\\'; *++dir_end = '\0'; } else ++dir_end; if (findfirst(searchspec, &ff, FA_ALL)) return -1; do { int func_result; /* Skip `.' and `..' entries. */ if (ff.ff_name[0] == '.' && (ff.ff_name[1] == '\0' || ff.ff_name[1] == '.')) continue; /* Construct full pathname in FOUND[]. */ strcpy(dir_end, ff.ff_name); /* Invoke FUNC() on this file. */ if ((func_result = (*func)(found, &ff)) != 0) return func_result; /* If this is a directory, walk its siblings. */ if (ff.ff_attrib & 0x10) { int subwalk_result; if ((subwalk_result = __file_tree_walk(found, func)) != 0) return subwalk_result; } } while (findnext(&ff) == 0); if (errno == ENMFILE) /* normal case: tree exhausted */ { errno = e; /* restore errno from previous syscall */ return 0; } return -1; /* error; errno set by findnext() */ } #ifdef TEST #include int ff_walker(const char *path, const struct ffblk *ff) { printf("%s:\t%lu\t", path, ff->ff_fsize); if (ff->ff_attrib & 1) printf("R"); if (ff->ff_attrib & 2) printf("H"); if (ff->ff_attrib & 4) printf("S"); if (ff->ff_attrib & 8) printf("V"); if (ff->ff_attrib & 0x10) printf("D"); if (ff->ff_attrib & 0x20) printf("A"); printf("\n"); if (strcmp(ff->ff_name, "XXXXX") == 0) return 8; return 0; } int main(int argc, char *argv[]) { if (argc > 1) { char msg[80]; sprintf(msg, "file_tree_walk: %d", file_tree_walk(argv[1], ff_walker)); if (errno) perror(msg); else puts(msg); } else printf("Usage: %s dir\n", argv[0]); return 0; } #endif