X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fmisc.c;h=e92c8aa830e36fe2fca6cd25aeaf9f107d7b6bac;hp=5264952e95c0b3e8fc812b8f9b698878b2d5442b;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=d28eee6b4f16d0fb847ee57771a42062259405b8 diff --git a/src/misc.c b/src/misc.c index 5264952..e92c8aa 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,7 +1,7 @@ /* Miscellaneous functions, not really specific to GNU tar. Copyright 1988, 1992, 1994-1997, 1999-2001, 2003-2007, 2009-2010, - 2012-2013 Free Software Foundation, Inc. + 2012-2014 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -29,6 +29,8 @@ # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 #endif +static const char *tar_getcdpath (int); + /* Handling strings. */ @@ -230,7 +232,7 @@ 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 + Leave ".." alone, as it may be significant in the presence of symlinks and on platforms where "/.." != "/". Destructive version: modifies its argument. */ @@ -279,21 +281,25 @@ normalize_filename (int cdidx, const char *name) 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? */ - const char *cwd = tar_getcdpath (cdidx); + 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 (cwd); + + if (!cdpath) + call_arg_fatal ("getcwd", "."); + copylen = strlen (cdpath); need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT - && copylen == 2 && ISSLASH (cwd[1])); + && copylen == 2 && ISSLASH (cdpath[1])); copy = xmalloc (copylen + need_separator + strlen (name) + 1); - strcpy (copy, cwd); + strcpy (copy, cdpath); copy[copylen] = DIRECTORY_SEPARATOR; strcpy (copy + copylen + need_separator, name); } @@ -832,8 +838,11 @@ struct wd { /* The directory's name. */ char const *name; - /* Current working directory; initialized by tar_getcwd */ - char *cwd; + /* "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). It is NULL if the + absolute path could not be determined. */ + 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. */ @@ -875,20 +884,18 @@ chdir_count (void) int chdir_arg (char const *dir) { + char *absdir; + if (wd_count == wd_alloc) { if (wd_alloc == 0) - { - wd_alloc = 2; - wd = xmalloc (sizeof *wd * wd_alloc); - } - else - wd = x2nrealloc (wd, &wd_alloc, sizeof *wd); + wd_alloc = 2; + wd = x2nrealloc (wd, &wd_alloc, sizeof *wd); if (! wd_count) { wd[wd_count].name = "."; - wd[wd_count].cwd = xgetcwd (); + wd[wd_count].abspath = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -905,15 +912,22 @@ chdir_arg (char const *dir) return wd_count - 1; } - wd[wd_count].name = dir; - if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) - wd[wd_count].cwd = xstrdup (wd[wd_count].name); - else + + /* If the given name is absolute, use it to represent this directory; + otherwise, construct a name based on the previous -C option. */ + if (IS_ABSOLUTE_FILE_NAME (dir)) + absdir = xstrdup (dir); + else if (wd[wd_count - 1].abspath) { - 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); + namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath); + namebuf_add_dir (nbuf, dir); + absdir = namebuf_finish (nbuf); } + else + absdir = 0; + + wd[wd_count].name = dir; + wd[wd_count].abspath = absdir; wd[wd_count].fd = 0; return wd_count++; } @@ -993,7 +1007,14 @@ tar_dirname (void) return wd[chdir_current].name; } -const char * +/* 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.) */ +static const char * tar_getcdpath (int idx) { if (!wd) @@ -1003,7 +1024,7 @@ tar_getcdpath (int idx) cwd = xgetcwd (); return cwd; } - return wd[idx].cwd; + return wd[idx].abspath; } void @@ -1192,7 +1213,7 @@ 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);