0,0 → 1,220 |
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
/* ftw() for DJGPP. |
* |
* Recursively descent the directory hierarchy rooted in DIR, |
* calling FUNC for each object in the hierarchy. |
* |
* Copyright (c) 1995 Eli Zaretskii <eliz@is.elta.co.il> |
* |
* This software may be used freely as long as this copyright notice is |
* left intact. There is no warranty on this software. |
* |
*/ |
|
#include <libc/stubs.h> |
#include <stdio.h> |
#include <string.h> |
#include <errno.h> |
#include <ctype.h> |
#include <sys/stat.h> |
#include <dirent.h> |
#include <io.h> |
#include <ftw.h> |
|
static int |
walk_dir(char *path, int (*func)(const char *, struct stat *, int)) |
{ |
DIR *dp; |
struct dirent *de; |
struct stat stbuf; |
int flag; |
int e = errno; |
int pathlen = strlen(path); |
|
if ((dp = opendir(path)) == 0) |
return -1; |
|
for (errno = 0; (de = readdir(dp)) != 0; errno = 0) |
{ |
int func_result; |
char lastc = de->d_name[de->d_namlen - 1]; |
|
/* Skip `.' and `..' entries. Checking the last char is enough, |
because readdir will never return a filename which ends with |
a dot. */ |
if (lastc == '.') |
continue; |
|
/* Append found name to directory path. */ |
if (pathlen + de->d_namlen + 1 > FILENAME_MAX) |
{ |
(void)closedir(dp); |
errno = ENAMETOOLONG; |
return -1; |
} |
if (path[pathlen-1] == '/' || path[pathlen-1] == '\\') |
pathlen--; |
path[pathlen] = '/'; |
strcpy(path + pathlen + 1, de->d_name); |
|
if (stat(path, &stbuf) < 0) |
flag = FTW_NS; |
else if (S_ISDIR(stbuf.st_mode)) |
flag = FTW_D; |
else if (S_ISLABEL(stbuf.st_mode)) |
flag = FTW_VL; |
else |
flag = FTW_F; |
|
/* Invoke FUNC() on this object. */ |
errno = e; |
if ((func_result = (*func)(path, &stbuf, flag)) != 0) |
{ |
(void)closedir(dp); |
return func_result; |
} |
|
/* If this is a directory, walk its siblings. */ |
if (flag == FTW_D) |
{ |
int subwalk_result; |
|
errno = e; |
if ((subwalk_result = walk_dir(path, func)) != 0) |
{ |
(void)closedir(dp); |
return subwalk_result; |
} |
} |
|
/* Erase D_NAME[] from PATH. */ |
path[pathlen] = '\0'; |
} |
|
(void)closedir(dp); |
if (errno == 0) /* normal case: this subtree exhausted */ |
{ |
errno = e;/* restore errno from previous syscall */ |
return 0; |
} |
else |
return -1; /* with whatever errno was set by readdir() */ |
} |
|
int |
ftw(const char *dir, int (*func)(const char *, struct stat *, int), |
int ignored) |
{ |
int flag; |
unsigned char pathbuf[FILENAME_MAX]; |
int dirattr; |
int len; |
int e = errno; |
|
ignored = ignored; /* pacify -Wall */ |
|
if (dir == 0 || func == 0) |
{ |
errno = EFAULT; |
return -1; |
} |
|
if (*dir == '\0') |
{ |
errno = ENOENT; |
return -1; |
} |
|
strcpy(pathbuf, dir); |
len = strlen(pathbuf); |
if (pathbuf[len-1] == ':') |
{ |
pathbuf[len++] = '.'; |
pathbuf[len] = '\0'; |
} |
|
/* Fail for non-directories. */ |
errno = 0; |
dirattr = _chmod(pathbuf, 0, 0); |
if (errno == ENOENT) |
return -1; |
else if ((dirattr & 0x10) != 0x10) |
{ |
errno = ENOTDIR; |
return -1; |
} |
else |
{ |
int func_result; |
struct stat stbuf; |
|
if (stat(pathbuf, &stbuf) < 0) |
flag = FTW_NS; |
else |
flag = FTW_D; |
errno = e; |
if ((func_result = (*func)(pathbuf, &stbuf, flag)) != 0) |
return func_result; |
|
return walk_dir(pathbuf, func); |
} |
} |
|
#ifdef TEST |
|
#include <stdlib.h> |
|
int |
ftw_walker(const char *path, struct stat *sb, int flag) |
{ |
char *base; |
|
printf("%s:\t%u\t", path, sb->st_size); |
if (S_ISLABEL(sb->st_mode)) |
printf("V"); |
if (S_ISDIR(sb->st_mode)) |
printf("D"); |
if (S_ISCHR(sb->st_mode)) |
printf("C"); |
if (sb->st_mode & S_IRUSR) |
printf("r"); |
if (sb->st_mode & S_IWUSR) |
printf("w"); |
if (sb->st_mode & S_IXUSR) |
printf("x"); |
|
if (flag == FTW_NS) |
printf(" !!no_stat!!"); |
printf("\n"); |
|
base = strrchr(path, '/'); |
if (base == 0) |
base = strrchr(path, '\\'); |
if (base == 0) |
base = strrchr(path, ':'); |
if (strcmp(base == 0 ? path : base + 1, "xxxxx") == 0) |
return 8; |
return 0; |
} |
|
int |
main(int argc, char *argv[]) |
{ |
if (argc > 1) |
{ |
char msg[80]; |
|
sprintf(msg, "file_tree_walk: %d", |
ftw(argv[1], ftw_walker, 0)); |
if (errno) |
perror(msg); |
else |
puts(msg); |
} |
else |
printf("Usage: %s dir\n", argv[0]); |
|
return 0; |
} |
|
#endif |