static void
test_symlink(void)
{
	const char *refname = "test_read_format_zip_symlink.zip";
	char *p;
	size_t s;
	struct archive *a;
	struct archive_entry *ae;

	extract_reference_file(refname);
	p = slurpfile(&s, refname);

	/* Symlinks can only be extracted with the seeking reader. */
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
	assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("file", archive_entry_pathname(ae));
	assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("symlink", archive_entry_pathname(ae));
	assertEqualInt(AE_IFLNK, archive_entry_filetype(ae));
	assertEqualInt(0, archive_entry_size(ae));
	assertEqualString("file", archive_entry_symlink(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);

	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
Example #2
0
static int ar_entry_symlink(lua_State *L) {
    struct archive_entry* self = *ar_entry_check(L, 1);
    int is_set;
    if ( NULL == self ) return 0;

    is_set = ( lua_gettop(L) == 2 );
    lua_pushstring(L, archive_entry_symlink(self));
    if ( is_set ) {
        archive_entry_copy_symlink(self, lua_tostring(L, 2));
    }
    return 1;
}
Example #3
0
static gboolean
asb_utils_explode_file (struct archive_entry *entry, const gchar *dir)
{
	const gchar *tmp;
	g_autofree gchar *path = NULL;
	g_autofree gchar *buf = NULL;

	/* no output file */
	if (archive_entry_pathname (entry) == NULL)
		return FALSE;

	/* update output path */
	tmp = archive_entry_pathname (entry);
	path = asb_utils_sanitise_path (tmp);
	buf = g_build_filename (dir, path, NULL);
	archive_entry_update_pathname_utf8 (entry, buf);

	/* update hardlinks */
	tmp = archive_entry_hardlink (entry);
	if (tmp != NULL) {
		g_autofree gchar *buf_link = NULL;
		g_autofree gchar *path_link = NULL;
		path_link = asb_utils_sanitise_path (tmp);
		buf_link = g_build_filename (dir, path_link, NULL);
		if (!g_file_test (buf_link, G_FILE_TEST_EXISTS)) {
			g_warning ("%s does not exist, cannot hardlink", tmp);
			return FALSE;
		}
		archive_entry_update_hardlink_utf8 (entry, buf_link);
	}

	/* update symlinks */
	tmp = archive_entry_symlink (entry);
	if (tmp != NULL) {
		g_autofree gchar *path_link = NULL;

		path_link = asb_utils_sanitise_path (tmp);
		if (g_path_is_absolute (path_link)) {
			guint symlink_depth;
			g_autofree gchar *back_up = NULL;
			g_autofree gchar *buf_link = NULL;

			symlink_depth = asb_utils_count_directories_deep (path) - 1;
			back_up = asb_utils_get_back_to_root (symlink_depth);
			buf_link = g_build_filename (back_up, tmp, NULL);

			archive_entry_update_symlink_utf8 (entry, buf_link);
		} else {
			archive_entry_update_symlink_utf8 (entry, path_link);
		}
	}
	return TRUE;
}
static void verify4(struct archive_entry *ae)
{
	assert(S_ISBLK(archive_entry_mode(ae)));
	assertEqualInt(archive_entry_mode(ae) & 0777, 0755);
	assertEqualInt(archive_entry_uid(ae), 1000);
	assertEqualInt(archive_entry_gid(ae), 1000);
	assertEqualString(archive_entry_uname(ae), "tim");
	assertEqualString(archive_entry_gname(ae), "tim");
	assertEqualString(archive_entry_pathname(ae), "devblock");
	assert(archive_entry_symlink(ae) == NULL);
	assert(archive_entry_hardlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 1184389185);
}
Example #5
0
/* Print destination paths at DEBUG level. */
static void print_paths(struct archive_entry *entry)
{
    const char *path = archive_entry_pathname(entry);
    const char *hardlink = archive_entry_hardlink(entry);
    const char *symlink = archive_entry_symlink(entry);
    if (hardlink)
        opkg_msg(DEBUG, "Extracting '%s', hardlink to '%s'.\n", path, hardlink);
    else if (symlink)
        opkg_msg(DEBUG, "Extracting '%s', symlink to '%s'.\n", path, symlink);
    else
        opkg_msg(DEBUG, "Extracting '%s'.\n", path);

}
static void verify6(struct archive_entry *ae)
{
	assertEqualInt(archive_entry_filetype(ae), AE_IFIFO);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0755);
	assertEqualInt(archive_entry_uid(ae), 1000);
	assertEqualInt(archive_entry_gid(ae), 1000);
	assertEqualString(archive_entry_uname(ae), "tim");
	assertEqualString(archive_entry_gname(ae), "tim");
	assertEqualString(archive_entry_pathname(ae), "fifo");
	assert(archive_entry_symlink(ae) == NULL);
	assert(archive_entry_hardlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 1184389185);
}
Example #7
0
static void verify2(struct archive *a, struct archive_entry *ae)
{
	(void)a; /* UNUSED */
	assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0755);
	assertEqualInt(archive_entry_uid(ae), UID);
	assertEqualInt(archive_entry_gid(ae), GID);
	assertEqualString(archive_entry_uname(ae), UNAME);
	assertEqualString(archive_entry_gname(ae), GNAME);
	assertEqualString(archive_entry_pathname(ae), "symlink");
	assertEqualString(archive_entry_symlink(ae), "f1");
	assert(archive_entry_hardlink(ae) == NULL);
}
static int
archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
{
	char buff[512];
	int ret, ret2;
	struct ustar *ustar;

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

	/* Only regular files (not hardlinks) have data. */
	if (archive_entry_hardlink(entry) != NULL ||
	    archive_entry_symlink(entry) != NULL ||
	    !(archive_entry_filetype(entry) == AE_IFREG))
		archive_entry_set_size(entry, 0);

	if (AE_IFDIR == archive_entry_filetype(entry)) {
		const char *p;
		char *t;
		/*
		 * Ensure a trailing '/'.  Modify the entry so
		 * the client sees the change.
		 */
		p = archive_entry_pathname(entry);
		if (p[strlen(p) - 1] != '/') {
			t = (char *)malloc(strlen(p) + 2);
			if (t == NULL) {
				archive_set_error(&a->archive, ENOMEM,
				"Can't allocate ustar data");
				return(ARCHIVE_FATAL);
			}
			strcpy(t, p);
			strcat(t, "/");
			archive_entry_copy_pathname(entry, t);
			free(t);
		}
	}

	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
	if (ret < ARCHIVE_WARN)
		return (ret);
	ret2 = (a->compressor.write)(a, buff, 512);
	if (ret2 < ARCHIVE_WARN)
		return (ret2);
	if (ret2 < ret)
		ret = ret2;

	ustar->entry_bytes_remaining = archive_entry_size(entry);
	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
	return (ret);
}
Example #9
0
static void verify7(struct archive *a, struct archive_entry *ae)
{
	(void)a; /* UNUSED */
	assert(archive_entry_filetype(ae) == AE_IFREG);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0644);
	assertEqualInt(archive_entry_uid(ae), UID);
	assertEqualInt(archive_entry_gid(ae), GID);
	assertEqualString(archive_entry_uname(ae), UNAME);
	assertEqualString(archive_entry_gname(ae), GNAME);
	assertEqualString(archive_entry_pathname(ae), "dir1/f1");
	assert(archive_entry_hardlink(ae) == NULL);
	assert(archive_entry_symlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 86401);
}
Example #10
0
static void
test_symname()
{
	const char *refname = "test_read_format_7zip_symbolic_name.7z";
	struct archive_entry *ae;
	struct archive *a;
	char buff[128];

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

	/* Verify regular file1. */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae));
	assertEqualString("file1", archive_entry_pathname(ae));
	assertEqualInt(86401, archive_entry_mtime(ae));
	assertEqualInt(32, archive_entry_size(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);
	assertEqualInt(32, archive_read_data(a, buff, sizeof(buff)));
	assertEqualMem(buff, "hellohellohello\nhellohellohello\n", 32);

	/* Verify symbolic-linke symlinkfile. */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualInt((AE_IFLNK | 0755), archive_entry_mode(ae));
	assertEqualString("symlinkfile", archive_entry_pathname(ae));
	assertEqualString("file1", archive_entry_symlink(ae));
	assertEqualInt(86401, archive_entry_mtime(ae));
	assertEqualInt(archive_entry_is_encrypted(ae), 0);
	assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0);

	assertEqualInt(2, archive_file_count(a));

	/* End of archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	/* Verify archive format. */
	assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
	assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));

	/* Close the archive. */
	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #11
