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);
}
Exemplo n.º 2
0
/*
 * The reference file for this has been manually tweaked so that:
 *   * file2 has length-at-end but file1 does not
 *   * file2 has an invalid CRC
 */
static void
verify_basic(struct archive *a, int seek_checks)
{
	struct archive_entry *ae;
	char *buff[128];
	const void *pv;
	size_t s;
	int64_t o;

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
        assertEqualString("ZIP 1.0 (uncompressed)", archive_format_name(a));
	assertEqualString("dir/", archive_entry_pathname(ae));
	assertEqualInt(1179604249, archive_entry_mtime(ae));
	assertEqualInt(0, archive_entry_size(ae));
	if (seek_checks)
		assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);
	assertEqualIntA(a, ARCHIVE_EOF,
	    archive_read_data_block(a, &pv, &s, &o));
	assertEqualInt((int)s, 0);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
        assertEqualString("ZIP 2.0 (deflation)", archive_format_name(a));
	assertEqualString("file1", archive_entry_pathname(ae));
	assertEqualInt(1179604289, archive_entry_mtime(ae));
	if (seek_checks)
		assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
	assertEqualInt(18, archive_entry_size(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);
	failure("archive_read_data() returns number of bytes read");
	if (archive_zlib_version() != NULL) {
		assertEqualInt(18, archive_read_data(a, buff, 19));
		assertEqualMem(buff, "hello\nhello\nhello\n", 18);
	} else {
		assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, 19));
		assertEqualString(archive_error_string(a),
		    "Unsupported ZIP compression method (deflation)");
		assert(archive_errno(a) != 0);
	}

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
        assertEqualString("ZIP 2.0 (deflation)", archive_format_name(a));
	assertEqualString("file2", archive_entry_pathname(ae));
	assertEqualInt(1179605932, archive_entry_mtime(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);
	if (seek_checks) {
		assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
	}
	assert(archive_entry_size_is_set(ae));
	assertEqualInt(18, archive_entry_size(ae));
	if (archive_zlib_version() != NULL) {
		failure("file2 has a bad CRC, so read should fail and not change buff");
		memset(buff, 'a', 19);
		assertEqualInt(ARCHIVE_WARN, archive_read_data(a, buff, 19));
		assertEqualMem(buff, "aaaaaaaaaaaaaaaaaaa", 19);
	} else {
		assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, 19));
		assertEqualString(archive_error_string(a),
		    "Unsupported ZIP compression method (deflation)");
		assert(archive_errno(a) != 0);
	}
	assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &ae));
        assertEqualString("ZIP 2.0 (deflation)", archive_format_name(a));
	/* Verify the number of files read. */
	failure("the archive file has three files");
	assertEqualInt(3, archive_file_count(a));
	assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
	assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
/* ArchiveWriter::finish {{{
 *
*/
ZEND_METHOD(ArchiveWriter, finish)
{
	zval *this = getThis();
	int resource_id;
	HashPosition pos;
	archive_file_t *arch;
	archive_entry_t **entry;
	int result, error_num;
	const char *error_string;
	mode_t mode;
	php_stream *stream;
	zend_error_handling error_handling;

	zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC);

	if (!_archive_get_fd(this, &arch TSRMLS_CC)) {
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}

	if (zend_hash_sort(arch->entries, zend_qsort, _archive_pathname_compare, 0 TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}

	zend_hash_internal_pointer_reset_ex(arch->entries, &pos);
	while (zend_hash_get_current_data_ex(arch->entries, (void **)&entry, &pos) == SUCCESS) {

		mode = archive_entry_mode((*entry)->entry);

		if (S_ISREG(mode) && archive_entry_size((*entry)->entry) > 0) {
			if ((stream = php_stream_open_wrapper_ex((*entry)->filename, "r", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, NULL))) {
				char buf[PHP_ARCHIVE_BUF_LEN];
				int header_written=0;
				int read_bytes;

				while ((read_bytes = php_stream_read(stream, buf, PHP_ARCHIVE_BUF_LEN))) {
					if (!header_written) {
						/* write header only after the first successful read */
						result = archive_write_header(arch->arch, (*entry)->entry);
						if (result == ARCHIVE_FATAL) {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write entry header for file %s: fatal error", (*entry)->filename);
							zend_restore_error_handling(&error_handling TSRMLS_CC);
							return;
						}
						header_written = 1;
					}
					result = archive_write_data(arch->arch, buf, read_bytes);

					if (result <= 0) {
						error_num = archive_errno(arch->arch);
						error_string = archive_error_string(arch->arch);

						if (error_num && error_string) {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write file %s to archive: error #%d, %s", (*entry)->filename, error_num, error_string);
						}
						else {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write file %s: unknown error %d", (*entry)->filename, result);
						}
						php_stream_close(stream);
						zend_restore_error_handling(&error_handling TSRMLS_CC);
						return;
					}
				}
				php_stream_close(stream);
			}
		}
		else {
			result = archive_write_header(arch->arch, (*entry)->entry);
			if (result == ARCHIVE_FATAL) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write entry header for file %s: fatal error", (*entry)->filename);
				zend_restore_error_handling(&error_handling TSRMLS_CC);
				return;
			}
		}
		zend_hash_move_forward_ex(arch->entries, &pos);
	}

	if ((resource_id = _archive_get_rsrc_id(this TSRMLS_CC))) {
		add_property_resource(this, "fd", 0);
		zend_list_delete(resource_id);
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		RETURN_TRUE;
	}

	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish writing of archive file");
	zend_restore_error_handling(&error_handling TSRMLS_CC);
}
Exemplo n.º 4
0
static void
test_unicode_UTF8(void)
{
  char buff[30];
  const char reffile[] = "test_read_format_rar_unicode.rar";
  const char test_txt[] = "kanji";
  struct archive_entry *ae;
  struct archive *a;

  if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) {
	skipping("en_US.UTF-8 locale not available on this system.");
	return;
  }

  extract_reference_file(reffile);
  assert((a = archive_read_new()) != NULL);
  assertA(0 == archive_read_support_filter_all(a));
  assertA(0 == archive_read_support_format_all(a));
  assertA(0 == archive_read_open_file(a, reffile, 10240));

  /* First header. */
  assertA(0 == archive_read_next_header(a, &ae));
#if defined(__APPLE__)
#define f1name "\xE8\xA1\xA8\xE3\x81\x9F\xE3\x82\x99\xE3\x82\x88/"\
      "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x95\xE3\x82\xA9"\
      "\xE3\x83\xAB\xE3\x82\xBF\xE3\x82\x99/\xE6\x96\xB0\xE8\xA6\x8F"\
      "\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88 "\
      "\xE3\x83\x88\xE3\x82\x99\xE3\x82\xAD\xE3\x83\xA5\xE3\x83\xA1"\
      "\xE3\x83\xB3\xE3\x83\x88.txt" /* NFD */
#else
#define f1name "\xE8\xA1\xA8\xE3\x81\xA0\xE3\x82\x88/"\
      "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x95\xE3\x82\xA9"\
      "\xE3\x83\xAB\xE3\x83\x80/\xE6\x96\xB0\xE8\xA6\x8F"\
      "\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88 "\
      "\xE3\x83\x89\xE3\x82\xAD\xE3\x83\xA5\xE3\x83\xA1"\
      "\xE3\x83\xB3\xE3\x83\x88.txt" /* NFC */
#endif
  assertEqualUTF8String(f1name, archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));

  /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
#if defined(__APPLE__)
#define f2name "\xE8\xA1\xA8\xE3\x81\x9F\xE3\x82\x99\xE3\x82\x88/"\
      "\xE6\xBC\xA2\xE5\xAD\x97\xE9\x95\xB7\xE3\x81\x84\xE3\x83\x95"\
      "\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\xE5\x90\x8Dlong-filename-in-"\
      "\xE6\xBC\xA2\xE5\xAD\x97.txt" /* NFD */
#else
#define f2name "\xE8\xA1\xA8\xE3\x81\xA0\xE3\x82\x88/"\
      "\xE6\xBC\xA2\xE5\xAD\x97\xE9\x95\xB7\xE3\x81\x84\xE3\x83\x95"\
      "\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\xE5\x90\x8Dlong-filename-in-"\
      "\xE6\xBC\xA2\xE5\xAD\x97.txt" /* NFC */
