X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fextract.c;h=f982433d77fff9aff5e30a8f28fa62b767b63b99;hb=d30babc23b4f25be970ada2e63a50220a3672281;hp=ca25603a45b5570b284f976d02addaf32c98427c;hpb=4aa85f09e755fc827cd5ab6225f20c83cd42245d;p=debian%2Ftar diff --git a/src/extract.c b/src/extract.c index ca25603a..f982433d 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1,7 +1,7 @@ /* Extract files from a tar archive. - Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2014 Free - Software Foundation, Inc. + Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2014, + 2016 Free Software Foundation, Inc. This file is part of GNU tar. @@ -109,7 +109,7 @@ struct delayed_set_stat struct xattr_array *xattr_map; /* Length and contents of name. */ size_t file_name_len; - char file_name[1]; + char *file_name; }; static struct delayed_set_stat *delayed_set_stat_head; @@ -441,9 +441,7 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st, mode_t mode, int atflag) { size_t file_name_len = strlen (file_name); - struct delayed_set_stat *data = - xmalloc (offsetof (struct delayed_set_stat, file_name) - + file_name_len + 1); + struct delayed_set_stat *data = xmalloc (sizeof (*data)); data->next = delayed_set_stat_head; data->mode = mode; if (st) @@ -456,6 +454,7 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st, data->mtime = st->mtime; } data->file_name_len = file_name_len; + data->file_name = xstrdup (file_name); data->current_mode = current_mode; data->current_mode_mask = current_mode_mask; data->interdir = ! st; @@ -537,6 +536,56 @@ repair_delayed_set_stat (char const *dir, quotearg_colon (dir))); } +static void +free_delayed_set_stat (struct delayed_set_stat *data) +{ + free (data->file_name); + xheader_xattr_free (data->xattr_map, data->xattr_map_size); + free (data->cntx_name); + free (data->acls_a_ptr); + free (data->acls_d_ptr); + free (data); +} + +void +remove_delayed_set_stat (const char *fname) +{ + struct delayed_set_stat *data, *next, *prev = NULL; + for (data = delayed_set_stat_head; data; data = next) + { + next = data->next; + if (chdir_current == data->change_dir + && strcmp (data->file_name, fname) == 0) + { + free_delayed_set_stat (data); + if (prev) + prev->next = next; + else + delayed_set_stat_head = next; + return; + } + else + prev = data; + } +} + +static void +fixup_delayed_set_stat (char const *src, char const *dst) +{ + struct delayed_set_stat *data; + for (data = delayed_set_stat_head; data; data = data->next) + { + if (chdir_current == data->change_dir + && strcmp (data->file_name, src) == 0) + { + free (data->file_name); + data->file_name = xstrdup (dst); + data->file_name_len = strlen (dst); + return; + } + } +} + /* After a file/link/directory creation has failed, see if it's because some required directory was not present, and if so, create all required directories. Return zero if all the required @@ -846,11 +895,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) } delayed_set_stat_head = data->next; - xheader_xattr_free (data->xattr_map, data->xattr_map_size); - free (data->cntx_name); - free (data->acls_a_ptr); - free (data->acls_d_ptr); - free (data); + free_delayed_set_stat (data); } } @@ -1741,7 +1786,9 @@ extract_finish (void) bool rename_directory (char *src, char *dst) { - if (renameat (chdir_fd, src, chdir_fd, dst) != 0) + if (renameat (chdir_fd, src, chdir_fd, dst) == 0) + fixup_delayed_set_stat (src, dst); + else { int e = errno; bool interdir_made;