Example #1
0
static void DTAR_write_header(struct archive* ar, uint64_t idx, uint64_t offset)
{
    /* allocate and entry for this item */
    struct archive_entry* entry = archive_entry_new();

    /* get file name for this item */
    /* fill up entry, FIXME: the uglyness of removing leading slash */
    const char* fname = mfu_flist_file_get_name(DTAR_flist, idx);
    archive_entry_copy_pathname(entry, &fname[1]);

    if (DTAR_user_opts.preserve) {
        struct archive* source = archive_read_disk_new();
        archive_read_disk_set_standard_lookup(source);
        int fd = open(fname, O_RDONLY);
        if (archive_read_disk_entry_from_file(source, entry, fd, NULL) != ARCHIVE_OK) {
            MFU_LOG(MFU_LOG_ERR, "archive_read_disk_entry_from_file(): %s", archive_error_string(ar));
        }
        archive_read_free(source);
        close(fd);
    } else {
        /* TODO: read stat info from mfu_flist */
        struct stat stbuf;
        mfu_lstat(fname, &stbuf);
        archive_entry_copy_stat(entry, &stbuf);

        /* set user name of owner */
        const char* uname = mfu_flist_file_get_username(DTAR_flist, idx);
        archive_entry_set_uname(entry, uname);

        /* set group name */
        const char* gname = mfu_flist_file_get_groupname(DTAR_flist, idx);
        archive_entry_set_gname(entry, gname);
    }

    /* TODO: Seems to be a bug here potentially leading to corrupted
     * archive files.  archive_write_free also writes two blocks of
     * NULL bytes at the end of an archive file, however, each rank
     * will have a different view of the length of the file, so one
     * rank may write its NULL blocks over top of the actual data
     * written by another rank */

    /* write entry info to archive */
    struct archive* dest = archive_write_new();
    archive_write_set_format_pax(dest);

    if (archive_write_open_fd(dest, DTAR_writer.fd_tar) != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_open_fd(): %s", archive_error_string(ar));
    }

    /* seek to offset in tar archive for this file */
    lseek(DTAR_writer.fd_tar, offset, SEEK_SET);

    /* write header for this item */
    if (archive_write_header(dest, entry) != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_header(): %s", archive_error_string(ar));
    }

    archive_entry_free(entry);
    archive_write_free(dest);
}
Example #2
0
void Writer::set_format_helper(struct archive *ar, int format)
{
    std::string error_msg;

    switch(format) {
        case Archive::FORMAT_AR_BSD:
            archive_write_set_format_ar_bsd(ar);
            break;
        case Archive::FORMAT_AR_SVR4:
            archive_write_set_format_ar_svr4(ar);
            break;
        case Archive::FORMAT_CPIO:
            archive_write_set_format_cpio(ar);
            break;
        case Archive::FORMAT_CPIO_NEWC:
            archive_write_set_format_cpio_newc(ar);
            break;
        case Archive::FORMAT_MTREE:
            archive_write_set_format_mtree(ar);
            break;
        case Archive::FORMAT_TAR:
        case Archive::FORMAT_TAR_PAX_RESTRICTED:
            archive_write_set_format_pax_restricted(ar);
            break;
        case Archive::FORMAT_TAR_PAX_INTERCHANGE:
            archive_write_set_format_pax(ar);
            break;
        case Archive::FORMAT_TAR_USTAR:
            archive_write_set_format_ustar(ar);
            break;
        default:
            error_msg = "unknown or unsupported archive format";
            throw Error(error_msg);
    }
}
/*
 * Verify that KOI8-R filenames are not translated to Unicode and UTF-8
 * when using hdrcharset=BINARY option.
 */