#endif
  assertEqualUTF8String(f2name, archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(5, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertEqualIntA(a, 5, archive_read_data(a, buff, 5));
  assertEqualMem(buff, test_txt, 5);

  /* Third header. */
  assertA(0 == archive_read_next_header(a, &ae));
#if defined(__APPLE__)
#define f3name "\xE8\xA1\xA8\xE3\x81\x9F\xE3\x82\x99\xE3\x82\x88/"\
      "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x95\xE3\x82"\
      "\xA9\xE3\x83\xAB\xE3\x82\xBF\xE3\x82\x99" /* NFD */
#else
#define f3name "\xE8\xA1\xA8\xE3\x81\xA0\xE3\x82\x88/"\
      "\xE6\x96\xB0\xE3\x81\x97\xE3\x81\x84\xE3\x83\x95\xE3\x82"\
      "\xA9\xE3\x83\xAB\xE3\x83\x80" /* NFC */
#endif
  assertEqualUTF8String(f3name, archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fourth header. */
  assertA(0 == archive_read_next_header(a, &ae));
#if defined(__APPLE__)
#define f4name "\xE8\xA1\xA8\xE3\x81\x9F\xE3\x82\x99\xE3\x82\x88" /* NFD */
#else
#define f4name "\xE8\xA1\xA8\xE3\x81\xA0\xE3\x82\x88" /* NFC */
#endif
  assertEqualUTF8String(f4name, archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fifth header, which has a symbolic-link name in multi-byte characters. */
  assertA(0 == archive_read_next_header(a, &ae));
#if defined(__APPLE__)
#define f5name "\xE8\xA1\xA8\xE3\x81\x9F\xE3\x82\x99\xE3\x82\x88/"\
      "\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB" /* NFD */
#else
#define f5name "\xE8\xA1\xA8\xE3\x81\xA0\xE3\x82\x88/"\
      "\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB" /* NFC */
#endif
  assertEqualUTF8String(f5name, archive_entry_pathname(ae));
  assertEqualUTF8String(
      "\xE6\xBC\xA2\xE5\xAD\x97\xE9\x95\xB7\xE3\x81\x84\xE3\x83\x95"
      "\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\xE5\x90\x8Dlong-filename-in-"
      "\xE6\xBC\xA2\xE5\xAD\x97.txt", archive_entry_symlink(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(41453, archive_entry_mode(ae));
  assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff)));

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Exemplo n.º 5
0
static void
test_compress_best(void)
{
  const char reffile[] = "test_read_format_rar_compress_best.rar";
  char file1_buff[20111];
  int file1_size = sizeof(file1_buff);
  const char file1_test_txt[] = "<P STYLE=\"margin-bottom: 0in\"><BR>\n"
                                "</P>\n"
                                "</BODY>\n"
                                "</HTML>";
  char file2_buff[20];
  int file2_size = sizeof(file2_buff);
  const char file2_test_txt[] = "test text document\r\n";
  struct archive_entry *ae;
  struct archive *a;

  extract_reference_file(reffile);
  assert((a = archive_read_new()) != NULL);
  assertA(0 == archive_read_support_filter_all(a));
  assertA(0 == archive_read_support_format_all(a));
  assertA(0 == archive_read_open_file(a, reffile, 10240));

  /* First header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("LibarchiveAddingTest.html", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(file1_size, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(file1_size == archive_read_data(a, file1_buff, file1_size));
  assertEqualMem(&file1_buff[file1_size - sizeof(file1_test_txt) + 1],
                 file1_test_txt, sizeof(file1_test_txt) - 1);

    /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testlink", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(41471, archive_entry_mode(ae));
  assertEqualString("LibarchiveAddingTest.html", archive_entry_symlink(ae));
  assertEqualIntA(a, 0, archive_read_data(a, file1_buff, 30));

  /* Third header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir/test.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(file2_size, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(file2_size == archive_read_data(a, file2_buff, file2_size));
  assertEqualMem(&file2_buff[file2_size + 1 - sizeof(file2_test_txt)],
                 file2_test_txt, sizeof(file2_test_txt) - 1);

  /* Fourth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir/LibarchiveAddingTest.html",
                    archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(file1_size, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(file1_size == archive_read_data(a, file1_buff, file1_size));
  assertEqualMem(&file1_buff[file1_size - sizeof(file1_test_txt) + 1],
                 file1_test_txt, sizeof(file1_test_txt) - 1);

  /* Fifth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Sixth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testemptydir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(6, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static int
archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
{
    struct cpio *cpio;
    const char *p, *path;
    int pathlength, ret;
    int64_t ino;
    struct cpio_header   h;

    cpio = (struct cpio *)a->format_data;
    ret = 0;

    path = archive_entry_pathname(entry);
    pathlength = strlen(path) + 1; /* Include trailing null. */

    memset(&h, 0, sizeof(h));
    format_octal(070707, &h.c_magic, sizeof(h.c_magic));
    format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev));
    /*
     * TODO: Generate artificial inode numbers rather than just
     * re-using the ones off the disk.  That way, the 18-bit c_ino
     * field only limits the number of files in the archive.
     */
    ino = archive_entry_ino64(entry);
    if (ino < 0 || ino > 0777777) {
        archive_set_error(&a->archive, ERANGE,
                          "large inode number truncated");
        ret = ARCHIVE_WARN;
    }

    format_octal(archive_entry_ino64(entry) & 0777777, &h.c_ino, sizeof(h.c_ino));
    format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode));
    format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid));
    format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid));
    format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink));
    if (archive_entry_filetype(entry) == AE_IFBLK
            || archive_entry_filetype(entry) == AE_IFCHR)
        format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev));
    else
        format_octal(0, &h.c_rdev, sizeof(h.c_rdev));
    format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
    format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize));

    /* Non-regular files don't store bodies. */
    if (archive_entry_filetype(entry) != AE_IFREG)
        archive_entry_set_size(entry, 0);

    /* Symlinks get the link written as the body of the entry. */
    p = archive_entry_symlink(entry);
    if (p != NULL  &&  *p != '\0')
        format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
    else
        format_octal(archive_entry_size(entry),
                     &h.c_filesize, sizeof(h.c_filesize));

    ret = (a->compressor.write)(a, &h, sizeof(h));
    if (ret != ARCHIVE_OK)
        return (ARCHIVE_FATAL);

    ret = (a->compressor.write)(a, path, pathlength);
    if (ret != ARCHIVE_OK)
        return (ARCHIVE_FATAL);

    cpio->entry_bytes_remaining = archive_entry_size(entry);

    /* Write the symlink now. */
    if (p != NULL  &&  *p != '\0')
        ret = (a->compressor.write)(a, p, strlen(p));

    return (ret);
}
static int
archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
{
	int ret, append_fn;
	char buff[60];
	char *ss, *se;
	struct ar_w *ar;
	const char *pathname;
	const char *filename;
	int64_t size;

	append_fn = 0;
	ar = (struct ar_w *)a->format_data;
	ar->is_strtab = 0;
	filename = NULL;
	size = archive_entry_size(entry);


	/*
	 * Reject files with empty name.
	 */
	pathname = archive_entry_pathname(entry);
	if (*pathname == '\0') {
		archive_set_error(&a->archive, EINVAL,
		    "Invalid filename");
		return (ARCHIVE_WARN);
	}

	/*
	 * If we are now at the beginning of the archive,
	 * we need first write the ar global header.
	 */
	if (a->archive.file_position == 0)
		(a->compressor.write)(a, "!<arch>\n", 8);

	memset(buff, ' ', 60);
	strncpy(&buff[AR_fmag_offset], "`\n", 2);

	if (strcmp(pathname, "/") == 0 ) {
		/* Entry is archive symbol table in GNU format */
		buff[AR_name_offset] = '/';
		goto stat;
	}
	if (strcmp(pathname, "__.SYMDEF") == 0) {
		/* Entry is archive symbol table in BSD format */
		strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
		goto stat;
	}
	if (strcmp(pathname, "//") == 0) {
		/*
		 * Entry is archive filename table, inform that we should
		 * collect strtab in next _data call.
		 */
		ar->is_strtab = 1;
		buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';
		/*
		 * For archive string table, only ar_size filed should
		 * be set.
		 */
		goto size;
	}

	/*
	 * Otherwise, entry is a normal archive member.
	 * Strip leading paths from filenames, if any.
	 */
	if ((filename = ar_basename(pathname)) == NULL) {
		/* Reject filenames with trailing "/" */
		archive_set_error(&a->archive, EINVAL,
		    "Invalid filename");
		return (ARCHIVE_WARN);
	}

	if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) {
		/*
		 * SVR4/GNU variant use a "/" to mark then end of the filename,
		 * make it possible to have embedded spaces in the filename.
		 * So, the longest filename here (without extension) is
		 * actually 15 bytes.
		 */
		if (strlen(filename) <= 15) {
			strncpy(&buff[AR_name_offset], 
			    filename, strlen(filename));
			buff[AR_name_offset + strlen(filename)] = '/';
		} else {
			/*
			 * For filename longer than 15 bytes, GNU variant
			 * makes use of a string table and instead stores the
			 * offset of the real filename to in the ar_name field.
			 * The string table should have been written before.
			 */
			if (ar->has_strtab <= 0) {
				archive_set_error(&a->archive, EINVAL,
				    "Can't find string table");
				return (ARCHIVE_WARN);
			}

			se = (char *)malloc(strlen(filename) + 3);
			if (se == NULL) {
				archive_set_error(&a->archive, ENOMEM,
				    "Can't allocate filename buffer");
				return (ARCHIVE_FATAL);
			}

			strncpy(se, filename, strlen(filename));
			strcpy(se + strlen(filename), "/\n");

			ss = strstr(ar->strtab, se);
			free(se);

			if (ss == NULL) {
				archive_set_error(&a->archive, EINVAL,
				    "Invalid string table");
				return (ARCHIVE_WARN);
			}

			/*
			 * GNU variant puts "/" followed by digits into
			 * ar_name field. These digits indicates the real
			 * filename string's offset to the string table.
			 */
			buff[AR_name_offset] = '/';
			if (format_decimal(ss - ar->strtab,
			    buff + AR_name_offset + 1,
			    AR_name_size - 1)) {
				archive_set_error(&a->archive, ERANGE,
				    "string table offset too large");
				return (ARCHIVE_WARN);
			}
		}
	} else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) {
		/*
		 * BSD variant: for any file name which is more than
		 * 16 chars or contains one or more embedded space(s), the
		 * string "#1/" followed by the ASCII length of the name is
		 * put into the ar_name field. The file size (stored in the
		 * ar_size field) is incremented by the length of the name.
		 * The name is then written immediately following the
		 * archive header.
		 */
		if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
			strncpy(&buff[AR_name_offset], filename, strlen(filename));
			buff[AR_name_offset + strlen(filename)] = ' ';
		}
		else {
			strncpy(buff + AR_name_offset, "#1/", 3);
			if (format_decimal(strlen(filename),
			    buff + AR_name_offset + 3,
			    AR_name_size - 3)) {
				archive_set_error(&a->archive, ERANGE,
				    "File name too long");
				return (ARCHIVE_WARN);
			}
			append_fn = 1;
			size += strlen(filename);
		}
	}

stat:
	if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "File modification time too large");
		return (ARCHIVE_WARN);
	}
	if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "Numeric user ID too large");
		return (ARCHIVE_WARN);
	}
	if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "Numeric group ID too large");
		return (ARCHIVE_WARN);
	}
	if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "Numeric mode too large");
		return (ARCHIVE_WARN);
	}
	/*
	 * Sanity Check: A non-pseudo archive member should always be
	 * a regular file.
	 */
	if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) {
		archive_set_error(&a->archive, EINVAL,
		    "Regular file required for non-pseudo member");
		return (ARCHIVE_WARN);
	}

size:
	if (format_decimal(size, buff + AR_size_offset, AR_size_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "File size out of range");
		return (ARCHIVE_WARN);
	}

	ret = (a->compressor.write)(a, buff, 60);
	if (ret != ARCHIVE_OK)
		return (ret);

	ar->entry_bytes_remaining = size;
	ar->entry_padding = ar->entry_bytes_remaining % 2;

	if (append_fn > 0) {
		ret = (a->compressor.write)(a, filename, strlen(filename));
		if (ret != ARCHIVE_OK)
			return (ret);
		ar->entry_bytes_remaining -= strlen(filename);
	}

	return (ARCHIVE_OK);
}
Exemplo n.º 8
0
static void
test_filename(const char *prefix, int dlen, int flen)
{
	char buff[8192];
	char filename[400];
	char dirname[400];
	struct archive_entry *ae;
	struct archive *a;
	size_t used;
	char *p;
	int i;

	p = filename;
	if (prefix) {
		strcpy(filename, prefix);
		p += strlen(p);
	}
	if (dlen > 0) {
		for (i = 0; i < dlen; i++)
			*p++ = 'a';
		*p++ = '/';
	}
	for (i = 0; i < flen; i++)
		*p++ = 'b';
	*p = '\0';

	strcpy(dirname, filename);

	/* Create a new archive in memory. */
	assert((a = archive_write_new()) != NULL);
	assertA(0 == archive_write_set_format_pax_restricted(a));
	assertA(0 == archive_write_add_filter_none(a));
	assertA(0 == archive_write_set_bytes_per_block(a,0));
	assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));

	/*
	 * Write a file to it.
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, filename);
	archive_entry_set_mode(ae, S_IFREG | 0755);
	failure("Pathname %d/%d", dlen, flen);
	assertA(0 == archive_write_header(a, ae));
	archive_entry_free(ae);

	/*
	 * Write a dir to it (without trailing '/').
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, dirname);
	archive_entry_set_mode(ae, S_IFDIR | 0755);
	failure("Dirname %d/%d", dlen, flen);
	assertA(0 == archive_write_header(a, ae));
	archive_entry_free(ae);

	/* Tar adds a '/' to directory names. */
	strcat(dirname, "/");

	/*
	 * Write a dir to it (with trailing '/').
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, dirname);
	archive_entry_set_mode(ae, S_IFDIR | 0755);
	failure("Dirname %d/%d", dlen, flen);
	assertA(0 == archive_write_header(a, ae));
	archive_entry_free(ae);

	/* Close out the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now, read the data back.
	 */
	assert((a = archive_read_new()) != NULL);
	assertA(0 == archive_read_support_format_all(a));
	assertA(0 == archive_read_support_filter_all(a));
	assertA(0 == archive_read_open_memory(a, buff, used));

	/* Read the file and check the filename. */
	assertA(0 == archive_read_next_header(a, &ae));
	assertEqualString(filename, archive_entry_pathname(ae));
	assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));

	/*
	 * Read the two dirs and check the names.
	 *
	 * Both dirs should read back with the same name, since
	 * tar should add a trailing '/' to any dir that doesn't
	 * already have one.  We only report the first such failure
	 * here.
	 */
	assertA(0 == archive_read_next_header(a, &ae));
	assertEqualString(dirname, archive_entry_pathname(ae));
	assert((S_IFDIR | 0755) == archive_entry_mode(ae));

	assertA(0 == archive_read_next_header(a, &ae));
	assertEqualString(dirname, archive_entry_pathname(ae));
	assert((S_IFDIR | 0755) == archive_entry_mode(ae));

	/* Verify the end of the archive. */
	assert(1 == archive_read_next_header(a, &ae));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static void
test_filename(const char *prefix, int dlen, int flen)
{
	char buff[8192];
	char filename[400];
	char dirname[400];
	struct archive_entry *ae;
	struct archive *a;
	size_t used;
	int separator = 0;
	int i = 0;

	if (prefix != NULL) {
		strcpy(filename, prefix);
		i = (int)strlen(prefix);
	}
	if (dlen > 0) {
		for (; i < dlen; i++)
			filename[i] = 'a';
		filename[i++] = '/';
		separator = 1;
	}
	for (; i < dlen + flen + separator; i++)
		filename[i] = 'b';
	filename[i] = '\0';

	strcpy(dirname, filename);

	/* Create a new archive in memory. */
	assert((a = archive_write_new()) != NULL);
	assertA(0 == archive_write_set_format_ustar(a));
	assertA(0 == archive_write_set_compression_none(a));
	assertA(0 == archive_write_set_bytes_per_block(a,0));
	assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));

	/*
	 * Write a file to it.
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, filename);
	archive_entry_set_mode(ae, S_IFREG | 0755);
	failure("dlen=%d, flen=%d", dlen, flen);
	if (flen > 100) {
		assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
	} else {
		assertEqualIntA(a, 0, archive_write_header(a, ae));
	}
	archive_entry_free(ae);

	/*
	 * Write a dir to it (without trailing '/').
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, dirname);
	archive_entry_set_mode(ae, S_IFDIR | 0755);
	failure("dlen=%d, flen=%d", dlen, flen);
	if (flen >= 100) {
		assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
	} else {
		assertEqualIntA(a, 0, archive_write_header(a, ae));
	}
	archive_entry_free(ae);

	/* Tar adds a '/' to directory names. */
	strcat(dirname, "/");

	/*
	 * Write a dir to it (with trailing '/').
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, dirname);
	archive_entry_set_mode(ae, S_IFDIR | 0755);
	failure("dlen=%d, flen=%d", dlen, flen);
	if (flen >= 100) {
		assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
	} else {
		assertEqualIntA(a, 0, archive_write_header(a, ae));
	}
	archive_entry_free(ae);

	/* Close out the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now, read the data back.
	 */
	assert((a = archive_read_new()) != NULL);
	assertA(0 == archive_read_support_format_all(a));
	assertA(0 == archive_read_support_filter_all(a));
	assertA(0 == archive_read_open_memory(a, buff, used));

	if (flen <= 100) {
		/* Read the file and check the filename. */
		assertA(0 == archive_read_next_header(a, &ae));
		failure("dlen=%d, flen=%d", dlen, flen);
		assertEqualString(filename, archive_entry_pathname(ae));
		assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
	}

	/*
	 * Read the two dirs and check the names.
	 *
	 * Both dirs should read back with the same name, since
	 * tar should add a trailing '/' to any dir that doesn't
	 * already have one.
	 */
	if (flen <= 99) {
		assertA(0 == archive_read_next_header(a, &ae));
		assert((S_IFDIR | 0755) == archive_entry_mode(ae));
		failure("dlen=%d, flen=%d", dlen, flen);
		assertEqualString(dirname, archive_entry_pathname(ae));
	}

	if (flen <= 99) {
		assertA(0 == archive_read_next_header(a, &ae));
		assert((S_IFDIR | 0755) == archive_entry_mode(ae));
		assertEqualString(dirname, archive_entry_pathname(ae));
	}

	/* Verify the end of the archive. */
	failure("This fails if entries were written that should not have been written.  dlen=%d, flen=%d", dlen, flen);
	assertEqualInt(1, archive_read_next_header(a, &ae));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Exemplo n.º 10
