X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fextract.c;h=0e499e5d4121649cc3c468ecb4d9aeda3aba811b;hb=8c75b1387a33fdbf3cbc8ba8bfa0ab1851d30894;hp=44233b9efdddbd51f123385418cbfe5d6270a0e5;hpb=e23d123b9326881803da64b1eb1e35fc0362e993;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index 44233b9..0e499e5 100644 --- a/src/extract.c +++ b/src/extract.c @@ -110,12 +110,15 @@ struct delayed_link /* The next delayed link in the list. */ struct delayed_link *next; - /* The device, inode number and ctime of the placeholder. Use - ctime, not mtime, to make false matches less likely if some - other process removes the placeholder. */ + /* The device, inode number and birthtime of the placeholder. + birthtime.tv_nsec is negative if the birthtime is not available. + Don't use mtime as this would allow for false matches if some + other process removes the placeholder. Don't use ctime as + this would cause race conditions and other screwups, e.g., + when restoring hard-linked symlinks. */ dev_t dev; ino_t ino; - struct timespec ctime; + struct timespec birthtime; /* True if the link is symbolic. */ bool is_symlink; @@ -609,6 +612,18 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) switch (e) { case ELOOP: + + /* With open ("symlink", O_NOFOLLOW|...), POSIX says errno == ELOOP, + but some operating systems do not conform to the standard. */ +#ifdef EFTYPE + /* NetBSD uses errno == EFTYPE; see . */ + case EFTYPE: +#endif + /* FreeBSD 8.1 uses errno == EMLINK. */ + case EMLINK: + /* Tru64 5.1B uses errno == ENOTSUP. */ + case ENOTSUP: + if (! regular || old_files_option != OVERWRITE_OLD_FILES || dereference_option) break; @@ -627,9 +642,14 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) switch (old_files_option) { - case KEEP_OLD_FILES: + case SKIP_OLD_FILES: + WARNOPT (WARN_EXISTING_FILE, + (0, 0, _("%s: skipping existing file"), file_name)); return RECOVER_SKIP; + case KEEP_OLD_FILES: + return RECOVER_NO; + case KEEP_NEWER_FILES: if (file_newer_p (file_name, stp, ¤t_stat_info)) break; @@ -867,7 +887,8 @@ open_output_file (char const *file_name, int typeflag, mode_t mode, /* If O_NOFOLLOW is needed but does not work, check for a symlink separately. There's a race condition, but that cannot be avoided on hosts lacking O_NOFOLLOW. */ - if (! O_NOFOLLOW && overwriting_old_files && ! dereference_option) + if (! HAVE_WORKING_O_NOFOLLOW + && overwriting_old_files && ! dereference_option) { struct stat st; if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 @@ -978,7 +999,7 @@ extract_file (char *file_name, int typeflag) if (written > size) written = size; errno = 0; - count = full_write (fd, data_block->buffer, written); + count = blocking_write (fd, data_block->buffer, written); size -= written; set_next_block_after ((union block *) @@ -1064,7 +1085,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made) delayed_link_head = p; p->dev = st.st_dev; p->ino = st.st_ino; - p->ctime = get_stat_ctime (&st); + p->birthtime = get_stat_birthtime (&st); p->is_symlink = is_symlink; if (is_symlink) { @@ -1122,7 +1143,8 @@ extract_link (char *file_name, int typeflag) if (ds->change_dir == chdir_current && ds->dev == st1.st_dev && ds->ino == st1.st_ino - && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0) + && (timespec_cmp (ds->birthtime, get_stat_birthtime (&st1)) + == 0)) { struct string_list *p = xmalloc (offsetof (struct string_list, string) + strlen (file_name) + 1); @@ -1205,7 +1227,7 @@ static int extract_node (char *file_name, int typeflag) { bool interdir_made = false; - mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX + mode_t mode = (current_stat_info.stat.st_mode & (MODE_RWX | S_IFBLK | S_IFCHR) & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0)); while (mknodat (chdir_fd, file_name, mode, current_stat_info.stat.st_rdev) @@ -1364,7 +1386,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) default: WARNOPT (WARN_UNKNOWN_CAST, (0, 0, - _("%s: Unknown file type `%c', extracted as normal file"), + _("%s: Unknown file type '%c', extracted as normal file"), quotearg_colon (file_name), typeflag)); *fun = extract_file; } @@ -1488,7 +1510,7 @@ apply_delayed_links (void) if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0 && st.st_dev == ds->dev && st.st_ino == ds->ino - && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0) + && timespec_cmp (get_stat_birthtime (&st), ds->birthtime) == 0) { /* Unlink the placeholder, then create a hard link if possible, a symbolic link otherwise. */