📄 sparse.c
字号:
&& h->star_in_header.sp[0].offset[10] != '\0') { /* Old star format */ for (i = 0; i < SPARSES_IN_STAR_HEADER; i++) { rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]); if (rc != add_ok) break; } ext_p = h->star_in_header.isextended; } else ext_p = 1; for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended) { h = find_next_block (); if (!h) { ERROR ((0, 0, _("Unexpected EOF in archive"))); return false; } set_next_block_after (h); for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++) rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]); } if (rc == add_fail) { ERROR ((0, 0, _("%s: invalid sparse archive member"), file->stat_info->orig_file_name)); return false; } return true;}static struct tar_sparse_optab const star_optab = { NULL, /* No init function */ NULL, /* No done function */ star_sparse_member_p, NULL, star_fixup_header, star_get_sparse_info, NULL, /* No scan_block function */ NULL, /* No dump region function */ sparse_extract_region,};/* GNU PAX sparse file format. There are several versions: * 0.0 The initial version of sparse format used by tar 1.14-1.15.1. The sparse file map is stored in x header: GNU.sparse.size Real size of the stored file GNU.sparse.numblocks Number of blocks in the sparse map repeat numblocks time GNU.sparse.offset Offset of the next data block GNU.sparse.numbytes Size of the next data block end repeat This has been reported as conflicting with the POSIX specs. The reason is that offsets and sizes of non-zero data blocks were stored in multiple instances of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas POSIX requires the latest occurrence of the variable to override all previous occurrences. To avoid this incompatibility two following versions were introduced. * 0.1 Used by tar 1.15.2 -- 1.15.91 (alpha releases). The sparse file map is stored in x header: GNU.sparse.size Real size of the stored file GNU.sparse.numblocks Number of blocks in the sparse map GNU.sparse.map Map of non-null data chunks. A string consisting of comma-separated values "offset,size[,offset,size]..." The resulting GNU.sparse.map string can be *very* long. While POSIX does not impose any limit on the length of a x header variable, this can confuse some tars. * 1.0 Starting from this version, the exact sparse format version is specified explicitely in the header using the following variables: GNU.sparse.major Major version GNU.sparse.minor Minor version X header keeps the following variables: GNU.sparse.name Real file name of the sparse file GNU.sparse.realsize Real size of the stored file (corresponds to the old GNU.sparse.size variable) The name field of the ustar header is constructed using the pattern "%d/GNUSparseFile.%p/%f". The sparse map itself is stored in the file data block, preceding the actual file data. It consists of a series of octal numbers of arbitrary length, delimited by newlines. The map is padded with nulls to the nearest block boundary. The first number gives the number of entries in the map. Following are map entries, each one consisting of two numbers giving the offset and size of the data block it describes. The format is designed in such a way that non-posix aware tars and tars not supporting GNU.sparse.* keywords will extract each sparse file in its condensed form with the file map attached and will place it into a separate directory. Then, using a simple program it would be possible to expand the file to its original form even without GNU tar. Bu default, v.1.0 archives are created. To use other formats, --sparse-version option is provided. Additionally, v.0.0 can be obtained by deleting GNU.sparse.map from 0.1 format: --sparse-version 0.1 --pax-option delete=GNU.sparse.map*/static boolpax_sparse_member_p (struct tar_sparse_file *file){ return file->stat_info->sparse_map_avail > 0 || file->stat_info->sparse_major > 0;}static boolpax_dump_header_0 (struct tar_sparse_file *file){ off_t block_ordinal = current_block_ordinal (); union block *blk; size_t i; char nbuf[UINTMAX_STRSIZE_BOUND]; struct sp_array *map = file->stat_info->sparse_map; char *save_file_name = NULL; /* Store the real file size */ xheader_store ("GNU.sparse.size", file->stat_info, NULL); xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL); if (xheader_keyword_deleted_p ("GNU.sparse.map") || tar_sparse_minor == 0) { for (i = 0; i < file->stat_info->sparse_map_avail; i++) { xheader_store ("GNU.sparse.offset", file->stat_info, &i); xheader_store ("GNU.sparse.numbytes", file->stat_info, &i); } } else { xheader_store ("GNU.sparse.name", file->stat_info, NULL); save_file_name = file->stat_info->file_name; file->stat_info->file_name = xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0); xheader_string_begin (&file->stat_info->xhdr); for (i = 0; i < file->stat_info->sparse_map_avail; i++) { if (i) xheader_string_add (&file->stat_info->xhdr, ","); xheader_string_add (&file->stat_info->xhdr, umaxtostr (map[i].offset, nbuf)); xheader_string_add (&file->stat_info->xhdr, ","); xheader_string_add (&file->stat_info->xhdr, umaxtostr (map[i].numbytes, nbuf)); } if (!xheader_string_end (&file->stat_info->xhdr, "GNU.sparse.map")) { free (file->stat_info->file_name); file->stat_info->file_name = save_file_name; return false; } } blk = start_header (file->stat_info); /* Store the effective (shrunken) file size */ OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size); finish_header (file->stat_info, blk, block_ordinal); if (save_file_name) { free (file->stat_info->file_name); file->stat_info->file_name = save_file_name; } return true;}static boolpax_dump_header_1 (struct tar_sparse_file *file){ off_t block_ordinal = current_block_ordinal (); union block *blk; char *p, *q; size_t i; char nbuf[UINTMAX_STRSIZE_BOUND]; off_t size = 0; struct sp_array *map = file->stat_info->sparse_map; char *save_file_name = file->stat_info->file_name;#define COPY_STRING(b,dst,src) do \ { \ char *endp = b->buffer + BLOCKSIZE; \ char *srcp = src; \ while (*srcp) \ { \ if (dst == endp) \ { \ set_next_block_after (b); \ b = find_next_block (); \ dst = b->buffer; \ endp = b->buffer + BLOCKSIZE; \ } \ *dst++ = *srcp++; \ } \ } while (0) /* Compute stored file size */ p = umaxtostr (file->stat_info->sparse_map_avail, nbuf); size += strlen (p) + 1; for (i = 0; i < file->stat_info->sparse_map_avail; i++) { p = umaxtostr (map[i].offset, nbuf); size += strlen (p) + 1; p = umaxtostr (map[i].numbytes, nbuf); size += strlen (p) + 1; } size = (size + BLOCKSIZE - 1) / BLOCKSIZE; file->stat_info->archive_file_size += size * BLOCKSIZE; file->dumped_size += size * BLOCKSIZE; /* Store sparse file identification */ xheader_store ("GNU.sparse.major", file->stat_info, NULL); xheader_store ("GNU.sparse.minor", file->stat_info, NULL); xheader_store ("GNU.sparse.name", file->stat_info, NULL); xheader_store ("GNU.sparse.realsize", file->stat_info, NULL); file->stat_info->file_name = xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0); blk = start_header (file->stat_info); /* Store the effective (shrunken) file size */ OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size); finish_header (file->stat_info, blk, block_ordinal); free (file->stat_info->file_name); file->stat_info->file_name = save_file_name; blk = find_next_block (); q = blk->buffer; p = umaxtostr (file->stat_info->sparse_map_avail, nbuf); COPY_STRING (blk, q, p); COPY_STRING (blk, q, "\n"); for (i = 0; i < file->stat_info->sparse_map_avail; i++) { p = umaxtostr (map[i].offset, nbuf); COPY_STRING (blk, q, p); COPY_STRING (blk, q, "\n"); p = umaxtostr (map[i].numbytes, nbuf); COPY_STRING (blk, q, p); COPY_STRING (blk, q, "\n"); } memset (q, 0, BLOCKSIZE - (q - blk->buffer)); set_next_block_after (blk); return true;}static boolpax_dump_header (struct tar_sparse_file *file){ file->stat_info->sparse_major = tar_sparse_major; file->stat_info->sparse_minor = tar_sparse_minor; return (file->stat_info->sparse_major == 0) ? pax_dump_header_0 (file) : pax_dump_header_1 (file);}static booldecode_num (uintmax_t *num, char const *arg, uintmax_t maxval){ uintmax_t u; char *arg_lim; if (!ISDIGIT (*arg)) return false; u = strtoumax (arg, &arg_lim, 10); if (! (u <= maxval && errno != ERANGE) || *arg_lim) return false; *num = u; return true;}static boolpax_decode_header (struct tar_sparse_file *file){ if (file->stat_info->sparse_major > 0) { uintmax_t u; char nbuf[UINTMAX_STRSIZE_BOUND]; union block *blk; char *p; size_t i;#define COPY_BUF(b,buf,src) do \ { \ char *endp = b->buffer + BLOCKSIZE; \ char *dst = buf; \ do \ { \ if (dst == buf + UINTMAX_STRSIZE_BOUND -1) \ { \ ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \ file->stat_info->orig_file_name)); \ return false; \ } \ if (src == endp) \ { \ set_next_block_after (b); \ file->dumped_size += BLOCKSIZE; \ b = find_next_block (); \ src = b->buffer; \ endp = b->buffer + BLOCKSIZE; \ } \ *dst = *src++; \ } \ while (*dst++ != '\n'); \ dst[-1] = 0; \ } while (0) set_next_block_after (current_header); file->dumped_size += BLOCKSIZE; blk = find_next_block (); p = blk->buffer; COPY_BUF (blk,nbuf,p); if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t))) { ERROR ((0, 0, _("%s: malformed sparse archive member"), file->stat_info->orig_file_name)); return false; } file->stat_info->sparse_map_size = u; file->stat_info->sparse_map = xcalloc (file->stat_info->sparse_map_size, sizeof (*file->stat_info->sparse_map)); file->stat_info->sparse_map_avail = 0; for (i = 0; i < file->stat_info->sparse_map_size; i++) { struct sp_array sp; COPY_BUF (blk,nbuf,p); if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t))) { ERROR ((0, 0, _("%s: malformed sparse archive member"), file->stat_info->orig_file_name)); return false; } sp.offset = u; COPY_BUF (blk,nbuf,p); if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t))) { ERROR ((0, 0, _("%s: malformed sparse archive member"), file->stat_info->orig_file_name)); return false; } sp.numbytes = u; sparse_add_map (file->stat_info, &sp); } set_next_block_after (blk); } return true;}static struct tar_sparse_optab const pax_optab = { NULL, /* No init function */ NULL, /* No done function */ pax_sparse_member_p, pax_dump_header, NULL, pax_decode_header, NULL, /* No scan_block function */ sparse_dump_region, sparse_extract_region,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -