@@ -14,8 +14,12 @@
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
#include <time.h>
#include <string.h>
+#include <assert.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
@@ -120,3 +124,148 @@ errout:
}
+#ifdef HAVE_PTHREAD
+errcode_t ext2fs_clone_fs(ext2_filsys fs, ext2_filsys *dest, unsigned int flags)
+{
+ errcode_t retval;
+ ext2_filsys childfs;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &childfs);
+ if (retval)
+ return retval;
+
+ /* make an exact copy implying lists and memory structures are shared */
+ memcpy(childfs, fs, sizeof(struct struct_ext2_filsys));
+ childfs->inode_map = NULL;
+ childfs->block_map = NULL;
+ childfs->badblocks = NULL;
+ childfs->dblist = NULL;
+
+ pthread_mutex_lock(&fs->refcount_mutex);
+ fs->refcount++;
+ pthread_mutex_unlock(&fs->refcount_mutex);
+
+ if ((flags & EXT2FS_CLONE_INODE) && fs->inode_map) {
+ retval = ext2fs_copy_bitmap(fs->inode_map, &childfs->inode_map);
+ if (retval)
+ return retval;
+ childfs->inode_map->fs = childfs;
+ }
+
+ if ((flags & EXT2FS_CLONE_BLOCK) && fs->block_map) {
+ retval = ext2fs_copy_bitmap(fs->block_map, &childfs->block_map);
+ if (retval)
+ return retval;
+ childfs->block_map->fs = childfs;
+ }
+
+ if ((flags & EXT2FS_CLONE_BADBLOCKS) && fs->badblocks) {
+ retval = ext2fs_badblocks_copy(fs->badblocks, &childfs->badblocks);
+ if (retval)
+ return retval;
+ }
+
+ if ((flags & EXT2FS_CLONE_DBLIST) && fs->dblist) {
+ retval = ext2fs_copy_dblist(fs->dblist, &childfs->dblist);
+ if (retval)
+ return retval;
+ childfs->dblist->fs = childfs;
+ }
+
+ /* icache when NULL will be rebuilt if needed */
+ childfs->icache = NULL;
+
+ childfs->clone_flags = flags;
+ childfs->parent = fs;
+ *dest = childfs;
+
+ return 0;
+}
+
+errcode_t ext2fs_merge_fs(ext2_filsys fs)
+{
+ errcode_t retval = 0;
+ ext2_filsys dest = fs->parent;
+ ext2_filsys src = fs;
+ unsigned int flags = fs->clone_flags;
+
+ pthread_mutex_lock(&fs->refcount_mutex);
+ fs->refcount--;
+ assert(fs->refcount >= 0);
+ pthread_mutex_unlock(&fs->refcount_mutex);
+
+ if ((flags & EXT2FS_CLONE_INODE) && src->inode_map) {
+ if (dest->inode_map == NULL) {
+ dest->inode_map = src->inode_map;
+ src->inode_map = NULL;
+ } else {
+ retval = ext2fs_merge_bitmap(src->inode_map, dest->inode_map, NULL, NULL);
+ if (retval)
+ goto out;
+ }
+ dest->inode_map->fs = dest;
+ }
+
+ if ((flags & EXT2FS_CLONE_BLOCK) && src->block_map) {
+ if (dest->block_map == NULL) {
+ dest->block_map = src->block_map;
+ src->block_map = NULL;
+ } else {
+ retval = ext2fs_merge_bitmap(src->block_map, dest->block_map, NULL, NULL);
+ if (retval)
+ goto out;
+ }
+ dest->block_map->fs = dest;
+ }
+
+ if ((flags & EXT2FS_CLONE_BADBLOCKS) && src->badblocks) {
+ if (dest->badblocks == NULL)
+ retval = ext2fs_badblocks_copy(src->badblocks, &dest->badblocks);
+ else
+ retval = ext2fs_badblocks_merge(src->badblocks, dest->badblocks);
+ if (retval)
+ goto out;
+ }
+
+ if ((flags & EXT2FS_CLONE_DBLIST) && src->dblist) {
+ if (dest->dblist == NULL) {
+ dest->dblist = src->dblist;
+ src->dblist = NULL;
+ } else {
+ retval = ext2fs_merge_dblist(src->dblist, dest->dblist);
+ if (retval)
+ goto out;
+ }
+ dest->dblist->fs = dest;
+ }
+
+ dest->flags |= src->flags;
+ if (!(dest->flags & EXT2_FLAG_VALID))
+ ext2fs_unmark_valid(dest);
+
+ if (src->icache) {
+ ext2fs_free_inode_cache(src->icache);
+ src->icache = NULL;
+ }
+
+out:
+ /* TODO check if io_channel_close is called correctly here? */
+ if (src->io)
+ io_channel_close(src->io);
+
+ if ((flags & EXT2FS_CLONE_INODE) && src->inode_map)
+ ext2fs_free_generic_bmap(src->inode_map);
+ if ((flags & EXT2FS_CLONE_BLOCK) && src->block_map)
+ ext2fs_free_generic_bmap(src->block_map);
+ if ((flags & EXT2FS_CLONE_BADBLOCKS) && src->badblocks)
+ ext2fs_badblocks_list_free(src->badblocks);
+ if ((flags & EXT2FS_CLONE_DBLIST) && src->dblist)
+ ext2fs_free_dblist(src->dblist);
+
+ ext2fs_free_mem(&src);
+
+ return retval;
+}
+#endif
@@ -12,6 +12,10 @@
#ifndef _EXT2FS_EXT2FS_H
#define _EXT2FS_EXT2FS_H
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
#ifdef __GNUC__
#define EXT2FS_ATTR(x) __attribute__(x)
#else
@@ -330,6 +334,14 @@ struct struct_ext2_filsys {
struct ext2fs_hashmap* block_sha_map;
const struct ext2fs_nls_table *encoding;
+
+#ifdef HAVE_PTHREAD
+ struct struct_ext2_filsys *parent;
+ /* TODO do we need refcount? */
+ size_t refcount;
+ pthread_mutex_t refcount_mutex;
+ unsigned int clone_flags;
+#endif
};
#if EXT2_FLAT_INCLUDES
@@ -1056,6 +1068,18 @@ extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
/* check_desc.c */
extern errcode_t ext2fs_check_desc(ext2_filsys fs);
+#ifdef HAVE_PTHREAD
+/* flags for ext2fs_clone_fs */
+#define EXT2FS_CLONE_BLOCK 0x0001
+#define EXT2FS_CLONE_INODE 0x0002
+#define EXT2FS_CLONE_BADBLOCKS 0x0004
+#define EXT2FS_CLONE_DBLIST 0x0008
+
+extern errcode_t ext2fs_clone_fs(ext2_filsys fs, ext2_filsys *dest,
+ unsigned int flags);
+extern errcode_t ext2fs_merge_fs(ext2_filsys fs);
+#endif
+
/* closefs.c */
extern errcode_t ext2fs_close(ext2_filsys fs);
extern errcode_t ext2fs_close2(ext2_filsys fs, int flags);