static void
test_pax_filename_encoding_KOI8R_BINARY(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

	if (NULL == setlocale(LC_ALL, "ru_RU.KOI8-R")) {
		skipping("KOI8-R locale not available on this system.");
		return;
	}

	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	/* BINARY mode should be accepted. */
	assertEqualInt(ARCHIVE_OK,
	    archive_write_set_options(a, "hdrcharset=BINARY"));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	archive_entry_set_pathname(entry, "\xD0\xD2\xC9");
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* "hdrcharset=BINARY" pax attribute should be written. */
	assertEqualMem(buff + 512, "21 hdrcharset=BINARY\x0A", 21);
	/* Above three characters in KOI8-R should not translate to any
	 * character-set. */
	assertEqualMem(buff + 512+21, "12 path=\xD0\xD2\xC9\x0A", 12);
}
/*
 * Verify that CP932/SJIS filenames are correctly translated to Unicode and UTF-8.
 */
static void
test_pax_filename_encoding_CP932(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

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

	/* Check if the paltform completely supports the string conversion. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
		skipping("This system cannot convert character-set"
		    " from CP932/SJIS to UTF-8.");
		archive_write_free(a);
		return;
	}
	archive_write_free(a);

	/* Re-create a write archive object since filenames should be written
	 * in UTF-8 by default. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	archive_entry_set_pathname(entry, "\x95\x5C.txt");
	/* Check the Unicode version. */
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Check UTF-8 version. */
	assertEqualMem(buff + 512, "16 path=\xE8\xA1\xA8.txt\x0A", 16);

}
/*
 * Verify that CP1251 filenames are correctly translated to Unicode and UTF-8.
 */
static void
test_pax_filename_encoding_CP1251(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

	if (NULL == setlocale(LC_ALL, "Russian_Russia") &&
	    NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
		skipping("KOI8-R locale not available on this system.");
		return;
	}

	/* Check if the paltform completely supports the string conversion. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
		skipping("This system cannot convert character-set"
		    " from KOI8-R to UTF-8.");
		archive_write_free(a);
		return;
	}
	archive_write_free(a);

	/* Re-create a write archive object since filenames should be written
	 * in UTF-8 by default. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	archive_entry_set_pathname(entry, "\xef\xf0\xe8");
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Above three characters in KOI8-R should translate to the following
	 * three characters (two bytes each) in UTF-8. */
	assertEqualMem(buff + 512, "15 path=\xD0\xBF\xD1\x80\xD0\xB8\x0A", 15);
}
/*
 * Set output format to 'restricted pax' format.
 *
 * This is the same as normal 'pax', but tries to suppress
 * the pax header whenever possible.  This is the default for
 * bsdtar, for instance.
 */
int
archive_write_set_format_pax_restricted(struct archive *_a)
{
	struct archive_write *a = (struct archive_write *)_a;
	int r;
	r = archive_write_set_format_pax(&a->archive);
	a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
	a->archive.archive_format_name = "restricted POSIX pax interchange";
	return (r);
}
Example #7
0
struct archive * DTAR_new_archive() {
    struct archive *a = archive_write_new();
    archive_write_set_format_pax(a);
    int r = archive_write_open_fd(a, DTAR_writer.fd_tar);
    if ( r != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_open_fd(): %s", archive_error_string(a));
        return NULL;
    }

    return a;
}
/*
 * Pax format writer only accepts both BINARY and UTF-8.
 * If other character-set name is specified, you will get ARCHIVE_FAILED.
 */
