diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 66 | ||||
-rw-r--r-- | src/clone_data.c | 84 | ||||
-rw-r--r-- | src/clone_ea.c | 70 | ||||
-rw-r--r-- | src/clone_extents.c | 200 | ||||
-rw-r--r-- | src/clone_fs.c | 52 | ||||
-rw-r--r-- | src/clone_inode.c | 59 | ||||
-rw-r--r-- | src/ea_map.c | 79 | ||||
-rw-r--r-- | src/ext_clone.c | 99 | ||||
-rw-r--r-- | src/project.h | 56 | ||||
-rw-r--r-- | src/prototypes.h | 27 | ||||
-rw-r--r-- | src/stats.c | 139 | ||||
-rw-r--r-- | src/zap_fs.c | 52 | ||||
-rw-r--r-- | src/zap_inode.c | 41 |
13 files changed, 1024 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..da2463f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,66 @@ + +CPROTO=cproto +AM_CPPFLAGS = ${LIBE2P_INC} ${LIBEXT2FS_INC} ${LIBCOM_ERR_INC} ${LIBDB_INC} + +HSRCS=project.h prototypes.h + +noinst_HEADERS=${HSRCS} +bin_PROGRAMS = ext_clone + +CSRCS= clone_data.c clone_ea.c clone_extents.c clone_inode.c ea_map.c ext_clone.c stats.c clone_fs.c zap_fs.c zap_inode.c + +ext_clone_SOURCES = ${CSRCS} +ext_clone_LDADD = ${LIBE2P_LIB} ${LIBEXT2FS_LIB} ${LIBCOM_ERR_LIB} ${LIBDB_LIB} -lm + +AM_CFLAGS=-g -Wall + +ext_clone_LDFLAGS = --static + +BUILT_SOURCES = + +src.img: + umount src || true + mkdir -p src + rm -f src.img + truncate -s 128M src.img + mkfs.ext4 -b 4096 -O 64bit -E stride=16,stripe-width=112 src.img + mount src.img src + (cd src && git clone git://git.panaceas.org/tools/sympathy ) + (cd src && truncate -s 8g holey && dd if=/dev/zero of=holey conv=notrunc,nocreat bs=1024k seek=4000 count=1 ) + (cd src && ln holey linky) + (cd src && touch empty) + ls -lZR src + ls -lR src + umount src + rmdir src + + + +protos: + echo > prototypes.h + ${CPROTO} -v ${INCLUDES} ${CSRCS} > prototypes.tmp + mv -f prototypes.tmp prototypes.h + +test: ext_clone src.img + umount dst || true + umount src || true + truncate -s 256M dst.img + mkfs.ext4 -F dst.img -b 4096 -O 64bit -E stride=16,stripe-width=96 + ext_clone -s src.img -d dst.img + e2fsck -f -y dst.img || true + echo "stat <123>" > cmd + debugfs -f cmd src.img > src.txt + debugfs -f cmd dst.img > dst.txt + diff -uN src.txt dst.txt || true + mkdir -p src + mkdir -p dst + mount -o ro src.img src + mount -o ro dst.img dst + rsync -varX -n src/ dst/ + umount dst + umount src + rmdir src + rmdir dst + +tidy: + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} diff --git a/src/clone_data.c b/src/clone_data.c new file mode 100644 index 0000000..3083914 --- /dev/null +++ b/src/clone_data.c @@ -0,0 +1,84 @@ +#include "project.h" + + +int clone_data (ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i, uint64_t offset, uint64_t len) +{ + int ret; + __u64 file_len; + unsigned got, written, fetch; + ext2_file_t src_f = NULL, dst_f = NULL; + + do { + + EXT2_MOAN_FAIL (ret, ext2fs_file_open2 (src_fs, i_num, src_i, 0, &src_f)); + + if (ret) + return -1; + + EXT2_MOAN_FAIL (ret, ext2fs_file_open2 (dst_fs, i_num, dst_i, EXT2_FILE_WRITE, &dst_f)); + + if (ret) + return -1; + + + + if (offset) { + + EXT2_MOAN_FAIL (ret, ext2fs_file_lseek (src_f, offset, SEEK_SET, NULL)); + + if (ret) + return -1; + + EXT2_MOAN_FAIL (ret, ext2fs_file_lseek (dst_f, offset, SEEK_SET, NULL)); + + if (ret) + return -1; + } + + EXT2_MOAN_FAIL (ret, ext2fs_file_get_lsize (src_f, &file_len)); + + if (ret) + break; + + + file_len -= offset; + + + if (len > file_len) + len = file_len; + + while (len) { + + fetch = len > BUF_SZ ? BUF_SZ : len; + + EXT2_MOAN_FAIL (ret, ext2fs_file_read (src_f, buf, fetch, &got)); + + if (ret) + break; + + if (got) { + EXT2_MOAN_FAIL (ret, ext2fs_file_write (dst_f, buf, got, &written)); + + if (ret) + break; + + if (written != got) { + fprintf (stderr, "Not all bytes written in inode %d\n", (int) i_num); + ret = 1; + break; + } + } + + stats_bytes += written; + len -= written; + } + + } while (0); + + ext2fs_file_flush (dst_f); + ext2fs_file_close (dst_f); + ext2fs_file_close (src_f); + return ret; +} + + diff --git a/src/clone_ea.c b/src/clone_ea.c new file mode 100644 index 0000000..d8287b7 --- /dev/null +++ b/src/clone_ea.c @@ -0,0 +1,70 @@ +#include "project.h" + +int clone_ea (ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i) +{ + int ret; + blk64_t src_blk = src_i->i_file_acl; + blk64_t goal, dst_blk, len; + dgrp_t group; + + struct ext2_ext_attr_header *h; + + if (!src_blk) return 0; + + if (!ea_map_lookup (src_blk, &dst_blk, &len)) { + /* Easy case */ + + EXT2_MOAN_FAIL (ret, ext2fs_adjust_ea_refcount2 (dst_fs, dst_blk, buf, +1, NULL)); + + if (ret) return ret; + + dst_i->i_file_acl = dst_blk; + dst_i->i_blocks += len * (dst_fs->blocksize / 512); + return 0; + } + + EXT2_MOAN_FAIL (ret, io_channel_read_blk64 (src_fs->io, src_blk, 1, buf)); + + if (ret) return ret; + + h = (struct ext2_ext_attr_header *) buf; + len = h->h_blocks; + + if (len > 1) { + EXT2_MOAN_FAIL (ret, io_channel_read_blk64 (src_fs->io, src_blk + 1, len - 1, buf + src_fs->blocksize)); + + if (ret) return ret; + } + + h->h_refcount = 0; + + group = ext2fs_group_of_ino (dst_fs, i_num); + goal = ext2fs_group_first_block2 (dst_fs, group); + + EXT2_MOAN_FAIL (ret, ext2fs_alloc_range (dst_fs, 0, goal, len, &dst_blk)); + + if (ret) return ret; + + //printf ("EA block %d mapped to block %d len %d\n", (int)src_blk, (int) dst_blk, (int)len); + stats_ea_blocks++; + + if (ea_map_set (src_blk, dst_blk, len)) + return -1; + + + EXT2_MOAN_FAIL (ret, io_channel_write_blk64 (dst_fs->io, dst_blk, len, buf)); + + if (ret) return ret; + + dst_i->i_file_acl = dst_blk & 0xffffffff; + dst_i->osd2.linux2.l_i_file_acl_high= dst_blk >> 32; + dst_i->i_blocks += len * (dst_fs->blocksize / 512); + EXT2_MOAN_FAIL (ret, ext2fs_adjust_ea_refcount2 (dst_fs, dst_blk, buf, +1, NULL)); + + if (ret) return ret; + + + return 0; +} + + diff --git a/src/clone_extents.c b/src/clone_extents.c new file mode 100644 index 0000000..09c639b --- /dev/null +++ b/src/clone_extents.c @@ -0,0 +1,200 @@ +#include "project.h" + + +static int allocate_extent (ext2_filsys fs, ext2_ino_t i_num, ext2_extent_handle_t eh, blk64_t l_start, blk64_t len, __u32 flags) +{ + blk64_t goal, start, size, want,max; + dgrp_t group; + int ret; + struct ext2fs_extent e; + + group = ext2fs_group_of_ino (fs, i_num); + goal = ext2fs_group_first_block2 (fs, group); + + + max = (flags & EXT2_EXTENT_FLAGS_UNINIT) ? EXT_UNINIT_MAX_LEN:EXT_INIT_MAX_LEN; + + ret = 0; + + while (len) { + + want = (len > max) ? max : len; + + EXT2_MOAN_FAIL (ret, ext2fs_new_range (fs, 0, goal, want, + fs->block_map, &start, &size)); + + if (ret) + break; + + if (size > want) size = want; + + ext2fs_block_alloc_stats_range (fs, start, size, +1); + + + e.e_pblk = start; + e.e_lblk = l_start; + e.e_len = size; + e.e_flags = flags; + + + EXT2_MOAN_FAIL (ret, ext2fs_extent_insert (eh, EXT2_EXTENT_INSERT_AFTER, &e)); + + if (ret) { + + fprintf(stderr,"Failed extent was:\n"); + fprintf(stderr," e.e_pblk = %lld\n",(long long int) e.e_pblk); + fprintf(stderr," e.e_lblk = %lld\n",(long long int) e.e_lblk); + fprintf(stderr," e.e_len = %lld\n",(long long int) e.e_len); + fprintf(stderr," e.e_flags = 0x%llx\n",(long long int) e.e_flags); + break; + } + + len -= size; + + } + + return ret; +} + + +int clone_extents (ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i) +{ + ext2_extent_handle_t src_e = NULL, dst_e = NULL; + // struct ext2_extent_info info; + struct ext2fs_extent e; + int ret; + blk64_t l_start = 0; + blk64_t l_len = 0; + __u32 flags; + + + do { + EXT2_MOAN_FAIL (ret, ext2fs_extent_open2 (src_fs, i_num, src_i, &src_e)); + + if (ret) + break; + + + EXT2_MOAN_FAIL (ret, ext2fs_extent_open2 (dst_fs, i_num, dst_i, &dst_e)); + + if (ret) + break; + + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (dst_fs, i_num, dst_i)); + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e)"); + break; + } + + + + for (;;) { + + if (e.e_flags & EXT2_EXTENT_FLAGS_LEAF) { + + if (!l_len) + flags = e.e_flags; + + if (((l_start + l_len) != e.e_lblk) || (flags != e.e_flags) ) { + ret = allocate_extent (dst_fs, i_num, dst_e, l_start, l_len, flags); + + if (ret) break; + + dst_i->i_blocks += l_len * (dst_fs->blocksize / 512); + + l_start = e.e_lblk; + l_len = e.e_len; + flags = e.e_flags; + } else + l_len += e.e_len; + + } + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + ret = 0; + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e)"); + break; + } + } + + if (l_len) + ret = allocate_extent (dst_fs, i_num, dst_e, l_start, l_len, flags); + + if (ret) break; + + dst_i->i_blocks += l_len * (dst_fs->blocksize / 512); + + if (dst_e) + ext2fs_extent_free (dst_e); + + dst_e = NULL; + + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (dst_fs, i_num, dst_i)); + + if (ret) + break; + + EXT2_MOAN_FAIL (ret, ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e)); + + if (ret) + break; + + + for (;;) { + uint64_t file_offset, file_len; + + + if ((e.e_flags & EXT2_EXTENT_FLAGS_LEAF) && ! (e.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { + + file_offset = e.e_lblk; + file_len = e.e_len; + + file_offset *= src_fs->blocksize; + file_len *= src_fs->blocksize; + + if (clone_data (src_fs, dst_fs, i_num, src_i, dst_i, file_offset, file_len)) { + ret = 1; + break; + } + } + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + ret = 0; + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e)"); + break; + } + } + + } while (0); + + if (dst_e) + ext2fs_extent_free (dst_e); + + if (src_e) + ext2fs_extent_free (src_e); + + + return ret; +} + + + diff --git a/src/clone_fs.c b/src/clone_fs.c new file mode 100644 index 0000000..1269b30 --- /dev/null +++ b/src/clone_fs.c @@ -0,0 +1,52 @@ +#include "project.h" + + +int clone_fs (ext2_filsys src_fs, ext2_filsys dst_fs) +{ + int skip; + int ret; + ext2_inode_scan scan; + ext2_ino_t i_num; + struct ext2_inode src_i; + + EXT2_MOAN_FAIL (ret, ext2fs_open_inode_scan (src_fs, 0, &scan)); + + if (ret) return -1; + + for (;;) { + EXT2_MOAN_FAIL (ret, ext2fs_get_next_inode (scan, &i_num, &src_i)); + + if (ret) break; + + if (!i_num) break; + + skip = 0; + + switch (i_num) { + case EXT2_BAD_INO: + case EXT4_USR_QUOTA_INO: + case EXT4_GRP_QUOTA_INO: + case EXT2_BOOT_LOADER_INO: + case EXT2_UNDEL_DIR_INO: + case EXT2_RESIZE_INO: + case EXT2_EXCLUDE_INO: + case EXT4_REPLICA_INO: + skip = 1; + } + + if (i_num == src_fs->super->s_journal_inum) skip = 1; + + if (skip) continue; + + if (clone_inode (src_fs, dst_fs, i_num, &src_i)) { + fprintf (stderr, "clone_inode(%d) failed\n", (int) i_num); + break; + } + } + + ext2fs_close_inode_scan (scan); + return 0; +} + + + diff --git a/src/clone_inode.c b/src/clone_inode.c new file mode 100644 index 0000000..33d4647 --- /dev/null +++ b/src/clone_inode.c @@ -0,0 +1,59 @@ +#include "project.h" + +int clone_inode (ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i) +{ + struct ext2_inode dst_i; + int ret; + + // printf ("cloning inode %d\n", (int) i_num); + + EXT2_MOAN_FAIL (ret, ext2fs_read_inode (dst_fs, i_num, &dst_i)); + + + memcpy (&dst_i, src_i, sizeof (*src_i)); + + dst_i.i_blocks = 0; + memset (&dst_i.i_block, 0, sizeof (dst_i.i_block)); + dst_i.i_file_acl = 0; + + dst_i.osd2.linux2.l_i_blocks_hi = 0; + dst_i.osd2.linux2.l_i_file_acl_high = 0; + + if (src_i->i_file_acl) + if (clone_ea (src_fs, dst_fs, i_num, src_i, &dst_i)) + return -1; + + if (src_i->i_flags & EXT4_EXTENTS_FL) { + if (clone_extents (src_fs, dst_fs, i_num, src_i, &dst_i)) { + fprintf (stderr, "Cloning extents for inode %d failed\n", (int) i_num); + return -1; + } + + } else { + + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (dst_fs, i_num, &dst_i)); + + if (clone_data (src_fs, dst_fs, i_num, src_i, &dst_i, 0, 0)) { + fprintf (stderr, "Cloning data for inode %d failed\n", (int) i_num); + return -1; + } + } + + if (ret) + return -1; + + if (dst_i.i_mode & LINUX_S_IFDIR) + ext2fs_inode_alloc_stats2 (dst_fs, i_num, +1, +1); + else + ext2fs_inode_alloc_stats2 (dst_fs, i_num, +1, 0); + + if (ret) + return -1; + + stats_inodes++; + stats (0); + + return 0; +} + + diff --git a/src/ea_map.c b/src/ea_map.c new file mode 100644 index 0000000..e8d103e --- /dev/null +++ b/src/ea_map.c @@ -0,0 +1,79 @@ +#include "project.h" +#include <db.h> + +static DB *ea_map_db = NULL; + +static int ea_map_init (void) +{ + int ret; + + ret = db_create (&ea_map_db, NULL, 0); + + if (ret) { + ea_map_db = NULL; + return -1; + } + + ret = ea_map_db->open (ea_map_db, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0x600); + + if (ret) { + ea_map_db->err (ea_map_db, ret, "ea_map_db"); + ea_map_db->close (ea_map_db, 0); + ea_map_db = NULL; + return -1; + } + + return 0; +} + +int ea_map_lookup (blk64_t src_blk, blk64_t *dst_blk, blk64_t *len) +{ + DBT key = {0}, data = {0}; + blk64_t *buf; + + if (!ea_map_db) + return -1; + + key.size = sizeof (src_blk); + key.data = &src_blk; + + if (ea_map_db->get (ea_map_db, NULL, &key, &data, 0)) + return -1; + + if (data.size != (2 * sizeof (blk64_t))) + return -1; + + buf = (blk64_t *) data.data; + + *dst_blk = buf[0]; + *len = buf[1]; + + return 0; +} + + +int ea_map_set (blk64_t src_blk, blk64_t dst_blk, blk64_t len) +{ + DBT key = {0}, data = {0}; + blk64_t buf[2] = {dst_blk, len}; + int ret; + + if (!ea_map_db) + if (ea_map_init()) + return -1; + + + key.size = sizeof (src_blk); + key.data = &src_blk; + data.size = 2 * sizeof (dst_blk); + data.data = buf; + + ret = ea_map_db->put (ea_map_db, NULL, &key, &data, 0); + + if (ret) + ea_map_db->err (ea_map_db, ret, "DB->put"); + + return ret; +} + + diff --git a/src/ext_clone.c b/src/ext_clone.c new file mode 100644 index 0000000..1899455 --- /dev/null +++ b/src/ext_clone.c @@ -0,0 +1,99 @@ +#include "project.h" + +static void +usage (void) +{ + fprintf (stderr, "ext_clone -s src_dev -d dest_dev\n"); + exit (1); +} + + +char buf[BUF_SZ]; + + + +int main (int argc, char *argv[]) +{ + int ret; + ext2_filsys src_fs = NULL; + ext2_filsys dst_fs = NULL; + char *src_dev = NULL; + char *dst_dev = NULL; + + int opt; + + while ((opt = getopt (argc, argv, "d:s:")) != -1) { + switch (opt) { + case 'd': + dst_dev = optarg; + break; + + case 's': + src_dev = optarg; + break; + + default: + usage(); + } + } + + if ((!src_dev) || (!dst_dev)) usage(); + + do { + EXT2_MOAN_FAIL (ret, ext2fs_open (src_dev, EXT2_FLAG_64BITS, 0, 0, unix_io_manager, &src_fs)); + + if (ret) + break; + + EXT2_MOAN_FAIL (ret, ext2fs_open (dst_dev, EXT2_FLAG_64BITS | EXT2_FLAG_RW, 0, 0, unix_io_manager, &dst_fs)); + + if (ret) + break; + + + /*make the hash seed the same */ + + memcpy (dst_fs->super->s_hash_seed, src_fs->super->s_hash_seed, sizeof (src_fs->super->s_hash_seed)); + dst_fs->super->s_def_hash_version = src_fs->super->s_def_hash_version; + + ext2fs_mark_super_dirty (dst_fs); + + + + + EXT2_MOAN_FAIL (ret, ext2fs_read_inode_bitmap (dst_fs)); + + if (ret) + break; + + EXT2_MOAN_FAIL (ret, ext2fs_read_block_bitmap (dst_fs)); + + if (ret) + break; + + ret = zap_fs (dst_fs); + + if (ret) + break; + + + ret = clone_fs (src_fs, dst_fs); + + } while (0); + + + + if (dst_fs) + ext2fs_close (dst_fs); + + if (src_fs) + ext2fs_close (src_fs); + + stats (1); + + return ret; +} + + + + diff --git a/src/project.h b/src/project.h new file mode 100644 index 0000000..da07ded --- /dev/null +++ b/src/project.h @@ -0,0 +1,56 @@ +#include "config.h" + +#include <math.h> + +#include <sys/time.h> +#include <time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> + +#include <malloc.h> + +#include <string.h> +#include <strings.h> + +#include <unistd.h> + +#include <stdint.h> + + +#include <sys/types.h> + +#include <fcntl.h> +#include <sys/stat.h> +#include <attr/xattr.h> +#include <errno.h> + + +#include <ext2fs/ext2fs.h> +#include <e2p/e2p.h> + +#define BUF_SZ (16*1024*1024) + +#define EXT2_DO_MOAN(v,wot,file,function,line) \ + if (v) { \ + fprintf (stderr, "%s:%s:%d %s failed %d(%s)\n", file,function, line, wot, (v) ,error_message(v)); \ + } + + +#define EXT2_MOAN(v,wot) \ + do { \ + EXT2_DO_MOAN(v,wot,__FILE__,__FUNCTION__,__LINE__) \ + } while (0) + + +#define EXT2_MOAN_FAIL(v,wot) \ + do { \ + (v)= wot; \ + EXT2_DO_MOAN(v,#wot,__FILE__,__FUNCTION__,__LINE__) \ + } while (0) + + + +#include "prototypes.h" + diff --git a/src/prototypes.h b/src/prototypes.h new file mode 100644 index 0000000..3ac93b7 --- /dev/null +++ b/src/prototypes.h @@ -0,0 +1,27 @@ +/* clone_data.c */ +int clone_data(ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i, uint64_t offset, uint64_t len); +/* clone_ea.c */ +int clone_ea(ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i); +/* clone_extents.c */ +int clone_extents(ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i); +/* clone_inode.c */ +int clone_inode(ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i); +/* ea_map.c */ +int ea_map_lookup(blk64_t src_blk, blk64_t *dst_blk, blk64_t *len); +int ea_map_set(blk64_t src_blk, blk64_t dst_blk, blk64_t len); +/* ext_clone.c */ +char buf[(16*1024*1024)]; +int main(int argc, char *argv[]); +/* stats.c */ +uint64_t stats_inodes; +uint64_t stats_ea_blocks; +uint64_t stats_bytes; +struct timeval start_time; +struct timeval last_time; +void stats(int force); +/* clone_fs.c */ +int clone_fs(ext2_filsys src_fs, ext2_filsys dst_fs); +/* zap_fs.c */ +int zap_fs(ext2_filsys fs); +/* zap_inode.c */ +int zap_inode(ext2_filsys fs, ext2_ino_t i_num, struct ext2_inode *i); diff --git a/src/stats.c b/src/stats.c new file mode 100644 index 0000000..1fb7c03 --- /dev/null +++ b/src/stats.c @@ -0,0 +1,139 @@ +#include "project.h" + +uint64_t stats_inodes; +uint64_t stats_ea_blocks; +uint64_t stats_bytes; +static uint64_t last_bytes; + + +struct timeval start_time, last_time; + +static int first = 1; + + + +static int do_time (char *ptr, double t) +{ + double h, m, s; + + if (t < 60.0) + return sprintf (ptr, "%.1fs", t); + + if (t < 3600.0) { + m = floor (t / 60.0); + t -= 60 * m; + s = floor (t); + t -= s; + t *= 10; + return sprintf (ptr, "%d:%02d.%dm", (int) m, (int) s, (int) t); + } + + h = floor (t / 3600.0); + t -= 3600 * h; + m = floor (t / 60.0); + t -= 60 * m; + s = floor (t); + t -= s; + t *= 10; + return sprintf (ptr, "%d:%02d:%02d.%dh", (int) h, (int) m, (int) s, + (int) t); +} + +static int do_rate (char *ptr, double r) +{ + if (r < 1024.0) + return sprintf (ptr, "%.1f b", r); + + if (r < 1048576.0) + return sprintf (ptr, "%.1f K", r / 1024.0); + + if (r < 1073741824.0) + return sprintf (ptr, "%.1f M", r / 1048576.0); + + return sprintf (ptr, "%.1f G", r / 1073741824.0); +} + + +void stats (int force) +{ + struct timeval now, diff1, diff2; + char charbuf[128], *ptr = charbuf; + double totaltime, totalbytes, intertime, interbytes; + + gettimeofday (&now, NULL); + + + if (first) { + first = 0; + last_time = now; + start_time = now; + return; + } + + + timersub (&now, &last_time, &diff1); + + if ((!force) && (diff1.tv_sec < 10)) + return; + + timersub (&now, &start_time, &diff2); + + intertime = (double) diff1.tv_usec; + intertime /= 1000000.0; + intertime += (double) diff1.tv_sec; + + totaltime = (double) diff2.tv_usec; + totaltime /= 1000000.0; + totaltime += (double) diff2.tv_sec; + + totalbytes = (double) stats_bytes; + interbytes = stats_bytes - (double) last_bytes; + + last_bytes = stats_bytes; + last_time = now; + + intertime += 0.001; + totaltime += 0.001; + + ptr += do_time (ptr, totaltime); + ptr += sprintf (ptr, " rate:"); + ptr += do_rate (ptr, interbytes / intertime); + ptr += sprintf (ptr, "/"); + ptr += do_rate (ptr, totalbytes / totaltime); + ptr += sprintf (ptr, " bytes:"); + ptr += do_rate (ptr, totalbytes); + ptr += sprintf (ptr, " inodes %lld ea_blocks %lld\n", + (long long int) stats_inodes, (long long int) stats_ea_blocks); + fputs (charbuf, stderr); + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/zap_fs.c b/src/zap_fs.c new file mode 100644 index 0000000..0cfd7ac --- /dev/null +++ b/src/zap_fs.c @@ -0,0 +1,52 @@ +#include "project.h" + + +int zap_fs (ext2_filsys fs) +{ + int skip; + int ret; + ext2_inode_scan scan; + ext2_ino_t i_num; + struct ext2_inode i; + + EXT2_MOAN_FAIL (ret, ext2fs_open_inode_scan (fs, 0, &scan)); + + if (ret) return -1; + + for (;;) { + EXT2_MOAN_FAIL (ret, ext2fs_get_next_inode (scan, &i_num, &i)); + + if (ret) break; + + if (!i_num) break; + + skip = 0; + + switch (i_num) { + case EXT2_BAD_INO: + case EXT4_USR_QUOTA_INO: + case EXT4_GRP_QUOTA_INO: + case EXT2_BOOT_LOADER_INO: + case EXT2_UNDEL_DIR_INO: + case EXT2_RESIZE_INO: + case EXT2_EXCLUDE_INO: + case EXT4_REPLICA_INO: + skip = 1; + } + + if (i_num == fs->super->s_journal_inum) skip = 1; + + if (skip) continue; + + if (zap_inode (fs, i_num, &i)) { + fprintf (stderr, "zap_inode(%d) failed\n", (int) i_num); + break; + } + } + + ext2fs_close_inode_scan (scan); + return 0; +} + + + diff --git a/src/zap_inode.c b/src/zap_inode.c new file mode 100644 index 0000000..f40a16b --- /dev/null +++ b/src/zap_inode.c @@ -0,0 +1,41 @@ +#include "project.h" + +static int clear_blocks (ext2_filsys fs, blk_t *b_num, + e2_blkcnt_t blockcnt, + blk_t ref_block, + int ref_offset, + void *priv_data) +{ + ext2fs_block_alloc_stats2 (fs, *b_num, -1); + + *b_num = 0; + return BLOCK_CHANGED; +} + + + + +int zap_inode (ext2_filsys fs, ext2_ino_t i_num, struct ext2_inode *i) +{ + int ret; + + printf ("clearing already used inode %d\n", (int) i_num); + + EXT2_MOAN_FAIL (ret, ext2fs_block_iterate2 (fs, i_num, BLOCK_FLAG_DEPTH_TRAVERSE, 0, clear_blocks, NULL)); + + if (ret) return -1; + + if (i->i_mode & LINUX_S_IFDIR) + ext2fs_inode_alloc_stats2 (fs, i_num, -1, -1); + else + ext2fs_inode_alloc_stats2 (fs, i_num, -1, 0); + + memset (i, 0, sizeof (*i)); + + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (fs, i_num, i)); + + return ret; +} + + + |