2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2008 Joerg Sonnenberger
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.9 2008/06/21 19:06:37 kientzle Exp $");
30 #ifdef HAVE_SYS_STAT_H
40 /* #include <stdint.h> */ /* See archive_platform.h */
49 #include "archive_entry.h"
50 #include "archive_private.h"
51 #include "archive_read_private.h"
52 #include "archive_string.h"
58 #define MTREE_HAS_DEVICE 0x0001
59 #define MTREE_HAS_FFLAGS 0x0002
60 #define MTREE_HAS_GID 0x0004
61 #define MTREE_HAS_GNAME 0x0008
62 #define MTREE_HAS_MTIME 0x0010
63 #define MTREE_HAS_NLINK 0x0020
64 #define MTREE_HAS_PERM 0x0040
65 #define MTREE_HAS_SIZE 0x0080
66 #define MTREE_HAS_TYPE 0x0100
67 #define MTREE_HAS_UID 0x0200
68 #define MTREE_HAS_UNAME 0x0400
70 #define MTREE_HAS_OPTIONAL 0x0800
73 struct mtree_option
*next
;
78 struct mtree_entry
*next
;
79 struct mtree_option
*options
;
86 struct archive_string line
;
93 const char *archive_format_name
;
94 struct mtree_entry
*entries
;
95 struct mtree_entry
*this_entry
;
96 struct archive_string current_dir
;
97 struct archive_string contents_name
;
99 struct archive_entry_linkresolver
*resolver
;
101 off_t cur_size
, cur_offset
;
104 static int cleanup(struct archive_read
*);
105 static int mtree_bid(struct archive_read
*);
106 static int parse_file(struct archive_read
*, struct archive_entry
*,
107 struct mtree
*, struct mtree_entry
*, int *);
108 static void parse_escapes(char *, struct mtree_entry
*);
109 static int parse_line(struct archive_read
*, struct archive_entry
*,
110 struct mtree
*, struct mtree_entry
*, int *);
111 static int parse_keyword(struct archive_read
*, struct mtree
*,
112 struct archive_entry
*, struct mtree_option
*, int *);
113 static int read_data(struct archive_read
*a
,
114 const void **buff
, size_t *size
, off_t
*offset
);
115 static ssize_t
readline(struct archive_read
*, struct mtree
*, char **, ssize_t
);
116 static int skip(struct archive_read
*a
);
117 static int read_header(struct archive_read
*,
118 struct archive_entry
*);
119 static int64_t mtree_atol10(char **);
120 static int64_t mtree_atol8(char **);
121 static int64_t mtree_atol(char **);
124 free_options(struct mtree_option
*head
)
126 struct mtree_option
*next
;
128 for (; head
!= NULL
; head
= next
) {
136 archive_read_support_format_mtree(struct archive
*_a
)
138 struct archive_read
*a
= (struct archive_read
*)_a
;
142 mtree
= (struct mtree
*)malloc(sizeof(*mtree
));
144 archive_set_error(&a
->archive
, ENOMEM
,
145 "Can't allocate mtree data");
146 return (ARCHIVE_FATAL
);
148 memset(mtree
, 0, sizeof(*mtree
));
151 r
= __archive_read_register_format(a
, mtree
,
152 mtree_bid
, read_header
, read_data
, skip
, cleanup
);
160 cleanup(struct archive_read
*a
)
163 struct mtree_entry
*p
, *q
;
165 mtree
= (struct mtree
*)(a
->format
->data
);
171 free_options(p
->options
);
175 archive_string_free(&mtree
->line
);
176 archive_string_free(&mtree
->current_dir
);
177 archive_string_free(&mtree
->contents_name
);
178 archive_entry_linkresolver_free(mtree
->resolver
);
182 (a
->format
->data
) = NULL
;
188 mtree_bid(struct archive_read
*a
)
193 const char *signature
= "#mtree";
197 mtree
= (struct mtree
*)(a
->format
->data
);
199 /* Now let's look at the actual header and see if it matches. */
200 bytes_read
= (a
->decompressor
->read_ahead
)(a
, &h
, strlen(signature
));
207 while (bytes_read
> 0 && *signature
!= '\0') {
208 if (*p
!= *signature
)
219 * The extended mtree format permits multiple lines specifying
220 * attributes for each file. For those entries, only the last line
221 * is actually used. Practically speaking, that means we have
222 * to read the entire mtree file into memory up front.
224 * The parsing is done in two steps. First, it is decided if a line
225 * changes the global defaults and if it is, processed accordingly.
226 * Otherwise, the options of the line are merged with the current
230 add_option(struct archive_read
*a
, struct mtree_option
**global
,
231 const char *value
, size_t len
)
233 struct mtree_option
*option
;
235 if ((option
= malloc(sizeof(*option
))) == NULL
) {
236 archive_set_error(&a
->archive
, errno
, "Can't allocate memory");
237 return (ARCHIVE_FATAL
);
239 if ((option
->value
= malloc(len
+ 1)) == NULL
) {
241 archive_set_error(&a
->archive
, errno
, "Can't allocate memory");
242 return (ARCHIVE_FATAL
);
244 memcpy(option
->value
, value
, len
);
245 option
->value
[len
] = '\0';
246 option
->next
= *global
;
252 remove_option(struct mtree_option
**global
, const char *value
, size_t len
)
254 struct mtree_option
*iter
, *last
;
257 for (iter
= *global
; iter
!= NULL
; last
= iter
, iter
= iter
->next
) {
258 if (strncmp(iter
->value
, value
, len
) == 0 &&
259 (iter
->value
[len
] == '\0' ||
260 iter
->value
[len
] == '='))
266 *global
= iter
->next
;
268 last
->next
= iter
->next
;
275 process_global_set(struct archive_read
*a
,
276 struct mtree_option
**global
, const char *line
)
278 const char *next
, *eq
;
284 next
= line
+ strspn(line
, " \t\r\n");
288 next
= line
+ strcspn(line
, " \t\r\n");
289 eq
= strchr(line
, '=');
295 remove_option(global
, line
, len
);
296 r
= add_option(a
, global
, line
, next
- line
);
304 process_global_unset(struct archive_read
*a
,
305 struct mtree_option
**global
, const char *line
)
311 if (strchr(line
, '=') != NULL
) {
312 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
313 "/unset shall not contain `='");
314 return ARCHIVE_FATAL
;
318 next
= line
+ strspn(line
, " \t\r\n");
322 len
= strcspn(line
, " \t\r\n");
324 if (len
== 3 && strncmp(line
, "all", 3) == 0) {
325 free_options(*global
);
328 remove_option(global
, line
, len
);
336 process_add_entry(struct archive_read
*a
, struct mtree
*mtree
,
337 struct mtree_option
**global
, const char *line
,
338 struct mtree_entry
**last_entry
)
340 struct mtree_entry
*entry
;
341 struct mtree_option
*iter
;
342 const char *next
, *eq
;
346 if ((entry
= malloc(sizeof(*entry
))) == NULL
) {
347 archive_set_error(&a
->archive
, errno
, "Can't allocate memory");
348 return (ARCHIVE_FATAL
);
351 entry
->options
= NULL
;
356 /* Add this entry to list. */
357 if (*last_entry
== NULL
)
358 mtree
->entries
= entry
;
360 (*last_entry
)->next
= entry
;
363 len
= strcspn(line
, " \t\r\n");
364 if ((entry
->name
= malloc(len
+ 1)) == NULL
) {
365 archive_set_error(&a
->archive
, errno
, "Can't allocate memory");
366 return (ARCHIVE_FATAL
);
369 memcpy(entry
->name
, line
, len
);
370 entry
->name
[len
] = '\0';
371 parse_escapes(entry
->name
, entry
);
374 for (iter
= *global
; iter
!= NULL
; iter
= iter
->next
) {
375 r
= add_option(a
, &entry
->options
, iter
->value
,
376 strlen(iter
->value
));
382 next
= line
+ strspn(line
, " \t\r\n");
386 next
= line
+ strcspn(line
, " \t\r\n");
387 eq
= strchr(line
, '=');
393 remove_option(&entry
->options
, line
, len
);
394 r
= add_option(a
, &entry
->options
, line
, next
- line
);
402 read_mtree(struct archive_read
*a
, struct mtree
*mtree
)
407 struct mtree_option
*global
;
408 struct mtree_entry
*last_entry
;
411 mtree
->archive_format
= ARCHIVE_FORMAT_MTREE_V1
;
412 mtree
->archive_format_name
= "mtree";
418 for (counter
= 1; ; ++counter
) {
419 len
= readline(a
, mtree
, &p
, 256);
421 mtree
->this_entry
= mtree
->entries
;
426 /* Leading whitespace is never significant, ignore it. */
427 while (*p
== ' ' || *p
== '\t') {
431 /* Skip content lines and blank lines. */
434 if (*p
== '\r' || *p
== '\n' || *p
== '\0')
437 r
= process_add_entry(a
, mtree
, &global
, p
,
439 } else if (strncmp(p
, "/set", 4) == 0) {
440 if (p
[4] != ' ' && p
[4] != '\t')
442 r
= process_global_set(a
, &global
, p
);
443 } else if (strncmp(p
, "/unset", 6) == 0) {
444 if (p
[6] != ' ' && p
[6] != '\t')
446 r
= process_global_unset(a
, &global
, p
);
454 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
455 "Can't parse line %ju", counter
);
456 return ARCHIVE_FATAL
;
460 * Read in the entire mtree file into memory on the first request.
461 * Then use the next unused file to satisfy each header request.
464 read_header(struct archive_read
*a
, struct archive_entry
*entry
)
470 mtree
= (struct mtree
*)(a
->format
->data
);
472 if (mtree
->fd
>= 0) {
477 if (mtree
->entries
== NULL
) {
478 mtree
->resolver
= archive_entry_linkresolver_new();
479 if (mtree
->resolver
== NULL
)
480 return ARCHIVE_FATAL
;
481 archive_entry_linkresolver_set_strategy(mtree
->resolver
,
482 ARCHIVE_FORMAT_MTREE
);
483 r
= read_mtree(a
, mtree
);
488 a
->archive
.archive_format
= mtree
->archive_format
;
489 a
->archive
.archive_format_name
= mtree
->archive_format_name
;
492 if (mtree
->this_entry
== NULL
)
493 return (ARCHIVE_EOF
);
494 if (strcmp(mtree
->this_entry
->name
, "..") == 0) {
495 mtree
->this_entry
->used
= 1;
496 if (archive_strlen(&mtree
->current_dir
) > 0) {
497 /* Roll back current path. */
498 p
= mtree
->current_dir
.s
499 + mtree
->current_dir
.length
- 1;
500 while (p
>= mtree
->current_dir
.s
&& *p
!= '/')
502 if (p
>= mtree
->current_dir
.s
)
504 mtree
->current_dir
.length
505 = p
- mtree
->current_dir
.s
+ 1;
508 if (!mtree
->this_entry
->used
) {
510 r
= parse_file(a
, entry
, mtree
, mtree
->this_entry
, &use_next
);
514 mtree
->this_entry
= mtree
->this_entry
->next
;
519 * A single file can have multiple lines contribute specifications.
520 * Parse as many lines as necessary, then pull additional information
521 * from a backing file on disk as necessary.
524 parse_file(struct archive_read
*a
, struct archive_entry
*entry
,
525 struct mtree
*mtree
, struct mtree_entry
*mentry
, int *use_next
)
528 struct stat st_storage
, *st
;
529 struct mtree_entry
*mp
;
530 struct archive_entry
*sparse_entry
;
531 int r
= ARCHIVE_OK
, r1
, parsed_kws
, mismatched_type
;
535 /* Initialize reasonable defaults. */
536 mtree
->filetype
= AE_IFREG
;
537 archive_entry_set_size(entry
, 0);
539 /* Parse options from this line. */
541 r
= parse_line(a
, entry
, mtree
, mentry
, &parsed_kws
);
544 archive_entry_copy_pathname(entry
, mentry
->name
);
546 * "Full" entries are allowed to have multiple lines
547 * and those lines aren't required to be adjacent. We
548 * don't support multiple lines for "relative" entries
549 * nor do we make any attempt to merge data from
550 * separate "relative" and "full" entries. (Merging
551 * "relative" and "full" entries would require dealing
552 * with pathname canonicalization, which is a very
555 for (mp
= mentry
->next
; mp
!= NULL
; mp
= mp
->next
) {
556 if (mp
->full
&& !mp
->used
557 && strcmp(mentry
->name
, mp
->name
) == 0) {
558 /* Later lines override earlier ones. */
560 r1
= parse_line(a
, entry
, mtree
, mp
,
568 * Relative entries require us to construct
569 * the full path and possibly update the
572 size_t n
= archive_strlen(&mtree
->current_dir
);
574 archive_strcat(&mtree
->current_dir
, "/");
575 archive_strcat(&mtree
->current_dir
, mentry
->name
);
576 archive_entry_copy_pathname(entry
, mtree
->current_dir
.s
);
577 if (archive_entry_filetype(entry
) != AE_IFDIR
)
578 mtree
->current_dir
.length
= n
;
582 * Try to open and stat the file to get the real size
583 * and other file info. It would be nice to avoid
584 * this here so that getting a listing of an mtree
585 * wouldn't require opening every referenced contents
586 * file. But then we wouldn't know the actual
587 * contents size, so I don't see a really viable way
588 * around this. (Also, we may want to someday pull
589 * other unspecified info from the contents file on
593 if (archive_strlen(&mtree
->contents_name
) > 0)
594 path
= mtree
->contents_name
.s
;
596 path
= archive_entry_pathname(entry
);
598 if (archive_entry_filetype(entry
) == AE_IFREG
||
599 archive_entry_filetype(entry
) == AE_IFDIR
) {
600 mtree
->fd
= open(path
,
601 O_RDONLY
| O_BINARY
);
602 if (mtree
->fd
== -1 &&
604 archive_strlen(&mtree
->contents_name
) > 0)) {
605 archive_set_error(&a
->archive
, errno
,
606 "Can't open %s", path
);
612 if (mtree
->fd
>= 0) {
613 if (fstat(mtree
->fd
, st
) == -1) {
614 archive_set_error(&a
->archive
, errno
,
615 "Could not fstat %s", path
);
617 /* If we can't stat it, don't keep it open. */
622 } else if (lstat(path
, st
) == -1) {
627 * If there is a contents file on disk, use that size;
628 * otherwise leave it as-is (it might have been set from
629 * the mtree size= keyword).
633 if ((st
->st_mode
& S_IFMT
) == S_IFREG
&&
634 archive_entry_filetype(entry
) != AE_IFREG
)
636 if ((st
->st_mode
& S_IFMT
) == S_IFLNK
&&
637 archive_entry_filetype(entry
) != AE_IFLNK
)
639 if ((st
->st_mode
& S_IFSOCK
) == S_IFSOCK
&&
640 archive_entry_filetype(entry
) != AE_IFSOCK
)
642 if ((st
->st_mode
& S_IFMT
) == S_IFCHR
&&
643 archive_entry_filetype(entry
) != AE_IFCHR
)
645 if ((st
->st_mode
& S_IFMT
) == S_IFBLK
&&
646 archive_entry_filetype(entry
) != AE_IFBLK
)
648 if ((st
->st_mode
& S_IFMT
) == S_IFDIR
&&
649 archive_entry_filetype(entry
) != AE_IFDIR
)
651 if ((st
->st_mode
& S_IFMT
) == S_IFIFO
&&
652 archive_entry_filetype(entry
) != AE_IFIFO
)
655 if (mismatched_type
) {
656 if ((parsed_kws
& MTREE_HAS_OPTIONAL
) == 0) {
657 archive_set_error(&a
->archive
,
659 "mtree specification has different type for %s",
660 archive_entry_pathname(entry
));
665 /* Don't hold a non-regular file open. */
675 if ((parsed_kws
& MTREE_HAS_DEVICE
) == 0 &&
676 (archive_entry_filetype(entry
) == AE_IFCHR
||
677 archive_entry_filetype(entry
) == AE_IFBLK
))
678 archive_entry_set_rdev(entry
, st
->st_rdev
);
679 if ((parsed_kws
& (MTREE_HAS_GID
| MTREE_HAS_GNAME
)) == 0)
680 archive_entry_set_gid(entry
, st
->st_gid
);
681 if ((parsed_kws
& (MTREE_HAS_UID
| MTREE_HAS_UNAME
)) == 0)
682 archive_entry_set_uid(entry
, st
->st_uid
);
683 if ((parsed_kws
& MTREE_HAS_MTIME
) == 0) {
684 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
685 archive_entry_set_mtime(entry
, st
->st_mtime
,
686 st
->st_mtimespec
.tv_nsec
);
687 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
688 archive_entry_set_mtime(entry
, st
->st_mtime
,
689 st
->st_mtim
.tv_nsec
);
691 archive_entry_set_mtime(entry
, st
->st_mtime
, 0);
694 if ((parsed_kws
& MTREE_HAS_NLINK
) == 0)
695 archive_entry_set_nlink(entry
, st
->st_nlink
);
696 if ((parsed_kws
& MTREE_HAS_PERM
) == 0)
697 archive_entry_set_perm(entry
, st
->st_mode
);
698 if ((parsed_kws
& MTREE_HAS_SIZE
) == 0)
699 archive_entry_set_size(entry
, st
->st_size
);
700 archive_entry_set_ino(entry
, st
->st_ino
);
701 archive_entry_set_dev(entry
, st
->st_dev
);
703 archive_entry_linkify(mtree
->resolver
, &entry
, &sparse_entry
);
704 } else if (parsed_kws
& MTREE_HAS_OPTIONAL
) {
706 * Couldn't open the entry, stat it or the on-disk type
707 * didn't match. If this entry is optional, just ignore it
708 * and read the next header entry.
714 mtree
->cur_size
= archive_entry_size(entry
);
721 * Each line contains a sequence of keywords.
724 parse_line(struct archive_read
*a
, struct archive_entry
*entry
,
725 struct mtree
*mtree
, struct mtree_entry
*mp
, int *parsed_kws
)
727 struct mtree_option
*iter
;
728 int r
= ARCHIVE_OK
, r1
;
730 for (iter
= mp
->options
; iter
!= NULL
; iter
= iter
->next
) {
731 r1
= parse_keyword(a
, mtree
, entry
, iter
, parsed_kws
);
735 if ((*parsed_kws
& MTREE_HAS_TYPE
) == 0) {
736 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
737 "Missing type keyword in mtree specification");
738 return (ARCHIVE_WARN
);
744 * Device entries have one of the following forms:
746 * format,major,minor[,subdevice]
748 * Just use major and minor, no translation etc is done
752 parse_device(struct archive
*a
, struct archive_entry
*entry
, char *val
)
754 char *comma1
, *comma2
;
756 comma1
= strchr(val
, ',');
757 if (comma1
== NULL
) {
758 archive_entry_set_dev(entry
, mtree_atol10(&val
));
762 comma2
= strchr(comma1
, ',');
763 if (comma2
== NULL
) {
764 archive_set_error(a
, ARCHIVE_ERRNO_FILE_FORMAT
,
765 "Malformed device attribute");
766 return (ARCHIVE_WARN
);
769 archive_entry_set_rdevmajor(entry
, mtree_atol(&comma1
));
770 archive_entry_set_rdevminor(entry
, mtree_atol(&comma2
));
775 * Parse a single keyword and its value.
778 parse_keyword(struct archive_read
*a
, struct mtree
*mtree
,
779 struct archive_entry
*entry
, struct mtree_option
*option
, int *parsed_kws
)
788 if (strcmp(key
, "optional") == 0) {
789 *parsed_kws
|= MTREE_HAS_OPTIONAL
;
792 if (strcmp(key
, "ignore") == 0) {
794 * The mtree processing is not recursive, so
795 * recursion will only happen for explicitly listed
801 val
= strchr(key
, '=');
803 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
804 "Malformed attribute \"%s\" (%d)", key
, key
[0]);
805 return (ARCHIVE_WARN
);
813 if (strcmp(key
, "content") == 0
814 || strcmp(key
, "contents") == 0) {
815 parse_escapes(val
, NULL
);
816 archive_strcpy(&mtree
->contents_name
, val
);
819 if (strcmp(key
, "cksum") == 0)
822 if (strcmp(key
, "device") == 0) {
823 *parsed_kws
|= MTREE_HAS_DEVICE
;
824 return parse_device(&a
->archive
, entry
, val
);
827 if (strcmp(key
, "flags") == 0) {
828 *parsed_kws
|= MTREE_HAS_FFLAGS
;
829 archive_entry_copy_fflags_text(entry
, val
);
833 if (strcmp(key
, "gid") == 0) {
834 *parsed_kws
|= MTREE_HAS_GID
;
835 archive_entry_set_gid(entry
, mtree_atol10(&val
));
838 if (strcmp(key
, "gname") == 0) {
839 *parsed_kws
|= MTREE_HAS_GNAME
;
840 archive_entry_copy_gname(entry
, val
);
844 if (strcmp(key
, "link") == 0) {
845 archive_entry_copy_symlink(entry
, val
);
849 if (strcmp(key
, "md5") == 0 || strcmp(key
, "md5digest") == 0)
851 if (strcmp(key
, "mode") == 0) {
852 if (val
[0] >= '0' && val
[0] <= '9') {
853 *parsed_kws
|= MTREE_HAS_PERM
;
854 archive_entry_set_perm(entry
,
857 archive_set_error(&a
->archive
,
858 ARCHIVE_ERRNO_FILE_FORMAT
,
859 "Symbolic mode \"%s\" unsupported", val
);
865 if (strcmp(key
, "nlink") == 0) {
866 *parsed_kws
|= MTREE_HAS_NLINK
;
867 archive_entry_set_nlink(entry
, mtree_atol10(&val
));
871 if (strcmp(key
, "rmd160") == 0 ||
872 strcmp(key
, "rmd160digest") == 0)
875 if (strcmp(key
, "sha1") == 0 || strcmp(key
, "sha1digest") == 0)
877 if (strcmp(key
, "sha256") == 0 ||
878 strcmp(key
, "sha256digest") == 0)
880 if (strcmp(key
, "sha384") == 0 ||
881 strcmp(key
, "sha384digest") == 0)
883 if (strcmp(key
, "sha512") == 0 ||
884 strcmp(key
, "sha512digest") == 0)
886 if (strcmp(key
, "size") == 0) {
887 archive_entry_set_size(entry
, mtree_atol10(&val
));
891 if (strcmp(key
, "tags") == 0) {
893 * Comma delimited list of tags.
894 * Ignore the tags for now, but the interface
895 * should be extended to allow inclusion/exclusion.
899 if (strcmp(key
, "time") == 0) {
900 *parsed_kws
|= MTREE_HAS_MTIME
;
901 archive_entry_set_mtime(entry
, mtree_atol10(&val
), 0);
904 if (strcmp(key
, "type") == 0) {
905 *parsed_kws
|= MTREE_HAS_TYPE
;
908 if (strcmp(val
, "block") == 0) {
909 mtree
->filetype
= AE_IFBLK
;
913 if (strcmp(val
, "char") == 0) {
914 mtree
->filetype
= AE_IFCHR
;
918 if (strcmp(val
, "dir") == 0) {
919 mtree
->filetype
= AE_IFDIR
;
923 if (strcmp(val
, "fifo") == 0) {
924 mtree
->filetype
= AE_IFIFO
;
927 if (strcmp(val
, "file") == 0) {
928 mtree
->filetype
= AE_IFREG
;
932 if (strcmp(val
, "link") == 0) {
933 mtree
->filetype
= AE_IFLNK
;
937 archive_set_error(&a
->archive
,
938 ARCHIVE_ERRNO_FILE_FORMAT
,
939 "Unrecognized file type \"%s\"", val
);
940 return (ARCHIVE_WARN
);
942 archive_entry_set_filetype(entry
, mtree
->filetype
);
946 if (strcmp(key
, "uid") == 0) {
947 *parsed_kws
|= MTREE_HAS_UID
;
948 archive_entry_set_uid(entry
, mtree_atol10(&val
));
951 if (strcmp(key
, "uname") == 0) {
952 *parsed_kws
|= MTREE_HAS_UNAME
;
953 archive_entry_copy_uname(entry
, val
);
957 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
958 "Unrecognized key %s=%s", key
, val
);
959 return (ARCHIVE_WARN
);
965 read_data(struct archive_read
*a
, const void **buff
, size_t *size
, off_t
*offset
)
967 size_t bytes_to_read
;
971 mtree
= (struct mtree
*)(a
->format
->data
);
976 return (ARCHIVE_EOF
);
978 if (mtree
->buff
== NULL
) {
979 mtree
->buffsize
= 64 * 1024;
980 mtree
->buff
= malloc(mtree
->buffsize
);
981 if (mtree
->buff
== NULL
) {
982 archive_set_error(&a
->archive
, ENOMEM
,
983 "Can't allocate memory");
985 return (ARCHIVE_FATAL
);
989 *offset
= mtree
->offset
;
990 if ((off_t
)mtree
->buffsize
> mtree
->cur_size
- mtree
->offset
)
991 bytes_to_read
= mtree
->cur_size
- mtree
->offset
;
993 bytes_to_read
= mtree
->buffsize
;
994 bytes_read
= read(mtree
->fd
, mtree
->buff
, bytes_to_read
);
995 if (bytes_read
< 0) {
996 archive_set_error(&a
->archive
, errno
, "Can't read");
997 return (ARCHIVE_WARN
);
999 if (bytes_read
== 0) {
1001 return (ARCHIVE_EOF
);
1003 mtree
->offset
+= bytes_read
;
1005 return (ARCHIVE_OK
);
1008 /* Skip does nothing except possibly close the contents file. */
1010 skip(struct archive_read
*a
)
1012 struct mtree
*mtree
;
1014 mtree
= (struct mtree
*)(a
->format
->data
);
1015 if (mtree
->fd
>= 0) {
1019 return (ARCHIVE_OK
);
1023 * Since parsing backslash sequences always makes strings shorter,
1024 * we can always do this conversion in-place.
1027 parse_escapes(char *src
, struct mtree_entry
*mentry
)
1033 * The current directory is somewhat special, it should be archived
1034 * only once as it will confuse extraction otherwise.
1036 if (strcmp(src
, ".") == 0)
1039 while (*src
!= '\0') {
1041 if (c
== '/' && mentry
!= NULL
)
1046 if (src
[1] < '0' || src
[1] > '7') {
1055 if (src
[1] >= '0' && src
[1] <= '7' &&
1056 src
[2] >= '0' && src
[2] <= '7') {
1057 c
= (src
[0] - '0') << 6;
1058 c
|= (src
[1] - '0') << 3;
1059 c
|= (src
[2] - '0');
1103 * Note that this implementation does not (and should not!) obey
1104 * locale settings; you cannot simply substitute strtol here, since
1105 * it does obey locale.
1108 mtree_atol8(char **p
)
1110 int64_t l
, limit
, last_digit_limit
;
1114 limit
= INT64_MAX
/ base
;
1115 last_digit_limit
= INT64_MAX
% base
;
1119 while (digit
>= 0 && digit
< base
) {
1120 if (l
>limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1121 l
= INT64_MAX
; /* Truncate on overflow. */
1124 l
= (l
* base
) + digit
;
1125 digit
= *++(*p
) - '0';
1131 * Note that this implementation does not (and should not!) obey
1132 * locale settings; you cannot simply substitute strtol here, since
1133 * it does obey locale.
1136 mtree_atol10(char **p
)
1138 int64_t l
, limit
, last_digit_limit
;
1139 int base
, digit
, sign
;
1142 limit
= INT64_MAX
/ base
;
1143 last_digit_limit
= INT64_MAX
% base
;
1153 while (digit
>= 0 && digit
< base
) {
1154 if (l
> limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1155 l
= UINT64_MAX
; /* Truncate on overflow. */
1158 l
= (l
* base
) + digit
;
1159 digit
= *++(*p
) - '0';
1161 return (sign
< 0) ? -l
: l
;
1165 * Note that this implementation does not (and should not!) obey
1166 * locale settings; you cannot simply substitute strtol here, since
1167 * it does obey locale.
1170 mtree_atol16(char **p
)
1172 int64_t l
, limit
, last_digit_limit
;
1173 int base
, digit
, sign
;
1176 limit
= INT64_MAX
/ base
;
1177 last_digit_limit
= INT64_MAX
% base
;
1186 if (**p
>= '0' && **p
<= '9')
1188 else if (**p
>= 'a' && **p
<= 'f')
1189 digit
= **p
- 'a' + 10;
1190 else if (**p
>= 'A' && **p
<= 'F')
1191 digit
= **p
- 'A' + 10;
1194 while (digit
>= 0 && digit
< base
) {
1195 if (l
> limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1196 l
= UINT64_MAX
; /* Truncate on overflow. */
1199 l
= (l
* base
) + digit
;
1200 if (**p
>= '0' && **p
<= '9')
1202 else if (**p
>= 'a' && **p
<= 'f')
1203 digit
= **p
- 'a' + 10;
1204 else if (**p
>= 'A' && **p
<= 'F')
1205 digit
= **p
- 'A' + 10;
1209 return (sign
< 0) ? -l
: l
;
1213 mtree_atol(char **p
)
1216 return mtree_atol10(p
);
1217 if ((*p
)[1] == 'x' || (*p
)[1] == 'X') {
1219 return mtree_atol16(p
);
1221 return mtree_atol8(p
);
1225 * Returns length of line (including trailing newline)
1226 * or negative on error. 'start' argument is updated to
1227 * point to first character of line.
1230 readline(struct archive_read
*a
, struct mtree
*mtree
, char **start
, ssize_t limit
)
1233 ssize_t total_size
= 0;
1239 /* Accumulate line in a line buffer. */
1241 /* Read some more. */
1242 bytes_read
= (a
->decompressor
->read_ahead
)(a
, &t
, 1);
1243 if (bytes_read
== 0)
1246 return (ARCHIVE_FATAL
);
1247 s
= t
; /* Start of line? */
1248 p
= memchr(t
, '\n', bytes_read
);
1249 /* If we found '\n', trim the read. */
1251 bytes_read
= 1 + ((const char *)p
) - s
;
1253 if (total_size
+ bytes_read
+ 1 > limit
) {
1254 archive_set_error(&a
->archive
,
1255 ARCHIVE_ERRNO_FILE_FORMAT
,
1257 return (ARCHIVE_FATAL
);
1259 if (archive_string_ensure(&mtree
->line
,
1260 total_size
+ bytes_read
+ 1) == NULL
) {
1261 archive_set_error(&a
->archive
, ENOMEM
,
1262 "Can't allocate working buffer");
1263 return (ARCHIVE_FATAL
);
1265 memcpy(mtree
->line
.s
+ total_size
, t
, bytes_read
);
1266 (a
->decompressor
->consume
)(a
, bytes_read
);
1267 total_size
+= bytes_read
;
1268 /* Null terminate. */
1269 mtree
->line
.s
[total_size
] = '\0';
1270 /* If we found an unescaped '\n', clean up and return. */
1273 for (u
= mtree
->line
.s
; *u
; ++u
) {
1275 *start
= mtree
->line
.s
;
1281 *start
= mtree
->line
.s
;
1292 total_size
- (u
- mtree
->line
.s
) + 1);