teach find_root_device to deal with /dev/ subdirs (by "Kirill K. Smirnov"
No binary (build failed)
—
(log yok)
| @@ -504,11 +504,11 @@ static struct dnode **list_dir(const char *path) | |
| /* are we going to list the file- it may be . or .. or a hidden file */ | |
| if (entry->d_name[0] == '.') { | |
| - | if ((entry->d_name[1] == 0 || ( |
| - | entry->d_name[1] == '.' |
| - | && entry->d_name[2] == 0)) |
| - | && !(all_fmt & DISP_DOT)) |
| + | if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2])) |
| + | && !(all_fmt & DISP_DOT) |
| + | ) { |
| continue; | |
| + | } |
| if (!(all_fmt & DISP_HIDDEN)) | |
| continue; | |
| } | |
| @@ -40,7 +40,7 @@ int rm_main(int argc, char **argv) | |
| do { | |
| const char *base = bb_get_last_path_component(*argv); | |
| - | if ((base[0] == '.') && (!base[1] || ((base[1] == '.') && !base[2]))) { |
| + | if (DOT_OR_DOTDOT(base)) { |
| bb_error_msg("cannot remove '.' or '..'"); | |
| } else if (remove_file(*argv, flags) >= 0) { | |
| continue; | |
| @@ -405,6 +405,7 @@ extern char *xasprintf(const char *format, ...) __attribute__ ((format (printf, | |
| #define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1]) | |
| #define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1]) | |
| #define NOT_LONE_CHAR(s,c) ((s)[0] != (c) || (s)[1]) | |
| + | #define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) |
| /* dmalloc will redefine these to it's own implementation. It is safe | |
| * to have the prototypes here unconditionally. */ | |
| @@ -17,7 +17,7 @@ | |
| char *concat_subpath_file(const char *path, const char *f) | |
| { | |
| - | if (f && *f == '.' && (!f[1] || (f[1] == '.' && !f[2]))) |
| + | if (f && DOT_OR_DOTDOT(f)) |
| return NULL; | |
| return concat_path_file(path, f); | |
| } | |
| @@ -9,26 +9,65 @@ | |
| #include "libbb.h" | |
| - | char *find_block_device(const char *path) |
| + | /* Find block device /dev/XXX which contains specified file |
| + | * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */ |
| + | |
| + | /* Do not reallocate all this stuff on each recursion */ |
| + | enum { DEVNAME_MAX = 256 }; |
| + | struct arena { |
| + | struct stat st; |
| + | dev_t dev; |
| + | /* Was PATH_MAX, but we recurse _/dev_. We can assume |
| + | * people are not crazy enough to have mega-deep tree there */ |
| + | char devpath[DEVNAME_MAX]; |
| + | }; |
| + | |
| + | static char *find_block_device_in_dir(struct arena *ap) |
| { | |
| DIR *dir; | |
| struct dirent *entry; | |
| - | struct stat st; |
| - | dev_t dev; |
| - | char *retpath=NULL; |
| + | char *retpath = NULL; |
| + | int len, rem; |
| + | |
| + | dir = opendir(ap->devpath); |
| + | if (!dir) |
| + | return NULL; |
| - | if (stat(path, &st) || !(dir = opendir("/dev"))) |
| + | len = strlen(ap->devpath); |
| + | rem = DEVNAME_MAX-2 - len; |
| + | if (rem <= 0) |
| return NULL; | |
| - | dev = (st.st_mode & S_IFMT) == S_IFBLK ? st.st_rdev : st.st_dev; |
| + | ap->devpath[len++] = '/'; |
| + | |
| while ((entry = readdir(dir)) != NULL) { | |
| - | char devpath[PATH_MAX]; |
| - | sprintf(devpath,"/dev/%s", entry->d_name); |
| - | if (!stat(devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) { |
| - | retpath = xstrdup(devpath); |
| + | safe_strncpy(ap->devpath + len, entry->d_name, rem); |
| + | if (stat(ap->devpath, &ap->st) != 0) |
| + | continue; |
| + | if (S_ISBLK(ap->st.st_mode) && ap->st.st_rdev == ap->dev) { |
| + | retpath = xstrdup(ap->devpath); |
| break; | |
| } | |
| + | if (S_ISDIR(ap->st.st_mode)) { |
| + | /* Do not recurse for '.' and '..' */ |
| + | if (DOT_OR_DOTDOT(entry->d_name)) |
| + | continue; |
| + | retpath = find_block_device_in_dir(ap); |
| + | if (retpath) |
| + | break; |
| + | } |
| } | |
| closedir(dir); | |
| return retpath; | |
| } | |
| + | |
| + | char *find_block_device(const char *path) |
| + | { |
| + | struct arena a; |
| + | |
| + | if (stat(path, &a.st) != 0) |
| + | return NULL; |
| + | a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev; |
| + | strcpy(a.devpath, "/dev"); |
| + | return find_block_device_in_dir(&a); |
| + | } |
| @@ -26,13 +26,16 @@ char *bb_simplify_path(const char *path) | |
| if (*p == '/') { | |
| if (*s == '/') { /* skip duplicate (or initial) slash */ | |
| continue; | |
| - | } else if (*s == '.') { |
| - | if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */ |
| + | } |
| + | if (*s == '.') { |
| + | if (s[1] == '/' || !s[1]) { /* remove extra '.' */ |
| continue; | |
| - | } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) { |
| + | } |
| + | if ((s[1] == '.') && (s[2] == '/' || !s[2])) { |
| ++s; | |
| if (p > start) { | |
| - | while (*--p != '/'); /* omit previous dir */ |
| + | while (*--p != '/') /* omit previous dir */ |
| + | continue; |
| } | |
| continue; | |
| } | |
| @@ -1369,7 +1369,7 @@ static void dir_operation(int type, const char * dir_name, int var, unsigned lon | |
| while ( (de = readdir (dp) ) != NULL ) | |
| { | |
| - | if(de->d_name && *de->d_name == '.' && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))) |
| + | if(de->d_name && DOT_OR_DOTDOT(de->d_name)) |
| continue; | |
| snprintf (path, sizeof (path), "%s/%s", dir_name, de->d_name); | |
| debug_msg_logger(LOG_ERR, "%s: %s", __FUNCTION__, path); | |
| @@ -1573,7 +1573,7 @@ static void handleIncoming(void) | |
| } | |
| /* algorithm stolen from libbb bb_simplify_path(), | |
| - | but don't strdup and reducing trailing slash and protect out root */ |
| + | * but don't strdup and reducing trailing slash and protect out root */ |
| purl = test = url; | |
| do { | |
| if (*purl == '/') { | |
| @@ -1583,18 +1583,18 @@ static void handleIncoming(void) | |
| } | |
| if (*test == '.') { | |
| /* skip extra '.' */ | |
| - | if (test[1] == '/' || test[1] == 0) { |
| + | if (test[1] == '/' || !test[1]) { |
| continue; | |
| - | } else |
| + | } |
| /* '..': be careful */ | |
| - | if (test[1] == '.' && (test[2] == '/' || test[2] == 0)) { |
| + | if (test[1] == '.' && (test[2] == '/' || !test[2])) { |
| ++test; | |
| if (purl == url) { | |
| /* protect out root */ | |
| goto BAD_REQUEST; | |
| } | |
| while (*--purl != '/') /* omit previous dir */; | |
| - | continue; |
| + | continue; |
| } | |
| } | |
| } | |
| @@ -2293,7 +2293,8 @@ updatepwd(const char *dir) | |
| break; | |
| } | |
| break; | |
| - | } else if (p[1] == '\0') |
| + | } |
| + | if (p[1] == '\0') |
| break; | |
| /* fall through */ | |
| default: | |