Exemple #1
0
static int ar_entry_mtime(lua_State *L) {
    struct archive_entry* self = *ar_entry_check(L, 1);
    int is_set;
    int num_results;
    if ( NULL == self ) return 0;

    is_set = ( lua_gettop(L) >= 2 );
    num_results = 0;
    if ( archive_entry_mtime_is_set(self) ) {
        num_results = 2;
        lua_pushnumber(L, archive_entry_mtime(self));
        lua_pushnumber(L, archive_entry_mtime_nsec(self));
    }
    if ( is_set ) {
        if ( lua_isnil(L, 2) ) {
            archive_entry_unset_mtime(self);
        } else if ( lua_istable(L, 2) ) {
            lua_rawgeti(L, 2, 1);
            lua_rawgeti(L, 2, 2);
            archive_entry_set_mtime(self,
                                    lua_tonumber(L, -2),
                                    lua_tonumber(L, -1));
        } else {
            archive_entry_set_mtime(self,
                                    lua_tonumber(L, 2),
                                    lua_tonumber(L, 3));
        }
    }
    return num_results;
}
static int
header_bin_be(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	const unsigned char *header;

	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
	a->archive.archive_format_name = "cpio (big-endian binary)";

	/* Read fixed-size portion of header. */
	h = __archive_read_ahead(a, bin_header_size, NULL);
	if (h == NULL)
	    return (ARCHIVE_FATAL);

	/* Parse out binary fields. */
	header = (const unsigned char *)h;

	archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
	archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
	archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
	archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
	archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
	archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
	archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
	archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
	*namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
	*name_pad = *namelength & 1; /* Pad to even. */

	cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
	    __archive_read_consume(a, bin_header_size);
	return (ARCHIVE_OK);
}
static int
header_bin_be(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
    const void *h;
    const struct cpio_bin_header *header;

    a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
    a->archive.archive_format_name = "cpio (big-endian binary)";

    /* Read fixed-size portion of header. */
    h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL);
    if (h == NULL)
        return (ARCHIVE_FATAL);
    __archive_read_consume(a, sizeof(struct cpio_bin_header));

    /* Parse out binary fields. */
    header = (const struct cpio_bin_header *)h;
    archive_entry_set_dev(entry, header->c_dev[0] * 256 + header->c_dev[1]);
    archive_entry_set_ino(entry, header->c_ino[0] * 256 + header->c_ino[1]);
    archive_entry_set_mode(entry, header->c_mode[0] * 256 + header->c_mode[1]);
    archive_entry_set_uid(entry, header->c_uid[0] * 256 + header->c_uid[1]);
    archive_entry_set_gid(entry, header->c_gid[0] * 256 + header->c_gid[1]);
    archive_entry_set_nlink(entry, header->c_nlink[0] * 256 + header->c_nlink[1]);
    archive_entry_set_rdev(entry, header->c_rdev[0] * 256 + header->c_rdev[1]);
    archive_entry_set_mtime(entry, be4(header->c_mtime), 0);
    *namelength = header->c_namesize[0] * 256 + header->c_namesize[1];
    *name_pad = *namelength & 1; /* Pad to even. */

    cpio->entry_bytes_remaining = be4(header->c_filesize);
    archive_entry_set_size(entry, cpio->entry_bytes_remaining);
    cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
    return (ARCHIVE_OK);
}
static int
header_odc(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	int r;
	const char *header;

	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
	a->archive.archive_format_name = "POSIX octet-oriented cpio";

	/* Find the start of the next header. */
	r = find_odc_header(a);
	if (r < ARCHIVE_WARN)
		return (r);

	if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) {
		int r2 = (header_afiol(a, cpio, entry, namelength, name_pad));
		if (r2 == ARCHIVE_OK)
			return (r);
		else
			return (r2);
	}

	/* Read fixed-size portion of header. */
	h = __archive_read_ahead(a, odc_header_size, NULL);
	if (h == NULL)
	    return (ARCHIVE_FATAL);

	/* Parse out octal fields. */
	header = (const char *)h;

	archive_entry_set_dev(entry, 
		(dev_t)atol8(header + odc_dev_offset, odc_dev_size));
	archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));
	archive_entry_set_mode(entry, 
		(mode_t)atol8(header + odc_mode_offset, odc_mode_size));
	archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));
	archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));
	archive_entry_set_nlink(entry, 
		(unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size));
	archive_entry_set_rdev(entry,
		(dev_t)atol8(header + odc_rdev_offset, odc_rdev_size));
	archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);
	*namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size);
	*name_pad = 0; /* No padding of filename. */

	/*
	 * Note: entry_bytes_remaining is at least 64 bits and
	 * therefore guaranteed to be big enough for a 33-bit file
	 * size.
	 */
	cpio->entry_bytes_remaining =
	    atol8(header + odc_filesize_offset, odc_filesize_size);
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	cpio->entry_padding = 0;
	__archive_read_consume(a, odc_header_size);
	return (r);
}
static int
header_newc(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	const struct cpio_newc_header *header;
	size_t bytes;
	int r;

	r = find_newc_header(a);
	if (r < ARCHIVE_WARN)
		return (r);

	/* Read fixed-size portion of header. */
	bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header));
	if (bytes < sizeof(struct cpio_newc_header))
	    return (ARCHIVE_FATAL);
	(a->decompressor->consume)(a, sizeof(struct cpio_newc_header));

	/* Parse out hex fields. */
	header = (const struct cpio_newc_header *)h;

	if (memcmp(header->c_magic, "070701", 6) == 0) {
		a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
		a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
	} else if (memcmp(header->c_magic, "070702", 6) == 0) {
		a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
		a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
	} else {
		/* TODO: Abort here? */
	}

	archive_entry_set_devmajor(entry, atol16(header->c_devmajor, sizeof(header->c_devmajor)));
	archive_entry_set_devminor(entry, atol16(header->c_devminor, sizeof(header->c_devminor)));
	archive_entry_set_ino(entry, atol16(header->c_ino, sizeof(header->c_ino)));
	archive_entry_set_mode(entry, atol16(header->c_mode, sizeof(header->c_mode)));
	archive_entry_set_uid(entry, atol16(header->c_uid, sizeof(header->c_uid)));
	archive_entry_set_gid(entry, atol16(header->c_gid, sizeof(header->c_gid)));
	archive_entry_set_nlink(entry, atol16(header->c_nlink, sizeof(header->c_nlink)));
	archive_entry_set_rdevmajor(entry, atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor)));
	archive_entry_set_rdevminor(entry, atol16(header->c_rdevminor, sizeof(header->c_rdevminor)));
	archive_entry_set_mtime(entry, atol16(header->c_mtime, sizeof(header->c_mtime)), 0);
	*namelength = atol16(header->c_namesize, sizeof(header->c_namesize));
	/* Pad name to 2 more than a multiple of 4. */
	*name_pad = (2 - *namelength) & 3;

	/*
	 * Note: entry_bytes_remaining is at least 64 bits and
	 * therefore guaranteed to be big enough for a 33-bit file
	 * size.
	 */
	cpio->entry_bytes_remaining =
	    atol16(header->c_filesize, sizeof(header->c_filesize));
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	/* Pad file contents to a multiple of 4. */
	cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
	return (r);
}
int myarch_set_entry(const char *filename, size_t  len, struct archive_entry *entry)
{
	time_t	tm;

	archive_entry_set_pathname(entry, filename);
	archive_entry_set_size(entry, len);
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, 0644);
	archive_entry_set_mtime(entry, time(&tm), 0);
	return 0;
}
int createArchiveofFilesPC(char** files, unsigned long * size,
		unsigned int fileCount, const char* filename, const char* tarHostDir) {
	unsigned int ctr = 0;
	struct timespec ts;
	struct archive_entry* entry;
	struct archive* archive = archive_write_new();
	int dirlen = strlen(tarHostDir);
	if ((archive_write_set_compression_gzip(archive) != ARCHIVE_OK)
			|| (archive_write_set_format_ustar(archive) != ARCHIVE_OK)
			|| (archive_write_open_filename(archive, filename) != ARCHIVE_OK)) {
		printf("%s\n", archive_error_string(archive));
		return -1;
	}
	int tarHostDirLen = strlen(tarHostDir);
	for (ctr = 0; ctr < fileCount; ctr++) {
		entry = archive_entry_new();
		clock_gettime(CLOCK_REALTIME, &ts);

		//Set entry to be stored under the tarHostDir directory
		const char* path = files[ctr];
		int pathlength = dirlen + strlen(path) + 2; //One for / and the other for '\0'
		char newPath[pathlength];
		if(tarHostDirLen>0)
			snprintf(newPath, pathlength, "%s/%s", tarHostDir, boost::filesystem::path(path).filename().c_str());
		else
			snprintf(newPath, pathlength, "%s", boost::filesystem::path(path).filename().c_str());
		archive_entry_set_pathname(entry, newPath);
		archive_entry_set_size(entry, size[ctr]);
		archive_entry_set_filetype(entry, AE_IFREG);
		archive_entry_set_perm(entry, 0444);
		archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec);

		int rc = archive_write_header(archive, entry);
		char *contents = new char[size[ctr]+1];
		FILE* fp = fopen(files[ctr],"rb");
		fread((void *)contents, size[ctr], 1, fp);
		fclose(fp);
		archive_write_data(archive, contents, size[ctr]);
		archive_entry_free(entry);
		entry = NULL;
		delete[] contents;
		if (ARCHIVE_OK != rc) {
			printf("%s\n", archive_error_string(archive));
			return -1;
		}
	}
	archive_write_finish(archive);
}
static int
header_odc(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	int r;
	const struct cpio_odc_header *header;
	size_t bytes;

	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
	a->archive.archive_format_name = "POSIX octet-oriented cpio";

	/* Find the start of the next header. */
	r = find_odc_header(a);
	if (r < ARCHIVE_WARN)
		return (r);

	/* Read fixed-size portion of header. */
	bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header));
	if (bytes < sizeof(struct cpio_odc_header))
	    return (ARCHIVE_FATAL);
	(a->decompressor->consume)(a, sizeof(struct cpio_odc_header));

	/* Parse out octal fields. */
	header = (const struct cpio_odc_header *)h;

	archive_entry_set_dev(entry, atol8(header->c_dev, sizeof(header->c_dev)));
	archive_entry_set_ino(entry, atol8(header->c_ino, sizeof(header->c_ino)));
	archive_entry_set_mode(entry, atol8(header->c_mode, sizeof(header->c_mode)));
	archive_entry_set_uid(entry, atol8(header->c_uid, sizeof(header->c_uid)));
	archive_entry_set_gid(entry, atol8(header->c_gid, sizeof(header->c_gid)));
	archive_entry_set_nlink(entry, atol8(header->c_nlink, sizeof(header->c_nlink)));
	archive_entry_set_rdev(entry, atol8(header->c_rdev, sizeof(header->c_rdev)));
	archive_entry_set_mtime(entry, atol8(header->c_mtime, sizeof(header->c_mtime)), 0);
	*namelength = atol8(header->c_namesize, sizeof(header->c_namesize));
	*name_pad = 0; /* No padding of filename. */

	/*
	 * Note: entry_bytes_remaining is at least 64 bits and
	 * therefore guaranteed to be big enough for a 33-bit file
	 * size.
	 */
	cpio->entry_bytes_remaining =
	    atol8(header->c_filesize, sizeof(header->c_filesize));
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	cpio->entry_padding = 0;
	return (r);
}
/*
 * Check that an ISO 9660 image is correctly created.
 */
