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