0
/*
 * Apple shipped a customized version of bsdtar starting with MacOS 10.6.
 */
static void
test_compat_mac_2(void)
{
	char name[] = "test_compat_mac-2.tar.Z";
	struct archive_entry *ae;
	struct archive *a;
	const void *attr;
	size_t attrSize;

	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	extract_reference_file(name);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("./", archive_entry_pathname(ae));
	assertEqualInt(1303628303, archive_entry_mtime(ae));
	assertEqualInt(501, archive_entry_uid(ae));
	assertEqualString("tim", archive_entry_uname(ae));
	assertEqualInt(20, archive_entry_gid(ae));
	assertEqualString("staff", archive_entry_gname(ae));
	assertEqualInt(040755, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr == NULL);
	assertEqualInt(0, attrSize);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("./mydir/", archive_entry_pathname(ae));
	assertEqualInt(1303628303, archive_entry_mtime(ae));
	assertEqualInt(501, archive_entry_uid(ae));
	assertEqualString("tim", archive_entry_uname(ae));
	assertEqualInt(20, archive_entry_gid(ae));
	assertEqualString("staff", archive_entry_gname(ae));
	assertEqualInt(040755, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(267, attrSize);
	assertEqualMem("\x00\x05\x16\x07\x00\x02\x00\x00Mac OS X", attr, 16);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("./myfile", archive_entry_pathname(ae));
	assertEqualInt(1303628303, archive_entry_mtime(ae));
	assertEqualInt(501, archive_entry_uid(ae));
	assertEqualString("tim", archive_entry_uname(ae));
	assertEqualInt(20, archive_entry_gid(ae));
	assertEqualString("staff", archive_entry_gname(ae));
	assertEqualInt(0100644, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(267, attrSize);
	assertEqualMem("\x00\x05\x16\x07\x00\x02\x00\x00Mac OS X", attr, 16);

	/* Verify the end-of-archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	/* Verify that the format detection worked. */
	assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
	assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);

	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Exemplo n.º 11
0
/*
 * Apple shipped an extended version of GNU tar with Mac OS X 10.5
 * and earlier.
 */
static void
test_compat_mac_1(void)
{
	char name[] = "test_compat_mac-1.tar.Z";
	struct archive_entry *ae;
	struct archive *a;
	const void *attr;
	size_t attrSize;

	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	extract_reference_file(name);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString(TESTPATH, archive_entry_pathname(ae));
	assertEqualInt(1275688109, archive_entry_mtime(ae));
	assertEqualInt(95594, archive_entry_uid(ae));
	assertEqualString("kientzle", archive_entry_uname(ae));
	assertEqualInt(5000, archive_entry_gid(ae));
	assertEqualString("", archive_entry_gname(ae));
	assertEqualInt(040755, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr == NULL);
	assertEqualInt(0, attrSize);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString(TESTPATH "dir/", archive_entry_pathname(ae));
	assertEqualInt(1275687611, archive_entry_mtime(ae));
	assertEqualInt(95594, archive_entry_uid(ae));
	assertEqualString("kientzle", archive_entry_uname(ae));
	assertEqualInt(5000, archive_entry_gid(ae));
	assertEqualString("", archive_entry_gname(ae));
	assertEqualInt(040755, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(225, attrSize);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString(TESTPATH "file", archive_entry_pathname(ae));
	assertEqualInt(1275687588, archive_entry_mtime(ae));
	assertEqualInt(95594, archive_entry_uid(ae));
	assertEqualString("kientzle", archive_entry_uname(ae));
	assertEqualInt(5000, archive_entry_gid(ae));
	assertEqualString("", archive_entry_gname(ae));
	assertEqualInt(0100644, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(225, attrSize);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("dir/", archive_entry_pathname(ae));
	assertEqualInt(1275688064, archive_entry_mtime(ae));
	assertEqualInt(95594, archive_entry_uid(ae));
	assertEqualString("kientzle", archive_entry_uname(ae));
	assertEqualInt(5000, archive_entry_gid(ae));
	assertEqualString("", archive_entry_gname(ae));
	assertEqualInt(040755, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(225, attrSize);
	assertEqualMem("\x00\x05\x16\x07\x00\x02\x00\x00Mac OS X", attr, 16);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("file", archive_entry_pathname(ae));
	assertEqualInt(1275625860, archive_entry_mtime(ae));
	assertEqualInt(95594, archive_entry_uid(ae));
	assertEqualString("kientzle", archive_entry_uname(ae));
	assertEqualInt(5000, archive_entry_gid(ae));
	assertEqualString("", archive_entry_gname(ae));
	assertEqualInt(0100644, archive_entry_mode(ae));

	attr = archive_entry_mac_metadata(ae, &attrSize);
	assert(attr != NULL);
	assertEqualInt(225, attrSize);
	assertEqualMem("\x00\x05\x16\x07\x00\x02\x00\x00Mac OS X", attr, 16);

	/* Verify the end-of-archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	/* Verify that the format detection worked. */
	assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
	assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);

	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static void
test_open_filename_mbs(void)
{
	char buff[64];
	struct archive_entry *ae;
	struct archive *a;

	/* Write an archive through this FILE *. */
	assert((a = archive_write_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a));
	assertEqualIntA(a, ARCHIVE_OK,
	    archive_write_open_filename(a, "test.tar"));

	/*
	 * Write a file to it.
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_set_mtime(ae, 1, 0);
	archive_entry_copy_pathname(ae, "file");
	archive_entry_set_mode(ae, S_IFREG | 0755);
	archive_entry_set_size(ae, 8);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);
	assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9));

	/*
	 * Write a second file to it.
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_copy_pathname(ae, "file2");
	archive_entry_set_mode(ae, S_IFREG | 0755);
	archive_entry_set_size(ae, 819200);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);

	/* Close out the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now, read the data back.
	 */
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK,
	    archive_read_open_filename(a, "test.tar", 512));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(1, archive_entry_mtime(ae));
	assertEqualInt(0, archive_entry_mtime_nsec(ae));
	assertEqualInt(0, archive_entry_atime(ae));
	assertEqualInt(0, archive_entry_ctime(ae));
	assertEqualString("file", archive_entry_pathname(ae));
	assert((S_IFREG | 0755) == archive_entry_mode(ae));
	assertEqualInt(8, archive_entry_size(ae));
	assertEqualIntA(a, 8, archive_read_data(a, buff, 10));
	assertEqualMem(buff, "12345678", 8);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("file2", archive_entry_pathname(ae));
	assert((S_IFREG | 0755) == archive_entry_mode(ae));
	assertEqualInt(819200, archive_entry_size(ae));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));

	/* Verify the end of the archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));

	/*
	 * Verify some of the error handling.
	 */
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_FATAL,
	    archive_read_open_filename(a, "nonexistent.tar", 512));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));

}
Exemplo n.º 13
0
static void
test_format(int	(*set_format)(struct archive *))
{
    char filedata[64];
    struct archive_entry *ae;
    struct archive *a;
    char *p;
    size_t used;
    size_t buffsize = 1000000;
    char *buff;
    int damaged = 0;

    buff = malloc(buffsize);

    /* Create a new archive in memory. */
    assert((a = archive_write_new()) != NULL);
    assertA(0 == (*set_format)(a));
    assertA(0 == archive_write_add_filter_none(a));
    assertA(0 == archive_write_open_memory(a, buff, buffsize, &used));

    /*
     * Write a file to it.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_set_mtime(ae, 1, 10);
    assert(1 == archive_entry_mtime(ae));
    assert(10 == archive_entry_mtime_nsec(ae));
    p = strdup("file");
    archive_entry_copy_pathname(ae, p);
    strcpy(p, "XXXX");
    free(p);
    assertEqualString("file", archive_entry_pathname(ae));
    archive_entry_set_mode(ae, S_IFREG | 0755);
    assert((S_IFREG | 0755) == archive_entry_mode(ae));
    archive_entry_set_size(ae, 8);

    assertA(0 == archive_write_header(a, ae));
    archive_entry_free(ae);
    assertA(8 == archive_write_data(a, "12345678", 9));

    /*
     * Write another file to it.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_set_mtime(ae, 1, 10);
    assert(1 == archive_entry_mtime(ae));
    assert(10 == archive_entry_mtime_nsec(ae));
    p = strdup("file2");
    archive_entry_copy_pathname(ae, p);
    strcpy(p, "XXXX");
    free(p);
    assertEqualString("file2", archive_entry_pathname(ae));
    archive_entry_set_mode(ae, S_IFREG | 0755);
    assert((S_IFREG | 0755) == archive_entry_mode(ae));
    archive_entry_set_size(ae, 4);

    assertA(0 == archive_write_header(a, ae));
    archive_entry_free(ae);
    assertA(4 == archive_write_data(a, "1234", 5));

    /*
     * Write a file with a name, filetype, and size.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_copy_pathname(ae, "name");
    archive_entry_set_size(ae, 0);
    archive_entry_set_filetype(ae, AE_IFREG);
    assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
    assert(archive_error_string(a) == NULL);
    archive_entry_free(ae);

    /*
     * Write a file with a name and filetype but no size.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_copy_pathname(ae, "name");
    archive_entry_unset_size(ae);
    archive_entry_set_filetype(ae, AE_IFREG);
    assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
    assert(archive_error_string(a) != NULL);
    archive_entry_free(ae);

    /*
     * Write a file with a name and size but no filetype.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_copy_pathname(ae, "name");
    archive_entry_set_size(ae, 0);
    assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
    assert(archive_error_string(a) != NULL);
    archive_entry_free(ae);

    /*
     * Write a file with a size and filetype but no name.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_set_size(ae, 0);
    archive_entry_set_filetype(ae, AE_IFREG);
    assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
    assert(archive_error_string(a) != NULL);
    archive_entry_free(ae);

    /*
     * Write a directory to it.
     */
    assert((ae = archive_entry_new()) != NULL);
    archive_entry_set_mtime(ae, 11, 110);
    archive_entry_copy_pathname(ae, "dir");
    archive_entry_set_mode(ae, S_IFDIR | 0755);
    archive_entry_set_size(ae, 512);

    assertA(0 == archive_write_header(a, ae));
    assertEqualInt(0, archive_entry_size(ae));
    archive_entry_free(ae);
    assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9));


    /* Close out the archive. */
    assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
    assertEqualInt(ARCHIVE_OK, archive_write_free(a));

    /*
     * Damage the second entry to test the search-ahead recovery.
     * TODO: Move the damage-recovery checking to a separate test;
     * it doesn't really belong in this write test.
     */
    {
        int i;
        for (i = 80; i < 150; i++) {
            if (memcmp(buff + i, "07070", 5) == 0) {
                damaged = 1;
                buff[i] = 'X';
                break;
            }
        }
    }
    failure("Unable to locate the second header for damage-recovery test.");
    assert(damaged == 1);

    /*
     * Now, read the data back.
     */
    assert((a = archive_read_new()) != NULL);
    assertA(0 == archive_read_support_format_all(a));
    assertA(0 == archive_read_support_filter_all(a));
    assertA(0 == archive_read_open_memory(a, buff, used));

    if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) {
        archive_read_free(a);
        return;
    }

    assertEqualInt(1, archive_entry_mtime(ae));
    /* Not the same as above: cpio doesn't store hi-res times. */
    assert(0 == archive_entry_mtime_nsec(ae));
    assert(0 == archive_entry_atime(ae));
    assert(0 == archive_entry_ctime(ae));
    assertEqualString("file", archive_entry_pathname(ae));
    assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
    assertEqualInt(8, archive_entry_size(ae));
    assertA(8 == archive_read_data(a, filedata, 10));
    assertEqualMem(filedata, "12345678", 8);

    /*
     * The second file can't be read because we damaged its header.
     */

    /*
     * Read the third file back.
     * ARCHIVE_WARN here because the damaged entry was skipped.
     */
    assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae));
    assertEqualString("name", archive_entry_pathname(ae));

    /*
     * Read the dir entry back.
     */
    assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
    assertEqualInt(11, archive_entry_mtime(ae));
    assert(0 == archive_entry_mtime_nsec(ae));
    assert(0 == archive_entry_atime(ae));
    assert(0 == archive_entry_ctime(ae));
    assertEqualString("dir", archive_entry_pathname(ae));
    assertEqualInt((S_IFDIR | 0755), archive_entry_mode(ae));
    assertEqualInt(0, archive_entry_size(ae));
    assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));

    /* Verify the end of the archive. */
    assertEqualIntA(a, 1, archive_read_next_header(a, &ae));
    assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
    assertEqualInt(ARCHIVE_OK, archive_read_free(a));

    free(buff);
}
static int
archive_format_gnutar_header(struct archive_write *a, char h[512],
    struct archive_entry *entry, int tartype)
{
	unsigned int checksum;
	int i, ret;
	size_t copy_length;
	const char *p;
	struct gnutar *gnutar;