static void
add_entry(struct archive *a, const char *fname, const char *sym)
{
	struct archive_entry *ae;

	assert((ae = archive_entry_new()) != NULL);
	archive_entry_set_birthtime(ae, 2, 20);
	archive_entry_set_atime(ae, 3, 30);
	archive_entry_set_ctime(ae, 4, 40);
	archive_entry_set_mtime(ae, 5, 50);
	archive_entry_copy_pathname(ae, fname);
	if (sym != NULL)
		archive_entry_set_symlink(ae, sym);
	archive_entry_set_mode(ae, S_IFREG | 0555);
	archive_entry_set_size(ae, 0);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);
}
static void create_reg_file(struct archive_entry *ae, const char *msg)
{
	static const char data[]="abcdefghijklmnopqrstuvwxyz";
	struct archive *ad;

	/* Write the entry to disk. */
	assert((ad = archive_write_disk_new()) != NULL);
        archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
	failure("%s", msg);
	/*
	 * A touchy API design issue: archive_write_data() does (as of
	 * 2.4.12) enforce the entry size as a limit on the data
	 * written to the file.  This was not enforced prior to
	 * 2.4.12.  The change was prompted by the refined
	 * hardlink-restore semantics introduced at that time.  In
	 * short, libarchive needs to know whether a "hardlink entry"
	 * is going to overwrite the contents so that it can know
	 * whether or not to open the file for writing.  This implies
	 * that there is a fundamental semantic difference between an
	 * entry with a zero size and one with a non-zero size in the
	 * case of hardlinks and treating the hardlink case
	 * differently from the regular file case is just asking for
	 * trouble.  So, a zero size must always mean that no data
	 * will be accepted, which is consistent with the file size in
	 * the entry being a maximum size.
	 */
	archive_entry_set_size(ae, sizeof(data));
	archive_entry_set_mtime(ae, 123456789, 0);
	assertEqualIntA(ad, 0, archive_write_header(ad, ae));
	assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
	assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
#if ARCHIVE_VERSION_NUMBER < 2000000
	archive_write_finish(ad);
#else
	assertEqualInt(0, archive_write_finish(ad));
#endif
	/* Test the entries on disk. */
	assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777);
	assertFileSize(archive_entry_pathname(ae), sizeof(data));
	/* test_write_disk_times has more detailed tests of this area. */
	assertFileMtime(archive_entry_pathname(ae), 123456789, 0);
        failure("No atime given, so atime should get set to current time");
	assertFileAtimeRecent(archive_entry_pathname(ae));
}
void
archive_entry_copy_bhfi(struct archive_entry *entry,
            BY_HANDLE_FILE_INFORMATION *bhfi)
{
    time_t secs;
    long nsecs;

    fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs);
    archive_entry_set_atime(entry, secs, nsecs);
    fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs);
    archive_entry_set_mtime(entry, secs, nsecs);
    fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs);
    archive_entry_set_birthtime(entry, secs, nsecs);
    archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber);
    archive_entry_set_ino64(entry, (((int64_t)bhfi->nFileIndexHigh) << 32)
        + bhfi->nFileIndexLow);
    archive_entry_set_nlink(entry, bhfi->nNumberOfLinks);
    archive_entry_set_size(entry, (((int64_t)bhfi->nFileSizeHigh) << 32)
        + bhfi->nFileSizeLow);
}
int createArchiveofFiles(char** files, unsigned long * size,
		unsigned int fileCount, const char* filename) {
	unsigned int ctr = 0;
	struct timespec ts;
	struct archive_entry* entry;
	struct archive* archive = archive_write_new();
	if ((archive_write_set_compression_gzip(archive) != ARCHIVE_OK)
			|| (archive_write_set_format_ustar(archive) != ARCHIVE_OK)
			|| (archive_write_open_filename(archive, filename) != ARCHIVE_OK)) {
		printf("%s\n", archive_error_string(archive));
		return -1;
	}
	for (ctr = 0; ctr < fileCount; ctr++) {
		entry = archive_entry_new();
		clock_gettime(CLOCK_REALTIME, &ts);

		archive_entry_set_pathname(entry, files[ctr]);
		archive_entry_set_size(entry, size[ctr]);
		archive_entry_set_filetype(entry, AE_IFREG);
		archive_entry_set_perm(entry, 0444);
		archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec);

		int rc = archive_write_header(archive, entry);
		char *contents = new char[size[ctr]+1];
		FILE* fp = fopen(files[ctr],"rb");
		fread((void *)contents, size[ctr], 1, fp);
		fclose(fp);
		archive_write_data(archive, contents, size[ctr]);
		archive_entry_free(entry);
		entry = NULL;
		delete[] contents;
		if (ARCHIVE_OK != rc) {
			printf("%s\n", archive_error_string(archive));
			return -1;
		}
	}
	archive_write_finish(archive);
}
Exemple #13
0
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi)
{
    archive_entry_clear(entry);

    char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL);
    archive_entry_copy_pathname(entry, filename);
    _free(filename);

    archive_entry_set_size(entry, rpmfiFSize(fi));
    rpm_mode_t mode = rpmfiFMode(fi);
    archive_entry_set_filetype(entry, mode & S_IFMT);
    archive_entry_set_perm(entry, mode);

    archive_entry_set_uname(entry, rpmfiFUser(fi));
    archive_entry_set_gname(entry, rpmfiFGroup(fi));
    archive_entry_set_rdev(entry, rpmfiFRdev(fi));
    archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0);

    if (S_ISLNK(mode))
	archive_entry_set_symlink(entry, rpmfiFLink(fi));
}
Exemple #14
0
static void record_entry(db_writer_t *writer, const char *root, const char *entry)
{
    time_t now = time(NULL);
    char entry_path[PATH_MAX];

    snprintf(entry_path, PATH_MAX, "%s/%s", root, entry);
    archive_entry_set_pathname(writer->entry, entry_path);
    archive_entry_set_filetype(writer->entry, AE_IFREG);
    archive_entry_set_size(writer->entry, writer->buf.len);

    archive_entry_set_perm(writer->entry, 0644);
    archive_entry_set_ctime(writer->entry, now, 0);
    archive_entry_set_mtime(writer->entry, now, 0);
    archive_entry_set_atime(writer->entry, now, 0);

    archive_write_header(writer->archive, writer->entry);
    archive_write_data(writer->archive, writer->buf.data, writer->buf.len);

    archive_entry_clear(writer->entry);
    buffer_clear(&writer->buf);
}
/*
 * NOTE: if a filename suffix is ".z", it is the file gziped by afio.
 * it would be nice that we can show uncompressed file size and we can
 * uncompressed file contents automatically, unfortunately we have nothing
 * to get a uncompressed file size while reading each header. It means
 * we also cannot uncompress file contents under our framework.
 */
