Beispiel #1
0
static int
is_sparse_supported(const char *path)
{
	const struct sparse sparse_file[] = {
 		/* This hole size is too small to create a sparse
		 * files for almost filesystem. */
		{ HOLE,	 1024 }, { DATA, 10240 },
		{ END,	0 }
	};
	int fd, r;
	const char *testfile = "can_sparse";

	(void)path; /* UNUSED */
	create_sparse_file(testfile, sparse_file);
	fd = open(testfile,  O_RDWR);
	if (fd < 0)
		return (0);
	r = lseek(fd, 0, SEEK_HOLE);
	close(fd);
	unlink(testfile);
#if defined(HAVE_LINUX_FIEMAP_H)
	if (r < 0)
		return (is_sparse_supported_fiemap(path));
#endif
	return (r >= 0);
}
Beispiel #2
0
static int
is_sparse_supported_fiemap(const char *path)
{
	const struct sparse sparse_file[] = {
 		/* This hole size is too small to create a sparse
		 * files for almost filesystem. */
		{ HOLE,	 1024 }, { DATA, 10240 },
		{ END,	0 }
	};
	int fd, r;
	struct fiemap *fm;
	char buff[1024];
	const char *testfile = "can_sparse";

	(void)path; /* UNUSED */
	memset(buff, 0, sizeof(buff));
	create_sparse_file(testfile, sparse_file);
	fd = open(testfile,  O_RDWR);
	if (fd < 0)
		return (0);
	fm = (struct fiemap *)buff;
	fm->fm_start = 0;
	fm->fm_length = ~0ULL;;
	fm->fm_flags = FIEMAP_FLAG_SYNC;
	fm->fm_extent_count = (sizeof(buff) - sizeof(*fm))/
		sizeof(struct fiemap_extent);
	r = ioctl(fd, FS_IOC_FIEMAP, fm);
	close(fd);
	unlink(testfile);
	return (r >= 0);
}
Beispiel #3
0
static int
is_sparse_supported(const char *path)
{
	const struct sparse sparse_file[] = {
 		/* This hole size is too small to create a sparse
		 * files for almost filesystem. */
		{ HOLE,	 1024 }, { DATA, 10240 },
		{ END,	0 }
	};
	struct utsname ut;
	char *p, *e;
	long d;
	int fd, r;
	struct fiemap *fm;
	char buff[1024];
	const char *testfile = "can_sparse";

	memset(&ut, 0, sizeof(ut));
	assertEqualInt(uname(&ut), 0);
	p = ut.release;
	d = strtol(p, &e, 10);
	if (d < 2 || *e != '.')
		return (0);
	p = e + 1;
	d = strtol(p, &e, 10);
	if (d < 6 || *e != '.')
		return (0);
	p = e + 1;
	d = strtol(p, NULL, 10);
	if (d < 28)
		return (0);
	create_sparse_file(testfile, sparse_file);
	fd = open(testfile,  O_RDWR);
	if (fd < 0)
		return (0);
	fm = (struct fiemap *)buff;
	fm->fm_start = 0;
	fm->fm_length = ~0ULL;;
	fm->fm_flags = FIEMAP_FLAG_SYNC;
	fm->fm_extent_count = (sizeof(buff) - sizeof(*fm))/
		sizeof(struct fiemap_extent);
	r = ioctl(fd, FS_IOC_FIEMAP, fm);
	if (r < 0 && (errno == ENOTTY || errno == EOPNOTSUPP))
		return (0);/* Not supported. */
	close(fd);
	unlink(testfile);
	return (1);
}
Beispiel #4
0
int
main(int argc, const char *argv[])
{
	if (argc < 2) {
		fprintf(stderr, "Usage: %s filename len\n", argv[0]);
		exit(1);
	}

	int i = 1;
	while (i < argc && argv[i][0] == '-') {
		switch (argv[i][1]) {
			case 'v':
				Opt_verbose = 1;
				break;
			case 's':
				Opt_sparse = 1;
				break;
			case 'f':
				Opt_force = 1;
				break;
			default:
				out_err("Unknown option: \'%c\'.", argv[i][1]);
				exit(2);
		}
		++i;
	}

	const char *filename = argv[i];
	long long len = atoll(argv[i + 1]);

	if (len < 0) {
		out_err("Invalid file length: %lld.\n", len);
		exit(3);
	}

	if (create_sparse_file(filename, len) < 0) {
		out_err("File creation failed.");
		exit(4);
	}

	if (Opt_verbose)
		print_file_size(filename);

	return 0;
}
/*
 * Sparse test with directory traversals.
 */
