* Boston, MA 021110-1307, USA.
*/
-#define _XOPEN_SOURCE 700
-#define __USE_XOPEN2K8
-#define __XOPEN2K8 /* due to an error in dirent.h, to get dirfd() */
-#define _GNU_SOURCE /* O_NOATIME */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
u64 blocks[7], u64 num_bytes, u32 nodesize,
- u32 leafsize, u32 sectorsize, u32 stripesize, u64 features)
+ u32 sectorsize, u32 stripesize, u64 features)
{
struct btrfs_super_block super;
struct extent_buffer *buf = NULL;
btrfs_set_super_root(&super, blocks[1]);
btrfs_set_super_chunk_root(&super, blocks[3]);
btrfs_set_super_total_bytes(&super, num_bytes);
- btrfs_set_super_bytes_used(&super, 6 * leafsize);
+ btrfs_set_super_bytes_used(&super, 6 * nodesize);
btrfs_set_super_sectorsize(&super, sectorsize);
- btrfs_set_super_leafsize(&super, leafsize);
+ btrfs_set_super_leafsize(&super, nodesize);
btrfs_set_super_nodesize(&super, nodesize);
btrfs_set_super_stripesize(&super, stripesize);
btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32);
if (label)
strncpy(super.label, label, BTRFS_LABEL_SIZE - 1);
- buf = malloc(sizeof(*buf) + max(sectorsize, leafsize));
+ buf = malloc(sizeof(*buf) + max(sectorsize, nodesize));
/* create the tree of root objects */
- memset(buf->data, 0, leafsize);
- buf->len = leafsize;
+ memset(buf->data, 0, nodesize);
+ buf->len = nodesize;
btrfs_set_header_bytenr(buf, blocks[1]);
btrfs_set_header_nritems(buf, 4);
btrfs_set_header_generation(buf, 1);
btrfs_set_stack_inode_generation(inode_item, 1);
btrfs_set_stack_inode_size(inode_item, 3);
btrfs_set_stack_inode_nlink(inode_item, 1);
- btrfs_set_stack_inode_nbytes(inode_item, leafsize);
+ btrfs_set_stack_inode_nbytes(inode_item, nodesize);
btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
btrfs_set_root_refs(&root_item, 1);
- btrfs_set_root_used(&root_item, leafsize);
+ btrfs_set_root_used(&root_item, nodesize);
btrfs_set_root_generation(&root_item, 1);
memset(&disk_key, 0, sizeof(disk_key));
btrfs_set_disk_key_offset(&disk_key, 0);
nritems = 0;
- itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
+ itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) - sizeof(root_item);
btrfs_set_root_bytenr(&root_item, blocks[2]);
btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID);
btrfs_set_item_key(buf, &disk_key, nritems);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[1]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[1]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
/* create the items for the extent tree */
- memset(buf->data+sizeof(struct btrfs_header), 0,
- leafsize-sizeof(struct btrfs_header));
+ memset(buf->data + sizeof(struct btrfs_header), 0,
+ nodesize - sizeof(struct btrfs_header));
nritems = 0;
- itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize);
+ itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize);
for (i = 1; i < 7; i++) {
item_size = sizeof(struct btrfs_extent_item);
if (!skinny_metadata)
} else {
btrfs_set_disk_key_type(&disk_key,
BTRFS_EXTENT_ITEM_KEY);
- btrfs_set_disk_key_offset(&disk_key, leafsize);
+ btrfs_set_disk_key_offset(&disk_key, nodesize);
}
btrfs_set_item_key(buf, &disk_key, nritems);
btrfs_set_item_offset(buf, btrfs_item_nr(nritems),
btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
btrfs_set_header_nritems(buf, nritems);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[2]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[2]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
/* create the chunk tree */
- memset(buf->data+sizeof(struct btrfs_header), 0,
- leafsize-sizeof(struct btrfs_header));
+ memset(buf->data + sizeof(struct btrfs_header), 0,
+ nodesize - sizeof(struct btrfs_header));
nritems = 0;
item_size = sizeof(*dev_item);
- itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - item_size;
+ itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) - item_size;
/* first device 1 (there is no device 0) */
btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID);
btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID);
btrfs_set_header_nritems(buf, nritems);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[3]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[3]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
/* create the device tree */
- memset(buf->data+sizeof(struct btrfs_header), 0,
- leafsize-sizeof(struct btrfs_header));
+ memset(buf->data + sizeof(struct btrfs_header), 0,
+ nodesize - sizeof(struct btrfs_header));
nritems = 0;
- itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
+ itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) -
sizeof(struct btrfs_dev_extent);
btrfs_set_disk_key_objectid(&disk_key, 1);
btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID);
btrfs_set_header_nritems(buf, nritems);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[4]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[4]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
/* create the FS root */
- memset(buf->data+sizeof(struct btrfs_header), 0,
- leafsize-sizeof(struct btrfs_header));
+ memset(buf->data + sizeof(struct btrfs_header), 0,
+ nodesize - sizeof(struct btrfs_header));
btrfs_set_header_bytenr(buf, blocks[5]);
btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
btrfs_set_header_nritems(buf, 0);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[5]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[5]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
/* finally create the csum root */
- memset(buf->data+sizeof(struct btrfs_header), 0,
- leafsize-sizeof(struct btrfs_header));
+ memset(buf->data + sizeof(struct btrfs_header), 0,
+ nodesize - sizeof(struct btrfs_header));
btrfs_set_header_bytenr(buf, blocks[6]);
btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID);
btrfs_set_header_nritems(buf, 0);
csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
- ret = pwrite(fd, buf->data, leafsize, blocks[6]);
- if (ret != leafsize) {
+ ret = pwrite(fd, buf->data, nodesize, blocks[6]);
+ if (ret != nodesize) {
ret = (ret < 0 ? -errno : -EIO);
goto out;
}
* optimization.
*/
if (discard_range(fd, 0, 0) == 0) {
- fprintf(stderr, "Performing full device TRIM (%s) ...\n",
+ printf("Performing full device TRIM (%s) ...\n",
pretty_size(block_count));
discard_blocks(fd, 0, block_count);
}
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
btrfs_set_stack_inode_size(&inode_item, 0);
btrfs_set_stack_inode_nlink(&inode_item, 1);
- btrfs_set_stack_inode_nbytes(&inode_item, root->leafsize);
+ btrfs_set_stack_inode_nbytes(&inode_item, root->nodesize);
btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
btrfs_set_stack_timespec_sec(&inode_item.atime, now);
btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
return ret;
}
+static int is_reg_file(const char *path)
+{
+ struct stat statbuf;
+
+ if (stat(path, &statbuf) < 0)
+ return -errno;
+ return S_ISREG(statbuf.st_mode);
+}
+
/*
* This function checks if the given input parameter is
* an uuid or a path
- * return -1: some error in the given input
- * return 0: unknow input
- * return 1: given input is uuid
- * return 2: given input is path
+ * return <0 : some error in the given input
+ * return BTRFS_ARG_UNKNOWN: unknown input
+ * return BTRFS_ARG_UUID: given input is uuid
+ * return BTRFS_ARG_MNTPOINT: given input is path
+ * return BTRFS_ARG_REG: given input is regular file
*/
int check_arg_type(const char *input)
{
if (is_mount_point(path) == 1)
return BTRFS_ARG_MNTPOINT;
+ if (is_reg_file(path))
+ return BTRFS_ARG_REG;
+
return BTRFS_ARG_UNKNOWN;
}
}
/*
+ * Unsafe subvolume check.
+ *
+ * This only checks ino == BTRFS_FIRST_FREE_OBJECTID, even it is not in a
+ * btrfs mount point.
+ * Must use together with other reliable method like btrfs ioctl.
+ */
+static int __is_subvol(const char *path)
+{
+ struct stat st;
+ int ret;
+
+ ret = lstat(path, &st);
+ if (ret < 0)
+ return ret;
+
+ return st.st_ino == BTRFS_FIRST_FREE_OBJECTID;
+}
+
+/*
* A not-so-good version fls64. No fascinating optimization since
* no one except parse_size use it
*/
return ret;
}
+u64 parse_qgroupid(const char *p)
+{
+ char *s = strchr(p, '/');
+ const char *ptr_src_end = p + strlen(p);
+ char *ptr_parse_end = NULL;
+ u64 level;
+ u64 id;
+ int fd;
+ int ret = 0;
+
+ if (p[0] == '/')
+ goto path;
+
+ /* Numeric format like '0/257' is the primary case */
+ if (!s) {
+ id = strtoull(p, &ptr_parse_end, 10);
+ if (ptr_parse_end != ptr_src_end)
+ goto path;
+ return id;
+ }
+ level = strtoull(p, &ptr_parse_end, 10);
+ if (ptr_parse_end != s)
+ goto path;
+
+ id = strtoull(s + 1, &ptr_parse_end, 10);
+ if (ptr_parse_end != ptr_src_end)
+ goto path;
+
+ return (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
+
+path:
+ /* Path format like subv at 'my_subvol' is the fallback case */
+ ret = __is_subvol(p);
+ if (ret < 0 || !ret)
+ goto err;
+ fd = open(p, O_RDONLY);
+ if (fd < 0)
+ goto err;
+ ret = lookup_ino_rootid(fd, &id);
+ close(fd);
+ if (ret < 0)
+ goto err;
+ return id;
+
+err:
+ fprintf(stderr, "ERROR: invalid qgroupid or subvolume path: %s\n", p);
+ exit(-1);
+}
+
int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags)
{
int ret;
int ret = 0;
int ndevs = 0;
int i = 0;
+ int replacing = 0;
struct btrfs_fs_devices *fs_devices_mnt = NULL;
struct btrfs_ioctl_dev_info_args *di_args;
+ struct btrfs_ioctl_dev_info_args tmp;
char mp[BTRFS_PATH_NAME_MAX + 1];
DIR *dirstream = NULL;
ret = search_chunk_tree_for_fs_info(fd, fi_args);
if (ret)
goto out;
+
+ /*
+ * search_chunk_tree_for_fs_info() will lacks the devid 0
+ * so manual probe for it here.
+ */
+ ret = get_device_info(fd, 0, &tmp);
+ if (!ret) {
+ fi_args->num_devices++;
+ ndevs++;
+ replacing = 1;
+ if (i == 0)
+ i++;
+ }
}
if (!fi_args->num_devices)
goto out;
}
+ if (replacing)
+ memcpy(di_args, &tmp, sizeof(tmp));
for (; i <= fi_args->max_id; ++i) {
ret = get_device_info(fd, i, &di_args[ndevs]);
if (ret == -ENODEV)
if (!dev)
continue;
/* if we are here its definitely a btrfs disk*/
- strncpy(path, blkid_dev_devname(dev), PATH_MAX);
+ strncpy_null(path, blkid_dev_devname(dev));
fd = open(path, O_RDONLY);
if (fd < 0) {
return ret;
}
-int test_minimum_size(const char *file, u32 leafsize)
+int test_minimum_size(const char *file, u32 nodesize)
{
int fd;
struct stat statbuf;
close(fd);
return -errno;
}
- if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(leafsize)) {
+ if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(nodesize)) {
close(fd);
return 1;
}
return v2_supported;
}
+
+int btrfs_check_nodesize(u32 nodesize, u32 sectorsize)
+{
+ if (nodesize < sectorsize) {
+ fprintf(stderr,
+ "ERROR: Illegal nodesize %u (smaller than %u)\n",
+ nodesize, sectorsize);
+ return -1;
+ } else if (nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+ fprintf(stderr,
+ "ERROR: Illegal nodesize %u (larger than %u)\n",
+ nodesize, BTRFS_MAX_METADATA_BLOCKSIZE);
+ return -1;
+ } else if (nodesize & (sectorsize - 1)) {
+ fprintf(stderr,
+ "ERROR: Illegal nodesize %u (not aligned to %u)\n",
+ nodesize, sectorsize);
+ return -1;
+ }
+ return 0;
+}