📄 extract.c
字号:
link_name = current_stat_info.link_name; if (! absolute_names_option && contains_dot_dot (link_name)) return create_placeholder_file (file_name, false, &interdir_made); do { struct stat st1, st2; int e; int status = link (link_name, file_name); e = errno; if (status == 0) { struct delayed_link *ds = delayed_link_head; if (ds && lstat (link_name, &st1) == 0) for (; ds; ds = ds->next) if (ds->dev == st1.st_dev && ds->ino == st1.st_ino && timespec_cmp (ds->mtime, get_stat_mtime (&st1)) == 0) { struct string_list *p = xmalloc (offsetof (struct string_list, string) + strlen (file_name) + 1); strcpy (p->string, file_name); p->next = ds->sources; ds->sources = p; break; } return 0; } else if ((e == EEXIST && strcmp (link_name, file_name) == 0) || (lstat (link_name, &st1) == 0 && lstat (file_name, &st2) == 0 && st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)) return 0; errno = e; } while (maybe_recoverable (file_name, &interdir_made)); if (!(incremental_option && errno == EEXIST)) { link_error (link_name, file_name); return 1; } return 0;}static intextract_symlink (char *file_name, int typeflag){#ifdef HAVE_SYMLINK int status; int interdir_made = 0; transform_member_name (¤t_stat_info.link_name, xform_symlink); if (! absolute_names_option && (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name) || contains_dot_dot (current_stat_info.link_name))) return create_placeholder_file (file_name, true, &interdir_made); while ((status = symlink (current_stat_info.link_name, file_name))) if (!maybe_recoverable (file_name, &interdir_made)) break; if (status == 0) set_stat (file_name, ¤t_stat_info, NULL, 0, 0, SYMTYPE); else symlink_error (current_stat_info.link_name, file_name); return status;#else static int warned_once; if (!warned_once) { warned_once = 1; WARN ((0, 0, _("Attempting extraction of symbolic links as hard links"))); } return extract_link (file_name, typeflag);#endif}#if S_IFCHR || S_IFBLKstatic intextract_node (char *file_name, int typeflag){ int status; int interdir_made = 0; mode_t mode = current_stat_info.stat.st_mode & ~ current_umask; mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0; do status = mknod (file_name, mode ^ invert_permissions, current_stat_info.stat.st_rdev); while (status && maybe_recoverable (file_name, &interdir_made)); if (status != 0) mknod_error (file_name); else set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, ARCHIVED_PERMSTATUS, typeflag); return status;}#endif#if HAVE_MKFIFO || defined mkfifostatic intextract_fifo (char *file_name, int typeflag){ int status; int interdir_made = 0; mode_t mode = current_stat_info.stat.st_mode & ~ current_umask; mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0; while ((status = mkfifo (file_name, mode)) != 0) if (!maybe_recoverable (file_name, &interdir_made)) break; if (status == 0) set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, ARCHIVED_PERMSTATUS, typeflag); else mkfifo_error (file_name); return status;}#endifstatic intextract_volhdr (char *file_name, int typeflag){ if (verbose_option) fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name)); skip_member (); return 0;}static intextract_failure (char *file_name, int typeflag){ return 1;}typedef int (*tar_extractor_t) (char *file_name, int typeflag);/* Prepare to extract a file. Find extractor function. Return zero if extraction should not proceed. */static intprepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun){ int rc = 1; if (EXTRACT_OVER_PIPE) rc = 0; /* Select the extractor */ switch (typeflag) { case GNUTYPE_SPARSE: *fun = extract_file; rc = 1; break; case AREGTYPE: case REGTYPE: case CONTTYPE: /* Appears to be a file. But BSD tar uses the convention that a slash suffix means a directory. */ if (current_stat_info.had_trailing_slash) *fun = extract_dir; else { *fun = extract_file; rc = 1; } break; case SYMTYPE: *fun = extract_symlink; break; case LNKTYPE: *fun = extract_link; break;#if S_IFCHR case CHRTYPE: current_stat_info.stat.st_mode |= S_IFCHR; *fun = extract_node; break;#endif#if S_IFBLK case BLKTYPE: current_stat_info.stat.st_mode |= S_IFBLK; *fun = extract_node; break;#endif#if HAVE_MKFIFO || defined mkfifo case FIFOTYPE: *fun = extract_fifo; break;#endif case DIRTYPE: case GNUTYPE_DUMPDIR: *fun = extract_dir; if (current_stat_info.is_dumpdir) delay_directory_restore_option = true; break; case GNUTYPE_VOLHDR: *fun = extract_volhdr; break; case GNUTYPE_MULTIVOL: ERROR ((0, 0, _("%s: Cannot extract -- file is continued from another volume"), quotearg_colon (current_stat_info.file_name))); *fun = extract_failure; break; case GNUTYPE_LONGNAME: case GNUTYPE_LONGLINK: ERROR ((0, 0, _("Unexpected long name header"))); *fun = extract_failure; break; default: WARN ((0, 0, _("%s: Unknown file type `%c', extracted as normal file"), quotearg_colon (file_name), typeflag)); *fun = extract_file; } /* Determine whether the extraction should proceed */ if (rc == 0) return 0; switch (old_files_option) { case UNLINK_FIRST_OLD_FILES: if (!remove_any_file (file_name, recursive_unlink_option ? RECURSIVE_REMOVE_OPTION : ORDINARY_REMOVE_OPTION) && errno && errno != ENOENT) { unlink_error (file_name); return 0; } break; case KEEP_NEWER_FILES: if (file_newer_p (file_name, ¤t_stat_info)) { WARN ((0, 0, _("Current %s is newer or same age"), quote (file_name))); return 0; } break; default: break; } return 1;}/* Extract a file from the archive. */voidextract_archive (void){ char typeflag; tar_extractor_t fun; set_next_block_after (current_header); decode_header (current_header, ¤t_stat_info, ¤t_format, 1); if (!current_stat_info.file_name[0] || (interactive_option && !confirm ("extract", current_stat_info.file_name))) { skip_member (); return; } /* Print the block from current_header and current_stat. */ if (verbose_option) print_header (¤t_stat_info, -1); /* Restore stats for all non-ancestor directories, unless it is an incremental archive. (see NOTICE in the comment to delay_set_stat above) */ if (!delay_directory_restore_option) apply_nonancestor_delayed_set_stat (current_stat_info.file_name, 0); /* Take a safety backup of a previously existing file. */ if (backup_option) if (!maybe_backup_file (current_stat_info.file_name, 0)) { int e = errno; ERROR ((0, e, _("%s: Was unable to backup this file"), quotearg_colon (current_stat_info.file_name))); skip_member (); return; } /* Extract the archive entry according to its type. */ /* KLUDGE */ typeflag = sparse_member_p (¤t_stat_info) ? GNUTYPE_SPARSE : current_header->header.typeflag; if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun)) { if (fun && (*fun) (current_stat_info.file_name, typeflag) && backup_option) undo_last_backup (); } else skip_member ();}/* Extract the symbolic links whose final extraction were delayed. */static voidapply_delayed_links (void){ struct delayed_link *ds; for (ds = delayed_link_head; ds; ) { struct string_list *sources = ds->sources; char const *valid_source = 0; for (sources = ds->sources; sources; sources = sources->next) { char const *source = sources->string; struct stat st; /* Make sure the placeholder file is still there. If not, don't create a link, as the placeholder was probably removed by a later extraction. */ if (lstat (source, &st) == 0 && st.st_dev == ds->dev && st.st_ino == ds->ino && timespec_cmp (get_stat_mtime (&st), ds->mtime) == 0) { /* Unlink the placeholder, then create a hard link if possible, a symbolic link otherwise. */ if (unlink (source) != 0) unlink_error (source); else if (valid_source && link (valid_source, source) == 0) ; else if (!ds->is_symlink) { if (link (ds->target, source) != 0) link_error (ds->target, source); } else if (symlink (ds->target, source) != 0) 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; } } } for (sources = ds->sources; sources; ) { struct string_list *next = sources->next; free (sources); sources = next; } { struct delayed_link *next = ds->next; free (ds); ds = next; } } delayed_link_head = 0;}/* Finish the extraction of an archive. */voidextract_finish (void){ /* First, fix the status of ordinary directories that need fixing. */ apply_nonancestor_delayed_set_stat ("", 0); /* Then, apply delayed links, so that they don't affect delayed directory status-setting for ordinary directories. */ apply_delayed_links (); /* Finally, fix the status of directories that are ancestors of delayed links. */ apply_nonancestor_delayed_set_stat ("", 1);}boolrename_directory (char *src, char *dst){ if (rename (src, dst)) { int e = errno; switch (e) { case ENOENT: if (make_directories (dst)) { if (rename (src, dst) == 0) return true; e = errno; } break; case EXDEV: /* FIXME: Fall back to recursive copying */ default: break; } ERROR ((0, e, _("Cannot rename %s to %s"), quote_n (0, src), quote_n (1, dst))); return false; } return true;}voidfatal_exit (void){ extract_finish (); error (TAREXIT_FAILURE, 0, _("Error is not recoverable: exiting now")); abort ();}voidxalloc_die (void){ error (0, 0, "%s", _("memory exhausted")); fatal_exit ();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -