X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=bd396a307d2e37b0091262cd3e73092f54ef1899;hb=b41b004638faa8b446fe37bb8b178a6be496c666;hp=d68d80656c8d76f25c117b073c9e71e9e62785e5;hpb=738fb9c2f44eee567bb60e22dc011bdfd2f362a8;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index d68d806..bd396a3 100644 --- a/src/misc.c +++ b/src/misc.c @@ -283,21 +283,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_getcwd (); + 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; @@ -831,7 +830,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 +886,7 @@ chdir_arg (char const *dir) if (! wd_count) { wd[wd_count].name = "."; + wd[wd_count].cwd = NULL; wd[wd_count].fd = AT_FDCWD; wd_count++; } @@ -903,6 +904,7 @@ chdir_arg (char const *dir) } wd[wd_count].name = dir; + wd[wd_count].cwd = NULL; wd[wd_count].fd = 0; return wd_count++; } @@ -976,6 +978,38 @@ chdir_do (int i) } } +const char * +tar_getcwd (void) +{ + static char *cwd; + namebuf_t nbuf; + int i; + + if (!cwd) + cwd = xgetcwd (); + 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); + } + return wd[chdir_current].cwd; +} + void close_diag (char const *name) { @@ -1145,6 +1179,30 @@ namebuf_name (namebuf_t buf, const char *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.