/* * Set output format to 'shar' format. */ int archive_write_set_format_shar(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; struct shar *shar; archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_format_shar"); /* If someone else was already registered, unregister them. */ if (a->format_free != NULL) (a->format_free)(a); shar = (struct shar *)calloc(1, sizeof(*shar)); if (shar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data"); return (ARCHIVE_FATAL); } archive_string_init(&shar->work); archive_string_init(&shar->quoted_name); a->format_data = shar; a->format_name = "shar"; a->format_write_header = archive_write_shar_header; a->format_close = archive_write_shar_close; a->format_free = archive_write_shar_free; a->format_write_data = archive_write_shar_data_sed; a->format_finish_entry = archive_write_shar_finish_entry; a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE; a->archive.archive_format_name = "shar"; return (ARCHIVE_OK); }
static void test_archive_string_copy(void) { struct archive_string s, t, u, v; archive_string_init(&s); assertExactString(0, 0, NULL, s); archive_string_init(&t); assertExactString(0, 0, NULL, t); archive_string_init(&u); assertExactString(0, 0, NULL, u); archive_string_init(&v); assertExactString(0, 0, NULL, v); /* null target, null source */ archive_string_copy(&t, &s); assertExactString(0, 0, NULL, s); assertExactString(0, EXTENT, "", t); /* null target, empty source */ archive_string_copy(&u, &t); assertExactString(0, EXTENT, "", t); assertExactString(0, EXTENT, "", u); /* empty target, empty source */ archive_string_copy(&u, &t); assertExactString(0, EXTENT, "", t); assertExactString(0, EXTENT, "", u); /* null target, non-empty source */ assert(NULL != archive_strcpy(&s, "snafubar")); assertExactString(8, EXTENT, "snafubar", s); archive_string_copy(&v, &s); assertExactString(8, EXTENT, "snafubar", s); assertExactString(8, EXTENT, "snafubar", v); /* empty target, non-empty source */ assertExactString(0, EXTENT, "", t); archive_string_copy(&t, &s); assertExactString(8, EXTENT, "snafubar", s); assertExactString(8, EXTENT, "snafubar", t); /* non-empty target, non-empty source */ assert(NULL != archive_strcpy(&s, "fubar")); assertExactString(5, EXTENT, "fubar", s); archive_string_copy(&t, &s); assertExactString(5, EXTENT, "fubar", s); assertExactString(5, EXTENT, "fubar", t); }
int __archive_mktemp(const char *tmpdir) { struct archive_string temp_name; int fd = -1; archive_string_init(&temp_name); if (tmpdir == NULL) { if (get_tempdir(&temp_name) != ARCHIVE_OK) goto exit_tmpfile; } else { archive_strcpy(&temp_name, tmpdir); if (temp_name.s[temp_name.length-1] != '/') archive_strappend_char(&temp_name, '/'); } archive_strcat(&temp_name, "libarchive_XXXXXX"); fd = mkstemp(temp_name.s); if (fd < 0) goto exit_tmpfile; __archive_ensure_cloexec_flag(fd); unlink(temp_name.s); exit_tmpfile: archive_string_free(&temp_name); return (fd); }
const char * archive_version_details(void) { static struct archive_string str; static int init = 0; if (!init) { archive_string_init(&str); archive_strcat(&str, ARCHIVE_VERSION_STRING); #ifdef HAVE_ZLIB_H archive_strcat(&str, " zlib/"); archive_strcat(&str, ZLIB_VERSION); #endif #ifdef HAVE_LZMA_H archive_strcat(&str, " liblzma/"); archive_strcat(&str, LZMA_VERSION_STRING); #endif #ifdef HAVE_BZLIB_H { const char *p = BZ2_bzlibVersion(); const char *sep = strchr(p, ','); if (sep == NULL) sep = p + strlen(p); archive_strcat(&str, " bz2lib/"); archive_strncat(&str, p, sep - p); } #endif #if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) archive_string_sprintf(&str, " liblz4/%d.%d.%d", LZ4_VERSION_MAJOR, LZ4_VERSION_MINOR, LZ4_VERSION_RELEASE); #endif } return str.s; }
int __archive_mktemp(const char *tmpdir) { static const char num[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; struct archive_string temp_name; struct stat st; int fd; char *tp, *ep; fd = -1; archive_string_init(&temp_name); if (tmpdir == NULL) { if (get_tempdir(&temp_name) != ARCHIVE_OK) goto exit_tmpfile; } else archive_strcpy(&temp_name, tmpdir); if (temp_name.s[temp_name.length-1] == '/') { temp_name.s[temp_name.length-1] = '\0'; temp_name.length --; } if (stat(temp_name.s, &st) < 0) goto exit_tmpfile; if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; goto exit_tmpfile; } archive_strcat(&temp_name, "/libarchive_"); tp = temp_name.s + archive_strlen(&temp_name); archive_strcat(&temp_name, "XXXXXXXXXX"); ep = temp_name.s + archive_strlen(&temp_name); do { char *p; p = tp; archive_random(p, ep - p); while (p < ep) { int d = *((unsigned char *)p) % sizeof(num); *p++ = num[d]; } fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600); } while (fd < 0 && errno == EEXIST); if (fd < 0) goto exit_tmpfile; __archive_ensure_cloexec_flag(fd); unlink(temp_name.s); exit_tmpfile: archive_string_free(&temp_name); return (fd); }
static void expose_parent_dirs(struct zip *zip, const char *name, size_t name_length) { struct archive_string str; struct zip_entry *dir; char *s; archive_string_init(&str); archive_strncpy(&str, name, name_length); for (;;) { s = strrchr(str.s, '/'); if (s == NULL) break; *s = '\0'; /* Transfer the parent directory from zip->tree_rsrc RB * tree to zip->tree RB tree to expose. */ dir = (struct zip_entry *) __archive_rb_tree_find_node(&zip->tree_rsrc, str.s); if (dir == NULL) break; __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node); archive_string_free(&dir->rsrcname); __archive_rb_tree_insert_node(&zip->tree, &dir->node); } archive_string_free(&str); }
static int set_timefilter_date_w(struct archive_match *a, int timetype, const wchar_t *datestr) { struct archive_string as; time_t t; if (datestr == NULL || *datestr == L'\0') { archive_set_error(&(a->archive), EINVAL, "date is empty"); return (ARCHIVE_FAILED); } archive_string_init(&as); if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) { archive_string_free(&as); if (errno == ENOMEM) return (error_nomem(a)); archive_set_error(&(a->archive), -1, "Failed to convert WCS to MBS"); return (ARCHIVE_FAILED); } t = get_date(a->now, as.s); archive_string_free(&as); if (t == (time_t)-1) { archive_set_error(&(a->archive), EINVAL, "invalid date string"); return (ARCHIVE_FAILED); } return set_timefilter(a, timetype, t, 0, t, 0); }
static int set_timefilter_pathname_wcs(struct archive_match *a, int timetype, const wchar_t *path) { struct archive_string as; int r; if (path == NULL || *path == L'\0') { archive_set_error(&(a->archive), EINVAL, "pathname is empty"); return (ARCHIVE_FAILED); } /* Convert WCS filename to MBS filename. */ archive_string_init(&as); if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) { archive_string_free(&as); if (errno == ENOMEM) return (error_nomem(a)); archive_set_error(&(a->archive), -1, "Failed to convert WCS to MBS"); return (ARCHIVE_FAILED); } r = set_timefilter_pathname_mbs(a, timetype, as.s); archive_string_free(&as); return (r); }
int archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, size_t block_size) { struct read_file_data *mine = (struct read_file_data *)calloc(1, sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t)); if (!mine) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } mine->fd = -1; mine->block_size = block_size; if (wfilename == NULL || wfilename[0] == L'\0') { mine->filename_type = FNT_STDIN; } else { #if defined(_WIN32) && !defined(__CYGWIN__) mine->filename_type = FNT_WCS; wcscpy(mine->filename.w, wfilename); #else /* * POSIX system does not support a wchar_t interface for * open() system call, so we have to translate a whcar_t * filename to multi-byte one and use it. */ struct archive_string fn; archive_string_init(&fn); if (archive_string_append_from_wcs(&fn, wfilename, wcslen(wfilename)) != 0) { if (errno == ENOMEM) archive_set_error(a, errno, "Can't allocate memory"); else archive_set_error(a, EINVAL, "Failed to convert a wide-character" " filename to a multi-byte filename"); archive_string_free(&fn); free(mine); return (ARCHIVE_FATAL); } mine->filename_type = FNT_MBS; strcpy(mine->filename.m, fn.s); archive_string_free(&fn); #endif } if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) return (ARCHIVE_FATAL); archive_read_set_open_callback(a, file_open); archive_read_set_read_callback(a, file_read); archive_read_set_skip_callback(a, file_skip); archive_read_set_close_callback(a, file_close); archive_read_set_switch_callback(a, file_switch); archive_read_set_seek_callback(a, file_seek); return (archive_read_open1(a)); }
static void test_archive_string_sprintf(void) { struct archive_string s; #define S16 "0123456789abcdef" #define S32 S16 S16 #define S64 S32 S32 #define S128 S64 S64 const char *s32 = S32; const char *s33 = S32 "0"; const char *s64 = S64; const char *s65 = S64 "0"; const char *s128 = S128; const char *s129 = S128 "0"; #undef S16 #undef S32 #undef S64 #undef S128 archive_string_init(&s); assertExactString(0, 0, NULL, s); archive_string_sprintf(&s, "%s", ""); assertExactString(0, 2 * EXTENT, "", s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s32); assertExactString(32, 2 * EXTENT, s32, s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s33); assertExactString(33, 2 * EXTENT, s33, s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s64); assertExactString(64, 4 * EXTENT, s64, s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s65); assertExactString(65, 4 * EXTENT, s65, s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s128); assertExactString(128, 8 * EXTENT, s128, s); archive_string_empty(&s); archive_string_sprintf(&s, "%s", s129); assertExactString(129, 8 * EXTENT, s129, s); archive_string_empty(&s); archive_string_sprintf(&s, "%d", 1234567890); assertExactString(10, 8 * EXTENT, "1234567890", s); }
/* * Set up command line arguments. * Returns ARCHIVE_OK if everything okey. * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an * empty command line. * Returns ARCHIVE_FATAL if no memory. */ int __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd) { struct archive_string as; const char *p; ssize_t al; int r; archive_string_init(&as); /* Get first argument as a command path. */ al = get_argument(&as, cmd); if (al < 0) { r = ARCHIVE_FAILED;/* Invalid sequence. */ goto exit_function; } if (archive_strlen(&as) == 0) { r = ARCHIVE_FAILED;/* An empty command path. */ goto exit_function; } r = cmdline_set_path(data, as.s); if (r != ARCHIVE_OK) goto exit_function; p = strrchr(as.s, '/'); if (p == NULL) p = as.s; else p++; r = cmdline_add_arg(data, p); if (r != ARCHIVE_OK) goto exit_function; cmd += al; for (;;) { al = get_argument(&as, cmd); if (al < 0) { r = ARCHIVE_FAILED;/* Invalid sequence. */ goto exit_function; } if (al == 0) break; cmd += al; if (archive_strlen(&as) == 0 && *cmd == '\0') break; r = cmdline_add_arg(data, as.s); if (r != ARCHIVE_OK) goto exit_function; } r = ARCHIVE_OK; exit_function: archive_string_free(&as); return (r); }
static void test_archive_strappend_char(void) { struct archive_string s; archive_string_init(&s); assertExactString(0, 0, NULL, s); /* null target */ archive_strappend_char(&s, 'X'); assertExactString(1, EXTENT, "X", s); /* non-empty target */ archive_strappend_char(&s, 'Y'); assertExactString(2, EXTENT, "XY", s); }
static void test_archive_strcpy(void) { struct archive_string s; archive_string_init(&s); assertExactString(0, 0, NULL, s); /* null target */ assert(&s == archive_strcpy(&s, "snafu")); assertExactString(5, EXTENT, "snafu", s); /* dirty target */ assert(&s == archive_strcpy(&s, "foo")); assertExactString(3, EXTENT, "foo", s); /* dirty target, empty source */ assert(&s == archive_strcpy(&s, "")); assertExactString(0, EXTENT, "", s); }
static void test_archive_strncpy(void) { struct archive_string s; archive_string_init(&s); assertExactString(0, 0, NULL, s); /* perfect length */ assert(&s == archive_strncpy(&s, "fubar", 5)); assertExactString(5, EXTENT, "fubar", s); /* short read */ assert(&s == archive_strncpy(&s, "snafubar", 5)); assertExactString(5, EXTENT, "snafu", s); /* long read is ok too! */ assert(&s == archive_strncpy(&s, "snafu", 8)); assertExactString(5, EXTENT, "snafu", s); }
static int archive_write_lrzip_open(struct archive_write_filter *f) { struct write_lrzip *data = (struct write_lrzip *)f->data; struct archive_string as; int r; archive_string_init(&as); archive_strcpy(&as, "lrzip -q"); /* Specify compression type. */ switch (data->compression) { case lzma:/* default compression */ break; case bzip2: archive_strcat(&as, " -b"); break; case gzip: archive_strcat(&as, " -g"); break; case lzo: archive_strcat(&as, " -l"); break; case none: archive_strcat(&as, " -n"); break; case zpaq: archive_strcat(&as, " -z"); break; } /* Specify compression level. */ if (data->compression_level > 0) { archive_strcat(&as, " -L "); archive_strappend_char(&as, '0' + data->compression_level); } r = __archive_write_program_open(f, data->pdata, as.s); archive_string_free(&as); return (r); }
static int archive_compressor_bzip2_open(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; struct archive_string as; int r; archive_string_init(&as); archive_strcpy(&as, "bzip2"); /* Specify compression level. */ if (data->compression_level > 0) { archive_strcat(&as, " -"); archive_strappend_char(&as, '0' + data->compression_level); } f->write = archive_compressor_bzip2_write; r = __archive_write_program_open(f, data->pdata, as.s); archive_string_free(&as); return (r); }
int archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, size_t block_size) { enum fnt_e filename_type; if (wfilename == NULL || wfilename[0] == L'\0') { filename_type = FNT_STDIN; } else { #if defined(_WIN32) && !defined(__CYGWIN__) filename_type = FNT_WCS; #else /* * POSIX system does not support a wchar_t interface for * open() system call, so we have to translate a whcar_t * filename to multi-byte one and use it. */ struct archive_string fn; int r; archive_string_init(&fn); if (archive_string_append_from_wcs(&fn, wfilename, wcslen(wfilename)) != 0) { if (errno == ENOMEM) archive_set_error(a, errno, "Can't allocate memory"); else archive_set_error(a, EINVAL, "Failed to convert a wide-character" " filename to a multi-byte filename"); archive_string_free(&fn); return (ARCHIVE_FATAL); } r = file_open_filename(a, FNT_MBS, fn.s, block_size); archive_string_free(&fn); return (r); #endif } return (file_open_filename(a, filename_type, wfilename, block_size)); }
static void test_archive_string_ensure(void) { struct archive_string s; archive_string_init(&s); assertExactString(0, 0, NULL, s); /* single-extent allocation */ assert(&s == archive_string_ensure(&s, 5)); assertNonNULLString(0, EXTENT, s); /* what happens around extent boundaries? */ assert(&s == archive_string_ensure(&s, EXTENT - 1)); assertNonNULLString(0, EXTENT, s); assert(&s == archive_string_ensure(&s, EXTENT)); assertNonNULLString(0, EXTENT, s); assert(&s == archive_string_ensure(&s, EXTENT + 1)); assertNonNULLString(0, 2 * EXTENT, s); }
const char * archive_version_details(void) { static struct archive_string str; static int init = 0; const char *zlib = archive_zlib_version(); const char *liblzma = archive_liblzma_version(); const char *bzlib = archive_bzlib_version(); const char *liblz4 = archive_liblz4_version(); if (!init) { archive_string_init(&str); archive_strcat(&str, ARCHIVE_VERSION_STRING); if (zlib != NULL) { archive_strcat(&str, " zlib/"); archive_strcat(&str, zlib); } if (liblzma) { archive_strcat(&str, " liblzma/"); archive_strcat(&str, liblzma); } if (bzlib) { const char *p = bzlib; const char *sep = strchr(p, ','); if (sep == NULL) sep = p + strlen(p); archive_strcat(&str, " bz2lib/"); archive_strncat(&str, p, sep - p); } if (liblz4) { archive_strcat(&str, " liblz4/"); archive_strcat(&str, liblz4); } } return str.s; }
static void test_archive_strcat(void) { struct archive_string s; archive_string_init(&s); assertExactString(0, 0, NULL, s); /* null target, empty source */ assert(&s == archive_strcat(&s, "")); assertExactString(0, EXTENT, "", s); /* empty target, empty source */ assert(&s == archive_strcat(&s, "")); assertExactString(0, EXTENT, "", s); /* empty target, non-empty source */ assert(&s == archive_strcat(&s, "fubar")); assertExactString(5, EXTENT, "fubar", s); /* non-empty target, non-empty source */ assert(&s == archive_strcat(&s, "baz")); assertExactString(8, EXTENT, "fubarbaz", s); }
/* * The Mac OS "copyfile()" API copies the extended metadata for a * file into a separate file in AppleDouble format (see RFC 1740). * * Mac OS tar and cpio implementations store this extended * metadata as a separate entry just before the regular entry * with a "._" prefix added to the filename. * * Note that this is currently done unconditionally; the tar program has * an option to discard this information before the archive is written. * * TODO: If there's a failure, report it and return ARCHIVE_WARN. */ static int setup_mac_metadata(struct archive_read_disk *a, struct archive_entry *entry, int *fd) { int tempfd = -1; int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR; struct stat copyfile_stat; int ret = ARCHIVE_OK; void *buff = NULL; int have_attrs; const char *name, *tempdir; struct archive_string tempfile; (void)fd; /* UNUSED */ name = archive_entry_sourcepath(entry); if (name == NULL) name = archive_entry_pathname(entry); if (name == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Can't open file to read extended attributes: No name"); return (ARCHIVE_WARN); } if (a->tree != NULL) { if (a->tree_enter_working_dir(a->tree) != 0) { archive_set_error(&a->archive, errno, "Couldn't change dir"); return (ARCHIVE_FAILED); } } /* Short-circuit if there's nothing to do. */ have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); if (have_attrs == -1) { archive_set_error(&a->archive, errno, "Could not check extended attributes"); return (ARCHIVE_WARN); } if (have_attrs == 0) return (ARCHIVE_OK); tempdir = NULL; if (issetugid() == 0) tempdir = getenv("TMPDIR"); if (tempdir == NULL) tempdir = _PATH_TMP; archive_string_init(&tempfile); archive_strcpy(&tempfile, tempdir); archive_strcat(&tempfile, "tar.md.XXXXXX"); tempfd = mkstemp(tempfile.s); if (tempfd < 0) { archive_set_error(&a->archive, errno, "Could not open extended attribute file"); ret = ARCHIVE_WARN; goto cleanup; } __archive_ensure_cloexec_flag(tempfd); /* XXX I wish copyfile() could pack directly to a memory * buffer; that would avoid the temp file here. For that * matter, it would be nice if fcopyfile() actually worked, * that would reduce the many open/close races here. */ if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) { archive_set_error(&a->archive, errno, "Could not pack extended attributes"); ret = ARCHIVE_WARN; goto cleanup; } if (fstat(tempfd, ©file_stat)) { archive_set_error(&a->archive, errno, "Could not check size of extended attributes"); ret = ARCHIVE_WARN; goto cleanup; } buff = malloc(copyfile_stat.st_size); if (buff == NULL) { archive_set_error(&a->archive, errno, "Could not allocate memory for extended attributes"); ret = ARCHIVE_WARN; goto cleanup; } if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) { archive_set_error(&a->archive, errno, "Could not read extended attributes into memory"); ret = ARCHIVE_WARN; goto cleanup; } archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size); cleanup: if (tempfd >= 0) { close(tempfd); unlink(tempfile.s); } archive_string_free(&tempfile); free(buff); return (ret); }
static int archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) { char buff[512]; int ret, ret2; struct v7tar *v7tar; struct archive_entry *entry_main; struct archive_string_conv *sconv; v7tar = (struct v7tar *)a->format_data; /* Setup default string conversion. */ if (v7tar->opt_sconv == NULL) { if (!v7tar->init_default_conversion) { v7tar->sconv_default = archive_string_default_conversion_for_write( &(a->archive)); v7tar->init_default_conversion = 1; } sconv = v7tar->sconv_default; } else sconv = v7tar->opt_sconv; /* Sanity check. */ if (archive_entry_pathname(entry) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Can't record entry in tar file without pathname"); return (ARCHIVE_FAILED); } /* Only regular files (not hardlinks) have data. */ if (archive_entry_hardlink(entry) != NULL || archive_entry_symlink(entry) != NULL || !(archive_entry_filetype(entry) == AE_IFREG)) archive_entry_set_size(entry, 0); if (AE_IFDIR == archive_entry_filetype(entry)) { const char *p; size_t path_length; /* * Ensure a trailing '/'. Modify the entry so * the client sees the change. */ #if defined(_WIN32) && !defined(__CYGWIN__) const wchar_t *wp; wp = archive_entry_pathname_w(entry); if (wp != NULL && wp[wcslen(wp) -1] != L'/') { struct archive_wstring ws; archive_string_init(&ws); path_length = wcslen(wp); if (archive_wstring_ensure(&ws, path_length + 2) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate v7tar data"); archive_wstring_free(&ws); return(ARCHIVE_FATAL); } /* Should we keep '\' ? */ if (wp[path_length -1] == L'\\') path_length--; archive_wstrncpy(&ws, wp, path_length); archive_wstrappend_wchar(&ws, L'/'); archive_entry_copy_pathname_w(entry, ws.s); archive_wstring_free(&ws); p = NULL; } else #endif p = archive_entry_pathname(entry); /* * On Windows, this is a backup operation just in * case getting WCS failed. On POSIX, this is a * normal operation. */ if (p != NULL && p[strlen(p) - 1] != '/') { struct archive_string as; archive_string_init(&as); path_length = strlen(p); if (archive_string_ensure(&as, path_length + 2) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate v7tar data"); archive_string_free(&as); return(ARCHIVE_FATAL); } #if defined(_WIN32) && !defined(__CYGWIN__) /* NOTE: This might break the pathname * if the current code page is CP932 and * the pathname includes a character '\' * as a part of its multibyte pathname. */ if (p[strlen(p) -1] == '\\') path_length--; else #endif archive_strncpy(&as, p, path_length); archive_strappend_char(&as, '/'); archive_entry_copy_pathname(entry, as.s); archive_string_free(&as); } } #if defined(_WIN32) && !defined(__CYGWIN__) /* Make sure the path separators in pahtname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate v7tar data"); return(ARCHIVE_FATAL); } if (entry != entry_main) entry = entry_main; else entry_main = NULL; #else entry_main = NULL; #endif ret = format_header_v7tar(a, buff, entry, 1, sconv); if (ret < ARCHIVE_WARN) { if (entry_main) archive_entry_free(entry_main); return (ret); } ret2 = __archive_write_output(a, buff, 512); if (ret2 < ARCHIVE_WARN) { if (entry_main) archive_entry_free(entry_main); return (ret2); } if (ret2 < ret) ret = ret2; v7tar->entry_bytes_remaining = archive_entry_size(entry); v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining); if (entry_main) archive_entry_free(entry_main); return (ret); }
static int add_pattern_from_file(struct archive_match *a, struct match_list *mlist, int mbs, const void *pathname, int nullSeparator) { struct archive *ar; struct archive_entry *ae; struct archive_string as; const void *buff; size_t size; int64_t offset; int r; ar = archive_read_new(); if (ar == NULL) { archive_set_error(&(a->archive), ENOMEM, "No memory"); return (ARCHIVE_FATAL); } r = archive_read_support_format_raw(ar); r = archive_read_support_format_empty(ar); if (r != ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); return (r); } if (mbs) r = archive_read_open_filename(ar, pathname, 512*20); else r = archive_read_open_filename_w(ar, pathname, 512*20); if (r != ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); return (r); } r = archive_read_next_header(ar, &ae); if (r != ARCHIVE_OK) { archive_read_free(ar); if (r == ARCHIVE_EOF) { return (ARCHIVE_OK); } else { archive_copy_error(&(a->archive), ar); return (r); } } archive_string_init(&as); while ((r = archive_read_data_block(ar, &buff, &size, &offset)) == ARCHIVE_OK) { const char *b = (const char *)buff; while (size) { const char *s = (const char *)b; size_t length = 0; int found_separator = 0; while (length < size) { if (nullSeparator) { if (*b == '\0') { found_separator = 1; break; } } else { if (*b == 0x0d || *b == 0x0a) { found_separator = 1; break; } } b++; length++; } if (!found_separator) { archive_strncat(&as, s, length); /* Read next data block. */ break; } b++; size -= length + 1; archive_strncat(&as, s, length); /* If the line is not empty, add the pattern. */ if (archive_strlen(&as) > 0) { /* Add pattern. */ r = add_pattern_mbs(a, mlist, as.s); if (r != ARCHIVE_OK) { archive_read_free(ar); archive_string_free(&as); return (r); } archive_string_empty(&as); } } } /* If an error occurred, report it immediately. */ if (r < ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); archive_string_free(&as); return (r); } /* If the line is not empty, add the pattern. */ if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { /* Add pattern. */ r = add_pattern_mbs(a, mlist, as.s); if (r != ARCHIVE_OK) { archive_read_free(ar); archive_string_free(&as); return (r); } } archive_read_free(ar); archive_string_free(&as); return (ARCHIVE_OK); }
/* * Write /set keyword. It means set global datas. * [directory-only mode] * - It is only once to write /set keyword. It is using values of the * first entry. * [normal mode] * - Write /set keyword. It is using values of the first entry whose * filetype is a regular file. * - When a parent directory of the entry whose filetype is the regular * file is changed, check the global datas and write it again if its * values are different from the entry's. */ static void set_global(struct mtree_writer *mtree, struct archive_entry *entry) { struct archive_string setstr; struct archive_string unsetstr; const char *name; int keys, oldkeys, effkeys; mode_t set_type = 0; switch (archive_entry_filetype(entry)) { case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR: case AE_IFBLK: case AE_IFIFO: break; case AE_IFDIR: if (mtree->dironly) set_type = AE_IFDIR; break; case AE_IFREG: default: /* Handle unknown file types as regular files. */ if (!mtree->dironly) set_type = AE_IFREG; break; } if (set_type == 0) return; if (mtree->set.processed && !parent_dir_changed(&mtree->set.parent, entry)) return; /* At first, save a parent directory of the entry for following * entries. */ if (!mtree->set.processed && set_type == AE_IFREG) parent_dir_changed(&mtree->set.parent, entry); archive_string_init(&setstr); archive_string_init(&unsetstr); keys = mtree->keys & (F_FLAGS | F_GID | F_GNAME | F_NLINK | F_MODE | F_TYPE | F_UID | F_UNAME); oldkeys = mtree->set.keys; effkeys = keys; if (mtree->set.processed) { /* * Check the global datas for whether it needs updating. */ effkeys &= ~F_TYPE; if ((oldkeys & (F_UNAME | F_UID)) != 0 && mtree->set.uid == archive_entry_uid(entry)) effkeys &= ~(F_UNAME | F_UID); if ((oldkeys & (F_GNAME | F_GID)) != 0 && mtree->set.gid == archive_entry_gid(entry)) effkeys &= ~(F_GNAME | F_GID); if ((oldkeys & F_MODE) != 0 && mtree->set.mode == (archive_entry_mode(entry) & 07777)) effkeys &= ~F_MODE; if ((oldkeys & F_FLAGS) != 0) { unsigned long fflags_set; unsigned long fflags_clear; archive_entry_fflags(entry, &fflags_set, &fflags_clear); if (fflags_set == mtree->set.fflags_set && fflags_clear == mtree->set.fflags_clear) effkeys &= ~F_FLAGS; } } if ((keys & effkeys & F_TYPE) != 0) { mtree->set.type = set_type; if (set_type == AE_IFDIR) archive_strcat(&setstr, " type=dir"); else archive_strcat(&setstr, " type=file"); } if ((keys & effkeys & F_UNAME) != 0) { if ((name = archive_entry_uname(entry)) != NULL) { archive_strcat(&setstr, " uname="); mtree_quote(&setstr, name); } else if ((oldkeys & F_UNAME) != 0) archive_strcat(&unsetstr, " uname"); else keys &= ~F_UNAME; } if ((keys & effkeys & F_UID) != 0) { mtree->set.uid = archive_entry_uid(entry); archive_string_sprintf(&setstr, " uid=%jd", (intmax_t)mtree->set.uid); } if ((keys & effkeys & F_GNAME) != 0) { if ((name = archive_entry_gname(entry)) != NULL) { archive_strcat(&setstr, " gname="); mtree_quote(&setstr, name); } else if ((oldkeys & F_GNAME) != 0) archive_strcat(&unsetstr, " gname"); else keys &= ~F_GNAME; } if ((keys & effkeys & F_GID) != 0) { mtree->set.gid = archive_entry_gid(entry); archive_string_sprintf(&setstr, " gid=%jd", (intmax_t)mtree->set.gid); } if ((keys & effkeys & F_MODE) != 0) { mtree->set.mode = archive_entry_mode(entry) & 07777; archive_string_sprintf(&setstr, " mode=%o", mtree->set.mode); } if ((keys & effkeys & F_FLAGS) != 0) { if ((name = archive_entry_fflags_text(entry)) != NULL) { archive_strcat(&setstr, " flags="); mtree_quote(&setstr, name); archive_entry_fflags(entry, &mtree->set.fflags_set, &mtree->set.fflags_clear); } else if ((oldkeys & F_FLAGS) != 0) archive_strcat(&unsetstr, " flags"); else keys &= ~F_FLAGS; } if (unsetstr.length > 0) archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s); archive_string_free(&unsetstr); if (setstr.length > 0) archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s); archive_string_free(&setstr); mtree->set.keys = keys; mtree->set.processed = 1; /* On directory-only mode, it is only once to write /set keyword. */ if (mtree->dironly) mtree->set.output = 0; }
static int archive_write_gnutar_header(struct archive_write *a, struct archive_entry *entry) { char buff[512]; int r, ret, ret2 = ARCHIVE_OK; int tartype; struct gnutar *gnutar; struct archive_string_conv *sconv; struct archive_entry *entry_main; gnutar = (struct gnutar *)a->format_data; /* Setup default string conversion. */ if (gnutar->opt_sconv == NULL) { if (!gnutar->init_default_conversion) { gnutar->sconv_default = archive_string_default_conversion_for_write( &(a->archive)); gnutar->init_default_conversion = 1; } sconv = gnutar->sconv_default; } else sconv = gnutar->opt_sconv; /* Only regular files (not hardlinks) have data. */ if (archive_entry_hardlink(entry) != NULL || archive_entry_symlink(entry) != NULL || !(archive_entry_filetype(entry) == AE_IFREG)) archive_entry_set_size(entry, 0); if (AE_IFDIR == archive_entry_filetype(entry)) { const char *p; size_t path_length; /* * Ensure a trailing '/'. Modify the entry so * the client sees the change. */ #if defined(_WIN32) && !defined(__CYGWIN__) const wchar_t *wp; wp = archive_entry_pathname_w(entry); if (wp != NULL && wp[wcslen(wp) -1] != L'/') { struct archive_wstring ws; archive_string_init(&ws); path_length = wcslen(wp); if (archive_wstring_ensure(&ws, path_length + 2) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data"); archive_wstring_free(&ws); return(ARCHIVE_FATAL); } /* Should we keep '\' ? */ if (wp[path_length -1] == L'\\') path_length--; archive_wstrncpy(&ws, wp, path_length); archive_wstrappend_wchar(&ws, L'/'); archive_entry_copy_pathname_w(entry, ws.s); archive_wstring_free(&ws); p = NULL; } else #endif p = archive_entry_pathname(entry); /* * On Windows, this is a backup operation just in * case getting WCS failed. On POSIX, this is a * normal operation. */ if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') { struct archive_string as; archive_string_init(&as); path_length = strlen(p); if (archive_string_ensure(&as, path_length + 2) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data"); archive_string_free(&as); return(ARCHIVE_FATAL); } #if defined(_WIN32) && !defined(__CYGWIN__) /* NOTE: This might break the pathname * if the current code page is CP932 and * the pathname includes a character '\' * as a part of its multibyte pathname. */ if (p[strlen(p) -1] == '\\') path_length--; else #endif archive_strncpy(&as, p, path_length); archive_strappend_char(&as, '/'); archive_entry_copy_pathname(entry, as.s); archive_string_free(&as); } } #if defined(_WIN32) && !defined(__CYGWIN__) /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data"); return(ARCHIVE_FATAL); } if (entry != entry_main) entry = entry_main; else entry_main = NULL; #else entry_main = NULL; #endif r = archive_entry_pathname_l(entry, &(gnutar->pathname), &(gnutar->pathname_length), sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathame"); ret = ARCHIVE_FATAL; goto exit_write_header; } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate pathname '%s' to %s", archive_entry_pathname(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } r = archive_entry_uname_l(entry, &(gnutar->uname), &(gnutar->uname_length), sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Uname"); ret = ARCHIVE_FATAL; goto exit_write_header; } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate uname '%s' to %s", archive_entry_uname(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } r = archive_entry_gname_l(entry, &(gnutar->gname), &(gnutar->gname_length), sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Gname"); ret = ARCHIVE_FATAL; goto exit_write_header; } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate gname '%s' to %s", archive_entry_gname(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } /* If linkname is longer than 100 chars we need to add a 'K' header. */ r = archive_entry_hardlink_l(entry, &(gnutar->linkname), &(gnutar->linkname_length), sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); ret = ARCHIVE_FATAL; goto exit_write_header; } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate linkname '%s' to %s", archive_entry_hardlink(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } if (gnutar->linkname_length == 0) { r = archive_entry_symlink_l(entry, &(gnutar->linkname), &(gnutar->linkname_length), sconv); if (r != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); ret = ARCHIVE_FATAL; goto exit_write_header; } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate linkname '%s' to %s", archive_entry_hardlink(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } } if (gnutar->linkname_length > GNUTAR_linkname_size) { size_t length = gnutar->linkname_length + 1; struct archive_entry *temp = archive_entry_new2(&a->archive); /* Uname/gname here don't really matter since no one reads them; * these are the values that GNU tar happens to use on FreeBSD. */ archive_entry_set_uname(temp, "root"); archive_entry_set_gname(temp, "wheel"); archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_size(temp, length); ret = archive_format_gnutar_header(a, buff, temp, 'K'); archive_entry_free(temp); if (ret < ARCHIVE_WARN) goto exit_write_header; ret = __archive_write_output(a, buff, 512); if (ret < ARCHIVE_WARN) goto exit_write_header; /* Write name and trailing null byte. */ ret = __archive_write_output(a, gnutar->linkname, length); if (ret < ARCHIVE_WARN) goto exit_write_header; /* Pad to 512 bytes */ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); if (ret < ARCHIVE_WARN) goto exit_write_header; } /* If pathname is longer than 100 chars we need to add an 'L' header. */ if (gnutar->pathname_length > GNUTAR_name_size) { const char *pathname = gnutar->pathname; size_t length = gnutar->pathname_length + 1; struct archive_entry *temp = archive_entry_new2(&a->archive); /* Uname/gname here don't really matter since no one reads them; * these are the values that GNU tar happens to use on FreeBSD. */ archive_entry_set_uname(temp, "root"); archive_entry_set_gname(temp, "wheel"); archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_size(temp, length); ret = archive_format_gnutar_header(a, buff, temp, 'L'); archive_entry_free(temp); if (ret < ARCHIVE_WARN) goto exit_write_header; ret = __archive_write_output(a, buff, 512); if(ret < ARCHIVE_WARN) goto exit_write_header; /* Write pathname + trailing null byte. */ ret = __archive_write_output(a, pathname, length); if(ret < ARCHIVE_WARN) goto exit_write_header; /* Pad to multiple of 512 bytes. */ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); if (ret < ARCHIVE_WARN) goto exit_write_header; } if (archive_entry_hardlink(entry) != NULL) { tartype = '1'; } else switch (archive_entry_filetype(entry)) { case AE_IFREG: tartype = '0' ; break; case AE_IFLNK: tartype = '2' ; break; case AE_IFCHR: tartype = '3' ; break; case AE_IFBLK: tartype = '4' ; break; case AE_IFDIR: tartype = '5' ; break; case AE_IFIFO: tartype = '6' ; break; case AE_IFSOCK: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive socket"); ret = ARCHIVE_FAILED; goto exit_write_header; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive this (mode=0%lo)", (unsigned long)archive_entry_mode(entry)); ret = ARCHIVE_FAILED; goto exit_write_header; } ret = archive_format_gnutar_header(a, buff, entry, tartype); if (ret < ARCHIVE_WARN) goto exit_write_header; if (ret2 < ret) ret = ret2; ret2 = __archive_write_output(a, buff, 512); if (ret2 < ARCHIVE_WARN) { ret = ret2; goto exit_write_header; } if (ret2 < ret) ret = ret2; gnutar->entry_bytes_remaining = archive_entry_size(entry); gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining); exit_write_header: archive_entry_free(entry_main); return (ret); }
/* * Do not use Windows tmpfile() function. * It will make a temporary file under the root directory * and it'll cause permission error if a user who is * non-Administrator creates temporary files. * Also Windows version of mktemp family including _mktemp_s * are not secure. */ int __archive_mktemp(const char *tmpdir) { static const wchar_t *prefix = L"libarchive_"; static const wchar_t *suffix = L"XXXXXXXXXX"; static const wchar_t num[] = { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', L'u', L'v', L'w', L'x', L'y', L'z' }; HCRYPTPROV hProv; struct archive_wstring temp_name; wchar_t *ws; DWORD attr; wchar_t *xp, *ep; int fd; hProv = (HCRYPTPROV)NULL; fd = -1; ws = NULL; archive_string_init(&temp_name); /* Get a temporary directory. */ if (tmpdir == NULL) { size_t l; wchar_t *tmp; l = GetTempPathW(0, NULL); if (l == 0) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } tmp = malloc(l*sizeof(wchar_t)); if (tmp == NULL) { errno = ENOMEM; goto exit_tmpfile; } GetTempPathW((DWORD)l, tmp); archive_wstrcpy(&temp_name, tmp); free(tmp); } else { if (archive_wstring_append_from_mbs(&temp_name, tmpdir, strlen(tmpdir)) < 0) goto exit_tmpfile; if (temp_name.s[temp_name.length-1] != L'/') archive_wstrappend_wchar(&temp_name, L'/'); } /* Check if temp_name is a directory. */ attr = GetFileAttributesW(temp_name.s); if (attr == (DWORD)-1) { if (GetLastError() != ERROR_FILE_NOT_FOUND) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } ws = __la_win_permissive_name_w(temp_name.s); if (ws == NULL) { errno = EINVAL; goto exit_tmpfile; } attr = GetFileAttributesW(ws); if (attr == (DWORD)-1) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } } if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { errno = ENOTDIR; goto exit_tmpfile; } /* * Create a temporary file. */ archive_wstrcat(&temp_name, prefix); archive_wstrcat(&temp_name, suffix); ep = temp_name.s + archive_strlen(&temp_name); xp = ep - wcslen(suffix); if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } for (;;) { wchar_t *p; HANDLE h; /* Generate a random file name through CryptGenRandom(). */ p = xp; if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), (BYTE*)p)) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } for (; p < ep; p++) *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; free(ws); ws = __la_win_permissive_name_w(temp_name.s); if (ws == NULL) { errno = EINVAL; goto exit_tmpfile; } /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to * delete this temporary file immediately when this * file closed. */ h = CreateFileW(ws, GENERIC_READ | GENERIC_WRITE | DELETE, 0,/* Not share */ NULL, CREATE_NEW,/* Create a new file only */ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); if (h == INVALID_HANDLE_VALUE) { /* The same file already exists. retry with * a new filename. */ if (GetLastError() == ERROR_FILE_EXISTS) continue; /* Otherwise, fail creation temporary file. */ la_dosmaperr(GetLastError()); goto exit_tmpfile; } fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); if (fd == -1) { CloseHandle(h); goto exit_tmpfile; } else break;/* success! */ } exit_tmpfile: if (hProv != (HCRYPTPROV)NULL) CryptReleaseContext(hProv, 0); free(ws); archive_wstring_free(&temp_name); return (fd); }
static int _warc_header(struct archive_write *a, struct archive_entry *entry) { struct warc_s *w = a->format_data; struct archive_string hdr; #define MAX_HDR_SIZE 512 /* check whether warcinfo record needs outputting */ if (!w->omit_warcinfo) { ssize_t r; warc_essential_hdr_t wi = { WT_INFO, /*uri*/NULL, /*urn*/NULL, /*rtm*/0, /*mtm*/0, /*cty*/"application/warc-fields", /*len*/sizeof(warcinfo) - 1U, }; wi.rtime = w->now; wi.mtime = w->now; archive_string_init(&hdr); r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi); if (r >= 0) { /* jackpot! */ /* now also use HDR buffer for the actual warcinfo */ archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1); /* append end-of-record indicator */ archive_strncat(&hdr, "\r\n\r\n", 4); /* write to output stream */ __archive_write_output(a, hdr.s, archive_strlen(&hdr)); } /* indicate we're done with file header writing */ w->omit_warcinfo = 1U; archive_string_free(&hdr); } if (archive_entry_pathname(entry) == NULL) { archive_set_error(&a->archive, EINVAL, "Invalid filename"); return (ARCHIVE_WARN); } w->typ = archive_entry_filetype(entry); w->populz = 0U; if (w->typ == AE_IFREG) { warc_essential_hdr_t rh = { WT_RSRC, /*uri*/NULL, /*urn*/NULL, /*rtm*/0, /*mtm*/0, /*cty*/NULL, /*len*/0, }; ssize_t r; rh.tgturi = archive_entry_pathname(entry); rh.rtime = w->now; rh.mtime = archive_entry_mtime(entry); rh.cntlen = (size_t)archive_entry_size(entry); archive_string_init(&hdr); r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh); if (r < 0) { /* don't bother */ archive_set_error( &a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "cannot archive file"); return (ARCHIVE_WARN); } /* otherwise append to output stream */ __archive_write_output(a, hdr.s, r); /* and let subsequent calls to _data() know about the size */ w->populz = rh.cntlen; archive_string_free(&hdr); return (ARCHIVE_OK); } /* just resort to erroring as per Tim's advice */ archive_set_error( &a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "WARC can only process regular files"); return (ARCHIVE_FAILED); }
pid_t __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) { HANDLE childStdout[2], childStdin[2],childStderr; SECURITY_ATTRIBUTES secAtts; STARTUPINFOA staInfo; PROCESS_INFORMATION childInfo; struct archive_string cmdline; struct archive_string fullpath; struct archive_cmdline *acmd; char *arg0, *ext; int i, l; DWORD fl, fl_old; childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE; childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE; childStderr = INVALID_HANDLE_VALUE; archive_string_init(&cmdline); archive_string_init(&fullpath); acmd = __archive_cmdline_allocate(); if (acmd == NULL) goto fail; if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK) goto fail; /* * Search the full path of 'path'. * NOTE: This does not need if we give CreateProcessA 'path' as * a part of the cmdline and give CreateProcessA NULL as first * parameter, but I do not like that way. */ ext = strrchr(acmd->path, '.'); if (ext == NULL || strlen(ext) > 4) /* 'path' does not have a proper extension, so we have to * give SearchPath() ".exe" as the extension. */ ext = ".exe"; else ext = NULL;/* 'path' has an extension. */ fl = MAX_PATH; do { if (archive_string_ensure(&fullpath, fl) == NULL) goto fail; fl_old = fl; fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s, &arg0); } while (fl != 0 && fl > fl_old); if (fl == 0) goto fail; /* * Make a command line. */ for (l = 0, i = 0; acmd->argv[i] != NULL; i++) { if (i == 0) continue; l += (int)strlen(acmd->argv[i]) + 1; } if (archive_string_ensure(&cmdline, l + 1) == NULL) goto fail; for (i = 0; acmd->argv[i] != NULL; i++) { if (i == 0) { const char *p, *sp; if ((p = strchr(acmd->argv[i], '/')) != NULL || (p = strchr(acmd->argv[i], '\\')) != NULL) p++; else p = acmd->argv[i]; if ((sp = strchr(p, ' ')) != NULL) archive_strappend_char(&cmdline, '"'); archive_strcat(&cmdline, p); if (sp != NULL) archive_strappend_char(&cmdline, '"'); } else { archive_strappend_char(&cmdline, ' '); archive_strcat(&cmdline, acmd->argv[i]); } } if (i <= 1) { const char *sp; if ((sp = strchr(arg0, ' ')) != NULL) archive_strappend_char(&cmdline, '"'); archive_strcat(&cmdline, arg0); if (sp != NULL) archive_strappend_char(&cmdline, '"'); } secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); secAtts.bInheritHandle = TRUE; secAtts.lpSecurityDescriptor = NULL; if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0) goto fail; if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0)) goto fail; if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) goto fail; if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0)) goto fail; if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), GetCurrentProcess(), &childStderr, 0, TRUE, DUPLICATE_SAME_ACCESS) == 0) goto fail; memset(&staInfo, 0, sizeof(staInfo)); staInfo.cb = sizeof(staInfo); staInfo.hStdError = childStderr; staInfo.hStdOutput = childStdout[1]; staInfo.hStdInput = childStdin[0]; staInfo.wShowWindow = SW_HIDE; staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0, NULL, NULL, &staInfo, &childInfo) == 0) goto fail; WaitForInputIdle(childInfo.hProcess, INFINITE); CloseHandle(childInfo.hProcess); CloseHandle(childInfo.hThread); *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY); *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY); CloseHandle(childStdout[1]); CloseHandle(childStdin[0]); archive_string_free(&cmdline); archive_string_free(&fullpath); __archive_cmdline_free(acmd); return (childInfo.dwProcessId); fail: if (childStdout[0] != INVALID_HANDLE_VALUE) CloseHandle(childStdout[0]); if (childStdout[1] != INVALID_HANDLE_VALUE) CloseHandle(childStdout[1]); if (childStdin[0] != INVALID_HANDLE_VALUE) CloseHandle(childStdin[0]); if (childStdin[1] != INVALID_HANDLE_VALUE) CloseHandle(childStdin[1]); if (childStderr != INVALID_HANDLE_VALUE) CloseHandle(childStderr); archive_string_free(&cmdline); archive_string_free(&fullpath); __archive_cmdline_free(acmd); return (-1); }