]> 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 r178848,
[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 #ifndef O_BINARY
54 #define O_BINARY 0
55 #endif
56
57 struct mtree_entry {
58         struct mtree_entry *next;
59         char *name;
60         char *option_start;
61         char *option_end;
62         char full;
63         char used;
64 };
65
66 struct mtree {
67         struct archive_string    line;
68         size_t                   buffsize;
69         char                    *buff;
70         off_t                    offset;
71         int                      fd;
72         int                      filetype;
73         int                      archive_format;
74         const char              *archive_format_name;
75         struct mtree_entry      *entries;
76         struct mtree_entry      *this_entry;
77         struct archive_string    current_dir;
78         struct archive_string    contents_name;
79
80         off_t                    cur_size, cur_offset;
81 };
82
83 static int      cleanup(struct archive_read *);
84 static int      mtree_bid(struct archive_read *);
85 static int      parse_file(struct archive_read *, struct archive_entry *,
86                     struct mtree *, struct mtree_entry *);
87 static void     parse_escapes(char *, struct mtree_entry *);
88 static int      parse_line(struct archive_read *, struct archive_entry *,
89                     struct mtree *, struct mtree_entry *);
90 static int      parse_keyword(struct archive_read *, struct mtree *,
91                     struct archive_entry *, char *, char *);
92 static int      read_data(struct archive_read *a,
93                     const void **buff, size_t *size, off_t *offset);
94 static ssize_t  readline(struct archive_read *, struct mtree *, char **, ssize_t);
95 static int      skip(struct archive_read *a);
96 static int      read_header(struct archive_read *,
97                     struct archive_entry *);
98 static int64_t  mtree_atol10(char **);
99 static int64_t  mtree_atol8(char **);
100
101 int
102 archive_read_support_format_mtree(struct archive *_a)
103 {
104         struct archive_read *a = (struct archive_read *)_a;
105         struct mtree *mtree;
106         int r;
107
108         mtree = (struct mtree *)malloc(sizeof(*mtree));
109         if (mtree == NULL) {
110                 archive_set_error(&a->archive, ENOMEM,
111                     "Can't allocate mtree data");
112                 return (ARCHIVE_FATAL);
113         }
114         memset(mtree, 0, sizeof(*mtree));
115         mtree->fd = -1;
116
117         r = __archive_read_register_format(a, mtree,
118             mtree_bid, read_header, read_data, skip, cleanup);
119
120         if (r != ARCHIVE_OK)
121                 free(mtree);
122         return (ARCHIVE_OK);
123 }
124
125 static int
126 cleanup(struct archive_read *a)
127 {
128         struct mtree *mtree;
129         struct mtree_entry *p, *q;
130
131         mtree = (struct mtree *)(a->format->data);
132         p = mtree->entries;
133         while (p != NULL) {
134                 q = p->next;
135                 free(p->name);
136                 /*
137                  * Note: option_start, option_end are pointers into
138                  * the block that p->name points to.  So we should
139                  * not try to free them!
140                  */
141                 free(p);
142                 p = q;
143         }
144         archive_string_free(&mtree->line);
145         archive_string_free(&mtree->current_dir);
146         archive_string_free(&mtree->contents_name);
147         free(mtree->buff);
148         free(mtree);
149         (a->format->data) = NULL;
150         return (ARCHIVE_OK);
151 }
152
153
154 static int
155 mtree_bid(struct archive_read *a)
156 {
157         struct mtree *mtree;
158         ssize_t bytes_read;
159         const void *h;
160         const char *signature = "#mtree";
161         const char *p;
162         int bid;
163
164         mtree = (struct mtree *)(a->format->data);
165
166         /* Now let's look at the actual header and see if it matches. */
167         bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
168
169         if (bytes_read <= 0)
170                 return (bytes_read);
171
172         p = h;
173         bid = 0;
174         while (bytes_read > 0 && *signature != '\0') {
175                 if (*p != *signature)
176                         return (bid = 0);
177                 bid += 8;
178                 p++;
179                 signature++;
180                 bytes_read--;
181         }
182         return (bid);
183 }
184
185 /*
186  * The extended mtree format permits multiple lines specifying
187  * attributes for each file.  Practically speaking, that means we have
188  * to read the entire mtree file into memory up front.
189  */
190 static int
191 read_mtree(struct archive_read *a, struct mtree *mtree)
192 {
193         ssize_t len;
194         char *p;
195         struct mtree_entry *mentry;
196         struct mtree_entry *last_mentry = NULL;
197
198         mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1;
199         mtree->archive_format_name = "mtree";
200
201         for (;;) {
202                 len = readline(a, mtree, &p, 256);
203                 if (len == 0) {
204                         mtree->this_entry = mtree->entries;
205                         return (ARCHIVE_OK);
206                 }
207                 if (len < 0)
208                         return (len);
209                 /* Leading whitespace is never significant, ignore it. */
210                 while (*p == ' ' || *p == '\t') {
211                         ++p;
212                         --len;
213                 }
214                 /* Skip content lines and blank lines. */
215                 if (*p == '#')
216                         continue;
217                 if (*p == '\r' || *p == '\n' || *p == '\0')
218                         continue;
219                 mentry = malloc(sizeof(*mentry));
220                 if (mentry == NULL) {
221                         archive_set_error(&a->archive, ENOMEM,
222                             "Can't allocate memory");
223                         return (ARCHIVE_FATAL);
224                 }
225                 memset(mentry, 0, sizeof(*mentry));
226                 /* Add this entry to list. */
227                 if (last_mentry == NULL) {
228                         last_mentry = mtree->entries = mentry;
229                 } else {
230                         last_mentry->next = mentry;
231                 }
232                 last_mentry = mentry;
233
234                 /* Copy line over onto heap. */
235                 mentry->name = malloc(len + 1);
236                 if (mentry->name == NULL) {
237                         free(mentry);
238                         archive_set_error(&a->archive, ENOMEM,
239                             "Can't allocate memory");
240                         return (ARCHIVE_FATAL);
241                 }
242                 strcpy(mentry->name, p);
243                 mentry->option_end = mentry->name + len;
244                 /* Find end of name. */
245                 p = mentry->name;
246                 while (*p != ' ' && *p != '\n' && *p != '\0')
247                         ++p;
248                 *p++ = '\0';
249                 parse_escapes(mentry->name, mentry);
250                 /* Find start of options and record it. */
251                 while (p < mentry->option_end && (*p == ' ' || *p == '\t'))
252                         ++p;
253                 mentry->option_start = p;
254                 /* Null terminate each separate option. */
255                 while (++p < mentry->option_end)
256                         if (*p == ' ' || *p == '\t' || *p == '\n')
257                                 *p = '\0';
258         }
259 }
260
261 /*
262  * Read in the entire mtree file into memory on the first request.
263  * Then use the next unused file to satisfy each header request.
264  */
265 static int
266 read_header(struct archive_read *a, struct archive_entry *entry)
267 {
268         struct mtree *mtree;
269         char *p;
270         int r;
271
272         mtree = (struct mtree *)(a->format->data);
273
274         if (mtree->fd >= 0) {
275                 close(mtree->fd);
276                 mtree->fd = -1;
277         }
278
279         if (mtree->entries == NULL) {
280                 r = read_mtree(a, mtree);
281                 if (r != ARCHIVE_OK)
282                         return (r);
283         }
284
285         a->archive.archive_format = mtree->archive_format;
286         a->archive.archive_format_name = mtree->archive_format_name;
287
288         for (;;) {
289                 if (mtree->this_entry == NULL)
290                         return (ARCHIVE_EOF);
291                 if (strcmp(mtree->this_entry->name, "..") == 0) {
292                         mtree->this_entry->used = 1;
293                         if (archive_strlen(&mtree->current_dir) > 0) {
294                                 /* Roll back current path. */
295                                 p = mtree->current_dir.s
296                                     + mtree->current_dir.length - 1;
297                                 while (p >= mtree->current_dir.s && *p != '/')
298                                         --p;
299                                 if (p >= mtree->current_dir.s)
300                                         --p;
301                                 mtree->current_dir.length
302                                     = p - mtree->current_dir.s + 1;
303                         }
304                 }
305                 if (!mtree->this_entry->used) {
306                         r = parse_file(a, entry, mtree, mtree->this_entry);
307                         return (r);
308                 }
309                 mtree->this_entry = mtree->this_entry->next;
310         }
311 }
312
313 /*
314  * A single file can have multiple lines contribute specifications.
315  * Parse as many lines as necessary, then pull additional information
316  * from a backing file on disk as necessary.
317  */
318 static int
319 parse_file(struct archive_read *a, struct archive_entry *entry,
320     struct mtree *mtree, struct mtree_entry *mentry)
321 {
322         struct stat st;
323         struct mtree_entry *mp;
324         int r = ARCHIVE_OK, r1;
325
326         mentry->used = 1;
327
328         /* Initialize reasonable defaults. */
329         mtree->filetype = AE_IFREG;
330         archive_entry_set_size(entry, 0);
331
332         /* Parse options from this line. */
333         r = parse_line(a, entry, mtree, mentry);
334
335         if (mentry->full) {
336                 archive_entry_copy_pathname(entry, mentry->name);
337                 /*
338                  * "Full" entries are allowed to have multiple lines
339                  * and those lines aren't required to be adjacent.  We
340                  * don't support multiple lines for "relative" entries
341                  * nor do we make any attempt to merge data from
342                  * separate "relative" and "full" entries.  (Merging
343                  * "relative" and "full" entries would require dealing
344                  * with pathname canonicalization, which is a very
345                  * tricky subject.)
346                  */
347                 for (mp = mentry->next; mp != NULL; mp = mp->next) {
348                         if (mp->full && !mp->used
349                             && strcmp(mentry->name, mp->name) == 0) {
350                                 /* Later lines override earlier ones. */
351                                 mp->used = 1;
352                                 r1 = parse_line(a, entry, mtree, mp);
353                                 if (r1 < r)
354                                         r = r1;
355                         }
356                 }
357         } else {
358                 /*
359                  * Relative entries require us to construct
360                  * the full path and possibly update the
361                  * current directory.
362                  */
363                 size_t n = archive_strlen(&mtree->current_dir);
364                 if (n > 0)
365                         archive_strcat(&mtree->current_dir, "/");
366                 archive_strcat(&mtree->current_dir, mentry->name);
367                 archive_entry_copy_pathname(entry, mtree->current_dir.s);
368                 if (archive_entry_filetype(entry) != AE_IFDIR)
369                         mtree->current_dir.length = n;
370         }
371
372         /*
373          * Try to open and stat the file to get the real size
374          * and other file info.  It would be nice to avoid
375          * this here so that getting a listing of an mtree
376          * wouldn't require opening every referenced contents
377          * file.  But then we wouldn't know the actual
378          * contents size, so I don't see a really viable way
379          * around this.  (Also, we may want to someday pull
380          * other unspecified info from the contents file on
381          * disk.)
382          */
383         mtree->fd = -1;
384         if (archive_strlen(&mtree->contents_name) > 0) {
385                 mtree->fd = open(mtree->contents_name.s,
386                     O_RDONLY | O_BINARY);
387                 if (mtree->fd < 0) {
388                         archive_set_error(&a->archive, errno,
389                             "Can't open content=\"%s\"",
390                             mtree->contents_name.s);
391                         r = ARCHIVE_WARN;
392                 }
393         } else if (archive_entry_filetype(entry) == AE_IFREG) {
394                 mtree->fd = open(archive_entry_pathname(entry),
395                     O_RDONLY | O_BINARY);
396         }
397
398         /*
399          * If there is a contents file on disk, use that size;
400          * otherwise leave it as-is (it might have been set from
401          * the mtree size= keyword).
402          */
403         if (mtree->fd >= 0) {
404                 if (fstat(mtree->fd, &st) != 0) {
405                         archive_set_error(&a->archive, errno,
406                             "could not stat %s",
407                             archive_entry_pathname(entry));
408                         r = ARCHIVE_WARN;
409                         /* If we can't stat it, don't keep it open. */
410                         close(mtree->fd);
411                         mtree->fd = -1;
412                 } else if ((st.st_mode & S_IFMT) != S_IFREG) {
413                         archive_set_error(&a->archive, errno,
414                             "%s is not a regular file",
415                             archive_entry_pathname(entry));
416                         r = ARCHIVE_WARN;
417                         /* Don't hold a non-regular file open. */
418                         close(mtree->fd);
419                         mtree->fd = -1;
420                 } else {
421                         archive_entry_set_size(entry, st.st_size);
422                         archive_entry_set_ino(entry, st.st_ino);
423                         archive_entry_set_dev(entry, st.st_dev);
424                         archive_entry_set_nlink(entry, st.st_nlink);
425                 }
426         }
427         mtree->cur_size = archive_entry_size(entry);
428         mtree->offset = 0;
429
430         return r;
431 }
432
433 /*
434  * Each line contains a sequence of keywords.
435  */
436 static int
437 parse_line(struct archive_read *a, struct archive_entry *entry,
438     struct mtree *mtree, struct mtree_entry *mp)
439 {
440         char *p, *q;
441         int r = ARCHIVE_OK, r1;
442
443         p = mp->option_start;
444         while (p < mp->option_end) {
445                 q = p + strlen(p);
446                 r1 = parse_keyword(a, mtree, entry, p, q);
447                 if (r1 < r)
448                         r = r1;
449                 p = q + 1;
450         }
451         return (r);
452 }
453
454 /*
455  * Parse a single keyword and its value.
456  */
457 static int
458 parse_keyword(struct archive_read *a, struct mtree *mtree,
459     struct archive_entry *entry, char *key, char *end)
460 {
461         char *val;
462
463         if (end == key)
464                 return (ARCHIVE_OK);
465         if (*key == '\0')
466                 return (ARCHIVE_OK);
467
468         val = strchr(key, '=');
469         if (val == NULL) {
470                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
471                     "Malformed attribute \"%s\" (%d)", key, key[0]);
472                 return (ARCHIVE_WARN);
473         }
474
475         *val = '\0';
476         ++val;
477
478         switch (key[0]) {
479         case 'c':
480                 if (strcmp(key, "content") == 0
481                     || strcmp(key, "contents") == 0) {
482                         parse_escapes(val, NULL);
483                         archive_strcpy(&mtree->contents_name, val);
484                         break;
485                 }
486         case 'g':
487                 if (strcmp(key, "gid") == 0) {
488                         archive_entry_set_gid(entry, mtree_atol10(&val));
489                         break;
490                 }
491                 if (strcmp(key, "gname") == 0) {
492                         archive_entry_copy_gname(entry, val);
493                         break;
494                 }
495         case 'l':
496                 if (strcmp(key, "link") == 0) {
497                         archive_entry_set_link(entry, val);
498                         break;
499                 }
500         case 'm':
501                 if (strcmp(key, "mode") == 0) {
502                         if (val[0] == '0') {
503                                 archive_entry_set_perm(entry,
504                                     mtree_atol8(&val));
505                         } else
506                                 archive_set_error(&a->archive,
507                                     ARCHIVE_ERRNO_FILE_FORMAT,
508                                     "Symbolic mode \"%s\" unsupported", val);
509                         break;
510                 }
511         case 's':
512                 if (strcmp(key, "size") == 0) {
513                         archive_entry_set_size(entry, mtree_atol10(&val));
514                         break;
515                 }
516         case 't':
517                 if (strcmp(key, "type") == 0) {
518                         switch (val[0]) {
519                         case 'b':
520                                 if (strcmp(val, "block") == 0) {
521                                         mtree->filetype = AE_IFBLK;
522                                         break;
523                                 }
524                         case 'c':
525                                 if (strcmp(val, "char") == 0) {
526                                         mtree->filetype = AE_IFCHR;
527                                         break;
528                                 }
529                         case 'd':
530                                 if (strcmp(val, "dir") == 0) {
531                                         mtree->filetype = AE_IFDIR;
532                                         break;
533                                 }
534                         case 'f':
535                                 if (strcmp(val, "fifo") == 0) {
536                                         mtree->filetype = AE_IFIFO;
537                                         break;
538                                 }
539                                 if (strcmp(val, "file") == 0) {
540                                         mtree->filetype = AE_IFREG;
541                                         break;
542                                 }
543                         case 'l':
544                                 if (strcmp(val, "link") == 0) {
545                                         mtree->filetype = AE_IFLNK;
546                                         break;
547                                 }
548                         default:
549                                 archive_set_error(&a->archive,
550                                     ARCHIVE_ERRNO_FILE_FORMAT,
551                                     "Unrecognized file type \"%s\"", val);
552                                 return (ARCHIVE_WARN);
553                         }
554                         archive_entry_set_filetype(entry, mtree->filetype);
555                         break;
556                 }
557                 if (strcmp(key, "time") == 0) {
558                         archive_entry_set_mtime(entry, mtree_atol10(&val), 0);
559                         break;
560                 }
561         case 'u':
562                 if (strcmp(key, "uid") == 0) {
563                         archive_entry_set_uid(entry, mtree_atol10(&val));
564                         break;
565                 }
566                 if (strcmp(key, "uname") == 0) {
567                         archive_entry_copy_uname(entry, val);
568                         break;
569                 }
570         default:
571                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
572                     "Unrecognized key %s=%s", key, val);
573                 return (ARCHIVE_WARN);
574         }
575         return (ARCHIVE_OK);
576 }
577
578 static int
579 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
580 {
581         size_t bytes_to_read;
582         ssize_t bytes_read;
583         struct mtree *mtree;
584
585         mtree = (struct mtree *)(a->format->data);
586         if (mtree->fd < 0) {
587                 *buff = NULL;
588                 *offset = 0;
589                 *size = 0;
590                 return (ARCHIVE_EOF);
591         }
592         if (mtree->buff == NULL) {
593                 mtree->buffsize = 64 * 1024;
594                 mtree->buff = malloc(mtree->buffsize);
595                 if (mtree->buff == NULL) {
596                         archive_set_error(&a->archive, ENOMEM,
597                             "Can't allocate memory");
598                 }
599         }
600
601         *buff = mtree->buff;
602         *offset = mtree->offset;
603         if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset)
604                 bytes_to_read = mtree->cur_size - mtree->offset;
605         else
606                 bytes_to_read = mtree->buffsize;
607         bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
608         if (bytes_read < 0) {
609                 archive_set_error(&a->archive, errno, "Can't read");
610                 return (ARCHIVE_WARN);
611         }
612         if (bytes_read == 0) {
613                 *size = 0;
614                 return (ARCHIVE_EOF);
615         }
616         mtree->offset += bytes_read;
617         *size = bytes_read;
618         return (ARCHIVE_OK);
619 }
620
621 /* Skip does nothing except possibly close the contents file. */
622 static int
623 skip(struct archive_read *a)
624 {
625         struct mtree *mtree;
626
627         mtree = (struct mtree *)(a->format->data);
628         if (mtree->fd >= 0) {
629                 close(mtree->fd);
630                 mtree->fd = -1;
631         }
632         return (ARCHIVE_OK);
633 }
634
635 /*
636  * Since parsing octal escapes always makes strings shorter,
637  * we can always do this conversion in-place.
638  */
639 static void
640 parse_escapes(char *src, struct mtree_entry *mentry)
641 {
642         char *dest = src;
643         char c;
644
645         while (*src != '\0') {
646                 c = *src++;
647                 if (c == '/' && mentry != NULL)
648                         mentry->full = 1;
649                 if (c == '\\') {
650                         if (src[0] >= '0' && src[0] <= '3'
651                             && src[1] >= '0' && src[1] <= '7'
652                             && src[2] >= '0' && src[2] <= '7') {
653                                 c = (src[0] - '0') << 6;
654                                 c |= (src[1] - '0') << 3;
655                                 c |= (src[2] - '0');
656                                 src += 3;
657                         }
658                 }
659                 *dest++ = c;
660         }
661         *dest = '\0';
662 }
663
664 /*
665  * Note that this implementation does not (and should not!) obey
666  * locale settings; you cannot simply substitute strtol here, since
667  * it does obey locale.
668  */
669 static int64_t
670 mtree_atol8(char **p)
671 {
672         int64_t l, limit, last_digit_limit;
673         int digit, base;
674
675         base = 8;
676         limit = INT64_MAX / base;
677         last_digit_limit = INT64_MAX % base;
678
679         l = 0;
680         digit = **p - '0';
681         while (digit >= 0 && digit < base) {
682                 if (l>limit || (l == limit && digit > last_digit_limit)) {
683                         l = INT64_MAX; /* Truncate on overflow. */
684                         break;
685                 }
686                 l = (l * base) + digit;
687                 digit = *++(*p) - '0';
688         }
689         return (l);
690 }
691
692 /*
693  * Note that this implementation does not (and should not!) obey
694  * locale settings; you cannot simply substitute strtol here, since
695  * it does obey locale.
696  */
697 static int64_t
698 mtree_atol10(char **p)
699 {
700         int64_t l, limit, last_digit_limit;
701         int base, digit, sign;
702
703         base = 10;
704         limit = INT64_MAX / base;
705         last_digit_limit = INT64_MAX % base;
706
707         if (**p == '-') {
708                 sign = -1;
709                 ++(*p);
710         } else
711                 sign = 1;
712
713         l = 0;
714         digit = **p - '0';
715         while (digit >= 0 && digit < base) {
716                 if (l > limit || (l == limit && digit > last_digit_limit)) {
717                         l = UINT64_MAX; /* Truncate on overflow. */
718                         break;
719                 }
720                 l = (l * base) + digit;
721                 digit = *++(*p) - '0';
722         }
723         return (sign < 0) ? -l : l;
724 }
725
726 /*
727  * Returns length of line (including trailing newline)
728  * or negative on error.  'start' argument is updated to
729  * point to first character of line.
730  */
731 static ssize_t
732 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
733 {
734         ssize_t bytes_read;
735         ssize_t total_size = 0;
736         const void *t;
737         const char *s;
738         void *p;
739
740         /* Accumulate line in a line buffer. */
741         for (;;) {
742                 /* Read some more. */
743                 bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
744                 if (bytes_read == 0)
745                         return (0);
746                 if (bytes_read < 0)
747                         return (ARCHIVE_FATAL);
748                 s = t;  /* Start of line? */
749                 p = memchr(t, '\n', bytes_read);
750                 /* If we found '\n', trim the read. */
751                 if (p != NULL) {
752                         bytes_read = 1 + ((const char *)p) - s;
753                 }
754                 if (total_size + bytes_read + 1 > limit) {
755                         archive_set_error(&a->archive,
756                             ARCHIVE_ERRNO_FILE_FORMAT,
757                             "Line too long");
758                         return (ARCHIVE_FATAL);
759                 }
760                 if (archive_string_ensure(&mtree->line,
761                         total_size + bytes_read + 1) == NULL) {
762                         archive_set_error(&a->archive, ENOMEM,
763                             "Can't allocate working buffer");
764                         return (ARCHIVE_FATAL);
765                 }
766                 memcpy(mtree->line.s + total_size, t, bytes_read);
767                 (a->decompressor->consume)(a, bytes_read);
768                 total_size += bytes_read;
769                 /* Null terminate. */
770                 mtree->line.s[total_size] = '\0';
771                 /* If we found '\n', clean up and return. */
772                 if (p != NULL) {
773                         *start = mtree->line.s;
774                         return (total_size);
775                 }
776         }
777 }