1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * Copyright (c) 2008 Joerg Sonnenberger 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28228763Smm__FBSDID("$FreeBSD: stable/10/contrib/libarchive/libarchive/archive_write_set_format_shar.c 358090 2020-02-19 01:51:44Z mm $"); 29228753Smm 30228753Smm#ifdef HAVE_ERRNO_H 31228753Smm#include <errno.h> 32228753Smm#endif 33228753Smm#include <stdio.h> 34228753Smm#ifdef HAVE_STDLIB_H 35228753Smm#include <stdlib.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_STRING_H 38228753Smm#include <string.h> 39228753Smm#endif 40228753Smm 41228753Smm#include "archive.h" 42228753Smm#include "archive_entry.h" 43228753Smm#include "archive_private.h" 44228753Smm#include "archive_write_private.h" 45358090Smm#include "archive_write_set_format_private.h" 46228753Smm 47228753Smmstruct shar { 48228753Smm int dump; 49228753Smm int end_of_line; 50228753Smm struct archive_entry *entry; 51228753Smm int has_data; 52228753Smm char *last_dir; 53228753Smm 54228753Smm /* Line buffer for uuencoded dump format */ 55228753Smm char outbuff[45]; 56228753Smm size_t outpos; 57228753Smm 58228753Smm int wrote_header; 59228753Smm struct archive_string work; 60228753Smm struct archive_string quoted_name; 61228753Smm}; 62228753Smm 63232153Smmstatic int archive_write_shar_close(struct archive_write *); 64232153Smmstatic int archive_write_shar_free(struct archive_write *); 65228753Smmstatic int archive_write_shar_header(struct archive_write *, 66228753Smm struct archive_entry *); 67228753Smmstatic ssize_t archive_write_shar_data_sed(struct archive_write *, 68228753Smm const void * buff, size_t); 69228753Smmstatic ssize_t archive_write_shar_data_uuencode(struct archive_write *, 70228753Smm const void * buff, size_t); 71228753Smmstatic int archive_write_shar_finish_entry(struct archive_write *); 72228753Smm 73228753Smm/* 74228753Smm * Copy the given string to the buffer, quoting all shell meta characters 75228753Smm * found. 76228753Smm */ 77228753Smmstatic void 78228753Smmshar_quote(struct archive_string *buf, const char *str, int in_shell) 79228753Smm{ 80228753Smm static const char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; 81228753Smm size_t len; 82228753Smm 83228753Smm while (*str != '\0') { 84228753Smm if ((len = strcspn(str, meta)) != 0) { 85228753Smm archive_strncat(buf, str, len); 86228753Smm str += len; 87228753Smm } else if (*str == '\n') { 88228753Smm if (in_shell) 89228753Smm archive_strcat(buf, "\"\n\""); 90228753Smm else 91228753Smm archive_strcat(buf, "\\n"); 92228753Smm ++str; 93228753Smm } else { 94228753Smm archive_strappend_char(buf, '\\'); 95228753Smm archive_strappend_char(buf, *str); 96228753Smm ++str; 97228753Smm } 98228753Smm } 99228753Smm} 100228753Smm 101228753Smm/* 102228753Smm * Set output format to 'shar' format. 103228753Smm */ 104228753Smmint 105228753Smmarchive_write_set_format_shar(struct archive *_a) 106228753Smm{ 107228753Smm struct archive_write *a = (struct archive_write *)_a; 108228753Smm struct shar *shar; 109228753Smm 110232153Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 111232153Smm ARCHIVE_STATE_NEW, "archive_write_set_format_shar"); 112232153Smm 113228753Smm /* If someone else was already registered, unregister them. */ 114232153Smm if (a->format_free != NULL) 115232153Smm (a->format_free)(a); 116228753Smm 117311042Smm shar = (struct shar *)calloc(1, sizeof(*shar)); 118228753Smm if (shar == NULL) { 119228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data"); 120228753Smm return (ARCHIVE_FATAL); 121228753Smm } 122228753Smm archive_string_init(&shar->work); 123228753Smm archive_string_init(&shar->quoted_name); 124228753Smm a->format_data = shar; 125228753Smm a->format_name = "shar"; 126228753Smm a->format_write_header = archive_write_shar_header; 127232153Smm a->format_close = archive_write_shar_close; 128232153Smm a->format_free = archive_write_shar_free; 129228753Smm a->format_write_data = archive_write_shar_data_sed; 130228753Smm a->format_finish_entry = archive_write_shar_finish_entry; 131228753Smm a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE; 132228753Smm a->archive.archive_format_name = "shar"; 133228753Smm return (ARCHIVE_OK); 134228753Smm} 135228753Smm 136228753Smm/* 137228753Smm * An alternate 'shar' that uses uudecode instead of 'sed' to encode 138228753Smm * file contents and can therefore be used to archive binary files. 139228753Smm * In addition, this variant also attempts to restore ownership, file modes, 140228753Smm * and other extended file information. 141228753Smm */ 142228753Smmint 143228753Smmarchive_write_set_format_shar_dump(struct archive *_a) 144228753Smm{ 145228753Smm struct archive_write *a = (struct archive_write *)_a; 146228753Smm struct shar *shar; 147228753Smm 148228753Smm archive_write_set_format_shar(&a->archive); 149228753Smm shar = (struct shar *)a->format_data; 150228753Smm shar->dump = 1; 151228753Smm a->format_write_data = archive_write_shar_data_uuencode; 152228753Smm a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP; 153228753Smm a->archive.archive_format_name = "shar dump"; 154228753Smm return (ARCHIVE_OK); 155228753Smm} 156228753Smm 157228753Smmstatic int 158228753Smmarchive_write_shar_header(struct archive_write *a, struct archive_entry *entry) 159228753Smm{ 160228753Smm const char *linkname; 161228753Smm const char *name; 162228753Smm char *p, *pp; 163228753Smm struct shar *shar; 164228753Smm 165228753Smm shar = (struct shar *)a->format_data; 166228753Smm if (!shar->wrote_header) { 167228753Smm archive_strcat(&shar->work, "#!/bin/sh\n"); 168228753Smm archive_strcat(&shar->work, "# This is a shell archive\n"); 169228753Smm shar->wrote_header = 1; 170228753Smm } 171228753Smm 172228753Smm /* Save the entry for the closing. */ 173344674Smm archive_entry_free(shar->entry); 174228753Smm shar->entry = archive_entry_clone(entry); 175228753Smm name = archive_entry_pathname(entry); 176228753Smm 177228753Smm /* Handle some preparatory issues. */ 178228753Smm switch(archive_entry_filetype(entry)) { 179228753Smm case AE_IFREG: 180228753Smm /* Only regular files have non-zero size. */ 181228753Smm break; 182228753Smm case AE_IFDIR: 183228753Smm archive_entry_set_size(entry, 0); 184228753Smm /* Don't bother trying to recreate '.' */ 185228753Smm if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0) 186228753Smm return (ARCHIVE_OK); 187228753Smm break; 188228753Smm case AE_IFIFO: 189228753Smm case AE_IFCHR: 190228753Smm case AE_IFBLK: 191228753Smm /* All other file types have zero size in the archive. */ 192228753Smm archive_entry_set_size(entry, 0); 193228753Smm break; 194228753Smm default: 195228753Smm archive_entry_set_size(entry, 0); 196228753Smm if (archive_entry_hardlink(entry) == NULL && 197228753Smm archive_entry_symlink(entry) == NULL) { 198358090Smm __archive_write_entry_filetype_unsupported( 199358090Smm &a->archive, entry, "shar"); 200228753Smm return (ARCHIVE_WARN); 201228753Smm } 202228753Smm } 203228753Smm 204228753Smm archive_string_empty(&shar->quoted_name); 205228753Smm shar_quote(&shar->quoted_name, name, 1); 206228753Smm 207228753Smm /* Stock preparation for all file types. */ 208228753Smm archive_string_sprintf(&shar->work, "echo x %s\n", shar->quoted_name.s); 209228753Smm 210228753Smm if (archive_entry_filetype(entry) != AE_IFDIR) { 211228753Smm /* Try to create the dir. */ 212228753Smm p = strdup(name); 213228753Smm pp = strrchr(p, '/'); 214228753Smm /* If there is a / character, try to create the dir. */ 215228753Smm if (pp != NULL) { 216228753Smm *pp = '\0'; 217228753Smm 218228753Smm /* Try to avoid a lot of redundant mkdir commands. */ 219228753Smm if (strcmp(p, ".") == 0) { 220228753Smm /* Don't try to "mkdir ." */ 221228753Smm free(p); 222228753Smm } else if (shar->last_dir == NULL) { 223228753Smm archive_strcat(&shar->work, "mkdir -p "); 224228753Smm shar_quote(&shar->work, p, 1); 225228753Smm archive_strcat(&shar->work, 226228753Smm " > /dev/null 2>&1\n"); 227228753Smm shar->last_dir = p; 228228753Smm } else if (strcmp(p, shar->last_dir) == 0) { 229228753Smm /* We've already created this exact dir. */ 230228753Smm free(p); 231228753Smm } else if (strlen(p) < strlen(shar->last_dir) && 232228753Smm strncmp(p, shar->last_dir, strlen(p)) == 0) { 233228753Smm /* We've already created a subdir. */ 234228753Smm free(p); 235228753Smm } else { 236228753Smm archive_strcat(&shar->work, "mkdir -p "); 237228753Smm shar_quote(&shar->work, p, 1); 238228753Smm archive_strcat(&shar->work, 239228753Smm " > /dev/null 2>&1\n"); 240228753Smm shar->last_dir = p; 241228753Smm } 242228753Smm } else { 243228753Smm free(p); 244228753Smm } 245228753Smm } 246228753Smm 247228753Smm /* Handle file-type specific issues. */ 248228753Smm shar->has_data = 0; 249228753Smm if ((linkname = archive_entry_hardlink(entry)) != NULL) { 250228753Smm archive_strcat(&shar->work, "ln -f "); 251228753Smm shar_quote(&shar->work, linkname, 1); 252228753Smm archive_string_sprintf(&shar->work, " %s\n", 253228753Smm shar->quoted_name.s); 254228753Smm } else if ((linkname = archive_entry_symlink(entry)) != NULL) { 255228753Smm archive_strcat(&shar->work, "ln -fs "); 256228753Smm shar_quote(&shar->work, linkname, 1); 257228753Smm archive_string_sprintf(&shar->work, " %s\n", 258228753Smm shar->quoted_name.s); 259228753Smm } else { 260228753Smm switch(archive_entry_filetype(entry)) { 261228753Smm case AE_IFREG: 262228753Smm if (archive_entry_size(entry) == 0) { 263228753Smm /* More portable than "touch." */ 264228753Smm archive_string_sprintf(&shar->work, 265228753Smm "test -e \"%s\" || :> \"%s\"\n", 266228753Smm shar->quoted_name.s, shar->quoted_name.s); 267228753Smm } else { 268228753Smm if (shar->dump) { 269232153Smm unsigned int mode = archive_entry_mode(entry) & 0777; 270228753Smm archive_string_sprintf(&shar->work, 271228753Smm "uudecode -p > %s << 'SHAR_END'\n", 272228753Smm shar->quoted_name.s); 273228753Smm archive_string_sprintf(&shar->work, 274232153Smm "begin %o ", mode); 275228753Smm shar_quote(&shar->work, name, 0); 276228753Smm archive_strcat(&shar->work, "\n"); 277228753Smm } else { 278228753Smm archive_string_sprintf(&shar->work, 279228753Smm "sed 's/^X//' > %s << 'SHAR_END'\n", 280228753Smm shar->quoted_name.s); 281228753Smm } 282228753Smm shar->has_data = 1; 283228753Smm shar->end_of_line = 1; 284228753Smm shar->outpos = 0; 285228753Smm } 286228753Smm break; 287228753Smm case AE_IFDIR: 288228753Smm archive_string_sprintf(&shar->work, 289228753Smm "mkdir -p %s > /dev/null 2>&1\n", 290228753Smm shar->quoted_name.s); 291228753Smm /* Record that we just created this directory. */ 292344674Smm free(shar->last_dir); 293228753Smm 294228753Smm shar->last_dir = strdup(name); 295228753Smm /* Trim a trailing '/'. */ 296228753Smm pp = strrchr(shar->last_dir, '/'); 297228753Smm if (pp != NULL && pp[1] == '\0') 298228753Smm *pp = '\0'; 299228753Smm /* 300228753Smm * TODO: Put dir name/mode on a list to be fixed 301228753Smm * up at end of archive. 302228753Smm */ 303228753Smm break; 304228753Smm case AE_IFIFO: 305228753Smm archive_string_sprintf(&shar->work, 306228753Smm "mkfifo %s\n", shar->quoted_name.s); 307228753Smm break; 308228753Smm case AE_IFCHR: 309228753Smm archive_string_sprintf(&shar->work, 310232153Smm "mknod %s c %ju %ju\n", shar->quoted_name.s, 311232153Smm (uintmax_t)archive_entry_rdevmajor(entry), 312232153Smm (uintmax_t)archive_entry_rdevminor(entry)); 313228753Smm break; 314228753Smm case AE_IFBLK: 315228753Smm archive_string_sprintf(&shar->work, 316232153Smm "mknod %s b %ju %ju\n", shar->quoted_name.s, 317232153Smm (uintmax_t)archive_entry_rdevmajor(entry), 318232153Smm (uintmax_t)archive_entry_rdevminor(entry)); 319228753Smm break; 320228753Smm default: 321228753Smm return (ARCHIVE_WARN); 322228753Smm } 323228753Smm } 324228753Smm 325228753Smm return (ARCHIVE_OK); 326228753Smm} 327228753Smm 328228753Smmstatic ssize_t 329228753Smmarchive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n) 330228753Smm{ 331228753Smm static const size_t ensured = 65533; 332228753Smm struct shar *shar; 333228753Smm const char *src; 334228753Smm char *buf, *buf_end; 335228753Smm int ret; 336228753Smm size_t written = n; 337228753Smm 338228753Smm shar = (struct shar *)a->format_data; 339228753Smm if (!shar->has_data || n == 0) 340228753Smm return (0); 341228753Smm 342228753Smm src = (const char *)buff; 343228753Smm 344228753Smm /* 345228753Smm * ensure is the number of bytes in buffer before expanding the 346228753Smm * current character. Each operation writes the current character 347228753Smm * and optionally the start-of-new-line marker. This can happen 348228753Smm * twice before entering the loop, so make sure three additional 349228753Smm * bytes can be written. 350228753Smm */ 351232153Smm if (archive_string_ensure(&shar->work, ensured + 3) == NULL) { 352232153Smm archive_set_error(&a->archive, ENOMEM, "Out of memory"); 353232153Smm return (ARCHIVE_FATAL); 354232153Smm } 355228753Smm 356228753Smm if (shar->work.length > ensured) { 357232153Smm ret = __archive_write_output(a, shar->work.s, 358228753Smm shar->work.length); 359228753Smm if (ret != ARCHIVE_OK) 360228753Smm return (ARCHIVE_FATAL); 361228753Smm archive_string_empty(&shar->work); 362228753Smm } 363228753Smm buf = shar->work.s + shar->work.length; 364228753Smm buf_end = shar->work.s + ensured; 365228753Smm 366228753Smm if (shar->end_of_line) { 367228753Smm *buf++ = 'X'; 368228753Smm shar->end_of_line = 0; 369228753Smm } 370228753Smm 371228753Smm while (n-- != 0) { 372228753Smm if ((*buf++ = *src++) == '\n') { 373228753Smm if (n == 0) 374228753Smm shar->end_of_line = 1; 375228753Smm else 376228753Smm *buf++ = 'X'; 377228753Smm } 378228753Smm 379228753Smm if (buf >= buf_end) { 380228753Smm shar->work.length = buf - shar->work.s; 381232153Smm ret = __archive_write_output(a, shar->work.s, 382228753Smm shar->work.length); 383228753Smm if (ret != ARCHIVE_OK) 384228753Smm return (ARCHIVE_FATAL); 385228753Smm archive_string_empty(&shar->work); 386228753Smm buf = shar->work.s; 387228753Smm } 388228753Smm } 389228753Smm 390228753Smm shar->work.length = buf - shar->work.s; 391228753Smm 392228753Smm return (written); 393228753Smm} 394228753Smm 395228753Smm#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`') 396228753Smm 397228753Smmstatic void 398228753Smmuuencode_group(const char _in[3], char out[4]) 399228753Smm{ 400228753Smm const unsigned char *in = (const unsigned char *)_in; 401228753Smm int t; 402228753Smm 403228753Smm t = (in[0] << 16) | (in[1] << 8) | in[2]; 404228753Smm out[0] = UUENC( 0x3f & (t >> 18) ); 405228753Smm out[1] = UUENC( 0x3f & (t >> 12) ); 406228753Smm out[2] = UUENC( 0x3f & (t >> 6) ); 407228753Smm out[3] = UUENC( 0x3f & t ); 408228753Smm} 409228753Smm 410232153Smmstatic int 411232153Smm_uuencode_line(struct archive_write *a, struct shar *shar, const char *inbuf, size_t len) 412228753Smm{ 413232153Smm char *buf; 414228753Smm size_t alloc_len; 415228753Smm 416228753Smm /* len <= 45 -> expanded to 60 + len byte + new line */ 417228753Smm alloc_len = shar->work.length + 62; 418232153Smm if (archive_string_ensure(&shar->work, alloc_len) == NULL) { 419232153Smm archive_set_error(&a->archive, ENOMEM, "Out of memory"); 420232153Smm return (ARCHIVE_FATAL); 421232153Smm } 422228753Smm 423228753Smm buf = shar->work.s + shar->work.length; 424228753Smm *buf++ = UUENC(len); 425228753Smm while (len >= 3) { 426228753Smm uuencode_group(inbuf, buf); 427228753Smm len -= 3; 428228753Smm inbuf += 3; 429228753Smm buf += 4; 430228753Smm } 431228753Smm if (len != 0) { 432232153Smm char tmp_buf[3]; 433228753Smm tmp_buf[0] = inbuf[0]; 434228753Smm if (len == 1) 435228753Smm tmp_buf[1] = '\0'; 436228753Smm else 437228753Smm tmp_buf[1] = inbuf[1]; 438228753Smm tmp_buf[2] = '\0'; 439232153Smm uuencode_group(tmp_buf, buf); 440228753Smm buf += 4; 441228753Smm } 442228753Smm *buf++ = '\n'; 443232153Smm if ((buf - shar->work.s) > (ptrdiff_t)(shar->work.length + 62)) { 444232153Smm archive_set_error(&a->archive, 445232153Smm ARCHIVE_ERRNO_MISC, "Buffer overflow"); 446232153Smm return (ARCHIVE_FATAL); 447232153Smm } 448228753Smm shar->work.length = buf - shar->work.s; 449232153Smm return (ARCHIVE_OK); 450228753Smm} 451228753Smm 452232153Smm#define uuencode_line(__a, __shar, __inbuf, __len) \ 453232153Smm do { \ 454232153Smm int r = _uuencode_line(__a, __shar, __inbuf, __len); \ 455232153Smm if (r != ARCHIVE_OK) \ 456232153Smm return (ARCHIVE_FATAL); \ 457232153Smm } while (0) 458232153Smm 459228753Smmstatic ssize_t 460228753Smmarchive_write_shar_data_uuencode(struct archive_write *a, const void *buff, 461228753Smm size_t length) 462228753Smm{ 463228753Smm struct shar *shar; 464228753Smm const char *src; 465228753Smm size_t n; 466228753Smm int ret; 467228753Smm 468228753Smm shar = (struct shar *)a->format_data; 469228753Smm if (!shar->has_data) 470228753Smm return (ARCHIVE_OK); 471228753Smm src = (const char *)buff; 472228753Smm 473228753Smm if (shar->outpos != 0) { 474228753Smm n = 45 - shar->outpos; 475228753Smm if (n > length) 476228753Smm n = length; 477228753Smm memcpy(shar->outbuff + shar->outpos, src, n); 478228753Smm if (shar->outpos + n < 45) { 479228753Smm shar->outpos += n; 480228753Smm return length; 481228753Smm } 482232153Smm uuencode_line(a, shar, shar->outbuff, 45); 483228753Smm src += n; 484228753Smm n = length - n; 485228753Smm } else { 486228753Smm n = length; 487228753Smm } 488228753Smm 489228753Smm while (n >= 45) { 490232153Smm uuencode_line(a, shar, src, 45); 491228753Smm src += 45; 492228753Smm n -= 45; 493228753Smm 494228753Smm if (shar->work.length < 65536) 495228753Smm continue; 496232153Smm ret = __archive_write_output(a, shar->work.s, 497228753Smm shar->work.length); 498228753Smm if (ret != ARCHIVE_OK) 499228753Smm return (ARCHIVE_FATAL); 500228753Smm archive_string_empty(&shar->work); 501228753Smm } 502228753Smm if (n != 0) { 503228753Smm memcpy(shar->outbuff, src, n); 504228753Smm shar->outpos = n; 505228753Smm } 506228753Smm return (length); 507228753Smm} 508228753Smm 509228753Smmstatic int 510228753Smmarchive_write_shar_finish_entry(struct archive_write *a) 511228753Smm{ 512228753Smm const char *g, *p, *u; 513228753Smm struct shar *shar; 514228753Smm int ret; 515228753Smm 516228753Smm shar = (struct shar *)a->format_data; 517228753Smm if (shar->entry == NULL) 518228753Smm return (0); 519228753Smm 520228753Smm if (shar->dump) { 521228753Smm /* Finish uuencoded data. */ 522228753Smm if (shar->has_data) { 523228753Smm if (shar->outpos > 0) 524232153Smm uuencode_line(a, shar, shar->outbuff, 525228753Smm shar->outpos); 526228753Smm archive_strcat(&shar->work, "`\nend\n"); 527228753Smm archive_strcat(&shar->work, "SHAR_END\n"); 528228753Smm } 529228753Smm /* Restore file mode, owner, flags. */ 530228753Smm /* 531228753Smm * TODO: Don't immediately restore mode for 532228753Smm * directories; defer that to end of script. 533228753Smm */ 534228753Smm archive_string_sprintf(&shar->work, "chmod %o ", 535232153Smm (unsigned int)(archive_entry_mode(shar->entry) & 07777)); 536228753Smm shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1); 537228753Smm archive_strcat(&shar->work, "\n"); 538228753Smm 539228753Smm u = archive_entry_uname(shar->entry); 540228753Smm g = archive_entry_gname(shar->entry); 541228753Smm if (u != NULL || g != NULL) { 542228753Smm archive_strcat(&shar->work, "chown "); 543228753Smm if (u != NULL) 544228753Smm shar_quote(&shar->work, u, 1); 545228753Smm if (g != NULL) { 546228753Smm archive_strcat(&shar->work, ":"); 547228753Smm shar_quote(&shar->work, g, 1); 548228753Smm } 549302001Smm archive_strcat(&shar->work, " "); 550228753Smm shar_quote(&shar->work, 551228753Smm archive_entry_pathname(shar->entry), 1); 552228753Smm archive_strcat(&shar->work, "\n"); 553228753Smm } 554228753Smm 555228753Smm if ((p = archive_entry_fflags_text(shar->entry)) != NULL) { 556228753Smm archive_string_sprintf(&shar->work, "chflags %s ", p); 557228753Smm shar_quote(&shar->work, 558228753Smm archive_entry_pathname(shar->entry), 1); 559228753Smm archive_strcat(&shar->work, "\n"); 560228753Smm } 561228753Smm 562228753Smm /* TODO: restore ACLs */ 563228753Smm 564228753Smm } else { 565228753Smm if (shar->has_data) { 566228753Smm /* Finish sed-encoded data: ensure last line ends. */ 567228753Smm if (!shar->end_of_line) 568228753Smm archive_strappend_char(&shar->work, '\n'); 569228753Smm archive_strcat(&shar->work, "SHAR_END\n"); 570228753Smm } 571228753Smm } 572228753Smm 573228753Smm archive_entry_free(shar->entry); 574228753Smm shar->entry = NULL; 575228753Smm 576228753Smm if (shar->work.length < 65536) 577228753Smm return (ARCHIVE_OK); 578228753Smm 579232153Smm ret = __archive_write_output(a, shar->work.s, shar->work.length); 580228753Smm if (ret != ARCHIVE_OK) 581228753Smm return (ARCHIVE_FATAL); 582228753Smm archive_string_empty(&shar->work); 583228753Smm 584228753Smm return (ARCHIVE_OK); 585228753Smm} 586228753Smm 587228753Smmstatic int 588232153Smmarchive_write_shar_close(struct archive_write *a) 589228753Smm{ 590228753Smm struct shar *shar; 591228753Smm int ret; 592228753Smm 593228753Smm /* 594228753Smm * TODO: Accumulate list of directory names/modes and 595228753Smm * fix them all up at end-of-archive. 596228753Smm */ 597228753Smm 598228753Smm shar = (struct shar *)a->format_data; 599228753Smm 600228753Smm /* 601228753Smm * Only write the end-of-archive markers if the archive was 602228753Smm * actually started. This avoids problems if someone sets 603228753Smm * shar format, then sets another format (which would invoke 604228753Smm * shar_finish to free the format-specific data). 605228753Smm */ 606228753Smm if (shar->wrote_header == 0) 607228753Smm return (ARCHIVE_OK); 608228753Smm 609228753Smm archive_strcat(&shar->work, "exit\n"); 610228753Smm 611232153Smm ret = __archive_write_output(a, shar->work.s, shar->work.length); 612228753Smm if (ret != ARCHIVE_OK) 613228753Smm return (ARCHIVE_FATAL); 614228753Smm 615228753Smm /* Shar output is never padded. */ 616228753Smm archive_write_set_bytes_in_last_block(&a->archive, 1); 617228753Smm /* 618228753Smm * TODO: shar should also suppress padding of 619228753Smm * uncompressed data within gzip/bzip2 streams. 620228753Smm */ 621228753Smm 622228753Smm return (ARCHIVE_OK); 623228753Smm} 624228753Smm 625228753Smmstatic int 626232153Smmarchive_write_shar_free(struct archive_write *a) 627228753Smm{ 628228753Smm struct shar *shar; 629228753Smm 630228753Smm shar = (struct shar *)a->format_data; 631228753Smm if (shar == NULL) 632228753Smm return (ARCHIVE_OK); 633228753Smm 634228753Smm archive_entry_free(shar->entry); 635228753Smm free(shar->last_dir); 636228753Smm archive_string_free(&(shar->work)); 637228753Smm archive_string_free(&(shar->quoted_name)); 638228753Smm free(shar); 639228753Smm a->format_data = NULL; 640228753Smm return (ARCHIVE_OK); 641228753Smm} 642