static int
header_afiol(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	const char *header;

	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
	a->archive.archive_format_name = "afio large ASCII";

	/* Read fixed-size portion of header. */
	h = __archive_read_ahead(a, afiol_header_size, NULL);
	if (h == NULL)
	    return (ARCHIVE_FATAL);

	/* Parse out octal fields. */
	header = (const char *)h;

	archive_entry_set_dev(entry, 
		(dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
	archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));
	archive_entry_set_mode(entry,
		(mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
	archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
	archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));
	archive_entry_set_nlink(entry,
		(unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size));
	archive_entry_set_rdev(entry,
		(dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size));
	archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);
	*namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size);
	*name_pad = 0; /* No padding of filename. */

	cpio->entry_bytes_remaining =
	    atol16(header + afiol_filesize_offset, afiol_filesize_size);
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	cpio->entry_padding = 0;
	__archive_read_consume(a, afiol_header_size);
	return (ARCHIVE_OK);
}
Exemple #16
0
int
xbps_archive_append_buf(struct archive *ar, const void *buf, const size_t buflen,
	const char *fname, const mode_t mode, const char *uname, const char *gname)
{
	struct archive_entry *entry;
	time_t tm;

	assert(ar);
	assert(buf);
	assert(fname);
	assert(uname);
	assert(gname);

	tm = time(NULL);
	entry = archive_entry_new();
	assert(entry);

	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, mode);
	archive_entry_set_uname(entry, uname);
	archive_entry_set_gname(entry, gname);
	archive_entry_set_pathname(entry, fname);
	archive_entry_set_size(entry, buflen);
	archive_entry_set_atime(entry, tm, 0);
	archive_entry_set_mtime(entry, tm, 0);
	archive_entry_set_ctime(entry, tm, 0);

	if (archive_write_header(ar, entry) != ARCHIVE_OK) {
		archive_entry_free(entry);
		return archive_errno(ar);
	}
	if (archive_write_data(ar, buf, buflen) != ARCHIVE_OK) {
		archive_entry_free(entry);
		return archive_errno(ar);
	}
	archive_write_finish_entry(ar);
	archive_entry_free(entry);

	return 0;
}
static int
ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
    const char *h)
{
	uint64_t n;

	/* Copy remaining header */
	archive_entry_set_mtime(entry,
	    (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L);
	archive_entry_set_uid(entry,
	    (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size));
	archive_entry_set_gid(entry,
	    (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size));
	archive_entry_set_mode(entry,
	    (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
	n = ar_atol10(h + AR_size_offset, AR_size_size);

	ar->entry_offset = 0;
	ar->entry_padding = n % 2;
	archive_entry_set_size(entry, n);
	ar->entry_bytes_remaining = n;
	return (ARCHIVE_OK);
}
static void create_reg_file_win(struct archive_entry *ae, const char *msg)
{
	static const char data[]="abcdefghijklmnopqrstuvwxyz";
	struct archive *ad;
	struct stat st;
	char *p, *fname;
	size_t l;

	/* Write the entry to disk. */
	assert((ad = archive_write_disk_new()) != NULL);
        archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
	failure("%s", msg);
	archive_entry_set_size(ae, sizeof(data));
	archive_entry_set_mtime(ae, 123456789, 0);
	assertEqualIntA(ad, 0, archive_write_header(ad, ae));
	assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
	assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
#if ARCHIVE_VERSION_NUMBER < 2000000
	archive_write_finish(ad);
#else
	assertEqualInt(0, archive_write_finish(ad));
#endif
	/* Test the entries on disk. */
	l = strlen(archive_entry_pathname(ae));
	fname = malloc(l + 1);
	assert(NULL != fname);
	strcpy(fname, archive_entry_pathname(ae));
	/* Replace unusable characters in Windows to '_' */
	for (p = fname; *p != '\0'; p++)
		if (*p == ':' || *p == '*' || *p == '?' ||
		    *p == '"' || *p == '<' || *p == '>' || *p == '|')
			*p = '_';
	assert(0 == stat(fname, &st));
	failure("st.st_mode=%o archive_entry_mode(ae)=%o",
	    st.st_mode, archive_entry_mode(ae));
	assertEqualInt(st.st_size, sizeof(data));
}
Exemple #19
0
void
archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
{
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
	archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec);
	archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec);
	archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
	archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec);
	archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec);
	archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
	archive_entry_set_atime(entry, st->st_atime, st->st_atime_n);
	archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n);
	archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n);
#elif HAVE_STRUCT_STAT_ST_UMTIME
	archive_entry_set_atime(entry, st->st_atime, st->st_uatime * 1000);
	archive_entry_set_ctime(entry, st->st_ctime, st->st_uctime * 1000);
	archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime * 1000);
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
	archive_entry_set_atime(entry, st->st_atime, st->st_atime_usec * 1000);
	archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_usec * 1000);
	archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec * 1000);
#else
	archive_entry_set_atime(entry, st->st_atime, 0);
	archive_entry_set_ctime(entry, st->st_ctime, 0);
	archive_entry_set_mtime(entry, st->st_mtime, 0);
#endif
#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
	archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_BIRTHTIME
	archive_entry_set_birthtime(entry, st->st_birthtime, 0);
#else
	archive_entry_unset_birthtime(entry);