static void
test_pax_filename_encoding_KOI8R_CP1251(void)
{
  	struct archive *a;

	if (NULL == setlocale(LC_ALL, "ru_RU.KOI8-R")) {
		skipping("KOI8-R locale not available on this system.");
		return;
	}

	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	/* pax format writer only accepts both BINARY and UTF-8. */
	assertEqualInt(ARCHIVE_FAILED,
	    archive_write_set_options(a, "hdrcharset=CP1251"));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
}
Example #9
0
void DTAR_write_header(struct archive *ar, uint64_t idx, uint64_t offset)
{

    const char * fname = mfu_flist_file_get_name(DTAR_flist, idx);

    /* fill up entry, FIXME: the uglyness of removing leading slash */
    struct archive_entry *entry = archive_entry_new();
    archive_entry_copy_pathname(entry, &fname[1]);

    if (DTAR_user_opts.preserve) {
        struct archive * source = archive_read_disk_new();
        archive_read_disk_set_standard_lookup(source);
        int fd = open(fname, O_RDONLY);
        if (archive_read_disk_entry_from_file(source, entry, fd, NULL) != ARCHIVE_OK) {
            MFU_LOG(MFU_LOG_ERR, "archive_read_disk_entry_from_file(): %s", archive_error_string(ar));
        }
        archive_read_free(source);
    } else {
        /* read stat info from mfu_flist */
        struct stat stbuf;
        mfu_lstat(fname, &stbuf);
        archive_entry_copy_stat(entry, &stbuf);
        const char* uname = mfu_flist_file_get_username(DTAR_flist, idx);
        archive_entry_set_uname(entry, uname);
        const char* gname = mfu_flist_file_get_groupname(DTAR_flist, idx);
        archive_entry_set_gname(entry, gname);
    }
    /* write entry info to archive */
    struct archive* dest = archive_write_new();
    archive_write_set_format_pax(dest);

    if (archive_write_open_fd(dest, DTAR_writer.fd_tar) != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_open_fd(): %s", archive_error_string(ar));
    }

    lseek64(DTAR_writer.fd_tar, offset, SEEK_SET);

    if (archive_write_header(dest, entry) != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_header(): %s", archive_error_string(ar));
    }
    archive_entry_free(entry);
    archive_write_free(dest);

}
/* ArchiveWriter::__construct {{{
 *
*/
ZEND_METHOD(ArchiveWriter, __construct)
{
	archive_file_t *arch = NULL;
	int resource_id;
	zval *this = getThis();
	const char *error_string = NULL;
	char *filename;
	long error_num, filename_len, result, format=0, compression=0;
	zend_error_handling error_handling;

	zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC);

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &filename, &filename_len, &format, &compression) == FAILURE) {
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}

#if PHP_API_VERSION < 20100412
	if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}
#endif

	if (php_check_open_basedir(filename TSRMLS_CC)) {
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}

	arch = (archive_file_t *) emalloc(sizeof(archive_file_t));

	arch->stream = NULL;

	ALLOC_HASHTABLE(arch->entries);
	zend_hash_init(arch->entries, 10, NULL, _archive_entries_hash_dtor, 0);

	arch->mode = PHP_ARCHIVE_WRITE_MODE;
	arch->buf = emalloc(PHP_ARCHIVE_BUF_LEN + 1);
	arch->filename = estrndup(filename, filename_len);
	arch->arch = archive_write_new();

	switch (compression) {
		case PHP_ARCHIVE_COMPRESSION_GZIP:
			if (archive_write_add_filter_gzip(arch->arch) != ARCHIVE_OK) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Gzip compression is not supported in this build");
				zend_restore_error_handling(&error_handling TSRMLS_CC);
				return;
			}
			break;

		case PHP_ARCHIVE_COMPRESSION_BZIP2:
			if (archive_write_add_filter_bzip2(arch->arch) != ARCHIVE_OK) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bzip2 compression is not supported in this build");
				zend_restore_error_handling(&error_handling TSRMLS_CC);
				return;
			}
			break;
		case 0: /* default value */
		case PHP_ARCHIVE_COMPRESSION_NONE:
			/* always supported */
			break;
		default:
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported compression type %ld", compression);
			zend_restore_error_handling(&error_handling TSRMLS_CC);
			return;
			break;
	}

	switch (format) {
		case 0: /* default value */
		case PHP_ARCHIVE_FORMAT_TAR:
		case PHP_ARCHIVE_FORMAT_PAX_RESTRICTED:
			archive_write_set_format_pax_restricted(arch->arch);
			break;
		case PHP_ARCHIVE_FORMAT_PAX:
			archive_write_set_format_pax(arch->arch);
			break;
		case PHP_ARCHIVE_FORMAT_CPIO:
			archive_write_set_format_cpio(arch->arch);
			break;
		case PHP_ARCHIVE_FORMAT_SHAR:
			archive_write_set_format_shar(arch->arch);
			break;
		case PHP_ARCHIVE_FORMAT_USTAR:
			archive_write_set_format_ustar(arch->arch);
			break;
		default:
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported archive format: %ld", format);
			zend_restore_error_handling(&error_handling TSRMLS_CC);
			return;
			break;
	}

	archive_write_set_bytes_per_block(arch->arch, DEFAULT_BYTES_PER_BLOCK);
	result = archive_write_open(arch->arch, arch, _archive_open_clbk, _archive_write_clbk, _archive_close_clbk);
	/* do not pad the last block */
	archive_write_set_bytes_in_last_block(arch->arch, 1);

	if (result) {
		error_num = archive_errno(arch->arch);
		error_string = archive_error_string(arch->arch);
		efree(arch->filename);
		efree(arch->buf);
		efree(arch);
		if (error_num && error_string) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: error #%ld, %s", filename, error_num, error_string);
		}
		else {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: unknown error %ld", filename, result);
		}
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}

	resource_id = zend_list_insert(arch,le_archive);
	add_property_resource(this, "fd", resource_id);

	zend_restore_error_handling(&error_handling TSRMLS_CC);
	return;
}
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);
}
/*
 * Set the locale and write a pathname containing invalid characters.
 * This should work; the underlying implementation should automatically
 * fall back to storing the pathname in binary.
 */
