Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/libbb/recursive_action.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/libbb/recursive_action.c
r821 r1770 8 8 */ 9 9 10 #include <stdio.h>11 #include <string.h>12 #include <dirent.h>13 #include <sys/stat.h>14 #include <stdlib.h> /* free() */15 10 #include "libbb.h" 16 11 17 12 #undef DEBUG_RECURS_ACTION 18 19 13 20 14 /* … … 28 22 * is so stinking huge. 29 23 */ 24 25 static int true_action(const char *fileName, struct stat *statbuf, 26 void* userData, int depth) 27 { 28 return TRUE; 29 } 30 31 /* fileAction return value of 0 on any file in directory will make 32 * recursive_action() return 0, but it doesn't stop directory traversal 33 * (fileAction/dirAction will be called on each file). 34 * 35 * if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP) 36 * prevents recursion into that directory, instead 37 * recursive_action() returns 0 (if FALSE) or 1 (if SKIP). 38 * 39 * followLinks=0/1 differs mainly in handling of links to dirs. 40 * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. 41 * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. 42 */ 43 30 44 int recursive_action(const char *fileName, 31 int recurse, int followLinks, int depthFirst, 32 int (*fileAction) (const char *fileName, 33 struct stat * statbuf, 34 void* userData), 35 int (*dirAction) (const char *fileName, 36 struct stat * statbuf, 37 void* userData), 38 void* userData) 45 unsigned flags, 46 int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), 47 int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), 48 void* userData, 49 unsigned depth) 39 50 { 51 struct stat statbuf; 40 52 int status; 41 struct stat statbuf;53 DIR *dir; 42 54 struct dirent *next; 43 55 44 if (followLinks) 45 status = stat(fileName, &statbuf); 46 else 47 status = lstat(fileName, &statbuf); 56 if (!fileAction) fileAction = true_action; 57 if (!dirAction) dirAction = true_action; 48 58 59 status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ 60 if (!depth) status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; 61 status = ((flags & status) ? stat : lstat)(fileName, &statbuf); 49 62 if (status < 0) { 50 63 #ifdef DEBUG_RECURS_ACTION 51 bb_error_msg("status=%d followLinks=%d TRUE=%d", 52 status, followLinks, TRUE); 64 bb_error_msg("status=%d flags=%x", status, flags); 53 65 #endif 54 bb_perror_msg("%s", fileName); 55 return FALSE; 66 goto done_nak_warn; 56 67 } 57 68 58 if (! followLinks && (S_ISLNK(statbuf.st_mode))) { 59 if (fileAction == NULL) 60 return TRUE; 61 else 62 return fileAction(fileName, &statbuf, userData); 69 /* If S_ISLNK(m), then we know that !S_ISDIR(m). 70 * Then we can skip checking first part: if it is true, then 71 * (!dir) is also true! */ 72 if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ 73 !S_ISDIR(statbuf.st_mode) 74 ) { 75 return fileAction(fileName, &statbuf, userData, depth); 63 76 } 64 77 65 if (! recurse) { 66 if (S_ISDIR(statbuf.st_mode)) { 67 if (dirAction != NULL) 68 return (dirAction(fileName, &statbuf, userData)); 69 else 70 return TRUE; 71 } 78 /* It's a directory (or a link to one, and followLinks is set) */ 79 80 if (!(flags & ACTION_RECURSE)) { 81 return dirAction(fileName, &statbuf, userData, depth); 72 82 } 73 83 74 if (S_ISDIR(statbuf.st_mode)) { 75 DIR *dir; 84 if (!(flags & ACTION_DEPTHFIRST)) { 85 status = dirAction(fileName, &statbuf, userData, depth); 86 if (!status) 87 goto done_nak_warn; 88 if (status == SKIP) 89 return TRUE; 90 } 76 91 77 if (dirAction != NULL && ! depthFirst) { 78 status = dirAction(fileName, &statbuf, userData); 79 if (! status) { 80 bb_perror_msg("%s", fileName); 81 return FALSE; 82 } else if (status == SKIP) 83 return TRUE; 84 } 85 dir = bb_opendir(fileName); 86 if (!dir) { 87 return FALSE; 88 } 89 status = TRUE; 90 while ((next = readdir(dir)) != NULL) { 91 char *nextFile; 92 dir = opendir(fileName); 93 if (!dir) { 94 /* findutils-4.1.20 reports this */ 95 /* (i.e. it doesn't silently return with exit code 1) */ 96 /* To trigger: "find -exec rm -rf {} \;" */ 97 goto done_nak_warn; 98 } 99 status = TRUE; 100 while ((next = readdir(dir)) != NULL) { 101 char *nextFile; 92 102 93 nextFile = concat_subpath_file(fileName, next->d_name); 94 if(nextFile == NULL) 95 continue; 96 if (! recursive_action(nextFile, TRUE, followLinks, depthFirst, 97 fileAction, dirAction, userData)) { 98 status = FALSE; 99 } 100 free(nextFile); 101 } 102 closedir(dir); 103 if (dirAction != NULL && depthFirst) { 104 if (! dirAction(fileName, &statbuf, userData)) { 105 bb_perror_msg("%s", fileName); 106 return FALSE; 107 } 108 } 109 if (! status) 110 return FALSE; 111 } else { 112 if (fileAction == NULL) 113 return TRUE; 114 else 115 return fileAction(fileName, &statbuf, userData); 103 nextFile = concat_subpath_file(fileName, next->d_name); 104 if (nextFile == NULL) 105 continue; 106 /* now descend into it (NB: ACTION_RECURSE is set in flags) */ 107 if (!recursive_action(nextFile, flags, fileAction, dirAction, userData, depth+1)) 108 status = FALSE; 109 free(nextFile); 116 110 } 111 closedir(dir); 112 113 if (flags & ACTION_DEPTHFIRST) { 114 if (!dirAction(fileName, &statbuf, userData, depth)) 115 goto done_nak_warn; 116 } 117 118 if (!status) 119 return FALSE; 117 120 return TRUE; 121 122 done_nak_warn: 123 bb_perror_msg("%s", fileName); 124 return FALSE; 118 125 }
Note:
See TracChangeset
for help on using the changeset viewer.