#endif
	archive_entry_set_dev(entry, st->st_dev);
	archive_entry_set_gid(entry, st->st_gid);
	archive_entry_set_uid(entry, st->st_uid);
	archive_entry_set_ino(entry, st->st_ino);
	archive_entry_set_nlink(entry, st->st_nlink);
	archive_entry_set_rdev(entry, st->st_rdev);
	archive_entry_set_size(entry, st->st_size);
	archive_entry_set_mode(entry, st->st_mode);
}
static int
header_bin_le(struct archive_read *a, struct cpio *cpio,
    struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
	const void *h;
	const struct cpio_bin_header *header;
	size_t bytes;

	a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
	a->archive.archive_format_name = "cpio (little-endian binary)";

	/* Read fixed-size portion of header. */
	bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_bin_header));
	if (bytes < sizeof(struct cpio_bin_header))
	    return (ARCHIVE_FATAL);
	(a->decompressor->consume)(a, sizeof(struct cpio_bin_header));

	/* Parse out binary fields. */
	header = (const struct cpio_bin_header *)h;

	archive_entry_set_dev(entry, header->c_dev[0] + header->c_dev[1] * 256);
	archive_entry_set_ino(entry, header->c_ino[0] + header->c_ino[1] * 256);
	archive_entry_set_mode(entry, header->c_mode[0] + header->c_mode[1] * 256);
	archive_entry_set_uid(entry, header->c_uid[0] + header->c_uid[1] * 256);
	archive_entry_set_gid(entry, header->c_gid[0] + header->c_gid[1] * 256);
	archive_entry_set_nlink(entry, header->c_nlink[0] + header->c_nlink[1] * 256);
	archive_entry_set_rdev(entry, header->c_rdev[0] + header->c_rdev[1] * 256);
	archive_entry_set_mtime(entry, le4(header->c_mtime), 0);
	*namelength = header->c_namesize[0] + header->c_namesize[1] * 256;
	*name_pad = *namelength & 1; /* Pad to even. */

	cpio->entry_bytes_remaining = le4(header->c_filesize);
	archive_entry_set_size(entry, cpio->entry_bytes_remaining);
	cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
	return (ARCHIVE_OK);
}
static int
_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
{
#define HDR_PROBE_LEN		(12U)
	struct warc_s *w = a->format->data;
	unsigned int ver;
	const char *buf;
	ssize_t nrd;
	const char *eoh;
	/* for the file name, saves some strndup()'ing */
	warc_string_t fnam;
	/* warc record type, not that we really use it a lot */
	warc_type_t ftyp;
	/* content-length+error monad */
	ssize_t cntlen;
	/* record time is the WARC-Date time we reinterpret it as ctime */
	time_t rtime;
	/* mtime is the Last-Modified time which will be the entry's mtime */
	time_t mtime;

start_over:
	/* just use read_ahead() they keep track of unconsumed
	 * bits and bobs for us; no need to put an extra shift in
	 * and reproduce that functionality here */
	buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);

	if (nrd < 0) {
		/* no good */
		archive_set_error(
			&a->archive, ARCHIVE_ERRNO_MISC,
			"Bad record header");
		return (ARCHIVE_FATAL);
	} else if (buf == NULL) {
		/* there should be room for at least WARC/bla\r\n
		 * must be EOF therefore */
		return (ARCHIVE_EOF);
	}
 	/* looks good so far, try and find the end of the header now */
	eoh = _warc_find_eoh(buf, nrd);
	if (eoh == NULL) {
		/* still no good, the header end might be beyond the
		 * probe we've requested, but then again who'd cram
		 * so much stuff into the header *and* be 28500-compliant */
		archive_set_error(
			&a->archive, ARCHIVE_ERRNO_MISC,
			"Bad record header");
		return (ARCHIVE_FATAL);
	} else if ((ver = _warc_rdver(buf, eoh - buf)) > 10000U) {
		/* nawww, I wish they promised backward compatibility
		 * anyhoo, in their infinite wisdom the 28500 guys might
		 * come up with something we can't possibly handle so
		 * best end things here */
		archive_set_error(
			&a->archive, ARCHIVE_ERRNO_MISC,
			"Unsupported record version");
		return (ARCHIVE_FATAL);
	} else if ((cntlen = _warc_rdlen(buf, eoh - buf)) < 0) {
		/* nightmare!  the specs say content-length is mandatory
		 * so I don't feel overly bad stopping the reader here */
		archive_set_error(
			&a->archive, EINVAL,
			"Bad content length");
		return (ARCHIVE_FATAL);
	} else if ((rtime = _warc_rdrtm(buf, eoh - buf)) == (time_t)-1) {
		/* record time is mandatory as per WARC/1.0,
		 * so just barf here, fast and loud */
		archive_set_error(
			&a->archive, EINVAL,
			"Bad record time");
		return (ARCHIVE_FATAL);
	}

	/* let the world know we're a WARC archive */
	a->archive.archive_format = ARCHIVE_FORMAT_WARC;
	if (ver != w->pver) {
		/* stringify this entry's version */
		archive_string_sprintf(&w->sver,
			"WARC/%u.%u", ver / 10000, ver % 10000);
		/* remember the version */
		w->pver = ver;
	}
	/* start off with the type */
	ftyp = _warc_rdtyp(buf, eoh - buf);
	/* and let future calls know about the content */
	w->cntlen = cntlen;
	w->cntoff = 0U;
	mtime = 0;/* Avoid compiling error on some platform. */

	switch (ftyp) {
	case WT_RSRC:
	case WT_RSP:
		/* only try and read the filename in the cases that are
		 * guaranteed to have one */
		fnam = _warc_rduri(buf, eoh - buf);
		/* check the last character in the URI to avoid creating
		 * directory endpoints as files, see Todo above */
		if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {
			/* break here for now */
			fnam.len = 0U;
			fnam.str = NULL;
			break;
		}
		/* bang to our string pool, so we save a
		 * malloc()+free() roundtrip */
		if (fnam.len + 1U > w->pool.len) {
			w->pool.len = ((fnam.len + 64U) / 64U) * 64U;
			w->pool.str = realloc(w->pool.str, w->pool.len);
		}
		memcpy(w->pool.str, fnam.str, fnam.len);
		w->pool.str[fnam.len] = '\0';
		/* let noone else know about the pool, it's a secret, shhh */
		fnam.str = w->pool.str;

		/* snarf mtime or deduce from rtime
		 * this is a custom header added by our writer, it's quite
		 * hard to believe anyone else would go through with it
		 * (apart from being part of some http responses of course) */
		if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {
			mtime = rtime;
		}
		break;
	default:
		fnam.len = 0U;
		fnam.str = NULL;
		break;
	}

	/* now eat some of those delicious buffer bits */
	__archive_read_consume(a, eoh - buf);

	switch (ftyp) {
	case WT_RSRC:
	case WT_RSP:
		if (fnam.len > 0U) {
			/* populate entry object */
			archive_entry_set_filetype(entry, AE_IFREG);
			archive_entry_copy_pathname(entry, fnam.str);
			archive_entry_set_size(entry, cntlen);
			archive_entry_set_perm(entry, 0644);
			/* rtime is the new ctime, mtime stays mtime */
			archive_entry_set_ctime(entry, rtime, 0L);
			archive_entry_set_mtime(entry, mtime, 0L);
			break;
		}
		/* FALLTHROUGH */
	default:
		/* consume the content and start over */
		_warc_skip(a);
		goto start_over;
	}
	return (ARCHIVE_OK);
}
Exemple #22
0
void
archive_entry_unset_mtime(struct archive_entry *entry)
{
	archive_entry_set_mtime(entry, 0, 0);
	entry->ae_set &= ~AE_SET_MTIME;
}
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);
}
	void TarUtils::write(std::ostream &output, const io::ObservedFile &root, const std::set<ObservedFile> &files_to_send)
	{
		bool processed = false;

		//create new archive, set format to tar, use callbacks (above this method)
		struct archive *a;
		a = archive_write_new();
		archive_write_set_format_ustar(a);
		archive_write_open(a, &output, &__tar_utils_open_callback, &__tar_utils_write_callback, &__tar_utils_close_callback);

		for(std::set<ObservedFile>::const_iterator of_iter = files_to_send.begin(); of_iter != files_to_send.end(); ++of_iter)
		{
			const ObservedFile &of = (*of_iter);
			const ibrcommon::File &file = of.getFile();

			struct archive_entry *entry;
			entry = archive_entry_new();
			archive_entry_set_size(entry, file.size());

			if(file.isDirectory())
			{
				archive_entry_set_filetype(entry, AE_IFDIR);
				archive_entry_set_perm(entry, 0755);
			}
			else
			{
				archive_entry_set_filetype(entry, AE_IFREG);
				archive_entry_set_perm(entry, 0644);
			}

			archive_entry_set_pathname(entry, rel_filename(root, of).c_str());

			//set timestamps
			struct timespec ts;
			clock_gettime(CLOCK_REALTIME, &ts);
			archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec); //accesstime
			archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec); //creationtime
			archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec); //time, inode changed
			archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec); //modification time

			archive_write_header(a, entry);

			try {
#ifdef HAVE_LIBTFFS
				//read file on vfat-image
				try {
					const FATFile &ffile = dynamic_cast<const FATFile&>(file);
					processed = true;

					// get image reader
					const FatImageReader &reader = ffile.getReader();

					// open fat file
					io::FatImageReader::FileHandle fh = reader.open(ffile);

					char buff[BUFF_SIZE];
					ssize_t ret = 0;
					size_t len = 0;

					// read file
					len = fh.read((unsigned char*)&buff, BUFF_SIZE);

					//write buffer to archive
					while (len > 0)
					{
						if( (ret = archive_write_data(a, buff, len)) < 0)
						{
							IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive_write_data failed" << IBRCOMMON_LOGGER_ENDL;
							break;
						}

						// read next chunk
						len = fh.read((unsigned char*)&buff, BUFF_SIZE);
					}
				} catch (const std::bad_cast&) { };
#endif

				if (!processed)
				{
					char buff[BUFF_SIZE];
					ssize_t ret = 0;

					// open file for reading
					std::ifstream fs(file.getPath().c_str());

					// write buffer to archive
					while (fs.good())
					{
						// read bytes
						fs.read(buff, BUFF_SIZE);

						// write bytes to archive
						if( (ret = archive_write_data(a, buff, fs.gcount())) < 0)
						{
							IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive write failed" << IBRCOMMON_LOGGER_ENDL;
							break;
						}
					}
				}
			} catch (const ibrcommon::IOException &e) {
				// write failed
				IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive write failed: " << e.what() << IBRCOMMON_LOGGER_ENDL;

				archive_entry_free(entry);
				archive_write_close(a);
				archive_write_free(a);

				throw;
			}

			archive_entry_free(entry);
		}
		archive_write_close(a);
		archive_write_free(a);
	}
