1/*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * Copyright (c) 2008 Joerg Sonnenberger 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 * 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 29#ifdef HAVE_ERRNO_H 30#include <errno.h> 31#endif 32#include <stdio.h> 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 46struct shar { 47 int dump; 48 int end_of_line; 49 struct archive_entry *entry; 50 int has_data; 51 char *last_dir; 52 53 /* Line buffer for uuencoded dump format */ 54 char outbuff[45]; 55 size_t outpos; 56 57 int wrote_header; 58 struct archive_string work; 59 struct archive_string quoted_name; 60}; 61 62static int archive_write_shar_close(struct archive_write *); 63static int archive_write_shar_free(struct archive_write *); 64static int archive_write_shar_header(struct archive_write *, 65 struct archive_entry *); 66static ssize_t archive_write_shar_data_sed(struct archive_write *, 67 const void * buff, size_t); 68static ssize_t archive_write_shar_data_uuencode(struct archive_write *, 69 const void * buff, size_t); 70static int archive_write_shar_finish_entry(struct archive_write *); 71 72/* 73 * Copy the given string to the buffer, quoting all shell meta characters 74 * found. 75 */ 76static void 77shar_quote(struct archive_string *buf, const char *str, int in_shell) 78{ 79 static const char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; 80 size_t len; 81 82 while (*str != '\0') { 83 if ((len = strcspn(str, meta)) != 0) { 84 archive_strncat(buf, str, len); 85 str += len; 86 } else if (*str == '\n') { 87 if (in_shell) 88 archive_strcat(buf, "\"\n\""); 89 else 90 archive_strcat(buf, "\\n"); 91 ++str; 92 } else { 93 archive_strappend_char(buf, '\\'); 94 archive_strappend_char(buf, *str); 95 ++str; 96 } 97 } 98} 99 100/* 101 * Set output format to 'shar' format. 102 */ 103int 104archive_write_set_format_shar(struct archive *_a) 105{ 106 struct archive_write *a = (struct archive_write *)_a; 107 struct shar *shar; 108 109 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 110 ARCHIVE_STATE_NEW, "archive_write_set_format_shar"); 111 112 /* If someone else was already registered, unregister them. */ 113 if (a->format_free != NULL) 114 (a->format_free)(a); 115 116 shar = (struct shar *)calloc(1, sizeof(*shar)); 117 if (shar == NULL) { 118 archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data"); 119 return (ARCHIVE_FATAL); 120 } 121 archive_string_init(&shar->work); 122 archive_string_init(&shar->quoted_name); 123 a->format_data = shar; 124 a->format_name = "shar"; 125 a->format_write_header = archive_write_shar_header; 126 a->format_close = archive_write_shar_close; 127 a->format_free = archive_write_shar_free; 128 a->format_write_data = archive_write_shar_data_sed; 129 a->format_finish_entry = archive_write_shar_finish_entry; 130 a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE; 131 a->archive.archive_format_name = "shar"; 132 return (ARCHIVE_OK); 133} 134 135/* 136 * An alternate 'shar' that uses uudecode instead of 'sed' to encode 137 * file contents and can therefore be used to archive binary files. 138 * In addition, this variant also attempts to restore ownership, file modes, 139 * and other extended file information. 140 */ 141int 142archive_write_set_format_shar_dump(struct archive *_a) 143{ 144 struct archive_write *a = (struct archive_write *)_a; 145 struct shar *shar; 146 147 archive_write_set_format_shar(&a->archive); 148 shar = (struct shar *)a->format_data; 149 shar->dump = 1; 150 a->format_write_data = archive_write_shar_data_uuencode; 151 a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP; 152 a->archive.archive_format_name = "shar dump"; 153 return (ARCHIVE_OK); 154} 155 156static int 157archive_write_shar_header(struct archive_write *a, struct archive_entry *entry) 158{ 159 const char *linkname; 160 const char *name; 161 char *p, *pp; 162 struct shar *shar; 163 164 shar = (struct shar *)a->format_data; 165 if (!shar->wrote_header) { 166 archive_strcat(&shar->work, "#!/bin/sh\n"); 167 archive_strcat(&shar->work, "# This is a shell archive\n"); 168 shar->wrote_header = 1; 169 } 170 171 /* Save the entry for the closing. */ 172 archive_entry_free(shar->entry); 173 shar->entry = archive_entry_clone(entry); 174 name = archive_entry_pathname(entry); 175 176 /* Handle some preparatory issues. */ 177 switch(archive_entry_filetype(entry)) { 178 case AE_IFREG: 179 /* Only regular files have non-zero size. */ 180 break; 181 case AE_IFDIR: 182 archive_entry_set_size(entry, 0); 183 /* Don't bother trying to recreate '.' */ 184 if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0) 185 return (ARCHIVE_OK); 186 break; 187 case AE_IFIFO: 188 case AE_IFCHR: 189 case AE_IFBLK: 190 /* All other file types have zero size in the archive. */ 191 archive_entry_set_size(entry, 0); 192 break; 193 default: 194 archive_entry_set_size(entry, 0); 195 if (archive_entry_hardlink(entry) == NULL && 196 archive_entry_symlink(entry) == NULL) { 197 __archive_write_entry_filetype_unsupported( 198 &a->archive, entry, "shar"); 199 return (ARCHIVE_WARN); 200 } 201 } 202 203 archive_string_empty(&shar->quoted_name); 204 shar_quote(&shar->quoted_name, name, 1); 205 206 /* Stock preparation for all file types. */ 207 archive_string_sprintf(&shar->work, "echo x %s\n", shar->quoted_name.s); 208 209 if (archive_entry_filetype(entry) != AE_IFDIR) { 210 /* Try to create the dir. */ 211 p = strdup(name); 212 pp = strrchr(p, '/'); 213 /* If there is a / character, try to create the dir. */ 214 if (pp != NULL) { 215 *pp = '\0'; 216 217 /* Try to avoid a lot of redundant mkdir commands. */ 218 if (strcmp(p, ".") == 0) { 219 /* Don't try to "mkdir ." */ 220 free(p); 221 } else if (shar->last_dir == NULL) { 222 archive_strcat(&shar->work, "mkdir -p "); 223 shar_quote(&shar->work, p, 1); 224 archive_strcat(&shar->work, 225 " > /dev/null 2>&1\n"); 226 shar->last_dir = p; 227 } else if (strcmp(p, shar->last_dir) == 0) { 228 /* We've already created this exact dir. */ 229 free(p); 230 } else if (strlen(p) < strlen(shar->last_dir) && 231 strncmp(p, shar->last_dir, strlen(p)) == 0) { 232 /* We've already created a subdir. */ 233 free(p); 234 } else { 235 archive_strcat(&shar->work, "mkdir -p "); 236 shar_quote(&shar->work, p, 1); 237 archive_strcat(&shar->work, 238 " > /dev/null 2>&1\n"); 239 shar->last_dir = p; 240 } 241 } else { 242 free(p); 243 } 244 } 245 246 /* Handle file-type specific issues. */ 247 shar->has_data = 0; 248 if ((linkname = archive_entry_hardlink(entry)) != NULL) { 249 archive_strcat(&shar->work, "ln -f "); 250 shar_quote(&shar->work, linkname, 1); 251 archive_string_sprintf(&shar->work, " %s\n", 252 shar->quoted_name.s); 253 } else if ((linkname = archive_entry_symlink(entry)) != NULL) { 254 archive_strcat(&shar->work, "ln -fs "); 255 shar_quote(&shar->work, linkname, 1); 256 archive_string_sprintf(&shar->work, " %s\n", 257 shar->quoted_name.s); 258 } else { 259 switch(archive_entry_filetype(entry)) { 260 case AE_IFREG: 261 if (archive_entry_size(entry) == 0) { 262 /* More portable than "touch." */ 263 archive_string_sprintf(&shar->work, 264 "test -e \"%s\" || :> \"%s\"\n", 265 shar->quoted_name.s, shar->quoted_name.s); 266 } else { 267 if (shar->dump) { 268 unsigned int mode = archive_entry_mode(entry) & 0777; 269 archive_string_sprintf(&shar->work, 270 "uudecode -p > %s << 'SHAR_END'\n", 271 shar->quoted_name.s); 272 archive_string_sprintf(&shar->work, 273 "begin %o ", mode); 274 shar_quote(&shar->work, name, 0); 275 archive_strcat(&shar->work, "\n"); 276 } else { 277 archive_string_sprintf(&shar->work, 278 "sed 's/^X//' > %s << 'SHAR_END'\n", 279 shar->quoted_name.s); 280 } 281 shar->has_data = 1; 282 shar->end_of_line = 1; 283 shar->outpos = 0; 284 } 285 break; 286 case AE_IFDIR: 287 archive_string_sprintf(&shar->work, 288 "mkdir -p %s > /dev/null 2>&1\n", 289 shar->quoted_name.s); 290 /* Record that we just created this directory. */ 291 free(shar->last_dir); 292 293 shar->last_dir = strdup(name); 294 /* Trim a trailing '/'. */ 295 pp = strrchr(shar->last_dir, '/'); 296 if (pp != NULL && pp[1] == '\0') 297 *pp = '\0'; 298 /* 299 * TODO: Put dir name/mode on a list to be fixed 300 * up at end of archive. 301 */ 302 break; 303 case AE_IFIFO: 304 archive_string_sprintf(&shar->work, 305 "mkfifo %s\n", shar->quoted_name.s); 306 break; 307 case AE_IFCHR: 308 archive_string_sprintf(&shar->work, 309 "mknod %s c %ju %ju\n", shar->quoted_name.s, 310 (uintmax_t)archive_entry_rdevmajor(entry), 311 (uintmax_t)archive_entry_rdevminor(entry)); 312 break; 313 case AE_IFBLK: 314 archive_string_sprintf(&shar->work, 315 "mknod %s b %ju %ju\n", shar->quoted_name.s, 316 (uintmax_t)archive_entry_rdevmajor(entry), 317 (uintmax_t)archive_entry_rdevminor(entry)); 318 break; 319 default: 320 return (ARCHIVE_WARN); 321 } 322 } 323 324 return (ARCHIVE_OK); 325} 326 327static ssize_t 328archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n) 329{ 330 static const size_t ensured = 65533; 331 struct shar *shar; 332 const char *src; 333 char *buf, *buf_end; 334 int ret; 335 size_t written = n; 336 337 shar = (struct shar *)a->format_data; 338 if (!shar->has_data || n == 0) 339 return (0); 340 341 src = (const char *)buff; 342 343 /* 344 * ensure is the number of bytes in buffer before expanding the 345 * current character. Each operation writes the current character 346 * and optionally the start-of-new-line marker. This can happen 347 * twice before entering the loop, so make sure three additional 348 * bytes can be written. 349 */ 350 if (archive_string_ensure(&shar->work, ensured + 3) == NULL) { 351 archive_set_error(&a->archive, ENOMEM, "Out of memory"); 352 return (ARCHIVE_FATAL); 353 } 354 355 if (shar->work.length > ensured) { 356 ret = __archive_write_output(a, shar->work.s, 357 shar->work.length); 358 if (ret != ARCHIVE_OK) 359 return (ARCHIVE_FATAL); 360 archive_string_empty(&shar->work); 361 } 362 buf = shar->work.s + shar->work.length; 363 buf_end = shar->work.s + ensured; 364 365 if (shar->end_of_line) { 366 *buf++ = 'X'; 367 shar->end_of_line = 0; 368 } 369 370 while (n-- != 0) { 371 if ((*buf++ = *src++) == '\n') { 372 if (n == 0) 373 shar->end_of_line = 1; 374 else 375 *buf++ = 'X'; 376 } 377 378 if (buf >= buf_end) { 379 shar->work.length = buf - shar->work.s; 380 ret = __archive_write_output(a, shar->work.s, 381 shar->work.length); 382 if (ret != ARCHIVE_OK) 383 return (ARCHIVE_FATAL); 384 archive_string_empty(&shar->work); 385 buf = shar->work.s; 386 } 387 } 388 389 shar->work.length = buf - shar->work.s; 390 391 return (written); 392} 393 394#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`') 395 396static void 397uuencode_group(const char _in[3], char out[4]) 398{ 399 const unsigned char *in = (const unsigned char *)_in; 400 int t; 401 402 t = (in[0] << 16) | (in[1] << 8) | in[2]; 403 out[0] = UUENC( 0x3f & (t >> 18) ); 404 out[1] = UUENC( 0x3f & (t >> 12) ); 405 out[2] = UUENC( 0x3f & (t >> 6) ); 406 out[3] = UUENC( 0x3f & t ); 407} 408 409static int 410_uuencode_line(struct archive_write *a, struct shar *shar, const char *inbuf, size_t len) 411{ 412 char *buf; 413 size_t alloc_len; 414 415 /* len <= 45 -> expanded to 60 + len byte + new line */ 416 alloc_len = shar->work.length + 62; 417 if (archive_string_ensure(&shar->work, alloc_len) == NULL) { 418 archive_set_error(&a->archive, ENOMEM, "Out of memory"); 419 return (ARCHIVE_FATAL); 420 } 421 422 buf = shar->work.s + shar->work.length; 423 *buf++ = UUENC(len); 424 while (len >= 3) { 425 uuencode_group(inbuf, buf); 426 len -= 3; 427 inbuf += 3; 428 buf += 4; 429 } 430 if (len != 0) { 431 char tmp_buf[3]; 432 tmp_buf[0] = inbuf[0]; 433 if (len == 1) 434 tmp_buf[1] = '\0'; 435 else 436 tmp_buf[1] = inbuf[1]; 437 tmp_buf[2] = '\0'; 438 uuencode_group(tmp_buf, buf); 439 buf += 4; 440 } 441 *buf++ = '\n'; 442 if ((buf - shar->work.s) > (ptrdiff_t)(shar->work.length + 62)) { 443 archive_set_error(&a->archive, 444 ARCHIVE_ERRNO_MISC, "Buffer overflow"); 445 return (ARCHIVE_FATAL); 446 } 447 shar->work.length = buf - shar->work.s; 448 return (ARCHIVE_OK); 449} 450 451#define uuencode_line(__a, __shar, __inbuf, __len) \ 452 do { \ 453 int r = _uuencode_line(__a, __shar, __inbuf, __len); \ 454 if (r != ARCHIVE_OK) \ 455 return (ARCHIVE_FATAL); \ 456 } while (0) 457 458static ssize_t 459archive_write_shar_data_uuencode(struct archive_write *a, const void *buff, 460 size_t length) 461{ 462 struct shar *shar; 463 const char *src; 464 size_t n; 465 int ret; 466 467 shar = (struct shar *)a->format_data; 468 if (!shar->has_data) 469 return (ARCHIVE_OK); 470 src = (const char *)buff; 471 472 if (shar->outpos != 0) { 473 n = 45 - shar->outpos; 474 if (n > length) 475 n = length; 476 memcpy(shar->outbuff + shar->outpos, src, n); 477 if (shar->outpos + n < 45) { 478 shar->outpos += n; 479 return length; 480 } 481 uuencode_line(a, shar, shar->outbuff, 45); 482 src += n; 483 n = length - n; 484 } else { 485 n = length; 486 } 487 488 while (n >= 45) { 489 uuencode_line(a, shar, src, 45); 490 src += 45; 491 n -= 45; 492 493 if (shar->work.length < 65536) 494 continue; 495 ret = __archive_write_output(a, shar->work.s, 496 shar->work.length); 497 if (ret != ARCHIVE_OK) 498 return (ARCHIVE_FATAL); 499 archive_string_empty(&shar->work); 500 } 501 if (n != 0) { 502 memcpy(shar->outbuff, src, n); 503 shar->outpos = n; 504 } 505 return (length); 506} 507 508static int 509archive_write_shar_finish_entry(struct archive_write *a) 510{ 511 const char *g, *p, *u; 512 struct shar *shar; 513 int ret; 514 515 shar = (struct shar *)a->format_data; 516 if (shar->entry == NULL) 517 return (0); 518 519 if (shar->dump) { 520 /* Finish uuencoded data. */ 521 if (shar->has_data) { 522 if (shar->outpos > 0) 523 uuencode_line(a, shar, shar->outbuff, 524 shar->outpos); 525 archive_strcat(&shar->work, "`\nend\n"); 526 archive_strcat(&shar->work, "SHAR_END\n"); 527 } 528 /* Restore file mode, owner, flags. */ 529 /* 530 * TODO: Don't immediately restore mode for 531 * directories; defer that to end of script. 532 */ 533 archive_string_sprintf(&shar->work, "chmod %o ", 534 (unsigned int)(archive_entry_mode(shar->entry) & 07777)); 535 shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1); 536 archive_strcat(&shar->work, "\n"); 537 538 u = archive_entry_uname(shar->entry); 539 g = archive_entry_gname(shar->entry); 540 if (u != NULL || g != NULL) { 541 archive_strcat(&shar->work, "chown "); 542 if (u != NULL) 543 shar_quote(&shar->work, u, 1); 544 if (g != NULL) { 545 archive_strcat(&shar->work, ":"); 546 shar_quote(&shar->work, g, 1); 547 } 548 archive_strcat(&shar->work, " "); 549 shar_quote(&shar->work, 550 archive_entry_pathname(shar->entry), 1); 551 archive_strcat(&shar->work, "\n"); 552 } 553 554 if ((p = archive_entry_fflags_text(shar->entry)) != NULL) { 555 archive_string_sprintf(&shar->work, "chflags %s ", p); 556 shar_quote(&shar->work, 557 archive_entry_pathname(shar->entry), 1); 558 archive_strcat(&shar->work, "\n"); 559 } 560 561 /* TODO: restore ACLs */ 562 563 } else { 564 if (shar->has_data) { 565 /* Finish sed-encoded data: ensure last line ends. */ 566 if (!shar->end_of_line) 567 archive_strappend_char(&shar->work, '\n'); 568 archive_strcat(&shar->work, "SHAR_END\n"); 569 } 570 } 571 572 archive_entry_free(shar->entry); 573 shar->entry = NULL; 574 575 if (shar->work.length < 65536) 576 return (ARCHIVE_OK); 577 578 ret = __archive_write_output(a, shar->work.s, shar->work.length); 579 if (ret != ARCHIVE_OK) 580 return (ARCHIVE_FATAL); 581 archive_string_empty(&shar->work); 582 583 return (ARCHIVE_OK); 584} 585 586static int 587archive_write_shar_close(struct archive_write *a) 588{ 589 struct shar *shar; 590 int ret; 591 592 /* 593 * TODO: Accumulate list of directory names/modes and 594 * fix them all up at end-of-archive. 595 */ 596 597 shar = (struct shar *)a->format_data; 598 599 /* 600 * Only write the end-of-archive markers if the archive was 601 * actually started. This avoids problems if someone sets 602 * shar format, then sets another format (which would invoke 603 * shar_finish to free the format-specific data). 604 */ 605 if (shar->wrote_header == 0) 606 return (ARCHIVE_OK); 607 608 archive_strcat(&shar->work, "exit\n"); 609 610 ret = __archive_write_output(a, shar->work.s, shar->work.length); 611 if (ret != ARCHIVE_OK) 612 return (ARCHIVE_FATAL); 613 614 /* Shar output is never padded. */ 615 archive_write_set_bytes_in_last_block(&a->archive, 1); 616 /* 617 * TODO: shar should also suppress padding of 618 * uncompressed data within gzip/bzip2 streams. 619 */ 620 621 return (ARCHIVE_OK); 622} 623 624static int 625archive_write_shar_free(struct archive_write *a) 626{ 627 struct shar *shar; 628 629 shar = (struct shar *)a->format_data; 630 if (shar == NULL) 631 return (ARCHIVE_OK); 632 633 archive_entry_free(shar->entry); 634 free(shar->last_dir); 635 archive_string_free(&(shar->work)); 636 archive_string_free(&(shar->quoted_name)); 637 free(shar); 638 a->format_data = NULL; 639 return (ARCHIVE_OK); 640} 641