0
int cmp_target(alpm_pkg_t *pkg, const char *path,
		struct archive_entry *entry)
{
	const char *ptarget = archive_entry_symlink(entry);
	char ftarget[PATH_MAX];
	ssize_t len = readlink(path, ftarget, PATH_MAX);
	ftarget[len] = '\0';

	if(strcmp(ptarget, ftarget) != 0) {
		eprintf("%s: '%s' symlink target mismatch (expected %s)\n",
				alpm_pkg_get_name(pkg), path, ptarget);
		return 1;
	}

	return 0;
}
static void verify1(struct archive_entry *ae)
{
	/* A hardlink is not a symlink. */
	assert(archive_entry_filetype(ae) != AE_IFLNK);
	/* Nor is it a directory. */
	assert(archive_entry_filetype(ae) != AE_IFDIR);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0644);
	assertEqualInt(archive_entry_uid(ae), 1000);
	assertEqualInt(archive_entry_gid(ae), 1000);
	assertEqualString(archive_entry_uname(ae), "tim");
	assertEqualString(archive_entry_gname(ae), "tim");
	assertEqualString(archive_entry_pathname(ae), "hardlink");
	assertEqualString(archive_entry_hardlink(ae), "file");
	assert(archive_entry_symlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 1184388530);
}
Example #13
0
static void verify1(struct archive *a, struct archive_entry *ae)
{
	(void)a; /* UNUSED */
	/* A hardlink is not a symlink. */
	assert(archive_entry_filetype(ae) != AE_IFLNK);
	/* Nor is it a directory. */
	assert(archive_entry_filetype(ae) != AE_IFDIR);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0644);
	assertEqualInt(archive_entry_uid(ae), UID);
	assertEqualInt(archive_entry_gid(ae), GID);
	assertEqualString(archive_entry_uname(ae), UNAME);
	assertEqualString(archive_entry_gname(ae), GNAME);
	assertEqualString(archive_entry_pathname(ae), "hardlink");
	assertEqualString(archive_entry_hardlink(ae), "f1");
	assert(archive_entry_symlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 86401);
	assertEqualInt(archive_entry_nlink(ae), 2);
}
static void verifyxL(struct archive_entry *ae)
{
	assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0755);
	assertEqualInt(archive_entry_uid(ae), 1000);
	assertEqualInt(archive_entry_gid(ae), 1000);
	assertEqualString(archive_entry_uname(ae), "tim");
	assertEqualString(archive_entry_gname(ae), "tim");
	assertEqualString(archive_entry_pathname(ae), "symlink");
	assertEqualString(archive_entry_symlink(ae),
	    "this_is_a_very_long_symlink_body_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_"
	    "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz");
	assert(archive_entry_hardlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 1184390648);
}
Example #15
0
static void verify0(struct archive *a, struct archive_entry *ae)
{
	const void *p;
	size_t size;
	int64_t offset;

	assert(archive_entry_filetype(ae) == AE_IFREG);
	assertEqualInt(archive_entry_mode(ae) & 0777, 0644);
	assertEqualInt(archive_entry_uid(ae), UID);
	assertEqualInt(archive_entry_gid(ae), GID);
	assertEqualString(archive_entry_uname(ae), UNAME);
	assertEqualString(archive_entry_gname(ae), GNAME);
	assertEqualString(archive_entry_pathname(ae), "f1");
	assert(archive_entry_hardlink(ae) == NULL);
	assert(archive_entry_symlink(ae) == NULL);
	assertEqualInt(archive_entry_mtime(ae), 86401);
	assertEqualInt(archive_entry_size(ae), 16);
	assertEqualInt(archive_read_data_block(a, &p, &size, &offset), 0);
	assertEqualInt((int)size, 16);
	assertEqualInt((int)offset, 0);
	assertEqualMem(p, "hellohellohello\n", 16);
}
Example #16
0
static int check_file_link(const char *pkgname, const char *filepath,
		struct stat *st, struct archive_entry *entry)
{
	size_t length = st->st_size + 1;
	char link[length];

	if(readlink(filepath, link, length) != st->st_size) {
		/* this should not happen */
		pm_printf(ALPM_LOG_ERROR, _("unable to read symlink contents: %s\n"), filepath);
		return 1;
	}
	link[length - 1] = '\0';

	if(strcmp(link, archive_entry_symlink(entry)) != 0) {
		if(!config->quiet) {
			pm_printf(ALPM_LOG_WARNING, _("%s: %s (Symlink path mismatch)\n"),
					pkgname, filepath);
		}
		return 1;
	}