	gnutar = (struct gnutar *)a->format_data;

	ret = 0;

	/*
	 * The "template header" already includes the signature,
	 * various end-of-field markers, and other required elements.
	 */
	memcpy(h, &template_header, 512);

	/*
	 * Because the block is already null-filled, and strings
	 * are allowed to exactly fill their destination (without null),
	 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
	 */

	if (tartype == 'K' || tartype == 'L') {
		p = archive_entry_pathname(entry);
		copy_length = strlen(p);
	} else {
		p = gnutar->pathname;
		copy_length = gnutar->pathname_length;
	}
	if (copy_length > GNUTAR_name_size)
		copy_length = GNUTAR_name_size;
	memcpy(h + GNUTAR_name_offset, p, copy_length);

	if ((copy_length = gnutar->linkname_length) > 0) {
		if (copy_length > GNUTAR_linkname_size)
			copy_length = GNUTAR_linkname_size;
		memcpy(h + GNUTAR_linkname_offset, gnutar->linkname,
		    copy_length);
	}

	/* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */
	if (tartype == 'K' || tartype == 'L') {
		p = archive_entry_uname(entry);
		copy_length = strlen(p);
	} else {
		p = gnutar->uname;
		copy_length = gnutar->uname_length;
	}
	if (copy_length > 0) {
		if (copy_length > GNUTAR_uname_size)
			copy_length = GNUTAR_uname_size;
		memcpy(h + GNUTAR_uname_offset, p, copy_length);
	}

	/* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */
	if (tartype == 'K' || tartype == 'L') {
		p = archive_entry_gname(entry);
		copy_length = strlen(p);
	} else {
		p = gnutar->gname;
		copy_length = gnutar->gname_length;
	}
	if (copy_length > 0) {
		if (strlen(p) > GNUTAR_gname_size)
			copy_length = GNUTAR_gname_size;
		memcpy(h + GNUTAR_gname_offset, p, copy_length);
	}

	/* By truncating the mode here, we ensure it always fits. */
	format_octal(archive_entry_mode(entry) & 07777,
	    h + GNUTAR_mode_offset, GNUTAR_mode_size);

	/* GNU tar supports base-256 here, so should never overflow. */
	if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,
		GNUTAR_uid_size, GNUTAR_uid_max_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "Numeric user ID %jd too large",
		    (intmax_t)archive_entry_uid(entry));
		ret = ARCHIVE_FAILED;
	}

	/* GNU tar supports base-256 here, so should never overflow. */
	if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,
		GNUTAR_gid_size, GNUTAR_gid_max_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "Numeric group ID %jd too large",
		    (intmax_t)archive_entry_gid(entry));
		ret = ARCHIVE_FAILED;
	}

	/* GNU tar supports base-256 here, so should never overflow. */
	if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset,
		GNUTAR_size_size, GNUTAR_size_max_size)) {
		archive_set_error(&a->archive, ERANGE,
		    "File size out of range");
		ret = ARCHIVE_FAILED;
	}

	/* Shouldn't overflow before 2106, since mtime field is 33 bits. */
	format_octal(archive_entry_mtime(entry),
	    h + GNUTAR_mtime_offset, GNUTAR_mtime_size);

	if (archive_entry_filetype(entry) == AE_IFBLK
	    || archive_entry_filetype(entry) == AE_IFCHR) {
		if (format_octal(archive_entry_rdevmajor(entry),
		    h + GNUTAR_rdevmajor_offset,
			GNUTAR_rdevmajor_size)) {
			archive_set_error(&a->archive, ERANGE,
			    "Major device number too large");
			ret = ARCHIVE_FAILED;
		}

		if (format_octal(archive_entry_rdevminor(entry),
		    h + GNUTAR_rdevminor_offset,
			GNUTAR_rdevminor_size)) {
			archive_set_error(&a->archive, ERANGE,
			    "Minor device number too large");
			ret = ARCHIVE_FAILED;
		}
	}

	h[GNUTAR_typeflag_offset] = tartype;

	checksum = 0;
	for (i = 0; i < 512; i++)
		checksum += 255 & (unsigned int)h[i];
	h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
	/* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
	format_octal(checksum, h + GNUTAR_checksum_offset, 6);
	return (ret);
}
static void
test_filter_by_name(const char *filter_name, int filter_code,
    int (*can_filter_prog)(void))
{
	struct archive_entry *ae;
	struct archive *a;
	size_t used;
	size_t buffsize = 1024 * 128;
	char *buff;
	int r;

	assert((buff = malloc(buffsize)) != NULL);
	if (buff == NULL)
		return;

	/* Create a new archive in memory. */
	assert((a = archive_write_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
	r = archive_write_add_filter_by_name(a, filter_name);
	if (r == ARCHIVE_WARN) {
		if (!can_filter_prog()) {
			skipping("%s filter not suported on this platform",
			    filter_name);
			assertEqualInt(ARCHIVE_OK, archive_write_free(a));
			free(buff);
			return;
		}
	} else if (r == ARCHIVE_FATAL &&
	    (strcmp(archive_error_string(a),
		   "lzma compression not supported on this platform") == 0 ||
	     strcmp(archive_error_string(a),
		   "xz compression not supported on this platform") == 0)) {
		skipping("%s filter not suported on this platform", filter_name);
		assertEqualInt(ARCHIVE_OK, archive_write_free(a));
		free(buff);
		return;
	} else {
		if (!assertEqualIntA(a, ARCHIVE_OK, r)) {
			assertEqualInt(ARCHIVE_OK, archive_write_free(a));
			free(buff);
			return;
		}
	}
	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 10));
	assertEqualIntA(a, ARCHIVE_OK,
	    archive_write_open_memory(a, buff, buffsize, &used));

	/*
	 * Write a file to it.
	 */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_set_mtime(ae, 1, 0);
	assertEqualInt(1, archive_entry_mtime(ae));
	archive_entry_set_ctime(ae, 1, 0);
	assertEqualInt(1, archive_entry_ctime(ae));
	archive_entry_set_atime(ae, 1, 0);
	assertEqualInt(1, archive_entry_atime(ae));
	archive_entry_copy_pathname(ae, "file");
	assertEqualString("file", archive_entry_pathname(ae));
	archive_entry_set_mode(ae, AE_IFREG | 0755);
	assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae));
	archive_entry_set_size(ae, 8);
	assertEqualInt(0, archive_write_header(a, ae));
	archive_entry_free(ae);
	assertEqualInt(8, archive_write_data(a, "12345678", 8));

	/* Close out the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now, read the data back.
	 */
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));

	/*
	 * Read and verify the file.
	 */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(1, archive_entry_mtime(ae));
	assertEqualString("file", archive_entry_pathname(ae));
	assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
	assertEqualInt(8, archive_entry_size(ae));

	/* Verify the end of the archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	/* Verify archive format. */
	assertEqualIntA(a, filter_code, archive_filter_code(a, 0));
	assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a));

	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
	free(buff);
}
Exemplo n.º 16
0
static void
test_1(void)
{
	struct archive_entry *ae;
	struct archive *a;
	size_t used;
	size_t blocksize;
	int64_t offset, length;
	char *buff2;
	size_t buff2_size = 0x13000;
	char buff3[1024];
	long i;

	assert((buff2 = malloc(buff2_size)) != NULL);
	/* Repeat the following for a variety of odd blocksizes. */
	for (blocksize = 1; blocksize < 100000; blocksize += blocksize + 3) {
		/* Create a new archive in memory. */
		assert((a = archive_write_new()) != NULL);
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_format_pax(a));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_compression_none(a));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_bytes_per_block(a, (int)blocksize));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_bytes_in_last_block(a, (int)blocksize));
		assertEqualInt(blocksize,
		    archive_write_get_bytes_in_last_block(a));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_open_memory(a, buff, sizeof(buff), &used));
		assertEqualInt(blocksize,
		    archive_write_get_bytes_in_last_block(a));

		/*
		 * Write a file to it.
		 */
		assert((ae = archive_entry_new()) != NULL);
		archive_entry_set_mtime(ae, 1, 10);
		assertEqualInt(1, archive_entry_mtime(ae));
		assertEqualInt(10, archive_entry_mtime_nsec(ae));
		archive_entry_copy_pathname(ae, "file");
		assertEqualString("file", archive_entry_pathname(ae));
		archive_entry_set_mode(ae, S_IFREG | 0755);
		assertEqualInt(S_IFREG | 0755, archive_entry_mode(ae));
		archive_entry_set_size(ae, 0x81000);
		archive_entry_sparse_add_entry(ae, 0x10000, 0x1000);
		archive_entry_sparse_add_entry(ae, 0x80000, 0x1000);

		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
		archive_entry_free(ae);
		memset(buff2, 'a', buff2_size);
		for (i = 0; i < 0x81000;) {
			size_t ws = buff2_size;
			if (i + ws > 0x81000)
				ws = 0x81000 - i;
			assertEqualInt(ws,
				archive_write_data(a, buff2, ws));
			i += ws;
		}

		/* Close out the archive. */
		assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
		assertEqualInt(ARCHIVE_OK, archive_write_free(a));

		/* This calculation gives "the smallest multiple of
		 * the block size that is at least 11264 bytes". */
		failure("blocksize=%d", blocksize);
		assertEqualInt(((11264 - 1)/blocksize+1)*blocksize, used);

		/*
		 * Now, read the data back.
		 */
		assert((a = archive_read_new()) != NULL);
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_read_support_format_all(a));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_read_support_filter_all(a));
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_read_open_memory(a, buff, used));

		assertEqualIntA(a, ARCHIVE_OK,
		    archive_read_next_header(a, &ae));

		assertEqualInt(1, archive_entry_mtime(ae));
		assertEqualInt(10, archive_entry_mtime_nsec(ae));
		assertEqualInt(0, archive_entry_atime(ae));
		assertEqualInt(0, archive_entry_ctime(ae));
		assertEqualString("file", archive_entry_pathname(ae));
		assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
		assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
		assertEqualInt(0x81000, archive_entry_size(ae));
		/* Verify sparse information. */
		assertEqualInt(2, archive_entry_sparse_reset(ae));
		assertEqualInt(0,
			archive_entry_sparse_next(ae, &offset, &length));
		assertEqualInt(0x10000, offset);
		assertEqualInt(0x1000, length);
		assertEqualInt(0,
			archive_entry_sparse_next(ae, &offset, &length));
		assertEqualInt(0x80000, offset);
		assertEqualInt(0x1000, length);
		/* Verify file contents. */
		memset(buff3, 0, sizeof(buff3));
		for (i = 0; i < 0x10000; i += 1024) {
			assertEqualInt(1024, archive_read_data(a, buff2, 1024));
			failure("Read data(0x%lx - 0x%lx) should be all zero",
			    i, i + 1024);
			assertEqualMem(buff2, buff3, 1024);
		}
		memset(buff3, 'a', sizeof(buff3));
		for (i = 0x10000; i < 0x11000; i += 1024) {
			assertEqualInt(1024, archive_read_data(a, buff2, 1024));
			failure("Read data(0x%lx - 0x%lx) should be all 'a'",
			    i, i + 1024);
			assertEqualMem(buff2, buff3, 1024);
		}
		memset(buff3, 0, sizeof(buff3));
		for (i = 0x11000; i < 0x80000; i += 1024) {
			assertEqualInt(1024, archive_read_data(a, buff2, 1024));
			failure("Read data(0x%lx - 0x%lx) should be all zero",
			    i, i + 1024);
			assertEqualMem(buff2, buff3, 1024);
		}
		memset(buff3, 'a', sizeof(buff3));
		for (i = 0x80000; i < 0x81000; i += 1024) {
			assertEqualInt(1024, archive_read_data(a, buff2, 1024));
			failure("Read data(0x%lx - 0x%lx) should be all 'a'",
			    i, i + 1024);
			assertEqualMem(buff2, buff3, 1024);
		}

		/* Verify the end of the archive. */
		assertEqualIntA(a, ARCHIVE_EOF,
		    archive_read_next_header(a, &ae));
		assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
		assertEqualInt(ARCHIVE_OK, archive_read_free(a));
	}
	free(buff2);
}
Exemplo n.º 17
0
static int
archive_write_zip_close(struct archive_write *a)
{
	struct zip *zip;
	struct zip_file_header_link *l;
	uint8_t h[SIZE_FILE_HEADER];
	uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
	uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
	int64_t offset_start, offset_end;
	int entries;
	int ret;

	zip = a->format_data;
	l = zip->central_directory;

	/*
	 * Formatting central directory file header fields that are
	 * fixed for all entries.
	 * Fields not used (and therefor 0) are:
	 *
	 *   - comment_length
	 *   - disk_number
	 *   - attributes_internal
	 */
	memset(h, 0, sizeof(h));
	archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
	archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
	archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT);

	entries = 0;
	offset_start = zip->written_bytes;

	/* Formatting individual header fields per entry and
	 * writing each entry. */
	while (l != NULL) {
		archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags);
		archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
		archive_le32enc(&h[FILE_HEADER_TIMEDATE],
			dos_time(archive_entry_mtime(l->entry)));
		archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
		archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
			(uint32_t)l->compressed_size);
		archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
			(uint32_t)archive_entry_size(l->entry));
		archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
			(uint16_t)path_length(l->entry));
		archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
		archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
			archive_entry_mode(l->entry));
		archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);

		/* Formatting extra data. */
		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
			ZIP_SIGNATURE_EXTRA_TIMESTAMP);
		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
		e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
		archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
			(uint32_t)archive_entry_mtime(l->entry));
		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
			ZIP_SIGNATURE_EXTRA_NEW_UNIX);
		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);

		ret = __archive_write_output(a, h, sizeof(h));
		if (ret != ARCHIVE_OK)
			return (ARCHIVE_FATAL);
		zip->written_bytes += sizeof(h);

		ret = write_path(l->entry, a);
		if (ret <= ARCHIVE_OK)
			return (ARCHIVE_FATAL);
		zip->written_bytes += ret;

		ret = __archive_write_output(a, e, sizeof(e));
		if (ret != ARCHIVE_OK)
			return (ARCHIVE_FATAL);
		zip->written_bytes += sizeof(e);

		l = l->next;
		entries++;
	}
	offset_end = zip->written_bytes;

	/* Formatting end of central directory. */
	memset(end, 0, sizeof(end));
	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
		ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
		(uint32_t)(offset_end - offset_start));
	archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
		(uint32_t)offset_start);

	/* Writing end of central directory. */
	ret = __archive_write_output(a, end, sizeof(end));
	if (ret != ARCHIVE_OK)
		return (ARCHIVE_FATAL);
	zip->written_bytes += sizeof(end);
	return (ARCHIVE_OK);
}
static int
archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
{
	const char *linkname;
	const char *name;
	char *p, *pp;
	struct shar *shar;

	shar = (struct shar *)a->format_data;
	if (!shar->wrote_header) {
		archive_strcat(&shar->work, "#!/bin/sh\n");
		archive_strcat(&shar->work, "# This is a shell archive\n");
		shar->wrote_header = 1;
	}

	/* Save the entry for the closing. */
	if (shar->entry)
		archive_entry_free(shar->entry);
	shar->entry = archive_entry_clone(entry);
	name = archive_entry_pathname(entry);

	/* Handle some preparatory issues. */
	switch(archive_entry_filetype(entry)) {
	case AE_IFREG:
		/* Only regular files have non-zero size. */
		break;
	case AE_IFDIR:
		archive_entry_set_size(entry, 0);
		/* Don't bother trying to recreate '.' */
		if (strcmp(name, ".") == 0  ||  strcmp(name, "./") == 0)
			return (ARCHIVE_OK);
		break;
	case AE_IFIFO:
	case AE_IFCHR:
	case AE_IFBLK:
		/* All other file types have zero size in the archive. */
		archive_entry_set_size(entry, 0);
		break;
	default:
		archive_entry_set_size(entry, 0);
		if (archive_entry_hardlink(entry) == NULL &&
		    archive_entry_symlink(entry) == NULL) {
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
			    "shar format cannot archive this");
			return (ARCHIVE_WARN);
		}
	}

	archive_string_empty(&shar->quoted_name);
	shar_quote(&shar->quoted_name, name, 1);

	/* Stock preparation for all file types. */
	archive_string_sprintf(&shar->work, "echo x %s\n", shar->quoted_name.s);

	if (archive_entry_filetype(entry) != AE_IFDIR) {
		/* Try to create the dir. */
		p = strdup(name);
		pp = strrchr(p, '/');
		/* If there is a / character, try to create the dir. */
		if (pp != NULL) {
			*pp = '\0';

			/* Try to avoid a lot of redundant mkdir commands. */
			if (strcmp(p, ".") == 0) {
				/* Don't try to "mkdir ." */
				free(p);
			} else if (shar->last_dir == NULL) {
				archive_strcat(&shar->work, "mkdir -p ");
				shar_quote(&shar->work, p, 1);
				archive_strcat(&shar->work,
				    " > /dev/null 2>&1\n");
				shar->last_dir = p;
			} else if (strcmp(p, shar->last_dir) == 0) {
				/* We've already created this exact dir. */
				free(p);
			} else if (strlen(p) < strlen(shar->last_dir) &&
			    strncmp(p, shar->last_dir, strlen(p)) == 0) {
				/* We've already created a subdir. */
				free(p);
			} else {
				archive_strcat(&shar->work, "mkdir -p ");
				shar_quote(&shar->work, p, 1);
				archive_strcat(&shar->work,
				    " > /dev/null 2>&1\n");
				shar->last_dir = p;
			}
		} else {
			free(p);
		}
	}

	/* Handle file-type specific issues. */
	shar->has_data = 0;
	if ((linkname = archive_entry_hardlink(entry)) != NULL) {
		archive_strcat(&shar->work, "ln -f ");
		shar_quote(&shar->work, linkname, 1);
		archive_string_sprintf(&shar->work, " %s\n",
		    shar->quoted_name.s);
	} else if ((linkname = archive_entry_symlink(entry)) != NULL) {
		archive_strcat(&shar->work, "ln -fs ");
		shar_quote(&shar->work, linkname, 1);
		archive_string_sprintf(&shar->work, " %s\n",
		    shar->quoted_name.s);
	} else {
		switch(archive_entry_filetype(entry)) {
		case AE_IFREG:
			if (archive_entry_size(entry) == 0) {
				/* More portable than "touch." */
				archive_string_sprintf(&shar->work,
				    "test -e \"%s\" || :> \"%s\"\n",
				    shar->quoted_name.s, shar->quoted_name.s);
			} else {
				if (shar->dump) {
					unsigned int mode = archive_entry_mode(entry) & 0777;
					archive_string_sprintf(&shar->work,
					    "uudecode -p > %s << 'SHAR_END'\n",
					    shar->quoted_name.s);
					archive_string_sprintf(&shar->work,
					    "begin %o ", mode);
					shar_quote(&shar->work, name, 0);
					archive_strcat(&shar->work, "\n");
				} else {
					archive_string_sprintf(&shar->work,
					    "sed 's/^X//' > %s << 'SHAR_END'\n",
					    shar->quoted_name.s);
				}
				shar->has_data = 1;
				shar->end_of_line = 1;
				shar->outpos = 0;
			}
			break;
		case AE_IFDIR:
			archive_string_sprintf(&shar->work,
			    "mkdir -p %s > /dev/null 2>&1\n",
			    shar->quoted_name.s);
			/* Record that we just created this directory. */
			if (shar->last_dir != NULL)
				free(shar->last_dir);

			shar->last_dir = strdup(name);
			/* Trim a trailing '/'. */
			pp = strrchr(shar->last_dir, '/');
			if (pp != NULL && pp[1] == '\0')
				*pp = '\0';
			/*
			 * TODO: Put dir name/mode on a list to be fixed
			 * up at end of archive.
			 */
			break;
		case AE_IFIFO:
			archive_string_sprintf(&shar->work,
			    "mkfifo %s\n", shar->quoted_name.s);
			break;
		case AE_IFCHR:
			archive_string_sprintf(&shar->work,
			    "mknod %s c %ju %ju\n", shar->quoted_name.s,
			    (uintmax_t)archive_entry_rdevmajor(entry),
			    (uintmax_t)archive_entry_rdevminor(entry));
			break;
		case AE_IFBLK:
			archive_string_sprintf(&shar->work,
			    "mknod %s b %ju %ju\n", shar->quoted_name.s,
			    (uintmax_t)archive_entry_rdevmajor(entry),
			    (uintmax_t)archive_entry_rdevminor(entry));
			break;
		default:
			return (ARCHIVE_WARN);
		}
	}

	return (ARCHIVE_OK);
}
Exemplo n.º 19
0
/*
 * Handle read modes: 'x', 't' and 'p'.
 */