Exemple #25
0
/*
 * Parse a single keyword and its value.
 */
static int
parse_keyword(struct archive_read *a, struct mtree *mtree,
    struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)
{
	char *val, *key;

	key = opt->value;

	if (*key == '\0')
		return (ARCHIVE_OK);

	if (strcmp(key, "nochange") == 0) {
		*parsed_kws |= MTREE_HAS_NOCHANGE;
		return (ARCHIVE_OK);
	}
	if (strcmp(key, "optional") == 0) {
		*parsed_kws |= MTREE_HAS_OPTIONAL;
		return (ARCHIVE_OK);
	}
	if (strcmp(key, "ignore") == 0) {
		/*
		 * The mtree processing is not recursive, so
		 * recursion will only happen for explicitly listed
		 * entries.
		 */
		return (ARCHIVE_OK);
	}

	val = strchr(key, '=');
	if (val == NULL) {
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
		    "Malformed attribute \"%s\" (%d)", key, key[0]);
		return (ARCHIVE_WARN);
	}

	*val = '\0';
	++val;

	switch (key[0]) {
	case 'c':
		if (strcmp(key, "content") == 0
		    || strcmp(key, "contents") == 0) {
			parse_escapes(val, NULL);
			archive_strcpy(&mtree->contents_name, val);
			break;
		}
		if (strcmp(key, "cksum") == 0)
			break;
	case 'd':
		if (strcmp(key, "device") == 0) {
			*parsed_kws |= MTREE_HAS_DEVICE;
			return parse_device(&a->archive, entry, val);
		}
	case 'f':
		if (strcmp(key, "flags") == 0) {
			*parsed_kws |= MTREE_HAS_FFLAGS;
			archive_entry_copy_fflags_text(entry, val);
			break;
		}
	case 'g':
		if (strcmp(key, "gid") == 0) {
			*parsed_kws |= MTREE_HAS_GID;
			archive_entry_set_gid(entry, mtree_atol10(&val));
			break;
		}
		if (strcmp(key, "gname") == 0) {
			*parsed_kws |= MTREE_HAS_GNAME;
			archive_entry_copy_gname(entry, val);
			break;
		}
	case 'l':
		if (strcmp(key, "link") == 0) {
			archive_entry_copy_symlink(entry, val);
			break;
		}
	case 'm':
		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
			break;
		if (strcmp(key, "mode") == 0) {
			if (val[0] >= '0' && val[0] <= '9') {
				*parsed_kws |= MTREE_HAS_PERM;
				archive_entry_set_perm(entry,
				    (mode_t)mtree_atol8(&val));
			} else {
				archive_set_error(&a->archive,
				    ARCHIVE_ERRNO_FILE_FORMAT,
				    "Symbolic mode \"%s\" unsupported", val);
				return ARCHIVE_WARN;
			}
			break;
		}
	case 'n':
		if (strcmp(key, "nlink") == 0) {
			*parsed_kws |= MTREE_HAS_NLINK;
			archive_entry_set_nlink(entry,
				(unsigned int)mtree_atol10(&val));
			break;
		}
	case 'r':
		if (strcmp(key, "rmd160") == 0 ||
		    strcmp(key, "rmd160digest") == 0)
			break;
	case 's':
		if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
			break;
		if (strcmp(key, "sha256") == 0 ||
		    strcmp(key, "sha256digest") == 0)
			break;
		if (strcmp(key, "sha384") == 0 ||
		    strcmp(key, "sha384digest") == 0)
			break;
		if (strcmp(key, "sha512") == 0 ||
		    strcmp(key, "sha512digest") == 0)
			break;
		if (strcmp(key, "size") == 0) {
			archive_entry_set_size(entry, mtree_atol10(&val));
			break;
		}
	case 't':
		if (strcmp(key, "tags") == 0) {
			/*
			 * Comma delimited list of tags.
			 * Ignore the tags for now, but the interface
			 * should be extended to allow inclusion/exclusion.
			 */
			break;
		}
		if (strcmp(key, "time") == 0) {
			int64_t m;
			int64_t my_time_t_max = get_time_t_max();
			int64_t my_time_t_min = get_time_t_min();
			long ns;

			*parsed_kws |= MTREE_HAS_MTIME;
			m = mtree_atol10(&val);
			/* Replicate an old mtree bug:
			 * 123456789.1 represents 123456789
			 * seconds and 1 nanosecond. */
			if (*val == '.') {
				++val;
				ns = (long)mtree_atol10(&val);
			} else
				ns = 0;
			if (m > my_time_t_max)
				m = my_time_t_max;
			else if (m < my_time_t_min)
				m = my_time_t_min;
			archive_entry_set_mtime(entry, (time_t)m, ns);
			break;
		}
		if (strcmp(key, "type") == 0) {
			switch (val[0]) {
			case 'b':
				if (strcmp(val, "block") == 0) {
					archive_entry_set_filetype(entry, AE_IFBLK);
					break;
				}
			case 'c':
				if (strcmp(val, "char") == 0) {
					archive_entry_set_filetype(entry, AE_IFCHR);
					break;
				}
			case 'd':
				if (strcmp(val, "dir") == 0) {
					archive_entry_set_filetype(entry, AE_IFDIR);
					break;
				}
			case 'f':
				if (strcmp(val, "fifo") == 0) {
					archive_entry_set_filetype(entry, AE_IFIFO);
					break;
				}
				if (strcmp(val, "file") == 0) {
					archive_entry_set_filetype(entry, AE_IFREG);
					break;
				}
			case 'l':
				if (strcmp(val, "link") == 0) {
					archive_entry_set_filetype(entry, AE_IFLNK);
					break;
				}
			default:
				archive_set_error(&a->archive,
				    ARCHIVE_ERRNO_FILE_FORMAT,
				    "Unrecognized file type \"%s\"; assuming \"file\"", val);
				archive_entry_set_filetype(entry, AE_IFREG);
				return (ARCHIVE_WARN);
			}
			*parsed_kws |= MTREE_HAS_TYPE;
			break;
		}
	case 'u':
		if (strcmp(key, "uid") == 0) {
			*parsed_kws |= MTREE_HAS_UID;
			archive_entry_set_uid(entry, mtree_atol10(&val));
			break;
		}
		if (strcmp(key, "uname") == 0) {
			*parsed_kws |= MTREE_HAS_UNAME;
			archive_entry_copy_uname(entry, val);
			break;
		}
	default:
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
		    "Unrecognized key %s=%s", key, val);
		return (ARCHIVE_WARN);
	}
	return (ARCHIVE_OK);
}
Exemple #26
0
/*
 * A single file can have multiple lines contribute specifications.
 * Parse as many lines as necessary, then pull additional information
 * from a backing file on disk as necessary.
 */
