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: head/lib/libarchive/archive_read_support_format_mtree.c 201165 2009-12-29 05:52:13Z kientzle $");
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, "mtree",
152
mtree_bid, NULL, 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)
190
const char *signature = "#mtree";
193
/* Now let's look at the actual header and see if it matches. */
194
p = __archive_read_ahead(a, strlen(signature), NULL);
198
if (strncmp(p, signature, strlen(signature)) == 0)
199
return (8 * (int)strlen(signature));
204
* The extended mtree format permits multiple lines specifying
205
* attributes for each file. For those entries, only the last line
206
* is actually used. Practically speaking, that means we have
207
* to read the entire mtree file into memory up front.
209
* The parsing is done in two steps. First, it is decided if a line
210
* changes the global defaults and if it is, processed accordingly.
211
* Otherwise, the options of the line are merged with the current
215
add_option(struct archive_read *a, struct mtree_option **global,
216
const char *value, size_t len)
218
struct mtree_option *option;
220
if ((option = malloc(sizeof(*option))) == NULL) {
221
archive_set_error(&a->archive, errno, "Can't allocate memory");
222
return (ARCHIVE_FATAL);
224
if ((option->value = malloc(len + 1)) == NULL) {
226
archive_set_error(&a->archive, errno, "Can't allocate memory");
227
return (ARCHIVE_FATAL);
229
memcpy(option->value, value, len);
230
option->value[len] = '\0';
231
option->next = *global;
237
remove_option(struct mtree_option **global, const char *value, size_t len)
239
struct mtree_option *iter, *last;
242
for (iter = *global; iter != NULL; last = iter, iter = iter->next) {
243
if (strncmp(iter->value, value, len) == 0 &&
244
(iter->value[len] == '\0' ||
245
iter->value[len] == '='))
251
*global = iter->next;
253
last->next = iter->next;
260
process_global_set(struct archive_read *a,
261
struct mtree_option **global, const char *line)
263
const char *next, *eq;
269
next = line + strspn(line, " \t\r\n");
273
next = line + strcspn(line, " \t\r\n");
274
eq = strchr(line, '=');
280
remove_option(global, line, len);
281
r = add_option(a, global, line, next - line);
289
process_global_unset(struct archive_read *a,
290
struct mtree_option **global, const char *line)
296
if (strchr(line, '=') != NULL) {
297
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
298
"/unset shall not contain `='");
299
return ARCHIVE_FATAL;
303
next = line + strspn(line, " \t\r\n");
307
len = strcspn(line, " \t\r\n");
309
if (len == 3 && strncmp(line, "all", 3) == 0) {
310
free_options(*global);
313
remove_option(global, line, len);
321
process_add_entry(struct archive_read *a, struct mtree *mtree,
322
struct mtree_option **global, const char *line,
323
struct mtree_entry **last_entry)
325
struct mtree_entry *entry;
326
struct mtree_option *iter;
327
const char *next, *eq;
331
if ((entry = malloc(sizeof(*entry))) == NULL) {
332
archive_set_error(&a->archive, errno, "Can't allocate memory");
333
return (ARCHIVE_FATAL);
336
entry->options = NULL;
341
/* Add this entry to list. */
342
if (*last_entry == NULL)
343
mtree->entries = entry;
345
(*last_entry)->next = entry;
348
len = strcspn(line, " \t\r\n");
349
if ((entry->name = malloc(len + 1)) == NULL) {
350
archive_set_error(&a->archive, errno, "Can't allocate memory");
351
return (ARCHIVE_FATAL);
354
memcpy(entry->name, line, len);
355
entry->name[len] = '\0';
356
parse_escapes(entry->name, entry);
359
for (iter = *global; iter != NULL; iter = iter->next) {
360
r = add_option(a, &entry->options, iter->value,
361
strlen(iter->value));
367
next = line + strspn(line, " \t\r\n");
371
next = line + strcspn(line, " \t\r\n");
372
eq = strchr(line, '=');
373
if (eq == NULL || eq > next)
378
remove_option(&entry->options, line, len);
379
r = add_option(a, &entry->options, line, next - line);
387
read_mtree(struct archive_read *a, struct mtree *mtree)
392
struct mtree_option *global;
393
struct mtree_entry *last_entry;
396
mtree->archive_format = ARCHIVE_FORMAT_MTREE;
397
mtree->archive_format_name = "mtree";
402
for (counter = 1; ; ++counter) {
403
len = readline(a, mtree, &p, 256);
405
mtree->this_entry = mtree->entries;
406
free_options(global);
410
free_options(global);
413
/* Leading whitespace is never significant, ignore it. */
414
while (*p == ' ' || *p == '\t') {
418
/* Skip content lines and blank lines. */
421
if (*p == '\r' || *p == '\n' || *p == '\0')
424
r = process_add_entry(a, mtree, &global, p,
426
} else if (strncmp(p, "/set", 4) == 0) {
427
if (p[4] != ' ' && p[4] != '\t')
429
r = process_global_set(a, &global, p);
430
} else if (strncmp(p, "/unset", 6) == 0) {
431
if (p[6] != ' ' && p[6] != '\t')
433
r = process_global_unset(a, &global, p);
437
if (r != ARCHIVE_OK) {
438
free_options(global);
443
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
444
"Can't parse line %ju", counter);
445
free_options(global);
446
return (ARCHIVE_FATAL);
450
* Read in the entire mtree file into memory on the first request.
451
* Then use the next unused file to satisfy each header request.
454
read_header(struct archive_read *a, struct archive_entry *entry)
460
mtree = (struct mtree *)(a->format->data);
462
if (mtree->fd >= 0) {
467
if (mtree->entries == NULL) {
468
mtree->resolver = archive_entry_linkresolver_new();
469
if (mtree->resolver == NULL)
470
return ARCHIVE_FATAL;
471
archive_entry_linkresolver_set_strategy(mtree->resolver,
472
ARCHIVE_FORMAT_MTREE);
473
r = read_mtree(a, mtree);
478
a->archive.archive_format = mtree->archive_format;
479
a->archive.archive_format_name = mtree->archive_format_name;
482
if (mtree->this_entry == NULL)
483
return (ARCHIVE_EOF);
484
if (strcmp(mtree->this_entry->name, "..") == 0) {
485
mtree->this_entry->used = 1;
486
if (archive_strlen(&mtree->current_dir) > 0) {
487
/* Roll back current path. */
488
p = mtree->current_dir.s
489
+ mtree->current_dir.length - 1;
490
while (p >= mtree->current_dir.s && *p != '/')
492
if (p >= mtree->current_dir.s)
494
mtree->current_dir.length
495
= p - mtree->current_dir.s + 1;
498
if (!mtree->this_entry->used) {
500
r = parse_file(a, entry, mtree, mtree->this_entry, &use_next);
504
mtree->this_entry = mtree->this_entry->next;
509
* A single file can have multiple lines contribute specifications.
510
* Parse as many lines as necessary, then pull additional information
511
* from a backing file on disk as necessary.
514
parse_file(struct archive_read *a, struct archive_entry *entry,
515
struct mtree *mtree, struct mtree_entry *mentry, int *use_next)
518
struct stat st_storage, *st;
519
struct mtree_entry *mp;
520
struct archive_entry *sparse_entry;
521
int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type;
525
/* Initialize reasonable defaults. */
526
mtree->filetype = AE_IFREG;
527
archive_entry_set_size(entry, 0);
529
/* Parse options from this line. */
531
r = parse_line(a, entry, mtree, mentry, &parsed_kws);
534
archive_entry_copy_pathname(entry, mentry->name);
536
* "Full" entries are allowed to have multiple lines
537
* and those lines aren't required to be adjacent. We
538
* don't support multiple lines for "relative" entries
539
* nor do we make any attempt to merge data from
540
* separate "relative" and "full" entries. (Merging
541
* "relative" and "full" entries would require dealing
542
* with pathname canonicalization, which is a very
545
for (mp = mentry->next; mp != NULL; mp = mp->next) {
546
if (mp->full && !mp->used
547
&& strcmp(mentry->name, mp->name) == 0) {
548
/* Later lines override earlier ones. */
550
r1 = parse_line(a, entry, mtree, mp,
558
* Relative entries require us to construct
559
* the full path and possibly update the
562
size_t n = archive_strlen(&mtree->current_dir);
564
archive_strcat(&mtree->current_dir, "/");
565
archive_strcat(&mtree->current_dir, mentry->name);
566
archive_entry_copy_pathname(entry, mtree->current_dir.s);
567
if (archive_entry_filetype(entry) != AE_IFDIR)
568
mtree->current_dir.length = n;
572
* Try to open and stat the file to get the real size
573
* and other file info. It would be nice to avoid
574
* this here so that getting a listing of an mtree
575
* wouldn't require opening every referenced contents
576
* file. But then we wouldn't know the actual
577
* contents size, so I don't see a really viable way
578
* around this. (Also, we may want to someday pull
579
* other unspecified info from the contents file on
583
if (archive_strlen(&mtree->contents_name) > 0)
584
path = mtree->contents_name.s;
586
path = archive_entry_pathname(entry);
588
if (archive_entry_filetype(entry) == AE_IFREG ||
589
archive_entry_filetype(entry) == AE_IFDIR) {
590
mtree->fd = open(path, O_RDONLY | O_BINARY);
591
if (mtree->fd == -1 &&
593
archive_strlen(&mtree->contents_name) > 0)) {
594
archive_set_error(&a->archive, errno,
595
"Can't open %s", path);
601
if (mtree->fd >= 0) {
602
if (fstat(mtree->fd, st) == -1) {
603
archive_set_error(&a->archive, errno,
604
"Could not fstat %s", path);
606
/* If we can't stat it, don't keep it open. */
611
} else if (lstat(path, st) == -1) {
616
* If there is a contents file on disk, use that size;
617
* otherwise leave it as-is (it might have been set from
618
* the mtree size= keyword).
622
if ((st->st_mode & S_IFMT) == S_IFREG &&
623
archive_entry_filetype(entry) != AE_IFREG)
625
if ((st->st_mode & S_IFMT) == S_IFLNK &&
626
archive_entry_filetype(entry) != AE_IFLNK)
628
if ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
629
archive_entry_filetype(entry) != AE_IFSOCK)
631
if ((st->st_mode & S_IFMT) == S_IFCHR &&
632
archive_entry_filetype(entry) != AE_IFCHR)
634
if ((st->st_mode & S_IFMT) == S_IFBLK &&
635
archive_entry_filetype(entry) != AE_IFBLK)
637
if ((st->st_mode & S_IFMT) == S_IFDIR &&
638
archive_entry_filetype(entry) != AE_IFDIR)
640
if ((st->st_mode & S_IFMT) == S_IFIFO &&
641
archive_entry_filetype(entry) != AE_IFIFO)
644
if (mismatched_type) {
645
if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) {
646
archive_set_error(&a->archive,
648
"mtree specification has different type for %s",
649
archive_entry_pathname(entry));
654
/* Don't hold a non-regular file open. */
664
if ((parsed_kws & MTREE_HAS_DEVICE) == 0 &&
665
(archive_entry_filetype(entry) == AE_IFCHR ||
666
archive_entry_filetype(entry) == AE_IFBLK))
667
archive_entry_set_rdev(entry, st->st_rdev);
668
if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0)
669
archive_entry_set_gid(entry, st->st_gid);
670
if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0)
671
archive_entry_set_uid(entry, st->st_uid);
672
if ((parsed_kws & MTREE_HAS_MTIME) == 0) {
673
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
674
archive_entry_set_mtime(entry, st->st_mtime,
675
st->st_mtimespec.tv_nsec);
676
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
677
archive_entry_set_mtime(entry, st->st_mtime,
678
st->st_mtim.tv_nsec);
679
#elif HAVE_STRUCT_STAT_ST_MTIME_N
680
archive_entry_set_mtime(entry, st->st_mtime,
682
#elif HAVE_STRUCT_STAT_ST_UMTIME
683
archive_entry_set_mtime(entry, st->st_mtime,
685
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
686
archive_entry_set_mtime(entry, st->st_mtime,
687
st->st_mtime_usec*1000);
689
archive_entry_set_mtime(entry, st->st_mtime, 0);
692
if ((parsed_kws & MTREE_HAS_NLINK) == 0)
693
archive_entry_set_nlink(entry, st->st_nlink);
694
if ((parsed_kws & MTREE_HAS_PERM) == 0)
695
archive_entry_set_perm(entry, st->st_mode);
696
if ((parsed_kws & MTREE_HAS_SIZE) == 0)
697
archive_entry_set_size(entry, st->st_size);
698
archive_entry_set_ino(entry, st->st_ino);
699
archive_entry_set_dev(entry, st->st_dev);
701
archive_entry_linkify(mtree->resolver, &entry, &sparse_entry);
702
} else if (parsed_kws & MTREE_HAS_OPTIONAL) {
704
* Couldn't open the entry, stat it or the on-disk type
705
* didn't match. If this entry is optional, just ignore it
706
* and read the next header entry.
712
mtree->cur_size = archive_entry_size(entry);
719
* Each line contains a sequence of keywords.
722
parse_line(struct archive_read *a, struct archive_entry *entry,
723
struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws)
725
struct mtree_option *iter;
726
int r = ARCHIVE_OK, r1;
728
for (iter = mp->options; iter != NULL; iter = iter->next) {
729
r1 = parse_keyword(a, mtree, entry, iter, parsed_kws);
733
if ((*parsed_kws & MTREE_HAS_TYPE) == 0) {
734
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
735
"Missing type keyword in mtree specification");
736
return (ARCHIVE_WARN);
742
* Device entries have one of the following forms:
744
* format,major,minor[,subdevice]
746
* Just use major and minor, no translation etc is done
750
parse_device(struct archive *a, struct archive_entry *entry, char *val)
752
char *comma1, *comma2;
754
comma1 = strchr(val, ',');
755
if (comma1 == NULL) {
756
archive_entry_set_dev(entry, mtree_atol10(&val));
760
comma2 = strchr(comma1, ',');
761
if (comma2 == NULL) {
762
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
763
"Malformed device attribute");
764
return (ARCHIVE_WARN);
767
archive_entry_set_rdevmajor(entry, mtree_atol(&comma1));
768
archive_entry_set_rdevminor(entry, mtree_atol(&comma2));
773
* Parse a single keyword and its value.
776
parse_keyword(struct archive_read *a, struct mtree *mtree,
777
struct archive_entry *entry, struct mtree_option *option, int *parsed_kws)
786
if (strcmp(key, "optional") == 0) {
787
*parsed_kws |= MTREE_HAS_OPTIONAL;
790
if (strcmp(key, "ignore") == 0) {
792
* The mtree processing is not recursive, so
793
* recursion will only happen for explicitly listed
799
val = strchr(key, '=');
801
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
802
"Malformed attribute \"%s\" (%d)", key, key[0]);
803
return (ARCHIVE_WARN);
811
if (strcmp(key, "content") == 0
812
|| strcmp(key, "contents") == 0) {
813
parse_escapes(val, NULL);
814
archive_strcpy(&mtree->contents_name, val);
817
if (strcmp(key, "cksum") == 0)
820
if (strcmp(key, "device") == 0) {
821
*parsed_kws |= MTREE_HAS_DEVICE;
822
return parse_device(&a->archive, entry, val);
825
if (strcmp(key, "flags") == 0) {
826
*parsed_kws |= MTREE_HAS_FFLAGS;
827
archive_entry_copy_fflags_text(entry, val);
831
if (strcmp(key, "gid") == 0) {
832
*parsed_kws |= MTREE_HAS_GID;
833
archive_entry_set_gid(entry, mtree_atol10(&val));
836
if (strcmp(key, "gname") == 0) {
837
*parsed_kws |= MTREE_HAS_GNAME;
838
archive_entry_copy_gname(entry, val);
842
if (strcmp(key, "link") == 0) {
843
archive_entry_copy_symlink(entry, val);
847
if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
849
if (strcmp(key, "mode") == 0) {
850
if (val[0] >= '0' && val[0] <= '9') {
851
*parsed_kws |= MTREE_HAS_PERM;
852
archive_entry_set_perm(entry,
855
archive_set_error(&a->archive,
856
ARCHIVE_ERRNO_FILE_FORMAT,
857
"Symbolic mode \"%s\" unsupported", val);
863
if (strcmp(key, "nlink") == 0) {
864
*parsed_kws |= MTREE_HAS_NLINK;
865
archive_entry_set_nlink(entry, mtree_atol10(&val));
869
if (strcmp(key, "rmd160") == 0 ||
870
strcmp(key, "rmd160digest") == 0)
873
if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
875
if (strcmp(key, "sha256") == 0 ||
876
strcmp(key, "sha256digest") == 0)
878
if (strcmp(key, "sha384") == 0 ||
879
strcmp(key, "sha384digest") == 0)
881
if (strcmp(key, "sha512") == 0 ||
882
strcmp(key, "sha512digest") == 0)
884
if (strcmp(key, "size") == 0) {
885
archive_entry_set_size(entry, mtree_atol10(&val));
889
if (strcmp(key, "tags") == 0) {
891
* Comma delimited list of tags.
892
* Ignore the tags for now, but the interface
893
* should be extended to allow inclusion/exclusion.
897
if (strcmp(key, "time") == 0) {
901
*parsed_kws |= MTREE_HAS_MTIME;
902
m = (time_t)mtree_atol10(&val);
905
ns = (long)mtree_atol10(&val);
908
archive_entry_set_mtime(entry, m, ns);
911
if (strcmp(key, "type") == 0) {
912
*parsed_kws |= MTREE_HAS_TYPE;
915
if (strcmp(val, "block") == 0) {
916
mtree->filetype = AE_IFBLK;
920
if (strcmp(val, "char") == 0) {
921
mtree->filetype = AE_IFCHR;
925
if (strcmp(val, "dir") == 0) {
926
mtree->filetype = AE_IFDIR;
930
if (strcmp(val, "fifo") == 0) {
931
mtree->filetype = AE_IFIFO;
934
if (strcmp(val, "file") == 0) {
935
mtree->filetype = AE_IFREG;
939
if (strcmp(val, "link") == 0) {
940
mtree->filetype = AE_IFLNK;
944
archive_set_error(&a->archive,
945
ARCHIVE_ERRNO_FILE_FORMAT,
946
"Unrecognized file type \"%s\"", val);
947
return (ARCHIVE_WARN);
949
archive_entry_set_filetype(entry, mtree->filetype);
953
if (strcmp(key, "uid") == 0) {
954
*parsed_kws |= MTREE_HAS_UID;
955
archive_entry_set_uid(entry, mtree_atol10(&val));
958
if (strcmp(key, "uname") == 0) {
959
*parsed_kws |= MTREE_HAS_UNAME;
960
archive_entry_copy_uname(entry, val);
964
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
965
"Unrecognized key %s=%s", key, val);
966
return (ARCHIVE_WARN);
972
read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
974
size_t bytes_to_read;
978
mtree = (struct mtree *)(a->format->data);
983
return (ARCHIVE_EOF);
985
if (mtree->buff == NULL) {
986
mtree->buffsize = 64 * 1024;
987
mtree->buff = malloc(mtree->buffsize);
988
if (mtree->buff == NULL) {
989
archive_set_error(&a->archive, ENOMEM,
990
"Can't allocate memory");
991
return (ARCHIVE_FATAL);
996
*offset = mtree->offset;
997
if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset)
998
bytes_to_read = mtree->cur_size - mtree->offset;
1000
bytes_to_read = mtree->buffsize;
1001
bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
1002
if (bytes_read < 0) {
1003
archive_set_error(&a->archive, errno, "Can't read");
1004
return (ARCHIVE_WARN);
1006
if (bytes_read == 0) {
1008
return (ARCHIVE_EOF);
1010
mtree->offset += bytes_read;
1012
return (ARCHIVE_OK);
1015
/* Skip does nothing except possibly close the contents file. */
1017
skip(struct archive_read *a)
1019
struct mtree *mtree;
1021
mtree = (struct mtree *)(a->format->data);
1022
if (mtree->fd >= 0) {
1026
return (ARCHIVE_OK);
1030
* Since parsing backslash sequences always makes strings shorter,
1031
* we can always do this conversion in-place.
1034
parse_escapes(char *src, struct mtree_entry *mentry)
1039
if (mentry != NULL && strcmp(src, ".") == 0)
1042
while (*src != '\0') {
1044
if (c == '/' && mentry != NULL)
1049
if (src[1] < '0' || src[1] > '7') {
1058
if (src[1] >= '0' && src[1] <= '7' &&
1059
src[2] >= '0' && src[2] <= '7') {
1060
c = (src[0] - '0') << 6;
1061
c |= (src[1] - '0') << 3;
1062
c |= (src[2] - '0');
1106
* Note that this implementation does not (and should not!) obey
1107
* locale settings; you cannot simply substitute strtol here, since
1108
* it does obey locale.
1111
mtree_atol8(char **p)
1113
int64_t l, limit, last_digit_limit;
1117
limit = INT64_MAX / base;
1118
last_digit_limit = INT64_MAX % base;
1122
while (digit >= 0 && digit < base) {
1123
if (l>limit || (l == limit && digit > last_digit_limit)) {
1124
l = INT64_MAX; /* Truncate on overflow. */
1127
l = (l * base) + digit;
1128
digit = *++(*p) - '0';
1134
* Note that this implementation does not (and should not!) obey
1135
* locale settings; you cannot simply substitute strtol here, since
1136
* it does obey locale.
1139
mtree_atol10(char **p)
1141
int64_t l, limit, last_digit_limit;
1142
int base, digit, sign;
1145
limit = INT64_MAX / base;
1146
last_digit_limit = INT64_MAX % base;
1156
while (digit >= 0 && digit < base) {
1157
if (l > limit || (l == limit && digit > last_digit_limit)) {
1158
l = INT64_MAX; /* Truncate on overflow. */
1161
l = (l * base) + digit;
1162
digit = *++(*p) - '0';
1164
return (sign < 0) ? -l : l;
1168
* Note that this implementation does not (and should not!) obey
1169
* locale settings; you cannot simply substitute strtol here, since
1170
* it does obey locale.
1173
mtree_atol16(char **p)
1175
int64_t l, limit, last_digit_limit;
1176
int base, digit, sign;
1179
limit = INT64_MAX / base;
1180
last_digit_limit = INT64_MAX % base;
1189
if (**p >= '0' && **p <= '9')
1191
else if (**p >= 'a' && **p <= 'f')
1192
digit = **p - 'a' + 10;
1193
else if (**p >= 'A' && **p <= 'F')
1194
digit = **p - 'A' + 10;
1197
while (digit >= 0 && digit < base) {
1198
if (l > limit || (l == limit && digit > last_digit_limit)) {
1199
l = INT64_MAX; /* Truncate on overflow. */
1202
l = (l * base) + digit;
1203
if (**p >= '0' && **p <= '9')
1205
else if (**p >= 'a' && **p <= 'f')
1206
digit = **p - 'a' + 10;
1207
else if (**p >= 'A' && **p <= 'F')
1208
digit = **p - 'A' + 10;
1212
return (sign < 0) ? -l : l;
1216
mtree_atol(char **p)
1219
return mtree_atol10(p);
1220
if ((*p)[1] == 'x' || (*p)[1] == 'X') {
1222
return mtree_atol16(p);
1224
return mtree_atol8(p);
1228
* Returns length of line (including trailing newline)
1229
* or negative on error. 'start' argument is updated to
1230
* point to first character of line.
1233
readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
1236
ssize_t total_size = 0;
1237
ssize_t find_off = 0;
1243
/* Accumulate line in a line buffer. */
1245
/* Read some more. */
1246
t = __archive_read_ahead(a, 1, &bytes_read);
1250
return (ARCHIVE_FATAL);
1251
s = t; /* Start of line? */
1252
p = memchr(t, '\n', bytes_read);
1253
/* If we found '\n', trim the read. */
1255
bytes_read = 1 + ((const char *)p) - s;
1257
if (total_size + bytes_read + 1 > limit) {
1258
archive_set_error(&a->archive,
1259
ARCHIVE_ERRNO_FILE_FORMAT,
1261
return (ARCHIVE_FATAL);
1263
if (archive_string_ensure(&mtree->line,
1264
total_size + bytes_read + 1) == NULL) {
1265
archive_set_error(&a->archive, ENOMEM,
1266
"Can't allocate working buffer");
1267
return (ARCHIVE_FATAL);
1269
memcpy(mtree->line.s + total_size, t, bytes_read);
1270
__archive_read_consume(a, bytes_read);
1271
total_size += bytes_read;
1272
/* Null terminate. */
1273
mtree->line.s[total_size] = '\0';
1274
/* If we found an unescaped '\n', clean up and return. */
1275
for (u = mtree->line.s + find_off; *u; ++u) {
1277
*start = mtree->line.s;
1283
*start = mtree->line.s;
1294
total_size - (u - mtree->line.s) + 1);
1302
find_off = u - mtree->line.s;