static void
read_archive(struct bsdar *bsdar, char mode)
{
	struct archive		 *a;
	struct archive_entry	 *entry;
	struct stat		  sb;
	struct tm		 *tp;
	const char		 *bname;
	const char		 *name;
	mode_t			  md;
	size_t			  size;
	time_t			  mtime;
	uid_t			  uid;
	gid_t			  gid;
	char			**av;
	char			  buf[25];
	char			  find;
	int			  flags, r, i;

	if ((a = archive_read_new()) == NULL)
		bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed");
	archive_read_support_format_ar(a);
	AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ));

	for (;;) {
		r = archive_read_next_header(a, &entry);
		if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
		    r == ARCHIVE_FATAL)
			bsdar_warnc(bsdar, archive_errno(a), "%s",
			    archive_error_string(a));
		if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL)
			break;
		if (r == ARCHIVE_RETRY) {
			bsdar_warnc(bsdar, 0, "Retrying...");
			continue;
		}

		if ((name = archive_entry_pathname(entry)) == NULL)
			break;

		/* Skip pseudo members. */
		if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0 ||
		    strcmp(name, "/SYM64/") == 0)
			continue;

		if (bsdar->argc > 0) {
			find = 0;
			for(i = 0; i < bsdar->argc; i++) {
				av = &bsdar->argv[i];
				if (*av == NULL)
					continue;
				if ((bname = basename(*av)) == NULL)
					bsdar_errc(bsdar, EX_SOFTWARE, errno,
					    "basename failed");
				if (strcmp(bname, name) != 0)
					continue;

				*av = NULL;
				find = 1;
				break;
			}
			if (!find)
				continue;
		}

		if (mode == 't') {
			if (bsdar->options & AR_V) {
				md = archive_entry_mode(entry);
				uid = archive_entry_uid(entry);
				gid = archive_entry_gid(entry);
				size = archive_entry_size(entry);
				mtime = archive_entry_mtime(entry);
				(void)strmode(md, buf);
				(void)fprintf(stdout, "%s %6d/%-6d %8ju ",
				    buf + 1, uid, gid, (uintmax_t)size);
				tp = localtime(&mtime);
				(void)strftime(buf, sizeof(buf),
				    "%b %e %H:%M %Y", tp);
				(void)fprintf(stdout, "%s %s", buf, name);
			} else
				(void)fprintf(stdout, "%s", name);
			r = archive_read_data_skip(a);
			if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
			    r == ARCHIVE_FATAL) {
				(void)fprintf(stdout, "\n");
				bsdar_warnc(bsdar, archive_errno(a), "%s",
				    archive_error_string(a));
			}

			if (r == ARCHIVE_FATAL)
				break;

			(void)fprintf(stdout, "\n");
		} else {
			/* mode == 'x' || mode = 'p' */
			if (mode == 'p') {
				if (bsdar->options & AR_V) {
					(void)fprintf(stdout, "\n<%s>\n\n",
					    name);
					fflush(stdout);
				}
				r = archive_read_data_into_fd(a, 1);
			} else {
				/* mode == 'x' */
				if (stat(name, &sb) != 0) {
					if (errno != ENOENT) {
						bsdar_warnc(bsdar, 0,
						    "stat %s failed",
						    bsdar->filename);
						continue;
					}
				} else {
					/* stat success, file exist */
					if (bsdar->options & AR_CC)
						continue;
					if (bsdar->options & AR_U &&
					    archive_entry_mtime(entry) <=
					    sb.st_mtime)
						continue;
				}

				if (bsdar->options & AR_V)
					(void)fprintf(stdout, "x - %s\n", name);
				/* Disallow absolute paths. */
				if (name[0] == '/') {
					bsdar_warnc(bsdar, 0,
					    "Absolute path '%s'", name);
					continue;
				}
				/* Basic path security flags. */
				flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS |
				    ARCHIVE_EXTRACT_SECURE_NODOTDOT;
				if (bsdar->options & AR_O)
					flags |= ARCHIVE_EXTRACT_TIME;

				r = archive_read_extract(a, entry, flags);
			}

			if (r)
				bsdar_warnc(bsdar, archive_errno(a), "%s",
				    archive_error_string(a));
		}
	}
	AC(archive_read_close(a));
	AC(archive_read_free(a));
}
static int
archive_write_shar_finish_entry(struct archive_write *a)
{
	const char *g, *p, *u;
	struct shar *shar;
	int ret;

	shar = (struct shar *)a->format_data;
	if (shar->entry == NULL)
		return (0);

	if (shar->dump) {
		/* Finish uuencoded data. */
		if (shar->has_data) {
			if (shar->outpos > 0)
				uuencode_line(a, shar, shar->outbuff,
				    shar->outpos);
			archive_strcat(&shar->work, "`\nend\n");
			archive_strcat(&shar->work, "SHAR_END\n");
		}
		/* Restore file mode, owner, flags. */
		/*
		 * TODO: Don't immediately restore mode for
		 * directories; defer that to end of script.
		 */
		archive_string_sprintf(&shar->work, "chmod %o ",
		    (unsigned int)(archive_entry_mode(shar->entry) & 07777));
		shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1);
		archive_strcat(&shar->work, "\n");

		u = archive_entry_uname(shar->entry);
		g = archive_entry_gname(shar->entry);
		if (u != NULL || g != NULL) {
			archive_strcat(&shar->work, "chown ");
			if (u != NULL)
				shar_quote(&shar->work, u, 1);
			if (g != NULL) {
				archive_strcat(&shar->work, ":");
				shar_quote(&shar->work, g, 1);
			}
			archive_strcat(&shar->work, " ");
			shar_quote(&shar->work,
			    archive_entry_pathname(shar->entry), 1);
			archive_strcat(&shar->work, "\n");
		}

		if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
			archive_string_sprintf(&shar->work, "chflags %s ", p);
			shar_quote(&shar->work,
			    archive_entry_pathname(shar->entry), 1);
			archive_strcat(&shar->work, "\n");
		}

		/* TODO: restore ACLs */

	} else {
		if (shar->has_data) {
			/* Finish sed-encoded data:  ensure last line ends. */
			if (!shar->end_of_line)
				archive_strappend_char(&shar->work, '\n');
			archive_strcat(&shar->work, "SHAR_END\n");
		}
	}

	archive_entry_free(shar->entry);
	shar->entry = NULL;

	if (shar->work.length < 65536)
		return (ARCHIVE_OK);

	ret = __archive_write_output(a, shar->work.s, shar->work.length);
	if (ret != ARCHIVE_OK)
		return (ARCHIVE_FATAL);
	archive_string_empty(&shar->work);

	return (ARCHIVE_OK);
}
Exemplo n.º 21
0
static void
verify_contents(struct archive *a, int expect_details)
{
	char filedata[64];
	struct archive_entry *ae;

	/*
	 * Read and verify first file.
	 */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(1, archive_entry_mtime(ae));
	/* Zip doesn't store high-resolution mtime. */
	assertEqualInt(0, archive_entry_mtime_nsec(ae));
	assertEqualInt(0, archive_entry_atime(ae));
	assertEqualInt(0, archive_entry_ctime(ae));
	assertEqualString("file", archive_entry_pathname(ae));
	if (expect_details) {
		assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
		assertEqualInt(8, archive_entry_size(ae));
	} else {
		assertEqualInt(0, archive_entry_size(ae));
	}
	assertEqualIntA(a, 8,
	    archive_read_data(a, filedata, sizeof(filedata)));
	assertEqualMem(filedata, "12345678", 8);


	/*
	 * Read the second file back.
	 */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(1, archive_entry_mtime(ae));
	assertEqualInt(0, archive_entry_mtime_nsec(ae));
	assertEqualInt(0, archive_entry_atime(ae));
	assertEqualInt(0, archive_entry_ctime(ae));
	assertEqualString("file2", archive_entry_pathname(ae));
	if (expect_details) {
		assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae));
		assertEqualInt(4, archive_entry_size(ae));
	} else {
		assertEqualInt(0, archive_entry_size(ae));
	}
	assertEqualIntA(a, 4,
	    archive_read_data(a, filedata, sizeof(filedata)));
	assertEqualMem(filedata, "1234", 4);

	/*
	 * Read the third file back.
	 */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(1, archive_entry_mtime(ae));
	assertEqualInt(0, archive_entry_mtime_nsec(ae));
	assertEqualInt(0, archive_entry_atime(ae));
	assertEqualInt(0, archive_entry_ctime(ae));
	assertEqualString("symlink", archive_entry_pathname(ae));
	if (expect_details) {
		assertEqualInt(AE_IFLNK | 0755, archive_entry_mode(ae));
		assertEqualInt(0, archive_entry_size(ae));
		assertEqualString("file1", archive_entry_symlink(ae));
	} else {
		assertEqualInt(AE_IFREG | 0777, archive_entry_mode(ae));
		assertEqualInt(0, archive_entry_size(ae));
	}

	/*
	 * Read the dir entry back.
	 */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt(11, archive_entry_mtime(ae));
	assertEqualInt(0, archive_entry_mtime_nsec(ae));
	assertEqualInt(0, archive_entry_atime(ae));
	assertEqualInt(0, archive_entry_ctime(ae));
	assertEqualString("dir/", archive_entry_pathname(ae));
	if (expect_details)
		assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae));
	assertEqualInt(0, archive_entry_size(ae));
	assertEqualIntA(a, 0, archive_read_data(a, filedata, 10));

	/* Verify the end of the archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static int
archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
{
    struct cpio *cpio;
    const char *p, *path;
    int pathlength, ret;
    struct cpio_header_newc  h;
    int pad;

    cpio = (struct cpio *)a->format_data;
    ret = 0;

    path = archive_entry_pathname(entry);
    pathlength = strlen(path) + 1; /* Include trailing null. */

    memset(&h, 0, sizeof(h));
    format_hex(0x070701, &h.c_magic, sizeof(h.c_magic));
    format_hex(archive_entry_devmajor(entry), &h.c_devmajor, sizeof(h.c_devmajor));
    format_hex(archive_entry_devminor(entry), &h.c_devminor, sizeof(h.c_devminor));
    if (archive_entry_ino64(entry) > 0xffffffff) {
        archive_set_error(&a->archive, ERANGE, "large inode number truncated");
        ret = ARCHIVE_WARN;
    }

    format_hex(archive_entry_ino64(entry) & 0xffffffff, &h.c_ino, sizeof(h.c_ino));
    format_hex(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode));
    format_hex(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid));
    format_hex(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid));
    format_hex(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink));
    if (archive_entry_filetype(entry) == AE_IFBLK
        || archive_entry_filetype(entry) == AE_IFCHR) {
        format_hex(archive_entry_rdevmajor(entry), &h.c_rdevmajor, sizeof(h.c_rdevmajor));
        format_hex(archive_entry_rdevminor(entry), &h.c_rdevminor, sizeof(h.c_rdevminor));
    } else {
        format_hex(0, &h.c_rdevmajor, sizeof(h.c_rdevmajor));
        format_hex(0, &h.c_rdevminor, sizeof(h.c_rdevminor));
    }
    format_hex(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
    format_hex(pathlength, &h.c_namesize, sizeof(h.c_namesize));
    format_hex(0, &h.c_checksum, sizeof(h.c_checksum));

    /* Non-regular files don't store bodies. */
    if (archive_entry_filetype(entry) != AE_IFREG)
        archive_entry_set_size(entry, 0);

    /* Symlinks get the link written as the body of the entry. */
    p = archive_entry_symlink(entry);
    if (p != NULL  &&  *p != '\0')
        format_hex(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
    else
        format_hex(archive_entry_size(entry),
            &h.c_filesize, sizeof(h.c_filesize));

    ret = (a->compressor.write)(a, &h, sizeof(h));
    if (ret != ARCHIVE_OK)
        return (ARCHIVE_FATAL);

    /* Pad pathname to even length. */
    ret = (a->compressor.write)(a, path, pathlength);
    if (ret != ARCHIVE_OK)
        return (ARCHIVE_FATAL);
    pad = PAD4(pathlength + sizeof(struct cpio_header_newc));
    if (pad)
        ret = (a->compressor.write)(a, "\0\0\0", pad);
    if (ret != ARCHIVE_OK)
        return (ARCHIVE_FATAL);

    cpio->entry_bytes_remaining = archive_entry_size(entry);
    cpio->padding = PAD4(cpio->entry_bytes_remaining);

    /* Write the symlink now. */
    if (p != NULL  &&  *p != '\0') {
        ret = (a->compressor.write)(a, p, strlen(p));
        if (ret != ARCHIVE_OK)
            return (ARCHIVE_FATAL);
        pad = PAD4(strlen(p));
        ret = (a->compressor.write)(a, "\0\0\0", pad);
    }

    return (ret);
}
Exemplo n.º 23
0
static void
test_unicode_CP932(void)
{
  char buff[30];
  const char reffile[] = "test_read_format_rar_unicode.rar";
  const char test_txt[] = "kanji";
  struct archive_entry *ae;
  struct archive *a;

  if (NULL == setlocale(LC_ALL, "Japanese_Japan") &&
    NULL == setlocale(LC_ALL, "ja_JP.SJIS")) {
	skipping("CP932 locale not available on this system.");
	return;
  }

  extract_reference_file(reffile);
  assert((a = archive_read_new()) != NULL);
  assertA(0 == archive_read_support_filter_all(a));
  assertA(0 == archive_read_support_format_all(a));
  /* Specify the charset of symbolic-link file name. */
  if (ARCHIVE_OK != archive_read_set_options(a, "rar:hdrcharset=UTF-8")) {
	skipping("This system cannot convert character-set"
	    " from UTF-8 to CP932.");
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
	return;
  }
  assertA(0 == archive_read_open_file(a, reffile, 10240));

  /* First header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("\x95\x5c\x82\xbe\x82\xe6/\x90\x56\x82\xb5\x82\xa2"
      "\x83\x74\x83\x48\x83\x8b\x83\x5f/\x90\x56\x8b\x4b\x83\x65\x83\x4c"
      "\x83\x58\x83\x67 \x83\x68\x83\x4c\x83\x85\x83\x81\x83\x93\x83\x67.txt",
      archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));

  /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("\x95\x5c\x82\xbe\x82\xe6/\x8a\xbf\x8e\x9a"
      "\x92\xb7\x82\xa2\x83\x74\x83\x40\x83\x43\x83\x8b\x96\xbc\x6c"
      "\x6f\x6e\x67\x2d\x66\x69\x6c\x65\x6e\x61\x6d\x65\x2d\x69\x6e"
      "\x2d\x8a\xbf\x8e\x9a.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(5, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(5 == archive_read_data(a, buff, 5));
  assertEqualMem(buff, test_txt, 5);

  /* Third header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("\x95\x5c\x82\xbe\x82\xe6/"
      "\x90\x56\x82\xb5\x82\xa2\x83\x74\x83\x48\x83\x8b\x83\x5f",
      archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fourth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("\x95\x5c\x82\xbe\x82\xe6", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fifth header, which has a symbolic-link name in multi-byte characters. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("\x95\x5c\x82\xbe\x82\xe6/"
      "\x83\x74\x83\x40\x83\x43\x83\x8B", archive_entry_pathname(ae));
  assertEqualString("\x8a\xbf\x8e\x9a"
      "\x92\xb7\x82\xa2\x83\x74\x83\x40\x83\x43\x83\x8b\x96\xbc\x6c"
      "\x6f\x6e\x67\x2d\x66\x69\x6c\x65\x6e\x61\x6d\x65\x2d\x69\x6e"
      "\x2d\x8a\xbf\x8e\x9a.txt", archive_entry_symlink(ae));
  assertA((int)archive_entry_mtime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(41453, archive_entry_mode(ae));
  assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff)));

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Exemplo n.º 24
0
static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
		struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
{
	const char *entryname = archive_entry_pathname(entry);
	mode_t entrymode = archive_entry_mode(entry);
	alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg);
	char filename[PATH_MAX]; /* the actual file we're extracting */
	int needbackup = 0, notouch = 0;
	const char *hash_orig = NULL;
	int isnewfile = 0, errors = 0;
	struct stat lsbuf;
	size_t filename_len;

	if(*entryname == '.') {
		return extract_db_file(handle, archive, entry, newpkg, entryname);
	}

	if (!alpm_filelist_contains(&newpkg->files, entryname)) {
		_alpm_log(handle, ALPM_LOG_WARNING,
				_("file not found in file list for package %s. skipping extraction of %s\n"),
				newpkg->name, entryname);
		return 0;
	}

	/* build the new entryname relative to handle->root */
	filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
	if(filename_len >= PATH_MAX) {
		_alpm_log(handle, ALPM_LOG_ERROR,
				_("unable to extract %s%s: path too long"), handle->root, entryname);
		return 1;
	}

	/* if a file is in NoExtract then we never extract it */
	if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract,"
				" skipping extraction of %s\n",
				entryname, filename);
		archive_read_data_skip(archive);
		return 0;
	}

	/* Check for file existence. This is one of the more crucial parts
	 * to get 'right'. Here are the possibilities, with the filesystem
	 * on the left and the package on the top:
	 * (F=file, N=node, S=symlink, D=dir)
	 *               |  F/N  |   D
	 *  non-existent |   1   |   2
	 *  F/N          |   3   |   4
	 *  D            |   5   |   6
	 *
	 *  1,2- extract, no magic necessary. lstat (llstat) will fail here.
	 *  3,4- conflict checks should have caught this. either overwrite
	 *      or backup the file.
	 *  5- file replacing directory- don't allow it.
	 *  6- skip extraction, dir already exists.
	 */

	isnewfile = llstat(filename, &lsbuf) != 0;
	if(isnewfile) {
		/* cases 1,2: file doesn't exist, skip all backup checks */
	} else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) {
#if 0
		uid_t entryuid = archive_entry_uid(entry);
		gid_t entrygid = archive_entry_gid(entry);
#endif

		/* case 6: existing dir, ignore it */
		if(lsbuf.st_mode != entrymode) {
			/* if filesystem perms are different than pkg perms, warn user */
			mode_t mask = 07777;
			_alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
					"filesystem: %o  package: %o\n"), filename, lsbuf.st_mode & mask,
					entrymode & mask);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: directory permissions differ on %s\n"
					"filesystem: %o  package: %o\n", filename, lsbuf.st_mode & mask,
					entrymode & mask);
		}
