2
* Copyright (c) 2003-2004 Tim Kientzle
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
27
#include "archive_platform.h"
28
__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_shar.c,v 1.11 2004/11/05 05:26:30 kientzle Exp $");
38
#include "archive_entry.h"
39
#include "archive_private.h"
44
struct archive_entry *entry;
53
struct archive_string work;
56
static int archive_write_shar_finish(struct archive *);
57
static int archive_write_shar_header(struct archive *,
58
struct archive_entry *);
59
static int archive_write_shar_data_sed(struct archive *,
60
const void * buff, size_t);
61
static int archive_write_shar_data_uuencode(struct archive *,
62
const void * buff, size_t);
63
static int archive_write_shar_finish_entry(struct archive *);
64
static int shar_printf(struct archive *, const char *fmt, ...);
65
static void uuencode_group(struct shar *);
68
shar_printf(struct archive *a, const char *fmt, ...)
74
shar = a->format_data;
76
archive_string_empty(&(shar->work));
77
archive_string_vsprintf(&(shar->work), fmt, ap);
78
ret = ((a->compression_write)(a, shar->work.s, strlen(shar->work.s)));
84
* Set output format to 'shar' format.
87
archive_write_set_format_shar(struct archive *a)
91
/* If someone else was already registered, unregister them. */
92
if (a->format_finish != NULL)
93
(a->format_finish)(a);
95
shar = malloc(sizeof(*shar));
97
archive_set_error(a, ENOMEM, "Can't allocate shar data");
98
return (ARCHIVE_FATAL);
100
memset(shar, 0, sizeof(*shar));
101
a->format_data = shar;
103
a->pad_uncompressed = 0;
104
a->format_write_header = archive_write_shar_header;
105
a->format_finish = archive_write_shar_finish;
106
a->format_write_data = archive_write_shar_data_sed;
107
a->format_finish_entry = archive_write_shar_finish_entry;
108
a->archive_format = ARCHIVE_FORMAT_SHAR_BASE;
109
a->archive_format_name = "shar";
114
* An alternate 'shar' that uses uudecode instead of 'sed' to encode
115
* file contents and can therefore be used to archive binary files.
116
* In addition, this variant also attempts to restore ownership, file modes,
117
* and other extended file information.
120
archive_write_set_format_shar_dump(struct archive *a)
124
archive_write_set_format_shar(a);
125
shar = a->format_data;
127
a->format_write_data = archive_write_shar_data_uuencode;
128
a->archive_format = ARCHIVE_FORMAT_SHAR_DUMP;
129
a->archive_format_name = "shar dump";
134
archive_write_shar_header(struct archive *a, struct archive_entry *entry)
136
const char *linkname;
140
const struct stat *st;
143
shar = a->format_data;
144
if (!shar->wrote_header) {
145
ret = shar_printf(a, "#!/bin/sh\n");
146
if (ret != ARCHIVE_OK)
148
ret = shar_printf(a, "# This is a shell archive\n");
149
if (ret != ARCHIVE_OK)
151
shar->wrote_header = 1;
154
/* Save the entry for the closing. */
156
archive_entry_free(shar->entry);
157
shar->entry = archive_entry_clone(entry);
158
name = archive_entry_pathname(entry);
159
st = archive_entry_stat(entry);
161
/* Handle some preparatory issues. */
162
switch(st->st_mode & S_IFMT) {
164
/* Only regular files have non-zero size. */
167
archive_entry_set_size(entry, 0);
168
/* Don't bother trying to recreate '.' */
169
if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0)
175
/* All other file types have zero size in the archive. */
176
archive_entry_set_size(entry, 0);
179
archive_entry_set_size(entry, 0);
180
if (archive_entry_hardlink(entry) == NULL &&
181
archive_entry_symlink(entry) == NULL) {
182
archive_set_error(a, ARCHIVE_ERRNO_MISC,
183
"shar format cannot archive this");
184
return (ARCHIVE_WARN);
188
/* Stock preparation for all file types. */
189
ret = shar_printf(a, "echo x %s\n", name);
190
if (ret != ARCHIVE_OK)
193
if (!S_ISDIR(st->st_mode)) {
194
/* Try to create the dir. */
196
pp = strrchr(p, '/');
197
/* If there is a / character, try to create the dir. */
201
/* Try to avoid a lot of redundant mkdir commands. */
202
if (strcmp(p, ".") == 0) {
203
/* Don't try to "mkdir ." */
204
} else if (shar->last_dir == NULL) {
206
"mkdir -p %s > /dev/null 2>&1\n", p);
207
if (ret != ARCHIVE_OK)
210
} else if (strcmp(p, shar->last_dir) == 0) {
211
/* We've already created this exact dir. */
213
} else if (strlen(p) < strlen(shar->last_dir) &&
214
strncmp(p, shar->last_dir, strlen(p)) == 0) {
215
/* We've already created a subdir. */
219
"mkdir -p %s > /dev/null 2>&1\n", p);
220
if (ret != ARCHIVE_OK)
222
free(shar->last_dir);
228
/* Handle file-type specific issues. */
230
if ((linkname = archive_entry_hardlink(entry)) != NULL) {
231
ret = shar_printf(a, "ln -f %s %s\n", linkname, name);
232
if (ret != ARCHIVE_OK)
234
} else if ((linkname = archive_entry_symlink(entry)) != NULL) {
235
ret = shar_printf(a, "ln -fs %s %s\n", linkname, name);
236
if (ret != ARCHIVE_OK)
239
switch(st->st_mode & S_IFMT) {
241
if (archive_entry_size(entry) == 0) {
242
/* More portable than "touch." */
243
ret = shar_printf(a, "test -e \"%s\" || :> \"%s\"\n", name, name);
244
if (ret != ARCHIVE_OK)
249
"uudecode -o %s << 'SHAR_END'\n",
251
if (ret != ARCHIVE_OK)
253
ret = shar_printf(a, "begin %o %s\n",
254
archive_entry_mode(entry) & 0777,
256
if (ret != ARCHIVE_OK)
260
"sed 's/^X//' > %s << 'SHAR_END'\n",
262
if (ret != ARCHIVE_OK)
266
shar->end_of_line = 1;
272
ret = shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n",
274
if (ret != ARCHIVE_OK)
276
/* Record that we just created this directory. */
277
if (shar->last_dir != NULL)
278
free(shar->last_dir);
280
shar->last_dir = strdup(name);
281
/* Trim a trailing '/'. */
282
pp = strrchr(shar->last_dir, '/');
283
if (pp != NULL && pp[1] == '\0')
286
* TODO: Put dir name/mode on a list to be fixed
287
* up at end of archive.
291
ret = shar_printf(a, "mkfifo %s\n", name);
292
if (ret != ARCHIVE_OK)
296
ret = shar_printf(a, "mknod %s c %d %d\n", name,
297
archive_entry_rdevmajor(entry),
298
archive_entry_rdevminor(entry));
299
if (ret != ARCHIVE_OK)
303
ret = shar_printf(a, "mknod %s b %d %d\n", name,
304
archive_entry_rdevmajor(entry),
305
archive_entry_rdevminor(entry));
306
if (ret != ARCHIVE_OK)
310
return (ARCHIVE_WARN);
317
/* XXX TODO: This could be more efficient XXX */
319
archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
325
shar = a->format_data;
333
if (shar->end_of_line) {
334
shar->outbuff[shar->outpos++] = 'X';
335
shar->end_of_line = 0;
338
shar->end_of_line = 1;
339
shar->outbuff[shar->outpos++] = *src++;
341
if (shar->outpos > sizeof(shar->outbuff) - 2) {
342
ret = (a->compression_write)(a, shar->outbuff,
344
if (ret != ARCHIVE_OK)
350
if (shar->outpos > 0)
351
ret = (a->compression_write)(a, shar->outbuff, shar->outpos);
355
#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`')
357
/* XXX This could be a lot more efficient. XXX */
359
uuencode_group(struct shar *shar)
364
if (shar->uuavail > 0)
365
t = 0xff0000 & (shar->uubuffer[0] << 16);
366
if (shar->uuavail > 1)
367
t |= 0x00ff00 & (shar->uubuffer[1] << 8);
368
if (shar->uuavail > 2)
369
t |= 0x0000ff & (shar->uubuffer[2]);
370
shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>18) );
371
shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>12) );
372
shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>6) );
373
shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t) );
375
shar->outbytes += shar->uuavail;
376
shar->outbuff[shar->outpos] = 0;
380
archive_write_shar_data_uuencode(struct archive *a, const void *buff,
388
shar = a->format_data;
394
if (shar->uuavail == 3)
395
uuencode_group(shar);
396
if (shar->outpos >= 60) {
397
ret = shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
399
if (ret != ARCHIVE_OK)
405
shar->uubuffer[shar->uuavail++] = *src++;
412
archive_write_shar_finish_entry(struct archive *a)
414
const char *g, *p, *u;
418
shar = a->format_data;
419
if (shar->entry == NULL)
423
/* Finish uuencoded data. */
424
if (shar->has_data) {
425
if (shar->uuavail > 0)
426
uuencode_group(shar);
427
if (shar->outpos > 0) {
428
ret = shar_printf(a, "%c%s\n",
429
UUENC(shar->outbytes), shar->outbuff);
430
if (ret != ARCHIVE_OK)
436
ret = shar_printf(a, "%c\n", UUENC(0));
437
if (ret != ARCHIVE_OK)
439
ret = shar_printf(a, "end\n", UUENC(0));
440
if (ret != ARCHIVE_OK)
442
ret = shar_printf(a, "SHAR_END\n");
443
if (ret != ARCHIVE_OK)
446
/* Restore file mode, owner, flags. */
448
* TODO: Don't immediately restore mode for
449
* directories; defer that to end of script.
451
ret = shar_printf(a, "chmod %o %s\n",
452
archive_entry_mode(shar->entry) & 07777,
453
archive_entry_pathname(shar->entry));
454
if (ret != ARCHIVE_OK)
457
u = archive_entry_uname(shar->entry);
458
g = archive_entry_gname(shar->entry);
459
if (u != NULL || g != NULL) {
460
ret = shar_printf(a, "chown %s%s%s %s\n",
461
(u != NULL) ? u : "",
462
(g != NULL) ? ":" : "", (g != NULL) ? g : "",
463
archive_entry_pathname(shar->entry));
464
if (ret != ARCHIVE_OK)
468
if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
469
ret = shar_printf(a, "chflags %s %s\n", p,
470
archive_entry_pathname(shar->entry));
471
if (ret != ARCHIVE_OK)
475
/* TODO: restore ACLs */
478
if (shar->has_data) {
479
/* Finish sed-encoded data: ensure last line ends. */
480
if (!shar->end_of_line) {
481
ret = shar_printf(a, "\n");
482
if (ret != ARCHIVE_OK)
485
ret = shar_printf(a, "SHAR_END\n");
486
if (ret != ARCHIVE_OK)
491
archive_entry_free(shar->entry);
497
archive_write_shar_finish(struct archive *a)
503
* TODO: Accumulate list of directory names/modes and
504
* fix them all up at end-of-archive.
507
shar = a->format_data;
510
* Only write the end-of-archive markers if the archive was
511
* actually started. This avoids problems if someone sets
512
* shar format, then sets another format (which would invoke
513
* shar_finish to free the format-specific data).
515
if (shar->wrote_header) {
516
ret = shar_printf(a, "exit\n");
517
if (ret != ARCHIVE_OK)
519
/* Shar output is never padded. */
520
archive_write_set_bytes_in_last_block(a, 1);
522
* TODO: shar should also suppress padding of
523
* uncompressed data within gzip/bzip2 streams.
526
if (shar->entry != NULL)
527
archive_entry_free(shar->entry);
528
if (shar->last_dir != NULL)
529
free(shar->last_dir);
530
archive_string_free(&(shar->work));
532
a->format_data = NULL;