diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:22:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:22:03 +0000 |
commit | ffccd5b2b05243e7976db80f90f453dccfae9886 (patch) | |
tree | 39a43152d27f7390d8f7a6fb276fa6887f87c6e8 /src/vfs/tar/tar-internal.h | |
parent | Initial commit. (diff) | |
download | mc-ffccd5b2b05243e7976db80f90f453dccfae9886.tar.xz mc-ffccd5b2b05243e7976db80f90f453dccfae9886.zip |
Adding upstream version 3:4.8.30.upstream/3%4.8.30
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/vfs/tar/tar-internal.h')
-rw-r--r-- | src/vfs/tar/tar-internal.h | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/src/vfs/tar/tar-internal.h b/src/vfs/tar/tar-internal.h new file mode 100644 index 0000000..7b3bb53 --- /dev/null +++ b/src/vfs/tar/tar-internal.h @@ -0,0 +1,351 @@ + +#ifndef MC__VFS_TAR_INTERNAL_H +#define MC__VFS_TAR_INTERNAL_H + +#include <inttypes.h> /* (u)intmax_t */ +#include <limits.h> /* CHAR_BIT, INT_MAX, etc */ +#include <sys/stat.h> +#include <sys/types.h> + +#include "lib/vfs/xdirentry.h" /* vfs_s_super */ + +/*** typedefs(not structures) and defined constants **********************************************/ + +/* tar files are made in basic blocks of this size. */ +#define BLOCKSIZE 512 + +#define DEFAULT_BLOCKING 20 + +/* Sparse files are not supported in POSIX ustar format. For sparse files + with a POSIX header, a GNU extra header is provided which holds overall + sparse information and a few sparse descriptors. When an old GNU header + replaces both the POSIX header and the GNU extra header, it holds some + sparse descriptors too. Whether POSIX or not, if more sparse descriptors + are still needed, they are put into as many successive sparse headers as + necessary. The following constants tell how many sparse descriptors fit + in each kind of header able to hold them. */ + +#define SPARSES_IN_EXTRA_HEADER 16 +#define SPARSES_IN_OLDGNU_HEADER 4 +#define SPARSES_IN_SPARSE_HEADER 21 + +#define SPARSES_IN_STAR_HEADER 4 +#define SPARSES_IN_STAR_EXT_HEADER 21 + +/* *BEWARE* *BEWARE* *BEWARE* that the following information is still + boiling, and may change. Even if the OLDGNU format description should be + accurate, the so-called GNU format is not yet fully decided. It is + surely meant to use only extensions allowed by POSIX, but the sketch + below repeats some ugliness from the OLDGNU format, which should rather + go away. Sparse files should be saved in such a way that they do *not* + require two passes at archive creation time. Huge files get some POSIX + fields to overflow, alternate solutions have to be sought for this. */ + +/* This is a dir entry that contains the names of files that were in the + dir at the time the dump was made. */ +#define GNUTYPE_DUMPDIR 'D' + +/* Identifies the *next* file on the tape as having a long linkname. */ +#define GNUTYPE_LONGLINK 'K' + +/* Identifies the *next* file on the tape as having a long name. */ +#define GNUTYPE_LONGNAME 'L' + +/* Solaris extended header */ +#define SOLARIS_XHDTYPE 'X' + +#define GNUTYPE_SPARSE 'S' + + +/* These macros work even on ones'-complement hosts (!). + The extra casts work around some compiler bugs. */ +#define TYPE_SIGNED(t) (!((t) 0 < (t) (-1))) +#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) ? ~(t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0) +#define TYPE_MAXIMUM(t) (~(t) 0 - TYPE_MINIMUM (t)) + +#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where)) + +#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) + +/*** enums ***************************************************************************************/ + +/*** structures declarations (and typedefs of structures)*****************************************/ + +/* *INDENT-OFF* */ + +/* POSIX header */ +struct posix_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +/* Descriptor for a single file hole */ +struct sparse +{ /* byte offset */ + /* cppcheck-suppress unusedStructMember */ + char offset[12]; /* 0 */ + /* cppcheck-suppress unusedStructMember */ + char numbytes[12]; /* 12 */ + /* 24 */ +}; + +/* Extension header for sparse files, used immediately after the GNU extra + header, and used only if all sparse information cannot fit into that + extra header. There might even be many such extension headers, one after + the other, until all sparse information has been recorded. */ +struct sparse_header +{ /* byte offset */ + struct sparse sp[SPARSES_IN_SPARSE_HEADER]; + /* 0 */ + char isextended; /* 504 */ + /* 505 */ +}; + +/* The old GNU format header conflicts with POSIX format in such a way that + POSIX archives may fool old GNU tar's, and POSIX tar's might well be + fooled by old GNU tar archives. An old GNU format header uses the space + used by the prefix field in a POSIX header, and cumulates information + normally found in a GNU extra header. With an old GNU tar header, we + never see any POSIX header nor GNU extra header. Supplementary sparse + headers are allowed, however. */ +struct oldgnu_header +{ /* byte offset */ + char unused_pad1[345]; /* 0 */ + char atime[12]; /* 345 Incr. archive: atime of the file */ + char ctime[12]; /* 357 Incr. archive: ctime of the file */ + char offset[12]; /* 369 Multivolume archive: the offset of start of this volume */ + char longnames[4]; /* 381 Not used */ + char unused_pad2; /* 385 */ + struct sparse sp[SPARSES_IN_OLDGNU_HEADER]; + /* 386 */ + char isextended; /* 482 Sparse file: Extension sparse header follows */ + char realsize[12]; /* 483 Sparse file: Real size */ + /* 495 */ +}; + +/* J@"org Schilling star header */ +struct star_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[131]; /* 345 */ + char atime[12]; /* 476 */ + char ctime[12]; /* 488 */ + /* 500 */ +}; + +struct star_in_header +{ + char fill[345]; /* 0 Everything that is before t_prefix */ + char prefix[1]; /* 345 t_name prefix */ + char fill2; /* 346 */ + char fill3[8]; /* 347 */ + char isextended; /* 355 */ + struct sparse sp[SPARSES_IN_STAR_HEADER]; /* 356 */ + char realsize[12]; /* 452 Actual size of the file */ + char offset[12]; /* 464 Offset of multivolume contents */ + char atime[12]; /* 476 */ + char ctime[12]; /* 488 */ + char mfill[8]; /* 500 */ + char xmagic[4]; /* 508 "tar" */ +}; + +struct star_ext_header +{ + struct sparse sp[SPARSES_IN_STAR_EXT_HEADER]; + char isextended; +}; + +/* *INDENT-ON* */ + +/* tar Header Block, overall structure */ +union block +{ + char buffer[BLOCKSIZE]; + struct posix_header header; + struct star_header star_header; + struct oldgnu_header oldgnu_header; + struct sparse_header sparse_header; + struct star_in_header star_in_header; + struct star_ext_header star_ext_header; +}; + +/* Information about a sparse file */ +struct sp_array +{ + off_t offset; /* chunk offset in file */ + off_t numbytes; /* length of chunk */ + off_t arch_offset; /* chunk offset in archive */ +}; + +enum dump_status +{ + dump_status_ok, + dump_status_short, + dump_status_fail, + dump_status_not_implemented +}; + +enum archive_format +{ + TAR_UNKNOWN = 0, /**< format to be decided later */ + TAR_V7, /**< old V7 tar format */ + TAR_OLDGNU, /**< GNU format as per before tar 1.12 */ + TAR_USTAR, /**< POSIX.1-1988 (ustar) format */ + TAR_POSIX, /**< POSIX.1-2001 format */ + TAR_STAR, /**< star format defined in 1994 */ + TAR_GNU /**< almost same as OLDGNU_FORMAT */ +}; + +typedef struct +{ + struct vfs_s_super base; /* base class */ + + int fd; + struct stat st; + enum archive_format type; /**< type of the archive */ + union block *record_start; /**< start of record of archive */ +} tar_super_t; + +struct xheader +{ + size_t size; + char *buffer; +}; + +struct tar_stat_info +{ + char *orig_file_name; /**< name of file read from the archive header */ + char *file_name; /**< name of file for the current archive entry after being normalized */ + char *link_name; /**< name of link for the current archive entry */ +#if 0 + char *uname; /**< user name of owner */ + char *gname; /**< group name of owner */ +#endif + struct stat stat; /**< regular filesystem stat */ + + /* stat() doesn't always have access, data modification, and status + change times in a convenient form, so store them separately. */ + struct timespec atime; + struct timespec mtime; + struct timespec ctime; + + off_t archive_file_size; /**< size of file as stored in the archive. + Equals stat.st_size for non-sparse files */ + gboolean is_sparse; /**< is the file sparse */ + + /* For sparse files */ + unsigned int sparse_major; + unsigned int sparse_minor; + GArray *sparse_map; /**< array of struct sp_array */ + + off_t real_size; /**< real size of sparse file */ + gboolean real_size_set; /**< TRUE when GNU.sparse.realsize is set in archived file */ + + gboolean sparse_name_done; /**< TRUE if 'GNU.sparse.name' header was processed pax header parsing. + Following 'path' header (lower priority) will be ignored. */ + + /* Extended headers */ + struct xheader xhdr; + + /* For dumpdirs */ + gboolean is_dumpdir; /**< is the member a dumpdir? */ + gboolean skipped; /**< the member contents is already read (for GNUTYPE_DUMPDIR) */ + char *dumpdir; /**< contents of the dump directory */ +}; + +/*** global variables defined in .c file *********************************************************/ + +extern const int blocking_factor; +extern const size_t record_size; + +extern union block *record_end; /* last+1 block of archive record */ +extern union block *current_block; /* current block of archive */ +extern off_t record_start_block; /* block ordinal at record_start */ + +extern union block *current_header; + +/* Have we hit EOF yet? */ +extern gboolean hit_eof; + +extern struct tar_stat_info current_stat_info; + +/*** declarations of public functions ************************************************************/ + +/* tar-internal.c */ +void tar_base64_init (void); +void tar_assign_string (char **string, char *value); +void tar_assign_string_dup (char **string, const char *value); +void tar_assign_string_dup_n (char **string, const char *value, size_t n); +intmax_t tar_from_header (const char *where0, size_t digs, char const *type, intmax_t minval, + uintmax_t maxval, gboolean octal_only); +off_t off_from_header (const char *p, size_t s); +union block *tar_find_next_block (tar_super_t * archive); +gboolean tar_set_next_block_after (union block *block); +off_t tar_current_block_ordinal (const tar_super_t * archive); +gboolean tar_skip_file (tar_super_t * archive, off_t size); + +/* tar-sparse.c */ +gboolean tar_sparse_member_p (tar_super_t * archive, struct tar_stat_info *st); +gboolean tar_sparse_fixup_header (tar_super_t * archive, struct tar_stat_info *st); +enum dump_status tar_sparse_skip_file (tar_super_t * archive, struct tar_stat_info *st); + +/* tar-xheader.c */ +gboolean tar_xheader_decode (struct tar_stat_info *st); +gboolean tar_xheader_read (tar_super_t * archive, struct xheader *xhdr, union block *header, + off_t size); +gboolean tar_xheader_decode_global (struct xheader *xhdr); +void tar_xheader_destroy (struct xheader *xhdr); + +/*** inline functions ****************************************************************************/ + +/** + * Represent @n using a signed integer I such that (uintmax_t) I == @n. + With a good optimizing compiler, this is equivalent to (intmax_t) i + and requires zero machine instructions. */ +#if !(UINTMAX_MAX / 2 <= INTMAX_MAX) +#error "tar_represent_uintmax() returns intmax_t to represent uintmax_t" +#endif +static inline intmax_t +tar_represent_uintmax (uintmax_t n) +{ + intmax_t nd; + + if (n <= INTMAX_MAX) + return n; + + /* Avoid signed integer overflow on picky platforms. */ + nd = n - INTMAX_MIN; + return nd + INTMAX_MIN; +} + +#endif /* MC__VFS_TAR_INTERNAL_H */ |