#ifndef __MSYS__

#if 0
		/* Disable this warning until our user management in packages has improved.
		   Currently many packages have to create users in post_install and chown the
		   directories. These all resulted in "false-positive" warnings. */

		if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) {
			_alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n"
					"filesystem: %u:%u  package: %u:%u\n"), filename,
					lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: directory ownership differs on %s\n"
					"filesystem: %u:%u  package: %u:%u\n", filename,
					lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
		}
#endif

#endif
		_alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
				filename);
		archive_read_data_skip(archive);
		return 0;
	} else if(S_ISDIR(lsbuf.st_mode)) {
		/* case 5: trying to overwrite dir with file, don't allow it */
		_alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
				filename);
		archive_read_data_skip(archive);
		return 1;
	} else if(S_ISDIR(entrymode)) {
		/* case 4: trying to overwrite file with dir */
		_alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
				filename);
	} else {
		/* case 3: trying to overwrite file with file */
		/* if file is in NoUpgrade, don't touch it */
		if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) {
			notouch = 1;
		} else {
			alpm_backup_t *oldbackup;
			if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) {
				hash_orig = oldbackup->hash;
				needbackup = 1;
			} else if(backup) {
				/* allow adding backup files retroactively */
				needbackup = 1;
			}
		}
	}

	if(notouch || needbackup) {
		if(filename_len + strlen(".pacnew") >= PATH_MAX) {
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("unable to extract %s.pacnew: path too long"), filename);
			return 1;
		}
		strcpy(filename + filename_len, ".pacnew");
		isnewfile = (llstat(filename, &lsbuf) != 0 && errno == ENOENT);
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
	if(perform_extraction(handle, archive, entry, filename)) {
		errors++;
		return errors;
	}

	if(backup) {
		FREE(backup->hash);
		backup->hash = alpm_compute_md5sum(filename);
	}

	if(notouch) {
		alpm_event_pacnew_created_t event = {
			.type = ALPM_EVENT_PACNEW_CREATED,
			.from_noupgrade = 1,
			.oldpkg = oldpkg,
			.newpkg = newpkg,
			.file = filename
		};
		/* "remove" the .pacnew suffix */
		filename[filename_len] = '\0';
		EVENT(handle, &event);
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"warning: %s installed as %s.pacnew\n", filename, filename);
	} else if(needbackup) {
		char *hash_local = NULL, *hash_pkg = NULL;
		char origfile[PATH_MAX] = "";

		strncat(origfile, filename, filename_len);

		hash_local = alpm_compute_md5sum(origfile);
		hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename);

		_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile);
		_alpm_log(handle, ALPM_LOG_DEBUG, "current:  %s\n", hash_local);
		_alpm_log(handle, ALPM_LOG_DEBUG, "new:      %s\n", hash_pkg);
		_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);

		if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
			/* local and new files are the same, updating anyway to get
			 * correct timestamps */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					origfile);
			if(try_rename(handle, filename, origfile)) {
				errors++;
			}
		} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
			/* original and new files are the same, leave the local version alone,
			 * including any user changes */
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"action: leaving existing file in place\n");
			if(isnewfile) {
				unlink(filename);
			}
		} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
			/* installed file has NOT been changed by user,
			 * update to the new version */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					origfile);
			if(try_rename(handle, filename, origfile)) {
				errors++;
			}
		} else {
			/* none of the three files matched another,  leave the unpacked
			 * file alongside the local file */
			alpm_event_pacnew_created_t event = {
				.type = ALPM_EVENT_PACNEW_CREATED,
				.from_noupgrade = 0,
				.oldpkg = oldpkg,
				.newpkg = newpkg,
				.file = origfile
			};
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"action: keeping current file and installing"
					" new one with .pacnew ending\n");
			EVENT(handle, &event);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: %s installed as %s\n", origfile, filename);
		}

		free(hash_local);
		if(!backup) {
			free(hash_pkg);
		}
	}
	return errors;
}

