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.5 2008/05/19 18:06:48 cperciva 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 ((next
= 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. */
674 if ((parsed_kws
& MTREE_HAS_DEVICE
) == 0 &&
675 (archive_entry_filetype(entry
) == AE_IFCHR
||
676 archive_entry_filetype(entry
) == AE_IFBLK
))
677 archive_entry_set_rdev(entry
, st
->st_rdev
);
678 if ((parsed_kws
& (MTREE_HAS_GID
| MTREE_HAS_GNAME
)) == 0)
679 archive_entry_set_gid(entry
, st
->st_gid
);
680 if ((parsed_kws
& (MTREE_HAS_UID
| MTREE_HAS_UNAME
)) == 0)
681 archive_entry_set_uid(entry
, st
->st_uid
);
682 if ((parsed_kws
& MTREE_HAS_MTIME
) == 0) {
683 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
684 archive_entry_set_mtime(entry
, st
->st_mtime
,
685 st
->st_mtimespec
.tv_nsec
);
686 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
687 archive_entry_set_mtime(entry
, st
->st_mtime
,
688 st
->st_mtim
.tv_nsec
);
690 archive_entry_set_mtime(entry
, st
->st_mtime
, 0);
693 if ((parsed_kws
& MTREE_HAS_NLINK
) == 0)
694 archive_entry_set_nlink(entry
, st
->st_nlink
);
695 if ((parsed_kws
& MTREE_HAS_PERM
) == 0)
696 archive_entry_set_perm(entry
, st
->st_mode
);
697 if ((parsed_kws
& MTREE_HAS_SIZE
) == 0)
698 archive_entry_set_size(entry
, st
->st_size
);
699 archive_entry_set_ino(entry
, st
->st_ino
);
700 archive_entry_set_dev(entry
, st
->st_dev
);
702 archive_entry_linkify(mtree
->resolver
, &entry
, &sparse_entry
);
703 } else if (parsed_kws
& MTREE_HAS_OPTIONAL
) {
705 * Couldn't open the entry, stat it or the on-disk type
706 * didn't match. If this entry is optional, just ignore it
707 * and read the next header entry.
713 mtree
->cur_size
= archive_entry_size(entry
);
720 * Each line contains a sequence of keywords.
723 parse_line(struct archive_read
*a
, struct archive_entry
*entry
,
724 struct mtree
*mtree
, struct mtree_entry
*mp
, int *parsed_kws
)
726 struct mtree_option
*iter
;
727 int r
= ARCHIVE_OK
, r1
;
729 for (iter
= mp
->options
; iter
!= NULL
; iter
= iter
->next
) {
730 r1
= parse_keyword(a
, mtree
, entry
, iter
, parsed_kws
);
734 if ((*parsed_kws
& MTREE_HAS_TYPE
) == 0) {
735 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
736 "Missing type keyword in mtree specification");
737 return (ARCHIVE_WARN
);
743 * Device entries have one of the following forms:
745 * format,major,minor[,subdevice]
747 * Just use major and minor, no translation etc is done
751 parse_device(struct archive
*a
, struct archive_entry
*entry
, char *val
)
753 char *comma1
, *comma2
;
755 comma1
= strchr(val
, ',');
756 if (comma1
== NULL
) {
757 archive_entry_set_dev(entry
, mtree_atol10(&val
));
761 comma2
= strchr(comma1
, ',');
762 if (comma1
== NULL
) {
763 archive_set_error(a
, ARCHIVE_ERRNO_FILE_FORMAT
,
764 "Malformed device attribute");
765 return (ARCHIVE_WARN
);
768 archive_entry_set_rdevmajor(entry
, mtree_atol(&comma1
));
769 archive_entry_set_rdevminor(entry
, mtree_atol(&comma2
));
774 * Parse a single keyword and its value.
777 parse_keyword(struct archive_read
*a
, struct mtree
*mtree
,
778 struct archive_entry
*entry
, struct mtree_option
*option
, int *parsed_kws
)
787 if (strcmp(key
, "optional") == 0) {
788 *parsed_kws
|= MTREE_HAS_OPTIONAL
;
791 if (strcmp(key
, "ignore") == 0) {
793 * The mtree processing is not recursive, so
794 * recursion will only happen for explicitly listed
800 val
= strchr(key
, '=');
802 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
803 "Malformed attribute \"%s\" (%d)", key
, key
[0]);
804 return (ARCHIVE_WARN
);
812 if (strcmp(key
, "content") == 0
813 || strcmp(key
, "contents") == 0) {
814 parse_escapes(val
, NULL
);
815 archive_strcpy(&mtree
->contents_name
, val
);
818 if (strcmp(key
, "cksum") == 0)
821 if (strcmp(key
, "device") == 0) {
822 *parsed_kws
|= MTREE_HAS_DEVICE
;
823 return parse_device(&a
->archive
, entry
, val
);
826 if (strcmp(key
, "flags") == 0) {
827 *parsed_kws
|= MTREE_HAS_FFLAGS
;
828 archive_entry_copy_fflags_text(entry
, val
);
832 if (strcmp(key
, "gid") == 0) {
833 *parsed_kws
|= MTREE_HAS_GID
;
834 archive_entry_set_gid(entry
, mtree_atol10(&val
));
837 if (strcmp(key
, "gname") == 0) {
838 *parsed_kws
|= MTREE_HAS_GNAME
;
839 archive_entry_copy_gname(entry
, val
);
843 if (strcmp(key
, "link") == 0) {
844 archive_entry_copy_symlink(entry
, val
);
848 if (strcmp(key
, "md5") == 0 || strcmp(key
, "md5digest") == 0)
850 if (strcmp(key
, "mode") == 0) {
851 if (val
[0] >= '0' && val
[0] <= '9') {
852 *parsed_kws
|= MTREE_HAS_PERM
;
853 archive_entry_set_perm(entry
,
856 archive_set_error(&a
->archive
,
857 ARCHIVE_ERRNO_FILE_FORMAT
,
858 "Symbolic mode \"%s\" unsupported", val
);
864 if (strcmp(key
, "nlink") == 0) {
865 *parsed_kws
|= MTREE_HAS_NLINK
;
866 archive_entry_set_nlink(entry
, mtree_atol10(&val
));
870 if (strcmp(key
, "rmd160") == 0 ||
871 strcmp(key
, "rmd160digest") == 0)
874 if (strcmp(key
, "sha1") == 0 || strcmp(key
, "sha1digest") == 0)
876 if (strcmp(key
, "sha256") == 0 ||
877 strcmp(key
, "sha256digest") == 0)
879 if (strcmp(key
, "sha384") == 0 ||
880 strcmp(key
, "sha384digest") == 0)
882 if (strcmp(key
, "sha512") == 0 ||
883 strcmp(key
, "sha512digest") == 0)
885 if (strcmp(key
, "size") == 0) {
886 archive_entry_set_size(entry
, mtree_atol10(&val
));
890 if (strcmp(key
, "tags") == 0) {
892 * Comma delimited list of tags.
893 * Ignore the tags for now, but the interface
894 * should be extended to allow inclusion/exclusion.
898 if (strcmp(key
, "time") == 0) {
899 *parsed_kws
|= MTREE_HAS_MTIME
;
900 archive_entry_set_mtime(entry
, mtree_atol10(&val
), 0);
903 if (strcmp(key
, "type") == 0) {
904 *parsed_kws
|= MTREE_HAS_TYPE
;
907 if (strcmp(val
, "block") == 0) {
908 mtree
->filetype
= AE_IFBLK
;
912 if (strcmp(val
, "char") == 0) {
913 mtree
->filetype
= AE_IFCHR
;
917 if (strcmp(val
, "dir") == 0) {
918 mtree
->filetype
= AE_IFDIR
;
922 if (strcmp(val
, "fifo") == 0) {
923 mtree
->filetype
= AE_IFIFO
;
926 if (strcmp(val
, "file") == 0) {
927 mtree
->filetype
= AE_IFREG
;
931 if (strcmp(val
, "link") == 0) {
932 mtree
->filetype
= AE_IFLNK
;
936 archive_set_error(&a
->archive
,
937 ARCHIVE_ERRNO_FILE_FORMAT
,
938 "Unrecognized file type \"%s\"", val
);
939 return (ARCHIVE_WARN
);
941 archive_entry_set_filetype(entry
, mtree
->filetype
);
945 if (strcmp(key
, "uid") == 0) {
946 *parsed_kws
|= MTREE_HAS_UID
;
947 archive_entry_set_uid(entry
, mtree_atol10(&val
));
950 if (strcmp(key
, "uname") == 0) {
951 *parsed_kws
|= MTREE_HAS_UNAME
;
952 archive_entry_copy_uname(entry
, val
);
956 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_FILE_FORMAT
,
957 "Unrecognized key %s=%s", key
, val
);
958 return (ARCHIVE_WARN
);
964 read_data(struct archive_read
*a
, const void **buff
, size_t *size
, off_t
*offset
)
966 size_t bytes_to_read
;
970 mtree
= (struct mtree
*)(a
->format
->data
);
975 return (ARCHIVE_EOF
);
977 if (mtree
->buff
== NULL
) {
978 mtree
->buffsize
= 64 * 1024;
979 mtree
->buff
= malloc(mtree
->buffsize
);
980 if (mtree
->buff
== NULL
) {
981 archive_set_error(&a
->archive
, ENOMEM
,
982 "Can't allocate memory");
984 return (ARCHIVE_FATAL
);
988 *offset
= mtree
->offset
;
989 if ((off_t
)mtree
->buffsize
> mtree
->cur_size
- mtree
->offset
)
990 bytes_to_read
= mtree
->cur_size
- mtree
->offset
;
992 bytes_to_read
= mtree
->buffsize
;
993 bytes_read
= read(mtree
->fd
, mtree
->buff
, bytes_to_read
);
994 if (bytes_read
< 0) {
995 archive_set_error(&a
->archive
, errno
, "Can't read");
996 return (ARCHIVE_WARN
);
998 if (bytes_read
== 0) {
1000 return (ARCHIVE_EOF
);
1002 mtree
->offset
+= bytes_read
;
1004 return (ARCHIVE_OK
);
1007 /* Skip does nothing except possibly close the contents file. */
1009 skip(struct archive_read
*a
)
1011 struct mtree
*mtree
;
1013 mtree
= (struct mtree
*)(a
->format
->data
);
1014 if (mtree
->fd
>= 0) {
1018 return (ARCHIVE_OK
);
1022 * Since parsing octal escapes always makes strings shorter,
1023 * we can always do this conversion in-place.
1026 parse_escapes(char *src
, struct mtree_entry
*mentry
)
1032 * The current directory is somewhat special, it should be archived
1033 * only once as it will confuse extraction otherwise.
1035 if (strcmp(src
, ".") == 0)
1038 while (*src
!= '\0') {
1040 if (c
== '/' && mentry
!= NULL
)
1043 if (src
[0] >= '0' && src
[0] <= '3'
1044 && src
[1] >= '0' && src
[1] <= '7'
1045 && src
[2] >= '0' && src
[2] <= '7') {
1046 c
= (src
[0] - '0') << 6;
1047 c
|= (src
[1] - '0') << 3;
1048 c
|= (src
[2] - '0');
1058 * Note that this implementation does not (and should not!) obey
1059 * locale settings; you cannot simply substitute strtol here, since
1060 * it does obey locale.
1063 mtree_atol8(char **p
)
1065 int64_t l
, limit
, last_digit_limit
;
1069 limit
= INT64_MAX
/ base
;
1070 last_digit_limit
= INT64_MAX
% base
;
1074 while (digit
>= 0 && digit
< base
) {
1075 if (l
>limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1076 l
= INT64_MAX
; /* Truncate on overflow. */
1079 l
= (l
* base
) + digit
;
1080 digit
= *++(*p
) - '0';
1086 * Note that this implementation does not (and should not!) obey
1087 * locale settings; you cannot simply substitute strtol here, since
1088 * it does obey locale.
1091 mtree_atol10(char **p
)
1093 int64_t l
, limit
, last_digit_limit
;
1094 int base
, digit
, sign
;
1097 limit
= INT64_MAX
/ base
;
1098 last_digit_limit
= INT64_MAX
% base
;
1108 while (digit
>= 0 && digit
< base
) {
1109 if (l
> limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1110 l
= UINT64_MAX
; /* Truncate on overflow. */
1113 l
= (l
* base
) + digit
;
1114 digit
= *++(*p
) - '0';
1116 return (sign
< 0) ? -l
: l
;
1120 * Note that this implementation does not (and should not!) obey
1121 * locale settings; you cannot simply substitute strtol here, since
1122 * it does obey locale.
1125 mtree_atol16(char **p
)
1127 int64_t l
, limit
, last_digit_limit
;
1128 int base
, digit
, sign
;
1131 limit
= INT64_MAX
/ base
;
1132 last_digit_limit
= INT64_MAX
% base
;
1141 if (**p
>= '0' && **p
<= '9')
1143 else if (**p
>= 'a' && **p
<= 'f')
1144 digit
= **p
- 'a' + 10;
1145 else if (**p
>= 'A' && **p
<= 'F')
1146 digit
= **p
- 'A' + 10;
1149 while (digit
>= 0 && digit
< base
) {
1150 if (l
> limit
|| (l
== limit
&& digit
> last_digit_limit
)) {
1151 l
= UINT64_MAX
; /* Truncate on overflow. */
1154 l
= (l
* base
) + digit
;
1155 if (**p
>= '0' && **p
<= '9')
1157 else if (**p
>= 'a' && **p
<= 'f')
1158 digit
= **p
- 'a' + 10;
1159 else if (**p
>= 'A' && **p
<= 'F')
1160 digit
= **p
- 'A' + 10;
1164 return (sign
< 0) ? -l
: l
;
1168 mtree_atol(char **p
)
1171 return mtree_atol10(p
);
1172 if ((*p
)[1] == 'x' || (*p
)[1] == 'X') {
1174 return mtree_atol16(p
);
1176 return mtree_atol8(p
);
1180 * Returns length of line (including trailing newline)
1181 * or negative on error. 'start' argument is updated to
1182 * point to first character of line.
1185 readline(struct archive_read
*a
, struct mtree
*mtree
, char **start
, ssize_t limit
)
1188 ssize_t total_size
= 0;
1193 /* Accumulate line in a line buffer. */
1195 /* Read some more. */
1196 bytes_read
= (a
->decompressor
->read_ahead
)(a
, &t
, 1);
1197 if (bytes_read
== 0)
1200 return (ARCHIVE_FATAL
);
1201 s
= t
; /* Start of line? */
1202 p
= memchr(t
, '\n', bytes_read
);
1203 /* If we found '\n', trim the read. */
1205 bytes_read
= 1 + ((const char *)p
) - s
;
1207 if (total_size
+ bytes_read
+ 1 > limit
) {
1208 archive_set_error(&a
->archive
,
1209 ARCHIVE_ERRNO_FILE_FORMAT
,
1211 return (ARCHIVE_FATAL
);
1213 if (archive_string_ensure(&mtree
->line
,
1214 total_size
+ bytes_read
+ 1) == NULL
) {
1215 archive_set_error(&a
->archive
, ENOMEM
,
1216 "Can't allocate working buffer");
1217 return (ARCHIVE_FATAL
);
1219 memcpy(mtree
->line
.s
+ total_size
, t
, bytes_read
);
1220 (a
->decompressor
->consume
)(a
, bytes_read
);
1221 total_size
+= bytes_read
;
1222 /* Null terminate. */
1223 mtree
->line
.s
[total_size
] = '\0';
1224 /* If we found '\n', clean up and return. */
1226 *start
= mtree
->line
.s
;
1227 return (total_size
);