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;
70 const char *archive_format_name;
71 struct mtree_entry *entries;
72 struct mtree_entry *this_entry;
73 struct archive_string current_dir;
74 struct archive_string contents_name;
77 static int cleanup(struct archive_read *);
78 static int mtree_bid(struct archive_read *);
79 static void parse_escapes(char *, struct mtree_entry *);
80 static int parse_setting(struct archive_read *, struct mtree *,
81 struct archive_entry *, char *, char *);
82 static int read_data(struct archive_read *a,
83 const void **buff, size_t *size, off_t *offset);
84 static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
85 static int skip(struct archive_read *a);
86 static int read_header(struct archive_read *,
87 struct archive_entry *);
88 static int64_t mtree_atol10(char **);
89 static int64_t mtree_atol8(char **);
92 archive_read_support_format_mtree(struct archive *_a)
94 struct archive_read *a = (struct archive_read *)_a;
98 mtree = (struct mtree *)malloc(sizeof(*mtree));
100 archive_set_error(&a->archive, ENOMEM,
101 "Can't allocate mtree data");
102 return (ARCHIVE_FATAL);
104 memset(mtree, 0, sizeof(*mtree));
107 r = __archive_read_register_format(a, mtree,
108 mtree_bid, read_header, read_data, skip, cleanup);
116 cleanup(struct archive_read *a)
119 struct mtree_entry *p, *q;
121 mtree = (struct mtree *)(a->format->data);
127 * Note: option_start, option_end are pointers into
128 * the block that p->name points to. So we should
129 * not try to free them!
134 archive_string_free(&mtree->line);
135 archive_string_free(&mtree->current_dir);
136 archive_string_free(&mtree->contents_name);
139 (a->format->data) = NULL;
145 mtree_bid(struct archive_read *a)
150 const char *signature = "#mtree";
154 mtree = (struct mtree *)(a->format->data);
156 /* Now let's look at the actual header and see if it matches. */
157 bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
164 while (bytes_read > 0 && *signature != '\0') {
165 if (*p != *signature)
176 * The extended mtree format permits multiple lines specifying
177 * attributes for each file. Practically speaking, that means we have
178 * to read the entire mtree file into memory up front.
181 read_mtree(struct archive_read *a, struct mtree *mtree)
185 struct mtree_entry *mentry;
186 struct mtree_entry *last_mentry = NULL;
188 mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1;
189 mtree->archive_format_name = "mtree";
192 len = readline(a, mtree, &p, 256);
194 mtree->this_entry = mtree->entries;
199 /* Leading whitespace is never significant, ignore it. */
200 while (*p == ' ' || *p == '\t') {
204 /* Skip content lines and blank lines. */
207 if (*p == '\r' || *p == '\n' || *p == '\0')
209 mentry = malloc(sizeof(*mentry));
210 if (mentry == NULL) {
211 archive_set_error(&a->archive, ENOMEM,
212 "Can't allocate memory");
213 return (ARCHIVE_FATAL);
215 memset(mentry, 0, sizeof(*mentry));
216 /* Add this entry to list. */
217 if (last_mentry == NULL) {
218 last_mentry = mtree->entries = mentry;
220 last_mentry->next = mentry;
222 last_mentry = mentry;
224 /* Copy line over onto heap. */
225 mentry->name = malloc(len + 1);
226 if (mentry->name == NULL) {
228 archive_set_error(&a->archive, ENOMEM,
229 "Can't allocate memory");
230 return (ARCHIVE_FATAL);
232 strcpy(mentry->name, p);
233 mentry->option_end = mentry->name + len;
234 /* Find end of name. */
236 while (*p != ' ' && *p != '\n' && *p != '\0')
239 parse_escapes(mentry->name, mentry);
240 /* Find start of options and record it. */
241 while (p < mentry->option_end && (*p == ' ' || *p == '\t'))
243 mentry->option_start = p;
244 /* Null terminate each separate option. */
245 while (++p < mentry->option_end)
246 if (*p == ' ' || *p == '\t' || *p == '\n')
252 read_header(struct archive_read *a, struct archive_entry *entry)
256 struct mtree_entry *mentry, *mentry2;
258 int r = ARCHIVE_OK, r1;
260 mtree = (struct mtree *)(a->format->data);
262 if (mtree->fd >= 0) {
267 if (mtree->entries == NULL) {
268 r = read_mtree(a, mtree);
273 a->archive.archive_format = mtree->archive_format;
274 a->archive.archive_format_name = mtree->archive_format_name;
277 mentry = mtree->this_entry;
278 if (mentry == NULL) {
279 mtree->this_entry = NULL;
280 return (ARCHIVE_EOF);
282 mtree->this_entry = mentry->next;
286 if (strcmp(mentry->name, "..") == 0) {
287 if (archive_strlen(&mtree->current_dir) > 0) {
288 /* Roll back current path. */
289 p = mtree->current_dir.s
290 + mtree->current_dir.length - 1;
291 while (p >= mtree->current_dir.s && *p != '/')
293 if (p >= mtree->current_dir.s)
295 mtree->current_dir.length
296 = p - mtree->current_dir.s + 1;
301 mtree->filetype = AE_IFREG;
304 p = mentry->option_start;
305 while (p < mentry->option_end) {
307 r1 = parse_setting(a, mtree, entry, p, q);
308 if (r1 != ARCHIVE_OK)
314 archive_entry_copy_pathname(entry, mentry->name);
316 * "Full" entries are allowed to have multiple
317 * lines and those lines aren't required to be
318 * adjacent. We don't support multiple lines
319 * for "relative" entries nor do we make any
320 * attempt to merge data from separate
321 * "relative" and "full" entries. (Merging
322 * "relative" and "full" entries would require
323 * dealing with pathname canonicalization,
324 * which is a very tricky subject.)
326 mentry2 = mentry->next;
327 while (mentry2 != NULL) {
330 && strcmp(mentry->name, mentry2->name) == 0) {
332 * Add those options as well;
333 * later lines override
336 p = mentry2->option_start;
337 while (p < mentry2->option_end) {
339 r1 = parse_setting(a, mtree, entry, p, q);
340 if (r1 != ARCHIVE_OK)
346 mentry2 = mentry2->next;
350 * Relative entries require us to construct
351 * the full path and possibly update the
354 size_t n = archive_strlen(&mtree->current_dir);
356 archive_strcat(&mtree->current_dir, "/");
357 archive_strcat(&mtree->current_dir, mentry->name);
358 archive_entry_copy_pathname(entry, mtree->current_dir.s);
359 if (archive_entry_filetype(entry) != AE_IFDIR)
360 mtree->current_dir.length = n;
364 * Try to open and stat the file to get the real size.
365 * It would be nice to avoid this here so that getting
366 * a listing of an mtree wouldn't require opening
367 * every referenced contents file. But then we
368 * wouldn't know the actual contents size, so I don't
369 * see a really viable way around this. (Also, we may
370 * want to someday pull other unspecified info from
371 * the contents file on disk.)
373 if (archive_strlen(&mtree->contents_name) > 0) {
374 mtree->fd = open(mtree->contents_name.s, O_RDONLY);
376 archive_set_error(&a->archive, errno,
377 "Can't open content=\"%s\"",
378 mtree->contents_name.s);
382 /* If the specified path opens, use it. */
383 mtree->fd = open(mtree->current_dir.s, O_RDONLY);
384 /* But don't fail if it's not there. */
388 * If there is a contents file on disk, use that size;
389 * otherwise leave it as-is (it might have been set from
390 * the mtree size= keyword).
392 if (mtree->fd >= 0) {
393 fstat(mtree->fd, &st);
394 archive_entry_set_size(entry, st.st_size);
402 parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, char *key, char *end)
412 val = strchr(key, '=');
414 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
415 "Malformed attribute \"%s\" (%d)", key, key[0]);
416 return (ARCHIVE_WARN);
424 if (strcmp(key, "content") == 0) {
425 parse_escapes(val, NULL);
426 archive_strcpy(&mtree->contents_name, val);
430 if (strcmp(key, "gid") == 0) {
431 archive_entry_set_gid(entry, mtree_atol10(&val));
434 if (strcmp(key, "gname") == 0) {
435 archive_entry_copy_gname(entry, val);
439 if (strcmp(key, "mode") == 0) {
441 archive_entry_set_perm(entry,
444 archive_set_error(&a->archive,
445 ARCHIVE_ERRNO_FILE_FORMAT,
446 "Symbolic mode \"%s\" unsupported", val);
450 if (strcmp(key, "type") == 0) {
453 if (strcmp(val, "block") == 0) {
454 mtree->filetype = AE_IFBLK;
458 if (strcmp(val, "char") == 0) {
459 mtree->filetype = AE_IFCHR;
463 if (strcmp(val, "dir") == 0) {
464 mtree->filetype = AE_IFDIR;
468 if (strcmp(val, "fifo") == 0) {
469 mtree->filetype = AE_IFIFO;
472 if (strcmp(val, "file") == 0) {
473 mtree->filetype = AE_IFREG;
477 if (strcmp(val, "link") == 0) {
478 mtree->filetype = AE_IFLNK;
482 archive_set_error(&a->archive,
483 ARCHIVE_ERRNO_FILE_FORMAT,
484 "Unrecognized file type \"%s\"", val);
485 return (ARCHIVE_WARN);
487 archive_entry_set_filetype(entry, mtree->filetype);
490 if (strcmp(key, "time") == 0) {
491 archive_entry_set_mtime(entry, mtree_atol10(&val), 0);
495 if (strcmp(key, "uid") == 0) {
496 archive_entry_set_uid(entry, mtree_atol10(&val));
499 if (strcmp(key, "uname") == 0) {
500 archive_entry_copy_uname(entry, val);
504 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
505 "Unrecognized key %s=%s", key, val);
506 return (ARCHIVE_WARN);
512 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
517 mtree = (struct mtree *)(a->format->data);
522 return (ARCHIVE_EOF);
524 if (mtree->buff == NULL) {
525 mtree->buffsize = 64 * 1024;
526 mtree->buff = malloc(mtree->buffsize);
527 if (mtree->buff == NULL) {
528 archive_set_error(&a->archive, ENOMEM,
529 "Can't allocate memory");
534 *offset = mtree->offset;
535 bytes_read = read(mtree->fd, mtree->buff, mtree->buffsize);
536 if (bytes_read < 0) {
537 archive_set_error(&a->archive, errno, "Can't read");
538 return (ARCHIVE_WARN);
540 if (bytes_read == 0) {
542 return (ARCHIVE_EOF);
544 mtree->offset += bytes_read;
545 *size = (size_t)bytes_read;
549 /* Skip does nothing except possibly close the contents file. */
551 skip(struct archive_read *a)
555 mtree = (struct mtree *)(a->format->data);
556 if (mtree->fd >= 0) {
564 * Since parsing octal escapes always makes strings shorter,
565 * we can always do this conversion in-place.
568 parse_escapes(char *src, struct mtree_entry *mentry)
573 while (*src != '\0') {
575 if (c == '/' && mentry != NULL)
578 if (src[0] >= '0' && src[0] <= '3'
579 && src[1] >= '0' && src[1] <= '7'
580 && src[2] >= '0' && src[2] <= '7') {
581 c = (src[0] - '0') << 6;
582 c |= (src[1] - '0') << 3;
593 * Note that this implementation does not (and should not!) obey
594 * locale settings; you cannot simply substitute strtol here, since
595 * it does obey locale.
598 mtree_atol8(char **p)
600 int64_t l, limit, last_digit_limit;
604 limit = INT64_MAX / base;
605 last_digit_limit = INT64_MAX % base;
609 while (digit >= 0 && digit < base) {
610 if (l>limit || (l == limit && digit > last_digit_limit)) {
611 l = INT64_MAX; /* Truncate on overflow. */
614 l = (l * base) + digit;
615 digit = *++(*p) - '0';
621 * Note that this implementation does not (and should not!) obey
622 * locale settings; you cannot simply substitute strtol here, since
623 * it does obey locale.
626 mtree_atol10(char **p)
628 int64_t l, limit, last_digit_limit;
629 int base, digit, sign;
632 limit = INT64_MAX / base;
633 last_digit_limit = INT64_MAX % base;
643 while (digit >= 0 && digit < base) {
644 if (l > limit || (l == limit && digit > last_digit_limit)) {
645 l = UINT64_MAX; /* Truncate on overflow. */
648 l = (l * base) + digit;
649 digit = *++(*p) - '0';
651 return (sign < 0) ? -l : l;
655 * Returns length of line (including trailing newline)
656 * or negative on error. 'start' argument is updated to
657 * point to first character of line.
660 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
663 ssize_t total_size = 0;
668 /* Accumulate line in a line buffer. */
670 /* Read some more. */
671 bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
675 return (ARCHIVE_FATAL);
676 s = t; /* Start of line? */
677 p = memchr(t, '\n', bytes_read);
678 /* If we found '\n', trim the read. */
680 bytes_read = 1 + ((const char *)p) - s;
682 if (total_size + bytes_read + 1 > limit) {
683 archive_set_error(&a->archive,
684 ARCHIVE_ERRNO_FILE_FORMAT,
686 return (ARCHIVE_FATAL);
688 if (archive_string_ensure(&mtree->line,
689 total_size + bytes_read + 1) == NULL) {
690 archive_set_error(&a->archive, ENOMEM,
691 "Can't allocate working buffer");
692 return (ARCHIVE_FATAL);
694 memcpy(mtree->line.s + total_size, t, bytes_read);
695 (a->decompressor->consume)(a, bytes_read);
696 total_size += bytes_read;
697 /* Null terminate. */
698 mtree->line.s[total_size] = '\0';
699 /* If we found '\n', clean up and return. */
701 *start = mtree->line.s;