X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=343d5f9ffdf3bf9e84b51c2295e4e92562ba2e6a;hb=f7077dd38b018f19d3a5c7df6accc6b07b8a2356;hp=1b78b69ea199cdc09e29a1c769eef595a4165594;hpb=20dcc4d1226a4c170b56c1f2472a66bc67fd1f1d;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index 1b78b69..343d5f9 100644 --- a/src/misc.c +++ b/src/misc.c @@ -229,11 +229,12 @@ zap_slashes (char *name) } /* Normalize FILE_NAME by removing redundant slashes and "." - components, including redundant trailing slashes. Leave ".." - alone, as it may be significant in the presence of symlinks and on - platforms where "/.." != "/". Destructive version: modifies its - argument. */ -static void + components, including redundant trailing slashes. + Leave ".." alone, as it may be significant in the presence + of symlinks and on platforms where "/.." != "/". + + Destructive version: modifies its argument. */ +void normalize_filename_x (char *file_name) { char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); @@ -267,8 +268,9 @@ normalize_filename_x (char *file_name) } /* Normalize NAME by removing redundant slashes and "." components, - including redundant trailing slashes. Return a normalized - newly-allocated copy. */ + including redundant trailing slashes. + + Return a normalized newly-allocated copy. */ char * normalize_filename (const char *name) @@ -283,21 +285,20 @@ normalize_filename (const char *name) getcwd is slow, it might fail, and it does not necessarily return a canonical name even when it succeeds. Perhaps we can use dev+ino pairs instead of names? */ - copy = xgetcwd (); - if (copy) - { - size_t copylen = strlen (copy); - bool need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT - && copylen == 2 && ISSLASH (copy[1])); - copy = xrealloc (copy, copylen + need_separator + strlen (name) + 1); - copy[copylen] = DIRECTORY_SEPARATOR; - strcpy (copy + copylen + need_separator, name); - } - else - WARN ((0, errno, _("Cannot get working directory"))); + const char *cwd = tar_getcwd (); + size_t copylen; + bool need_separator; + + copylen = strlen (cwd); + need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT + && copylen == 2 && ISSLASH (cwd[1])); + copy = xmalloc (copylen + need_separator + strlen (name) + 1); + strcpy (copy, cwd); + copy[copylen] = DIRECTORY_SEPARATOR; + strcpy (copy + copylen + need_separator, name); } - if (! copy) + if (!copy) copy = xstrdup (name); normalize_filename_x (copy); return copy; @@ -631,7 +632,7 @@ remove_any_file (const char *file_name, enum remove_option option) case RECURSIVE_REMOVE_OPTION: { - char *directory = savedir (file_name); + char *directory = tar_savedir (file_name, 0); char const *entry; size_t entrylen; @@ -831,7 +832,8 @@ struct wd { /* The directory's name. */ char const *name; - + /* Current working directory; initialized by tar_getcwd */ + char *cwd; /* If nonzero, the file descriptor of the directory, or AT_FDCWD if the working directory. If zero, the directory needs to be opened to be used. */ @@ -886,6 +888,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; + wd[wd_count].cwd = NULL; wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -903,6 +906,7 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + wd[wd_count].cwd = NULL; wd[wd_count].fd = 0; return wd_count++; } @@ -976,6 +980,46 @@ chdir_do (int i) } } +const char * +tar_dirname (void) +{ + return wd[chdir_current].name; +} + +const char * +tar_getcwd (void) +{ + static char *cwd; + namebuf_t nbuf; + int i; + + if (!cwd) + cwd = xgetcwd (); + if (!wd) + return cwd; + + if (0 == chdir_current || !wd[chdir_current].cwd) + { + if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) + { + wd[chdir_current].cwd = xstrdup (wd[chdir_current].name); + return wd[chdir_current].cwd; + } + if (!wd[0].cwd) + wd[0].cwd = cwd; + + for (i = chdir_current - 1; i > 0; i--) + if (wd[i].cwd) + break; + + nbuf = namebuf_create (wd[i].cwd); + for (i++; i <= chdir_current; i++) + namebuf_add_dir (nbuf, wd[i].name); + wd[chdir_current].cwd = namebuf_finish (nbuf); + } + return wd[chdir_current].cwd; +} + void close_diag (char const *name) { @@ -1144,3 +1188,55 @@ namebuf_name (namebuf_t buf, const char *name) strcpy (buf->buffer + buf->dir_length, name); return buf->buffer; } + +void +namebuf_add_dir (namebuf_t buf, const char *name) +{ + static char dirsep[] = { DIRECTORY_SEPARATOR, 0 }; + if (!ISSLASH (buf->buffer[buf->dir_length - 1])) + { + namebuf_name (buf, dirsep); + buf->dir_length++; + } + namebuf_name (buf, name); + buf->dir_length += strlen (name); +} + +char * +namebuf_finish (namebuf_t buf) +{ + char *res = buf->buffer; + + if (ISSLASH (buf->buffer[buf->dir_length - 1])) + buf->buffer[buf->dir_length] = 0; + free (buf); + return res; +} + +/* Return the filenames in directory NAME, relative to the chdir_fd. + If the directory does not exist, report error if MUST_EXIST is + true. + + Return NULL on errors. +*/ +char * +tar_savedir (const char *name, int must_exist) +{ + char *ret = NULL; + DIR *dir = NULL; + int fd = openat (chdir_fd, name, open_read_flags | O_DIRECTORY); + if (fd < 0) + { + if (!must_exist && errno == ENOENT) + return NULL; + open_error (name); + } + else if (! ((dir = fdopendir (fd)) + && (ret = streamsavedir (dir)))) + savedir_error (name); + + if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0) + savedir_error (name); + + return ret; +}