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"
58 struct mtree_entry *next;
67 struct archive_string line;
74 const char *archive_format_name;
75 struct mtree_entry *entries;
76 struct mtree_entry *this_entry;
77 struct archive_string current_dir;
78 struct archive_string contents_name;
80 off_t cur_size, cur_offset;
83 static int cleanup(struct archive_read *);
84 static int mtree_bid(struct archive_read *);
85 static int parse_file(struct archive_read *, struct archive_entry *,
86 struct mtree *, struct mtree_entry *);
87 static void parse_escapes(char *, struct mtree_entry *);
88 static int parse_line(struct archive_read *, struct archive_entry *,
89 struct mtree *, struct mtree_entry *);
90 static int parse_keyword(struct archive_read *, struct mtree *,
91 struct archive_entry *, char *, char *);
92 static int read_data(struct archive_read *a,
93 const void **buff, size_t *size, off_t *offset);
94 static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
95 static int skip(struct archive_read *a);
96 static int read_header(struct archive_read *,
97 struct archive_entry *);
98 static int64_t mtree_atol10(char **);
99 static int64_t mtree_atol8(char **);
102 archive_read_support_format_mtree(struct archive *_a)
104 struct archive_read *a = (struct archive_read *)_a;
108 mtree = (struct mtree *)malloc(sizeof(*mtree));
110 archive_set_error(&a->archive, ENOMEM,
111 "Can't allocate mtree data");
112 return (ARCHIVE_FATAL);
114 memset(mtree, 0, sizeof(*mtree));
117 r = __archive_read_register_format(a, mtree,
118 mtree_bid, read_header, read_data, skip, cleanup);
126 cleanup(struct archive_read *a)
129 struct mtree_entry *p, *q;
131 mtree = (struct mtree *)(a->format->data);
137 * Note: option_start, option_end are pointers into
138 * the block that p->name points to. So we should
139 * not try to free them!
144 archive_string_free(&mtree->line);
145 archive_string_free(&mtree->current_dir);
146 archive_string_free(&mtree->contents_name);
149 (a->format->data) = NULL;
155 mtree_bid(struct archive_read *a)
160 const char *signature = "#mtree";
164 mtree = (struct mtree *)(a->format->data);
166 /* Now let's look at the actual header and see if it matches. */
167 bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
174 while (bytes_read > 0 && *signature != '\0') {
175 if (*p != *signature)
186 * The extended mtree format permits multiple lines specifying
187 * attributes for each file. Practically speaking, that means we have
188 * to read the entire mtree file into memory up front.
191 read_mtree(struct archive_read *a, struct mtree *mtree)
195 struct mtree_entry *mentry;
196 struct mtree_entry *last_mentry = NULL;
198 mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1;
199 mtree->archive_format_name = "mtree";
202 len = readline(a, mtree, &p, 256);
204 mtree->this_entry = mtree->entries;
209 /* Leading whitespace is never significant, ignore it. */
210 while (*p == ' ' || *p == '\t') {
214 /* Skip content lines and blank lines. */
217 if (*p == '\r' || *p == '\n' || *p == '\0')
219 mentry = malloc(sizeof(*mentry));
220 if (mentry == NULL) {
221 archive_set_error(&a->archive, ENOMEM,
222 "Can't allocate memory");
223 return (ARCHIVE_FATAL);
225 memset(mentry, 0, sizeof(*mentry));
226 /* Add this entry to list. */
227 if (last_mentry == NULL) {
228 last_mentry = mtree->entries = mentry;
230 last_mentry->next = mentry;
232 last_mentry = mentry;
234 /* Copy line over onto heap. */
235 mentry->name = malloc(len + 1);
236 if (mentry->name == NULL) {
238 archive_set_error(&a->archive, ENOMEM,
239 "Can't allocate memory");
240 return (ARCHIVE_FATAL);
242 strcpy(mentry->name, p);
243 mentry->option_end = mentry->name + len;
244 /* Find end of name. */
246 while (*p != ' ' && *p != '\n' && *p != '\0')
249 parse_escapes(mentry->name, mentry);
250 /* Find start of options and record it. */
251 while (p < mentry->option_end && (*p == ' ' || *p == '\t'))
253 mentry->option_start = p;
254 /* Null terminate each separate option. */
255 while (++p < mentry->option_end)
256 if (*p == ' ' || *p == '\t' || *p == '\n')
262 * Read in the entire mtree file into memory on the first request.
263 * Then use the next unused file to satisfy each header request.
266 read_header(struct archive_read *a, struct archive_entry *entry)
272 mtree = (struct mtree *)(a->format->data);
274 if (mtree->fd >= 0) {
279 if (mtree->entries == NULL) {
280 r = read_mtree(a, mtree);
285 a->archive.archive_format = mtree->archive_format;
286 a->archive.archive_format_name = mtree->archive_format_name;
289 if (mtree->this_entry == NULL)
290 return (ARCHIVE_EOF);
291 if (strcmp(mtree->this_entry->name, "..") == 0) {
292 mtree->this_entry->used = 1;
293 if (archive_strlen(&mtree->current_dir) > 0) {
294 /* Roll back current path. */
295 p = mtree->current_dir.s
296 + mtree->current_dir.length - 1;
297 while (p >= mtree->current_dir.s && *p != '/')
299 if (p >= mtree->current_dir.s)
301 mtree->current_dir.length
302 = p - mtree->current_dir.s + 1;
305 if (!mtree->this_entry->used) {
306 r = parse_file(a, entry, mtree, mtree->this_entry);
309 mtree->this_entry = mtree->this_entry->next;
314 * A single file can have multiple lines contribute specifications.
315 * Parse as many lines as necessary, then pull additional information
316 * from a backing file on disk as necessary.
319 parse_file(struct archive_read *a, struct archive_entry *entry,
320 struct mtree *mtree, struct mtree_entry *mentry)
323 struct mtree_entry *mp;
324 int r = ARCHIVE_OK, r1;
328 /* Initialize reasonable defaults. */
329 mtree->filetype = AE_IFREG;
330 archive_entry_set_size(entry, 0);
332 /* Parse options from this line. */
333 r = parse_line(a, entry, mtree, mentry);
336 archive_entry_copy_pathname(entry, mentry->name);
338 * "Full" entries are allowed to have multiple lines
339 * and those lines aren't required to be adjacent. We
340 * don't support multiple lines for "relative" entries
341 * nor do we make any attempt to merge data from
342 * separate "relative" and "full" entries. (Merging
343 * "relative" and "full" entries would require dealing
344 * with pathname canonicalization, which is a very
347 for (mp = mentry->next; mp != NULL; mp = mp->next) {
348 if (mp->full && !mp->used
349 && strcmp(mentry->name, mp->name) == 0) {
350 /* Later lines override earlier ones. */
352 r1 = parse_line(a, entry, mtree, mp);
359 * Relative entries require us to construct
360 * the full path and possibly update the
363 size_t n = archive_strlen(&mtree->current_dir);
365 archive_strcat(&mtree->current_dir, "/");
366 archive_strcat(&mtree->current_dir, mentry->name);
367 archive_entry_copy_pathname(entry, mtree->current_dir.s);
368 if (archive_entry_filetype(entry) != AE_IFDIR)
369 mtree->current_dir.length = n;
373 * Try to open and stat the file to get the real size
374 * and other file info. It would be nice to avoid
375 * this here so that getting a listing of an mtree
376 * wouldn't require opening every referenced contents
377 * file. But then we wouldn't know the actual
378 * contents size, so I don't see a really viable way
379 * around this. (Also, we may want to someday pull
380 * other unspecified info from the contents file on
384 if (archive_strlen(&mtree->contents_name) > 0) {
385 mtree->fd = open(mtree->contents_name.s,
386 O_RDONLY | O_BINARY);
388 archive_set_error(&a->archive, errno,
389 "Can't open content=\"%s\"",
390 mtree->contents_name.s);
393 } else if (archive_entry_filetype(entry) == AE_IFREG) {
394 mtree->fd = open(archive_entry_pathname(entry),
395 O_RDONLY | O_BINARY);
399 * If there is a contents file on disk, use that size;
400 * otherwise leave it as-is (it might have been set from
401 * the mtree size= keyword).
403 if (mtree->fd >= 0) {
404 if (fstat(mtree->fd, &st) != 0) {
405 archive_set_error(&a->archive, errno,
407 archive_entry_pathname(entry));
409 /* If we can't stat it, don't keep it open. */
412 } else if ((st.st_mode & S_IFMT) != S_IFREG) {
413 archive_set_error(&a->archive, errno,
414 "%s is not a regular file",
415 archive_entry_pathname(entry));
417 /* Don't hold a non-regular file open. */
421 archive_entry_set_size(entry, st.st_size);
422 archive_entry_set_ino(entry, st.st_ino);
423 archive_entry_set_dev(entry, st.st_dev);
424 archive_entry_set_nlink(entry, st.st_nlink);
427 mtree->cur_size = archive_entry_size(entry);
434 * Each line contains a sequence of keywords.
437 parse_line(struct archive_read *a, struct archive_entry *entry,
438 struct mtree *mtree, struct mtree_entry *mp)
441 int r = ARCHIVE_OK, r1;
443 p = mp->option_start;
444 while (p < mp->option_end) {
446 r1 = parse_keyword(a, mtree, entry, p, q);
455 * Parse a single keyword and its value.
458 parse_keyword(struct archive_read *a, struct mtree *mtree,
459 struct archive_entry *entry, char *key, char *end)
468 val = strchr(key, '=');
470 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
471 "Malformed attribute \"%s\" (%d)", key, key[0]);
472 return (ARCHIVE_WARN);
480 if (strcmp(key, "content") == 0
481 || strcmp(key, "contents") == 0) {
482 parse_escapes(val, NULL);
483 archive_strcpy(&mtree->contents_name, val);
487 if (strcmp(key, "gid") == 0) {
488 archive_entry_set_gid(entry, mtree_atol10(&val));
491 if (strcmp(key, "gname") == 0) {
492 archive_entry_copy_gname(entry, val);
496 if (strcmp(key, "link") == 0) {
497 archive_entry_set_link(entry, val);
501 if (strcmp(key, "mode") == 0) {
503 archive_entry_set_perm(entry,
506 archive_set_error(&a->archive,
507 ARCHIVE_ERRNO_FILE_FORMAT,
508 "Symbolic mode \"%s\" unsupported", val);
512 if (strcmp(key, "size") == 0) {
513 archive_entry_set_size(entry, mtree_atol10(&val));
517 if (strcmp(key, "type") == 0) {
520 if (strcmp(val, "block") == 0) {
521 mtree->filetype = AE_IFBLK;
525 if (strcmp(val, "char") == 0) {
526 mtree->filetype = AE_IFCHR;
530 if (strcmp(val, "dir") == 0) {
531 mtree->filetype = AE_IFDIR;
535 if (strcmp(val, "fifo") == 0) {
536 mtree->filetype = AE_IFIFO;
539 if (strcmp(val, "file") == 0) {
540 mtree->filetype = AE_IFREG;
544 if (strcmp(val, "link") == 0) {
545 mtree->filetype = AE_IFLNK;
549 archive_set_error(&a->archive,
550 ARCHIVE_ERRNO_FILE_FORMAT,
551 "Unrecognized file type \"%s\"", val);
552 return (ARCHIVE_WARN);
554 archive_entry_set_filetype(entry, mtree->filetype);
557 if (strcmp(key, "time") == 0) {
558 archive_entry_set_mtime(entry, mtree_atol10(&val), 0);
562 if (strcmp(key, "uid") == 0) {
563 archive_entry_set_uid(entry, mtree_atol10(&val));
566 if (strcmp(key, "uname") == 0) {
567 archive_entry_copy_uname(entry, val);
571 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
572 "Unrecognized key %s=%s", key, val);
573 return (ARCHIVE_WARN);
579 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
581 size_t bytes_to_read;
585 mtree = (struct mtree *)(a->format->data);
590 return (ARCHIVE_EOF);
592 if (mtree->buff == NULL) {
593 mtree->buffsize = 64 * 1024;
594 mtree->buff = malloc(mtree->buffsize);
595 if (mtree->buff == NULL) {
596 archive_set_error(&a->archive, ENOMEM,
597 "Can't allocate memory");
602 *offset = mtree->offset;
603 if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset)
604 bytes_to_read = mtree->cur_size - mtree->offset;
606 bytes_to_read = mtree->buffsize;
607 bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
608 if (bytes_read < 0) {
609 archive_set_error(&a->archive, errno, "Can't read");
610 return (ARCHIVE_WARN);
612 if (bytes_read == 0) {
614 return (ARCHIVE_EOF);
616 mtree->offset += bytes_read;
621 /* Skip does nothing except possibly close the contents file. */
623 skip(struct archive_read *a)
627 mtree = (struct mtree *)(a->format->data);
628 if (mtree->fd >= 0) {
636 * Since parsing octal escapes always makes strings shorter,
637 * we can always do this conversion in-place.
640 parse_escapes(char *src, struct mtree_entry *mentry)
645 while (*src != '\0') {
647 if (c == '/' && mentry != NULL)
650 if (src[0] >= '0' && src[0] <= '3'
651 && src[1] >= '0' && src[1] <= '7'
652 && src[2] >= '0' && src[2] <= '7') {
653 c = (src[0] - '0') << 6;
654 c |= (src[1] - '0') << 3;
665 * Note that this implementation does not (and should not!) obey
666 * locale settings; you cannot simply substitute strtol here, since
667 * it does obey locale.
670 mtree_atol8(char **p)
672 int64_t l, limit, last_digit_limit;
676 limit = INT64_MAX / base;
677 last_digit_limit = INT64_MAX % base;
681 while (digit >= 0 && digit < base) {
682 if (l>limit || (l == limit && digit > last_digit_limit)) {
683 l = INT64_MAX; /* Truncate on overflow. */
686 l = (l * base) + digit;
687 digit = *++(*p) - '0';
693 * Note that this implementation does not (and should not!) obey
694 * locale settings; you cannot simply substitute strtol here, since
695 * it does obey locale.
698 mtree_atol10(char **p)
700 int64_t l, limit, last_digit_limit;
701 int base, digit, sign;
704 limit = INT64_MAX / base;
705 last_digit_limit = INT64_MAX % base;
715 while (digit >= 0 && digit < base) {
716 if (l > limit || (l == limit && digit > last_digit_limit)) {
717 l = UINT64_MAX; /* Truncate on overflow. */
720 l = (l * base) + digit;
721 digit = *++(*p) - '0';
723 return (sign < 0) ? -l : l;
727 * Returns length of line (including trailing newline)
728 * or negative on error. 'start' argument is updated to
729 * point to first character of line.
732 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
735 ssize_t total_size = 0;
740 /* Accumulate line in a line buffer. */
742 /* Read some more. */
743 bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
747 return (ARCHIVE_FATAL);
748 s = t; /* Start of line? */
749 p = memchr(t, '\n', bytes_read);
750 /* If we found '\n', trim the read. */
752 bytes_read = 1 + ((const char *)p) - s;
754 if (total_size + bytes_read + 1 > limit) {
755 archive_set_error(&a->archive,
756 ARCHIVE_ERRNO_FILE_FORMAT,
758 return (ARCHIVE_FATAL);
760 if (archive_string_ensure(&mtree->line,
761 total_size + bytes_read + 1) == NULL) {
762 archive_set_error(&a->archive, ENOMEM,
763 "Can't allocate working buffer");
764 return (ARCHIVE_FATAL);
766 memcpy(mtree->line.s + total_size, t, bytes_read);
767 (a->decompressor->consume)(a, bytes_read);
768 total_size += bytes_read;
769 /* Null terminate. */
770 mtree->line.s[total_size] = '\0';
771 /* If we found '\n', clean up and return. */
773 *start = mtree->line.s;