📄 create.c
字号:
{ TIME_TO_CHARS (st->atime.tv_sec, header->oldgnu_header.atime); TIME_TO_CHARS (st->ctime.tv_sec, header->oldgnu_header.ctime); } header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE; switch (archive_format) { case V7_FORMAT: break; case OLDGNU_FORMAT: case GNU_FORMAT: /*FIXME?*/ /* Overwrite header->header.magic and header.version in one blow. */ strcpy (header->header.magic, OLDGNU_MAGIC); break; case POSIX_FORMAT: case USTAR_FORMAT: strncpy (header->header.magic, TMAGIC, TMAGLEN); strncpy (header->header.version, TVERSION, TVERSLEN); break; default: abort (); } if (archive_format == V7_FORMAT || numeric_owner_option) { /* header->header.[ug]name are left as the empty string. */ } else { uid_to_uname (st->stat.st_uid, &st->uname); gid_to_gname (st->stat.st_gid, &st->gname); if (archive_format == POSIX_FORMAT && (strlen (st->uname) > UNAME_FIELD_SIZE || !string_ascii_p (st->uname))) xheader_store ("uname", st, NULL); UNAME_TO_CHARS (st->uname, header->header.uname); if (archive_format == POSIX_FORMAT && (strlen (st->gname) > GNAME_FIELD_SIZE || !string_ascii_p (st->gname))) xheader_store ("gname", st, NULL); GNAME_TO_CHARS (st->gname, header->header.gname); } return header;}voidsimple_finish_header (union block *header){ size_t i; int sum; char *p; memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum); sum = 0; p = header->buffer; for (i = sizeof *header; i-- != 0; ) /* We can't use unsigned char here because of old compilers, e.g. V7. */ sum += 0xFF & *p++; /* Fill in the checksum field. It's formatted differently from the other fields: it has [6] digits, a null, then a space -- rather than digits, then a null. We use to_chars. The final space is already there, from checksumming, and to_chars doesn't modify it. This is a fast way to do: sprintf(header->header.chksum, "%6o", sum); */ uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7); set_next_block_after (header);}/* Finish off a filled-in header block and write it out. We also print the file name and/or full info if verbose is on. If BLOCK_ORDINAL is not negative, is the block ordinal of the first record for this file, which may be a preceding long name or long link record. */voidfinish_header (struct tar_stat_info *st, union block *header, off_t block_ordinal){ /* Note: It is important to do this before the call to write_extended(), so that the actual ustar header is printed */ if (verbose_option && header->header.typeflag != GNUTYPE_LONGLINK && header->header.typeflag != GNUTYPE_LONGNAME && header->header.typeflag != XHDTYPE && header->header.typeflag != XGLTYPE) { /* These globals are parameters to print_header, sigh. */ current_header = header; current_format = archive_format; print_header (st, block_ordinal); } header = write_extended (false, st, header); simple_finish_header (header);}voidpad_archive (off_t size_left){ union block *blk; while (size_left > 0) { mv_size_left (size_left); blk = find_next_block (); memset (blk->buffer, 0, BLOCKSIZE); set_next_block_after (blk); size_left -= BLOCKSIZE; }}static enum dump_statusdump_regular_file (int fd, struct tar_stat_info *st){ off_t size_left = st->stat.st_size; off_t block_ordinal; union block *blk; block_ordinal = current_block_ordinal (); blk = start_header (st); if (!blk) return dump_status_fail; /* Mark contiguous files, if we support them. */ if (archive_format != V7_FORMAT && S_ISCTG (st->stat.st_mode)) blk->header.typeflag = CONTTYPE; finish_header (st, blk, block_ordinal); mv_begin (st); while (size_left > 0) { size_t bufsize, count; mv_size_left (size_left); blk = find_next_block (); bufsize = available_space_after (blk); if (size_left < bufsize) { /* Last read -- zero out area beyond. */ bufsize = size_left; count = bufsize % BLOCKSIZE; if (count) memset (blk->buffer + size_left, 0, BLOCKSIZE - count); } count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize); if (count == SAFE_READ_ERROR) { read_diag_details (st->orig_file_name, st->stat.st_size - size_left, bufsize); pad_archive (size_left); return dump_status_short; } size_left -= count; set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); if (count != bufsize) { char buf[UINTMAX_STRSIZE_BOUND]; memset (blk->buffer + count, 0, bufsize - count); WARN ((0, 0, ngettext ("%s: File shrank by %s byte; padding with zeros", "%s: File shrank by %s bytes; padding with zeros", size_left), quotearg_colon (st->orig_file_name), STRINGIFY_BIGINT (size_left, buf))); if (! ignore_failed_read_option) exit_status = TAREXIT_DIFFERS; pad_archive (size_left - (bufsize - count)); return dump_status_short; } } return dump_status_ok;}static voiddump_dir0 (char *directory, struct tar_stat_info *st, int top_level, dev_t parent_device){ dev_t our_device = st->stat.st_dev; const char *tag_file_name; if (!is_avoided_name (st->orig_file_name)) { union block *blk = NULL; off_t block_ordinal = current_block_ordinal (); st->stat.st_size = 0; /* force 0 size on dir */ blk = start_header (st); if (!blk) return; if (incremental_option && archive_format != POSIX_FORMAT) blk->header.typeflag = GNUTYPE_DUMPDIR; else /* if (standard_option) */ blk->header.typeflag = DIRTYPE; /* If we're gnudumping, we aren't done yet so don't close it. */ if (!incremental_option) finish_header (st, blk, block_ordinal); else if (gnu_list_name->dir_contents) { if (archive_format == POSIX_FORMAT) { xheader_store ("GNU.dumpdir", st, gnu_list_name->dir_contents); finish_header (st, blk, block_ordinal); } else { off_t size_left; off_t totsize; size_t bufsize; ssize_t count; const char *buffer, *p_buffer; block_ordinal = current_block_ordinal (); buffer = gnu_list_name->dir_contents; if (buffer) totsize = dumpdir_size (buffer); else totsize = 0; OFF_TO_CHARS (totsize, blk->header.size); finish_header (st, blk, block_ordinal); p_buffer = buffer; size_left = totsize; mv_begin (st); mv_total_size (totsize); while (size_left > 0) { mv_size_left (size_left); blk = find_next_block (); bufsize = available_space_after (blk); if (size_left < bufsize) { bufsize = size_left; count = bufsize % BLOCKSIZE; if (count) memset (blk->buffer + size_left, 0, BLOCKSIZE - count); } memcpy (blk->buffer, p_buffer, bufsize); size_left -= bufsize; p_buffer += bufsize; set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); } mv_end (); } return; } } if (!recursion_option) return; if (one_file_system_option && !top_level && parent_device != st->stat.st_dev) { if (verbose_option) WARN ((0, 0, _("%s: file is on a different filesystem; not dumped"), quotearg_colon (st->orig_file_name))); } else { char *name_buf; size_t name_size; switch (check_exclusion_tags (st->orig_file_name, &tag_file_name)) { case exclusion_tag_all: /* Handled in dump_file0 */ break; case exclusion_tag_none: { char const *entry; size_t entry_len; size_t name_len; name_buf = xstrdup (st->orig_file_name); name_size = name_len = strlen (name_buf); /* Now output all the files in the directory. */ /* FIXME: Should speed this up by cd-ing into the dir. */ for (entry = directory; (entry_len = strlen (entry)) != 0; entry += entry_len + 1) { if (name_size < name_len + entry_len) { name_size = name_len + entry_len; name_buf = xrealloc (name_buf, name_size + 1); } strcpy (name_buf + name_len, entry); if (!excluded_name (name_buf)) dump_file (name_buf, 0, our_device); } free (name_buf); } break; case exclusion_tag_contents: exclusion_tag_warning (st->orig_file_name, tag_file_name, _("contents not dumped")); name_size = strlen (st->orig_file_name) + strlen (tag_file_name) + 1; name_buf = xmalloc (name_size); strcpy (name_buf, st->orig_file_name); strcat (name_buf, tag_file_name); dump_file (name_buf, 0, our_device); free (name_buf); break; case exclusion_tag_under: exclusion_tag_warning (st->orig_file_name, tag_file_name, _("contents not dumped")); break; } }}/* Ensure exactly one trailing slash. */static voidensure_slash (char **pstr){ size_t len = strlen (*pstr); while (len >= 1 && ISSLASH ((*pstr)[len - 1])) len--; if (!ISSLASH ((*pstr)[len])) *pstr = xrealloc (*pstr, len + 2); (*pstr)[len++] = '/'; (*pstr)[len] = '\0';}static booldump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device){ char *directory = fdsavedir (fd); if (!directory) { savedir_diag (st->orig_file_name); return false; } dump_dir0 (directory, st, top_level, parent_device); free (directory); return true;}/* Main functions of this module. */voidcreate_archive (void){ const char *p; open_archive (ACCESS_WRITE); buffer_write_global_xheader (); if (incremental_option) { size_t buffer_size = 1000; char *buffer = xmalloc (buffer_size); const char *q; collect_and_sort_names (); while ((p = name_from_list ()) != NULL) if (!excluded_name (p)) dump_file (p, -1, (dev_t) 0); blank_name_list (); while ((p = name_from_list ()) != NULL) if (!excluded_name (p)) { size_t plen = strlen (p); if (buffer_size <= plen) { while ((buffer_size *= 2) <= plen) continue; buffer = xrealloc (buffer, buffer_size); } memcpy (buffer, p, plen); if (! ISSLASH (buffer[plen - 1])) buffer[plen++] = '/'; q = gnu_list_name->dir_contents; if (q) while (*q) { size_t qlen = strlen (q); if (*q == 'Y') { if (buffer_size < plen + qlen) { while ((buffer_size *=2 ) < plen + qlen) continue; buffer = xrealloc (buffer, buffer_size); } strcpy (buffer + plen, q + 1); dump_file (buffer, -1, (dev_t) 0); } q += qlen + 1; } } free (buffer); } else { while ((p = name_next (1)) != NULL) if (!excluded_name (p)) dump_file (p, 1, (dev_t) 0); } write_eot (); close_archive (); if (listed_incremental_option) write_directory_file ();}/* Calculate the hash of a link. */static size_thash_link (void const *entry, size_t n_buckets){ struct link const *l = entry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -