Avoid need to append "/." for make_directories

* src/extract.c (make_directories): New arg JUST_PARENT.
All callers changed.
* src/misc.c (struct wd.name, add_wd, chdir_arg):
Use char *, not char const *, to let make_directories
temporarily alter slashes.  All uses changed.
(chdir_do): Do not create a new name with trailing "/."
because make_directories no longer needs this.
This commit is contained in:
Paul Eggert
2026-07-29 23:12:46 -07:00
parent 4dc85c626f
commit b7704c8d98
4 changed files with 37 additions and 41 deletions
+2 -2
View File
@@ -558,7 +558,7 @@ void verify_volume (void);
extern dev_t root_device;
void extr_init (void);
int make_directories (char *file_name);
int make_directories (char *file_name, bool just_parent);
void extract_archive (void);
void extract_finish (void);
bool rename_directory (char *src, char *dst);
@@ -782,7 +782,7 @@ idx_t blocking_write (int fd, void const *buf, idx_t count);
enum { BADFD = AT_FDCWD == -1 ? -2 : -1 };
extern idx_t chdir_current;
idx_t chdir_arg (char const *dir);
idx_t chdir_arg (char *dir);
void chdir_do (idx_t dir, bool create);
struct chdir_id { int err; dev_t st_dev; ino_t st_ino; } chdir_id (void);
struct fdbase fdbase (char const *);
+29 -22
View File
@@ -770,8 +770,8 @@ fixup_delayed_set_stat (char const *src, char const *dst)
}
}
/* Ensure that FILE_NAME's parent is a directory by creating the
directory and ancestors as needed.
/* Ensure that FILE_NAME is a directory by creating it and ancestors as needed.
If JUST_PARENT do so for FILE_NAME's parent directory, not FILE_NAME itself.
Do not overwrite existing files.
Possibly temporarily modify FILE_NAME if it contains slashes,
but restore FILE_NAME before returning.
@@ -779,7 +779,7 @@ fixup_delayed_set_stat (char const *src, char const *dst)
some other process), zero if a directory is already there, and
negative (issuing a diagnostic) otherwise. */
int
make_directories (char *file_name)
make_directories (char *file_name, bool just_parent)
{
char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
char *cursor; /* points into the file name */
@@ -787,29 +787,34 @@ make_directories (char *file_name)
int parent_errno;
int result = 0;
for (cursor = cursor0; *cursor; cursor++)
for (cursor = cursor0; ; cursor++)
{
mode_t mode;
mode_t desired_mode;
int status;
if (! ISSLASH (*cursor))
continue;
/* Avoid mkdir of empty string, if leading or double '/'. */
if (cursor == cursor0 || ISSLASH (cursor[-1]))
continue;
/* Avoid mkdir where last part of file name is "." or "..". */
if (cursor[-1] == '.'
&& (cursor == cursor0 + 1 || ISSLASH (cursor[-2])
|| (cursor[-2] == '.'
&& (cursor == cursor0 + 2 || ISSLASH (cursor[-3])))))
continue;
char c = *cursor;
if (! ISSLASH (c))
{
if (c)
continue;
if (just_parent)
break;
}
/* Avoid mkdir of empty string (if leading or double slash),
or where last part of file name is "." or "..". */
if (cursor == cursor0 || ISSLASH (cursor[-1])
|| (cursor[-1] == '.'
&& (cursor == cursor0 + 1 || ISSLASH (cursor[-2])
|| (cursor[-2] == '.'
&& (cursor == cursor0 + 2 || ISSLASH (cursor[-3]))))))
{
if (c)
continue;
break;
}
*cursor = '\0'; /* truncate the name there */
desired_mode = MODE_RWX & ~ newdir_umask;
mode = desired_mode | (we_are_root ? 0 : MODE_WXUSR);
@@ -846,6 +851,8 @@ make_directories (char *file_name)
break;
}
if (!c)
break;
*cursor = c;
}
@@ -982,7 +989,7 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
case ENOENT:
/* Attempt creating missing intermediate directories. */
if (0 < make_directories (file_name))
if (0 < make_directories (file_name, true))
return RECOVER_OK;
break;
@@ -2086,7 +2093,7 @@ rename_directory (char *src, char *dst)
switch (e)
{
case ENOENT:
if (0 <= make_directories (dst))
if (0 <= make_directories (dst, true))
{
f = fdbase (dst);
if (f.fd != BADFD
+5 -16
View File
@@ -959,7 +959,7 @@ set_file_atime (int fd, int parentfd, char const *file, struct timespec atime)
struct wd
{
/* The directory's name. */
char const *name;
char *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). It is NULL if the
@@ -1020,7 +1020,7 @@ chdir_count (void)
DFD is either AT_FDWD for the initial "." entry,
or 0 meaning the file descriptor is not open yet. */
static void
add_wd (char const *dir, int dfd)
add_wd (char *dir, int dfd)
{
wd[wd_count].name = dir;
wd[wd_count].abspath = NULL;
@@ -1051,7 +1051,7 @@ ensure_wd (void)
int n_incr_min = 4;
wd = xpalloc (NULL, &wd_alloc, n_incr_min, -1, sizeof *wd);
add_wd (".", AT_FDCWD);
add_wd ((char *) ".", AT_FDCWD);
}
}
@@ -1060,7 +1060,7 @@ ensure_wd (void)
two targets to the vector. However, if DIR is "." or an equivalent,
just reuse the last item in the vector. */
idx_t
chdir_arg (char const *dir)
chdir_arg (char *dir)
{
ensure_wd ();
@@ -1124,27 +1124,16 @@ chdir_do (idx_t i, bool create)
{
if (create)
{
char *dir_with_dot;
struct open_how saved_open_searchdir_how = open_searchdir_how;
/* Don't use O_BENEATH during creation of the
directory. The one-top-level directory is
allowed to be given as an absolute path. */
open_searchdir_how.resolve = 0;
/* Append a dot. make_directories creates
directories up to and excluding the last
component of the path. So, in order to create
"a/b", we need to pass "a/b/." to it. */
{
namebuf_t nbuf = namebuf_create (curr->name);
namebuf_add_dir (nbuf, ".");
dir_with_dot = namebuf_finish (nbuf);
}
if (0 <= make_directories (dir_with_dot))
if (0 <= make_directories (curr->name, false))
/* Directory created, retry */
fd = openat (chdir_fd, curr->name,
open_searchdir_how.flags & ~O_NOFOLLOW);
open_searchdir_how = saved_open_searchdir_how;
free (dir_with_dot);
/* Either the creation or open failed */
if (fd < 0)
open_fatal (curr->name);
+1 -1
View File
@@ -875,7 +875,7 @@ static idx_t name_buffer_length; /* allocated length of name_buffer */
void
name_init (void)
{
chdir_do (chdir_arg ("."), false);
chdir_do (chdir_arg ((char *) "."), false);
name_list_adjust ();
}