📄 create.c
字号:
uintmax_t num = l->dev ^ l->ino; return num % n_buckets;}/* Compare two links for equality. */static boolcompare_links (void const *entry1, void const *entry2){ struct link const *link1 = entry1; struct link const *link2 = entry2; return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;}static voidunknown_file_error (char const *p){ WARN ((0, 0, _("%s: Unknown file type; file ignored"), quotearg_colon (p))); if (!ignore_failed_read_option) exit_status = TAREXIT_FAILURE;}/* Handling of hard links *//* Table of all non-directories that we've written so far. Any time we see another, we check the table and avoid dumping the data again if we've done it once already. */static Hash_table *link_table;/* Try to dump stat as a hard link to another file in the archive. Return true if successful. */static booldump_hard_link (struct tar_stat_info *st){ if (link_table && st->stat.st_nlink > 1) { struct link lp; struct link *duplicate; off_t block_ordinal; union block *blk; lp.ino = st->stat.st_ino; lp.dev = st->stat.st_dev; if ((duplicate = hash_lookup (link_table, &lp))) { /* We found a link. */ char const *link_name = safer_name_suffix (duplicate->name, true, absolute_names_option); duplicate->nlink--; block_ordinal = current_block_ordinal (); assign_string (&st->link_name, link_name); if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < strlen (link_name)) write_long_link (st); st->stat.st_size = 0; blk = start_header (st); if (!blk) return false; tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE); blk->header.typeflag = LNKTYPE; finish_header (st, blk, block_ordinal); if (remove_files_option && unlink (st->orig_file_name) != 0) unlink_error (st->orig_file_name); return true; } } return false;}static voidfile_count_links (struct tar_stat_info *st){ if (hard_dereference_option) return; if (st->stat.st_nlink > 1) { struct link *duplicate; struct link *lp = xmalloc (offsetof (struct link, name) + strlen (st->orig_file_name) + 1); lp->ino = st->stat.st_ino; lp->dev = st->stat.st_dev; lp->nlink = st->stat.st_nlink; strcpy (lp->name, st->orig_file_name); if (! ((link_table || (link_table = hash_initialize (0, 0, hash_link, compare_links, 0))) && (duplicate = hash_insert (link_table, lp)))) xalloc_die (); if (duplicate != lp) abort (); lp->nlink--; }}/* For each dumped file, check if all its links were dumped. Emit warnings if it is not so. */voidcheck_links (void){ struct link *lp; if (!link_table) return; for (lp = hash_get_first (link_table); lp; lp = hash_get_next (link_table, lp)) { if (lp->nlink) { WARN ((0, 0, _("Missing links to %s.\n"), quote (lp->name))); } }}/* Dump a single file, recursing on directories. P is the file name to dump. TOP_LEVEL tells whether this is a top-level call; zero means no, positive means yes, and negative means the top level of an incremental dump. PARENT_DEVICE is the device of P's parent directory; it is examined only if TOP_LEVEL is zero. *//* FIXME: One should make sure that for *every* path leading to setting exit_status to failure, a clear diagnostic has been issued. */static voiddump_file0 (struct tar_stat_info *st, const char *p, int top_level, dev_t parent_device){ union block *header; char type; off_t original_size; struct timespec original_ctime; struct timespec restore_times[2]; off_t block_ordinal = -1; bool is_dir; if (interactive_option && !confirm ("add", p)) return; assign_string (&st->orig_file_name, p); assign_string (&st->file_name, safer_name_suffix (p, false, absolute_names_option)); transform_name (&st->file_name); if (deref_stat (dereference_option, p, &st->stat) != 0) { stat_diag (p); return; } st->archive_file_size = original_size = st->stat.st_size; st->atime = restore_times[0] = get_stat_atime (&st->stat); st->mtime = restore_times[1] = get_stat_mtime (&st->stat); st->ctime = original_ctime = get_stat_ctime (&st->stat);#ifdef S_ISHIDDEN if (S_ISHIDDEN (st->stat.st_mode)) { char *new = (char *) alloca (strlen (p) + 2); if (new) { strcpy (new, p); strcat (new, "@"); p = new; } }#endif /* See if we want only new files, and check if this one is too old to put in the archive. This check is omitted if incremental_option is set *and* the requested file is not explicitely listed in the command line. */ if (!(incremental_option && !is_individual_file (p)) && !S_ISDIR (st->stat.st_mode) && OLDER_TAR_STAT_TIME (*st, m) && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c))) { if (!incremental_option && verbose_option) WARN ((0, 0, _("%s: file is unchanged; not dumped"), quotearg_colon (p))); return; } /* See if we are trying to dump the archive. */ if (sys_file_is_archive (st)) { WARN ((0, 0, _("%s: file is the archive; not dumped"), quotearg_colon (p))); return; } if (is_avoided_name (p)) return; is_dir = S_ISDIR (st->stat.st_mode) != 0; if (!is_dir && dump_hard_link (st)) return; if (is_dir || S_ISREG (st->stat.st_mode) || S_ISCTG (st->stat.st_mode)) { bool ok; int fd = -1; struct stat final_stat; if (is_dir || file_dumpable_p (st)) { fd = open (p, (O_RDONLY | O_BINARY | (is_dir ? O_DIRECTORY | O_NONBLOCK : 0) | (atime_preserve_option == system_atime_preserve ? O_NOATIME : 0))); if (fd < 0) { if (!top_level && errno == ENOENT) WARN ((0, 0, _("%s: File removed before we read it"), quotearg_colon (p))); else open_diag (p); return; } } if (is_dir) { const char *tag_file_name; ensure_slash (&st->orig_file_name); ensure_slash (&st->file_name); if (check_exclusion_tags (st->orig_file_name, &tag_file_name) == exclusion_tag_all) { exclusion_tag_warning (st->orig_file_name, tag_file_name, _("directory not dumped")); return; } ok = dump_dir (fd, st, top_level, parent_device); /* dump_dir consumes FD if successful. */ if (ok) fd = -1; } else { enum dump_status status; if (fd != -1 && sparse_option && ST_IS_SPARSE (st->stat)) { status = sparse_dump_file (fd, st); if (status == dump_status_not_implemented) status = dump_regular_file (fd, st); } else status = dump_regular_file (fd, st); switch (status) { case dump_status_ok: case dump_status_short: mv_end (); file_count_links (st); break; case dump_status_fail: break; case dump_status_not_implemented: abort (); } ok = status == dump_status_ok; } if (ok) { /* If possible, reopen a directory if we are preserving atimes, so that we can set just the atime on systems with _FIOSATIME. */ if (fd < 0 && is_dir && atime_preserve_option == replace_atime_preserve) fd = open (p, O_RDONLY | O_BINARY | O_DIRECTORY | O_NONBLOCK); if ((fd < 0 ? deref_stat (dereference_option, p, &final_stat) : fstat (fd, &final_stat)) != 0) { stat_diag (p); ok = false; } } if (ok) { if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0 /* Original ctime will change if the file is a directory and --remove-files is given */ && !(remove_files_option && is_dir)) || original_size < final_stat.st_size) { WARN ((0, 0, _("%s: file changed as we read it"), quotearg_colon (p))); if (exit_status == TAREXIT_SUCCESS) exit_status = TAREXIT_DIFFERS; } else if (atime_preserve_option == replace_atime_preserve && set_file_atime (fd, p, restore_times) != 0) utime_error (p); } if (0 <= fd && close (fd) != 0) { close_diag (p); ok = false; } if (ok && remove_files_option) { if (is_dir) { if (rmdir (p) != 0 && errno != ENOTEMPTY) rmdir_error (p); } else { if (unlink (p) != 0) unlink_error (p); } } return; }#ifdef HAVE_READLINK else if (S_ISLNK (st->stat.st_mode)) { char *buffer; int size; size_t linklen = st->stat.st_size; if (linklen != st->stat.st_size || linklen + 1 == 0) xalloc_die (); buffer = (char *) alloca (linklen + 1); size = readlink (p, buffer, linklen + 1); if (size < 0) { readlink_diag (p); return; } buffer[size] = '\0'; assign_string (&st->link_name, buffer); transform_name (&st->link_name); if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size) write_long_link (st); block_ordinal = current_block_ordinal (); st->stat.st_size = 0; /* force 0 size on symlink */ header = start_header (st); if (!header) return; tar_copy_str (header->header.linkname, st->link_name, NAME_FIELD_SIZE); header->header.typeflag = SYMTYPE; finish_header (st, header, block_ordinal); /* nothing more to do to it */ if (remove_files_option) { if (unlink (p) == -1) unlink_error (p); } file_count_links (st); return; }#endif else if (S_ISCHR (st->stat.st_mode)) type = CHRTYPE; else if (S_ISBLK (st->stat.st_mode)) type = BLKTYPE; else if (S_ISFIFO (st->stat.st_mode)) type = FIFOTYPE; else if (S_ISSOCK (st->stat.st_mode)) { WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p))); return; } else if (S_ISDOOR (st->stat.st_mode)) { WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p))); return; } else { unknown_file_error (p); return; } if (archive_format == V7_FORMAT) { unknown_file_error (p); return; } block_ordinal = current_block_ordinal (); st->stat.st_size = 0; /* force 0 size */ header = start_header (st); if (!header) return; header->header.typeflag = type; if (type != FIFOTYPE) { MAJOR_TO_CHARS (major (st->stat.st_rdev), header->header.devmajor); MINOR_TO_CHARS (minor (st->stat.st_rdev), header->header.devminor); } finish_header (st, header, block_ordinal); if (remove_files_option) { if (unlink (p) == -1) unlink_error (p); }}voiddump_file (const char *p, int top_level, dev_t parent_device){ struct tar_stat_info st; tar_stat_init (&st); dump_file0 (&st, p, top_level, parent_device); if (listed_incremental_option) update_parent_directory (p); tar_stat_destroy (&st);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -