2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
29 #ifdef HAVE_SYS_STAT_H
39 /* #include <stdint.h> */ /* See archive_platform.h */
48 #include "archive_entry.h"
49 #include "archive_private.h"
50 #include "archive_read_private.h"
51 #include "archive_string.h"
54 struct mtree_entry *next;
63 struct archive_string line;
71 const char *archive_format_name;
72 struct mtree_entry *entries;
73 struct mtree_entry *this_entry;
74 struct archive_string current_dir;
75 struct archive_string contents_name;
78 static int bid(struct archive_read *);
79 static int cleanup(struct archive_read *);
80 static void parse_escapes(char *, struct mtree_entry *);
81 static int parse_setting(struct archive_read *, struct mtree *,
82 struct archive_entry *, char *, char *);
83 static int read_data(struct archive_read *a,
84 const void **buff, size_t *size, off_t *offset);
85 static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
86 static int skip(struct archive_read *a);
87 static int read_header(struct archive_read *,
88 struct archive_entry *);
89 static int64_t mtree_atol10(char **);
90 static int64_t mtree_atol8(char **);
93 archive_read_support_format_mtree(struct archive *_a)
95 struct archive_read *a = (struct archive_read *)_a;
99 mtree = (struct mtree *)malloc(sizeof(*mtree));
101 archive_set_error(&a->archive, ENOMEM,
102 "Can't allocate mtree data");
103 return (ARCHIVE_FATAL);
105 memset(mtree, 0, sizeof(*mtree));
109 r = __archive_read_register_format(a, mtree,
110 bid, read_header, read_data, skip, cleanup);
118 cleanup(struct archive_read *a)
121 struct mtree_entry *p, *q;
123 mtree = (struct mtree *)(a->format->data);
129 * Note: option_start, option_end are pointers into
130 * the block that p->name points to. So we should
131 * not try to free them!
136 archive_string_free(&mtree->line);
137 archive_string_free(&mtree->current_dir);
138 archive_string_free(&mtree->contents_name);
141 (a->format->data) = NULL;
147 bid(struct archive_read *a)
152 const char *signature = "#mtree";
155 mtree = (struct mtree *)(a->format->data);
156 if (mtree->bid != -1)
159 /* Now let's look at the actual header and see if it matches. */
160 bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
167 while (bytes_read > 0 && *signature != '\0') {
168 if (*p != *signature)
169 return (mtree->bid = 0);
179 * The extended mtree format permits multiple lines specifying
180 * attributes for each file. Practically speaking, that means we have
181 * to read the entire mtree file into memory up front.
184 read_mtree(struct archive_read *a, struct mtree *mtree)
188 struct mtree_entry *mentry;
189 struct mtree_entry *last_mentry = NULL;
191 mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1;
192 mtree->archive_format_name = "mtree";
195 len = readline(a, mtree, &p, 256);
197 mtree->this_entry = mtree->entries;
202 /* Leading whitespace is never significant, ignore it. */
203 while (*p == ' ' || *p == '\t') {
207 /* Skip content lines and blank lines. */
210 if (*p == '\r' || *p == '\n' || *p == '\0')
212 mentry = malloc(sizeof(*mentry));
213 if (mentry == NULL) {
214 archive_set_error(&a->archive, ENOMEM,
215 "Can't allocate memory");
216 return (ARCHIVE_FATAL);
218 memset(mentry, 0, sizeof(*mentry));
219 /* Add this entry to list. */
220 if (last_mentry == NULL) {
221 last_mentry = mtree->entries = mentry;
223 last_mentry->next = mentry;
225 last_mentry = mentry;
227 /* Copy line over onto heap. */
228 mentry->name = malloc(len + 1);
229 if (mentry->name == NULL) {
231 archive_set_error(&a->archive, ENOMEM,
232 "Can't allocate memory");
233 return (ARCHIVE_FATAL);
235 strcpy(mentry->name, p);
236 mentry->option_end = mentry->name + len;
237 /* Find end of name. */
239 while (*p != ' ' && *p != '\n' && *p != '\0')
242 parse_escapes(mentry->name, mentry);
243 /* Find start of options and record it. */
244 while (p < mentry->option_end && (*p == ' ' || *p == '\t'))
246 mentry->option_start = p;
247 /* Null terminate each separate option. */
248 while (++p < mentry->option_end)
249 if (*p == ' ' || *p == '\t' || *p == '\n')
255 read_header(struct archive_read *a, struct archive_entry *entry)
259 struct mtree_entry *mentry, *mentry2;
261 int r = ARCHIVE_OK, r1;
263 mtree = (struct mtree *)(a->format->data);
265 if (mtree->fd >= 0) {
270 if (mtree->entries == NULL) {
271 r = read_mtree(a, mtree);
276 a->archive.archive_format = mtree->archive_format;
277 a->archive.archive_format_name = mtree->archive_format_name;
280 mentry = mtree->this_entry;
281 if (mentry == NULL) {
282 mtree->this_entry = NULL;
283 return (ARCHIVE_EOF);
285 mtree->this_entry = mentry->next;
289 if (strcmp(mentry->name, "..") == 0) {
290 if (archive_strlen(&mtree->current_dir) > 0) {
291 /* Roll back current path. */
292 p = mtree->current_dir.s
293 + mtree->current_dir.length - 1;
294 while (p >= mtree->current_dir.s && *p != '/')
296 if (p >= mtree->current_dir.s)
298 mtree->current_dir.length
299 = p - mtree->current_dir.s + 1;
304 mtree->filetype = AE_IFREG;
307 p = mentry->option_start;
308 while (p < mentry->option_end) {
310 r1 = parse_setting(a, mtree, entry, p, q);
311 if (r1 != ARCHIVE_OK)
317 archive_entry_copy_pathname(entry, mentry->name);
319 * "Full" entries are allowed to have multiple
320 * lines and those lines aren't required to be
321 * adjacent. We don't support multiple lines
322 * for "relative" entries nor do we make any
323 * attempt to merge data from separate
324 * "relative" and "full" entries. (Merging
325 * "relative" and "full" entries would require
326 * dealing with pathname canonicalization,
327 * which is a very tricky subject.)
329 mentry2 = mentry->next;
330 while (mentry2 != NULL) {
333 && strcmp(mentry->name, mentry2->name) == 0) {
335 * Add those options as well;
336 * later lines override
339 p = mentry2->option_start;
340 while (p < mentry2->option_end) {
342 r1 = parse_setting(a, mtree, entry, p, q);
343 if (r1 != ARCHIVE_OK)
349 mentry2 = mentry2->next;
353 * Relative entries require us to construct
354 * the full path and possibly update the
357 size_t n = archive_strlen(&mtree->current_dir);
359 archive_strcat(&mtree->current_dir, "/");
360 archive_strcat(&mtree->current_dir, mentry->name);
361 archive_entry_copy_pathname(entry, mtree->current_dir.s);
362 if (archive_entry_filetype(entry) != AE_IFDIR)
363 mtree->current_dir.length = n;
367 * Try to open and stat the file to get the real size.
368 * It would be nice to avoid this here so that getting
369 * a listing of an mtree wouldn't require opening
370 * every referenced contents file. But then we
371 * wouldn't know the actual contents size, so I don't
372 * see a really viable way around this. (Also, we may
373 * want to someday pull other unspecified info from
374 * the contents file on disk.)
376 if (archive_strlen(&mtree->contents_name) > 0) {
377 mtree->fd = open(mtree->contents_name.s, O_RDONLY);
379 archive_set_error(&a->archive, errno,
380 "Can't open content=\"%s\"",
381 mtree->contents_name.s);
385 /* If the specified path opens, use it. */
386 mtree->fd = open(mtree->current_dir.s, O_RDONLY);
387 /* But don't fail if it's not there. */
391 * If there is a contents file on disk, use that size;
392 * otherwise leave it as-is (it might have been set from
393 * the mtree size= keyword).
395 if (mtree->fd >= 0) {
396 fstat(mtree->fd, &st);
397 archive_entry_set_size(entry, st.st_size);
405 parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, char *key, char *end)
415 val = strchr(key, '=');
417 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
418 "Malformed attribute \"%s\" (%d)", key, key[0]);
419 return (ARCHIVE_WARN);
427 if (strcmp(key, "content") == 0) {
428 parse_escapes(val, NULL);
429 archive_strcpy(&mtree->contents_name, val);
433 if (strcmp(key, "gid") == 0) {
434 archive_entry_set_gid(entry, mtree_atol10(&val));
437 if (strcmp(key, "gname") == 0) {
438 archive_entry_copy_gname(entry, val);
442 if (strcmp(key, "mode") == 0) {
444 archive_entry_set_perm(entry,
447 archive_set_error(&a->archive,
448 ARCHIVE_ERRNO_FILE_FORMAT,
449 "Symbolic mode \"%s\" unsupported", val);
453 if (strcmp(key, "type") == 0) {
456 if (strcmp(val, "block") == 0) {
457 mtree->filetype = AE_IFBLK;
461 if (strcmp(val, "char") == 0) {
462 mtree->filetype = AE_IFCHR;
466 if (strcmp(val, "dir") == 0) {
467 mtree->filetype = AE_IFDIR;
471 if (strcmp(val, "fifo") == 0) {
472 mtree->filetype = AE_IFIFO;
475 if (strcmp(val, "file") == 0) {
476 mtree->filetype = AE_IFREG;
480 if (strcmp(val, "link") == 0) {
481 mtree->filetype = AE_IFLNK;
485 archive_set_error(&a->archive,
486 ARCHIVE_ERRNO_FILE_FORMAT,
487 "Unrecognized file type \"%s\"", val);
488 return (ARCHIVE_WARN);
490 archive_entry_set_filetype(entry, mtree->filetype);
493 if (strcmp(key, "time") == 0) {
494 archive_entry_set_mtime(entry, mtree_atol10(&val), 0);
498 if (strcmp(key, "uid") == 0) {
499 archive_entry_set_uid(entry, mtree_atol10(&val));
502 if (strcmp(key, "uname") == 0) {
503 archive_entry_copy_uname(entry, val);
507 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
508 "Unrecognized key %s=%s", key, val);
509 return (ARCHIVE_WARN);
515 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
520 mtree = (struct mtree *)(a->format->data);
525 return (ARCHIVE_EOF);
527 if (mtree->buff == NULL) {
528 mtree->buffsize = 64 * 1024;
529 mtree->buff = malloc(mtree->buffsize);
530 if (mtree->buff == NULL) {
531 archive_set_error(&a->archive, ENOMEM,
532 "Can't allocate memory");
537 *offset = mtree->offset;
538 bytes_read = read(mtree->fd, mtree->buff, mtree->buffsize);
539 if (bytes_read < 0) {
540 archive_set_error(&a->archive, errno, "Can't read");
541 return (ARCHIVE_WARN);
543 if (bytes_read == 0) {
545 return (ARCHIVE_EOF);
547 mtree->offset += bytes_read;
548 *size = (size_t)bytes_read;
552 /* Skip does nothing except possibly close the contents file. */
554 skip(struct archive_read *a)
558 mtree = (struct mtree *)(a->format->data);
559 if (mtree->fd >= 0) {
567 * Since parsing octal escapes always makes strings shorter,
568 * we can always do this conversion in-place.
571 parse_escapes(char *src, struct mtree_entry *mentry)
576 while (*src != '\0') {
578 if (c == '/' && mentry != NULL)
581 if (src[0] >= '0' && src[0] <= '3'
582 && src[1] >= '0' && src[1] <= '7'
583 && src[2] >= '0' && src[2] <= '7') {
584 c = (src[0] - '0') << 6;
585 c |= (src[1] - '0') << 3;
596 * Note that this implementation does not (and should not!) obey
597 * locale settings; you cannot simply substitute strtol here, since
598 * it does obey locale.
601 mtree_atol8(char **p)
603 int64_t l, limit, last_digit_limit;
607 limit = INT64_MAX / base;
608 last_digit_limit = INT64_MAX % base;
612 while (digit >= 0 && digit < base) {
613 if (l>limit || (l == limit && digit > last_digit_limit)) {
614 l = INT64_MAX; /* Truncate on overflow. */
617 l = (l * base) + digit;
618 digit = *++(*p) - '0';
624 * Note that this implementation does not (and should not!) obey
625 * locale settings; you cannot simply substitute strtol here, since
626 * it does obey locale.
629 mtree_atol10(char **p)
631 int64_t l, limit, last_digit_limit;
632 int base, digit, sign;
635 limit = INT64_MAX / base;
636 last_digit_limit = INT64_MAX % base;
646 while (digit >= 0 && digit < base) {
647 if (l > limit || (l == limit && digit > last_digit_limit)) {
648 l = UINT64_MAX; /* Truncate on overflow. */
651 l = (l * base) + digit;
652 digit = *++(*p) - '0';
654 return (sign < 0) ? -l : l;
658 * Returns length of line (including trailing newline)
659 * or negative on error. 'start' argument is updated to
660 * point to first character of line.
663 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
666 ssize_t total_size = 0;
671 /* Accumulate line in a line buffer. */
673 /* Read some more. */
674 bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
678 return (ARCHIVE_FATAL);
679 s = t; /* Start of line? */
680 p = memchr(t, '\n', bytes_read);
681 /* If we found '\n', trim the read. */
683 bytes_read = 1 + ((const char *)p) - s;
685 if (total_size + bytes_read + 1 > limit) {
686 archive_set_error(&a->archive,
687 ARCHIVE_ERRNO_FILE_FORMAT,
689 return (ARCHIVE_FATAL);
691 if (archive_string_ensure(&mtree->line,
692 total_size + bytes_read + 1) == NULL) {
693 archive_set_error(&a->archive, ENOMEM,
694 "Can't allocate working buffer");
695 return (ARCHIVE_FATAL);
697 memcpy(mtree->line.s + total_size, t, bytes_read);
698 (a->decompressor->consume)(a, bytes_read);
699 total_size += bytes_read;
700 /* Null terminate. */
701 mtree->line.s[total_size] = '\0';
702 /* If we found '\n', clean up and return. */
704 *start = mtree->line.s;