static void
test_pax_filename_encoding_2(void)
{
	char filename[] = "abc\314\214mno\374xyz";
	struct archive *a;
	struct archive_entry *entry;
	char buff[65536];
	char longname[] = "abc\314\214mno\374xyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
	    ;
	size_t used;

	/*
	 * We need a starting locale which has invalid sequences.
	 * en_US.UTF-8 seems to be commonly supported.
	 */
	/* If it doesn't exist, just warn and return. */
	if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) {
		skipping("invalid encoding tests require a suitable locale;"
		    " en_US.UTF-8 not available on this system");
		return;
	}

	assert((a = archive_write_new()) != NULL);
	assertEqualIntA(a, 0, archive_write_set_format_pax(a));
	assertEqualIntA(a, 0, archive_write_add_filter_none(a));
	assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0));
	assertEqualInt(0,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	assert((entry = archive_entry_new()) != NULL);
	/* Set pathname, gname, uname, hardlink to nonconvertible values. */
	archive_entry_copy_pathname(entry, filename);
	archive_entry_copy_gname(entry, filename);
	archive_entry_copy_uname(entry, filename);
	archive_entry_copy_hardlink(entry, filename);
	archive_entry_set_filetype(entry, AE_IFREG);
	failure("This should generate a warning for nonconvertible names.");
	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	/* Set path, gname, uname, and symlink to nonconvertible values. */
	archive_entry_copy_pathname(entry, filename);
	archive_entry_copy_gname(entry, filename);
	archive_entry_copy_uname(entry, filename);
	archive_entry_copy_symlink(entry, filename);
	archive_entry_set_filetype(entry, AE_IFLNK);
	failure("This should generate a warning for nonconvertible names.");
	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	/* Set pathname to a very long nonconvertible value. */
	archive_entry_copy_pathname(entry, longname);
	archive_entry_set_filetype(entry, AE_IFREG);
	failure("This should generate a warning for nonconvertible names.");
	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
	archive_entry_free(entry);

	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now read the entries back.
	 */

	assert((a = archive_read_new()) != NULL);
	assertEqualInt(0, archive_read_support_format_tar(a));
	assertEqualInt(0, archive_read_open_memory(a, buff, used));

	assertEqualInt(0, archive_read_next_header(a, &entry));
	assertEqualString(filename, archive_entry_pathname(entry));
	assertEqualString(filename, archive_entry_gname(entry));
	assertEqualString(filename, archive_entry_uname(entry));
	assertEqualString(filename, archive_entry_hardlink(entry));

	assertEqualInt(0, archive_read_next_header(a, &entry));
	assertEqualString(filename, archive_entry_pathname(entry));
	assertEqualString(filename, archive_entry_gname(entry));
	assertEqualString(filename, archive_entry_uname(entry));
	assertEqualString(filename, archive_entry_symlink(entry));

	assertEqualInt(0, archive_read_next_header(a, &entry));
	assertEqualString(longname, archive_entry_pathname(entry));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
/*
 * Create an entry starting from a wide-character Unicode pathname,
 * read it back into "C" locale, which doesn't support the name.
 * TODO: Figure out the "right" behavior here.
 */
static void
test_pax_filename_encoding_3(void)
{
	wchar_t badname[] = L"xxxAyyyBzzz";
	const char badname_utf8[] = "xxx\xE1\x88\xB4yyy\xE5\x99\xB8zzz";
	struct archive *a;
	struct archive_entry *entry;
	char buff[65536];
	size_t used;

	badname[3] = 0x1234;
	badname[7] = 0x5678;

	/* If it doesn't exist, just warn and return. */
	if (NULL == setlocale(LC_ALL, "C")) {
		skipping("Can't set \"C\" locale, so can't exercise "
		    "certain character-conversion failures");
		return;
	}

	/* If wctomb is broken, warn and return. */
	if (wctomb(buff, 0x1234) > 0) {
		skipping("Cannot test conversion failures because \"C\" "
		    "locale on this system has no invalid characters.");
		return;
	}

	/* If wctomb is broken, warn and return. */
	if (wctomb(buff, 0x1234) > 0) {
		skipping("Cannot test conversion failures because \"C\" "
		    "locale on this system has no invalid characters.");
		return;
	}

	/* Skip test if archive_entry_update_pathname_utf8() is broken. */
	/* In particular, this is currently broken on Win32 because
	 * setlocale() does not set the default encoding for CP_ACP. */
	entry = archive_entry_new();
	if (archive_entry_update_pathname_utf8(entry, badname_utf8)) {
		archive_entry_free(entry);
		skipping("Cannot test conversion failures.");
		return;
	}
	archive_entry_free(entry);

	assert((a = archive_write_new()) != NULL);
	assertEqualIntA(a, 0, archive_write_set_format_pax(a));
	assertEqualIntA(a, 0, archive_write_add_filter_none(a));
	assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0));
	assertEqualInt(0,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	assert((entry = archive_entry_new()) != NULL);
	/* Set pathname to non-convertible wide value. */
	archive_entry_copy_pathname_w(entry, badname);
	archive_entry_set_filetype(entry, AE_IFREG);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	archive_entry_copy_pathname_w(entry, L"abc");
	/* Set gname to non-convertible wide value. */
	archive_entry_copy_gname_w(entry, badname);
	archive_entry_set_filetype(entry, AE_IFREG);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	archive_entry_copy_pathname_w(entry, L"abc");
	/* Set uname to non-convertible wide value. */
	archive_entry_copy_uname_w(entry, badname);
	archive_entry_set_filetype(entry, AE_IFREG);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	archive_entry_copy_pathname_w(entry, L"abc");
	/* Set hardlink to non-convertible wide value. */
	archive_entry_copy_hardlink_w(entry, badname);
	archive_entry_set_filetype(entry, AE_IFREG);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);

	assert((entry = archive_entry_new()) != NULL);
	archive_entry_copy_pathname_w(entry, L"abc");
	/* Set symlink to non-convertible wide value. */
	archive_entry_copy_symlink_w(entry, badname);
	archive_entry_set_filetype(entry, AE_IFLNK);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);

	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/*
	 * Now read the entries back.
	 */

	assert((a = archive_read_new()) != NULL);
	assertEqualInt(0, archive_read_support_format_tar(a));
	assertEqualInt(0, archive_read_open_memory(a, buff, used));

	failure("A non-convertible pathname should cause a warning.");
	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
	assertEqualWString(badname, archive_entry_pathname_w(entry));
	failure("If native locale can't convert, we should get UTF-8 back.");
	assertEqualString(badname_utf8, archive_entry_pathname(entry));

	failure("A non-convertible gname should cause a warning.");
	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
	assertEqualWString(badname, archive_entry_gname_w(entry));
	failure("If native locale can't convert, we should get UTF-8 back.");
	assertEqualString(badname_utf8, archive_entry_gname(entry));

	failure("A non-convertible uname should cause a warning.");
	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
	assertEqualWString(badname, archive_entry_uname_w(entry));
	failure("If native locale can't convert, we should get UTF-8 back.");
	assertEqualString(badname_utf8, archive_entry_uname(entry));

	failure("A non-convertible hardlink should cause a warning.");
	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
	assertEqualWString(badname, archive_entry_hardlink_w(entry));
	failure("If native locale can't convert, we should get UTF-8 back.");
	assertEqualString(badname_utf8, archive_entry_hardlink(entry));

	failure("A non-convertible symlink should cause a warning.");
	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
	assertEqualWString(badname, archive_entry_symlink_w(entry));
	assertEqualWString(NULL, archive_entry_hardlink_w(entry));
	failure("If native locale can't convert, we should get UTF-8 back.");
	assertEqualString(badname_utf8, archive_entry_symlink(entry));

	assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &entry));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #14
