X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=0424ea7cc2f9a582805a99e6463ce042cf68d626;hb=74ce228f6df956e6b7be9fd4f993bada4b7ea645;hp=b8ef6eabf1ae16e43b1fece6d948b7bf0bc65b76;hpb=e3d28d84bda24a45c239b398e7b42ccd9be2d0c2;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index b8ef6ea..0424ea7 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,37 +268,39 @@ 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; if (IS_RELATIVE_FILE_NAME (name)) { - /* Set COPY to the absolute file name if possible. + /* Set COPY to the absolute path for this name. FIXME: There should be no need to get the absolute file 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 = tar_getcwd (); - 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"))); + tar_getcdpath does not return a true "canonical" path, so + this following approach may lead to situations where the same + file or directory is processed twice under different absolute + paths without that duplication being detected. Perhaps we + should use dev+ino pairs instead of names? */ + const char *cdpath = tar_getcdpath (cdidx); + size_t copylen; + bool need_separator; + + copylen = strlen (cdpath); + need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT + && copylen == 2 && ISSLASH (cdpath[1])); + copy = xmalloc (copylen + need_separator + strlen (name) + 1); + strcpy (copy, cdpath); + copy[copylen] = DIRECTORY_SEPARATOR; + strcpy (copy + copylen + need_separator, name); } - if (! copy) + if (!copy) copy = xstrdup (name); normalize_filename_x (copy); return copy; @@ -831,7 +834,10 @@ struct wd { /* The directory's name. */ char const *name; - + /* "absolute" path representing this directory; in the contrast to + the real absolute pathname, it can contain /../ components (see + normalize_filename_x for the reason of it). */ + char *abspath; /* 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 +892,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; + wd[wd_count].abspath = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -903,6 +910,17 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + /* if the given name is an absolute path, then use that path + to represent this working directory; otherwise, construct + a path based on the previous -C option's absolute path */ + if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) + wd[wd_count].abspath = xstrdup (wd[wd_count].name); + else + { + namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath); + namebuf_add_dir (nbuf, wd[wd_count].name); + wd[wd_count].abspath = namebuf_finish (nbuf); + } wd[wd_count].fd = 0; return wd_count++; } @@ -976,19 +994,30 @@ chdir_do (int i) } } -char * -tar_getcwd (void) +const char * +tar_dirname (void) { - static char *cwd; - namebuf_t nbuf; - int i; - - if (!cwd) - cwd = xgetcwd (); - nbuf = namebuf_create (cwd); - for (i = 1; i <= chdir_current; i++) - namebuf_add_dir (nbuf, wd[i].name); - return namebuf_finish (nbuf); + return wd[chdir_current].name; +} + +/* Return the absolute path that represents the working + directory referenced by IDX. + + If wd is empty, then there were no -C options given, and + chdir_args() has never been called, so we simply return the + process's actual cwd. (Note that in this case IDX is ignored, + since it should always be 0.) */ +const char * +tar_getcdpath (int idx) +{ + if (!wd) + { + static char *cwd; + if (!cwd) + cwd = xgetcwd (); + return cwd; + } + return wd[idx].abspath; } void