static int
parse_file(struct archive_read *a, struct archive_entry *entry,
    struct mtree *mtree, struct mtree_entry *mentry, int *use_next)
{
	const char *path;
	struct stat st_storage, *st;
	struct mtree_entry *mp;
	struct archive_entry *sparse_entry;
	int r = ARCHIVE_OK, r1, parsed_kws;

	mentry->used = 1;

	/* Initialize reasonable defaults. */
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	archive_string_empty(&mtree->contents_name);

	/* Parse options from this line. */
	parsed_kws = 0;
	r = parse_line(a, entry, mtree, mentry, &parsed_kws);

	if (mentry->full) {
		archive_entry_copy_pathname(entry, mentry->name);
		/*
		 * "Full" entries are allowed to have multiple lines
		 * and those lines aren't required to be adjacent.  We
		 * don't support multiple lines for "relative" entries
		 * nor do we make any attempt to merge data from
		 * separate "relative" and "full" entries.  (Merging
		 * "relative" and "full" entries would require dealing
		 * with pathname canonicalization, which is a very
		 * tricky subject.)
		 */
		for (mp = mentry->next; mp != NULL; mp = mp->next) {
			if (mp->full && !mp->used
			    && strcmp(mentry->name, mp->name) == 0) {
				/* Later lines override earlier ones. */
				mp->used = 1;
				r1 = parse_line(a, entry, mtree, mp,
				    &parsed_kws);
				if (r1 < r)
					r = r1;
			}
		}
	} else {
		/*
		 * Relative entries require us to construct
		 * the full path and possibly update the
		 * current directory.
		 */
		size_t n = archive_strlen(&mtree->current_dir);
		if (n > 0)
			archive_strcat(&mtree->current_dir, "/");
		archive_strcat(&mtree->current_dir, mentry->name);
		archive_entry_copy_pathname(entry, mtree->current_dir.s);
		if (archive_entry_filetype(entry) != AE_IFDIR)
			mtree->current_dir.length = n;
	}

	/*
	 * Try to open and stat the file to get the real size
	 * and other file info.  It would be nice to avoid
	 * this here so that getting a listing of an mtree
	 * wouldn't require opening every referenced contents
	 * file.  But then we wouldn't know the actual
	 * contents size, so I don't see a really viable way
	 * around this.  (Also, we may want to someday pull
	 * other unspecified info from the contents file on
	 * disk.)
	 */
	mtree->fd = -1;
	if (archive_strlen(&mtree->contents_name) > 0)
		path = mtree->contents_name.s;
	else
		path = archive_entry_pathname(entry);

	if (archive_entry_filetype(entry) == AE_IFREG ||
	    archive_entry_filetype(entry) == AE_IFDIR) {
		mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
		__archive_ensure_cloexec_flag(mtree->fd);
		if (mtree->fd == -1 &&
		    (errno != ENOENT ||
		     archive_strlen(&mtree->contents_name) > 0)) {
			archive_set_error(&a->archive, errno,
			    "Can't open %s", path);
			r = ARCHIVE_WARN;
		}
	}

	st = &st_storage;
	if (mtree->fd >= 0) {
		if (fstat(mtree->fd, st) == -1) {
			archive_set_error(&a->archive, errno,
			    "Could not fstat %s", path);
			r = ARCHIVE_WARN;
			/* If we can't stat it, don't keep it open. */
			close(mtree->fd);
			mtree->fd = -1;
			st = NULL;
		}
	} else if (lstat(path, st) == -1) {
		st = NULL;
	}

