aboutsummaryrefslogtreecommitdiff
path: root/descend.c
diff options
context:
space:
mode:
Diffstat (limited to 'descend.c')
-rw-r--r--descend.c124
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;
+}