	return 0;
}
Example #17
0
static int
archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
{
	struct zip *zip;
	uint8_t h[SIZE_LOCAL_FILE_HEADER];
	uint8_t e[SIZE_EXTRA_DATA_LOCAL];
	uint8_t *d;
	struct zip_file_header_link *l;
	struct archive_string_conv *sconv;
	int ret, ret2 = ARCHIVE_OK;
	int64_t size;
	mode_t type;

	/* Entries other than a regular file or a folder are skipped. */
	type = archive_entry_filetype(entry);
	if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
		    "Filetype not supported");
		return ARCHIVE_FAILED;
	};

	/* Directory entries should have a size of 0. */
	if (type == AE_IFDIR)
		archive_entry_set_size(entry, 0);

	zip = a->format_data;
	/* Setup default conversion. */
	if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
		zip->sconv_default =
		    archive_string_default_conversion_for_write(&(a->archive));
		zip->init_default_conversion = 1;
	}

	if (zip->flags == 0) {
		/* Initialize the general purpose flags. */
		zip->flags = ZIP_FLAGS;
		if (zip->opt_sconv != NULL) {
			if (strcmp(archive_string_conversion_charset_name(
			    zip->opt_sconv), "UTF-8") == 0)
				zip->flags |= ZIP_FLAGS_UTF8_NAME;
#if HAVE_NL_LANGINFO
		} else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
			zip->flags |= ZIP_FLAGS_UTF8_NAME;
#endif
		}
	}
	d = zip->data_descriptor;
	size = archive_entry_size(entry);
	zip->remaining_data_bytes = size;

	/* Append archive entry to the central directory data. */
	l = (struct zip_file_header_link *) malloc(sizeof(*l));
	if (l == NULL) {
		archive_set_error(&a->archive, ENOMEM,
		    "Can't allocate zip header data");
		return (ARCHIVE_FATAL);
	}
#if defined(_WIN32) && !defined(__CYGWIN__)
	/* Make sure the path separators in pahtname, hardlink and symlink
	 * are all slash '/', not the Windows path separator '\'. */
	l->entry = __la_win_entry_in_posix_pathseparator(entry);
	if (l->entry == entry)
		l->entry = archive_entry_clone(entry);
#else
	l->entry = archive_entry_clone(entry);
#endif
	if (l->entry == NULL) {
		archive_set_error(&a->archive, ENOMEM,
		    "Can't allocate zip header data");
		free(l);
		return (ARCHIVE_FATAL);
	}
	l->flags = zip->flags;
	if (zip->opt_sconv != NULL)
		sconv = zip->opt_sconv;
	else
		sconv = zip->sconv_default;
	if (sconv != NULL) {
		const char *p;
		size_t len;

		if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {
			if (errno == ENOMEM) {
				archive_entry_free(l->entry);
				free(l);
				archive_set_error(&a->archive, ENOMEM,
				    "Can't allocate memory for Pathname");
				return (ARCHIVE_FATAL);
			}
			archive_set_error(&a->archive,
			    ARCHIVE_ERRNO_FILE_FORMAT,
			    "Can't translate Pathname '%s' to %s",
			    archive_entry_pathname(entry),
			    archive_string_conversion_charset_name(sconv));
			ret2 = ARCHIVE_WARN;
		}
		if (len > 0)
			archive_entry_set_pathname(l->entry, p);

		/*
		 * Although there is no character-set regulation for Symlink,
		 * it is suitable to convert a character-set of Symlinke to
		 * what those of the Pathname has been converted to.
		 */
		if (type == AE_IFLNK) {
			if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
				if (errno == ENOMEM) {
					archive_entry_free(l->entry);
					free(l);
					archive_set_error(&a->archive, ENOMEM,
					    "Can't allocate memory "
					    " for Symlink");
					return (ARCHIVE_FATAL);
				}
				/*
				 * Even if the strng conversion failed,
				 * we should not report the error since
				 * thre is no regulation for.
				 */
			} else if (len > 0)
				archive_entry_set_symlink(l->entry, p);
		}
	}
	/* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
	if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
	    is_all_ascii(archive_entry_pathname(l->entry)))
		l->flags &= ~ZIP_FLAGS_UTF8_NAME;

	/* Initialize the CRC variable and potentially the local crc32(). */
	l->crc32 = crc32(0, NULL, 0);
	if (type == AE_IFLNK) {
		const char *p = archive_entry_symlink(l->entry);
		if (p != NULL)
			size = strlen(p);
		else
			size = 0;
		zip->remaining_data_bytes = 0;
		archive_entry_set_size(l->entry, size);
		l->compression = COMPRESSION_STORE;
		l->compressed_size = size;
	} else {
		l->compression = zip->compression;
		l->compressed_size = 0;
	}
	l->next = NULL;
	if (zip->central_directory == NULL) {
		zip->central_directory = l;
	} else {
		zip->central_directory_end->next = l;
	}
	zip->central_directory_end = l;

	/* Store the offset of this header for later use in central
	 * directory. */
	l->offset = zip->written_bytes;

	memset(h, 0, sizeof(h));
	archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
		ZIP_SIGNATURE_LOCAL_FILE_HEADER);
	archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
	archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
	archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
	archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
		dos_time(archive_entry_mtime(entry)));
	archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
		(uint16_t)path_length(l->entry));

	switch (l->compression) {
	case COMPRESSION_STORE:
		/* Setting compressed and uncompressed sizes even when
		 * specification says to set to zero when using data
		 * descriptors. Otherwise the end of the data for an
		 * entry is rather difficult to find. */
		archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
		    (uint32_t)size);
		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
		    (uint32_t)size);
		break;
#ifdef HAVE_ZLIB_H
	case COMPRESSION_DEFLATE:
		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
		    (uint32_t)size);

		zip->stream.zalloc = Z_NULL;
		zip->stream.zfree = Z_NULL;
		zip->stream.opaque = Z_NULL;
		zip->stream.next_out = zip->buf;
		zip->stream.avail_out = (uInt)zip->len_buf;
		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
			archive_set_error(&a->archive, ENOMEM,
			    "Can't init deflate compressor");
			return (ARCHIVE_FATAL);
		}
		break;
#endif
	}

	/* Formatting extra data. */
	archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
		ZIP_SIGNATURE_EXTRA_TIMESTAMP);
	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
	e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
	    (uint32_t)archive_entry_mtime(entry));
	archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
	    (uint32_t)archive_entry_atime(entry));
	archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
	    (uint32_t)archive_entry_ctime(entry));

	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
		ZIP_SIGNATURE_EXTRA_NEW_UNIX);
	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
	e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
	e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
		(uint32_t)archive_entry_uid(entry));
	e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
		(uint32_t)archive_entry_gid(entry));

	archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
	    (uint32_t)size);

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

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

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

	if (type == AE_IFLNK) {
		const unsigned char *p;

		p = (const unsigned char *)archive_entry_symlink(l->entry);
		ret = __archive_write_output(a, p, (size_t)size);
		if (ret != ARCHIVE_OK)
			return (ARCHIVE_FATAL);
		zip->written_bytes += size;
		l->crc32 = crc32(l->crc32, p, (unsigned)size);
	}

	if (ret2 != ARCHIVE_OK)
		return (ret2);
	return (ARCHIVE_OK);
}
Example #18
0
/**
 * asb_utils_explode:
 * @filename: package filename
 * @dir: directory to decompress into
 * @glob: (element-type utf8): filename globs, or %NULL
 * @error: A #GError or %NULL
 *
 * Decompresses the package into a given directory.
 *
 * Returns: %TRUE for success, %FALSE otherwise
 *
 * Since: 0.1.0
 **/