	/*
	 * Check for a mismatch between the type in the specification and
	 * the type of the contents object on disk.
	 */
	if (st != NULL) {
		if (
		    ((st->st_mode & S_IFMT) == S_IFREG &&
		     archive_entry_filetype(entry) == AE_IFREG)
#ifdef S_IFLNK
		    || ((st->st_mode & S_IFMT) == S_IFLNK &&
			archive_entry_filetype(entry) == AE_IFLNK)
#endif
#ifdef S_IFSOCK
		    || ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
			archive_entry_filetype(entry) == AE_IFSOCK)
#endif
#ifdef S_IFCHR
		    || ((st->st_mode & S_IFMT) == S_IFCHR &&
			archive_entry_filetype(entry) == AE_IFCHR)
#endif
#ifdef S_IFBLK
		    || ((st->st_mode & S_IFMT) == S_IFBLK &&
			archive_entry_filetype(entry) == AE_IFBLK)
#endif
		    || ((st->st_mode & S_IFMT) == S_IFDIR &&
			archive_entry_filetype(entry) == AE_IFDIR)
#ifdef S_IFIFO
		    || ((st->st_mode & S_IFMT) == S_IFIFO &&
			archive_entry_filetype(entry) == AE_IFIFO)
#endif
		    ) {
			/* Types match. */
		} else {
			/* Types don't match; bail out gracefully. */
			if (mtree->fd >= 0)
				close(mtree->fd);
			mtree->fd = -1;
			if (parsed_kws & MTREE_HAS_OPTIONAL) {
				/* It's not an error for an optional entry
				   to not match disk. */
				*use_next = 1;
			} else if (r == ARCHIVE_OK) {
				archive_set_error(&a->archive,
				    ARCHIVE_ERRNO_MISC,
				    "mtree specification has different type for %s",
				    archive_entry_pathname(entry));
				r = ARCHIVE_WARN;
			}
			return r;
		}
	}

	/*
	 * If there is a contents file on disk, pick some of the metadata
	 * from that file.  For most of these, we only set it from the contents
	 * if it wasn't already parsed from the specification.
	 */
	if (st != NULL) {
		if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
		     (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
		    (archive_entry_filetype(entry) == AE_IFCHR ||
		     archive_entry_filetype(entry) == AE_IFBLK))
			archive_entry_set_rdev(entry, st->st_rdev);
		if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
			archive_entry_set_gid(entry, st->st_gid);
		if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
			archive_entry_set_uid(entry, st->st_uid);
		if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
			archive_entry_set_mtime(entry, st->st_mtime,
			    st->st_mtimespec.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
			archive_entry_set_mtime(entry, st->st_mtime,
			    st->st_mtim.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
			archive_entry_set_mtime(entry, st->st_mtime,
			    st->st_mtime_n);
#elif HAVE_STRUCT_STAT_ST_UMTIME
			archive_entry_set_mtime(entry, st->st_mtime,
			    st->st_umtime*1000);
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
			archive_entry_set_mtime(entry, st->st_mtime,
			    st->st_mtime_usec*1000);
#else
			archive_entry_set_mtime(entry, st->st_mtime, 0);
#endif
		}
		if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
			archive_entry_set_nlink(entry, st->st_nlink);
		if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
			archive_entry_set_perm(entry, st->st_mode);
		if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
			archive_entry_set_size(entry, st->st_size);
		archive_entry_set_ino(entry, st->st_ino);
		archive_entry_set_dev(entry, st->st_dev);

		archive_entry_linkify(mtree->resolver, &entry, &sparse_entry);
	} else if (parsed_kws & MTREE_HAS_OPTIONAL) {
		/*
		 * Couldn't open the entry, stat it or the on-disk type
		 * didn't match.  If this entry is optional, just ignore it
		 * and read the next header entry.
		 */
		*use_next = 1;
		return ARCHIVE_OK;
	}

	mtree->cur_size = archive_entry_size(entry);
	mtree->offset = 0;

	return r;
}
Exemple #27
0
int
packing_append_file_attr(struct packing *pack, const char *filepath,
    const char *newpath, const char *uname, const char *gname, mode_t perm,
    u_long fflags)
{
	int fd;
	int retcode = EPKG_OK;
	int ret;
	time_t source_time;
	struct stat st;
	struct archive_entry *entry, *sparse_entry;
	bool unset_timestamp;
	const char *source_date_epoch;
	char buf[32768];
	int len;

	entry = archive_entry_new();
	archive_entry_copy_sourcepath(entry, filepath);

	pkg_debug(2, "Packing file '%s'", filepath);

	if (lstat(filepath, &st) != 0) {
		pkg_emit_errno("lstat", filepath);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	ret = archive_read_disk_entry_from_file(pack->aread, entry, -1,
			&st);
	if (ret != ARCHIVE_OK) {
		pkg_emit_error("%s: %s", filepath,
				archive_error_string(pack->aread));
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	if (newpath != NULL)
		archive_entry_set_pathname(entry, newpath);

	if (archive_entry_filetype(entry) != AE_IFREG) {
		archive_entry_set_size(entry, 0);
	}

	if (uname != NULL && uname[0] != '\0') {
		archive_entry_set_uname(entry, uname);
	}

	if (gname != NULL && gname[0] != '\0') {
		archive_entry_set_gname(entry, gname);
	}

	if (fflags > 0)
		archive_entry_set_fflags(entry, fflags, 0);

	if (perm != 0)
		archive_entry_set_perm(entry, perm);

	unset_timestamp = pkg_object_bool(pkg_config_get("UNSET_TIMESTAMP"));

	if (unset_timestamp) {
		archive_entry_unset_atime(entry);
		archive_entry_unset_ctime(entry);
		archive_entry_unset_mtime(entry);
		archive_entry_unset_birthtime(entry);
	}

	if ((source_date_epoch = getenv("SOURCE_DATE_EPOCH")) != NULL) {
		if (source_date_epoch[strspn(source_date_epoch, "0123456789")] != '\0') {
			pkg_emit_error("Bad environment variable "
			    "SOURCE_DATE_EPOCH: %s", source_date_epoch);
			retcode = EPKG_FATAL;
			goto cleanup;
		}
		source_time = strtoll(source_date_epoch, NULL, 10);
		archive_entry_set_atime(entry, source_time, 0);
		archive_entry_set_ctime(entry, source_time, 0);
		archive_entry_set_mtime(entry, source_time, 0);
		archive_entry_set_birthtime(entry, source_time, 0);
	}

	archive_entry_linkify(pack->resolver, &entry, &sparse_entry);

	if (sparse_entry != NULL && entry == NULL)
		entry = sparse_entry;

	archive_write_header(pack->awrite, entry);

	if (archive_entry_size(entry) <= 0)
		goto cleanup;

	if ((fd = open(filepath, O_RDONLY)) < 0) {
		pkg_emit_errno("open", filepath);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	while ((len = read(fd, buf, sizeof(buf))) > 0) {
		if (archive_write_data(pack->awrite, buf, len) == -1) {
			pkg_emit_errno("archive_write_data", "archive write error");
			retcode = EPKG_FATAL;
			break;
		}
	}

	if (len == -1) {
		pkg_emit_errno("read", "file read error");
		retcode = EPKG_FATAL;
	}
	close(fd);

cleanup:
	archive_entry_free(entry);
	return (retcode);
}
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);
}
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
#endif
{
	int *marker;
	int matched;
	int i;
#if HAVE_SUN_ACL
	int e;
	aclent_t *acl_entry;
#else
	int entry_id = ACL_FIRST_ENTRY;
	acl_entry_t acl_entry;
#endif

	/* Count ACL entries in myacls array and allocate an indirect array. */
	marker = malloc(sizeof(marker[0]) * n);
	if (marker == NULL)
		return;
	for (i = 0; i < n; i++)
		marker[i] = i;

	/*
	 * Iterate over acls in system acl object, try to match each
	 * one with an item in the myacls array.
	 */
#if HAVE_SUN_ACL
	for(e = 0; e < acl->acl_cnt; e++) {
		acl_entry = &((aclent_t *)acl->acl_aclp)[e];
#else
	while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
		/* After the first time... */
		entry_id = ACL_NEXT_ENTRY;
#endif

		/* Search for a matching entry (tag and qualifier) */
		for (i = 0, matched = 0; i < n && !matched; i++) {
			if (acl_match(acl_entry, &myacls[marker[i]])) {
				/* We found a match; remove it. */
				marker[i] = marker[n - 1];
				n--;
				matched = 1;
			}
		}

		/* TODO: Print out more details in this case. */
		failure("ACL entry on file that shouldn't be there");
		assert(matched == 1);
	}

	/* Dump entries in the myacls array that weren't in the system acl. */
	for (i = 0; i < n; ++i) {
		failure(" ACL entry missing from file: "
		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
		    myacls[marker[i]].type, myacls[marker[i]].permset,
		    myacls[marker[i]].tag, myacls[marker[i]].qual,
		    myacls[marker[i]].name);
		assert(0); /* Record this as a failure. */
	}
	free(marker);
}

#endif


/*
 * Verify ACL restore-to-disk.  This test is Platform-specific.
 */

DEFINE_TEST(test_acl_platform_posix1e_restore)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
	struct stat st;
	struct archive *a;
	struct archive_entry *ae;
	int n, fd;
	char *func;
#if HAVE_SUN_ACL
	acl_t *acl, *acl2;
#else
	acl_t acl;
#endif

	/*
	 * First, do a quick manual set/read of ACL data to
	 * verify that the local filesystem does support ACLs.
	 * If it doesn't, we'll simply skip the remaining tests.
	 */
#if HAVE_SUN_ACL
	n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl != NULL);
#endif

	/* Create a test file and try ACL on it. */
	fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl);
		return;
	}

#if HAVE_SUN_ACL
	n = facl_get(fd, 0, &acl2);
	if (n != 0) {
		close(fd);
		acl_free(acl);
	}
	if (errno == ENOSYS) {
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl2->acl_type != ACLENT_T) {
		acl_free(acl2);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	acl_free(acl2);

	func = "facl_set()";
	n = facl_set(fd, acl);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl);
#endif
	acl_free(acl);
	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

#if HAVE_SUN_ACL

#endif
	close(fd);

	/* Create a write-to-disk object. */
	assert(NULL != (a = archive_write_disk_new()));
	archive_write_disk_set_options(a,
	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);

	/* Populate an archive entry with some metadata, including ACL info */
	ae = archive_entry_new();
	assert(ae != NULL);
	archive_entry_set_pathname(ae, "test0");
	archive_entry_set_mtime(ae, 123456, 7890);
	archive_entry_set_size(ae, 0);
	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);

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

	/* Verify the data on disk. */
	assertEqualInt(0, stat("test0", &st));
	assertEqualInt(st.st_mtime, 123456);
#if HAVE_SUN_ACL
	n = acl_get("test0", 0, &acl);
	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_get_file("test0", ACL_TYPE_ACCESS);
	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
	assert(acl != (acl_t)NULL);
#endif
	compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0]));
	acl_free(acl);
#endif	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
}

/*
 * Verify ACL read-from-disk.  This test is Platform-specific.
 */
DEFINE_TEST(test_acl_platform_posix1e_read)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else
	struct archive *a;
	struct archive_entry *ae;
	int n, fd, flags, dflags;
	char *func, *acl_text;
	const char *acl1_text, *acl2_text, *acl3_text;
#if HAVE_SUN_ACL
	acl_t *acl, *acl1, *acl2, *acl3;
#else
	acl_t acl1, acl2, acl3;
#endif

	/*
	 * Manually construct a directory and two files with
	 * different ACLs.  This also serves to verify that ACLs
	 * are supported on the local filesystem.
	 */

	/* Create a test file f1 with acl1 */
