7 /* Header for ustar-format tar archive. See the documentation of
8 the "pax" utility in [SUSv3] for the the "ustar" format
12 char name[100]; /* File name. Null-terminated if room. */
13 char mode[8]; /* Permissions as octal string. */
14 char uid[8]; /* User ID as octal string. */
15 char gid[8]; /* Group ID as octal string. */
16 char size[12]; /* File size in bytes as octal string. */
17 char mtime[12]; /* Modification time in seconds
18 from Jan 1, 1970, as octal string. */
19 char chksum[8]; /* Sum of octets in header as octal string. */
20 char typeflag; /* An enum ustar_type value. */
21 char linkname[100]; /* Name of link target.
22 Null-terminated if room. */
23 char magic[6]; /* "ustar\0" */
24 char version[2]; /* "00" */
25 char uname[32]; /* User name, always null-terminated. */
26 char gname[32]; /* Group name, always null-terminated. */
27 char devmajor[8]; /* Device major number as octal string. */
28 char devminor[8]; /* Device minor number as octal string. */
29 char prefix[155]; /* Prefix to file name.
30 Null-terminated if room. */
31 char padding[12]; /* Pad to 512 bytes. */
35 /* Returns the checksum for the given ustar format HEADER. */
37 calculate_chksum (const struct ustar_header *h)
39 const uint8_t *header = (const uint8_t *) h;
44 for (i = 0; i < USTAR_HEADER_SIZE; i++)
46 /* The ustar checksum is calculated as if the chksum field
48 const size_t chksum_start = offsetof (struct ustar_header, chksum);
49 const size_t chksum_end = chksum_start + sizeof h->chksum;
50 bool in_chksum_field = i >= chksum_start && i < chksum_end;
51 chksum += in_chksum_field ? ' ' : header[i];
56 /* Drop possibly dangerous prefixes from FILE_NAME and return the
57 stripped name. An archive with file names that start with "/"
58 or "../" could cause a naive tar extractor to write to
59 arbitrary parts of the file system, not just the destination
60 directory. We don't want to create such archives or be such a
63 The return value can be a suffix of FILE_NAME or a string
66 strip_antisocial_prefixes (const char *file_name)
68 while (*file_name == '/'
69 || !memcmp (file_name, "./", 2)
70 || !memcmp (file_name, "../", 3))
71 file_name = strchr (file_name, '/') + 1;
72 return *file_name == '\0' || !strcmp (file_name, "..") ? "." : file_name;
75 /* Composes HEADER as a USTAR_HEADER_SIZE (512)-byte archive
76 header in ustar format for a SIZE-byte file named FILE_NAME of
77 the given TYPE. The caller is responsible for writing the
78 header to a file or device.
80 If successful, returns true. On failure (due to an
81 excessively long file name), returns false. */
83 ustar_make_header (const char *file_name, enum ustar_type type,
84 int size, char header[USTAR_HEADER_SIZE])
86 struct ustar_header *h = (struct ustar_header *) header;
88 ASSERT (sizeof (struct ustar_header) == USTAR_HEADER_SIZE);
89 ASSERT (type == USTAR_REGULAR || type == USTAR_DIRECTORY);
91 /* Check file name. */
92 file_name = strip_antisocial_prefixes (file_name);
93 if (strlen (file_name) > 99)
95 printf ("%s: file name too long\n", file_name);
99 /* Fill in header except for final checksum. */
100 memset (h, 0, sizeof *h);
101 strlcpy (h->name, file_name, sizeof h->name);
102 snprintf (h->mode, sizeof h->mode, "%07o",
103 type == USTAR_REGULAR ? 0644 : 0755);
104 strlcpy (h->uid, "0000000", sizeof h->uid);
105 strlcpy (h->gid, "0000000", sizeof h->gid);
106 snprintf (h->size, sizeof h->size, "%011o", size);
107 snprintf (h->mtime, sizeof h->size, "%011o", 1136102400);
109 strlcpy (h->magic, "ustar", sizeof h->magic);
110 h->version[0] = h->version[1] = '0';
111 strlcpy (h->gname, "root", sizeof h->gname);
112 strlcpy (h->uname, "root", sizeof h->uname);
114 /* Compute and fill in final checksum. */
115 snprintf (h->chksum, sizeof h->chksum, "%07o", calculate_chksum (h));
120 /* Parses a SIZE-byte octal field in S in the format used by
121 ustar format. If successful, stores the field's value in
122 *VALUE and returns true; on failure, returns false.
124 ustar octal fields consist of a sequence of octal digits
125 terminated by a space or a null byte. The ustar specification
126 seems ambiguous as to whether these fields must be padded on
127 the left with '0's, so we accept any field that fits in the
128 available space, regardless of whether it fills the space. */
130 parse_octal_field (const char *s, size_t size, unsigned long int *value)
135 for (ofs = 0; ofs < size; ofs++)
138 if (c >= '0' && c <= '7')
140 if (*value > ULONG_MAX / 8)
145 *value = c - '0' + *value * 8;
147 else if (c == ' ' || c == '\0')
149 /* End of field, but disallow completely empty
160 /* Field did not end in space or null byte. */
164 /* Returns true if the CNT bytes starting at BLOCK are all zero,
167 is_all_zeros (const char *block, size_t cnt)
175 /* Parses HEADER as a ustar-format archive header for a regular
176 file or directory. If successful, stores the archived file's
177 name in *FILE_NAME (as a pointer into HEADER or a string
178 literal), its type in *TYPE, and its size in bytes in *SIZE,
179 and returns a null pointer. On failure, returns a
180 human-readable error message. */
182 ustar_parse_header (const char header[USTAR_HEADER_SIZE],
183 const char **file_name, enum ustar_type *type, int *size)
185 const struct ustar_header *h = (const struct ustar_header *) header;
186 unsigned long int chksum, size_ul;
188 ASSERT (sizeof (struct ustar_header) == USTAR_HEADER_SIZE);
190 /* Detect end of archive. */
191 if (is_all_zeros (header, USTAR_HEADER_SIZE))
199 /* Validate ustar header. */
200 if (memcmp (h->magic, "ustar", 6))
201 return "not a ustar archive";
202 else if (h->version[0] != '0' || h->version[1] != '0')
203 return "invalid ustar version";
204 else if (!parse_octal_field (h->chksum, sizeof h->chksum, &chksum))
205 return "corrupt chksum field";
206 else if (chksum != calculate_chksum (h))
207 return "checksum mismatch";
208 else if (h->name[sizeof h->name - 1] != '\0' || h->prefix[0] != '\0')
209 return "file name too long";
210 else if (h->typeflag != USTAR_REGULAR && h->typeflag != USTAR_DIRECTORY)
211 return "unimplemented file type";
212 if (h->typeflag == USTAR_REGULAR)
214 if (!parse_octal_field (h->size, sizeof h->size, &size_ul))
215 return "corrupt file size field";
216 else if (size_ul > INT_MAX)
217 return "file too large";
223 *file_name = strip_antisocial_prefixes (h->name);