static void
verify_sparse_file(struct archive *a, const char *path,
    const struct sparse *sparse, int blocks, int expected_data_blocks)
{
	struct archive_entry *ae;
	const void *buff;
	size_t bytes_read;
	int64_t offset;
	int64_t total;
	int data_blocks, hole;

	create_sparse_file(path, sparse);
	assert((ae = archive_entry_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, path));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
	/* Verify the number of holes only, not its offset nor its
	 * length because those alignments are deeply dependence on
	 * its filesystem. */ 
	assertEqualInt(blocks, archive_entry_sparse_count(ae));
	total = 0;
	data_blocks = 0;
	hole = 0;
	while (ARCHIVE_OK == archive_read_data_block(a, &buff, &bytes_read,
	    &offset)) {
		if (offset > total || offset == 0) {
			if (offset > total)
				hole = 1;
			data_blocks++;
		}
		total = offset + bytes_read;
	}
	assertEqualInt(expected_data_blocks, data_blocks);

	if (blocks > 1)
		assert(hole); /* There must be a hole if > 1 blocks were encoded */

	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	archive_entry_free(ae);
}
Beispiel #6
0
/*
 * Sparse test with directory traversals.
 */
static void
verify_sparse_file(struct archive *a, const char *path,
    const struct sparse *sparse, int expected_holes)
{
	struct archive_entry *ae;
	const void *buff;
	size_t bytes_read;
	int64_t offset, expected_offset, last_offset;
	int holes_seen = 0;

	create_sparse_file(path, sparse);
	assert((ae = archive_entry_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, path));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));

	expected_offset = 0;
	last_offset = 0;
	while (ARCHIVE_OK == archive_read_data_block(a, &buff, &bytes_read,
	    &offset)) {
		const char *start = buff;
#if DEBUG
		fprintf(stderr, "%s: bytes_read=%d offset=%d\n", path, (int)bytes_read, (int)offset);
#endif
		if (offset > last_offset) {
			++holes_seen;
		}
		/* Blocks entirely before the data we just read. */
		while (expected_offset + (int64_t)sparse->size < offset) {
#if DEBUG
			fprintf(stderr, "    skipping expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
			/* Must be holes. */
			assert(sparse->type == HOLE);
			expected_offset += sparse->size;
			++sparse;
		}
		/* Block that overlaps beginning of data */
		if (expected_offset < offset
		    && expected_offset + (int64_t)sparse->size <= offset + (int64_t)bytes_read) {
			const char *end = (const char *)buff + (expected_offset - offset) + (size_t)sparse->size;
#if DEBUG
			fprintf(stderr, "    overlapping hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
			/* Must be a hole, overlap must be filled with '\0' */
			if (assert(sparse->type == HOLE)) {
				assertMemoryFilledWith(start, end - start, '\0');
			}
			start = end;
			expected_offset += sparse->size;
			++sparse;
		}
		/* Blocks completely contained in data we just read. */
		while (expected_offset + (int64_t)sparse->size <= offset + (int64_t)bytes_read) {
			const char *end = (const char *)buff + (expected_offset - offset) + (size_t)sparse->size;
			if (sparse->type == HOLE) {
#if DEBUG
				fprintf(stderr, "    contained hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif

				/* verify data corresponding to hole is '\0' */
				if (end > (const char *)buff + bytes_read) {
					end = (const char *)buff + bytes_read;
				}
				assertMemoryFilledWith(start, end - start, '\0');
				start = end;
				expected_offset += sparse->size;
				++sparse;
			} else if (sparse->type == DATA) {
#if DEBUG
				fprintf(stderr, "    contained data expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
				/* verify data corresponding to hole is ' ' */
				if (assert(expected_offset + sparse->size <= offset + bytes_read)) {
					assert(start == (const char *)buff + (size_t)(expected_offset - offset));
					assertMemoryFilledWith(start, end - start, ' ');
				}
				start = end;
				expected_offset += sparse->size;
				++sparse;
			} else {
				break;
			}
		}
		/* Block that overlaps end of data */
		if (expected_offset < offset + (int64_t)bytes_read) {
			const char *end = (const char *)buff + bytes_read;
#if DEBUG
			fprintf(stderr, "    trailing overlap expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
			/* Must be a hole, overlap must be filled with '\0' */
			if (assert(sparse->type == HOLE)) {
				assertMemoryFilledWith(start, end - start, '\0');
			}
		}
		last_offset = offset + bytes_read;
	}
	/* Count a hole at EOF? */
	if (last_offset < archive_entry_size(ae)) {
		++holes_seen;
	}

	/* Verify blocks after last read */
	while (sparse->type == HOLE) {
		expected_offset += sparse->size;
		++sparse;
	}
	assert(sparse->type == END);
	assertEqualInt(expected_offset, archive_entry_size(ae));

	assertEqualInt(holes_seen, expected_holes);

	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	archive_entry_free(ae);
}