X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fmisc.c;h=e92c8aa830e36fe2fca6cd25aeaf9f107d7b6bac;hp=bd396a307d2e37b0091262cd3e73092f54ef1899;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=b41b004638faa8b446fe37bb8b178a6be496c666 diff --git a/src/misc.c b/src/misc.c index bd396a3..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. */ @@ -229,11 +231,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,31 +270,36 @@ 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? */ - 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); } @@ -830,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. */ @@ -873,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++; } @@ -903,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++; } @@ -979,35 +1002,29 @@ chdir_do (int i) } const char * -tar_getcwd (void) +tar_dirname (void) { - static char *cwd; - namebuf_t nbuf; - int i; + return wd[chdir_current].name; +} - if (!cwd) - cwd = xgetcwd (); +/* 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) - return cwd; - - if (0 == chdir_current || !wd[chdir_current].cwd) { - if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) - return wd[chdir_current].name; - - 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 @@ -1196,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);