gboolean
asb_utils_explode (const gchar *filename,
		   const gchar *dir,
		   GPtrArray *glob,
		   GError **error)
{
	const gchar *tmp;
	gboolean ret = TRUE;
	gboolean valid;
	int r;
	struct archive *arch = NULL;
	struct archive *arch_preview = NULL;
	struct archive_entry *entry;
	g_autoptr(GHashTable) matches = NULL;

	/* populate a hash with all the files, symlinks and hardlinks that
	 * actually need decompressing */
	arch_preview = archive_read_new ();
	archive_read_support_format_all (arch_preview);
	archive_read_support_filter_all (arch_preview);
	r = archive_read_open_filename (arch_preview, filename, 1024 * 32);
	if (r) {
		ret = FALSE;
		g_set_error (error,
			     ASB_PLUGIN_ERROR,
			     ASB_PLUGIN_ERROR_FAILED,
			     "Cannot open: %s",
			     archive_error_string (arch_preview));
		goto out;
	}
	matches = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
	for (;;) {
		g_autofree gchar *path = NULL;
		r = archive_read_next_header (arch_preview, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r != ARCHIVE_OK) {
			ret = FALSE;
			g_set_error (error,
				     ASB_PLUGIN_ERROR,
				     ASB_PLUGIN_ERROR_FAILED,
				     "Cannot read header: %s",
				     archive_error_string (arch_preview));
			goto out;
		}

		/* get the destination filename */
		tmp = archive_entry_pathname (entry);
		if (tmp == NULL)
			continue;
		path = asb_utils_sanitise_path (tmp);
		if (glob != NULL) {
			if (asb_glob_value_search (glob, path) == NULL)
				continue;
		}
		g_hash_table_insert (matches, g_strdup (path), GINT_TO_POINTER (1));

		/* add hardlink */
		tmp = archive_entry_hardlink (entry);
		if (tmp != NULL) {
			g_hash_table_insert (matches,
					     asb_utils_sanitise_path (tmp),
					     GINT_TO_POINTER (1));
		}

		/* add symlink */
		tmp = archive_entry_symlink (entry);
		if (tmp != NULL) {
			if (g_path_is_absolute (tmp)) {
				g_hash_table_insert (matches,
						     asb_utils_sanitise_path (tmp),
						     GINT_TO_POINTER (1));
			} else {
				g_autofree gchar *parent_dir = g_path_get_dirname (path);
				g_hash_table_insert (matches,
						     asb_utils_resolve_relative_symlink (parent_dir, tmp),
						     GINT_TO_POINTER (1));
			}
		}
	}

	/* decompress anything matching either glob */
	arch = archive_read_new ();
	archive_read_support_format_all (arch);
	archive_read_support_filter_all (arch);
	r = archive_read_open_filename (arch, filename, 1024 * 32);
	if (r) {
		ret = FALSE;
		g_set_error (error,
			     ASB_PLUGIN_ERROR,
			     ASB_PLUGIN_ERROR_FAILED,
			     "Cannot open: %s",
			     archive_error_string (arch));
		goto out;
	}
	for (;;) {
		g_autofree gchar *path = NULL;
		r = archive_read_next_header (arch, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r != ARCHIVE_OK) {
			ret = FALSE;
			g_set_error (error,
				     ASB_PLUGIN_ERROR,
				     ASB_PLUGIN_ERROR_FAILED,
				     "Cannot read header: %s",
				     archive_error_string (arch));
			goto out;
		}

		/* only extract if valid */
		tmp = archive_entry_pathname (entry);
		path = asb_utils_sanitise_path (tmp);
		if (g_hash_table_lookup (matches, path) == NULL)
			continue;
		valid = asb_utils_explode_file (entry, dir);
		if (!valid)
			continue;
		r = archive_read_extract (arch, entry, 0);
		if (r != ARCHIVE_OK) {
			ret = FALSE;
			g_set_error (error,
				     ASB_PLUGIN_ERROR,
				     ASB_PLUGIN_ERROR_FAILED,
				     "Cannot extract: %s",
				     archive_error_string (arch));
			goto out;
		}
	}
out:
	if (arch_preview != NULL) {
		archive_read_close (arch_preview);
		archive_read_free (arch_preview);
	}
	if (arch != NULL) {
		archive_read_close (arch);
		archive_read_free (arch);
	}
	return ret;
}
Example #19
0
/*
 * Display information about the current file.
 *
 * The format here roughly duplicates the output of 'ls -l'.
 * This is based on SUSv2, where 'tar tv' is documented as
 * listing additional information in an "unspecified format,"
 * and 'pax -l' is documented as using the same format as 'ls -l'.
 */
static void
list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
{
	char			 tmp[100];
	size_t			 w;
	const char		*p;
	const char		*fmt;
	time_t			 tim;
	static time_t		 now;

	/*
	 * We avoid collecting the entire list in memory at once by
	 * listing things as we see them.  However, that also means we can't
	 * just pre-compute the field widths.  Instead, we start with guesses
	 * and just widen them as necessary.  These numbers are completely
	 * arbitrary.
	 */
	if (!bsdtar->u_width) {
		bsdtar->u_width = 6;
		bsdtar->gs_width = 13;
	}
	if (!now)
		time(&now);
	fprintf(out, "%s %d ",
	    archive_entry_strmode(entry),
	    archive_entry_nlink(entry));

	/* Use uname if it's present, else uid. */
	p = archive_entry_uname(entry);
	if ((p == NULL) || (*p == '\0')) {
		sprintf(tmp, "%lu ",
		    (unsigned long)archive_entry_uid(entry));
		p = tmp;
	}
	w = strlen(p);
	if (w > bsdtar->u_width)
		bsdtar->u_width = w;
	fprintf(out, "%-*s ", (int)bsdtar->u_width, p);

	/* Use gname if it's present, else gid. */
	p = archive_entry_gname(entry);
	if (p != NULL && p[0] != '\0') {
		fprintf(out, "%s", p);
		w = strlen(p);
	} else {
		sprintf(tmp, "%lu",
		    (unsigned long)archive_entry_gid(entry));
		w = strlen(tmp);
		fprintf(out, "%s", tmp);
	}

	/*
	 * Print device number or file size, right-aligned so as to make
	 * total width of group and devnum/filesize fields be gs_width.
	 * If gs_width is too small, grow it.
	 */
	if (archive_entry_filetype(entry) == AE_IFCHR
	    || archive_entry_filetype(entry) == AE_IFBLK) {
		sprintf(tmp, "%lu,%lu",
		    (unsigned long)archive_entry_rdevmajor(entry),
		    (unsigned long)archive_entry_rdevminor(entry));
	} else {
		strcpy(tmp, tar_i64toa(archive_entry_size(entry)));
	}
	if (w + strlen(tmp) >= bsdtar->gs_width)
		bsdtar->gs_width = w+strlen(tmp)+1;
	fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);

	/* Format the time using 'ls -l' conventions. */
	tim = archive_entry_mtime(entry);
