diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-06-28 12:24:16 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-06-28 12:24:16 +0000 |
commit | 2fe04042d2ff81380fc43a0dbf6ce4a04341e5cf (patch) | |
tree | f7a6513369d7b9790ba28e5982cf41094fcb7536 | |
parent | 5497069f7fb503ad967717086e55810fc06ef027 (diff) | |
download | cpio-2fe04042d2ff81380fc43a0dbf6ce4a04341e5cf.tar.gz cpio-2fe04042d2ff81380fc43a0dbf6ce4a04341e5cf.tar.bz2 |
(create_all_directories): Update call to make_path
(delay_set_stat,repair_delayed_set_stat)
(apply_delayed_set_stat): New functions
-rw-r--r-- | src/util.c | 103 |
1 files changed, 102 insertions, 1 deletions
@@ -618,7 +618,14 @@ create_all_directories (char *name) error (2, 0, _("virtual memory exhausted")); if (dir[0] != '.' || dir[1] != '\0') - make_path (dir, mode, 0700, -1, -1, (char *) NULL); + { + const char *fmt; + if (warn_option & CPIO_WARN_INTERDIR) + fmt = _("Creating intermediate directory `%s'"); + else + fmt = NULL; + make_path (dir, mode, -1, -1, fmt); + } free (dir); } @@ -1340,3 +1347,97 @@ cpio_safer_name_suffix (char *name, bool link_target, bool absolute_names, memmove (name, p, (size_t)(strlen (p) + 1)); } + +/* This is a simplified form of delayed set_stat used by GNU tar. + With the time, both forms will merge and pass to paxutils + + List of directories whose statuses we need to extract after we've + finished extracting their subsidiary files. If you consider each + contiguous subsequence of elements of the form [D]?[^D]*, where [D] + represents an element where AFTER_LINKS is nonzero and [^D] + represents an element where AFTER_LINKS is zero, then the head + of the subsequence has the longest name, and each non-head element + in the prefix is an ancestor (in the directory hierarchy) of the + preceding element. */ + +struct delayed_set_stat + { + struct delayed_set_stat *next; + struct cpio_file_stat stat; + mode_t invert_permissions; + }; + +static struct delayed_set_stat *delayed_set_stat_head; + +void +delay_set_stat (char const *file_name, struct stat *st, + mode_t invert_permissions) +{ + size_t file_name_len = strlen (file_name); + struct delayed_set_stat *data = + xmalloc (sizeof (struct delayed_set_stat) + file_name_len + 1); + data->next = delayed_set_stat_head; + memset (&data->stat, 0, sizeof data->stat); + stat_to_cpio (&data->stat, st); + data->stat.c_name = (char*) (data + 1); + strcpy (data->stat.c_name, file_name); + data->invert_permissions = invert_permissions; + delayed_set_stat_head = data; +} + +/* Update the delayed_set_stat info for an intermediate directory + created within the file name of DIR. The intermediate directory turned + out to be the same as this directory, e.g. due to ".." or symbolic + links. *DIR_STAT_INFO is the status of the directory. */ +void +repair_delayed_set_stat (char const *dir, + struct stat *dir_stat_info) +{ + struct delayed_set_stat *data; + for (data = delayed_set_stat_head; data; data = data->next) + { + struct stat st; + if (stat (data->stat.c_name, &st) != 0) + { + stat_error (data->stat.c_name); + return; + } + + if (st.st_dev == dir_stat_info->st_dev + && st.st_ino == dir_stat_info->st_ino) + { + stat_to_cpio (&data->stat, dir_stat_info); + data->invert_permissions = + ((dir_stat_info->st_mode ^ st.st_mode) + & MODE_RWX & ~ newdir_umask); + return; + } + } + + ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"), + quotearg_colon (dir))); +} + +void +apply_delayed_set_stat () +{ + while (delayed_set_stat_head) + { + struct delayed_set_stat *data = delayed_set_stat_head; + if (data->invert_permissions) + { + struct stat st; + if (stat (data->stat.c_name, &st) != 0) + { + stat_error (data->stat.c_name); + return; + } + data->stat.c_mode = st.st_mode ^ data->invert_permissions; + } + set_perms (-1, &data->stat); + delayed_set_stat_head = data->next; + free (data); + } +} + + |