btrfs-convert: split into convert/.
Subsystems (2)
PATCH 4/4 btrfs-convert: split into convert/.
No material changes are made.
--- Makefile | 10 +- convert.c => convert/convert.c | 803 +--------------------------------------- convert/convert.h | 76 ++++ convert/ext2.c | 791 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 873 insertions(+), 807 deletions(-) rename convert.c => convert/convert.c (74%) create mode 100644 convert/convert.h create mode 100644 convert/ext2.c
Makefile +5 -5
@@ -1,6 +1,6 @@ CC=gcc AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -CFLAGS = -g -Werror -Os +CFLAGS = -g -Werror -Os -I. objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
@@ -29,7 +29,7 @@ endif .c.o: $(check) $< - $(CC) $(DEPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c $< + $(CC) $(DEPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c $< -o $@ all: version $(progs) manpages
@@ -74,8 +74,8 @@ dir-test: $(objects) dir-test.o quick-test: $(objects) quick-test.o gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) -convert: $(objects) convert.o - gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lblkid $(LDFLAGS) $(LIBS) +convert: $(objects) $(patsubst %.c,%.o,$(wildcard convert/*.c)) + gcc $(CFLAGS) -o btrfs-convert $^ -lext2fs -lblkid $(LDFLAGS) $(LIBS) ioctl-test: $(objects) ioctl-test.o gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
@@ -87,7 +87,7 @@ install-man: cd man; make install clean : - rm -f $(progs) cscope.out *.o .*.d btrfs-convert + rm -f $(progs) cscope.out *.o .*.d btrfs-convert convert/*.o convert/.*.d cd man; make clean install: $(progs) install-man
convert/convert.c renamed from convert.c +1 -802
859 lines not on this page · raw message
convert/convert.h new file +76 -0
76 lines not on this page · raw message
convert/ext2.c new file +791 -0
791 lines not on this page · raw message
Signature · 1 line
1.6.4.4
Thanks for doing all this work. Which filesystems have you currently wired up to the converter?
-chris
Quoted 1,811 lines · Sean Bartell
No material changes are made.
--- Makefile | 10 +- convert.c => convert/convert.c | 803 +--------------------------------------- convert/convert.h | 76 ++++ convert/ext2.c | 791 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 873 insertions(+), 807 deletions(-) rename convert.c => convert/convert.c (74%) create mode 100644 convert/convert.h create mode 100644 convert/ext2.cMakefile +5
-5@@ -1,6 +1,6 @@ CC=gcc AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -CFLAGS = -g -Werror -Os +CFLAGS = -g -Werror -Os -I. objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \@@ -29,7 +29,7 @@ endif .c.o: $(check) $< - $(CC) $(DEPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c $< + $(CC) $(DEPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c $< -o $@ all: version $(progs) manpages@@ -74,8 +74,8 @@ dir-test: $(objects) dir-test.o quick-test: $(objects) quick-test.o gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) -convert: $(objects) convert.o - gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lblkid $(LDFLAGS) $(LIBS) +convert: $(objects) $(patsubst %.c,%.o,$(wildcard convert/*.c)) + gcc $(CFLAGS) -o btrfs-convert $^ -lext2fs -lblkid $(LDFLAGS) $(LIBS) ioctl-test: $(objects) ioctl-test.o gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)@@ -87,7 +87,7 @@ install-man: cd man; make install clean : - rm -f $(progs) cscope.out *.o .*.d btrfs-convert + rm -f $(progs) cscope.out *.o .*.d btrfs-convert convert/*.o convert/.*.d cd man; make clean install: $(progs) install-manconvert/convert.c renamed from convert.c +1
-802@@ -24,117 +24,21 @@#endif #include <stdio.h> #include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/acl.h> #include <fcntl.h> #include <unistd.h> -#include <uuid/uuid.h> -#include <linux/fs.h> #include <blkid/blkid.h> #include "kerncompat.h" +#include "convert.h" #include "ctree.h" #include "disk-io.h" #include "volumes.h" #include "transaction.h" #include "crc32c.h" #include "utils.h" -#include <ext2fs/ext2_fs.h> -#include <ext2fs/ext2fs.h> -#include <ext2fs/ext2_ext_attr.h> -struct convert_fs { -u64 total_bytes; -u64 blocksize; -const char *label; - -/* Close the FS */ -int (*close)(struct convert_fs *fs); -/* Mark free extents as dirty */ -int (*cache_free_extents)(struct convert_fs *fs, -struct extent_io_tree *tree); -/* Copy everything over */ -int (*copy_inodes)(struct convert_fs *fs,struct btrfs_root *root, -int datacsum,int packing,int noxattr); - -void *privdata; -}; - -#define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO)#define STRIPE_LEN (64 * 1024)#define ORIG_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID -/* -* Open Ext2fs in readonly mode, read block allocation bitmap and -* inode bitmap into memory. -*/ -static int open_ext2fs (const char *name,ext2_filsys *ret_fs) -{ -errcode_t ret; -ext2_filsys ext2_fs; -ext2_ino_t ino; - ret =ext2fs_open (name,0 ,0 ,0 , unix_io_manager, &ext2_fs); -if (ret) { -fprintf (stderr,"ext2fs_open: %s\n" ,error_message (ret)); - goto fail; - } - ret =ext2fs_read_inode_bitmap (ext2_fs); -if (ret) { -fprintf (stderr,"ext2fs_read_inode_bitmap: %s\n" , -error_message (ret)); - goto fail; - } - ret =ext2fs_read_block_bitmap (ext2_fs); -if (ret) { -fprintf (stderr,"ext2fs_read_block_bitmap: %s\n" , -error_message (ret)); - goto fail; - } -/* -* search each block group for a free inode. this set up -* uninit block/inode bitmaps appropriately. -*/ - ino =1 ; -while (ino <= ext2_fs->super->s_inodes_count) { -ext2_ino_t foo; -ext2fs_new_inode (ext2_fs, ino,0 ,NULL , &foo); - ino +=EXT2_INODES_PER_GROUP (ext2_fs->super); - } - - *ret_fs = ext2_fs; -return 0 ; -fail: -return -1 ; -} - -static int ext2_close (struct convert_fs *fs) -{ -ext2fs_close ((ext2_filsys )fs->privdata); -return 0 ; -} - -static int ext2_cache_free_extents (struct convert_fs *fs, -struct extent_io_tree *free_tree) -{ -ext2_filsys ext2_fs = fs->privdata; -int ret =0 ; -blk_t block; -u64 bytenr; -u64 blocksize = ext2_fs->blocksize; - - block = ext2_fs->super->s_first_data_block; -for (; block < ext2_fs->super->s_blocks_count; block++) { -if (ext2fs_fast_test_block_bitmap (ext2_fs->block_map, block)) -continue ; - bytenr = block * blocksize; - ret =set_extent_dirty (free_tree, bytenr, - bytenr + blocksize -1 ,0 ); -BUG_ON (ret); - } - -return 0 ; -} -/* mark btrfs-reserved blocks as used */ static void adjust_free_extents (struct convert_fs *fs,struct extent_io_tree *free_tree)@@ -267,113 +171,6 @@ struct btrfs_extent_ops extent_ops = { .free_extent = custom_free_extent, }; -struct dir_iterate_data { -struct btrfs_trans_handle *trans; -struct btrfs_root *root; -struct btrfs_inode_item *inode; -u64 objectid; -u64 index_cnt; -u64 parent; -int errcode; -}; - -static u8 filetype_conversion_table[EXT2_FT_MAX ] = { - [EXT2_FT_UNKNOWN ] =BTRFS_FT_UNKNOWN , - [EXT2_FT_REG_FILE ] =BTRFS_FT_REG_FILE , - [EXT2_FT_DIR ] =BTRFS_FT_DIR , - [EXT2_FT_CHRDEV ] =BTRFS_FT_CHRDEV , - [EXT2_FT_BLKDEV ] =BTRFS_FT_BLKDEV , - [EXT2_FT_FIFO ] =BTRFS_FT_FIFO , - [EXT2_FT_SOCK ] =BTRFS_FT_SOCK , - [EXT2_FT_SYMLINK ] =BTRFS_FT_SYMLINK , -}; - -static int dir_iterate_proc (ext2_ino_t dir,int entry, -struct ext2_dir_entry *old, -int offset,int blocksize, -char *buf,void *priv_data) -{ -int ret; -int file_type; -u64 objectid; -u64 inode_size; -char dotdot[] =".." ; -struct btrfs_key location; -struct ext2_dir_entry_2 *dirent = (struct ext2_dir_entry_2 *)old; -struct dir_iterate_data *idata = (struct dir_iterate_data *)priv_data; - - objectid = dirent->inode +INO_OFFSET ; -if (!strncmp (dirent->name, dotdot, dirent->name_len)) { -if (dirent->name_len ==2 ) { -BUG_ON (idata->parent !=0 ); - idata->parent = objectid; - } -return 0 ; - } -if (dirent->inode <EXT2_GOOD_OLD_FIRST_INO ) -return 0 ; - - location.objectid = objectid; - location.offset =0 ; -btrfs_set_key_type (&location,BTRFS_INODE_ITEM_KEY ); - - file_type = dirent->file_type; -BUG_ON (file_type >EXT2_FT_SYMLINK ); - ret =btrfs_insert_dir_item (idata->trans, idata->root, - dirent->name, dirent->name_len, - idata->objectid, &location, - filetype_conversion_table[file_type], - idata->index_cnt); -if (ret) - goto fail; - ret =btrfs_insert_inode_ref (idata->trans, idata->root, - dirent->name, dirent->name_len, - objectid, idata->objectid, - idata->index_cnt); -if (ret) - goto fail; - idata->index_cnt++; - inode_size =btrfs_stack_inode_size (idata->inode) + - dirent->name_len *2 ; -btrfs_set_stack_inode_size (idata->inode, inode_size); -return 0 ; -fail: - idata->errcode = ret; -return BLOCK_ABORT ; -} - -static int create_dir_entries (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -struct btrfs_inode_item *btrfs_inode, -ext2_filsys ext2_fs,ext2_ino_t ext2_ino) -{ -int ret; -errcode_t err; -struct dir_iterate_data data = { - .trans = trans, - .root = root, - .inode = btrfs_inode, - .objectid = objectid, - .index_cnt =2 , - .parent =0 , - .errcode =0 , - }; - - err =ext2fs_dir_iterate2 (ext2_fs, ext2_ino,0 ,NULL , - dir_iterate_proc, &data); -if (err) - goto error; - ret = data.errcode; -if (ret ==0 && data.parent == objectid) { - ret =btrfs_insert_inode_ref (trans, root,".." ,2 , - objectid, objectid,0 ); - } -return ret; -error: -fprintf (stderr,"ext2fs_dir_iterate2: %s\n" ,error_message (err)); -return -1 ; -} -static int read_disk_extent (struct btrfs_root *root,u64 bytenr,u64 num_bytes,char *buffer) {@@ -524,22 +321,6 @@ fail:return ret; } -struct extent_iterate_data { -struct btrfs_trans_handle *trans; -struct btrfs_root *root; -u64 *inode_nbytes; -u64 objectid; -int checksum, packing; -u64 last_file_off; -u64 total_size; -enum {EXTENT_ITERATE_TYPE_NONE ,EXTENT_ITERATE_TYPE_MEM , -EXTENT_ITERATE_TYPE_DISK } type; -u64 size; -u64 file_off;/* always aligned to sectorsize */ -char *data;/* for mem */ -u64 disk_off;/* for disk */ -}; -static u64 extent_boundary (struct btrfs_root *root,u64 extent_start) {int i;@@ -710,9 +491,6 @@ int finish_file_extents(struct extent_iterate_data *priv)return 0 ; } -int add_file_mem_extent (struct extent_iterate_data *priv,u64 file_off, -u64 size,char *data); -int add_file_disk_extent (struct extent_iterate_data *priv,u64 file_off,u64 disk_off,u64 size) {@@ -861,510 +639,6 @@ int add_file_mem_extent(struct extent_iterate_data *priv, u64 file_off,return 0 ; } -static int __block_iterate_proc (ext2_filsys fs,blk_t *blocknr, -e2_blkcnt_t blockcnt,blk_t ref_block, -int ref_offset,void *priv_data) -{ -struct extent_iterate_data *idata; - idata = (struct extent_iterate_data *)priv_data; -u64 blocksize = fs->blocksize; -int ret =add_file_disk_extent (idata, blocksize * blockcnt, - blocksize * *blocknr, blocksize); -if (ret) -return BLOCK_ABORT ; -return 0 ; -} - -/* -* traverse file's data blocks, record these data blocks as file extents. -*/ -static int create_file_extents (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -struct btrfs_inode_item *btrfs_inode, -ext2_filsys ext2_fs,ext2_ino_t ext2_ino, -int datacsum,int packing) -{ -int ret; -errcode_t err; -u64 inode_nbytes =0 ; -u64 inode_size =btrfs_stack_inode_size (btrfs_inode); -struct extent_iterate_data data; - ret =start_file_extents (&data, trans, root, &inode_nbytes, objectid, - datacsum, packing, inode_size); -if (ret) -return ret; - err =ext2fs_block_iterate2 (ext2_fs, ext2_ino,BLOCK_FLAG_DATA_ONLY , -NULL , __block_iterate_proc, &data); -if (err) - goto error; - ret =finish_file_extents (&data); -if (ret) -return ret; -btrfs_set_stack_inode_nbytes (btrfs_inode, inode_nbytes); -return 0 ; -error: -fprintf (stderr,"ext2fs_block_iterate2: %s\n" ,error_message (err)); -return -1 ; -} - -static int create_symbol_link (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -struct btrfs_inode_item *btrfs_inode, -ext2_filsys ext2_fs,ext2_ino_t ext2_ino, -struct ext2_inode *ext2_inode) -{ -int ret; -char *pathname; -u64 inode_size =btrfs_stack_inode_size (btrfs_inode); -if (ext2fs_inode_data_blocks (ext2_fs, ext2_inode)) { -btrfs_set_stack_inode_size (btrfs_inode, inode_size +1 ); - ret =create_file_extents (trans, root, objectid, btrfs_inode, - ext2_fs, ext2_ino,1 ,1 ); -btrfs_set_stack_inode_size (btrfs_inode, inode_size); -return ret; - } - - pathname = (char *)&(ext2_inode->i_block[0 ]); -BUG_ON (pathname[inode_size] !=0 ); - ret =btrfs_insert_inline_extent (trans, root, objectid,0 , - pathname, inode_size +1 ); -btrfs_set_stack_inode_nbytes (btrfs_inode, inode_size +1 ); -return ret; -} - -/* -* Following xattr/acl related codes are based on codes in -* fs/ext3/xattr.c and fs/ext3/acl.c -*/ -#define EXT2_XATTR_BHDR (ptr) ((struct ext2_ext_attr_header *)(ptr)) -#define EXT2_XATTR_BFIRST (ptr) \ - ((struct ext2_ext_attr_entry *)(EXT2_XATTR_BHDR(ptr) + 1)) -#define EXT2_XATTR_IHDR (inode) \ - ((struct ext2_ext_attr_header *) ((void *)(inode) + \ - EXT2_GOOD_OLD_INODE_SIZE + (inode)->i_extra_isize)) -#define EXT2_XATTR_IFIRST (inode) \ - ((struct ext2_ext_attr_entry *) ((void *)EXT2_XATTR_IHDR(inode) + \ - sizeof(EXT2_XATTR_IHDR(inode)->h_magic))) - -static int ext2_xattr_check_names (struct ext2_ext_attr_entry *entry, -const void *end) -{ -struct ext2_ext_attr_entry *next; - -while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { - next =EXT2_EXT_ATTR_NEXT (entry); -if ((void *)next >= end) -return -EIO ; - entry = next; - } -return 0 ; -} - -static int ext2_xattr_check_block (const char *buf,size_t size) -{ -int error; -struct ext2_ext_attr_header *header =EXT2_XATTR_BHDR (buf); - -if (header->h_magic !=EXT2_EXT_ATTR_MAGIC || - header->h_blocks !=1 ) -return -EIO ; - error =ext2_xattr_check_names (EXT2_XATTR_BFIRST (buf), buf + size); -return error; -} - -static int ext2_xattr_check_entry (struct ext2_ext_attr_entry *entry, -size_t size) -{ -size_t value_size = entry->e_value_size; - -if (entry->e_value_block !=0 || value_size > size || - entry->e_value_offs + value_size > size) -return -EIO ; -return 0 ; -} - -#define EXT2_ACL_VERSION 0x0001 - -typedef struct { -__le16 e_tag; -__le16 e_perm; -__le32 e_id; -}ext2_acl_entry ; - -typedef struct { -__le16 e_tag; -__le16 e_perm; -}ext2_acl_entry_short ; - -typedef struct { -__le32 a_version; -}ext2_acl_header ; - -static inline int ext2_acl_count (size_t size) -{ -ssize_t s; - size -=sizeof (ext2_acl_header); - s = size -4 *sizeof (ext2_acl_entry_short); -if (s <0 ) { -if (size %sizeof (ext2_acl_entry_short)) -return -1 ; -return size /sizeof (ext2_acl_entry_short); - }else { -if (s %sizeof (ext2_acl_entry)) -return -1 ; -return s /sizeof (ext2_acl_entry) +4 ; - } -} - -#define ACL_EA_VERSION 0x0002 - -typedef struct { -__le16 e_tag; -__le16 e_perm; -__le32 e_id; -}acl_ea_entry ; - -typedef struct { -__le32 a_version; -acl_ea_entry a_entries[0 ]; -}acl_ea_header ; - -static inline size_t acl_ea_size (int count) -{ -return sizeof (acl_ea_header) + count *sizeof (acl_ea_entry); -} - -static int ext2_acl_to_xattr (void *dst,const void *src, -size_t dst_size,size_t src_size) -{ -int i, count; -const void *end = src + src_size; -acl_ea_header *ext_acl = (acl_ea_header *)dst; -acl_ea_entry *dst_entry = ext_acl->a_entries; -ext2_acl_entry *src_entry; - -if (src_size <sizeof (ext2_acl_header)) - goto fail; -if (((ext2_acl_header *)src)->a_version != -cpu_to_le32 (EXT2_ACL_VERSION )) - goto fail; - src +=sizeof (ext2_acl_header); - count =ext2_acl_count (src_size); -if (count <=0 ) - goto fail; - -BUG_ON (dst_size <acl_ea_size (count)); - ext_acl->a_version =cpu_to_le32 (ACL_EA_VERSION ); -for (i =0 ; i < count; i++, dst_entry++) { - src_entry = (ext2_acl_entry *)src; -if (src +sizeof (ext2_acl_entry_short) > end) - goto fail; - dst_entry->e_tag = src_entry->e_tag; - dst_entry->e_perm = src_entry->e_perm; -switch (le16_to_cpu (src_entry->e_tag)) { -case ACL_USER_OBJ : -case ACL_GROUP_OBJ : -case ACL_MASK : -case ACL_OTHER : - src +=sizeof (ext2_acl_entry_short); - dst_entry->e_id =cpu_to_le32 (ACL_UNDEFINED_ID ); -break ; -case ACL_USER : -case ACL_GROUP : - src +=sizeof (ext2_acl_entry); -if (src > end) - goto fail; - dst_entry->e_id = src_entry->e_id; -break ; -default : - goto fail; - } - } -if (src != end) - goto fail; -return 0 ; -fail: -return -EINVAL ; -} - -static char *xattr_prefix_table[] = { - [1 ] ="user." , - [2 ] ="system.posix_acl_access" , - [3 ] ="system.posix_acl_default" , - [4 ] ="trusted." , - [6 ] ="security." , -}; - -static int copy_single_xattr (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -struct ext2_ext_attr_entry *entry, -const void *data,u32 datalen) -{ -int ret =0 ; -int name_len; -int name_index; -void *databuf =NULL ; -char namebuf[XATTR_NAME_MAX +1 ]; - - name_index = entry->e_name_index; -if (name_index >=ARRAY_SIZE (xattr_prefix_table) || - xattr_prefix_table[name_index] ==NULL ) -return -EOPNOTSUPP ; - name_len =strlen (xattr_prefix_table[name_index]) + - entry->e_name_len; -if (name_len >=sizeof (namebuf)) -return -ERANGE ; - -if (name_index ==2 || name_index ==3 ) { -size_t bufsize =acl_ea_size (ext2_acl_count (datalen)); - databuf =malloc (bufsize); -if (!databuf) -return -ENOMEM ; - ret =ext2_acl_to_xattr (databuf, data, bufsize, datalen); -if (ret) - goto out; - data = databuf; - datalen = bufsize; - } -strcpy (namebuf, xattr_prefix_table[name_index]); -strncat (namebuf,EXT2_EXT_ATTR_NAME (entry), entry->e_name_len); -if (name_len + datalen >BTRFS_LEAF_DATA_SIZE (root) - -sizeof (struct btrfs_item ) -sizeof (struct btrfs_dir_item )) { -fprintf (stderr,"skip large xattr on inode %Lu name %.*s\n" , - objectid -INO_OFFSET , name_len, namebuf); - goto out; - } - ret =btrfs_insert_xattr_item (trans, root, namebuf, name_len, - data, datalen, objectid); -out: -if (databuf) -free (databuf); -return ret; -} - -static int copy_extended_attrs (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -struct btrfs_inode_item *btrfs_inode, -ext2_filsys ext2_fs,ext2_ino_t ext2_ino) -{ -int ret =0 ; -int inline_ea =0 ; -errcode_t err; -u32 datalen; -u32 block_size = ext2_fs->blocksize; -u32 inode_size =EXT2_INODE_SIZE (ext2_fs->super); -struct ext2_inode_large *ext2_inode; -struct ext2_ext_attr_entry *entry; -void *data; -char *buffer =NULL ; -char inode_buf[EXT2_GOOD_OLD_INODE_SIZE ]; - -if (inode_size <=EXT2_GOOD_OLD_INODE_SIZE ) { - ext2_inode = (struct ext2_inode_large *)inode_buf; - }else { - ext2_inode = (struct ext2_inode_large *)malloc (inode_size); -if (!ext2_inode) -return -ENOMEM ; - } - err =ext2fs_read_inode_full (ext2_fs, ext2_ino, (void *)ext2_inode, - inode_size); -if (err) { -fprintf (stderr,"ext2fs_read_inode_full: %s\n" , -error_message (err)); - ret =-1 ; - goto out; - } - -if (ext2_ino > ext2_fs->super->s_first_ino && - inode_size >EXT2_GOOD_OLD_INODE_SIZE ) { -if (EXT2_GOOD_OLD_INODE_SIZE + - ext2_inode->i_extra_isize > inode_size) { - ret = -EIO ; - goto out; - } -if (ext2_inode->i_extra_isize !=0 && -EXT2_XATTR_IHDR (ext2_inode)->h_magic == -EXT2_EXT_ATTR_MAGIC ) { - inline_ea =1 ; - } - } -if (inline_ea) { -int total; -void *end = (void *)ext2_inode + inode_size; - entry =EXT2_XATTR_IFIRST (ext2_inode); - total = end - (void *)entry; - ret =ext2_xattr_check_names (entry, end); -if (ret) - goto out; -while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { - ret =ext2_xattr_check_entry (entry, total); -if (ret) - goto out; - data = (void *)EXT2_XATTR_IFIRST (ext2_inode) + - entry->e_value_offs; - datalen = entry->e_value_size; - ret =copy_single_xattr (trans, root, objectid, - entry, data, datalen); -if (ret) - goto out; - entry =EXT2_EXT_ATTR_NEXT (entry); - } - } - -if (ext2_inode->i_file_acl ==0 ) - goto out; - - buffer =malloc (block_size); -if (!buffer) { - ret = -ENOMEM ; - goto out; - } - err =ext2fs_read_ext_attr (ext2_fs, ext2_inode->i_file_acl, buffer); -if (err) { -fprintf (stderr,"ext2fs_read_ext_attr: %s\n" , -error_message (err)); - ret =-1 ; - goto out; - } - ret =ext2_xattr_check_block (buffer, block_size); -if (ret) - goto out; - - entry =EXT2_XATTR_BFIRST (buffer); -while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { - ret =ext2_xattr_check_entry (entry, block_size); -if (ret) - goto out; - data = buffer + entry->e_value_offs; - datalen = entry->e_value_size; - ret =copy_single_xattr (trans, root, objectid, - entry, data, datalen); -if (ret) - goto out; - entry =EXT2_EXT_ATTR_NEXT (entry); - } -out: -if (buffer !=NULL ) -free (buffer); -if ((void *)ext2_inode != inode_buf) -free (ext2_inode); -return ret; -} -#define MINORBITS 20 -#define MKDEV (ma, mi) (((ma) << MINORBITS) | (mi)) - -static inline dev_t old_decode_dev (u16 val) -{ -return MKDEV ((val >>8 ) &255 , val &255 ); -} - -static inline dev_t new_decode_dev (u32 dev) -{ -unsigned major = (dev &0xfff00 ) >>8 ; -unsigned minor = (dev &0xff ) | ((dev >>12 ) &0xfff00 ); -return MKDEV (major, minor); -} - -static int copy_inode_item (struct btrfs_inode_item *dst, -struct ext2_inode *src,u32 blocksize) -{ -btrfs_set_stack_inode_generation (dst,1 ); -btrfs_set_stack_inode_size (dst, src->i_size); -btrfs_set_stack_inode_nbytes (dst,0 ); -btrfs_set_stack_inode_block_group (dst,0 ); -btrfs_set_stack_inode_nlink (dst, src->i_links_count); -btrfs_set_stack_inode_uid (dst, src->i_uid | (src->i_uid_high <<16 )); -btrfs_set_stack_inode_gid (dst, src->i_gid | (src->i_gid_high <<16 )); -btrfs_set_stack_inode_mode (dst, src->i_mode); -btrfs_set_stack_inode_rdev (dst,0 ); -btrfs_set_stack_inode_flags (dst,0 ); -btrfs_set_stack_timespec_sec (&dst->atime, src->i_atime); -btrfs_set_stack_timespec_nsec (&dst->atime,0 ); -btrfs_set_stack_timespec_sec (&dst->ctime, src->i_ctime); -btrfs_set_stack_timespec_nsec (&dst->ctime,0 ); -btrfs_set_stack_timespec_sec (&dst->mtime, src->i_mtime); -btrfs_set_stack_timespec_nsec (&dst->mtime,0 ); -btrfs_set_stack_timespec_sec (&dst->otime,0 ); -btrfs_set_stack_timespec_nsec (&dst->otime,0 ); - -if (S_ISDIR (src->i_mode)) { -btrfs_set_stack_inode_size (dst,0 ); -btrfs_set_stack_inode_nlink (dst,1 ); - } -if (S_ISREG (src->i_mode)) { -btrfs_set_stack_inode_size (dst, (u64 )src->i_size_high <<32 | - (u64 )src->i_size); - } -if (!S_ISREG (src->i_mode) && !S_ISDIR (src->i_mode) && - !S_ISLNK (src->i_mode)) { -if (src->i_block[0 ]) { -btrfs_set_stack_inode_rdev (dst, -old_decode_dev (src->i_block[0 ])); - }else { -btrfs_set_stack_inode_rdev (dst, -new_decode_dev (src->i_block[1 ])); - } - } -return 0 ; -} - -/* -* copy a single inode. do all the required works, such as cloning -* inode item, creating file extents and creating directory entries. -*/ -static int copy_single_inode (struct btrfs_trans_handle *trans, -struct btrfs_root *root,u64 objectid, -ext2_filsys ext2_fs,ext2_ino_t ext2_ino, -struct ext2_inode *ext2_inode, -int datacsum,int packing,int noxattr) -{ -int ret; -struct btrfs_key inode_key; -struct btrfs_inode_item btrfs_inode; - -if (ext2_inode->i_links_count ==0 ) -return 0 ; - -copy_inode_item (&btrfs_inode, ext2_inode, ext2_fs->blocksize); -if (!datacsum &&S_ISREG (ext2_inode->i_mode)) { -u32 flags =btrfs_stack_inode_flags (&btrfs_inode) | -BTRFS_INODE_NODATASUM ; -btrfs_set_stack_inode_flags (&btrfs_inode, flags); - } - -switch (ext2_inode->i_mode &S_IFMT ) { -case S_IFREG : - ret =create_file_extents (trans, root, objectid, &btrfs_inode, - ext2_fs, ext2_ino, datacsum, packing); -break ; -case S_IFDIR : - ret =create_dir_entries (trans, root, objectid, &btrfs_inode, - ext2_fs, ext2_ino); -break ; -case S_IFLNK : - ret =create_symbol_link (trans, root, objectid, &btrfs_inode, - ext2_fs, ext2_ino, ext2_inode); -break ; -default : - ret =0 ; -break ; - } -if (ret) -return ret; - -if (!noxattr) { - ret =copy_extended_attrs (trans, root, objectid, &btrfs_inode, - ext2_fs, ext2_ino); -if (ret) -return ret; - } - inode_key.objectid = objectid; - inode_key.offset =0 ; -btrfs_set_key_type (&inode_key,BTRFS_INODE_ITEM_KEY ); - ret =btrfs_insert_inode (trans, root, objectid, &btrfs_inode); -return ret; -} -static int copy_disk_extent (struct btrfs_root *root,u64 dst_bytenr,u64 src_bytenr,u32 num_bytes) {@@ -1388,61 +662,6 @@ fail: ret =-1 ;return ret; } -/* -* scan ext2's inode bitmap and copy all used inode. -*/ -static int ext2_copy_inodes (struct convert_fs *fs,struct btrfs_root *root, -int datacsum,int packing,int noxattr) -{ -ext2_filsys ext2_fs = fs->privdata; -int ret; -errcode_t err; -ext2_inode_scan ext2_scan; -struct ext2_inode ext2_inode; -ext2_ino_t ext2_ino; -u64 objectid; -struct btrfs_trans_handle *trans; - - trans =btrfs_start_transaction (root,1 ); -if (!trans) -return -ENOMEM ; - err =ext2fs_open_inode_scan (ext2_fs,0 , &ext2_scan); -if (err) { -fprintf (stderr,"ext2fs_open_inode_scan: %s\n" ,error_message (err)); -return -1 ; - } -while (!(err =ext2fs_get_next_inode (ext2_scan, &ext2_ino, - &ext2_inode))) { -/* no more inodes */ -if (ext2_ino ==0 ) -break ; -/* skip special inode in ext2fs */ -if (ext2_ino <EXT2_GOOD_OLD_FIRST_INO && - ext2_ino !=EXT2_ROOT_INO ) -continue ; - objectid = ext2_ino +INO_OFFSET ; - ret =copy_single_inode (trans, root, - objectid, ext2_fs, ext2_ino, - &ext2_inode, datacsum, packing, - noxattr); -if (ret) -return ret; -if (trans->blocks_used >=4096 ) { - ret =btrfs_commit_transaction (trans, root); -BUG_ON (ret); - trans =btrfs_start_transaction (root,1 ); -BUG_ON (!trans); - } - } -if (err) { -fprintf (stderr,"ext2fs_get_next_inode: %s\n" ,error_message (err)); -return -1 ; - } - ret =btrfs_commit_transaction (trans, root); -BUG_ON (ret); - -return ret; -}/* * Construct a range of the image file. @@ -2586,26 +1805,6 @@ static int copy_dirtiness(struct extent_io_tree *out,return 0 ; } -int ext2_open (struct convert_fs *fs,const char *name) -{ -int ret; -ext2_filsys ext2_fs; - ret =open_ext2fs (name, &ext2_fs); -if (ret) -return ret; - - fs->privdata = ext2_fs; - fs->blocksize = ext2_fs->blocksize; - fs->label = ext2_fs->super->s_volume_name; - fs->total_bytes = ext2_fs->super->s_blocks_count * fs->blocksize; - - fs->cache_free_extents = ext2_cache_free_extents; - fs->close = ext2_close; - fs->copy_inodes = ext2_copy_inodes; - -return 0 ; -} -static int open_fs (struct convert_fs *fs,const char *devname) { static struct {convert/convert.h new file +76
-0@@ -0,0 +1,76 @@ +/* +* Copyright (C) 2007 Oracle. All rights reserved. +* Copyright (C) 2010 Sean Bartell. All rights reserved. +* +* 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. +*/ +#ifndef BTRFS_CONVERT_H +#define BTRFS_CONVERT_H + +#include "ctree.h" +#include "kerncompat.h" +#include "transaction.h" + +struct convert_fs { +u64 total_bytes; +u64 blocksize; +const char *label; + +/* Close the FS */ +int (*close)(struct convert_fs *fs); +/* Mark free extents as dirty */ +int (*cache_free_extents)(struct convert_fs *fs, +struct extent_io_tree *tree); +/* Copy everything over */ +int (*copy_inodes)(struct convert_fs *fs,struct btrfs_root *root, +int datacsum,int packing,int noxattr); + +void *privdata; +}; + +int ext2_open (struct convert_fs *fs,const char *name); + +struct extent_iterate_data { +struct btrfs_trans_handle *trans; +struct btrfs_root *root; +u64 *inode_nbytes; +u64 objectid; +int checksum, packing; +u64 last_file_off; +u64 total_size; +enum {EXTENT_ITERATE_TYPE_NONE ,EXTENT_ITERATE_TYPE_MEM , +EXTENT_ITERATE_TYPE_DISK } type; +u64 size; +u64 file_off;/* always aligned to sectorsize */ +char *data;/* for mem */ +u64 disk_off;/* for disk */ +}; + +int start_file_extents (struct extent_iterate_data *priv, +struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 *inode_nbytes, +u64 objectid,int checksum,int packing, +u64 total_size); +int start_file_extents_range (struct extent_iterate_data *priv, +struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 *inode_nbytes, +u64 objectid,int checksum,u64 start,u64 end); +int finish_file_extents (struct extent_iterate_data *priv); +int add_file_mem_extent (struct extent_iterate_data *priv,u64 file_off, +u64 size,char *data); +int add_file_disk_extent (struct extent_iterate_data *priv,u64 file_off, +u64 disk_off,u64 size); + +#endif convert/ext2.c new file +791
-0@@ -0,0 +1,791 @@ +/* +* Copyright (C) 2007 Oracle. All rights reserved. +* +* 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 <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <linux/fs.h> +#include "kerncompat.h" +#include "convert.h" +#include "ctree.h" +#include "disk-io.h" +#include "transaction.h" +#include <ext2fs/ext2_fs.h> +#include <ext2fs/ext2fs.h> +#include <ext2fs/ext2_ext_attr.h> + +#define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO) + +/* +* Open Ext2fs in readonly mode, read block allocation bitmap and +* inode bitmap into memory. +*/ +static int open_ext2fs (const char *name,ext2_filsys *ret_fs) +{ +errcode_t ret; +ext2_filsys ext2_fs; +ext2_ino_t ino; + ret =ext2fs_open (name,0 ,0 ,0 , unix_io_manager, &ext2_fs); +if (ret) { +fprintf (stderr,"ext2fs_open: %s\n" ,error_message (ret)); + goto fail; + } + ret =ext2fs_read_inode_bitmap (ext2_fs); +if (ret) { +fprintf (stderr,"ext2fs_read_inode_bitmap: %s\n" , +error_message (ret)); + goto fail; + } + ret =ext2fs_read_block_bitmap (ext2_fs); +if (ret) { +fprintf (stderr,"ext2fs_read_block_bitmap: %s\n" , +error_message (ret)); + goto fail; + } +/* +* search each block group for a free inode. this set up +* uninit block/inode bitmaps appropriately. +*/ + ino =1 ; +while (ino <= ext2_fs->super->s_inodes_count) { +ext2_ino_t foo; +ext2fs_new_inode (ext2_fs, ino,0 ,NULL , &foo); + ino +=EXT2_INODES_PER_GROUP (ext2_fs->super); + } + + *ret_fs = ext2_fs; +return 0 ; +fail: +return -1 ; +} + +static int ext2_close (struct convert_fs *fs) +{ +ext2fs_close ((ext2_filsys )fs->privdata); +return 0 ; +} + +static int ext2_cache_free_extents (struct convert_fs *fs, +struct extent_io_tree *free_tree) +{ +ext2_filsys ext2_fs = fs->privdata; +int ret =0 ; +blk_t block; +u64 bytenr; +u64 blocksize = ext2_fs->blocksize; + + block = ext2_fs->super->s_first_data_block; +for (; block < ext2_fs->super->s_blocks_count; block++) { +if (ext2fs_fast_test_block_bitmap (ext2_fs->block_map, block)) +continue ; + bytenr = block * blocksize; + ret =set_extent_dirty (free_tree, bytenr, + bytenr + blocksize -1 ,0 ); +BUG_ON (ret); + } + +return 0 ; +} + +struct dir_iterate_data { +struct btrfs_trans_handle *trans; +struct btrfs_root *root; +struct btrfs_inode_item *inode; +u64 objectid; +u64 index_cnt; +u64 parent; +int errcode; +}; + +static u8 filetype_conversion_table[EXT2_FT_MAX ] = { + [EXT2_FT_UNKNOWN ] =BTRFS_FT_UNKNOWN , + [EXT2_FT_REG_FILE ] =BTRFS_FT_REG_FILE , + [EXT2_FT_DIR ] =BTRFS_FT_DIR , + [EXT2_FT_CHRDEV ] =BTRFS_FT_CHRDEV , + [EXT2_FT_BLKDEV ] =BTRFS_FT_BLKDEV , + [EXT2_FT_FIFO ] =BTRFS_FT_FIFO , + [EXT2_FT_SOCK ] =BTRFS_FT_SOCK , + [EXT2_FT_SYMLINK ] =BTRFS_FT_SYMLINK , +}; + +static int dir_iterate_proc (ext2_ino_t dir,int entry, +struct ext2_dir_entry *old, +int offset,int blocksize, +char *buf,void *priv_data) +{ +int ret; +int file_type; +u64 objectid; +u64 inode_size; +char dotdot[] =".." ; +struct btrfs_key location; +struct ext2_dir_entry_2 *dirent = (struct ext2_dir_entry_2 *)old; +struct dir_iterate_data *idata = (struct dir_iterate_data *)priv_data; + + objectid = dirent->inode +INO_OFFSET ; +if (!strncmp (dirent->name, dotdot, dirent->name_len)) { +if (dirent->name_len ==2 ) { +BUG_ON (idata->parent !=0 ); + idata->parent = objectid; + } +return 0 ; + } +if (dirent->inode <EXT2_GOOD_OLD_FIRST_INO ) +return 0 ; + + location.objectid = objectid; + location.offset =0 ; +btrfs_set_key_type (&location,BTRFS_INODE_ITEM_KEY ); + + file_type = dirent->file_type; +BUG_ON (file_type >EXT2_FT_SYMLINK ); + ret =btrfs_insert_dir_item (idata->trans, idata->root, + dirent->name, dirent->name_len, + idata->objectid, &location, + filetype_conversion_table[file_type], + idata->index_cnt); +if (ret) + goto fail; + ret =btrfs_insert_inode_ref (idata->trans, idata->root, + dirent->name, dirent->name_len, + objectid, idata->objectid, + idata->index_cnt); +if (ret) + goto fail; + idata->index_cnt++; + inode_size =btrfs_stack_inode_size (idata->inode) + + dirent->name_len *2 ; +btrfs_set_stack_inode_size (idata->inode, inode_size); +return 0 ; +fail: + idata->errcode = ret; +return BLOCK_ABORT ; +} + +static int create_dir_entries (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +struct btrfs_inode_item *btrfs_inode, +ext2_filsys ext2_fs,ext2_ino_t ext2_ino) +{ +int ret; +errcode_t err; +struct dir_iterate_data data = { + .trans = trans, + .root = root, + .inode = btrfs_inode, + .objectid = objectid, + .index_cnt =2 , + .parent =0 , + .errcode =0 , + }; + + err =ext2fs_dir_iterate2 (ext2_fs, ext2_ino,0 ,NULL , + dir_iterate_proc, &data); +if (err) + goto error; + ret = data.errcode; +if (ret ==0 && data.parent == objectid) { + ret =btrfs_insert_inode_ref (trans, root,".." ,2 , + objectid, objectid,0 ); + } +return ret; +error: +fprintf (stderr,"ext2fs_dir_iterate2: %s\n" ,error_message (err)); +return -1 ; +} + +static int __block_iterate_proc (ext2_filsys fs,blk_t *blocknr, +e2_blkcnt_t blockcnt,blk_t ref_block, +int ref_offset,void *priv_data) +{ +struct extent_iterate_data *idata; + idata = (struct extent_iterate_data *)priv_data; +u64 blocksize = fs->blocksize; +int ret =add_file_disk_extent (idata, blocksize * blockcnt, + blocksize * *blocknr, blocksize); +if (ret) +return BLOCK_ABORT ; +return 0 ; +} + +/* +* traverse file's data blocks, record these data blocks as file extents. +*/ +static int create_file_extents (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +struct btrfs_inode_item *btrfs_inode, +ext2_filsys ext2_fs,ext2_ino_t ext2_ino, +int datacsum,int packing) +{ +int ret; +errcode_t err; +u64 inode_nbytes =0 ; +u64 inode_size =btrfs_stack_inode_size (btrfs_inode); +struct extent_iterate_data data; + ret =start_file_extents (&data, trans, root, &inode_nbytes, objectid, + datacsum, packing, inode_size); +if (ret) +return ret; + err =ext2fs_block_iterate2 (ext2_fs, ext2_ino,BLOCK_FLAG_DATA_ONLY , +NULL , __block_iterate_proc, &data); +if (err) + goto error; + ret =finish_file_extents (&data); +if (ret) +return ret; +btrfs_set_stack_inode_nbytes (btrfs_inode, inode_nbytes); +return 0 ; +error: +fprintf (stderr,"ext2fs_block_iterate2: %s\n" ,error_message (err)); +return -1 ; +} + +static int create_symbol_link (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +struct btrfs_inode_item *btrfs_inode, +ext2_filsys ext2_fs,ext2_ino_t ext2_ino, +struct ext2_inode *ext2_inode) +{ +int ret; +char *pathname; +u64 inode_size =btrfs_stack_inode_size (btrfs_inode); +if (ext2fs_inode_data_blocks (ext2_fs, ext2_inode)) { +btrfs_set_stack_inode_size (btrfs_inode, inode_size +1 ); + ret =create_file_extents (trans, root, objectid, btrfs_inode, + ext2_fs, ext2_ino,1 ,1 ); +btrfs_set_stack_inode_size (btrfs_inode, inode_size); +return ret; + } + + pathname = (char *)&(ext2_inode->i_block[0 ]); +BUG_ON (pathname[inode_size] !=0 ); + ret =btrfs_insert_inline_extent (trans, root, objectid,0 , + pathname, inode_size +1 ); +btrfs_set_stack_inode_nbytes (btrfs_inode, inode_size +1 ); +return ret; +} + +/* +* Following xattr/acl related codes are based on codes in +* fs/ext3/xattr.c and fs/ext3/acl.c +*/ +#define EXT2_XATTR_BHDR (ptr) ((struct ext2_ext_attr_header *)(ptr)) +#define EXT2_XATTR_BFIRST (ptr) \ + ((struct ext2_ext_attr_entry *)(EXT2_XATTR_BHDR(ptr) + 1)) +#define EXT2_XATTR_IHDR (inode) \ + ((struct ext2_ext_attr_header *) ((void *)(inode) + \ + EXT2_GOOD_OLD_INODE_SIZE + (inode)->i_extra_isize)) +#define EXT2_XATTR_IFIRST (inode) \ + ((struct ext2_ext_attr_entry *) ((void *)EXT2_XATTR_IHDR(inode) + \ + sizeof(EXT2_XATTR_IHDR(inode)->h_magic))) + +static int ext2_xattr_check_names (struct ext2_ext_attr_entry *entry, +const void *end) +{ +struct ext2_ext_attr_entry *next; + +while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { + next =EXT2_EXT_ATTR_NEXT (entry); +if ((void *)next >= end) +return -EIO ; + entry = next; + } +return 0 ; +} + +static int ext2_xattr_check_block (const char *buf,size_t size) +{ +int error; +struct ext2_ext_attr_header *header =EXT2_XATTR_BHDR (buf); + +if (header->h_magic !=EXT2_EXT_ATTR_MAGIC || + header->h_blocks !=1 ) +return -EIO ; + error =ext2_xattr_check_names (EXT2_XATTR_BFIRST (buf), buf + size); +return error; +} + +static int ext2_xattr_check_entry (struct ext2_ext_attr_entry *entry, +size_t size) +{ +size_t value_size = entry->e_value_size; + +if (entry->e_value_block !=0 || value_size > size || + entry->e_value_offs + value_size > size) +return -EIO ; +return 0 ; +} + +#define EXT2_ACL_VERSION 0x0001 + +typedef struct { +__le16 e_tag; +__le16 e_perm; +__le32 e_id; +}ext2_acl_entry ; + +typedef struct { +__le16 e_tag; +__le16 e_perm; +}ext2_acl_entry_short ; + +typedef struct { +__le32 a_version; +}ext2_acl_header ; + +static inline int ext2_acl_count (size_t size) +{ +ssize_t s; + size -=sizeof (ext2_acl_header); + s = size -4 *sizeof (ext2_acl_entry_short); +if (s <0 ) { +if (size %sizeof (ext2_acl_entry_short)) +return -1 ; +return size /sizeof (ext2_acl_entry_short); + }else { +if (s %sizeof (ext2_acl_entry)) +return -1 ; +return s /sizeof (ext2_acl_entry) +4 ; + } +} + +#define ACL_EA_VERSION 0x0002 + +typedef struct { +__le16 e_tag; +__le16 e_perm; +__le32 e_id; +}acl_ea_entry ; + +typedef struct { +__le32 a_version; +acl_ea_entry a_entries[0 ]; +}acl_ea_header ; + +static inline size_t acl_ea_size (int count) +{ +return sizeof (acl_ea_header) + count *sizeof (acl_ea_entry); +} + +static int ext2_acl_to_xattr (void *dst,const void *src, +size_t dst_size,size_t src_size) +{ +int i, count; +const void *end = src + src_size; +acl_ea_header *ext_acl = (acl_ea_header *)dst; +acl_ea_entry *dst_entry = ext_acl->a_entries; +ext2_acl_entry *src_entry; + +if (src_size <sizeof (ext2_acl_header)) + goto fail; +if (((ext2_acl_header *)src)->a_version != +cpu_to_le32 (EXT2_ACL_VERSION )) + goto fail; + src +=sizeof (ext2_acl_header); + count =ext2_acl_count (src_size); +if (count <=0 ) + goto fail; + +BUG_ON (dst_size <acl_ea_size (count)); + ext_acl->a_version =cpu_to_le32 (ACL_EA_VERSION ); +for (i =0 ; i < count; i++, dst_entry++) { + src_entry = (ext2_acl_entry *)src; +if (src +sizeof (ext2_acl_entry_short) > end) + goto fail; + dst_entry->e_tag = src_entry->e_tag; + dst_entry->e_perm = src_entry->e_perm; +switch (le16_to_cpu (src_entry->e_tag)) { +case ACL_USER_OBJ : +case ACL_GROUP_OBJ : +case ACL_MASK : +case ACL_OTHER : + src +=sizeof (ext2_acl_entry_short); + dst_entry->e_id =cpu_to_le32 (ACL_UNDEFINED_ID ); +break ; +case ACL_USER : +case ACL_GROUP : + src +=sizeof (ext2_acl_entry); +if (src > end) + goto fail; + dst_entry->e_id = src_entry->e_id; +break ; +default : + goto fail; + } + } +if (src != end) + goto fail; +return 0 ; +fail: +return -EINVAL ; +} + +static char *xattr_prefix_table[] = { + [1 ] ="user." , + [2 ] ="system.posix_acl_access" , + [3 ] ="system.posix_acl_default" , + [4 ] ="trusted." , + [6 ] ="security." , +}; + +static int copy_single_xattr (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +struct ext2_ext_attr_entry *entry, +const void *data,u32 datalen) +{ +int ret =0 ; +int name_len; +int name_index; +void *databuf =NULL ; +char namebuf[XATTR_NAME_MAX +1 ]; + + name_index = entry->e_name_index; +if (name_index >=ARRAY_SIZE (xattr_prefix_table) || + xattr_prefix_table[name_index] ==NULL ) +return -EOPNOTSUPP ; + name_len =strlen (xattr_prefix_table[name_index]) + + entry->e_name_len; +if (name_len >=sizeof (namebuf)) +return -ERANGE ; + +if (name_index ==2 || name_index ==3 ) { +size_t bufsize =acl_ea_size (ext2_acl_count (datalen)); + databuf =malloc (bufsize); +if (!databuf) +return -ENOMEM ; + ret =ext2_acl_to_xattr (databuf, data, bufsize, datalen); +if (ret) + goto out; + data = databuf; + datalen = bufsize; + } +strcpy (namebuf, xattr_prefix_table[name_index]); +strncat (namebuf,EXT2_EXT_ATTR_NAME (entry), entry->e_name_len); +if (name_len + datalen >BTRFS_LEAF_DATA_SIZE (root) - +sizeof (struct btrfs_item ) -sizeof (struct btrfs_dir_item )) { +fprintf (stderr,"skip large xattr on inode %Lu name %.*s\n" , + objectid -INO_OFFSET , name_len, namebuf); + goto out; + } + ret =btrfs_insert_xattr_item (trans, root, namebuf, name_len, + data, datalen, objectid); +out: +if (databuf) +free (databuf); +return ret; +} + +static int copy_extended_attrs (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +struct btrfs_inode_item *btrfs_inode, +ext2_filsys ext2_fs,ext2_ino_t ext2_ino) +{ +int ret =0 ; +int inline_ea =0 ; +errcode_t err; +u32 datalen; +u32 block_size = ext2_fs->blocksize; +u32 inode_size =EXT2_INODE_SIZE (ext2_fs->super); +struct ext2_inode_large *ext2_inode; +struct ext2_ext_attr_entry *entry; +void *data; +char *buffer =NULL ; +char inode_buf[EXT2_GOOD_OLD_INODE_SIZE ]; + +if (inode_size <=EXT2_GOOD_OLD_INODE_SIZE ) { + ext2_inode = (struct ext2_inode_large *)inode_buf; + }else { + ext2_inode = (struct ext2_inode_large *)malloc (inode_size); +if (!ext2_inode) +return -ENOMEM ; + } + err =ext2fs_read_inode_full (ext2_fs, ext2_ino, (void *)ext2_inode, + inode_size); +if (err) { +fprintf (stderr,"ext2fs_read_inode_full: %s\n" , +error_message (err)); + ret =-1 ; + goto out; + } + +if (ext2_ino > ext2_fs->super->s_first_ino && + inode_size >EXT2_GOOD_OLD_INODE_SIZE ) { +if (EXT2_GOOD_OLD_INODE_SIZE + + ext2_inode->i_extra_isize > inode_size) { + ret = -EIO ; + goto out; + } +if (ext2_inode->i_extra_isize !=0 && +EXT2_XATTR_IHDR (ext2_inode)->h_magic == +EXT2_EXT_ATTR_MAGIC ) { + inline_ea =1 ; + } + } +if (inline_ea) { +int total; +void *end = (void *)ext2_inode + inode_size; + entry =EXT2_XATTR_IFIRST (ext2_inode); + total = end - (void *)entry; + ret =ext2_xattr_check_names (entry, end); +if (ret) + goto out; +while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { + ret =ext2_xattr_check_entry (entry, total); +if (ret) + goto out; + data = (void *)EXT2_XATTR_IFIRST (ext2_inode) + + entry->e_value_offs; + datalen = entry->e_value_size; + ret =copy_single_xattr (trans, root, objectid, + entry, data, datalen); +if (ret) + goto out; + entry =EXT2_EXT_ATTR_NEXT (entry); + } + } + +if (ext2_inode->i_file_acl ==0 ) + goto out; + + buffer =malloc (block_size); +if (!buffer) { + ret = -ENOMEM ; + goto out; + } + err =ext2fs_read_ext_attr (ext2_fs, ext2_inode->i_file_acl, buffer); +if (err) { +fprintf (stderr,"ext2fs_read_ext_attr: %s\n" , +error_message (err)); + ret =-1 ; + goto out; + } + ret =ext2_xattr_check_block (buffer, block_size); +if (ret) + goto out; + + entry =EXT2_XATTR_BFIRST (buffer); +while (!EXT2_EXT_IS_LAST_ENTRY (entry)) { + ret =ext2_xattr_check_entry (entry, block_size); +if (ret) + goto out; + data = buffer + entry->e_value_offs; + datalen = entry->e_value_size; + ret =copy_single_xattr (trans, root, objectid, + entry, data, datalen); +if (ret) + goto out; + entry =EXT2_EXT_ATTR_NEXT (entry); + } +out: +if (buffer !=NULL ) +free (buffer); +if ((void *)ext2_inode != inode_buf) +free (ext2_inode); +return ret; +} +#define MINORBITS 20 +#define MKDEV (ma, mi) (((ma) << MINORBITS) | (mi)) + +static inline dev_t old_decode_dev (u16 val) +{ +return MKDEV ((val >>8 ) &255 , val &255 ); +} + +static inline dev_t new_decode_dev (u32 dev) +{ +unsigned major = (dev &0xfff00 ) >>8 ; +unsigned minor = (dev &0xff ) | ((dev >>12 ) &0xfff00 ); +return MKDEV (major, minor); +} + +static int copy_inode_item (struct btrfs_inode_item *dst, +struct ext2_inode *src,u32 blocksize) +{ +btrfs_set_stack_inode_generation (dst,1 ); +btrfs_set_stack_inode_size (dst, src->i_size); +btrfs_set_stack_inode_nbytes (dst,0 ); +btrfs_set_stack_inode_block_group (dst,0 ); +btrfs_set_stack_inode_nlink (dst, src->i_links_count); +btrfs_set_stack_inode_uid (dst, src->i_uid | (src->i_uid_high <<16 )); +btrfs_set_stack_inode_gid (dst, src->i_gid | (src->i_gid_high <<16 )); +btrfs_set_stack_inode_mode (dst, src->i_mode); +btrfs_set_stack_inode_rdev (dst,0 ); +btrfs_set_stack_inode_flags (dst,0 ); +btrfs_set_stack_timespec_sec (&dst->atime, src->i_atime); +btrfs_set_stack_timespec_nsec (&dst->atime,0 ); +btrfs_set_stack_timespec_sec (&dst->ctime, src->i_ctime); +btrfs_set_stack_timespec_nsec (&dst->ctime,0 ); +btrfs_set_stack_timespec_sec (&dst->mtime, src->i_mtime); +btrfs_set_stack_timespec_nsec (&dst->mtime,0 ); +btrfs_set_stack_timespec_sec (&dst->otime,0 ); +btrfs_set_stack_timespec_nsec (&dst->otime,0 ); + +if (S_ISDIR (src->i_mode)) { +btrfs_set_stack_inode_size (dst,0 ); +btrfs_set_stack_inode_nlink (dst,1 ); + } +if (S_ISREG (src->i_mode)) { +btrfs_set_stack_inode_size (dst, (u64 )src->i_size_high <<32 | + (u64 )src->i_size); + } +if (!S_ISREG (src->i_mode) && !S_ISDIR (src->i_mode) && + !S_ISLNK (src->i_mode)) { +if (src->i_block[0 ]) { +btrfs_set_stack_inode_rdev (dst, +old_decode_dev (src->i_block[0 ])); + }else { +btrfs_set_stack_inode_rdev (dst, +new_decode_dev (src->i_block[1 ])); + } + } +return 0 ; +} + +/* +* copy a single inode. do all the required works, such as cloning +* inode item, creating file extents and creating directory entries. +*/ +static int copy_single_inode (struct btrfs_trans_handle *trans, +struct btrfs_root *root,u64 objectid, +ext2_filsys ext2_fs,ext2_ino_t ext2_ino, +struct ext2_inode *ext2_inode, +int datacsum,int packing,int noxattr) +{ +int ret; +struct btrfs_key inode_key; +struct btrfs_inode_item btrfs_inode; + +if (ext2_inode->i_links_count ==0 ) +return 0 ; + +copy_inode_item (&btrfs_inode, ext2_inode, ext2_fs->blocksize); +if (!datacsum &&S_ISREG (ext2_inode->i_mode)) { +u32 flags =btrfs_stack_inode_flags (&btrfs_inode) | +BTRFS_INODE_NODATASUM ; +btrfs_set_stack_inode_flags (&btrfs_inode, flags); + } + +switch (ext2_inode->i_mode &S_IFMT ) { +case S_IFREG : + ret =create_file_extents (trans, root, objectid, &btrfs_inode, + ext2_fs, ext2_ino, datacsum, packing); +break ; +case S_IFDIR : + ret =create_dir_entries (trans, root, objectid, &btrfs_inode, + ext2_fs, ext2_ino); +break ; +case S_IFLNK : + ret =create_symbol_link (trans, root, objectid, &btrfs_inode, + ext2_fs, ext2_ino, ext2_inode); +break ; +default : + ret =0 ; +break ; + } +if (ret) +return ret; + +if (!noxattr) { + ret =copy_extended_attrs (trans, root, objectid, &btrfs_inode, + ext2_fs, ext2_ino); +if (ret) +return ret; + } + inode_key.objectid = objectid; + inode_key.offset =0 ; +btrfs_set_key_type (&inode_key,BTRFS_INODE_ITEM_KEY ); + ret =btrfs_insert_inode (trans, root, objectid, &btrfs_inode); +return ret; +} + +/* +* scan ext2's inode bitmap and copy all used inode. +*/ +static int ext2_copy_inodes (struct convert_fs *fs,struct btrfs_root *root, +int datacsum,int packing,int noxattr) +{ +ext2_filsys ext2_fs = fs->privdata; +int ret; +errcode_t err; +ext2_inode_scan ext2_scan; +struct ext2_inode ext2_inode; +ext2_ino_t ext2_ino; +u64 objectid; +struct btrfs_trans_handle *trans; + + trans =btrfs_start_transaction (root,1 ); +if (!trans) +return -ENOMEM ; + err =ext2fs_open_inode_scan (ext2_fs,0 , &ext2_scan); +if (err) { +fprintf (stderr,"ext2fs_open_inode_scan: %s\n" ,error_message (err)); +return -1 ; + } +while (!(err =ext2fs_get_next_inode (ext2_scan, &ext2_ino, + &ext2_inode))) { +/* no more inodes */ +if (ext2_ino ==0 ) +break ; +/* skip special inode in ext2fs */ +if (ext2_ino <EXT2_GOOD_OLD_FIRST_INO && + ext2_ino !=EXT2_ROOT_INO ) +continue ; + objectid = ext2_ino +INO_OFFSET ; + ret =copy_single_inode (trans, root, + objectid, ext2_fs, ext2_ino, + &ext2_inode, datacsum, packing, + noxattr); +if (ret) +return ret; +if (trans->blocks_used >=4096 ) { + ret =btrfs_commit_transaction (trans, root); +BUG_ON (ret); + trans =btrfs_start_transaction (root,1 ); +BUG_ON (!trans); + } + } +if (err) { +fprintf (stderr,"ext2fs_get_next_inode: %s\n" ,error_message (err)); +return -1 ; + } + ret =btrfs_commit_transaction (trans, root); +BUG_ON (ret); + +return ret; +} + +int ext2_open (struct convert_fs *fs,const char *name) +{ +int ret; +ext2_filsys ext2_fs; + ret =open_ext2fs (name, &ext2_fs); +if (ret) +return ret; + + fs->privdata = ext2_fs; + fs->blocksize = ext2_fs->blocksize; + fs->label = ext2_fs->super->s_volume_name; + fs->total_bytes = ext2_fs->super->s_blocks_count * fs->blocksize; + + fs->cache_free_extents = ext2_cache_free_extents; + fs->close = ext2_close; + fs->copy_inodes = ext2_copy_inodes; + +return 0 ; +}Signature · 6 lines
1.6.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 2 lines · Chris Mason
Thanks for doing all this work. Which filesystems have you currently wired up to the converter?
ReiserFS is almost working; I just need to finish xattr support and clean up the patch. I have somewhat less free time now, so I'm not sure I can work on anything beyond ReiserFS.
I have looked briefly at other filesystems, and I've found that FAT, HFS, and HFS+ have alignment issues (file data isn't aligned to block size), while JFS, XFS, and NTFS do not.