#define HALF_YEAR (time_t)365 * 86400 / 2
#if defined(_WIN32) && !defined(__CYGWIN__)
#define DAY_FMT  "%d"  /* Windows' strftime function does not support %e format. */
#else
#define DAY_FMT  "%e"  /* Day number without leading zeros */
#endif
	if (tim < now - HALF_YEAR || tim > now + HALF_YEAR)
		fmt = bsdtar->day_first ? DAY_FMT " %b  %Y" : "%b " DAY_FMT "  %Y";
	else
		fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M";
	strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
	fprintf(out, " %s ", tmp);
	safe_fprintf(out, "%s", archive_entry_pathname(entry));

	/* Extra information for links. */
	if (archive_entry_hardlink(entry)) /* Hard link */
		safe_fprintf(out, " link to %s",
		    archive_entry_hardlink(entry));
	else if (archive_entry_symlink(entry)) /* Symbolic link */
		safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
}
static int
archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
{
	struct cpio *cpio;
	const char *p, *path;
	int pathlength, ret;
	struct cpio_header	 h;

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

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

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

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

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

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

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

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

	cpio->entry_bytes_remaining = archive_entry_size(entry);

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

	return (ret);
}
Example #21
0
/*
 * Display information about the current file.
 *
 * The format here roughly duplicates the output of 'ls -l'.
 * This is based on SUSv2, where 'tar tv' is documented as
 * listing additional information in an "unspecified format,"
 * and 'pax -l' is documented as using the same format as 'ls -l'.
 */
