X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=5264952e95c0b3e8fc812b8f9b698878b2d5442b;hb=d28eee6b4f16d0fb847ee57771a42062259405b8;hp=e1731447585a092bd57a3863f13c2955280805ac;hpb=cd7bdd4076ca154575bbef85eb2157e59befcfe2;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index e173144..5264952 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,11 +268,12 @@ 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) +normalize_filename (int cdidx, const char *name) { char *copy = NULL; @@ -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_getcdpath (cdidx); + 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; @@ -332,7 +333,7 @@ replace_prefix (char **pname, const char *samp, size_t slen, the range MINVAL .. -1, represent it with a string representation of the negative integer, using leading '-'. */ #if ! (INTMAX_MAX <= UINTMAX_MAX / 2) -# error "strtosysint accepts uintmax_t to represent intmax_t" +# error "sysinttostr: uintmax_t cannot represent all intmax_t values" #endif char * sysinttostr (uintmax_t value, intmax_t minval, uintmax_t maxval, @@ -361,7 +362,7 @@ sysinttostr (uintmax_t value, intmax_t minval, uintmax_t maxval, On conversion error, return 0 and set errno = EINVAL. On overflow, return an extreme value and set errno = ERANGE. */ #if ! (INTMAX_MAX <= UINTMAX_MAX) -# error "strtosysint accepts uintmax_t to represent nonnegative intmax_t" +# error "strtosysint: nonnegative intmax_t does not fit in uintmax_t" #endif intmax_t strtosysint (char const *arg, char **arglim, intmax_t minval, uintmax_t maxval) @@ -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 = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -903,6 +906,14 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) + wd[wd_count].cwd = xstrdup (wd[wd_count].name); + else + { + namebuf_t nbuf = namebuf_create (wd[wd_count - 1].cwd); + namebuf_add_dir (nbuf, wd[wd_count].name); + wd[wd_count].cwd = namebuf_finish (nbuf); + } wd[wd_count].fd = 0; return wd_count++; } @@ -976,6 +987,25 @@ chdir_do (int i) } } +const char * +tar_dirname (void) +{ + return wd[chdir_current].name; +} + +const char * +tar_getcdpath (int idx) +{ + if (!wd) + { + static char *cwd; + if (!cwd) + cwd = xgetcwd (); + return cwd; + } + return wd[idx].cwd; +} + void close_diag (char const *name) { @@ -1144,3 +1174,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; +}