X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fextract.c;h=d826371683a62a2f4d4ca5160a0a3f49974b75c4;hb=3209329337c87a102fa12d7eb60a3df323ba56c1;hp=80f2f9ceec68d1616d311680c6537e30cb83b348;hpb=2f800ce3fb9c38360e1b6dac70ee0d8ceae72c6a;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index 80f2f9c..d826371 100644 --- a/src/extract.c +++ b/src/extract.c @@ -57,7 +57,13 @@ enum permstatus struct delayed_set_stat { struct delayed_set_stat *next; - struct stat stat_info; + dev_t dev; + ino_t ino; + mode_t mode; + uid_t uid; + gid_t gid; + struct timespec atime; + struct timespec mtime; size_t file_name_len; mode_t invert_permissions; enum permstatus permstatus; @@ -76,7 +82,7 @@ struct delayed_link /* The device, inode number and last-modified time of the placeholder. */ dev_t dev; ino_t ino; - time_t mtime; + struct timespec mtime; /* True if the link is symbolic. */ bool is_symlink; @@ -206,23 +212,23 @@ check_time (char const *file_name, struct timespec t) gettime (&now); if (timespec_cmp (now, t) < 0) { - unsigned long int ds = t.tv_sec - now.tv_sec; - int dns = t.tv_nsec - now.tv_nsec; - char dnsbuf[sizeof ".FFFFFFFFF"]; - if (dns < 0) + char buf[TIMESPEC_STRSIZE_BOUND]; + struct timespec diff; + diff.tv_sec = t.tv_sec - now.tv_sec; + diff.tv_nsec = t.tv_nsec - now.tv_nsec; + if (diff.tv_nsec < 0) { - dns += 1000000000; - ds--; + diff.tv_nsec += BILLION; + diff.tv_sec--; } - code_ns_fraction (dns, dnsbuf); - WARN ((0, 0, _("%s: time stamp %s is %lu%s s in the future"), - file_name, tartime (t, true), ds, dnsbuf)); + WARN ((0, 0, _("%s: time stamp %s is %s s in the future"), + file_name, tartime (t, true), code_timespec (diff, buf))); } } } /* Restore stat attributes (owner, group, mode and times) for - FILE_NAME, using information given in *STAT_INFO. + FILE_NAME, using information given in *ST. If CUR_INFO is nonzero, *CUR_INFO is the file's currernt status. If not restoring permissions, invert the @@ -237,7 +243,7 @@ check_time (char const *file_name, struct timespec t) static void set_stat (char const *file_name, - struct stat const *stat_info, + struct tar_stat_info const *st, struct stat const *cur_info, mode_t invert_permissions, enum permstatus permstatus, char typeflag) @@ -256,8 +262,8 @@ set_stat (char const *file_name, /* FIXME: incremental_option should set ctime too, but how? */ struct timespec ts[2]; - ts[0] = incremental_option ? get_stat_atime (stat_info) : start_time; - ts[1] = get_stat_mtime (stat_info); + ts[0] = incremental_option ? st->atime : start_time; + ts[1] = st->mtime; if (utimens (file_name, ts) != 0) utime_error (file_name); @@ -272,7 +278,7 @@ set_stat (char const *file_name, done, it is not possible anymore to change file permissions, so we have to set permissions prior to possibly giving files away. */ - set_mode (file_name, stat_info, cur_info, + set_mode (file_name, &st->stat, cur_info, invert_permissions, permstatus, typeflag); } @@ -286,48 +292,54 @@ set_stat (char const *file_name, if (typeflag == SYMTYPE) { #if HAVE_LCHOWN - if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0) + if (lchown (file_name, st->stat.st_uid, st->stat.st_gid) < 0) chown_error_details (file_name, - stat_info->st_uid, stat_info->st_gid); + st->stat.st_uid, st->stat.st_gid); #endif } else { - if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0) + if (chown (file_name, st->stat.st_uid, st->stat.st_gid) < 0) chown_error_details (file_name, - stat_info->st_uid, stat_info->st_gid); + st->stat.st_uid, st->stat.st_gid); /* On a few systems, and in particular, those allowing to give files away, changing the owner or group destroys the suid or sgid bits. So let's attempt setting these bits once more. */ - if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)) - set_mode (file_name, stat_info, 0, + if (st->stat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)) + set_mode (file_name, &st->stat, 0, invert_permissions, permstatus, typeflag); } } } /* Remember to restore stat attributes (owner, group, mode and times) - for the directory FILE_NAME, using information given in *STAT_INFO, + for the directory FILE_NAME, using information given in *ST, once we stop extracting files into that directory. If not restoring permissions, remember to invert the INVERT_PERMISSIONS bits from the file's current permissions. PERMSTATUS specifies the status of the file's permissions. */ static void -delay_set_stat (char const *file_name, struct stat const *stat_info, +delay_set_stat (char const *file_name, struct tar_stat_info const *st, mode_t invert_permissions, enum permstatus permstatus) { 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); + data->next = delayed_set_stat_head; + data->dev = st->stat.st_dev; + data->ino = st->stat.st_ino; + data->mode = st->stat.st_mode; + data->uid = st->stat.st_uid; + data->gid = st->stat.st_gid; + data->atime = st->atime; + data->mtime = st->mtime; data->file_name_len = file_name_len; - strcpy (data->file_name, file_name); data->invert_permissions = invert_permissions; data->permstatus = permstatus; data->after_links = 0; - data->stat_info = *stat_info; - data->next = delayed_set_stat_head; + strcpy (data->file_name, file_name); delayed_set_stat_head = data; } @@ -352,7 +364,13 @@ repair_delayed_set_stat (char const *dir, if (st.st_dev == dir_stat_info->st_dev && st.st_ino == dir_stat_info->st_ino) { - data->stat_info = current_stat_info.stat; + data->dev = current_stat_info.stat.st_dev; + data->ino = current_stat_info.stat.st_ino; + data->mode = current_stat_info.stat.st_mode; + data->uid = current_stat_info.stat.st_uid; + data->gid = current_stat_info.stat.st_gid; + data->atime = current_stat_info.atime; + data->mtime = current_stat_info.mtime; data->invert_permissions = (MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode)); data->permstatus = ARCHIVED_PERMSTATUS; @@ -408,7 +426,7 @@ make_directories (char *file_name) invert_permissions is zero, because repair_delayed_set_stat may need to update the struct. */ delay_set_stat (file_name, - ¤t_stat_info.stat /* ignored */, + ¤t_stat_info /* ignored */, invert_permissions, INTERDIR_PERMSTATUS); print_for_mkdir (file_name, cursor - file_name, mode); @@ -448,7 +466,7 @@ file_newer_p (const char *file_name, struct tar_stat_info *tar_stat) return errno != ENOENT; } if (!S_ISDIR (st.st_mode) - && st.st_mtime >= tar_stat->stat.st_mtime) + && timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0) { return true; } @@ -551,8 +569,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) stat_error (data->file_name); skip_this_one = 1; } - else if (! (st.st_dev == data->stat_info.st_dev - && (st.st_ino == data->stat_info.st_ino))) + else if (! (st.st_dev == data->dev && st.st_ino == data->ino)) { ERROR ((0, 0, _("%s: Directory renamed before its status could be extracted"), @@ -562,8 +579,16 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) } if (! skip_this_one) - set_stat (data->file_name, &data->stat_info, cur_info, - data->invert_permissions, data->permstatus, DIRTYPE); + { + struct tar_stat_info st; + st.stat.st_mode = data->mode; + st.stat.st_uid = data->uid; + st.stat.st_gid = data->gid; + st.atime = data->atime; + st.mtime = data->mtime; + set_stat (data->file_name, &st, cur_info, + data->invert_permissions, data->permstatus, DIRTYPE); + } delayed_set_stat_head = data->next; free (data); @@ -627,7 +652,7 @@ extract_dir (char *file_name, int typeflag) if (status == 0 || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES) - delay_set_stat (file_name, ¤t_stat_info.stat, + delay_set_stat (file_name, ¤t_stat_info, MODE_RWX & (mode ^ current_stat_info.stat.st_mode), (status == 0 ? ARCHIVED_PERMSTATUS @@ -771,7 +796,7 @@ extract_file (char *file_name, int typeflag) if (to_command_option) sys_wait_command (); else - set_stat (file_name, ¤t_stat_info.stat, 0, 0, + set_stat (file_name, ¤t_stat_info, NULL, 0, (old_files_option == OVERWRITE_OLD_FILES ? UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS), typeflag); @@ -815,7 +840,7 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made) delayed_link_head = p; p->dev = st.st_dev; p->ino = st.st_ino; - p->mtime = st.st_mtime; + p->mtime = get_stat_mtime (&st); p->is_symlink = is_symlink; if (is_symlink) { @@ -842,8 +867,8 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made) stat_error (h->file_name); else { - h->stat_info.st_dev = st.st_dev; - h->stat_info.st_ino = st.st_ino; + h->dev = st.st_dev; + h->ino = st.st_ino; } } while ((h = h->next) && ! h->after_links); @@ -879,7 +904,7 @@ extract_link (char *file_name, int typeflag) for (; ds; ds = ds->next) if (ds->dev == st1.st_dev && ds->ino == st1.st_ino - && ds->mtime == st1.st_mtime) + && timespec_cmp (ds->mtime, get_stat_mtime (&st1)) == 0) { struct string_list *p = xmalloc (offsetof (struct string_list, string) + strlen (file_name) + 1); @@ -926,7 +951,7 @@ extract_symlink (char *file_name, int typeflag) break; if (status == 0) - set_stat (file_name, ¤t_stat_info.stat, 0, 0, 0, SYMTYPE); + set_stat (file_name, ¤t_stat_info, NULL, 0, 0, SYMTYPE); else symlink_error (current_stat_info.link_name, file_name); return status; @@ -958,7 +983,8 @@ extract_node (char *file_name, int typeflag) if (status != 0) mknod_error (file_name); else - set_stat (file_name, ¤t_stat_info.stat, 0, 0, ARCHIVED_PERMSTATUS, typeflag); + set_stat (file_name, ¤t_stat_info, NULL, 0, + ARCHIVED_PERMSTATUS, typeflag); return status; } #endif @@ -975,7 +1001,7 @@ extract_fifo (char *file_name, int typeflag) break; if (status == 0) - set_stat (file_name, ¤t_stat_info.stat, NULL, 0, + set_stat (file_name, ¤t_stat_info, NULL, 0, ARCHIVED_PERMSTATUS, typeflag); else mkfifo_error (file_name); @@ -1217,7 +1243,7 @@ apply_delayed_links (void) if (lstat (source, &st) == 0 && st.st_dev == ds->dev && st.st_ino == ds->ino - && st.st_mtime == ds->mtime) + && timespec_cmp (get_stat_mtime (&st), ds->mtime) == 0) { /* Unlink the placeholder, then create a hard link if possible, a symbolic link otherwise. */ @@ -1234,10 +1260,11 @@ apply_delayed_links (void) symlink_error (ds->target, source); else { + struct tar_stat_info st1; + st1.stat.st_uid = ds->uid; + st1.stat.st_gid = ds->gid; + set_stat (source, &st1, NULL, 0, 0, SYMTYPE); valid_source = source; - st.st_uid = ds->uid; - st.st_gid = ds->gid; - set_stat (source, &st, 0, 0, 0, SYMTYPE); } } }