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 
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39 
40 #include "archive.h"
41 #include "archive_entry.h"
42 #include "archive_private.h"
43 #include "archive_write_private.h"
44 #include "archive_write_set_format_private.h"
45 
46 struct ar_w {
47           uint64_t   entry_bytes_remaining;
48           uint64_t   entry_padding;
49           int                  is_strtab;
50           int                  has_strtab;
51           char                 wrote_global_header;
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 static int                     archive_write_set_format_ar(struct archive_write *);
74 static int                     archive_write_ar_header(struct archive_write *,
75                                    struct archive_entry *);
76 static ssize_t                 archive_write_ar_data(struct archive_write *,
77                                    const void *buff, size_t s);
78 static int                     archive_write_ar_free(struct archive_write *);
79 static int                     archive_write_ar_close(struct archive_write *);
80 static int                     archive_write_ar_finish_entry(struct archive_write *);
81 static const char   *ar_basename(const char *path);
82 static int                     format_octal(int64_t v, char *p, int s);
83 static int                     format_decimal(int64_t v, char *p, int s);
84 
85 int
archive_write_set_format_ar_bsd(struct archive * _a)86 archive_write_set_format_ar_bsd(struct archive *_a)
87 {
88           struct archive_write *a = (struct archive_write *)_a;
89           int r;
90 
91           archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
92               ARCHIVE_STATE_NEW, "archive_write_set_format_ar_bsd");
93           r = archive_write_set_format_ar(a);
94           if (r == ARCHIVE_OK) {
95                     a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
96                     a->archive.archive_format_name = "ar (BSD)";
97           }
98           return (r);
99 }
100 
101 int
archive_write_set_format_ar_svr4(struct archive * _a)102 archive_write_set_format_ar_svr4(struct archive *_a)
103 {
104           struct archive_write *a = (struct archive_write *)_a;
105           int r;
106 
107           archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
108               ARCHIVE_STATE_NEW, "archive_write_set_format_ar_svr4");
109           r = archive_write_set_format_ar(a);
110           if (r == ARCHIVE_OK) {
111                     a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;
112                     a->archive.archive_format_name = "ar (GNU/SVR4)";
113           }
114           return (r);
115 }
116 
117 /*
118  * Generic initialization.
119  */
120 static int
archive_write_set_format_ar(struct archive_write * a)121 archive_write_set_format_ar(struct archive_write *a)
122 {
123           struct ar_w *ar;
124 
125           /* If someone else was already registered, unregister them. */
126           if (a->format_free != NULL)
127                     (a->format_free)(a);
128 
129           ar = calloc(1, sizeof(*ar));
130           if (ar == NULL) {
131                     archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");
132                     return (ARCHIVE_FATAL);
133           }
134           a->format_data = ar;
135 
136           a->format_name = "ar";
137           a->format_write_header = archive_write_ar_header;
138           a->format_write_data = archive_write_ar_data;
139           a->format_close = archive_write_ar_close;
140           a->format_free = archive_write_ar_free;
141           a->format_finish_entry = archive_write_ar_finish_entry;
142           return (ARCHIVE_OK);
143 }
144 
145 static int
archive_write_ar_header(struct archive_write * a,struct archive_entry * entry)146 archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
147 {
148           int ret, append_fn;
149           char buff[60];
150           char *ss, *se;
151           struct ar_w *ar;
152           const char *pathname;
153           const char *filename;
154           int64_t size;
155 
156           append_fn = 0;
157           ar = (struct ar_w *)a->format_data;
158           ar->is_strtab = 0;
159           filename = NULL;
160           size = archive_entry_size(entry);
161 
162 
163           /*
164            * Reject files with empty name.
165            */
166           pathname = archive_entry_pathname(entry);
167           if (pathname == NULL || *pathname == '\0') {
168                     archive_set_error(&a->archive, EINVAL,
169                         "Invalid filename");
170                     return (ARCHIVE_WARN);
171           }
172 
173           /*
174            * If we are now at the beginning of the archive,
175            * we need first write the ar global header.
176            */
177           if (!ar->wrote_global_header) {
178                     __archive_write_output(a, "!<arch>\n", 8);
179                     ar->wrote_global_header = 1;
180           }
181 
182           memset(buff, ' ', 60);
183           memcpy(&buff[AR_fmag_offset], "`\n", 2);
184 
185           if (strcmp(pathname, "/") == 0 ) {
186                     /* Entry is archive symbol table in GNU format */
187                     buff[AR_name_offset] = '/';
188                     goto stat;
189           }
190           if (strcmp(pathname, "/SYM64/") == 0) {
191                     /* Entry is archive symbol table in GNU 64-bit format */
192                     memcpy(buff + AR_name_offset, "/SYM64/", 7);
193                     goto stat;
194           }
195           if (strcmp(pathname, "__.SYMDEF") == 0) {
196                     /* Entry is archive symbol table in BSD format */
197                     memcpy(buff + AR_name_offset, "__.SYMDEF", 9);
198                     goto stat;
199           }
200           if (strcmp(pathname, "//") == 0) {
201                     /*
202                      * Entry is archive filename table, inform that we should
203                      * collect strtab in next _data call.
204                      */
205                     ar->is_strtab = 1;
206                     buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';
207                     /*
208                      * For archive string table, only ar_size field should
209                      * be set.
210                      */
211                     goto size;
212           }
213 
214           /*
215            * Otherwise, entry is a normal archive member.
216            * Strip leading paths from filenames, if any.
217            */
218           if ((filename = ar_basename(pathname)) == NULL) {
219                     /* Reject filenames with trailing "/" */
220                     archive_set_error(&a->archive, EINVAL,
221                         "Invalid filename");
222                     return (ARCHIVE_WARN);
223           }
224 
225           if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) {
226                     /*
227                      * SVR4/GNU variant use a "/" to mark then end of the filename,
228                      * make it possible to have embedded spaces in the filename.
229                      * So, the longest filename here (without extension) is
230                      * actually 15 bytes.
231                      */
232                     if (strlen(filename) <= 15) {
233                               memcpy(&buff[AR_name_offset],
234                                   filename, strlen(filename));
235                               buff[AR_name_offset + strlen(filename)] = '/';
236                     } else {
237                               /*
238                                * For filename longer than 15 bytes, GNU variant
239                                * makes use of a string table and instead stores the
240                                * offset of the real filename to in the ar_name field.
241                                * The string table should have been written before.
242                                */
243                               if (ar->has_strtab <= 0) {
244                                         archive_set_error(&a->archive, EINVAL,
245                                             "Can't find string table");
246                                         return (ARCHIVE_WARN);
247                               }
248 
249                               se = malloc(strlen(filename) + 3);
250                               if (se == NULL) {
251                                         archive_set_error(&a->archive, ENOMEM,
252                                             "Can't allocate filename buffer");
253                                         return (ARCHIVE_FATAL);
254                               }
255 
256                               memcpy(se, filename, strlen(filename));
257                               strcpy(se + strlen(filename), "/\n");
258 
259                               ss = strstr(ar->strtab, se);
260                               free(se);
261 
262                               if (ss == NULL) {
263                                         archive_set_error(&a->archive, EINVAL,
264                                             "Invalid string table");
265                                         return (ARCHIVE_WARN);
266                               }
267 
268                               /*
269                                * GNU variant puts "/" followed by digits into
270                                * ar_name field. These digits indicates the real
271                                * filename string's offset to the string table.
272                                */
273                               buff[AR_name_offset] = '/';
274                               if (format_decimal(ss - ar->strtab,
275                                   buff + AR_name_offset + 1,
276                                   AR_name_size - 1)) {
277                                         archive_set_error(&a->archive, ERANGE,
278                                             "string table offset too large");
279                                         return (ARCHIVE_WARN);
280                               }
281                     }
282           } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) {
283                     /*
284                      * BSD variant: for any file name which is more than
285                      * 16 chars or contains one or more embedded space(s), the
286                      * string "#1/" followed by the ASCII length of the name is
287                      * put into the ar_name field. The file size (stored in the
288                      * ar_size field) is incremented by the length of the name.
289                      * The name is then written immediately following the
290                      * archive header.
291                      */
292                     if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
293                               memcpy(&buff[AR_name_offset], filename, strlen(filename));
294                               buff[AR_name_offset + strlen(filename)] = ' ';
295                     }
296                     else {
297                               memcpy(buff + AR_name_offset, "#1/", 3);
298                               if (format_decimal(strlen(filename),
299                                   buff + AR_name_offset + 3,
300                                   AR_name_size - 3)) {
301                                         archive_set_error(&a->archive, ERANGE,
302                                             "File name too long");
303                                         return (ARCHIVE_WARN);
304                               }
305                               append_fn = 1;
306                               size += strlen(filename);
307                     }
308           }
309 
310 stat:
311           if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) {
312                     archive_set_error(&a->archive, ERANGE,
313                         "File modification time too large");
314                     return (ARCHIVE_WARN);
315           }
316           if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) {
317                     archive_set_error(&a->archive, ERANGE,
318                         "Numeric user ID too large");
319                     return (ARCHIVE_WARN);
320           }
321           if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) {
322                     archive_set_error(&a->archive, ERANGE,
323                         "Numeric group ID too large");
324                     return (ARCHIVE_WARN);
325           }
326           if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) {
327                     archive_set_error(&a->archive, ERANGE,
328                         "Numeric mode too large");
329                     return (ARCHIVE_WARN);
330           }
331           /*
332            * Sanity Check: A non-pseudo archive member should always be
333            * a regular file.
334            */
335           if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) {
336                     archive_set_error(&a->archive, EINVAL,
337                         "Regular file required for non-pseudo member");
338                     return (ARCHIVE_WARN);
339           }
340 
341 size:
342           if (format_decimal(size, buff + AR_size_offset, AR_size_size)) {
343                     archive_set_error(&a->archive, ERANGE,
344                         "File size out of range");
345                     return (ARCHIVE_WARN);
346           }
347 
348           ret = __archive_write_output(a, buff, 60);
349           if (ret != ARCHIVE_OK)
350                     return (ret);
351 
352           ar->entry_bytes_remaining = size;
353           ar->entry_padding = ar->entry_bytes_remaining % 2;
354 
355           if (append_fn > 0) {
356                     ret = __archive_write_output(a, filename, strlen(filename));
357                     if (ret != ARCHIVE_OK)
358                               return (ret);
359                     ar->entry_bytes_remaining -= strlen(filename);
360           }
361 
362           return (ARCHIVE_OK);
363 }
364 
365 static ssize_t
archive_write_ar_data(struct archive_write * a,const void * buff,size_t s)366 archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
367 {
368           struct ar_w *ar;
369           int ret;
370 
371           ar = (struct ar_w *)a->format_data;
372           if (s > ar->entry_bytes_remaining)
373                     s = (size_t)ar->entry_bytes_remaining;
374 
375           if (ar->is_strtab > 0) {
376                     if (ar->has_strtab > 0) {
377                               archive_set_error(&a->archive, EINVAL,
378                                   "More than one string tables exist");
379                               return (ARCHIVE_WARN);
380                     }
381 
382                     ar->strtab = malloc(s + 1);
383                     if (ar->strtab == NULL) {
384                               archive_set_error(&a->archive, ENOMEM,
385                                   "Can't allocate strtab buffer");
386                               return (ARCHIVE_FATAL);
387                     }
388                     memcpy(ar->strtab, buff, s);
389                     ar->strtab[s] = '\0';
390                     ar->has_strtab = 1;
391           }
392 
393           ret = __archive_write_output(a, buff, s);
394           if (ret != ARCHIVE_OK)
395                     return (ret);
396 
397           ar->entry_bytes_remaining -= s;
398           return (s);
399 }
400 
401 static int
archive_write_ar_free(struct archive_write * a)402 archive_write_ar_free(struct archive_write *a)
403 {
404           struct ar_w *ar;
405 
406           ar = (struct ar_w *)a->format_data;
407 
408           if (ar == NULL)
409                     return (ARCHIVE_OK);
410 
411           if (ar->has_strtab > 0) {
412                     free(ar->strtab);
413                     ar->strtab = NULL;
414           }
415 
416           free(ar);
417           a->format_data = NULL;
418           return (ARCHIVE_OK);
419 }
420 
421 static int
archive_write_ar_close(struct archive_write * a)422 archive_write_ar_close(struct archive_write *a)
423 {
424           struct ar_w *ar;
425           int ret;
426 
427           /*
428            * If we haven't written anything yet, we need to write
429            * the ar global header now to make it a valid ar archive.
430            */
431           ar = (struct ar_w *)a->format_data;
432           if (!ar->wrote_global_header) {
433                     ar->wrote_global_header = 1;
434                     ret = __archive_write_output(a, "!<arch>\n", 8);
435                     return (ret);
436           }
437 
438           return (ARCHIVE_OK);
439 }
440 
441 static int
archive_write_ar_finish_entry(struct archive_write * a)442 archive_write_ar_finish_entry(struct archive_write *a)
443 {
444           struct ar_w *ar;
445           int ret;
446 
447           ar = (struct ar_w *)a->format_data;
448 
449           if (ar->entry_bytes_remaining != 0) {
450                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
451                         "Entry remaining bytes larger than 0");
452                     return (ARCHIVE_WARN);
453           }
454 
455           if (ar->entry_padding == 0) {
456                     return (ARCHIVE_OK);
457           }
458 
459           if (ar->entry_padding != 1) {
460                     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
461                         "Padding wrong size: %ju should be 1 or 0",
462                         (uintmax_t)ar->entry_padding);
463                     return (ARCHIVE_WARN);
464           }
465 
466           ret = __archive_write_output(a, "\n", 1);
467           return (ret);
468 }
469 
470 /*
471  * Format a number into the specified field using base-8.
472  * NB: This version is slightly different from the one in
473  * _ustar.c
474  */
475 static int
format_octal(int64_t v,char * p,int s)476 format_octal(int64_t v, char *p, int s)
477 {
478           int len;
479           char *h;
480 
481           len = s;
482           h = p;
483 
484           /* Octal values can't be negative, so use 0. */
485           if (v < 0) {
486                     while (len-- > 0)
487                               *p++ = '0';
488                     return (-1);
489           }
490 
491           p += s;             /* Start at the end and work backwards. */
492           do {
493                     *--p = (char)('0' + (v & 7));
494                     v >>= 3;
495           } while (--s > 0 && v > 0);
496 
497           if (v == 0) {
498                     memmove(h, p, len - s);
499                     p = h + len - s;
500                     while (s-- > 0)
501                               *p++ = ' ';
502                     return (0);
503           }
504           /* If it overflowed, fill field with max value. */
505           while (len-- > 0)
506                     *p++ = '7';
507 
508           return (-1);
509 }
510 
511 /*
512  * Format a number into the specified field using base-10.
513  */
514 static int
format_decimal(int64_t v,char * p,int s)515 format_decimal(int64_t v, char *p, int s)
516 {
517           int len;
518           char *h;
519 
520           len = s;
521           h = p;
522 
523           /* Negative values in ar header are meaningless, so use 0. */
524           if (v < 0) {
525                     while (len-- > 0)
526                               *p++ = '0';
527                     return (-1);
528           }
529 
530           p += s;
531           do {
532                     *--p = (char)('0' + (v % 10));
533                     v /= 10;
534           } while (--s > 0 && v > 0);
535 
536           if (v == 0) {
537                     memmove(h, p, len - s);
538                     p = h + len - s;
539                     while (s-- > 0)
540                               *p++ = ' ';
541                     return (0);
542           }
543           /* If it overflowed, fill field with max value. */
544           while (len-- > 0)
545                     *p++ = '9';
546 
547           return (-1);
548 }
549 
550 static const char *
ar_basename(const char * path)551 ar_basename(const char *path)
552 {
553           const char *endp, *startp;
554 
555           endp = path + strlen(path) - 1;
556           /*
557            * For filename with trailing slash(es), we return
558            * NULL indicating an error.
559            */
560           if (*endp == '/')
561                     return (NULL);
562 
563           /* Find the start of the base */
564           startp = endp;
565           while (startp > path && *(startp - 1) != '/')
566                     startp--;
567 
568           return (startp);
569 }
570