static void
list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
{
	char			 size[32];
	char			 date[32];
	char			 uids[16], gids[16];
	const char 		*uname, *gname;
	FILE			*out = stdout;
	const char		*fmt;
	time_t			 mtime;
	static time_t		 now;
	struct tm		*tm;

	if (!now)
		time(&now);

	if (cpio->option_numeric_uid_gid) {
		/* Format numeric uid/gid for display. */
		strcpy(uids, cpio_i64toa(archive_entry_uid(entry)));
		uname = uids;
		strcpy(gids, cpio_i64toa(archive_entry_gid(entry)));
		gname = gids;
	} else {
		/* Use uname if it's present, else lookup name from uid. */
		uname = archive_entry_uname(entry);
		if (uname == NULL)
			uname = lookup_uname(cpio, archive_entry_uid(entry));
		/* Use gname if it's present, else lookup name from gid. */
		gname = archive_entry_gname(entry);
		if (gname == NULL)
			gname = lookup_gname(cpio, archive_entry_gid(entry));
	}

	/* Print device number or file size. */
	if (archive_entry_filetype(entry) == AE_IFCHR
	    || archive_entry_filetype(entry) == AE_IFBLK) {
		snprintf(size, sizeof(size), "%lu,%lu",
		    (unsigned long)archive_entry_rdevmajor(entry),
		    (unsigned long)archive_entry_rdevminor(entry));
	} else {
		strcpy(size, cpio_i64toa(archive_entry_size(entry)));
	}

	/* Format the time using 'ls -l' conventions. */
	mtime = archive_entry_mtime(entry);
#if defined(_WIN32) && !defined(__CYGWIN__)
	/* Windows' strftime function does not support %e format. */
	if (mtime - now > 365*86400/2
		|| mtime - now < -365*86400/2)
		fmt = cpio->day_first ? "%d %b  %Y" : "%b %d  %Y";
	else
		fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M";
#else
	if (abs(mtime - now) > (365/2)*86400)
		fmt = cpio->day_first ? "%e %b  %Y" : "%b %e  %Y";
	else
		fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
#endif
	tm = localtime(&mtime);
	if (tm != NULL) {
		strftime(date, sizeof(date), fmt, tm);
	} else {
		*date = '\0';
	}

	fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
	    archive_entry_strmode(entry),
	    archive_entry_nlink(entry),
	    uname, gname, size, date,
	    archive_entry_pathname(entry));

	/* Extra information for links. */
	if (archive_entry_hardlink(entry)) /* Hard link */
		fprintf(out, " link to %s", archive_entry_hardlink(entry));
	else if (archive_entry_symlink(entry)) /* Symbolic link */
		fprintf(out, " -> %s", archive_entry_symlink(entry));
	fprintf(out, "\n");
}
Example #22
0
static void
test_compress_best(void)
{
  const char reffile[] = "test_read_format_rar_compress_best.rar";
  char file1_buff[20111];
  int file1_size = sizeof(file1_buff);
  const char file1_test_txt[] = "<P STYLE=\"margin-bottom: 0in\"><BR>\n"
                                "</P>\n"
                                "</BODY>\n"
                                "</HTML>";
  char file2_buff[20];
  int file2_size = sizeof(file2_buff);
  const char file2_test_txt[] = "test text document\r\n";
  struct archive_entry *ae;
  struct archive *a;

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

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

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

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

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

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

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

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(6, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #23
0
static void
test_basic(void)
{
  char buff[64];
  const char reffile[] = "test_read_format_rar.rar";
  const char test_txt[] = "test text document\r\n";
  int size = sizeof(test_txt)-1;
  struct archive_entry *ae;
  struct archive *a;

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

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

  /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testlink", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(41471, archive_entry_mode(ae));
  assertEqualString("test.txt", archive_entry_symlink(ae));
  assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff)));

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

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

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

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #24
0
static void
test_unicode_CP932(void)
{
  char buff[30];
  const char reffile[] = "test_read_format_rar_unicode.rar";
  const char test_txt[] = "kanji";
  struct archive_entry *ae;
  struct archive *a;

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

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

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

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

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

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

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

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #25
0
static void
test_unicode_UTF8(void)
{
  char buff[30];
  const char reffile[] = "test_read_format_rar_unicode.rar";
  const char test_txt[] = "kanji";
  struct archive_entry *ae;
  struct archive *a;

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

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

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

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

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

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

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

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #26
0
/*-
 * The logic here for -C <dir> attempts to avoid
 * chdir() as long as possible.  For example:
 * "-C /foo -C /bar file"          needs chdir("/bar") but not chdir("/foo")
 * "-C /foo -C bar file"           needs chdir("/foo/bar")
 * "-C /foo -C bar /file1"         does not need chdir()
 * "-C /foo -C bar /file1 file2"   needs chdir("/foo/bar") before file2
 *
 * The only correct way to handle this is to record a "pending" chdir
 * request and combine multiple requests intelligently until we
 * need to process a non-absolute file.  set_chdir() adds the new dir
 * to the pending list; do_chdir() actually executes any pending chdir.
 *
 * This way, programs that build tar command lines don't have to worry
 * about -C with non-existent directories; such requests will only
 * fail if the directory must be accessed.
 *
 */
void
set_chdir(struct bsdtar *bsdtar, const char *newdir)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
	if (newdir[0] == '/' || newdir[0] == '\\' ||
	    /* Detect this type, for example, "C:\" or "C:/" */
	    (((newdir[0] >= 'a' && newdir[0] <= 'z') ||
	      (newdir[0] >= 'A' && newdir[0] <= 'Z')) &&
	    newdir[1] == ':' && (newdir[2] == '/' || newdir[2] == '\\'))) {
#else
	if (newdir[0] == '/') {
#endif
		/* The -C /foo -C /bar case; dump first one. */
		free(bsdtar->pending_chdir);
		bsdtar->pending_chdir = NULL;
	}
	if (bsdtar->pending_chdir == NULL)
		/* Easy case: no previously-saved dir. */
		bsdtar->pending_chdir = strdup(newdir);
	else {
		/* The -C /foo -C bar case; concatenate */
		char *old_pending = bsdtar->pending_chdir;
		size_t old_len = strlen(old_pending);
		bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
		if (old_pending[old_len - 1] == '/')
			old_pending[old_len - 1] = '\0';
		if (bsdtar->pending_chdir != NULL)
			sprintf(bsdtar->pending_chdir, "%s/%s",
			    old_pending, newdir);
		free(old_pending);
	}
	if (bsdtar->pending_chdir == NULL)
		lafe_errc(1, errno, "No memory");
}

void
do_chdir(struct bsdtar *bsdtar)
{
	if (bsdtar->pending_chdir == NULL)
		return;

	if (chdir(bsdtar->pending_chdir) != 0) {
		lafe_errc(1, 0, "could not chdir to '%s'\n",
		    bsdtar->pending_chdir);
	}
	free(bsdtar->pending_chdir);
	bsdtar->pending_chdir = NULL;
}

static const char *
strip_components(const char *p, int elements)
{
	/* Skip as many elements as necessary. */
	while (elements > 0) {
		switch (*p++) {
		case '/':
#if defined(_WIN32) && !defined(__CYGWIN__)
		case '\\': /* Support \ path sep on Windows ONLY. */
#endif
			elements--;
			break;
		case '\0':
			/* Path is too short, skip it. */
			return (NULL);
		}
	}

	/* Skip any / characters.  This handles short paths that have
	 * additional / termination.  This also handles the case where
	 * the logic above stops in the middle of a duplicate //
	 * sequence (which would otherwise get converted to an
	 * absolute path). */
	for (;;) {
		switch (*p) {
		case '/':
#if defined(_WIN32) && !defined(__CYGWIN__)
		case '\\': /* Support \ path sep on Windows ONLY. */
#endif
			++p;
			break;
		case '\0':
			return (NULL);
		default:
			return (p);
		}
	}
}

static void
warn_strip_leading_char(struct bsdtar *bsdtar, const char *c)
{
	if (!bsdtar->warned_lead_slash) {
		lafe_warnc(0,
			   "Removing leading '%c' from member names",
			   c[0]);
		bsdtar->warned_lead_slash = 1;
	}
}

static void
warn_strip_drive_letter(struct bsdtar *bsdtar)
{
	if (!bsdtar->warned_lead_slash) {
		lafe_warnc(0,
			   "Removing leading drive letter from "
			   "member names");
		bsdtar->warned_lead_slash = 1;
	}
}

/*
 * Convert absolute path to non-absolute path by skipping leading
 * absolute path prefixes.
 */
static const char*
strip_absolute_path(struct bsdtar *bsdtar, const char *p)
{
	const char *rp;

	/* Remove leading "//./" or "//?/" or "//?/UNC/"
	 * (absolute path prefixes used by Windows API) */
	if ((p[0] == '/' || p[0] == '\\') &&
	    (p[1] == '/' || p[1] == '\\') &&
	    (p[2] == '.' || p[2] == '?') &&
	    (p[3] == '/' || p[3] == '\\'))
	{
		if (p[2] == '?' &&
		    (p[4] == 'U' || p[4] == 'u') &&
		    (p[5] == 'N' || p[5] == 'n') &&
		    (p[6] == 'C' || p[6] == 'c') &&
		    (p[7] == '/' || p[7] == '\\'))
			p += 8;
		else
			p += 4;
		warn_strip_drive_letter(bsdtar);
	}

	/* Remove multiple leading slashes and Windows drive letters. */
	do {
		rp = p;
		if (((p[0] >= 'a' && p[0] <= 'z') ||
		     (p[0] >= 'A' && p[0] <= 'Z')) &&
		    p[1] == ':') {
			p += 2;
			warn_strip_drive_letter(bsdtar);
		}

		/* Remove leading "/../", "/./", "//", etc. */
		while (p[0] == '/' || p[0] == '\\') {
			if (p[1] == '.' &&
			    p[2] == '.' &&
			    (p[3] == '/' || p[3] == '\\')) {
				p += 3; /* Remove "/..", leave "/" for next pass. */
			} else if (p[1] == '.' &&
				   (p[2] == '/' || p[2] == '\\')) {
				p += 2; /* Remove "/.", leave "/" for next pass. */
			} else
				p += 1; /* Remove "/". */
			warn_strip_leading_char(bsdtar, rp);
		}
	} while (rp != p);

	return (p);
}

/*
 * Handle --strip-components and any future path-rewriting options.
 * Returns non-zero if the pathname should not be extracted.
 *
 * Note: The rewrites are applied uniformly to pathnames and hardlink
 * names but not to symlink bodies.  This is deliberate: Symlink
 * bodies are not necessarily filenames.  Even when they are, they
 * need to be interpreted relative to the directory containing them,
 * so simple rewrites like this are rarely appropriate.
 *
 * TODO: Support pax-style regex path rewrites.
 */
int
edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
{
	const char *name = archive_entry_pathname(entry);
	const char *original_name = name;
	const char *hardlinkname = archive_entry_hardlink(entry);
	const char *original_hardlinkname = hardlinkname;
#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
	char *subst_name;
	int r;

	/* Apply user-specified substitution to pathname. */
	r = apply_substitution(bsdtar, name, &subst_name, 0, 0);
	if (r == -1) {
		lafe_warnc(0, "Invalid substitution, skipping entry");
		return 1;
	}
	if (r == 1) {
		archive_entry_copy_pathname(entry, subst_name);
		if (*subst_name == '\0') {
			free(subst_name);
			return -1;
		} else
			free(subst_name);
		name = archive_entry_pathname(entry);
		original_name = name;
	}

	/* Apply user-specified substitution to hardlink target. */
	if (hardlinkname != NULL) {
		r = apply_substitution(bsdtar, hardlinkname, &subst_name, 0, 1);
		if (r == -1) {
			lafe_warnc(0, "Invalid substitution, skipping entry");
			return 1;
		}
		if (r == 1) {
			archive_entry_copy_hardlink(entry, subst_name);
			free(subst_name);
		}
		hardlinkname = archive_entry_hardlink(entry);
		original_hardlinkname = hardlinkname;
	}

	/* Apply user-specified substitution to symlink body. */
	if (archive_entry_symlink(entry) != NULL) {
		r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1, 0);
		if (r == -1) {
			lafe_warnc(0, "Invalid substitution, skipping entry");
			return 1;
		}
		if (r == 1) {
			archive_entry_copy_symlink(entry, subst_name);
			free(subst_name);
		}
	}
#endif

	/* Strip leading dir names as per --strip-components option. */
	if (bsdtar->strip_components > 0) {
		name = strip_components(name, bsdtar->strip_components);
		if (name == NULL)
			return (1);

		if (hardlinkname != NULL) {
			hardlinkname = strip_components(hardlinkname,
			    bsdtar->strip_components);
			if (hardlinkname == NULL)
				return (1);
		}
	}

	if (!bsdtar->option_absolute_paths) {
		/* By default, don't write or restore absolute pathnames. */
		name = strip_absolute_path(bsdtar, name);
		if (*name == '\0')
			name = ".";

		if (hardlinkname != NULL) {
			hardlinkname = strip_absolute_path(bsdtar, hardlinkname);
			if (*hardlinkname == '\0')
				return (1);
		}
	} else {
		/* Strip redundant leading '/' characters. */
		while (name[0] == '/' && name[1] == '/')
			name++;
	}

	/* Replace name in archive_entry. */
	if (name != original_name) {
		archive_entry_copy_pathname(entry, name);
	}
	if (hardlinkname != original_hardlinkname) {
		archive_entry_copy_hardlink(entry, hardlinkname);
	}
	return (0);
}

/*
 * It would be nice to just use printf() for formatting large numbers,
 * but the compatibility problems are quite a headache.  Hence the
 * following simple utility function.
 */
const char *
tar_i64toa(int64_t n0)
{
	static char buff[24];
	uint64_t n = n0 < 0 ? -n0 : n0;
	char *p = buff + sizeof(buff);

	*--p = '\0';
	do {
		*--p = '0' + (int)(n % 10);
	} while (n /= 10);
	if (n0 < 0)
		*--p = '-';
	return p;
}

/*
 * Like strcmp(), but try to be a little more aware of the fact that
 * we're comparing two paths.  Right now, it just handles leading
 * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
 *
 * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
 * TODO: After this works, push it down into libarchive.
 * TODO: Publish the path normalization routines in libarchive so
 * that bsdtar can normalize paths and use fast strcmp() instead
 * of this.
 *
 * Note: This is currently only used within write.c, so should
 * not handle \ path separators.
 */

int
pathcmp(const char *a, const char *b)
{
	/* Skip leading './' */
	if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
		a += 2;
	if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
		b += 2;
	/* Find the first difference, or return (0) if none. */
	while (*a == *b) {
		if (*a == '\0')
			return (0);
		a++;
		b++;
	}
	/*
	 * If one ends in '/' and the other one doesn't,
	 * they're the same.
	 */
	if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
		return (0);
	if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
		return (0);
	/* They're really different, return the correct sign. */
	return (*(const unsigned char *)a - *(const unsigned char *)b);
}

#define PPBUFF_SIZE 1024
const char *
passphrase_callback(struct archive *a, void *_client_data)
{
	struct bsdtar *bsdtar = (struct bsdtar *)_client_data;
	(void)a; /* UNUSED */

	if (bsdtar->ppbuff == NULL) {
		bsdtar->ppbuff = malloc(PPBUFF_SIZE);
		if (bsdtar->ppbuff == NULL)
			lafe_errc(1, errno, "Out of memory");
	}
	return lafe_readpassphrase("Enter passphrase:",
		bsdtar->ppbuff, PPBUFF_SIZE);
}

void
passphrase_free(char *ppbuff)
{
	if (ppbuff != NULL) {
		memset(ppbuff, 0, PPBUFF_SIZE);
		free(ppbuff);
	}
}

/*
 * Display information about the current file.
 *
 * The format here roughly duplicates the output of 'ls -l'.
 * This is based on SUSv2, where 'tar tv' is documented as
 * listing additional information in an "unspecified format,"
 * and 'pax -l' is documented as using the same format as 'ls -l'.
 */
void
list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
{
	char			 tmp[100];
	size_t			 w;
	const char		*p;
	const char		*fmt;
	time_t			 tim;
	static time_t		 now;

	/*
	 * We avoid collecting the entire list in memory at once by
	 * listing things as we see them.  However, that also means we can't
	 * just pre-compute the field widths.  Instead, we start with guesses
	 * and just widen them as necessary.  These numbers are completely
	 * arbitrary.
	 */
	if (!bsdtar->u_width) {
		bsdtar->u_width = 6;
		bsdtar->gs_width = 13;
	}
	if (!now)
		time(&now);
	fprintf(out, "%s %d ",
	    archive_entry_strmode(entry),
	    archive_entry_nlink(entry));

	/* Use uname if it's present, else uid. */
	p = archive_entry_uname(entry);
	if ((p == NULL) || (*p == '\0')) {
		sprintf(tmp, "%lu ",
		    (unsigned long)archive_entry_uid(entry));
		p = tmp;
	}
	w = strlen(p);
	if (w > bsdtar->u_width)
		bsdtar->u_width = w;
	fprintf(out, "%-*s ", (int)bsdtar->u_width, p);

	/* Use gname if it's present, else gid. */
	p = archive_entry_gname(entry);
	if (p != NULL && p[0] != '\0') {
		fprintf(out, "%s", p);
		w = strlen(p);
	} else {
		sprintf(tmp, "%lu",
		    (unsigned long)archive_entry_gid(entry));
		w = strlen(tmp);
		fprintf(out, "%s", tmp);
	}

	/*
	 * Print device number or file size, right-aligned so as to make
	 * total width of group and devnum/filesize fields be gs_width.
	 * If gs_width is too small, grow it.
	 */
	if (archive_entry_filetype(entry) == AE_IFCHR
	    || archive_entry_filetype(entry) == AE_IFBLK) {
		sprintf(tmp, "%lu,%lu",
		    (unsigned long)archive_entry_rdevmajor(entry),
		    (unsigned long)archive_entry_rdevminor(entry));
	} else {
		strcpy(tmp, tar_i64toa(archive_entry_size(entry)));
	}
	if (w + strlen(tmp) >= bsdtar->gs_width)
		bsdtar->gs_width = w+strlen(tmp)+1;
	fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);

	/* Format the time using 'ls -l' conventions. */
	tim = archive_entry_mtime(entry);
#define	HALF_YEAR (time_t)365 * 86400 / 2
#if defined(_WIN32) && !defined(__CYGWIN__)
#define	DAY_FMT  "%d"  /* Windows' strftime function does not support %e format. */
#else
#define	DAY_FMT  "%e"  /* Day number without leading zeros */
#endif
	if (tim < now - HALF_YEAR || tim > now + HALF_YEAR)
		fmt = bsdtar->day_first ? DAY_FMT " %b  %Y" : "%b " DAY_FMT "  %Y";
	else
		fmt = bsdtar->day_first ? DAY_FMT " %b %H:%M" : "%b " DAY_FMT " %H:%M";
	strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
	fprintf(out, " %s ", tmp);
	safe_fprintf(out, "%s", archive_entry_pathname(entry));

	/* Extra information for links. */
	if (archive_entry_hardlink(entry)) /* Hard link */
		safe_fprintf(out, " link to %s",
		    archive_entry_hardlink(entry));
	else if (archive_entry_symlink(entry)) /* Symbolic link */
		safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
}
Example #27
0
/*
 * test_compat_gtar_1.tgz exercises reading long filenames and
 * symlink targets stored in the GNU tar format.
 */
