This is a standalone tool I've used to exercise the ioctl, simply pass
the name of a file and see the result. The numbers are a rough
estimate. It also takes the range arguments, but the ratio will be bogus
due to comparison to whole file (st_blocks), an exact extent length
from fiemap/filefrag is be the correct one.


david

/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

typedef uint64_t __u64;
typedef uint64_t u64;

#ifndef BTRFS_IOCTL_MAGIC
#define BTRFS_IOCTL_MAGIC 0x94
#endif

#ifndef BTRFS_IOC_COMPR_SIZE
#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
		struct __local__btrfs_ioctl_compr_size_args)
#endif

struct __local__btrfs_ioctl_compr_size_args {
	/* Range start, inclusive */
	__u64                           start;          /* in */
	/* Range end, exclusive */
	__u64                           end;            /* in */
	__u64                           size;           /* out */
	__u64                           reserved[2];
};

static u64 parse_size(char *s)
{
	int len = strlen(s);
	char c;
	u64 mult = 1;

	if (!isdigit(s[len - 1])) {
		c = tolower(s[len - 1]);
		switch (c) {
			case 'e':
			case 'E':
				mult *= 1024;
			case 't':
			case 'T':
				mult *= 1024;
			case 'g':
			case 'G':
				mult *= 1024;
			case 'm':
			case 'M':
				mult *= 1024;
			case 'k':
			case 'K':
				mult *= 1024;
			case 'b':
			case 'B':
				break;
			default:
				fprintf(stderr, "Unknown size descriptor %c\n", c);
				exit(1);
		}
		s[len - 1] = '\0';
	}
	return atoll(s) * mult;
}

static int open_file_or_dir(const char *fname)
{
	int ret;
	struct stat st;
	DIR *dirstream;
	int fd;

	ret = stat(fname, &st);
	if (ret < 0) {
		perror("stat");
		exit(1);
	}
	if (S_ISDIR(st.st_mode)) {
		dirstream = opendir(fname);
		if (!dirstream) {
			perror("opendir");
			exit(1);
		}
		fd = dirfd(dirstream);
	} else {
		fd = open(fname, O_RDONLY);
	}
	if (fd < 0) {
		perror("open");
		exit(1);
	}
	return fd;
}
static char buf[64];
static const char* end_or_eof(u64 end)
{
	if (end == (u64)-1)
		return "EOF";
	snprintf(buf, 64, "%llu", (unsigned long long)end);
	return buf;
}

int main(int argc, char **argv)
{
	int fd;
	int ret;
	u64 cblocks;
	unsigned long sblocks;
	struct stat st;
	struct __local__btrfs_ioctl_compr_size_args args;

	if (argc < 2) {
		printf("Usage: btrfs-compr-size <file> [start [end] ]\n");
		exit(1);
	}

	fd = open_file_or_dir(argv[1]);
	if (fd == -1) {
		perror("open");
		exit(1);
	}

	if (argc >= 3)
		args.start = parse_size(argv[2]);
	else
		args.start = 0;

	if (argc >= 4)
		args.end = parse_size(argv[3]);
	else
		args.end = (u64)-1;

	ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, &args);
	if (ret < 0) {
		perror("ioctl");
		exit(1);
	}
	fstat(fd, &st);
	cblocks=args.size;
	sblocks=st.st_blocks;
	printf("Compressed size of %s [%llu,%s)\n", argv[1],
			(unsigned long long)args.start,
			end_or_eof(args.end));
	printf(" compr size/512:  % 11lu\n", cblocks);
	printf(" stat blocks/512: % 11lu\n", sblocks);
	if (sblocks)
		printf(" compr/stat*100:  % 14.2f%%\n", (((float)cblocks) / sblocks) * 100);
	else
		printf(" compr/stat*100:  % 14.2f%%\n", (float)0);
	return 0;
}

Reply via email to