X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=cc2fef85a6c5781904ea9ca496c6ea26de9b1bb9;hb=29a6964af3e1baabe978ce608e0466e1250d08ab;hp=343d5f9ffdf3bf9e84b51c2295e4e92562ba2e6a;hpb=f7077dd38b018f19d3a5c7df6accc6b07b8a2356;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index 343d5f9..cc2fef8 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. */ @@ -273,27 +275,31 @@ normalize_filename_x (char *file_name) 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? */ - const char *cwd = tar_getcwd (); + 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 = NULL; + wd[wd_count].abspath = xgetcwd (); wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -905,8 +912,22 @@ chdir_arg (char const *dir) return wd_count - 1; } + + /* 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].abspath); + namebuf_add_dir (nbuf, dir); + absdir = namebuf_finish (nbuf); + } + else + absdir = 0; + wd[wd_count].name = dir; - wd[wd_count].cwd = NULL; + wd[wd_count].abspath = absdir; wd[wd_count].fd = 0; return wd_count++; } @@ -986,38 +1007,24 @@ tar_dirname (void) return wd[chdir_current].name; } -const char * -tar_getcwd (void) -{ - static char *cwd; - namebuf_t nbuf; - int i; +/* Return the absolute path that represents the working + directory referenced by IDX. - if (!cwd) - cwd = xgetcwd (); + 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) - 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); + static char *cwd; + if (!cwd) + cwd = xgetcwd (); + return cwd; } - return wd[chdir_current].cwd; + return wd[idx].abspath; } void @@ -1206,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); @@ -1232,7 +1239,7 @@ tar_savedir (const char *name, int must_exist) open_error (name); } else if (! ((dir = fdopendir (fd)) - && (ret = streamsavedir (dir)))) + && (ret = streamsavedir (dir, savedir_sort_order)))) savedir_error (name); if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0)