📄 extract.c
字号:
continue; /* Some other error in the mkdir. We return to the caller. */ break; } return did_something; /* tell them to retry if we made one */}static boolfile_newer_p (const char *file_name, struct tar_stat_info *tar_stat){ struct stat st; if (stat (file_name, &st)) { stat_warn (file_name); /* Be on the safe side: if the file does exist assume it is newer */ return errno != ENOENT; } if (!S_ISDIR (st.st_mode) && tar_timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0) { return true; } return false;}/* Attempt repairing what went wrong with the extraction. Delete an already existing file or create missing intermediate directories. Return nonzero if we somewhat increased our chances at a successful extraction. errno is properly restored on zero return. */static intmaybe_recoverable (char *file_name, int *interdir_made){ int e = errno; if (*interdir_made) return 0; switch (errno) { case EEXIST: /* Remove an old file, if the options allow this. */ switch (old_files_option) { case KEEP_OLD_FILES: return 0; case KEEP_NEWER_FILES: if (file_newer_p (file_name, ¤t_stat_info)) { errno = e; return 0; } /* FALL THROUGH */ case DEFAULT_OLD_FILES: case NO_OVERWRITE_DIR_OLD_FILES: case OVERWRITE_OLD_FILES: { int r = remove_any_file (file_name, ORDINARY_REMOVE_OPTION); errno = EEXIST; return r; } case UNLINK_FIRST_OLD_FILES: break; } case ENOENT: /* Attempt creating missing intermediate directories. */ if (! make_directories (file_name)) { errno = ENOENT; return 0; } *interdir_made = 1; return 1; default: /* Just say we can't do anything about it... */ return 0; }}/* Fix the statuses of all directories whose statuses need fixing, and which are not ancestors of FILE_NAME. If AFTER_LINKS is nonzero, do this for all such directories; otherwise, stop at the first directory that is marked to be fixed up only after delayed links are applied. */static voidapply_nonancestor_delayed_set_stat (char const *file_name, bool after_links){ size_t file_name_len = strlen (file_name); bool check_for_renamed_directories = 0; while (delayed_set_stat_head) { struct delayed_set_stat *data = delayed_set_stat_head; bool skip_this_one = 0; struct stat st; struct stat const *cur_info = 0; check_for_renamed_directories |= data->after_links; if (after_links < data->after_links || (data->file_name_len < file_name_len && file_name[data->file_name_len] && (ISSLASH (file_name[data->file_name_len]) || ISSLASH (file_name[data->file_name_len - 1])) && memcmp (file_name, data->file_name, data->file_name_len) == 0)) break; if (check_for_renamed_directories) { cur_info = &st; if (stat (data->file_name, &st) != 0) { stat_error (data->file_name); skip_this_one = 1; } else if (! (st.st_dev == data->dev && st.st_ino == data->ino)) { ERROR ((0, 0, _("%s: Directory renamed before its status could be extracted"), quotearg_colon (data->file_name))); skip_this_one = 1; } } if (! skip_this_one) { struct tar_stat_info sb; sb.stat.st_mode = data->mode; sb.stat.st_uid = data->uid; sb.stat.st_gid = data->gid; sb.atime = data->atime; sb.mtime = data->mtime; set_stat (data->file_name, &sb, cur_info, data->invert_permissions, data->permstatus, DIRTYPE); } delayed_set_stat_head = data->next; free (data); }}/* Extractor functions for various member types */static intextract_dir (char *file_name, int typeflag){ int status; mode_t mode; int interdir_made = 0; /* Save 'root device' to avoid purging mount points. */ if (one_file_system_option && root_device == 0) { struct stat st; char *dir = xgetcwd (); if (deref_stat (true, dir, &st)) stat_diag (dir); else root_device = st.st_dev; free (dir); } if (incremental_option) /* Read the entry and delete files that aren't listed in the archive. */ purge_directory (file_name); else if (typeflag == GNUTYPE_DUMPDIR) skip_member (); mode = current_stat_info.stat.st_mode | (we_are_root ? 0 : MODE_WXUSR); if (0 < same_owner_option || current_stat_info.stat.st_mode & ~ MODE_RWX) mode &= S_IRWXU; while ((status = mkdir (file_name, mode))) { if (errno == EEXIST && (interdir_made || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES)) { struct stat st; if (stat (file_name, &st) == 0) { if (interdir_made) { repair_delayed_set_stat (file_name, &st); return 0; } if (S_ISDIR (st.st_mode)) { mode = st.st_mode; break; } } errno = EEXIST; } if (maybe_recoverable (file_name, &interdir_made)) continue; if (errno != EEXIST) { mkdir_error (file_name); return 1; } break; } if (status == 0 || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES) { if (status == 0) delay_set_stat (file_name, ¤t_stat_info, ((mode ^ current_stat_info.stat.st_mode) & MODE_RWX & ~ current_umask), ARCHIVED_PERMSTATUS); else /* For an already existing directory, invert_perms must be 0 */ delay_set_stat (file_name, ¤t_stat_info, 0, UNKNOWN_PERMSTATUS); } return status;}static intopen_output_file (char *file_name, int typeflag, mode_t mode){ int fd; int openflag = (O_WRONLY | O_BINARY | O_CREAT | (old_files_option == OVERWRITE_OLD_FILES ? O_TRUNC : O_EXCL));#if O_CTG /* Contiguous files (on the Masscomp) have to specify the size in the open call that creates them. */ if (typeflag == CONTTYPE) fd = open (file_name, openflag | O_CTG, mode, current_stat_info.stat.st_size); else fd = open (file_name, openflag, mode);#else /* not O_CTG */ if (typeflag == CONTTYPE) { static int conttype_diagnosed; if (!conttype_diagnosed) { conttype_diagnosed = 1; WARN ((0, 0, _("Extracting contiguous files as regular files"))); } } fd = open (file_name, openflag, mode);#endif /* not O_CTG */ return fd;}static intextract_file (char *file_name, int typeflag){ int fd; off_t size; union block *data_block; int status; size_t count; size_t written; int interdir_made = 0; mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask; mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0; /* FIXME: deal with protection issues. */ if (to_stdout_option) fd = STDOUT_FILENO; else if (to_command_option) { fd = sys_exec_command (file_name, 'f', ¤t_stat_info); if (fd < 0) { skip_member (); return 0; } } else { do fd = open_output_file (file_name, typeflag, mode ^ invert_permissions); while (fd < 0 && maybe_recoverable (file_name, &interdir_made)); if (fd < 0) { skip_member (); open_error (file_name); return 1; } } mv_begin (¤t_stat_info); if (current_stat_info.is_sparse) sparse_extract_file (fd, ¤t_stat_info, &size); else for (size = current_stat_info.stat.st_size; size > 0; ) { mv_size_left (size); /* Locate data, determine max length writeable, write it, block that we have used the data, then check if the write worked. */ data_block = find_next_block (); if (! data_block) { ERROR ((0, 0, _("Unexpected EOF in archive"))); break; /* FIXME: What happens, then? */ } written = available_space_after (data_block); if (written > size) written = size; errno = 0; count = full_write (fd, data_block->buffer, written); size -= written; set_next_block_after ((union block *) (data_block->buffer + written - 1)); if (count != written) { if (!to_command_option) write_error_details (file_name, count, written); /* FIXME: shouldn't we restore from backup? */ break; } } skip_file (size); mv_end (); /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway. */ if (to_stdout_option) return 0; status = close (fd); if (status < 0) close_error (file_name); if (to_command_option) sys_wait_command (); else set_stat (file_name, ¤t_stat_info, NULL, invert_permissions, (old_files_option == OVERWRITE_OLD_FILES ? UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS), typeflag); return status;}/* Create a placeholder file with name FILE_NAME, which will be replaced after other extraction is done by a symbolic link if IS_SYMLINK is true, and by a hard link otherwise. Set *INTERDIR_MADE if an intermediate directory is made in the process. */static intcreate_placeholder_file (char *file_name, bool is_symlink, int *interdir_made){ int fd; struct stat st; while ((fd = open (file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0) if (! maybe_recoverable (file_name, interdir_made)) break; if (fd < 0) open_error (file_name); else if (fstat (fd, &st) != 0) { stat_error (file_name); close (fd); } else if (close (fd) != 0) close_error (file_name); else { struct delayed_set_stat *h; struct delayed_link *p = xmalloc (offsetof (struct delayed_link, target) + strlen (current_stat_info.link_name) + 1); p->next = delayed_link_head; delayed_link_head = p; p->dev = st.st_dev; p->ino = st.st_ino; p->mtime = get_stat_mtime (&st); p->is_symlink = is_symlink; if (is_symlink) { p->uid = current_stat_info.stat.st_uid; p->gid = current_stat_info.stat.st_gid; } p->sources = xmalloc (offsetof (struct string_list, string) + strlen (file_name) + 1); p->sources->next = 0; strcpy (p->sources->string, file_name); strcpy (p->target, current_stat_info.link_name); h = delayed_set_stat_head; if (h && ! h->after_links && strncmp (file_name, h->file_name, h->file_name_len) == 0 && ISSLASH (file_name[h->file_name_len]) && (last_component (file_name) == file_name + h->file_name_len + 1)) { do { h->after_links = 1; if (stat (h->file_name, &st) != 0) stat_error (h->file_name); else { h->dev = st.st_dev; h->ino = st.st_ino; } } while ((h = h->next) && ! h->after_links); } return 0; } return -1;}static intextract_link (char *file_name, int typeflag){ int interdir_made = 0; char const *link_name; transform_member_name (¤t_stat_info.link_name, xform_link);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -