Document the recently added WITHOUT_SRCS variable.
[dragonfly.git] / contrib / libarchive / archive_write_set_format_ustar.c
1 /*-
2  * Copyright (c) 2003-2004 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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.12 2004/11/05 05:26:30 kientzle Exp $");
29
30 #include <sys/stat.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "archive.h"
37 #include "archive_entry.h"
38 #include "archive_private.h"
39
40 struct ustar {
41         uint64_t        entry_bytes_remaining;
42         uint64_t        entry_padding;
43         char            written;
44 };
45
46 /*
47  * Define structure of POSIX 'ustar' tar header.
48  */
49 struct archive_entry_header_ustar {
50         char    name[100];
51         char    mode[6];
52         char    mode_padding[2];
53         char    uid[6];
54         char    uid_padding[2];
55         char    gid[6];
56         char    gid_padding[2];
57         char    size[11];
58         char    size_padding[1];
59         char    mtime[11];
60         char    mtime_padding[1];
61         char    checksum[8];
62         char    typeflag[1];
63         char    linkname[100];
64         char    magic[6]; /* For POSIX: "ustar\0" */
65         char    version[2]; /* For POSIX: "00" */
66         char    uname[32];
67         char    gname[32];
68         char    rdevmajor[6];
69         char    rdevmajor_padding[2];
70         char    rdevminor[6];
71         char    rdevminor_padding[2];
72         char    prefix[155];
73         char    padding[12];
74 };
75
76 /*
77  * A filled-in copy of the header for initialization.
78  */
79 static const struct archive_entry_header_ustar template_header = {
80         { "" },                         /* name */
81         { "000000" }, { ' ', '\0' },    /* mode, space-null termination. */
82         { "000000" }, { ' ', '\0' },    /* uid, space-null termination. */
83         { "000000" }, { ' ', '\0' },    /* gid, space-null termination. */
84         { "00000000000" }, { ' ' },     /* size, space termination. */
85         { "00000000000" }, { ' ' },     /* mtime, space termination. */
86         { "        " },                 /* Initial checksum value. */
87         { '0' },                        /* default: regular file */
88         { "" },                         /* linkname */
89         { "ustar" },                    /* magic */
90         { '0', '0' },                   /* version */
91         { "" },                         /* uname */
92         { "" },                         /* gname */
93         { "000000" }, { ' ', '\0' },    /* rdevmajor, space-null termination */
94         { "000000" }, { ' ', '\0' },    /* rdevminor, space-null termination */
95         { "" },                         /* prefix */
96         { "" }                          /* padding */
97 };
98
99 static int      archive_write_ustar_data(struct archive *a, const void *buff,
100                     size_t s);
101 static int      archive_write_ustar_finish(struct archive *);
102 static int      archive_write_ustar_finish_entry(struct archive *);
103 static int      archive_write_ustar_header(struct archive *,
104                     struct archive_entry *entry);
105 static int      format_256(int64_t, char *, int);
106 static int      format_number(int64_t, char *, int size, int max, int strict);
107 static int      format_octal(int64_t, char *, int);
108 static int      write_nulls(struct archive *a, size_t);
109
110 /*
111  * Set output format to 'ustar' format.
112  */
113 int
114 archive_write_set_format_ustar(struct archive *a)
115 {
116         struct ustar *ustar;
117
118         /* If someone else was already registered, unregister them. */
119         if (a->format_finish != NULL)
120                 (a->format_finish)(a);
121
122         ustar = malloc(sizeof(*ustar));
123         if (ustar == NULL) {
124                 archive_set_error(a, ENOMEM, "Can't allocate ustar data");
125                 return (ARCHIVE_FATAL);
126         }
127         memset(ustar, 0, sizeof(*ustar));
128         a->format_data = ustar;
129
130         a->pad_uncompressed = 1;        /* Mimic gtar in this respect. */
131         a->format_write_header = archive_write_ustar_header;
132         a->format_write_data = archive_write_ustar_data;
133         a->format_finish = archive_write_ustar_finish;
134         a->format_finish_entry = archive_write_ustar_finish_entry;
135         a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
136         a->archive_format_name = "POSIX ustar";
137         return (ARCHIVE_OK);
138 }
139
140 static int
141 archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
142 {
143         char buff[512];
144         int ret;
145         struct ustar *ustar;
146
147         ustar = a->format_data;
148         ustar->written = 1;
149
150         /* Only regular files (not hardlinks) have data. */
151         if (archive_entry_hardlink(entry) != NULL ||
152             archive_entry_symlink(entry) != NULL ||
153             !S_ISREG(archive_entry_mode(entry)))
154                 archive_entry_set_size(entry, 0);
155
156         ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
157         if (ret != ARCHIVE_OK)
158                 return (ret);
159         ret = (a->compression_write)(a, buff, 512);
160         if (ret != ARCHIVE_OK)
161                 return (ret);
162
163         ustar->entry_bytes_remaining = archive_entry_size(entry);
164         ustar->entry_padding = 0x1ff & (- ustar->entry_bytes_remaining);
165         return (ARCHIVE_OK);
166 }
167
168 /*
169  * Format a basic 512-byte "ustar" header.
170  *
171  * Returns -1 if format failed (due to field overflow).
172  * Note that this always formats as much of the header as possible.
173  * If "strict" is set to zero, it will extend numeric fields as
174  * necessary (overwriting terminators or using base-256 extensions).
175  *
176  * This is exported so that other 'tar' formats can use it.
177  */
178 int
179 __archive_write_format_header_ustar(struct archive *a, char buff[512],
180     struct archive_entry *entry, int tartype, int strict)
181 {
182         unsigned int checksum;
183         struct archive_entry_header_ustar *h;
184         int i, ret;
185         size_t copy_length;
186         const char *p, *pp;
187         const struct stat *st;
188         int mytartype;
189
190         ret = 0;
191         mytartype = -1;
192         /*
193          * The "template header" already includes the "ustar"
194          * signature, various end-of-field markers and other required
195          * elements.
196          */
197         memcpy(buff, &template_header, 512);
198
199         h = (struct archive_entry_header_ustar *)buff;
200
201         /*
202          * Because the block is already null-filled, and strings
203          * are allowed to exactly fill their destination (without null),
204          * I use memcpy(dest, src, strlen()) here a lot to copy strings.
205          */
206
207         pp = archive_entry_pathname(entry);
208         if (strlen(pp) <= sizeof(h->name))
209                 memcpy(h->name, pp, strlen(pp));
210         else {
211                 /* Store in two pieces, splitting at a '/'. */
212                 p = strchr(pp + strlen(pp) - sizeof(h->name) - 1, '/');
213                 /*
214                  * If there is no path separator, or the prefix or
215                  * remaining name are too large, return an error.
216                  */
217                 if (!p) {
218                         archive_set_error(a, ENAMETOOLONG,
219                             "Pathname too long");
220                         ret = ARCHIVE_WARN;
221                 } else if (p  > pp + sizeof(h->prefix)) {
222                         archive_set_error(a, ENAMETOOLONG,
223                             "Pathname too long");
224                         ret = ARCHIVE_WARN;
225                 } else {
226                         /* Copy prefix and remainder to appropriate places */
227                         memcpy(h->prefix, pp, p - pp);
228                         memcpy(h->name, p + 1, pp + strlen(pp) - p - 1);
229                 }
230         }
231
232         p = archive_entry_hardlink(entry);
233         if(p != NULL)
234                 mytartype = '1';
235         else
236                 p = archive_entry_symlink(entry);
237         if (p != NULL && p[0] != '\0') {
238                 copy_length = strlen(p);
239                 if (copy_length > sizeof(h->linkname)) {
240                         archive_set_error(a, ENAMETOOLONG,
241                             "Link contents too long");
242                         ret = ARCHIVE_WARN;
243                         copy_length = sizeof(h->linkname);
244                 }
245                 memcpy(h->linkname, p, copy_length);
246         }
247
248         p = archive_entry_uname(entry);
249         if (p != NULL && p[0] != '\0') {
250                 copy_length = strlen(p);
251                 if (copy_length > sizeof(h->uname)) {
252                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
253                             "Username too long");
254                         ret = ARCHIVE_WARN;
255                         copy_length = sizeof(h->uname);
256                 }
257                 memcpy(h->uname, p, copy_length);
258         }
259
260         p = archive_entry_gname(entry);
261         if (p != NULL && p[0] != '\0') {
262                 copy_length = strlen(p);
263                 if (strlen(p) > sizeof(h->gname)) {
264                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
265                             "Group name too long");
266                         ret = ARCHIVE_WARN;
267                         copy_length = sizeof(h->gname);
268                 }
269                 memcpy(h->gname, p, copy_length);
270         }
271
272         st = archive_entry_stat(entry);
273
274         if (format_number(st->st_mode & 07777, h->mode, sizeof(h->mode), 8, strict)) {
275                 archive_set_error(a, ERANGE, "Numeric mode too large");
276                 ret = ARCHIVE_WARN;
277         }
278
279         if (format_number(st->st_uid, h->uid, sizeof(h->uid), 8, strict)) {
280                 archive_set_error(a, ERANGE, "Numeric user ID too large");
281                 ret = ARCHIVE_WARN;
282         }
283
284         if (format_number(st->st_gid, h->gid, sizeof(h->gid), 8, strict)) {
285                 archive_set_error(a, ERANGE, "Numeric group ID too large");
286                 ret = ARCHIVE_WARN;
287         }
288
289         if (format_number(st->st_size, h->size, sizeof(h->size), 12, strict)) {
290                 archive_set_error(a, ERANGE, "File size out of range");
291                 ret = ARCHIVE_WARN;
292         }
293
294         if (format_number(st->st_mtime, h->mtime, sizeof(h->mtime), 12, strict)) {
295                 archive_set_error(a, ERANGE,
296                     "File modification time too large");
297                 ret = ARCHIVE_WARN;
298         }
299
300         if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
301                 if (format_number(major(st->st_rdev), h->rdevmajor,
302                         sizeof(h->rdevmajor), 8, strict)) {
303                         archive_set_error(a, ERANGE,
304                             "Major device number too large");
305                         ret = ARCHIVE_WARN;
306                 }
307
308                 if (format_number(minor(st->st_rdev), h->rdevminor,
309                         sizeof(h->rdevminor), 8, strict)) {
310                         archive_set_error(a, ERANGE,
311                             "Minor device number too large");
312                         ret = ARCHIVE_WARN;
313                 }
314         }
315
316         if (tartype >= 0) {
317                 h->typeflag[0] = tartype;
318         } else if (mytartype >= 0) {
319                 h->typeflag[0] = mytartype;
320         } else {
321                 switch (st->st_mode & S_IFMT) {
322                 case S_IFREG: h->typeflag[0] = '0' ; break;
323                 case S_IFLNK: h->typeflag[0] = '2' ; break;
324                 case S_IFCHR: h->typeflag[0] = '3' ; break;
325                 case S_IFBLK: h->typeflag[0] = '4' ; break;
326                 case S_IFDIR: h->typeflag[0] = '5' ; break;
327                 case S_IFIFO: h->typeflag[0] = '6' ; break;
328                 case S_IFSOCK:
329                         archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
330                             "tar format cannot archive socket");
331                         ret = ARCHIVE_WARN;
332                         break;
333                 default:
334                         archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
335                             "tar format cannot archive this (mode=0%lo)",
336                             (unsigned long)st->st_mode);
337                         ret = ARCHIVE_WARN;
338                 }
339         }
340
341         checksum = 0;
342         for (i = 0; i < 512; i++)
343                 checksum += 255 & (unsigned int)buff[i];
344         h->checksum[6] = '\0'; /* Can't be pre-set in the template. */
345         /* h->checksum[7] = ' '; */ /* This is pre-set in the template. */
346         format_octal(checksum, h->checksum, 6);
347         return (ret);
348 }
349
350 /*
351  * Format a number into a field, with some intelligence.
352  */
353 static int
354 format_number(int64_t v, char *p, int s, int maxsize, int strict)
355 {
356         int64_t limit;
357
358         limit = ((int64_t)1 << (s*3));
359
360         /* "Strict" only permits octal values with proper termination. */
361         if (strict)
362                 return (format_octal(v, p, s));
363
364         /*
365          * In non-strict mode, we allow the number to overwrite one or
366          * more bytes of the field termination.  Even old tar
367          * implementations should be able to handle this with no
368          * problem.
369          */
370         if (v >= 0) {
371                 while (s <= maxsize) {
372                         if (v < limit)
373                                 return (format_octal(v, p, s));
374                         s++;
375                         limit <<= 3;
376                 }
377         }
378
379         /* Base-256 can handle any number, positive or negative. */
380         return (format_256(v, p, maxsize));
381 }
382
383 /*
384  * Format a number into the specified field using base-256.
385  */
386 static int
387 format_256(int64_t v, char *p, int s)
388 {
389         p += s;
390         while (s-- > 0) {
391                 *--p = (char)(v & 0xff);
392                 v >>= 8;
393         }
394         *p |= 0x80; /* Set the base-256 marker bit. */
395         return (0);
396 }
397
398 /*
399  * Format a number into the specified field.
400  */
401 static int
402 format_octal(int64_t v, char *p, int s)
403 {
404         int len;
405
406         len = s;
407
408         /* Octal values can't be negative, so use 0. */
409         if (v < 0) {
410                 while (len-- > 0)
411                         *p++ = '0';
412                 return (-1);
413         }
414
415         p += s;         /* Start at the end and work backwards. */
416         while (s-- > 0) {
417                 *--p = '0' + (v & 7);
418                 v >>= 3;
419         }
420
421         if (v == 0)
422                 return (0);
423
424         /* If it overflowed, fill field with max value. */
425         while (len-- > 0)
426                 *p++ = '7';
427
428         return (-1);
429 }
430
431 static int
432 archive_write_ustar_finish(struct archive *a)
433 {
434         struct ustar *ustar;
435         int r;
436
437         r = ARCHIVE_OK;
438         ustar = a->format_data;
439         /*
440          * Suppress end-of-archive if nothing else was ever written.
441          * This fixes a problem where setting one format, then another
442          * ends up writing a gratuitous end-of-archive marker.
443          */
444         if (ustar->written && a->compression_write != NULL)
445                 r = write_nulls(a, 512*2);
446         free(ustar);
447         a->format_data = NULL;
448         return (r);
449 }
450
451 static int
452 archive_write_ustar_finish_entry(struct archive *a)
453 {
454         struct ustar *ustar;
455         int ret;
456
457         ustar = a->format_data;
458         ret = write_nulls(a,
459             ustar->entry_bytes_remaining + ustar->entry_padding);
460         ustar->entry_bytes_remaining = ustar->entry_padding = 0;
461         return (ret);
462 }
463
464 static int
465 write_nulls(struct archive *a, size_t padding)
466 {
467         int ret, to_write;
468
469         while (padding > 0) {
470                 to_write = padding < a->null_length ? padding : a->null_length;
471                 ret = (a->compression_write)(a, a->nulls, to_write);
472                 if (ret != ARCHIVE_OK)
473                         return (ret);
474                 padding -= to_write;
475         }
476         return (ARCHIVE_OK);
477 }
478
479 static int
480 archive_write_ustar_data(struct archive *a, const void *buff, size_t s)
481 {
482         struct ustar *ustar;
483         int ret;
484
485         ustar = a->format_data;
486         if (s > ustar->entry_bytes_remaining)
487                 s = ustar->entry_bytes_remaining;
488         ret = (a->compression_write)(a, buff, s);
489         ustar->entry_bytes_remaining -= s;
490         return (ret);
491 }