}
/* 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);
}
/* 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 = 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")));
+ 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;
{
/* 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. */
if (! wd_count)
{
wd[wd_count].name = ".";
+ wd[wd_count].abspath = xgetcwd ();
wd[wd_count].fd = AT_FDCWD;
wd_count++;
}
}
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++;
}
}
}
\f
+const char *
+tar_dirname (void)
+{
+ 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;
+}
+\f
void
close_diag (char const *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.