static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
		size_t pkg_current, size_t pkg_count)
{
	int i, ret = 0, errors = 0;
	int is_upgrade = 0;
	alpm_pkg_t *oldpkg = NULL;
	alpm_db_t *db = handle->db_local;
	alpm_trans_t *trans = handle->trans;
	alpm_progress_t progress = ALPM_PROGRESS_ADD_START;
	alpm_event_package_operation_t event;
	const char *log_msg = "adding";
	const char *pkgfile;

	ASSERT(trans != NULL, return -1);

	/* see if this is an upgrade. if so, remove the old package first */
	if((oldpkg = newpkg->oldpkg)) {
		int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg);
		if(cmp < 0) {
			log_msg = "downgrading";
			progress = ALPM_PROGRESS_DOWNGRADE_START;
			event.operation = ALPM_PACKAGE_DOWNGRADE;
		} else if(cmp == 0) {
			log_msg = "reinstalling";
			progress = ALPM_PROGRESS_REINSTALL_START;
			event.operation = ALPM_PACKAGE_REINSTALL;
		} else {
			log_msg = "upgrading";
			progress = ALPM_PROGRESS_UPGRADE_START;
			event.operation = ALPM_PACKAGE_UPGRADE;
		}
		is_upgrade = 1;

		/* copy over the install reason */
		newpkg->reason = alpm_pkg_get_reason(oldpkg);
	} else {
		event.operation = ALPM_PACKAGE_INSTALL;
	}

	event.type = ALPM_EVENT_PACKAGE_OPERATION_START;
	event.oldpkg = oldpkg;
	event.newpkg = newpkg;
	EVENT(handle, &event);

	pkgfile = newpkg->origin_data.file;

	_alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n",
			log_msg, newpkg->name, newpkg->version);
		/* pre_install/pre_upgrade scriptlet */
	if(alpm_pkg_has_scriptlet(newpkg) &&
			!(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
		const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";

		_alpm_runscriptlet(handle, pkgfile, scriptlet_name,
				newpkg->version, oldpkg ? oldpkg->version : NULL, 1);
	}

	/* we override any pre-set reason if we have alldeps or allexplicit set */
	if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) {
		newpkg->reason = ALPM_PKG_REASON_DEPEND;
	} else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) {
		newpkg->reason = ALPM_PKG_REASON_EXPLICIT;
	}

	if(oldpkg) {
		/* set up fake remove transaction */
		if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) {
			handle->pm_errno = ALPM_ERR_TRANS_ABORT;
			ret = -1;
			goto cleanup;
		}
	}

	/* prepare directory for database entries so permission are correct after
	   changelog/install script installation */
	if(_alpm_local_db_prepare(db, newpkg)) {
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"error: could not create database entry %s-%s\n",
				newpkg->name, newpkg->version);
		handle->pm_errno = ALPM_ERR_DB_WRITE;
		ret = -1;
		goto cleanup;
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
		struct archive *archive;
		struct archive_entry *entry;
		struct stat buf;
		int fd, cwdfd;

		_alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");

		fd = _alpm_open_archive(db->handle, pkgfile, &buf,
				&archive, ALPM_ERR_PKG_OPEN);
		if(fd < 0) {
			ret = -1;
			goto cleanup;
		}

		/* save the cwd so we can restore it later */
		OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC);
		if(cwdfd < 0) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
		}

		/* libarchive requires this for extracting hard links */
		if(chdir(handle->root) != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
					handle->root, strerror(errno));
			_alpm_archive_read_free(archive);
			close(fd);
			ret = -1;
			goto cleanup;
		}

		/* call PROGRESS once with 0 percent, as we sort-of skip that here */
		PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current);

		for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
			int percent;

			if(newpkg->size != 0) {
				/* Using compressed size for calculations here, as newpkg->isize is not
				 * exact when it comes to comparing to the ACTUAL uncompressed size
				 * (missing metadata sizes) */
				int64_t pos = _alpm_archive_compressed_ftell(archive);
				percent = (pos * 100) / newpkg->size;
				if(percent >= 100) {
					percent = 100;
				}
			} else {
				percent = 0;
			}

			PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current);

			/* extract the next file from the archive */
			errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
		}
		_alpm_archive_read_free(archive);
		close(fd);

		/* restore the old cwd if we have it */
		if(cwdfd >= 0) {
			if(fchdir(cwdfd) != 0) {
				_alpm_log(handle, ALPM_LOG_ERROR,
						_("could not restore working directory (%s)\n"), strerror(errno));
			}
			close(cwdfd);
		}

		if(errors) {
			ret = -1;
			if(is_upgrade) {
				_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
						newpkg->name);
				alpm_logaction(handle, ALPM_CALLER_PREFIX,
						"error: problem occurred while upgrading %s\n",
						newpkg->name);
			} else {
				_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"),
						newpkg->name);
				alpm_logaction(handle, ALPM_CALLER_PREFIX,
						"error: problem occurred while installing %s\n",
						newpkg->name);
			}
		}
	}

	/* make an install date (in UTC) */
	newpkg->installdate = time(NULL);

	_alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n");
	_alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);

	if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"),
				newpkg->name, newpkg->version);
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"error: could not update database entry %s-%s\n",
				newpkg->name, newpkg->version);
		handle->pm_errno = ALPM_ERR_DB_WRITE;
		ret = -1;
		goto cleanup;
	}

	if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
				newpkg->name);
	}

	PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current);

	switch(event.operation) {
		case ALPM_PACKAGE_INSTALL:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n",
					newpkg->name, newpkg->version);
			break;
		case ALPM_PACKAGE_DOWNGRADE:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n",
					newpkg->name, oldpkg->version, newpkg->version);
			break;
		case ALPM_PACKAGE_REINSTALL:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n",
					newpkg->name, newpkg->version);
			break;
		case ALPM_PACKAGE_UPGRADE:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n",
					newpkg->name, oldpkg->version, newpkg->version);
			break;
		default:
			/* we should never reach here */
			break;
	}

	/* run the post-install script if it exists */
	if(alpm_pkg_has_scriptlet(newpkg)
			&& !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
		char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
		const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";

		_alpm_runscriptlet(handle, scriptlet, scriptlet_name,
				newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
		free(scriptlet);
	}

	event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE;
	EVENT(handle, &event);

cleanup:
	return ret;
}
Exemplo n.º 25
0
static void
test_sfx(void)
{
  char buff[441];
  const char reffile[] = "test_read_format_rar_sfx.exe";
  const char test_txt[] = "test text file\r\n";
  int size = sizeof(test_txt)-1;
  struct archive_entry *ae;
  struct archive *a;

  extract_reference_file(reffile);
  assert((a = archive_read_new()) != NULL);
  assertA(0 == archive_read_support_filter_all(a));
  assertA(0 == archive_read_support_format_all(a));
  assertA(0 == archive_read_open_file(a, reffile, 10240));

  /* First header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("test.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(16, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(size == archive_read_data(a, buff, size));
  assertEqualMem(buff, test_txt, size);

  /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testshortcut.lnk", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(sizeof(buff), archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(sizeof(buff) == archive_read_data(a, buff, sizeof(buff)));

  /* Third header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir/test.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(16, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(size == archive_read_data(a, buff, size));
  assertEqualMem(buff, test_txt, size);

  /* Fourth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fifth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testemptydir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Exemplo n.º 26
0
/*
 * Extract a regular file.
 */
static void
extract_file(struct archive *a, struct archive_entry *e, char **path)
{
	int mode;
	time_t mtime;
	struct stat sb;
	struct timeval tv[2];
	int cr, fd, text, warn, check;
	ssize_t len;
	unsigned char *p, *q, *end;

	mode = archive_entry_mode(e) & 0777;
	if (mode == 0)
		mode = 0644;
	mtime = archive_entry_mtime(e);

	/* look for existing file of same name */
recheck:
	if (lstat(*path, &sb) == 0) {
		if (u_opt || f_opt) {
			/* check if up-to-date */
			if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
				return;
			(void)unlink(*path);
		} else if (o_opt) {
			/* overwrite */
			(void)unlink(*path);
		} else if (n_opt) {
			/* do not overwrite */
			return;
		} else {
			check = handle_existing_file(path);
			if (check == 0)
				goto recheck;
			if (check == -1)
				return; /* do not overwrite */
		}
	} else {
		if (f_opt)
			return;
	}

	if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
		error("open('%s')", *path);

	/* loop over file contents and write to disk */
	info(" extracting: %s", *path);
	text = a_opt;
	warn = 0;
	cr = 0;
	for (int n = 0; ; n++) {
		if (tty && (n % 4) == 0)
			info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);

		len = archive_read_data(a, buffer, sizeof buffer);

		if (len < 0)
			ac(len);

		/* left over CR from previous buffer */
		if (a_opt && cr) {
			if (len == 0 || buffer[0] != '\n')
				if (write(fd, "\r", 1) != 1)
					error("write('%s')", *path);
			cr = 0;
		}

		/* EOF */
		if (len == 0)
			break;
		end = buffer + len;

		/*
		 * Detect whether this is a text file.  The correct way to
		 * do this is to check the least significant bit of the
		 * "internal file attributes" field of the corresponding
		 * file header in the central directory, but libarchive
		 * does not read the central directory, so we have to
		 * guess by looking for non-ASCII characters in the
		 * buffer.  Hopefully we won't guess wrong.  If we do
		 * guess wrong, we print a warning message later.
		 */
		if (a_opt && n == 0) {
			for (p = buffer; p < end; ++p) {
				if (!isascii((unsigned char)*p)) {
					text = 0;
					break;
				}
			}
		}

		/* simple case */
		if (!a_opt || !text) {
			if (write(fd, buffer, len) != len)
				error("write('%s')", *path);
			continue;
		}

		/* hard case: convert \r\n to \n (sigh...) */
		for (p = buffer; p < end; p = q + 1) {
			for (q = p; q < end; q++) {
				if (!warn && !isascii(*q)) {
					warningx("%s may be corrupted due"
					    " to weak text file detection"
					    " heuristic", *path);
					warn = 1;
				}
				if (q[0] != '\r')
					continue;
				if (&q[1] == end) {
					cr = 1;
					break;
				}
				if (q[1] == '\n')
					break;
			}
			if (write(fd, p, q - p) != q - p)
				error("write('%s')", *path);
		}
	}
	if (tty)
		info("  \b\b");
	if (text)
		info(" (text)");
	info("\n");

	/* set access and modification time */
	tv[0].tv_sec = now;
	tv[0].tv_usec = 0;
	tv[1].tv_sec = mtime;
	tv[1].tv_usec = 0;
	if (futimes(fd, tv) != 0)
		error("utimes('%s')", *path);
	if (close(fd) != 0)
		error("close('%s')", *path);
}
Exemplo n.º 27
0
const struct stat *
archive_entry_stat(struct archive_entry *entry)
{
	struct stat *st;
	if (entry->stat == NULL) {
		entry->stat = calloc(1, sizeof(*st));
		if (entry->stat == NULL)
			return (NULL);
		entry->stat_valid = 0;
	}

	/*
	 * If none of the underlying fields have been changed, we
	 * don't need to regenerate.  In theory, we could use a bitmap
	 * here to flag only those items that have changed, but the
	 * extra complexity probably isn't worth it.  It will be very
	 * rare for anyone to change just one field then request a new
	 * stat structure.
	 */
	if (entry->stat_valid)
		return (entry->stat);

	st = entry->stat;
	/*
	 * Use the public interfaces to extract items, so that
	 * the appropriate conversions get invoked.
	 */
	st->st_atime = archive_entry_atime(entry);
#if HAVE_STRUCT_STAT_ST_BIRTHTIME
	st->st_birthtime = archive_entry_birthtime(entry);
#endif
	st->st_ctime = archive_entry_ctime(entry);
	st->st_mtime = archive_entry_mtime(entry);
	st->st_dev = archive_entry_dev(entry);
	st->st_gid = archive_entry_gid(entry);
	st->st_uid = archive_entry_uid(entry);
	st->st_ino = archive_entry_ino64(entry);
	st->st_nlink = archive_entry_nlink(entry);
	st->st_rdev = archive_entry_rdev(entry);
	st->st_size = archive_entry_size(entry);
	st->st_mode = archive_entry_mode(entry);

	/*
	 * On systems that support high-res timestamps, copy that
	 * information into struct stat.
	 */
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
	st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry);
	st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry);
	st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry);
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
	st->st_atim.tv_nsec = archive_entry_atime_nsec(entry);
	st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry);
	st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
	st->st_atime_n = archive_entry_atime_nsec(entry);
	st->st_ctime_n = archive_entry_ctime_nsec(entry);
	st->st_mtime_n = archive_entry_mtime_nsec(entry);
