]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_read_support_format_mtree.c
This commit was generated by cvs2svn to compensate for changes in r174993,
[FreeBSD/FreeBSD.git] / lib / libarchive / archive_read_support_format_mtree.c
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  */
25
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
28
29 #ifdef HAVE_SYS_STAT_H
30 #include <sys/stat.h>
31 #endif
32 #ifdef HAVE_ERRNO_H
33 #include <errno.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #include <stddef.h>
39 /* #include <stdint.h> */ /* See archive_platform.h */
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #ifdef HAVE_STRING_H
44 #include <string.h>
45 #endif
46
47 #include "archive.h"
48 #include "archive_entry.h"
49 #include "archive_private.h"
50 #include "archive_read_private.h"
51 #include "archive_string.h"
52
53 struct mtree_entry {
54         struct mtree_entry *next;
55         char *name;
56         char *option_start;
57         char *option_end;
58         char full;
59         char used;
60 };
61
62 struct mtree {
63         struct archive_string    line;
64         size_t                   buffsize;
65         char                    *buff;
66         off_t                    offset;
67         int                      fd;
68         int                      filetype;
69         int                      archive_format;
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;
75 };
76
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 **);
90
91 int
92 archive_read_support_format_mtree(struct archive *_a)
93 {
94         struct archive_read *a = (struct archive_read *)_a;
95         struct mtree *mtree;
96         int r;
97
98         mtree = (struct mtree *)malloc(sizeof(*mtree));
99         if (mtree == NULL) {
100                 archive_set_error(&a->archive, ENOMEM,
101                     "Can't allocate mtree data");
102                 return (ARCHIVE_FATAL);
103         }
104         memset(mtree, 0, sizeof(*mtree));
105         mtree->fd = -1;
106
107         r = __archive_read_register_format(a, mtree,
108             mtree_bid, read_header, read_data, skip, cleanup);
109
110         if (r != ARCHIVE_OK)
111                 free(mtree);
112         return (ARCHIVE_OK);
113 }
114
115 static int
116 cleanup(struct archive_read *a)
117 {
118         struct mtree *mtree;
119         struct mtree_entry *p, *q;
120
121         mtree = (struct mtree *)(a->format->data);
122         p = mtree->entries;
123         while (p != NULL) {
124                 q = p->next;
125                 free(p->name);
126                 /*
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!
130                  */
131                 free(p);
132                 p = q;
133         }
134         archive_string_free(&mtree->line);
135         archive_string_free(&mtree->current_dir);
136         archive_string_free(&mtree->contents_name);
137         free(mtree->buff);
138         free(mtree);
139         (a->format->data) = NULL;
140         return (ARCHIVE_OK);
141 }
142
143
144 static int
145 mtree_bid(struct archive_read *a)
146 {
147         struct mtree *mtree;
148         ssize_t bytes_read;
149         const void *h;
150         const char *signature = "#mtree";
151         const char *p;
152         int bid;
153
154         mtree = (struct mtree *)(a->format->data);
155
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));
158
159         if (bytes_read <= 0)
160                 return (bytes_read);
161
162         p = h;
163         bid = 0;
164         while (bytes_read > 0 && *signature != '\0') {
165                 if (*p != *signature)
166                         return (bid = 0);
167                 bid += 8;
168                 p++;
169                 signature++;
170                 bytes_read--;
171         }
172         return (bid);
173 }
174
175 /*
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.
179  */
180 static int
181 read_mtree(struct archive_read *a, struct mtree *mtree)
182 {
183         ssize_t len;
184         char *p;
185         struct mtree_entry *mentry;
186         struct mtree_entry *last_mentry = NULL;
187
188         mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1;
189         mtree->archive_format_name = "mtree";
190
191         for (;;) {
192                 len = readline(a, mtree, &p, 256);
193                 if (len == 0) {
194                         mtree->this_entry = mtree->entries;
195                         return (ARCHIVE_OK);
196                 }
197                 if (len < 0)
198                         return (len);
199                 /* Leading whitespace is never significant, ignore it. */
200                 while (*p == ' ' || *p == '\t') {
201                         ++p;
202                         --len;
203                 }
204                 /* Skip content lines and blank lines. */
205                 if (*p == '#')
206                         continue;
207                 if (*p == '\r' || *p == '\n' || *p == '\0')
208                         continue;
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);
214                 }
215                 memset(mentry, 0, sizeof(*mentry));
216                 /* Add this entry to list. */
217                 if (last_mentry == NULL) {
218                         last_mentry = mtree->entries = mentry;
219                 } else {
220                         last_mentry->next = mentry;
221                 }
222                 last_mentry = mentry;
223
224                 /* Copy line over onto heap. */
225                 mentry->name = malloc(len + 1);
226                 if (mentry->name == NULL) {
227                         free(mentry);
228                         archive_set_error(&a->archive, ENOMEM,
229                             "Can't allocate memory");
230                         return (ARCHIVE_FATAL);
231                 }
232                 strcpy(mentry->name, p);
233                 mentry->option_end = mentry->name + len;
234                 /* Find end of name. */
235                 p = mentry->name;
236                 while (*p != ' ' && *p != '\n' && *p != '\0')
237                         ++p;
238                 *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'))
242                         ++p;
243                 mentry->option_start = p;
244                 /* Null terminate each separate option. */
245                 while (++p < mentry->option_end)
246                         if (*p == ' ' || *p == '\t' || *p == '\n')
247                                 *p = '\0';
248         }
249 }
250
251 static int
252 read_header(struct archive_read *a, struct archive_entry *entry)
253 {
254         struct stat st;
255         struct mtree *mtree;
256         struct mtree_entry *mentry, *mentry2;
257         char *p, *q;
258         int r = ARCHIVE_OK, r1;
259
260         mtree = (struct mtree *)(a->format->data);
261
262         if (mtree->fd >= 0) {
263                 close(mtree->fd);
264                 mtree->fd = -1;
265         }
266
267         if (mtree->entries == NULL) {
268                 r = read_mtree(a, mtree);
269                 if (r != ARCHIVE_OK)
270                         return (r);
271         }
272
273         a->archive.archive_format = mtree->archive_format;
274         a->archive.archive_format_name = mtree->archive_format_name;
275
276         for (;;) {
277                 mentry = mtree->this_entry;
278                 if (mentry == NULL) {
279                         mtree->this_entry = NULL;
280                         return (ARCHIVE_EOF);
281                 }
282                 mtree->this_entry = mentry->next;
283                 if (mentry->used)
284                         continue;
285                 mentry->used = 1;
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 != '/')
292                                         --p;
293                                 if (p >= mtree->current_dir.s)
294                                         --p;
295                                 mtree->current_dir.length
296                                     = p - mtree->current_dir.s + 1;
297                         }
298                         continue;
299                 }
300
301                 mtree->filetype = AE_IFREG;
302
303                 /* Parse options. */
304                 p = mentry->option_start;
305                 while (p < mentry->option_end) {
306                         q = p + strlen(p);
307                         r1 = parse_setting(a, mtree, entry, p, q);
308                         if (r1 != ARCHIVE_OK)
309                                 r = r1;
310                         p = q + 1;
311                 }
312
313                 if (mentry->full) {
314                         archive_entry_copy_pathname(entry, mentry->name);
315                         /*
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.)
325                          */
326                         mentry2 = mentry->next;
327                         while (mentry2 != NULL) {
328                                 if (mentry2->full
329                                     && !mentry2->used
330                                     && strcmp(mentry->name, mentry2->name) == 0) {
331                                         /*
332                                          * Add those options as well;
333                                          * later lines override
334                                          * earlier ones.
335                                          */
336                                         p = mentry2->option_start;
337                                         while (p < mentry2->option_end) {
338                                                 q = p + strlen(p);
339                                                 r1 = parse_setting(a, mtree, entry, p, q);
340                                                 if (r1 != ARCHIVE_OK)
341                                                         r = r1;
342                                                 p = q + 1;
343                                         }
344                                         mentry2->used = 1;
345                                 }
346                                 mentry2 = mentry2->next;
347                         }
348                 } else {
349                         /*
350                          * Relative entries require us to construct
351                          * the full path and possibly update the
352                          * current directory.
353                          */
354                         size_t n = archive_strlen(&mtree->current_dir);
355                         if (n > 0)
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;
361                 }
362
363                 /*
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.)
372                  */
373                 if (archive_strlen(&mtree->contents_name) > 0) {
374                         mtree->fd = open(mtree->contents_name.s, O_RDONLY);
375                         if (mtree->fd < 0) {
376                                 archive_set_error(&a->archive, errno,
377                                     "Can't open content=\"%s\"",
378                                     mtree->contents_name.s);
379                                 r = ARCHIVE_WARN;
380                         }
381                 } else {
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. */
385                 }
386
387                 /*
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).
391                  */
392                 if (mtree->fd >= 0) {
393                         fstat(mtree->fd, &st);
394                         archive_entry_set_size(entry, st.st_size);
395                 }
396
397                 return r;
398         }
399 }
400
401 static int
402 parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, char *key, char *end)
403 {
404         char *val;
405
406
407         if (end == key)
408                 return (ARCHIVE_OK);
409         if (*key == '\0')
410                 return (ARCHIVE_OK);
411
412         val = strchr(key, '=');
413         if (val == NULL) {
414                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
415                     "Malformed attribute \"%s\" (%d)", key, key[0]);
416                 return (ARCHIVE_WARN);
417         }
418
419         *val = '\0';
420         ++val;
421
422         switch (key[0]) {
423         case 'c':
424                 if (strcmp(key, "content") == 0) {
425                         parse_escapes(val, NULL);
426                         archive_strcpy(&mtree->contents_name, val);
427                         break;
428                 }
429         case 'g':
430                 if (strcmp(key, "gid") == 0) {
431                         archive_entry_set_gid(entry, mtree_atol10(&val));
432                         break;
433                 }
434                 if (strcmp(key, "gname") == 0) {
435                         archive_entry_copy_gname(entry, val);
436                         break;
437                 }
438         case 'm':
439                 if (strcmp(key, "mode") == 0) {
440                         if (val[0] == '0') {
441                                 archive_entry_set_perm(entry,
442                                     mtree_atol8(&val));
443                         } else
444                                 archive_set_error(&a->archive,
445                                     ARCHIVE_ERRNO_FILE_FORMAT,
446                                     "Symbolic mode \"%s\" unsupported", val);
447                         break;
448                 }
449         case 't':
450                 if (strcmp(key, "type") == 0) {
451                         switch (val[0]) {
452                         case 'b':
453                                 if (strcmp(val, "block") == 0) {
454                                         mtree->filetype = AE_IFBLK;
455                                         break;
456                                 }
457                         case 'c':
458                                 if (strcmp(val, "char") == 0) {
459                                         mtree->filetype = AE_IFCHR;
460                                         break;
461                                 }
462                         case 'd':
463                                 if (strcmp(val, "dir") == 0) {
464                                         mtree->filetype = AE_IFDIR;
465                                         break;
466                                 }
467                         case 'f':
468                                 if (strcmp(val, "fifo") == 0) {
469                                         mtree->filetype = AE_IFIFO;
470                                         break;
471                                 }
472                                 if (strcmp(val, "file") == 0) {
473                                         mtree->filetype = AE_IFREG;
474                                         break;
475                                 }
476                         case 'l':
477                                 if (strcmp(val, "link") == 0) {
478                                         mtree->filetype = AE_IFLNK;
479                                         break;
480                                 }
481                         default:
482                                 archive_set_error(&a->archive,
483                                     ARCHIVE_ERRNO_FILE_FORMAT,
484                                     "Unrecognized file type \"%s\"", val);
485                                 return (ARCHIVE_WARN);
486                         }
487                         archive_entry_set_filetype(entry, mtree->filetype);
488                         break;
489                 }
490                 if (strcmp(key, "time") == 0) {
491                         archive_entry_set_mtime(entry, mtree_atol10(&val), 0);
492                         break;
493                 }
494         case 'u':
495                 if (strcmp(key, "uid") == 0) {
496                         archive_entry_set_uid(entry, mtree_atol10(&val));
497                         break;
498                 }
499                 if (strcmp(key, "uname") == 0) {
500                         archive_entry_copy_uname(entry, val);
501                         break;
502                 }
503         default:
504                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
505                     "Unrecognized key %s=%s", key, val);
506                 return (ARCHIVE_WARN);
507         }
508         return (ARCHIVE_OK);
509 }
510
511 static int
512 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
513 {
514         ssize_t bytes_read;
515         struct mtree *mtree;
516
517         mtree = (struct mtree *)(a->format->data);
518         if (mtree->fd < 0) {
519                 *buff = NULL;
520                 *offset = 0;
521                 *size = 0;
522                 return (ARCHIVE_EOF);
523         }
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");
530                 }
531         }
532
533         *buff = mtree->buff;
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);
539         }
540         if (bytes_read == 0) {
541                 *size = 0;
542                 return (ARCHIVE_EOF);
543         }
544         mtree->offset += bytes_read;
545         *size = (size_t)bytes_read;
546         return (ARCHIVE_OK);
547 }
548
549 /* Skip does nothing except possibly close the contents file. */
550 static int
551 skip(struct archive_read *a)
552 {
553         struct mtree *mtree;
554
555         mtree = (struct mtree *)(a->format->data);
556         if (mtree->fd >= 0) {
557                 close(mtree->fd);
558                 mtree->fd = -1;
559         }
560         return (ARCHIVE_OK);
561 }
562
563 /*
564  * Since parsing octal escapes always makes strings shorter,
565  * we can always do this conversion in-place.
566  */
567 static void
568 parse_escapes(char *src, struct mtree_entry *mentry)
569 {
570         char *dest = src;
571         char c;
572
573         while (*src != '\0') {
574                 c = *src++;
575                 if (c == '/' && mentry != NULL)
576                         mentry->full = 1;
577                 if (c == '\\') {
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;
583                                 c |= (src[2] - '0');
584                                 src += 3;
585                         }
586                 }
587                 *dest++ = c;
588         }
589         *dest = '\0';
590 }
591
592 /*
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.
596  */
597 static int64_t
598 mtree_atol8(char **p)
599 {
600         int64_t l, limit, last_digit_limit;
601         int digit, base;
602
603         base = 8;
604         limit = INT64_MAX / base;
605         last_digit_limit = INT64_MAX % base;
606
607         l = 0;
608         digit = **p - '0';
609         while (digit >= 0 && digit < base) {
610                 if (l>limit || (l == limit && digit > last_digit_limit)) {
611                         l = INT64_MAX; /* Truncate on overflow. */
612                         break;
613                 }
614                 l = (l * base) + digit;
615                 digit = *++(*p) - '0';
616         }
617         return (l);
618 }
619
620 /*
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.
624  */
625 static int64_t
626 mtree_atol10(char **p)
627 {
628         int64_t l, limit, last_digit_limit;
629         int base, digit, sign;
630
631         base = 10;
632         limit = INT64_MAX / base;
633         last_digit_limit = INT64_MAX % base;
634
635         if (**p == '-') {
636                 sign = -1;
637                 ++(*p);
638         } else
639                 sign = 1;
640
641         l = 0;
642         digit = **p - '0';
643         while (digit >= 0 && digit < base) {
644                 if (l > limit || (l == limit && digit > last_digit_limit)) {
645                         l = UINT64_MAX; /* Truncate on overflow. */
646                         break;
647                 }
648                 l = (l * base) + digit;
649                 digit = *++(*p) - '0';
650         }
651         return (sign < 0) ? -l : l;
652 }
653
654 /*
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.
658  */
659 static ssize_t
660 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
661 {
662         ssize_t bytes_read;
663         ssize_t total_size = 0;
664         const void *t;
665         const char *s;
666         void *p;
667
668         /* Accumulate line in a line buffer. */
669         for (;;) {
670                 /* Read some more. */
671                 bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
672                 if (bytes_read == 0)
673                         return (0);
674                 if (bytes_read < 0)
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. */
679                 if (p != NULL) {
680                         bytes_read = 1 + ((const char *)p) - s;
681                 }
682                 if (total_size + bytes_read + 1 > limit) {
683                         archive_set_error(&a->archive,
684                             ARCHIVE_ERRNO_FILE_FORMAT,
685                             "Line too long");
686                         return (ARCHIVE_FATAL);
687                 }
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);
693                 }
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. */
700                 if (p != NULL) {
701                         *start = mtree->line.s;
702                         return (total_size);
703                 }
704         }
705 }