diff options
Diffstat (limited to 'descend.c')
-rw-r--r-- | descend.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/descend.c b/descend.c new file mode 100644 index 000000000..9ada7b4fc --- /dev/null +++ b/descend.c @@ -0,0 +1,124 @@ +#include "internal.h" +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> + + +static int +noDots(const struct dirent * e) +{ + if ( e->d_name[0] == '.' + && (e->d_name[1] == '\0' + || (e->d_name[1] == '.' && e->d_name[2] == '\0')) ) + return 0; + else + return 1; +} + +extern int +descend( + struct FileInfo *oldInfo +,int (*function)(const struct FileInfo * i)) +{ + char pathname[1024]; + struct dirent * * names; + struct dirent * * n; + int length; + char * filename; + int status = 0; + int count; + + if ( *oldInfo->source == '\0' ) { + errno = EINVAL; + return -1; + } + + if ( oldInfo->stat.st_dev == 0 + && oldInfo->stat.st_ino == 0 + && oldInfo->stat.st_mode == 0 ) { + if ( lstat(oldInfo->source, &oldInfo->stat) != 0 ) + return -1; + oldInfo->isSymbolicLink = ((oldInfo->stat.st_mode & S_IFMT) == S_IFLNK); + + if ( oldInfo->isSymbolicLink ) + if ( stat(oldInfo->source, &oldInfo->stat) != 0 ) + memset((void *)&oldInfo->stat, 0, sizeof(oldInfo->stat)); + } + + if ( !oldInfo->processDirectoriesAfterTheirContents ) { + if ( function ) + status = (*function)(oldInfo); + if ( status == 0 ) + status = post_process(oldInfo); + } + + if ( (count = scandir(oldInfo->source, &names, noDots, alphasort)) < 0 ) + return -1; + + length = strlen(oldInfo->source); + if ( oldInfo->source[length-1] == '/' ) + length--; + + memcpy(pathname, oldInfo->source, length+1); + pathname[length] = '/'; + filename = &pathname[length+1]; + + n = names; + while ( count-- > 0 ) { + struct FileInfo i = *oldInfo; + + strcpy(filename, (*n)->d_name); + free(*n++); + + if ( lstat(pathname, &i.stat) != 0 && errno != ENOENT ) { + fprintf(stderr, "Can't stat %s: %s\n", pathname, strerror(errno)); + return -1; + } + i.isSymbolicLink = ((i.stat.st_mode & S_IFMT) == S_IFLNK); + + if ( i.isSymbolicLink ) + if ( stat(pathname, &i.stat) != 0 ) + memset((void *)&i.stat, 0, sizeof(i.stat)); + + i.source = pathname; + + if ( i.dyadic ) { + char d[1024]; + + i.destination = join_paths(d, i.destination, &i.source[i.directoryLength]); + } + else + i.destination = i.source; + + if ( !i.isSymbolicLink && (i.stat.st_mode & S_IFMT) == S_IFDIR ) + status = descend(&i, function); + else { + if ( function ) + status = (*function)(&i); + if ( status == 0 ) + status = post_process(&i); + } + + if ( !i.processDirectoriesAfterTheirContents + && status == 0 + && (i.stat.st_mode & S_IFMT) == S_IFDIR ) + descend(&i, function); + + if ( status != 0 && !i.force ) { + while ( count-- > 0 ) + free(*n++); + break; + } + } + free(names); + + if ( oldInfo->processDirectoriesAfterTheirContents ) { + if ( function ) + status = (*function)(oldInfo); + if ( status == 0 ) + status = post_process(oldInfo); + } + + return status; +} |