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