#elif HAVE_STRUCT_STAT_ST_UMTIME
	st->st_uatime = archive_entry_atime_nsec(entry) / 1000;
	st->st_uctime = archive_entry_ctime_nsec(entry) / 1000;
	st->st_umtime = archive_entry_mtime_nsec(entry) / 1000;
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
	st->st_atime_usec = archive_entry_atime_nsec(entry) / 1000;
	st->st_ctime_usec = archive_entry_ctime_nsec(entry) / 1000;
	st->st_mtime_usec = archive_entry_mtime_nsec(entry) / 1000;
#endif
#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
	st->st_birthtimespec.tv_nsec = archive_entry_birthtime_nsec(entry);
#endif

	/*
	 * TODO: On Linux, store 32 or 64 here depending on whether
	 * the cached stat structure is a stat32 or a stat64.  This
	 * will allow us to support both variants interchangeably.
	 */
	entry->stat_valid = 1;

	return (st);
}
Exemplo n.º 28
0
/*
 * test_compat_gtar_1.tgz exercises reading long filenames and
 * symlink targets stored in the GNU tar format.
 */
static void
test_compat_gtar_1(void)
{
	char name[] = "test_compat_gtar_1.tar";
	struct archive_entry *ae;
	struct archive *a;
	int r;

	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	extract_reference_file(name);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));

	/* Read first entry. */
	assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
	if (r != ARCHIVE_OK) {
		archive_read_free(a);
		return;
	}
	assertEqualString(
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890",
		archive_entry_pathname(ae));
	assertEqualInt(1197179003, archive_entry_mtime(ae));
	assertEqualInt(1000, archive_entry_uid(ae));
	assertEqualString("tim", archive_entry_uname(ae));
	assertEqualInt(1000, archive_entry_gid(ae));
	assertEqualString("tim", archive_entry_gname(ae));
	assertEqualInt(0100644, archive_entry_mode(ae));

	/* Read second entry. */
	assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
	if (r != ARCHIVE_OK) {
		archive_read_free(a);
		return;
	}
	assertEqualString(
		"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"
		"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"
		"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"
		"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij",
		archive_entry_pathname(ae));
	assertEqualString(
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890"
		"12345678901234567890123456789012345678901234567890",
		archive_entry_symlink(ae));
	assertEqualInt(1197179043, archive_entry_mtime(ae));
	assertEqualInt(1000, archive_entry_uid(ae));
	assertEqualString("tim", archive_entry_uname(ae));
	assertEqualInt(1000, archive_entry_gid(ae));
	assertEqualString("tim", archive_entry_gname(ae));
	assertEqualInt(0120755, archive_entry_mode(ae));

	/* Verify the end-of-archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	/* Verify that the format detection worked. */
	assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
	assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);

	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static int
write_header(struct archive_write *a, struct archive_entry *entry)
{
	int64_t ino;
	struct cpio *cpio;
	const char *p, *path;
	int pathlength, ret, ret_final;
	char h[c_header_size];
	struct archive_string_conv *sconv;
	struct archive_entry *entry_main;
	size_t len;
	int pad;

	cpio = (struct cpio *)a->format_data;
	ret_final = ARCHIVE_OK;
	sconv = get_sconv(a);

#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 ustar data");
		return(ARCHIVE_FATAL);
	}
	if (entry != entry_main)
		entry = entry_main;
	else
		entry_main = NULL;
#else
	entry_main = NULL;
#endif

	ret = archive_entry_pathname_l(entry, &path, &len, sconv);
	if (ret != 0) {
		if (errno == ENOMEM) {
			archive_set_error(&a->archive, ENOMEM,
			    "Can't allocate memory for Pathname");
			ret_final = 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));
		ret_final = ARCHIVE_WARN;
	}
	pathlength = (int)len + 1; /* Include trailing null. */

	memset(h, 0, c_header_size);
	format_hex(0x070701, h + c_magic_offset, c_magic_size);
	format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset,
	    c_devmajor_size);
	format_hex(archive_entry_devminor(entry), h + c_devminor_offset,
	    c_devminor_size);

	ino = archive_entry_ino64(entry);
	if (ino > 0xffffffff) {
		archive_set_error(&a->archive, ERANGE,
		    "large inode number truncated");
		ret_final = ARCHIVE_WARN;
	}

	/* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
	format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size);
	format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
	format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
	format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
	format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
	if (archive_entry_filetype(entry) == AE_IFBLK
	    || archive_entry_filetype(entry) == AE_IFCHR) {
	    format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size);
	    format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size);
	} else {
	    format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size);
	    format_hex(0, h + c_rdevminor_offset, c_rdevminor_size);
	}
	format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
	format_hex(pathlength, h + c_namesize_offset, c_namesize_size);
	format_hex(0, h + c_checksum_offset, c_checksum_size);

	/* Non-regular files don't store bodies. */
	if (archive_entry_filetype(entry) != AE_IFREG)
		archive_entry_set_size(entry, 0);

	/* Symlinks get the link written as the body of the entry. */
	ret = archive_entry_symlink_l(entry, &p, &len, sconv);
	if (ret != 0) {
		if (errno == ENOMEM) {
			archive_set_error(&a->archive, ENOMEM,
			    "Can't allocate memory for Likname");
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
		    "Can't translate linkname '%s' to %s",
		    archive_entry_symlink(entry),
		    archive_string_conversion_charset_name(sconv));
		ret_final = ARCHIVE_WARN;
	}
	if (len > 0 && p != NULL  &&  *p != '\0')
		ret = format_hex(strlen(p), h + c_filesize_offset,
		    c_filesize_size);
	else
		ret = format_hex(archive_entry_size(entry),
		    h + c_filesize_offset, c_filesize_size);
	if (ret) {
		archive_set_error(&a->archive, ERANGE,
		    "File is too large for this format.");
		ret_final = ARCHIVE_FAILED;
		goto exit_write_header;
	}

	ret = __archive_write_output(a, h, c_header_size);
	if (ret != ARCHIVE_OK) {
		ret_final = ARCHIVE_FATAL;
		goto exit_write_header;
	}

	/* Pad pathname to even length. */
	ret = __archive_write_output(a, path, pathlength);
	if (ret != ARCHIVE_OK) {
		ret_final = ARCHIVE_FATAL;
		goto exit_write_header;
	}
	pad = PAD4(pathlength + c_header_size);
	if (pad) {
		ret = __archive_write_output(a, "\0\0\0", pad);
		if (ret != ARCHIVE_OK) {
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
	}

	cpio->entry_bytes_remaining = archive_entry_size(entry);
	cpio->padding = (int)PAD4(cpio->entry_bytes_remaining);

	/* Write the symlink now. */
	if (p != NULL  &&  *p != '\0') {
		ret = __archive_write_output(a, p, strlen(p));
		if (ret != ARCHIVE_OK) {
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
		pad = PAD4(strlen(p));
		ret = __archive_write_output(a, "\0\0\0", pad);
		if (ret != ARCHIVE_OK) {
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
	}
exit_write_header:
	if (entry_main)
		archive_entry_free(entry_main);
	return (ret_final);
}
Exemplo n.º 30
0
/** Unpack a list of files in an archive.
 * @param handle the context handle
 * @param path the archive to unpack
 * @param prefix where to extract the files
 * @param list a list of files within the archive to unpack or NULL for all
 * @param breakfirst break after the first entry found
 * @return 0 on success, 1 on failure
 */
int _alpm_unpack(alpm_handle_t *handle, const char *path, const char *prefix,
		alpm_list_t *list, int breakfirst)
{
	int ret = 0;
	mode_t oldmask;
	struct archive *archive;
	struct archive_entry *entry;
	struct stat buf;
	int fd, cwdfd;

	fd = _alpm_open_archive(handle, path, &buf, &archive, ALPM_ERR_PKG_OPEN);
	if(fd < 0) {
		return 1;
	}

	oldmask = umask(0022);

	/* save the cwd so we can restore it later */
	OPEN(cwdfd, ".", O_RDONLY);
	if(cwdfd < 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
	}

	/* just in case our cwd was removed in the upgrade operation */
	if(chdir(prefix) != 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
				prefix, strerror(errno));
		ret = 1;
		goto cleanup;
	}

	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
		const char *entryname;
		mode_t mode;

		entryname = archive_entry_pathname(entry);

		/* If specific files were requested, skip entries that don't match. */
		if(list) {
			char *entry_prefix = strdup(entryname);
			char *p = strstr(entry_prefix,"/");
			if(p) {
				*(p+1) = '\0';
			}
			char *found = alpm_list_find_str(list, entry_prefix);
			free(entry_prefix);
			if(!found) {
				if(archive_read_data_skip(archive) != ARCHIVE_OK) {
					ret = 1;
					goto cleanup;
				}
				continue;
			} else {
				_alpm_log(handle, ALPM_LOG_DEBUG, "extracting: %s\n", entryname);
			}
		}

		mode = archive_entry_mode(entry);
		if(S_ISREG(mode)) {
			archive_entry_set_perm(entry, 0644);
		} else if(S_ISDIR(mode)) {
			archive_entry_set_perm(entry, 0755);
		}

		/* Extract the archive entry. */
		int readret = archive_read_extract(archive, entry, 0);
		if(readret == ARCHIVE_WARN) {
			/* operation succeeded but a non-critical error was encountered */
			_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
					entryname, archive_error_string(archive));
		} else if(readret != ARCHIVE_OK) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
					entryname, archive_error_string(archive));
			ret = 1;
			goto cleanup;
		}

		if(breakfirst) {
			break;
		}
	}

cleanup:
	umask(oldmask);
	archive_read_finish(archive);
	CLOSE(fd);
	if(cwdfd >= 0) {
		if(fchdir(cwdfd) != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("could not restore working directory (%s)\n"), strerror(errno));
		}
		CLOSE(cwdfd);
	}

	return ret;
}