0
static void mfu_flist_archive_create_libcircle(mfu_flist flist, const char* archivefile, mfu_archive_options_t* opts)
{
    DTAR_flist = flist;
    DTAR_user_opts = *opts;

    MPI_Comm_rank(MPI_COMM_WORLD, &DTAR_rank);

    /* TODO: stripe the archive file if on parallel file system */

    /* init statistics */
    DTAR_statistics.total_dirs  = 0;
    DTAR_statistics.total_files = 0;
    DTAR_statistics.total_links = 0;
    DTAR_statistics.total_size  = 0;
    DTAR_statistics.total_bytes_copied = 0;

    time(&(DTAR_statistics.time_started));
    DTAR_statistics.wtime_started = MPI_Wtime();

    /* create the archive file */
    DTAR_writer.name = archivefile;
    DTAR_writer.flags = O_WRONLY | O_CREAT | O_CLOEXEC | O_LARGEFILE;
    DTAR_writer.fd_tar = open(archivefile, DTAR_writer.flags, 0664);

    /* get number of items in our portion of the list */
    DTAR_count = mfu_flist_size(DTAR_flist);

    /* allocate memory for file sizes and offsets */
    uint64_t* fsizes = (uint64_t*) MFU_MALLOC(DTAR_count * sizeof(uint64_t));
    DTAR_offsets     = (uint64_t*) MFU_MALLOC(DTAR_count * sizeof(uint64_t));

    /* compute local offsets for each item and total
     * bytes we're contributing to the archive */
    uint64_t idx;
    uint64_t offset = 0;
    for (idx = 0; idx < DTAR_count; idx++) {
        /* assume the item takes no space */
        fsizes[idx] = 0;

        /* identify item type to compute its size in the archive */
        mfu_filetype type = mfu_flist_file_get_type(DTAR_flist, idx);
        if (type == MFU_TYPE_DIR || type == MFU_TYPE_LINK) {
            /* directories and symlinks only need the header */
            fsizes[idx] = DTAR_HDR_LENGTH;
        } else if (type == MFU_TYPE_FILE) {
            /* regular file requires a header, plus file content,
             * and things are packed into blocks of 512 bytes */
            uint64_t fsize = mfu_flist_file_get_size(DTAR_flist, idx);

            /* determine whether file size is integer multiple of 512 bytes */
            uint64_t rem = fsize % 512;
            if (rem == 0) {
                /* file content is multiple of 512 bytes, so perfect fit */
                fsizes[idx] = fsize + DTAR_HDR_LENGTH;
            } else {
                /* TODO: check and explain this math */
                fsizes[idx] = (fsize / 512 + 4) * 512;
            }

        }

        /* increment our local offset for this item */
        DTAR_offsets[idx] = offset;
        offset += fsizes[idx];
    }

    /* execute scan to figure our global base offset in the archive file */
    uint64_t global_offset = 0;
    MPI_Scan(&offset, &global_offset, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
    global_offset -= offset;

    /* update offsets for each of our file to their global offset */
    for (idx = 0; idx < DTAR_count; idx++) {
        DTAR_offsets[idx] += global_offset;
    }

    /* create an archive */
    struct archive* ar = archive_write_new();

    archive_write_set_format_pax(ar);

    int r = archive_write_open_fd(ar, DTAR_writer.fd_tar);
    if (r != ARCHIVE_OK) {
        MFU_LOG(MFU_LOG_ERR, "archive_write_open_fd(): %s", archive_error_string(ar));
        DTAR_abort(EXIT_FAILURE);
    }

    /* write headers for our files */
    for (idx = 0; idx < DTAR_count; idx++) {
        mfu_filetype type = mfu_flist_file_get_type(DTAR_flist, idx);
        if (type == MFU_TYPE_FILE || type == MFU_TYPE_DIR || type == MFU_TYPE_LINK) {
            DTAR_write_header(ar, idx, DTAR_offsets[idx]);
        }
    }

    /* prepare libcircle */
    CIRCLE_init(0, NULL, CIRCLE_SPLIT_EQUAL | CIRCLE_CREATE_GLOBAL);
    CIRCLE_loglevel loglevel = CIRCLE_LOG_WARN;
    CIRCLE_enable_logging(loglevel);

    /* register callbacks */
    CIRCLE_cb_create(&DTAR_enqueue_copy);
    CIRCLE_cb_process(&DTAR_perform_copy);

    /* run the libcircle job to copy data into archive file */
    CIRCLE_begin();
    CIRCLE_finalize();

    /* compute total bytes copied */
    uint64_t archive_size = 0;
    MPI_Allreduce(&offset, &archive_size, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
    DTAR_statistics.total_size = archive_size;

    DTAR_statistics.wtime_ended = MPI_Wtime();
    time(&(DTAR_statistics.time_ended));

    /* print stats */
    double rel_time = DTAR_statistics.wtime_ended - \
                      DTAR_statistics.wtime_started;
    if (DTAR_rank == 0) {
        char starttime_str[256];
        struct tm* localstart = localtime(&(DTAR_statistics.time_started));
        strftime(starttime_str, 256, "%b-%d-%Y, %H:%M:%S", localstart);

        char endtime_str[256];
        struct tm* localend = localtime(&(DTAR_statistics.time_ended));
        strftime(endtime_str, 256, "%b-%d-%Y, %H:%M:%S", localend);

        /* add two 512 blocks at the end */
        DTAR_statistics.total_size += 512 * 2;

        /* convert bandwidth to unit */
        double agg_rate_tmp;
        double agg_rate = (double) DTAR_statistics.total_size / rel_time;
        const char* agg_rate_units;
        mfu_format_bytes(agg_rate, &agg_rate_tmp, &agg_rate_units);

        MFU_LOG(MFU_LOG_INFO, "Started:    %s", starttime_str);
        MFU_LOG(MFU_LOG_INFO, "Completed:  %s", endtime_str);
        MFU_LOG(MFU_LOG_INFO, "Total archive size: %" PRIu64, DTAR_statistics.total_size);
        MFU_LOG(MFU_LOG_INFO, "Rate: %.3lf %s " \
                "(%.3" PRIu64 " bytes in %.3lf seconds)", \
                agg_rate_tmp, agg_rate_units, DTAR_statistics.total_size, rel_time);
    }

    /* clean up */
    mfu_free(&fsizes);
    mfu_free(&DTAR_offsets);

    /* close archive file */
    archive_write_free(ar);
    mfu_close(DTAR_writer.name, DTAR_writer.fd_tar);
}
Example #15
0
const gchar* archive_create(const char* archive_name, GSList* files,
			COMPRESS_METHOD method, ARCHIVE_FORMAT format) {
	struct archive* arch;
	struct archive_entry* entry;
	char* buf = NULL;
	ssize_t len;
	int fd;
	struct stat st;
	struct file_info* file;
	gchar* filename = NULL;
	gchar* msg = NULL;

#ifndef _TEST
	gint num = 0;
	gint total = g_slist_length (files);
#endif

	g_return_val_if_fail(files != NULL, "No files for archiving");

	debug_print("File: %s\n", archive_name);
	arch = archive_write_new();
	switch (method) {
		case ZIP:
			if (archive_write_set_compression_gzip(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
		case BZIP2:
			if (archive_write_set_compression_bzip2(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
#if NEW_ARCHIVE_API
		case COMPRESS:
			if (archive_write_set_compression_compress(arch) != ARCHIVE_OK)
    			        return archive_error_string(arch);
			break;
#endif
		case NO_COMPRESS:
			if (archive_write_set_compression_none(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
	}
	switch (format) {
		case TAR:
			if (archive_write_set_format_ustar(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
		case SHAR:
			if (archive_write_set_format_shar(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
		case PAX:
			if (archive_write_set_format_pax(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
		case CPIO:
			if (archive_write_set_format_cpio(arch) != ARCHIVE_OK)
				return archive_error_string(arch);
			break;
		case NO_FORMAT:
			return "Missing archive format";
	}
	if (archive_write_open_file(arch, archive_name) != ARCHIVE_OK)
		return archive_error_string(arch);

	while (files && ! stop_action) {
#ifndef _TEST
		set_progress_print_all(num++, total, 30);
#endif
		file = (struct file_info *) files->data;
		if (!file)
			continue;
		filename = get_full_path(file);
		/* libarchive will crash if instructed to add archive to it self */
		if (g_utf8_collate(archive_name, filename) == 0) {
			buf = NULL;
			buf = g_strdup_printf(
						"%s: Not dumping to %s", archive_name, filename);
			g_warning("%s\n", buf);
#ifndef _TEST
			debug_print("%s\n", buf);
#endif
			g_free(buf);
		}
		else {
#ifndef _TEST
			debug_print("Adding: %s\n", filename);
			msg = g_strdup_printf("%s", filename);
			set_progress_file_label(msg);
			g_free(msg);
#endif
			entry = archive_entry_new();
			lstat(filename, &st);
			if ((fd = open(filename, O_RDONLY)) == -1) {
				perror("open file");
			}
			else {
				archive_entry_copy_stat(entry, &st);
				archive_entry_set_pathname(entry, filename);
				if (S_ISLNK(st.st_mode)) {
					buf = NULL;
					buf = malloc(PATH_MAX + 1);
					if ((len = readlink(filename, buf, PATH_MAX)) < 0)
						perror("error in readlink");
					else
						buf[len] = '\0';
					archive_entry_set_symlink(entry, buf);
					g_free(buf);
					archive_entry_set_size(entry, 0);
					archive_write_header(arch, entry);
				}
				else {
					if (archive_write_header(arch, entry) != ARCHIVE_OK)
						g_warning("%s", archive_error_string(arch));
					buf = NULL;
					buf = malloc(READ_BLOCK_SIZE);
					len = read(fd, buf, READ_BLOCK_SIZE);
					while (len > 0) {
						if (archive_write_data(arch, buf, len) == -1)
							g_warning("%s", archive_error_string(arch));
						memset(buf, 0, READ_BLOCK_SIZE);
						len = read(fd, buf, READ_BLOCK_SIZE);
					}
					g_free(buf);
				}
				close(fd);
				archive_entry_free(entry);
			}
		}
		g_free(filename);
		files = g_slist_next(files);
	}
#ifndef _TEST
	if (stop_action)
		unlink(archive_name);
	stop_action = FALSE;
#endif
	archive_write_close(arch);
	archive_write_finish(arch);
	return NULL;
}