#if HAVE_SUN_ACL
	acl1_text = "user::rwx,"
	    "group::rwx,"
	    "other:rwx,"
	    "user:1:rw-,"
	    "group:15:r-x,"
	    "mask:rwx";
	n = acl_fromtext(acl1_text, &acl1);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl1_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::rwx\n"
	    "user:1:rw-\n"
	    "group:15:r-x\n"
	    "mask::rwx";
	acl1 = acl_from_text(acl1_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl1 != NULL);
#endif
	fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl1);
		return;
	}
#if HAVE_SUN_ACL
	/* Check if Solaris filesystem supports POSIX.1e ACLs */
	n = facl_get(fd, 0, &acl);
	if (n != 0)
		close(fd);
	if (n != 0 && errno == ENOSYS) {
		acl_free(acl1);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl->acl_type != ACLENT_T) {
		acl_free(acl);
		acl_free(acl1);
		close(fd);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}

	func = "facl_set()";
	n = facl_set(fd, acl1);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl1);
#endif
	acl_free(acl1);

	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	close(fd);

	assertMakeDir("d", 0700);

	/*
	 * Create file d/f1 with acl2
	 *
	 * This differs from acl1 in the u:1: and g:15: permissions.
	 *
	 * This file deliberately has the same name but a different ACL.
	 * Github Issue #777 explains how libarchive's directory traversal
	 * did not always correctly enter directories before attempting
	 * to read ACLs, resulting in reading the ACL from a like-named
	 * file in the wrong directory.
	 */
#if HAVE_SUN_ACL
	acl2_text = "user::rwx,"
	    "group::rwx,"
	    "other:---,"
	    "user:1:r--,"
	    "group:15:r--,"
	    "mask:rwx";
	n = acl_fromtext(acl2_text, &acl2);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl2_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::---\n"
	    "user:1:r--\n"
	    "group:15:r--\n"
	    "mask::rwx";
	acl2 = acl_from_text(acl2_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl2 != NULL);
#endif
	fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl2);
		return;
	}
#if HAVE_SUN_ACL
	func = "facl_set()";
	n = facl_set(fd, acl2);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl2);
#endif
	acl_free(acl2);
	if (n != 0)
		close(fd);
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);
	close(fd);

	/* Create nested directory d2 with default ACLs */
	assertMakeDir("d/d2", 0755);

#if HAVE_SUN_ACL
	acl3_text = "user::rwx,"
	    "group::r-x,"
	    "other:r-x,"
	    "user:2:r--,"
	    "group:16:-w-,"
	    "mask:rwx,"
	    "default:user::rwx,"
	    "default:user:1:r--,"
	    "default:group::r-x,"
	    "default:group:15:r--,"
	    "default:mask:rwx,"
	    "default:other:r-x";
	n = acl_fromtext(acl3_text, &acl3);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl3_text = "user::rwx\n"
	    "user:1:r--\n"
	    "group::r-x\n"
	    "group:15:r--\n"
	    "mask::rwx\n"
	    "other::r-x";
	acl3 = acl_from_text(acl3_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl3 != NULL);
#endif

#if HAVE_SUN_ACL
	func = "acl_set()";
	n = acl_set("d/d2", acl3);
#else
	func = "acl_set_file()";
	n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3);
#endif
	acl_free(acl3);

	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	/* Create a read-from-disk object. */
	assert(NULL != (a = archive_read_disk_new()));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
	assert(NULL != (ae = archive_entry_new()));

#if HAVE_SUN_ACL
	flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E
	    | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
	    | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS;
	dflags = flags;
#else
	flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
	dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
#endif

	/* Walk the dir until we see both of the files */
	while (ARCHIVE_OK == archive_read_next_header2(a, ae)) {
		archive_read_disk_descend(a);
		if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl1_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl2_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, dflags);
			assertEqualString(acl_text, acl3_text);
			free(acl_text);
		}
	}

	archive_entry_free(ae);
	assertEqualInt(ARCHIVE_OK, archive_free(a));
#endif
}
static int
archive_read_format_iso9660_read_header(struct archive_read *a,
    struct archive_entry *entry)
{
	struct iso9660 *iso9660;
	struct file_info *file;
	ssize_t bytes_read;
	int r;

	iso9660 = (struct iso9660 *)(a->format->data);

	if (!a->archive.archive_format) {
		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
		a->archive.archive_format_name = "ISO9660";
	}

	/* Get the next entry that appears after the current offset. */
	r = next_entry_seek(a, iso9660, &file);
	if (r != ARCHIVE_OK)
		return (r);

	iso9660->entry_bytes_remaining = file->size;
	iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */

	/* Set up the entry structure with information about this entry. */
	archive_entry_set_mode(entry, file->mode);
	archive_entry_set_uid(entry, file->uid);
	archive_entry_set_gid(entry, file->gid);
	archive_entry_set_nlink(entry, file->nlinks);
	archive_entry_set_ino(entry, file->inode);
	archive_entry_set_mtime(entry, file->mtime, 0);
	archive_entry_set_ctime(entry, file->ctime, 0);
	archive_entry_set_atime(entry, file->atime, 0);
	archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
	archive_string_empty(&iso9660->pathname);
	archive_entry_set_pathname(entry,
	    build_pathname(&iso9660->pathname, file));
	if (file->symlink.s != NULL)
		archive_entry_copy_symlink(entry, file->symlink.s);

	/* If this entry points to the same data as the previous
	 * entry, convert this into a hardlink to that entry.
	 * But don't bother for zero-length files. */
	if (file->offset == iso9660->previous_offset
	    && file->size == iso9660->previous_size
	    && file->size > 0) {
		archive_entry_set_hardlink(entry,
		    iso9660->previous_pathname.s);
		iso9660->entry_bytes_remaining = 0;
		iso9660->entry_sparse_offset = 0;
		release_file(iso9660, file);
		return (ARCHIVE_OK);
	}

	/* If the offset is before our current position, we can't
	 * seek backwards to extract it, so issue a warning. */
	if (file->offset < iso9660->current_position) {
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
		    "Ignoring out-of-order file");
		iso9660->entry_bytes_remaining = 0;
		iso9660->entry_sparse_offset = 0;
		release_file(iso9660, file);
		return (ARCHIVE_WARN);
	}

	iso9660->previous_size = file->size;
	iso9660->previous_offset = file->offset;
	archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s);

	/* If this is a directory, read in all of the entries right now. */
	if (archive_entry_filetype(entry) == AE_IFDIR) {
		while (iso9660->entry_bytes_remaining > 0) {
			const void *block;
			const unsigned char *p;
			ssize_t step = iso9660->logical_block_size;
			if (step > iso9660->entry_bytes_remaining)
				step = iso9660->entry_bytes_remaining;
			bytes_read = (a->decompressor->read_ahead)(a, &block, step);
			if (bytes_read < step) {
				archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
	    "Failed to read full block when scanning ISO9660 directory list");
				release_file(iso9660, file);
				return (ARCHIVE_FATAL);
			}
			if (bytes_read > step)
				bytes_read = step;
			(a->decompressor->consume)(a, bytes_read);
			iso9660->current_position += bytes_read;
			iso9660->entry_bytes_remaining -= bytes_read;
			for (p = (const unsigned char *)block;
			     *p != 0 && p < (const unsigned char *)block + bytes_read;
			     p += *p) {
				struct file_info *child;

				/* Skip '.' entry. */
				if (*(p + DR_name_len_offset) == 1
				    && *(p + DR_name_offset) == '\0')
					continue;
				/* Skip '..' entry. */
				if (*(p + DR_name_len_offset) == 1
				    && *(p + DR_name_offset) == '\001')
					continue;
				child = parse_file_info(iso9660, file, p);
				add_entry(iso9660, child);
				if (iso9660->seenRockridge) {
					a->archive.archive_format =
					    ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
					a->archive.archive_format_name =
					    "ISO9660 with Rockridge extensions";
				}
			}
		}
	}

	release_file(iso9660, file);
	return (ARCHIVE_OK);
}