Import libarchive 2.0.28.
[dragonfly/vkernel-mp.git] / contrib / libarchive-2.0 / libarchive / archive_write_set_format_ar.c
blob714b489c2064f251c1df873a56d93fee6315320d
1 /*-
2 * Copyright (c) 2007 Kai Wang
3 * Copyright (c) 2007 Tim Kientzle
4 * All rights reserved.
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.
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.
28 #include "archive_platform.h"
29 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.1 2007/04/03 05:34:36 kientzle Exp $");
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
44 #include "archive.h"
45 #include "archive_entry.h"
46 #include "archive_private.h"
47 #include "archive_write_private.h"
49 struct ar_w {
50 uint64_t entry_bytes_remaining;
51 uint64_t entry_padding;
52 int is_strtab;
53 int has_strtab;
54 char *strtab;
58 * Define structure of the "ar" header.
60 #define AR_name_offset 0
61 #define AR_name_size 16
62 #define AR_date_offset 16
63 #define AR_date_size 12
64 #define AR_uid_offset 28
65 #define AR_uid_size 6
66 #define AR_gid_offset 34
67 #define AR_gid_size 6
68 #define AR_mode_offset 40
69 #define AR_mode_size 8
70 #define AR_size_offset 48
71 #define AR_size_size 10
72 #define AR_fmag_offset 58
73 #define AR_fmag_size 2
76 * "ar" magic numbers.
78 #define ARMAG "!<arch>\n"
79 #define SARMAG 8 /* strlen(ARMAG); */
80 #define AR_EFMT1 "#1/"
81 #define SAR_EFMT1 3 /* strlen(AR_EFMT1); */
82 #define ARFMAG "`\n"
83 #define SARFMAG 2 /* strlen(ARFMAG); */
85 static int __archive_write_set_format_ar(struct archive_write *);
86 static int archive_write_ar_header(struct archive_write *,
87 struct archive_entry *);
88 static ssize_t archive_write_ar_data(struct archive_write *, const void *buff,
89 size_t s);
90 static int archive_write_ar_destroy(struct archive_write *);
91 static int archive_write_ar_finish_entry(struct archive_write *);
92 static int format_octal(int64_t v, char *p, int s);
93 static int format_decimal(int64_t v, char *p, int s);
95 int
96 archive_write_set_format_ar_bsd(struct archive *_a)
98 struct archive_write *a = (struct archive_write *)_a;
99 int r = __archive_write_set_format_ar(a);
100 if (r == ARCHIVE_OK) {
101 a->archive_format = ARCHIVE_FORMAT_AR_BSD;
102 a->archive_format_name = "ar (BSD)";
104 return (r);
108 archive_write_set_format_ar_svr4(struct archive *_a)
110 struct archive_write *a = (struct archive_write *)_a;
111 int r = __archive_write_set_format_ar(a);
112 if (r == ARCHIVE_OK) {
113 a->archive_format = ARCHIVE_FORMAT_AR_SVR4;
114 a->archive_format_name = "ar (GNU/SVR4)";
116 return (r);
120 * Generic initialization.
122 static int
123 __archive_write_set_format_ar(struct archive_write *a)
125 struct ar_w *ar;
127 /* If someone else was already registered, unregister them. */
128 if (a->format_destroy != NULL)
129 (a->format_destroy)(a);
131 ar = (struct ar_w *)malloc(sizeof(*ar));
132 if (ar == NULL) {
133 archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");
134 return (ARCHIVE_FATAL);
136 memset(ar, 0, sizeof(*ar));
137 a->format_data = ar;
139 a->format_write_header = archive_write_ar_header;
140 a->format_write_data = archive_write_ar_data;
141 a->format_finish = NULL;
142 a->format_destroy = archive_write_ar_destroy;
143 a->format_finish_entry = archive_write_ar_finish_entry;
144 return (ARCHIVE_OK);
147 static int
148 archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
150 int ret, append_fn;
151 char buff[60];
152 char *ss, *se;
153 struct ar_w *ar;
154 const char *pp;
155 const struct stat *st;
157 ret = 0;
158 append_fn = 0;
159 ar = (struct ar_w *)a->format_data;
160 ar->is_strtab = 0;
162 if (a->archive.file_position == 0) {
164 * We are now at the beginning of the archive,
165 * so we need first write the ar global header.
167 (a->compression_write)(a, ARMAG, SARMAG);
170 memset(buff, ' ', 60);
171 strncpy(&buff[AR_fmag_offset], ARFMAG, SARFMAG);
173 pp = archive_entry_pathname(entry);
175 if (strcmp(pp, "/") == 0 ) {
176 /* Entry is archive symbol table in GNU format */
177 buff[AR_name_offset] = '/';
178 goto stat;
180 if (strcmp(pp, "__.SYMDEF") == 0) {
181 /* Entry is archive symbol table in BSD format */
182 strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
183 goto stat;
185 if (strcmp(pp, "//") == 0) {
187 * Entry is archive string table, inform that we should
188 * collect strtab in next _data call.
190 ar->is_strtab = 1;
191 buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';
193 * For archive string table, only ar_size filed should
194 * be set.
196 goto size;
199 /* Otherwise, entry is a normal archive member. */
200 if (a->archive_format == ARCHIVE_FORMAT_AR_SVR4) {
202 * SVR4/GNU variant use a "/" to mark then end of the filename,
203 * make it possible to have embedded spaces in the filename.
204 * So, the longest filename here (without extension) is
205 * actually 15 bytes.
207 if (strlen(pp) <= 15) {
208 strncpy(&buff[AR_name_offset], pp, strlen(pp));
209 buff[AR_name_offset + strlen(pp)] = '/';
210 } else {
212 * For filename longer than 15 bytes, GNU variant
213 * makes use of a string table and instead stores the
214 * offset of the real filename to in the ar_name field.
215 * The string table should have been written before.
217 if (ar->has_strtab <= 0) {
218 archive_set_error(&a->archive, EINVAL,
219 "Can't find string table");
220 return (ARCHIVE_WARN);
223 se = (char *)malloc(strlen(pp) + 3);
224 if (se == NULL) {
225 archive_set_error(&a->archive, ENOMEM,
226 "Can't allocate filename buffer");
227 return (ARCHIVE_FATAL);
230 strncpy(se, pp, strlen(pp));
231 strcpy(se + strlen(pp), "/\n");
233 ss = strstr(ar->strtab, se);
234 free(se);
236 if (ss == NULL) {
237 archive_set_error(&a->archive, EINVAL,
238 "Invalid string table");
239 return (ARCHIVE_WARN);
243 * GNU variant puts "/" followed by digits into
244 * ar_name field. These digits indicates the real
245 * filename string's offset to the string table.
247 buff[AR_name_offset] = '/';
248 if (format_decimal(ss - ar->strtab,
249 buff + AR_name_offset + 1,
250 AR_name_size - 1)) {
251 archive_set_error(&a->archive, ERANGE,
252 "string table offset too large");
253 return (ARCHIVE_WARN);
256 } else if (a->archive_format == ARCHIVE_FORMAT_AR_BSD) {
258 * BSD variant: for any file name which is more than
259 * 16 chars or contains one or more embedded space(s), the
260 * string "#1/" followed by the ASCII length of the name is
261 * put into the ar_name field. The file size (stored in the
262 * ar_size field) is incremented by the length of the name.
263 * The name is then written immediately following the
264 * archive header.
266 if (strlen(pp) <= 16 && strchr(pp, ' ') == NULL) {
267 strncpy(&buff[AR_name_offset], pp, strlen(pp));
268 buff[AR_name_offset + strlen(pp)] = ' ';
270 else {
271 strncpy(buff + AR_name_offset, AR_EFMT1, SAR_EFMT1);
272 if (format_decimal(strlen(pp),
273 buff + AR_name_offset + SAR_EFMT1,
274 AR_name_size - SAR_EFMT1)) {
275 archive_set_error(&a->archive, ERANGE,
276 "File name too long");
277 return (ARCHIVE_WARN);
279 append_fn = 1;
280 archive_entry_set_size(entry,
281 archive_entry_size(entry) + strlen(pp));
285 stat:
286 st = archive_entry_stat(entry);
287 if (format_decimal(st->st_mtime, buff + AR_date_offset, AR_date_size)) {
288 archive_set_error(&a->archive, ERANGE,
289 "File modification time too large");
290 return (ARCHIVE_WARN);
292 if (format_decimal(st->st_uid, buff + AR_uid_offset, AR_uid_size)) {
293 archive_set_error(&a->archive, ERANGE,
294 "Numeric user ID too large");
295 return (ARCHIVE_WARN);
297 if (format_decimal(st->st_gid, buff + AR_gid_offset, AR_gid_size)) {
298 archive_set_error(&a->archive, ERANGE,
299 "Numeric group ID too large");
300 return (ARCHIVE_WARN);
302 if (format_octal(st->st_mode, buff + AR_mode_offset, AR_mode_size)) {
303 archive_set_error(&a->archive, ERANGE,
304 "Numeric mode too large");
305 return (ARCHIVE_WARN);
308 size:
309 if (format_decimal(archive_entry_size(entry), buff + AR_size_offset,
310 AR_size_size)) {
311 archive_set_error(&a->archive, ERANGE,
312 "File size out of range");
313 return (ARCHIVE_WARN);
316 ret = (a->compression_write)(a, buff, 60);
317 if (ret != ARCHIVE_OK)
318 return (ret);
320 ar->entry_bytes_remaining = archive_entry_size(entry);
321 ar->entry_padding = ar->entry_bytes_remaining % 2;
323 if (append_fn > 0) {
324 ret = (a->compression_write)(a, pp, strlen(pp));
325 if (ret != ARCHIVE_OK)
326 return (ret);
327 ar->entry_bytes_remaining -= strlen(pp);
330 return (ARCHIVE_OK);
333 static ssize_t
334 archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
336 struct ar_w *ar;
337 int ret;
339 ar = (struct ar_w *)a->format_data;
340 if (s > ar->entry_bytes_remaining)
341 s = ar->entry_bytes_remaining;
343 if (ar->is_strtab > 0) {
344 if (ar->has_strtab > 0) {
345 archive_set_error(&a->archive, EINVAL,
346 "More than one string tables exist");
347 return (ARCHIVE_WARN);
350 ar->strtab = (char *)malloc(s);
351 if (ar->strtab == NULL) {
352 archive_set_error(&a->archive, ENOMEM,
353 "Can't allocate strtab buffer");
354 return (ARCHIVE_FATAL);
356 strncpy(ar->strtab, buff, s);
357 ar->has_strtab = 1;
360 ret = (a->compression_write)(a, buff, s);
361 if (ret != ARCHIVE_OK)
362 return (ret);
364 ar->entry_bytes_remaining -= s;
365 return (s);
368 static int
369 archive_write_ar_destroy(struct archive_write *a)
371 struct ar_w *ar;
373 ar = (struct ar_w *)a->format_data;
375 if (ar->has_strtab > 0) {
376 free(ar->strtab);
377 ar->strtab = NULL;
380 free(ar);
381 a->format_data = NULL;
382 return (ARCHIVE_OK);
385 static int
386 archive_write_ar_finish_entry(struct archive_write *a)
388 struct ar_w *ar;
389 int ret;
391 ar = (struct ar_w *)a->format_data;
393 if (ar->entry_bytes_remaining != 0) {
394 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
395 "Entry remaining bytes larger than 0");
396 return (ARCHIVE_WARN);
399 if (ar->entry_padding == 0) {
400 return (ARCHIVE_OK);
403 if (ar->entry_padding != 1) {
404 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
405 "Padding wrong size: %d should be 1 or 0",
406 ar->entry_padding);
407 return (ARCHIVE_WARN);
410 ret = (a->compression_write)(a, "\n", 1);
411 return (ret);
415 * Format a number into the specified field using base-8.
416 * NB: This version is slightly different from the one in
417 * _ustar.c
419 static int
420 format_octal(int64_t v, char *p, int s)
422 int len;
423 char *h;
425 len = s;
426 h = p;
428 /* Octal values can't be negative, so use 0. */
429 if (v < 0) {
430 while (len-- > 0)
431 *p++ = '0';
432 return (-1);
435 p += s; /* Start at the end and work backwards. */
436 do {
437 *--p = (char)('0' + (v & 7));
438 v >>= 3;
439 } while (--s > 0 && v > 0);
441 if (v == 0) {
442 memmove(h, p, len - s);
443 p = h + len - s;
444 while (s-- > 0)
445 *p++ = ' ';
446 return (0);
448 /* If it overflowed, fill field with max value. */
449 while (len-- > 0)
450 *p++ = '7';
452 return (-1);
456 * Format a number into the specified field using base-10.
458 static int
459 format_decimal(int64_t v, char *p, int s)
461 int len;
462 char *h;
464 len = s;
465 h = p;
467 /* Negative values in ar header are meaningless , so use 0. */
468 if (v < 0) {
469 while (len-- > 0)
470 *p++ = '0';
471 return (-1);
474 p += s;
475 do {
476 *--p = (char)('0' + (v % 10));
477 v /= 10;
478 } while (--s > 0 && v > 0);
480 if (v == 0) {
481 memmove(h, p, len - s);
482 p = h + len - s;
483 while (s-- > 0)
484 *p++ = ' ';
485 return (0);
487 /* If it overflowed, fill field with max value. */
488 while (len-- > 0)
489 *p++ = '9';
491 return (-1);