static void
test_compat_gtar_1(void)
{
	char name[] = "test_compat_gtar_1.tar";
	struct archive_entry *ae;
	struct archive *a;
	int r;

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

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

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

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

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

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

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

#if defined(_WIN32) && !defined(__CYGWIN__)
	/* Make sure the path separators in pahtname, hardlink and symlink
	 * are all slash '/', not the Windows path separator '\'. */
	entry_main = __la_win_entry_in_posix_pathseparator(entry);
	if (entry_main == NULL) {
		archive_set_error(&a->archive, ENOMEM,
		    "Can't allocate ustar data");
		return(ARCHIVE_FATAL);
	}
	if (entry != entry_main)
		entry = entry_main;
	else
		entry_main = NULL;
#else
	entry_main = NULL;
#endif

	ret = archive_entry_pathname_l(entry, &path, &len, sconv);
	if (ret != 0) {
		if (errno == ENOMEM) {
			archive_set_error(&a->archive, ENOMEM,
			    "Can't allocate memory for Pathname");
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
		    "Can't translate pathname '%s' to %s",
		    archive_entry_pathname(entry),
		    archive_string_conversion_charset_name(sconv));
		ret_final = ARCHIVE_WARN;
	}
	pathlength = (int)len + 1; /* Include trailing null. */

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

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

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

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

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

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

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

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

	/* Write the symlink now. */
	if (p != NULL  &&  *p != '\0') {
		ret = __archive_write_output(a, p, strlen(p));
		if (ret != ARCHIVE_OK) {
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
		pad = PAD4(strlen(p));
		ret = __archive_write_output(a, "\0\0\0", pad);
		if (ret != ARCHIVE_OK) {
			ret_final = ARCHIVE_FATAL;
			goto exit_write_header;
		}
	}
exit_write_header:
	if (entry_main)
		archive_entry_free(entry_main);
	return (ret_final);
}
Example #29
0
static void
verify_contents(struct archive *a, int expect_details)
{
	char filedata[64];
	struct archive_entry *ae;

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


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

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

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

	/* Verify the end of the archive. */
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
Example #30
0
/*
 * Display information about the current file.
 *
 * The format here roughly duplicates the output of 'ls -l'.
 * This is based on SUSv2, where 'tar tv' is documented as
 * listing additional information in an "unspecified format,"
 * and 'pax -l' is documented as using the same format as 'ls -l'.
 */
static void
list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
{
	const struct stat	*st;
	char			 tmp[100];
	size_t			 w;
	const char		*p;
	const char		*fmt;
	time_t			 tim;
	static time_t		 now;

	st = archive_entry_stat(entry);

	/*
	 * We avoid collecting the entire list in memory at once by
	 * listing things as we see them.  However, that also means we can't
	 * just pre-compute the field widths.  Instead, we start with guesses
	 * and just widen them as necessary.  These numbers are completely
	 * arbitrary.
	 */
	if (!bsdtar->u_width) {
		bsdtar->u_width = 6;
		bsdtar->gs_width = 13;
	}
	if (!now)
		time(&now);
	fprintf(out, "%s %d ",
	    archive_entry_strmode(entry),
	    (int)(st->st_nlink));

	/* Use uname if it's present, else uid. */
	p = archive_entry_uname(entry);
	if ((p == NULL) || (*p == '\0')) {
		sprintf(tmp, "%lu ", (unsigned long)st->st_uid);
		p = tmp;
	}
	w = strlen(p);
	if (w > bsdtar->u_width)
		bsdtar->u_width = w;
	fprintf(out, "%-*s ", (int)bsdtar->u_width, p);

	/* Use gname if it's present, else gid. */
	p = archive_entry_gname(entry);
	if (p != NULL && p[0] != '\0') {
		fprintf(out, "%s", p);
		w = strlen(p);
	} else {
		sprintf(tmp, "%lu", (unsigned long)st->st_gid);
		w = strlen(tmp);
		fprintf(out, "%s", tmp);
	}

	/*
	 * Print device number or file size, right-aligned so as to make
	 * total width of group and devnum/filesize fields be gs_width.
	 * If gs_width is too small, grow it.
	 */
	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
		sprintf(tmp, "%lu,%lu",
		    (unsigned long)major(st->st_rdev),
		    (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */
	} else {
		/*
		 * Note the use of platform-dependent macros to format
		 * the filesize here.  We need the format string and the
		 * corresponding type for the cast.
		 */
		sprintf(tmp, BSDTAR_FILESIZE_PRINTF,
		    (BSDTAR_FILESIZE_TYPE)st->st_size);
	}
	if (w + strlen(tmp) >= bsdtar->gs_width)
		bsdtar->gs_width = w+strlen(tmp)+1;
	fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);

	/* Format the time using 'ls -l' conventions. */
	tim = (time_t)st->st_mtime;
	if (abs(tim - now) > (365/2)*86400)
		fmt = bsdtar->day_first ? "%e %b  %Y" : "%b %e  %Y";
	else
		fmt = bsdtar->day_first ? "%e %b %R" : "%b %e %R";
	strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
	fprintf(out, " %s ", tmp);
	safe_fprintf(out, "%s", archive_entry_pathname(entry));

	/* Extra information for links. */
	if (archive_entry_hardlink(entry)) /* Hard link */
		safe_fprintf(out, " link to %s",
		    archive_entry_hardlink(entry));
	else if (S_ISLNK(st->st_mode)) /* Symbolic link */
		safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
}