// make_btrfs [c]
int make_btrfs(int fd, u64 blocks[4], u64 num_bytes, u32 nodesize,
	       u32 leafsize, u32 sectorsize, u32 stripesize)
{
	struct btrfs_super_block super;
	struct extent_buffer *buf;
	struct btrfs_root_item root_item;
	struct btrfs_disk_key disk_key;
	struct btrfs_extent_ref *extent_ref;
	struct btrfs_extent_item *extent_item;
	struct btrfs_inode_item *inode_item;
	int i;
	int ret;
	u32 itemoff;
	u32 nritems = 0;
	u64 hash;
	u64 first_free;
	u64 ref_gen;
	u64 ref_root;

	first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1;
	first_free &= ~((u64)sectorsize - 1);

	num_bytes = (num_bytes / sectorsize) * sectorsize;
	uuid_generate(super.fsid);
	btrfs_set_super_bytenr(&super, blocks[0]);
	strncpy((char *)&super.magic, BTRFS_MAGIC, sizeof(super.magic));
	btrfs_set_super_generation(&super, 1);
	btrfs_set_super_root(&super, blocks[1]);
	btrfs_set_super_total_bytes(&super, num_bytes);
	btrfs_set_super_bytes_used(&super, first_free + 3 * leafsize);
	btrfs_set_super_root_dir(&super, 0);
	btrfs_set_super_sectorsize(&super, sectorsize);
	btrfs_set_super_leafsize(&super, leafsize);
	btrfs_set_super_nodesize(&super, nodesize);
	btrfs_set_super_stripesize(&super, stripesize);
	btrfs_set_super_root_level(&super, 0);

	buf = malloc(sizeof(*buf) + max(sectorsize, leafsize));

	BUG_ON(sizeof(super) > sectorsize);
	memset(buf->data, 0, sectorsize);
	memcpy(buf->data, &super, sizeof(super));
	ret = pwrite(fd, buf->data, sectorsize, blocks[0]);
	BUG_ON(ret != sectorsize);

	/* create the tree of root objects */
	memset(buf->data, 0, leafsize);
	btrfs_set_header_bytenr(buf, blocks[1]);
	btrfs_set_header_nritems(buf, 2);
	btrfs_set_header_generation(buf, 1);
	btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID);
	write_extent_buffer(buf, super.fsid, (unsigned long)
			    btrfs_header_fsid(buf), BTRFS_FSID_SIZE);

	/* create the items for the root tree */
	memset(&root_item, 0, sizeof(root_item));
	inode_item = &root_item.inode;
	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_nblocks(inode_item, 1);
	btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
	btrfs_set_root_refs(&root_item, 1);
	btrfs_set_root_used(&root_item, leafsize);

	memset(&disk_key, 0, sizeof(disk_key));
	btrfs_set_disk_key_type(&disk_key, BTRFS_ROOT_ITEM_KEY);
	btrfs_set_disk_key_offset(&disk_key, 0);

	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - 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, 0);
	btrfs_set_item_offset(buf, btrfs_item_nr(buf, 0), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(buf, 0), sizeof(root_item));
	write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, 0),
			    sizeof(root_item));

	itemoff = itemoff - sizeof(root_item);
	btrfs_set_root_bytenr(&root_item, blocks[3]);
	btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID);
	btrfs_set_item_key(buf, &disk_key, 1);
	btrfs_set_item_offset(buf, btrfs_item_nr(buf, 1), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(buf, 1), sizeof(root_item));
	write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, 1),
			    sizeof(root_item));
	ret = pwrite(fd, buf->data, leafsize, blocks[1]);
	BUG_ON(ret != leafsize);

	/* create the items for the extent tree */
	itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
		  sizeof(struct btrfs_extent_item);
	btrfs_set_disk_key_objectid(&disk_key, 0);
	btrfs_set_disk_key_offset(&disk_key, first_free);
	btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY);
	btrfs_set_item_key(buf, &disk_key, nritems);
	btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems), itemoff);
	btrfs_set_item_size(buf, btrfs_item_nr(buf,  nritems),
			    sizeof(struct btrfs_extent_item));
	extent_item = btrfs_item_ptr(buf, nritems, struct btrfs_extent_item);
	btrfs_set_extent_refs(buf, extent_item, 1);
	nritems++;
	for (i = 1; i < 4; i++) {
		BUG_ON(blocks[i] < first_free);
		BUG_ON(blocks[i] < blocks[i - 1]);

		/* create extent item */
		itemoff = itemoff - sizeof(struct btrfs_extent_item);
		btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
		btrfs_set_disk_key_offset(&disk_key, leafsize);
		btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY);
		btrfs_set_item_key(buf, &disk_key, nritems);
		btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
				      itemoff);
		btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
				    sizeof(struct btrfs_extent_item));
		extent_item = btrfs_item_ptr(buf, nritems,
					     struct btrfs_extent_item);
		btrfs_set_extent_refs(buf, extent_item, 1);
		nritems++;

		/* create extent ref */
		ref_root = reference_root_table[i];
		if (ref_root == BTRFS_FS_TREE_OBJECTID)
			ref_gen = 1;
		else
			ref_gen = 0;

		hash = btrfs_hash_extent_ref(ref_root, ref_gen, 0, 0);
		itemoff = itemoff - sizeof(struct btrfs_extent_ref);
		btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
		btrfs_set_disk_key_offset(&disk_key, hash);
		btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_REF_KEY);
		btrfs_set_item_key(buf, &disk_key, nritems);
		btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
				      itemoff);
		btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
				    sizeof(struct btrfs_extent_ref));
		extent_ref = btrfs_item_ptr(buf, nritems,
					     struct btrfs_extent_ref);
		btrfs_set_ref_root(buf, extent_ref, ref_root);
		btrfs_set_ref_generation(buf, extent_ref, ref_gen);
		btrfs_set_ref_objectid(buf, extent_ref, 0);
		btrfs_set_ref_offset(buf, extent_ref, 0);
		nritems++;
	}
	btrfs_set_header_bytenr(buf, blocks[2]);
	btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, nritems);
	ret = pwrite(fd, buf->data, leafsize, blocks[2]);
	BUG_ON(ret != leafsize);

	/* finally create the FS root */
	btrfs_set_header_bytenr(buf, blocks[3]);
	btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
	btrfs_set_header_nritems(buf, 0);
	ret = pwrite(fd, buf->data, leafsize, blocks[3]);
	BUG_ON(ret != leafsize);

	free(buf);
	return 0;
}