Import libarchive 2.0.28.
[dragonfly.git] / contrib / libarchive-2.0 / libarchive / archive_read_support_format_ar.c
1 /*-
2  * Copyright (c) 2007 Kai Wang
3  * Copyright (c) 2007 Tim Kientzle
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer
11  *    in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "archive_platform.h"
29 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.1 2007/04/03 05:34:36 kientzle Exp $");
30
31 #ifdef HAVE_ERRNO_H
32 #include <errno.h>
33 #endif
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40
41 #include "archive.h"
42 #include "archive_entry.h"
43 #include "archive_private.h"
44 #include "archive_read_private.h"
45
46 struct ar {
47         int      bid;
48         int      has_strtab;
49         off_t    entry_bytes_remaining;
50         off_t    entry_offset;
51         off_t    entry_padding;
52         char    *strtab;
53 };
54
55 /*
56  * Define structure of the "ar" header.
57  */
58 #define AR_name_offset 0
59 #define AR_name_size 16
60 #define AR_date_offset 16
61 #define AR_date_size 12
62 #define AR_uid_offset 28
63 #define AR_uid_size 6
64 #define AR_gid_offset 34
65 #define AR_gid_size 6
66 #define AR_mode_offset 40
67 #define AR_mode_size 8
68 #define AR_size_offset 48
69 #define AR_size_size 10
70 #define AR_fmag_offset 58
71 #define AR_fmag_size 2
72
73 /*
74  * "ar" magic numbers.
75  */
76 #define ARMAG           "!<arch>\n"
77 #define SARMAG          8               /* strlen(ARMAG); */
78 #define AR_EFMT1        "#1/"
79 #define SAR_EFMT1       3               /* strlen(AR_EFMT1); */
80 #define ARFMAG          "`\n"
81 #define SARFMAG         2               /* strlen(ARFMAG); */
82
83 #define isdigit(x)      (x) >= '0' && (x) <= '9'
84
85 static int      archive_read_format_ar_bid(struct archive_read *a);
86 static int      archive_read_format_ar_cleanup(struct archive_read *a);
87 static int      archive_read_format_ar_read_data(struct archive_read *a,
88                     const void **buff, size_t *size, off_t *offset);
89 static int      archive_read_format_ar_skip(struct archive_read *a);
90 static int      archive_read_format_ar_read_header(struct archive_read *a,
91                     struct archive_entry *e);
92 static int64_t  ar_atol8(const char *p, unsigned char_cnt);
93 static int64_t  ar_atol10(const char *p, unsigned char_cnt);
94 static int      ar_parse_string_table(struct archive_read *, struct ar *,
95                     const void *, ssize_t);
96
97 /*
98  * ANSI C99 defines constants for these, but not everyone supports
99  * those constants, so I define a couple of static variables here and
100  * compute the values.  These calculations should be portable to any
101  * 2s-complement architecture.
102  */
103 #ifdef UINT64_MAX
104 static const uint64_t max_uint64 = UINT64_MAX;
105 #else
106 static const uint64_t max_uint64 = ~(uint64_t)0;
107 #endif
108 #ifdef INT64_MAX
109 static const int64_t max_int64 = INT64_MAX;
110 #else
111 static const int64_t max_int64 = (int64_t)((~(uint64_t)0) >> 1);
112 #endif
113 #ifdef INT64_MIN
114 static const int64_t min_int64 = INT64_MIN;
115 #else
116 static const int64_t min_int64 = (int64_t)(~((~(uint64_t)0) >> 1));
117 #endif
118
119 int
120 archive_read_support_format_ar(struct archive *_a)
121 {
122         struct archive_read *a = (struct archive_read *)_a;
123         struct ar *ar;
124         int r;
125
126         ar = (struct ar *)malloc(sizeof(*ar));
127         if (ar == NULL) {
128                 archive_set_error(&a->archive, ENOMEM,
129                     "Can't allocate ar data");
130                 return (ARCHIVE_FATAL);
131         }
132         memset(ar, 0, sizeof(*ar));
133         ar->bid = -1;
134
135         r = __archive_read_register_format(a,
136             ar,
137             archive_read_format_ar_bid,
138             archive_read_format_ar_read_header,
139             archive_read_format_ar_read_data,
140             archive_read_format_ar_skip,
141             archive_read_format_ar_cleanup);
142
143         if (r != ARCHIVE_OK) {
144                 free(ar);
145                 return (r);
146         }
147         return (ARCHIVE_OK);
148 }
149
150 static int
151 archive_read_format_ar_cleanup(struct archive_read *a)
152 {
153         struct ar *ar;
154
155         ar = (struct ar *)*(a->pformat_data);
156         if (ar->has_strtab > 0)
157                 free(ar->strtab);
158         free(ar);
159         *(a->pformat_data) = NULL;
160         return (ARCHIVE_OK);
161 }
162
163 static int
164 archive_read_format_ar_bid(struct archive_read *a)
165 {
166         struct ar *ar;
167         ssize_t bytes_read;
168         const void *h;
169
170         if (a->archive.archive_format != 0 &&
171             (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
172             ARCHIVE_FORMAT_AR)
173                 return(0);
174
175         ar = (struct ar *)*(a->pformat_data);
176
177         if (ar->bid > 0)
178                 return (ar->bid);
179
180         bytes_read = (a->compression_read_ahead)(a, &h, SARMAG);
181         if (bytes_read < SARMAG)
182                 return (-1);
183
184         /*
185          * Verify the global header.
186          * TODO: Do we need to check more than this?
187          */
188         if (strncmp((const char*)h, ARMAG, SARMAG) == 0) {
189                 ar->bid = SARMAG;
190                 return (ar->bid);
191         }
192         return (-1);
193 }
194
195 static int
196 archive_read_format_ar_read_header(struct archive_read *a,
197     struct archive_entry *entry)
198 {
199         int r, bsd_append;
200         ssize_t bytes;
201         int64_t nval;
202         char *fname, *p;
203         struct ar *ar;
204         const void *b;
205         const char *h;
206
207         bsd_append = 0;
208
209         if (!a->archive.archive_format) {
210                 a->archive.archive_format = ARCHIVE_FORMAT_AR;
211                 a->archive.archive_format_name = "Unix Archiver";
212         }
213
214         if (a->archive.file_position == 0) {
215                 /*
216                  * We are now at the beginning of the archive,
217                  * so we need first consume the ar global header.
218                  */
219                 (a->compression_read_consume)(a, SARMAG);
220         }
221
222         /* Read 60-byte header */
223         bytes = (a->compression_read_ahead)(a, &b, 60);
224         if (bytes < 60) {
225                 /*
226                  * We just encountered an incomplete ar file,
227                  * though the _bid function accepted it.
228                  */
229                 return (ARCHIVE_EOF);
230         }
231         (a->compression_read_consume)(a, 60);
232
233         h = (const char *)b;
234
235         /* Consistency check */
236         if (strncmp(h + AR_fmag_offset, ARFMAG, SARFMAG) != 0) {
237                 archive_set_error(&a->archive, EINVAL,
238                     "Consistency check failed");
239                 return (ARCHIVE_WARN);
240         }
241
242         ar = (struct ar*)*(a->pformat_data);
243
244         if (strncmp(h + AR_name_offset, "//", 2) == 0) {
245                 /*
246                  * An archive member with ar_name "//" is an archive
247                  * string table.
248                  */
249                 nval = ar_atol10(h + AR_size_offset, AR_size_size);
250                 bytes = (a->compression_read_ahead)(a, &b, nval);
251                 if (bytes <= 0)
252                         return (ARCHIVE_FATAL);
253                 if (bytes < nval) {
254                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
255                             "Truncated input file");
256                         return (ARCHIVE_FATAL);
257                 }
258
259                 r = ar_parse_string_table(a, ar, b, nval);
260                 if (r == ARCHIVE_OK) {
261                         /*
262                          * Archive string table only have ar_name and ar_size fileds
263                          * in its header.
264                          */
265                         archive_entry_copy_pathname(entry, "//");
266                         nval = ar_atol10(h + AR_size_offset, AR_size_size);
267                         archive_entry_set_size(entry, nval);
268
269                         ar->entry_offset = 0;
270                         ar->entry_bytes_remaining = nval;
271                         ar->entry_padding = ar->entry_bytes_remaining % 2;
272                 }
273                 return (r);
274         }
275
276         if (h[AR_name_offset] == '/' && isdigit(h[AR_name_offset + 1])) {
277                 /*
278                  * Archive member is common format with SVR4/GNU variant.
279                  * "/" followed by one or more digit(s) in the ar_name
280                  * filed indicates an index to the string table.
281                  */
282                 if (ar->has_strtab > 0) {
283                         nval = ar_atol10(h + AR_name_offset + 1,
284                             AR_name_size - 1);
285                         archive_entry_copy_pathname(entry, &ar->strtab[nval]);
286                 } else {
287                         archive_set_error(&a->archive, EINVAL,
288                             "String table does not exist");
289                         return (ARCHIVE_WARN);
290                 }
291                 goto remain;
292         }
293
294         if (strncmp(h + AR_name_offset, AR_EFMT1, SAR_EFMT1) == 0) {
295                 /*
296                  * Archive member is common format with BSD variant.
297                  * AR_EFMT1 is followed by one or more digit(s) indicating
298                  * the length of the real filename which is appended
299                  * to the header.
300                  */
301                 nval = ar_atol10(h + AR_name_offset + SAR_EFMT1,
302                     AR_name_size - SAR_EFMT1);
303                 bytes = (a->compression_read_ahead)(a, &b, nval);
304                 if (bytes <= 0)
305                         return (ARCHIVE_FATAL);
306                 if (bytes < nval) {
307                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
308                             "Truncated input file");
309                         return (ARCHIVE_FATAL);
310                 }
311
312                 (a->compression_read_consume)(a, nval);
313
314                 fname = (char *)malloc(nval + 1);
315                 if (fname == NULL) {
316                         archive_set_error(&a->archive, ENOMEM,
317                             "Can't allocate fname buffer");
318                         return (ARCHIVE_FATAL);
319                 }
320                 strncpy(fname, b, nval);
321                 fname[nval] = '\0';
322                 archive_entry_copy_pathname(entry, fname);
323                 free(fname);
324                 fname = NULL;
325
326                 bsd_append = nval;
327                 goto remain;
328         }
329
330         /*
331          * "/" followed by one or more spaces indicate a
332          * SVR4/GNU archive symbol table.
333          *
334          */
335         if (strncmp(h + AR_name_offset, "/ ", 2) == 0) {
336                 archive_entry_copy_pathname(entry, "/");
337                 goto remain;
338         }
339         /*
340          * "__.SYMDEF" indicates a BSD archive symbol table.
341          */
342         if (strncmp(h + AR_name_offset, "__.SYMDEF", 9) == 0) {
343                 archive_entry_copy_pathname(entry, "__.SYMDEF");
344                 goto remain;
345         }
346
347         /*
348          * Otherwise, the ar_name fields stores the real
349          * filename.
350          * SVR4/GNU variant append a '/' to mark the end of
351          * filename, while BSD variant use a space.
352          */
353         fname = (char *)malloc(AR_name_size + 1);
354         strncpy(fname, h + AR_name_offset, AR_name_size);
355         fname[AR_name_size] = '\0';
356
357         if ((p = strchr(fname, '/')) != NULL) {
358                 /* SVR4/GNU format */
359                 *p = '\0';
360                 archive_entry_copy_pathname(entry, fname);
361                 free(fname);
362                 fname = NULL;
363                 goto remain;
364         }
365
366         /* BSD format */
367         if ((p = strchr(fname, ' ')) != NULL)
368                 *p = '\0';
369         archive_entry_copy_pathname(entry, fname);
370         free(fname);
371         fname = NULL;
372
373 remain:
374         /* Copy remaining header */
375         archive_entry_set_mtime(entry,
376             ar_atol10(h + AR_date_offset, AR_date_size), 0);
377         archive_entry_set_uid(entry,
378             ar_atol10(h + AR_uid_offset, AR_uid_size));
379         archive_entry_set_gid(entry,
380             ar_atol10(h + AR_gid_offset, AR_gid_size));
381         archive_entry_set_mode(entry,
382             ar_atol8(h + AR_mode_offset, AR_mode_size));
383         nval = ar_atol10(h + AR_size_offset, AR_size_size);
384
385         ar->entry_offset = 0;
386         ar->entry_padding = nval % 2;
387
388         /*
389          * For BSD variant, we should subtract the length of
390          * the appended filename string from ar_size to get the
391          * real file size. But remember we should do this only
392          * after we had calculated the padding.
393          */
394         if (bsd_append > 0)
395                 nval -= bsd_append;
396
397         archive_entry_set_size(entry, nval);
398         ar->entry_bytes_remaining = nval;
399
400         return (ARCHIVE_OK);
401 }
402
403 static int
404 archive_read_format_ar_read_data(struct archive_read *a,
405     const void **buff, size_t *size, off_t *offset)
406 {
407         ssize_t bytes_read;
408         struct ar *ar;
409
410         ar = (struct ar *)*(a->pformat_data);
411
412         if (ar->entry_bytes_remaining > 0) {
413                 bytes_read = (a->compression_read_ahead)(a, buff, 1);
414                 if (bytes_read == 0) {
415                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
416                             "Truncated ar archive");
417                         return (ARCHIVE_FATAL);
418                 }
419                 if (bytes_read < 0)
420                         return (ARCHIVE_FATAL);
421                 if (bytes_read > ar->entry_bytes_remaining)
422                         bytes_read = ar->entry_bytes_remaining;
423                 *size = bytes_read;
424                 *offset = ar->entry_offset;
425                 ar->entry_offset += bytes_read;
426                 ar->entry_bytes_remaining -= bytes_read;
427                 (a->compression_read_consume)(a, bytes_read);
428                 return (ARCHIVE_OK);
429         } else {
430                 while (ar->entry_padding > 0) {
431                         bytes_read = (a->compression_read_ahead)(a, buff, 1);
432                         if (bytes_read <= 0)
433                                 return (ARCHIVE_FATAL);
434                         if (bytes_read > ar->entry_padding)
435                                 bytes_read = ar->entry_padding;
436                         (a->compression_read_consume)(a, bytes_read);
437                         ar->entry_padding -= bytes_read;
438                 }
439                 *buff = NULL;
440                 *size = 0;
441                 *offset = ar->entry_offset;
442                 return (ARCHIVE_EOF);
443         }
444 }
445
446 static int
447 archive_read_format_ar_skip(struct archive_read *a)
448 {
449         off_t bytes_skipped;
450         struct ar* ar;
451         int r = ARCHIVE_OK;
452         const void *b;          /* Dummy variables */
453         size_t s;
454         off_t o;
455
456         ar = (struct ar *)*(a->pformat_data);
457         if (a->compression_skip == NULL) {
458                 while (r == ARCHIVE_OK)
459                         r = archive_read_format_ar_read_data(a, &b, &s, &o);
460                 return (r);
461         }
462
463         bytes_skipped = (a->compression_skip)(a, ar->entry_bytes_remaining +
464             ar->entry_padding);
465         if (bytes_skipped < 0)
466                 return (ARCHIVE_FATAL);
467
468         ar->entry_bytes_remaining = 0;
469         ar->entry_padding = 0;
470
471         return (ARCHIVE_OK);
472 }
473
474 static int
475 ar_parse_string_table(struct archive_read *a, struct ar *ar,
476     const void *h, ssize_t size)
477 {
478         char *p;
479
480         if (ar->has_strtab > 0) {
481                 archive_set_error(&a->archive, EINVAL,
482                     "More than one string tables exist");
483                 return (ARCHIVE_WARN);
484         }
485
486         ar->strtab = (char *)malloc(size);
487         if (ar->strtab == NULL) {
488                 archive_set_error(&a->archive, ENOMEM,
489                     "Can't allocate string table buffer");
490                 return (ARCHIVE_FATAL);
491         }
492
493         (void)memcpy(ar->strtab, h, size);
494         p = ar->strtab;
495         while (p < ar->strtab + size - 1) {
496                 if (*p == '/') {
497                         *p++ = '\0';
498                         if (*p == '\n')
499                                 *p++ = '\0';
500                         else {
501                                 archive_set_error(&a->archive, EINVAL,
502                                     "Invalid string table");
503                                 free(ar->strtab);
504                                 return (ARCHIVE_WARN);
505                         }
506                 } else
507                         p++;
508         }
509         /*
510          * Sanity check, last two chars must be `/\n' or '\n\n',
511          * depending on whether the string table is padded by a '\n'
512          * (string table produced by GNU ar always has a even size).
513          */
514         if (p != ar->strtab + size && *p != '\n') {
515                 archive_set_error(&a->archive, EINVAL,
516                     "Invalid string table");
517                 free(ar->strtab);
518                 return (ARCHIVE_WARN);
519         }
520
521         ar->has_strtab = 1;
522         return (ARCHIVE_OK);
523 }
524
525 static int64_t
526 ar_atol8(const char *p, unsigned char_cnt)
527 {
528         int64_t l, limit, last_digit_limit;
529         int digit, sign, base;
530
531         base = 8;
532         limit = max_int64 / base;
533         last_digit_limit = max_int64 % base;
534
535         while (*p == ' ' || *p == '\t')
536                 p++;
537         if (*p == '-') {
538                 sign = -1;
539                 p++;
540         } else
541                 sign = 1;
542
543         l = 0;
544         digit = *p - '0';
545         while (digit >= 0 && digit < base  && char_cnt-- > 0) {
546                 if (l>limit || (l == limit && digit > last_digit_limit)) {
547                         l = max_uint64; /* Truncate on overflow. */
548                         break;
549                 }
550                 l = (l * base) + digit;
551                 digit = *++p - '0';
552         }
553         return (sign < 0) ? -l : l;
554 }
555
556 static int64_t
557 ar_atol10(const char *p, unsigned char_cnt)
558 {
559         int64_t l, limit, last_digit_limit;
560         int base, digit, sign;
561
562         base = 10;
563         limit = max_int64 / base;
564         last_digit_limit = max_int64 % base;
565
566         while (*p == ' ' || *p == '\t')
567                 p++;
568         if (*p == '-') {
569                 sign = -1;
570                 p++;
571         } else
572                 sign = 1;
573
574         l = 0;
575         digit = *p - '0';
576         while (digit >= 0 && digit < base  && char_cnt-- > 0) {
577                 if (l > limit || (l == limit && digit > last_digit_limit)) {
578                         l = max_uint64; /* Truncate on overflow. */
579                         break;
580                 }
581                 l = (l * base) + digit;
582                 digit = *++p - '0';
583         }
584         return (sign < 0) ? -l : l;
585 }