Whamcloud - gitweb
Merge branch 'ry/mke2fs-populate' into next
authorTheodore Ts'o <tytso@mit.edu>
Thu, 6 Mar 2014 16:22:42 +0000 (11:22 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 6 Mar 2014 16:22:42 +0000 (11:22 -0500)
Conflicts:
debugfs/debugfs.c

debugfs/Makefile.in
debugfs/debugfs.c
debugfs/debugfs.h
misc/Makefile.in
misc/create_inode.c [new file with mode: 0644]
misc/create_inode.h [new file with mode: 0644]
misc/mke2fs.8.in
misc/mke2fs.c

index 5ddeab7..a82a53b 100644 (file)
@@ -18,7 +18,7 @@ MK_CMDS=      _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
 
 DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
        lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
-       filefrag.o extent_cmds.o extent_inode.o zap.o
+       filefrag.o extent_cmds.o extent_inode.o zap.o create_inode.o
 
 RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
        lsdel.o logdump.o htree.o e2freefrag.o filefrag.o extent_cmds.o \
@@ -28,7 +28,13 @@ SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
        $(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
        $(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
        $(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
-       $(srcdir)/filefrag.c $(srcdir)/extent_inode.c $(srcdir)/zap.c
+       $(srcdir)/filefrag.c $(srcdir)/extent_inode.c $(srcdir)/zap.c \
+       $(srcdir)/../misc/create_inode.c
+
+CREATE_INODE_DEPS= $(srcdir)/../misc/create_inode.h \
+       $(srcdir)/../misc/create_inode.c $(top_builddir)/lib/config.h \
+       $(srcdir)/../lib/ext2fs/ext2fs.h $(srcdir)/../lib/et/com_err.h \
+       $(srcdir)/../lib/e2p/e2p.h $(srcdir)/../misc/nls-enable.h
 
 LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
        $(LIBUUID) $(SYSLIBS)
@@ -81,6 +87,11 @@ e2freefrag.o: $(srcdir)/../misc/e2freefrag.c
        $(E) "  CC $@"
        $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -DDEBUGFS -o $@
 
+create_inode.o: $(CREATE_INODE_DEPS)
+       $(E) "  CC $@"
+       $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \
+                $(srcdir)/../misc/create_inode.c -DDEBUGFS -o $@
+
 debugfs.8: $(DEP_SUBSTITUTE) $(srcdir)/debugfs.8.in
        $(E) "  SUBST $@"
        $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/debugfs.8.in debugfs.8
@@ -142,7 +153,7 @@ debugfs.o: $(srcdir)/debugfs.c $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/jfs_user.h \
  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
- $(top_srcdir)/lib/ext2fs/kernel-list.h
+ $(top_srcdir)/lib/ext2fs/kernel-list.h $(top_srcdir)/misc/util.h
 util.o: $(srcdir)/util.c $(srcdir)/debugfs.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
index 4377b16..5554017 100644 (file)
@@ -25,8 +25,6 @@ extern char *optarg;
 #include <errno.h>
 #endif
 #include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 
 #include "debugfs.h"
 #include "uuid/uuid.h"
@@ -41,22 +39,11 @@ extern char *optarg;
 #define BUFSIZ 8192
 #endif
 
-/* 64KiB is the minimium blksize to best minimize system call overhead. */
-#ifndef IO_BUFSIZE
-#define IO_BUFSIZE 64*1024
-#endif
-
-/* Block size for `st_blocks' */
-#ifndef S_BLKSIZE
-#define S_BLKSIZE 512
-#endif
-
 ss_request_table *extra_cmds;
 const char *debug_prog_name;
 int sci_idx;
 
-ext2_filsys    current_fs = NULL;
-ext2_ino_t     root, cwd;
+ext2_ino_t     cwd;
 
 static void open_filesystem(char *device, int open_flags, blk64_t superblock,
                            blk64_t blocksize, int catastrophic,
@@ -1611,196 +1598,24 @@ void do_find_free_inode(int argc, char *argv[])
 }
 
 #ifndef READ_ONLY
-static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
-{
-       ext2_file_t     e2_file;
-       errcode_t       retval;
-       int             got;
-       unsigned int    written;
-       char            *buf;
-       char            *ptr;
-       char            *zero_buf;
-       int             cmp;
-
-       retval = ext2fs_file_open(current_fs, newfile,
-                                 EXT2_FILE_WRITE, &e2_file);
-       if (retval)
-               return retval;
-
-       retval = ext2fs_get_mem(bufsize, &buf);
-       if (retval) {
-               com_err("copy_file", retval, "can't allocate buffer\n");
-               return retval;
-       }
-
-       /* This is used for checking whether the whole block is zero */
-       retval = ext2fs_get_memzero(bufsize, &zero_buf);
-       if (retval) {
-               com_err("copy_file", retval, "can't allocate buffer\n");
-               ext2fs_free_mem(&buf);
-               return retval;
-       }
-
-       while (1) {
-               got = read(fd, buf, bufsize);
-               if (got == 0)
-                       break;
-               if (got < 0) {
-                       retval = errno;
-                       goto fail;
-               }
-               ptr = buf;
-
-               /* Sparse copy */
-               if (make_holes) {
-                       /* Check whether all is zero */
-                       cmp = memcmp(ptr, zero_buf, got);
-                       if (cmp == 0) {
-                                /* The whole block is zero, make a hole */
-                               retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
-                               if (retval)
-                                       goto fail;
-                               got = 0;
-                       }
-               }
-
-               /* Normal copy */
-               while (got > 0) {
-                       retval = ext2fs_file_write(e2_file, ptr,
-                                                  got, &written);
-                       if (retval)
-                               goto fail;
-
-                       got -= written;
-                       ptr += written;
-               }
-       }
-       ext2fs_free_mem(&buf);
-       ext2fs_free_mem(&zero_buf);
-       retval = ext2fs_file_close(e2_file);
-       return retval;
-
-fail:
-       ext2fs_free_mem(&buf);
-       ext2fs_free_mem(&zero_buf);
-       (void) ext2fs_file_close(e2_file);
-       return retval;
-}
-
 void do_write(int argc, char *argv[])
 {
-       int             fd;
-       struct stat     statbuf;
-       ext2_ino_t      newfile;
        errcode_t       retval;
-       struct ext2_inode inode;
-       int             bufsize = IO_BUFSIZE;
-       int             make_holes = 0;
 
        if (common_args_process(argc, argv, 3, 3, "write",
                                "<native file> <new file>", CHECK_FS_RW))
                return;
 
-       fd = open(argv[1], O_RDONLY);
-       if (fd < 0) {
-               com_err(argv[1], errno, 0);
-               return;
-       }
-       if (fstat(fd, &statbuf) < 0) {
-               com_err(argv[1], errno, 0);
-               close(fd);
-               return;
-       }
-
-       retval = ext2fs_namei(current_fs, root, cwd, argv[2], &newfile);
-       if (retval == 0) {
-               com_err(argv[0], 0, "The file '%s' already exists\n", argv[2]);
-               close(fd);
-               return;
-       }
-
-       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
-       if (retval) {
+       if ((retval = do_write_internal(cwd, argv[1], argv[2])))
                com_err(argv[0], retval, 0);
-               close(fd);
-               return;
-       }
-       printf("Allocated inode: %u\n", newfile);
-       retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
-                            EXT2_FT_REG_FILE);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, cwd);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       close(fd);
-                       return;
-               }
-               retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
-                                    EXT2_FT_REG_FILE);
-       }
-       if (retval) {
-               com_err(argv[2], retval, 0);
-               close(fd);
-               return;
-       }
-        if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
-               com_err(argv[0], 0, "Warning: inode already set");
-       ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
-       memset(&inode, 0, sizeof(inode));
-       inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
-       inode.i_atime = inode.i_ctime = inode.i_mtime =
-               current_fs->now ? current_fs->now : time(0);
-       inode.i_links_count = 1;
-       inode.i_size = statbuf.st_size;
-       if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
-                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
-               inode.i_flags |= EXT4_INLINE_DATA_FL;
-       } else if (current_fs->super->s_feature_incompat &
-                  EXT3_FEATURE_INCOMPAT_EXTENTS) {
-               int i;
-               struct ext3_extent_header *eh;
-
-               eh = (struct ext3_extent_header *) &inode.i_block[0];
-               eh->eh_depth = 0;
-               eh->eh_entries = 0;
-               eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
-               i = (sizeof(inode.i_block) - sizeof(*eh)) /
-                       sizeof(struct ext3_extent);
-               eh->eh_max = ext2fs_cpu_to_le16(i);
-               inode.i_flags |= EXT4_EXTENTS_FL;
-       }
-       if (debugfs_write_new_inode(newfile, &inode, argv[0])) {
-               close(fd);
-               return;
-       }
-       if (inode.i_flags & EXT4_INLINE_DATA_FL) {
-               retval = ext2fs_inline_data_init(current_fs, newfile);
-               if (retval)
-                       return;
-       }
-       if (LINUX_S_ISREG(inode.i_mode)) {
-               if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
-                       make_holes = 1;
-                       /*
-                        * Use I/O blocksize as buffer size when
-                        * copying sparse files.
-                        */
-                       bufsize = statbuf.st_blksize;
-               }
-               retval = copy_file(fd, newfile, bufsize, make_holes);
-               if (retval)
-                       com_err("copy_file", retval, 0);
-       }
-       close(fd);
 }
 
 void do_mknod(int argc, char *argv[])
 {
        unsigned long   mode, major, minor;
-       ext2_ino_t      newfile;
        errcode_t       retval;
-       struct ext2_inode inode;
        int             filetype, nr;
+       struct stat     st;
 
        if (check_fs_open(argv[0]))
                return;
@@ -1809,115 +1624,50 @@ void do_mknod(int argc, char *argv[])
                com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
                return;
        }
+
        mode = minor = major = 0;
        switch (argv[2][0]) {
                case 'p':
-                       mode = LINUX_S_IFIFO;
-                       filetype = EXT2_FT_FIFO;
+                       st.st_mode = S_IFIFO;
                        nr = 3;
                        break;
                case 'c':
-                       mode = LINUX_S_IFCHR;
-                       filetype = EXT2_FT_CHRDEV;
+                       st.st_mode = S_IFCHR;
                        nr = 5;
                        break;
                case 'b':
-                       mode = LINUX_S_IFBLK;
-                       filetype = EXT2_FT_BLKDEV;
+                       st.st_mode = S_IFBLK;
                        nr = 5;
                        break;
                default:
-                       filetype = 0;
                        nr = 0;
        }
+
        if (nr == 5) {
                major = strtoul(argv[3], argv+3, 0);
                minor = strtoul(argv[4], argv+4, 0);
                if (major > 65535 || minor > 65535 || argv[3][0] || argv[4][0])
                        nr = 0;
        }
+
        if (argc != nr)
                goto usage;
-       if (check_fs_read_write(argv[0]))
-               return;
-       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
-       if (retval) {
+
+       st.st_rdev = makedev(major, minor);
+       if ((retval = do_mknod_internal(cwd, argv[1], &st)))
                com_err(argv[0], retval, 0);
-               return;
-       }
-       printf("Allocated inode: %u\n", newfile);
-       retval = ext2fs_link(current_fs, cwd, argv[1], newfile, filetype);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, cwd);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               retval = ext2fs_link(current_fs, cwd, argv[1], newfile,
-                                    filetype);
-       }
-       if (retval) {
-               com_err(argv[1], retval, 0);
-               return;
-       }
-        if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
-               com_err(argv[0], 0, "Warning: inode already set");
-       ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
-       memset(&inode, 0, sizeof(inode));
-       inode.i_mode = mode;
-       inode.i_atime = inode.i_ctime = inode.i_mtime =
-               current_fs->now ? current_fs->now : time(0);
-       if ((major < 256) && (minor < 256)) {
-               inode.i_block[0] = major*256+minor;
-               inode.i_block[1] = 0;
-       } else {
-               inode.i_block[0] = 0;
-               inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
-       }
-       inode.i_links_count = 1;
-       if (debugfs_write_new_inode(newfile, &inode, argv[0]))
-               return;
 }
 
 void do_mkdir(int argc, char *argv[])
 {
-       char    *cp;
-       ext2_ino_t      parent;
-       char    *name;
        errcode_t retval;
 
        if (common_args_process(argc, argv, 2, 2, "mkdir",
                                "<filename>", CHECK_FS_RW))
                return;
 
-       cp = strrchr(argv[1], '/');
-       if (cp) {
-               *cp = 0;
-               parent = string_to_inode(argv[1]);
-               if (!parent) {
-                       com_err(argv[1], ENOENT, 0);
-                       return;
-               }
-               name = cp+1;
-       } else {
-               parent = cwd;
-               name = argv[1];
-       }
-
-try_again:
-       retval = ext2fs_mkdir(current_fs, parent, 0, name);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, parent);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               goto try_again;
-       }
-       if (retval) {
-               com_err("ext2fs_mkdir", retval, 0);
-               return;
-       }
+       if ((retval = do_mkdir_internal(cwd, argv[1], NULL)))
+               com_err(argv[0], retval, 0);
 
 }
 
@@ -2311,44 +2061,14 @@ void do_punch(int argc, char *argv[])
 
 void do_symlink(int argc, char *argv[])
 {
-       char            *cp;
-       ext2_ino_t      parent;
-       char            *name, *target;
        errcode_t       retval;
 
        if (common_args_process(argc, argv, 3, 3, "symlink",
                                "<filename> <target>", CHECK_FS_RW))
                return;
 
-       cp = strrchr(argv[1], '/');
-       if (cp) {
-               *cp = 0;
-               parent = string_to_inode(argv[1]);
-               if (!parent) {
-                       com_err(argv[1], ENOENT, 0);
-                       return;
-               }
-               name = cp+1;
-       } else {
-               parent = cwd;
-               name = argv[1];
-       }
-       target = argv[2];
-
-try_again:
-       retval = ext2fs_symlink(current_fs, parent, 0, name, target);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, parent);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               goto try_again;
-       }
-       if (retval) {
-               com_err("ext2fs_symlink", retval, 0);
-               return;
-       }
+       if ((retval = do_symlink_internal(cwd, argv[1], argv[2])))
+               com_err(argv[0], retval, 0);
 
 }
 
index 33389fa..5e3b256 100644 (file)
@@ -5,6 +5,7 @@
 #include "ss/ss.h"
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
+#include "../misc/create_inode.h"
 
 #ifdef __STDC__
 #define NOARGS void
index 29b6aab..fbd09a5 100644 (file)
@@ -43,7 +43,7 @@ LPROGS=               @E2INITRD_PROG@
 TUNE2FS_OBJS=  tune2fs.o util.o
 MKLPF_OBJS=    mklost+found.o
 MKE2FS_OBJS=   mke2fs.o util.o profile.o prof_err.o default_profile.o \
-                       mk_hugefiles.o
+                       mk_hugefiles.o create_inode.o
 CHATTR_OBJS=   chattr.o
 LSATTR_OBJS=   lsattr.o
 UUIDGEN_OBJS=  uuidgen.o
@@ -61,7 +61,8 @@ E2FREEFRAG_OBJS= e2freefrag.o
 PROFILED_TUNE2FS_OBJS= profiled/tune2fs.o profiled/util.o
 PROFILED_MKLPF_OBJS=   profiled/mklost+found.o
 PROFILED_MKE2FS_OBJS=  profiled/mke2fs.o profiled/util.o profiled/profile.o \
-                       profiled/prof_err.o profiled/default_profile.o
+                       profiled/prof_err.o profiled/default_profile.o \
+                       profiled/create_inode.o
 PROFILED_CHATTR_OBJS=  profiled/chattr.o
 PROFILED_LSATTR_OBJS=  profiled/lsattr.o
 PROFILED_UUIDGEN_OBJS= profiled/uuidgen.o
@@ -83,7 +84,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
                $(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
                $(srcdir)/filefrag.c $(srcdir)/base_device.c \
                $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
-               $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c
+               $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c $(srcdir)/create_inode.c
 
 LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
 DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR)
@@ -646,7 +647,7 @@ mke2fs.o: $(srcdir)/mke2fs.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(srcdir)/util.h profile.h prof_err.h $(top_srcdir)/version.h \
- $(srcdir)/nls-enable.h $(top_srcdir)/lib/quota/mkquota.h \
+ $(srcdir)/nls-enable.h $(top_srcdir)/lib/quota/mkquota.h $(srcdir)/create_inode.h\
  $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
  $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/mke2fs.h
@@ -737,3 +738,7 @@ e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/e2freefrag.h
+create_inode.o: $(srcdir)/create_inode.h $(srcdir)/create_inode.c \
+ $(top_builddir)/lib/config.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/nls-enable.h
diff --git a/misc/create_inode.c b/misc/create_inode.c
new file mode 100644 (file)
index 0000000..cf4a58f
--- /dev/null
@@ -0,0 +1,582 @@
+#include "create_inode.h"
+
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+#  define __func__ __FUNCTION__
+# else
+#  define __func__ "<unknown>"
+# endif
+#endif
+
+/* 64KiB is the minimium blksize to best minimize system call overhead. */
+#ifndef IO_BUFSIZE
+#define IO_BUFSIZE 64*1024
+#endif
+
+/* Block size for `st_blocks' */
+#ifndef S_BLKSIZE
+#define S_BLKSIZE 512
+#endif
+
+/* For saving the hard links */
+int hdlink_cnt = HDLINK_CNT;
+
+/* Link an inode number to a directory */
+static errcode_t add_link(ext2_ino_t parent_ino, ext2_ino_t ino, const char *name)
+{
+       struct ext2_inode       inode;
+       errcode_t               retval;
+
+       retval = ext2fs_read_inode(current_fs, ino, &inode);
+        if (retval) {
+               com_err(__func__, retval, "while reading inode %u", ino);
+               return retval;
+       }
+
+       retval = ext2fs_link(current_fs, parent_ino, name, ino, inode.i_flags);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(current_fs, parent_ino);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               retval = ext2fs_link(current_fs, parent_ino, name, ino, inode.i_flags);
+       }
+       if (retval) {
+               com_err(__func__, retval, "while linking %s", name);
+               return retval;
+       }
+
+       inode.i_links_count++;
+
+       retval = ext2fs_write_inode(current_fs, ino, &inode);
+       if (retval)
+               com_err(__func__, retval, "while writing inode %u", ino);
+
+       return retval;
+}
+
+/* Fill the uid, gid, mode and time for the inode */
+static void fill_inode(struct ext2_inode *inode, struct stat *st)
+{
+       if (st != NULL) {
+               inode->i_uid = st->st_uid;
+               inode->i_gid = st->st_gid;
+               inode->i_mode |= st->st_mode;
+               inode->i_atime = st->st_atime;
+               inode->i_mtime = st->st_mtime;
+               inode->i_ctime = st->st_ctime;
+       }
+}
+
+/* Set the uid, gid, mode and time for the inode */
+errcode_t set_inode_extra(ext2_ino_t cwd, ext2_ino_t ino, struct stat *st)
+{
+       errcode_t               retval;
+       struct ext2_inode       inode;
+
+       retval = ext2fs_read_inode(current_fs, ino, &inode);
+        if (retval) {
+               com_err(__func__, retval, "while reading inode %u", ino);
+               return retval;
+       }
+
+       fill_inode(&inode, st);
+
+       retval = ext2fs_write_inode(current_fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval, "while writing inode %u", ino);
+               return retval;
+       }
+}
+
+/* Make a special file which is block, character and fifo */
+errcode_t do_mknod_internal(ext2_ino_t cwd, const char *name, struct stat *st)
+{
+       ext2_ino_t              ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       unsigned long           major, minor, mode;
+       int                     filetype;
+
+       switch(st->st_mode & S_IFMT) {
+               case S_IFCHR:
+                       mode = LINUX_S_IFCHR;
+                       filetype = EXT2_FT_CHRDEV;
+                       break;
+               case S_IFBLK:
+                       mode = LINUX_S_IFBLK;
+                       filetype =  EXT2_FT_BLKDEV;
+                       break;
+               case S_IFIFO:
+                       mode = LINUX_S_IFIFO;
+                       filetype = EXT2_FT_FIFO;
+                       break;
+       }
+
+       if (!(current_fs->flags & EXT2_FLAG_RW)) {
+               com_err(__func__, 0, "Filesystem opened read/only");
+               return -1;
+       }
+       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &ino);
+       if (retval) {
+               com_err(__func__, retval, 0);
+               return retval;
+       }
+
+#ifdef DEBUGFS
+       printf("Allocated inode: %u\n", ino);
+#endif
+       retval = ext2fs_link(current_fs, cwd, name, ino, filetype);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(current_fs, cwd);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               retval = ext2fs_link(current_fs, cwd, name, ino, filetype);
+       }
+       if (retval) {
+               com_err(name, retval, 0);
+               return -1;
+       }
+        if (ext2fs_test_inode_bitmap2(current_fs->inode_map, ino))
+               com_err(__func__, 0, "Warning: inode already set");
+       ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0);
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = mode;
+       inode.i_atime = inode.i_ctime = inode.i_mtime =
+               current_fs->now ? current_fs->now : time(0);
+
+       major = major(st->st_rdev);
+       minor = minor(st->st_rdev);
+
+       if ((major < 256) && (minor < 256)) {
+               inode.i_block[0] = major * 256 + minor;
+               inode.i_block[1] = 0;
+       } else {
+               inode.i_block[0] = 0;
+               inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
+       }
+       inode.i_links_count = 1;
+
+       retval = ext2fs_write_new_inode(current_fs, ino, &inode);
+       if (retval)
+               com_err(__func__, retval, "while creating inode %u", ino);
+
+       return retval;
+}
+
+/* Make a symlink name -> target */
+errcode_t do_symlink_internal(ext2_ino_t cwd, const char *name, char *target)
+{
+       char                    *cp;
+       ext2_ino_t              parent_ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       struct stat             st;
+
+       cp = strrchr(name, '/');
+       if (cp) {
+               *cp = 0;
+               if ((retval =  ext2fs_namei(current_fs, root, cwd, name, &parent_ino))){
+                       com_err(name, retval, 0);
+                       return retval;
+               }
+               name = cp+1;
+       } else
+               parent_ino = cwd;
+
+try_again:
+       retval = ext2fs_symlink(current_fs, parent_ino, 0, name, target);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(current_fs, parent_ino);
+               if (retval) {
+                       com_err("do_symlink_internal", retval, "while expanding directory");
+                       return retval;
+               }
+               goto try_again;
+       }
+       if (retval) {
+               com_err("ext2fs_symlink", retval, 0);
+               return retval;
+       }
+
+}
+
+/* Make a directory in the fs */
+errcode_t do_mkdir_internal(ext2_ino_t cwd, const char *name, struct stat *st)
+{
+       char                    *cp;
+       ext2_ino_t              parent_ino, ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+
+
+       cp = strrchr(name, '/');
+       if (cp) {
+               *cp = 0;
+               if ((retval =  ext2fs_namei(current_fs, root, cwd, name, &parent_ino))){
+                       com_err(name, retval, 0);
+                       return retval;
+               }
+               name = cp+1;
+       } else
+               parent_ino = cwd;
+
+try_again:
+       retval = ext2fs_mkdir(current_fs, parent_ino, 0, name);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(current_fs, parent_ino);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               goto try_again;
+       }
+       if (retval) {
+               com_err("ext2fs_mkdir", retval, 0);
+               return retval;
+       }
+}
+
+static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
+{
+       ext2_file_t     e2_file;
+       errcode_t       retval;
+       int             got;
+       unsigned int    written;
+       char            *buf;
+       char            *ptr;
+       char            *zero_buf;
+       int             cmp;
+
+       retval = ext2fs_file_open(current_fs, newfile,
+                                 EXT2_FILE_WRITE, &e2_file);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_get_mem(bufsize, &buf);
+       if (retval) {
+               com_err("copy_file", retval, "can't allocate buffer\n");
+               return retval;
+       }
+
+       /* This is used for checking whether the whole block is zero */
+       retval = ext2fs_get_memzero(bufsize, &zero_buf);
+       if (retval) {
+               com_err("copy_file", retval, "can't allocate buffer\n");
+               ext2fs_free_mem(&buf);
+               return retval;
+       }
+
+       while (1) {
+               got = read(fd, buf, bufsize);
+               if (got == 0)
+                       break;
+               if (got < 0) {
+                       retval = errno;
+                       goto fail;
+               }
+               ptr = buf;
+
+               /* Sparse copy */
+               if (make_holes) {
+                       /* Check whether all is zero */
+                       cmp = memcmp(ptr, zero_buf, got);
+                       if (cmp == 0) {
+                                /* The whole block is zero, make a hole */
+                               retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
+                               if (retval)
+                                       goto fail;
+                               got = 0;
+                       }
+               }
+
+               /* Normal copy */
+               while (got > 0) {
+                       retval = ext2fs_file_write(e2_file, ptr,
+                                                  got, &written);
+                       if (retval)
+                               goto fail;
+
+                       got -= written;
+                       ptr += written;
+               }
+       }
+       ext2fs_free_mem(&buf);
+       ext2fs_free_mem(&zero_buf);
+       retval = ext2fs_file_close(e2_file);
+       return retval;
+
+fail:
+       ext2fs_free_mem(&buf);
+       ext2fs_free_mem(&zero_buf);
+       (void) ext2fs_file_close(e2_file);
+       return retval;
+}
+
+int is_hardlink(ext2_ino_t ino)
+{
+       int i;
+
+       for(i = 0; i < hdlinks.count; i++) {
+               if(hdlinks.hdl[i].src_ino == ino)
+                       return i;
+       }
+       return -1;
+}
+
+/* Copy the native file to the fs */
+errcode_t do_write_internal(ext2_ino_t cwd, const char *src, const char *dest)
+{
+       int             fd;
+       struct stat     statbuf;
+       ext2_ino_t      newfile;
+       errcode_t       retval;
+       struct ext2_inode inode;
+       int             bufsize = IO_BUFSIZE;
+       int             make_holes = 0;
+
+       fd = open(src, O_RDONLY);
+       if (fd < 0) {
+               com_err(src, errno, 0);
+               return errno;
+       }
+       if (fstat(fd, &statbuf) < 0) {
+               com_err(src, errno, 0);
+               close(fd);
+               return errno;
+       }
+
+       retval = ext2fs_namei(current_fs, root, cwd, dest, &newfile);
+       if (retval == 0) {
+               com_err(__func__, 0, "The file '%s' already exists\n", dest);
+               close(fd);
+               return errno;
+       }
+
+       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
+       if (retval) {
+               com_err(__func__, retval, 0);
+               close(fd);
+               return errno;
+       }
+#ifdef DEBUGFS
+       printf("Allocated inode: %u\n", newfile);
+#endif
+       retval = ext2fs_link(current_fs, cwd, dest, newfile,
+                               EXT2_FT_REG_FILE);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(current_fs, cwd);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       close(fd);
+                       return errno;
+               }
+               retval = ext2fs_link(current_fs, cwd, dest, newfile,
+                                       EXT2_FT_REG_FILE);
+       }
+       if (retval) {
+               com_err(dest, retval, 0);
+               close(fd);
+               return errno;
+       }
+        if (ext2fs_test_inode_bitmap2(current_fs->inode_map, newfile))
+               com_err(__func__, 0, "Warning: inode already set");
+       ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
+       inode.i_atime = inode.i_ctime = inode.i_mtime =
+               current_fs->now ? current_fs->now : time(0);
+       inode.i_links_count = 1;
+       inode.i_size = statbuf.st_size;
+       if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
+                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+               inode.i_flags |= EXT4_INLINE_DATA_FL;
+       } else if (current_fs->super->s_feature_incompat &
+                  EXT3_FEATURE_INCOMPAT_EXTENTS) {
+               int i;
+               struct ext3_extent_header *eh;
+
+               eh = (struct ext3_extent_header *) &inode.i_block[0];
+               eh->eh_depth = 0;
+               eh->eh_entries = 0;
+               eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
+               i = (sizeof(inode.i_block) - sizeof(*eh)) /
+                       sizeof(struct ext3_extent);
+               eh->eh_max = ext2fs_cpu_to_le16(i);
+               inode.i_flags |= EXT4_EXTENTS_FL;
+       }
+
+       if ((retval = ext2fs_write_new_inode(current_fs, newfile, &inode))) {
+               com_err(__func__, retval, "while creating inode %u", newfile);
+               close(fd);
+               return errno;
+       }
+       if (inode.i_flags & EXT4_INLINE_DATA_FL) {
+               retval = ext2fs_inline_data_init(current_fs, newfile);
+               if (retval)
+                       return;
+       }
+       if (LINUX_S_ISREG(inode.i_mode)) {
+               if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
+                       make_holes = 1;
+                       /*
+                        * Use I/O blocksize as buffer size when
+                        * copying sparse files.
+                        */
+                       bufsize = statbuf.st_blksize;
+               }
+               retval = copy_file(fd, newfile, bufsize, make_holes);
+               if (retval)
+                       com_err("copy_file", retval, 0);
+       }
+       close(fd);
+
+       return 0;
+}
+
+/* Copy files from source_dir to fs */
+errcode_t populate_fs(ext2_ino_t parent_ino, const char *source_dir)
+{
+       const char      *name;
+       DIR             *dh;
+       struct dirent   *dent;
+       struct stat     st;
+       char            ln_target[PATH_MAX];
+       unsigned int    save_inode;
+       ext2_ino_t      ino;
+       errcode_t       retval;
+       int             read_cnt;
+       int             hdlink;
+
+       root = EXT2_ROOT_INO;
+
+       if (chdir(source_dir) < 0) {
+               com_err(__func__, errno,
+                       _("while changing working directory to \"%s\""), source_dir);
+               return errno;
+       }
+
+       if (!(dh = opendir("."))) {
+               com_err(__func__, errno,
+                       _("while openning directory \"%s\""), source_dir);
+               return errno;
+       }
+
+       while((dent = readdir(dh))) {
+               if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+                       continue;
+               lstat(dent->d_name, &st);
+               name = dent->d_name;
+
+               /* Check for hardlinks */
+               save_inode = 0;
+               if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
+                       hdlink = is_hardlink(st.st_ino);
+                       if (hdlink >= 0) {
+                               retval = add_link(parent_ino,
+                                               hdlinks.hdl[hdlink].dst_ino, name);
+                               if (retval) {
+                                       com_err(__func__, retval, "while linking %s", name);
+                                       return retval;
+                               }
+                               continue;
+                       } else
+                               save_inode = 1;
+               }
+
+               switch(st.st_mode & S_IFMT) {
+                       case S_IFCHR:
+                       case S_IFBLK:
+                       case S_IFIFO:
+                               if ((retval = do_mknod_internal(parent_ino, name, &st))) {
+                                       com_err(__func__, retval,
+                                               _("while creating special file \"%s\""), name);
+                                       return retval;
+                               }
+                               break;
+                       case S_IFSOCK:
+                               /* FIXME: there is no make socket function atm. */
+                               com_err(__func__, 0,
+                                       _("ignoring socket file \"%s\""), name);
+                               continue;
+                       case S_IFLNK:
+                               if((read_cnt = readlink(name, ln_target, sizeof(ln_target))) == -1) {
+                                       com_err(__func__, errno,
+                                               _("while trying to readlink \"%s\""), name);
+                                       return errno;
+                               }
+                               ln_target[read_cnt] = '\0';
+                               if ((retval = do_symlink_internal(parent_ino, name, ln_target))) {
+                                       com_err(__func__, retval,
+                                               _("while writing symlink\"%s\""), name);
+                                       return retval;
+                               }
+                               break;
+                       case S_IFREG:
+                               if ((retval = do_write_internal(parent_ino, name, name))) {
+                                       com_err(__func__, retval,
+                                               _("while writing file \"%s\""), name);
+                                       return retval;
+                               }
+                               break;
+                       case S_IFDIR:
+                               if ((retval = do_mkdir_internal(parent_ino, name, &st))) {
+                                       com_err(__func__, retval,
+                                               _("while making dir \"%s\""), name);
+                                       return retval;
+                               }
+                               if ((retval = ext2fs_namei(current_fs, root, parent_ino, name, &ino))) {
+                                       com_err(name, retval, 0);
+                                               return retval;
+                               }
+                               /* Populate the dir recursively*/
+                               retval = populate_fs(ino, name);
+                               if (retval) {
+                                       com_err(__func__, retval, _("while adding dir \"%s\""), name);
+                                       return retval;
+                               }
+                               chdir("..");
+                               break;
+                       default:
+                               com_err(__func__, 0,
+                                       _("ignoring entry \"%s\""), name);
+               }
+
+               if ((retval =  ext2fs_namei(current_fs, root, parent_ino, name, &ino))){
+                       com_err(name, retval, 0);
+                       return retval;
+               }
+
+               if ((retval = set_inode_extra(parent_ino, ino, &st))) {
+                       com_err(__func__, retval,
+                               _("while setting inode for \"%s\""), name);
+                       return retval;
+               }
+
+               /* Save the hardlink ino */
+               if (save_inode) {
+                       /*
+                        * Check whether need more memory, and we don't need
+                        * free() since the lifespan will be over after the fs
+                        * populated.
+                        */
+                       if (hdlinks.count == hdlink_cnt) {
+                               if ((hdlinks.hdl = realloc (hdlinks.hdl,
+                                               (hdlink_cnt + HDLINK_CNT) *
+                                               sizeof (struct hdlink_s))) == NULL) {
+                                       com_err(name, errno, "Not enough memory");
+                                       return errno;
+                               }
+                               hdlink_cnt += HDLINK_CNT;
+                       }
+                       hdlinks.hdl[hdlinks.count].src_ino = st.st_ino;
+                       hdlinks.hdl[hdlinks.count].dst_ino = ino;
+                       hdlinks.count++;
+               }
+       }
+       closedir(dh);
+       return retval;
+}
diff --git a/misc/create_inode.h b/misc/create_inode.h
new file mode 100644 (file)
index 0000000..2b6d429
--- /dev/null
@@ -0,0 +1,35 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+struct hdlink_s
+{
+       ext2_ino_t src_ino;
+       ext2_ino_t dst_ino;
+};
+
+struct hdlinks_s
+{
+       int count;
+       struct hdlink_s *hdl;
+};
+
+struct hdlinks_s hdlinks;
+
+ext2_filsys    current_fs;
+ext2_ino_t     root;
+
+/* For saving the hard links */
+#define HDLINK_CNT     4
+extern int hdlink_cnt;
+
+/* For populating the filesystem */
+extern errcode_t populate_fs(ext2_ino_t parent_ino, const char *source_dir);
+extern errcode_t do_mknod_internal(ext2_ino_t cwd, const char *name, struct stat *st);
+extern errcode_t do_symlink_internal(ext2_ino_t cwd, const char *name, char *target);
+extern errcode_t do_mkdir_internal(ext2_ino_t cwd, const char *name, struct stat *st);
+extern errcode_t do_write_internal(ext2_ino_t cwd, const char *src, const char *dest);
index 9c38e20..bf17eae 100644 (file)
@@ -52,6 +52,10 @@ mke2fs \- create an ext2/ext3/ext4 filesystem
 .I number-of-inodes
 ]
 [
+.B \-d
+.I root-directory
+]
+[
 .B \-n
 ]
 [
@@ -529,6 +533,9 @@ the
 ratio).  This allows the user to specify the number
 of desired inodes directly.
 .TP
+.BI \-d " root-directory"
+Add the files from the root-directory to the filesystem.
+.TP
 .BI \-o " creator-os"
 Overrides the default value of the "creator operating system" field of the
 filesystem.  The creator field is set by default to the name of the OS the
index 808c3f9..61aced2 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
-#include <fcntl.h>
 #include <ctype.h>
 #include <time.h>
 #ifdef __linux__
@@ -45,25 +44,20 @@ extern int optind;
 #include <errno.h>
 #endif
 #include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <libgen.h>
 #include <limits.h>
 #include <blkid/blkid.h>
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fsP.h"
-#include "et/com_err.h"
 #include "uuid/uuid.h"
-#include "e2p/e2p.h"
-#include "ext2fs/ext2fs.h"
 #include "util.h"
 #include "profile.h"
 #include "prof_err.h"
 #include "../version.h"
-#include "nls-enable.h"
 #include "quota/mkquota.h"
 #include "mke2fs.h"
+#include "create_inode.h"
 
 #define STRIDE_LENGTH 8
 
@@ -111,6 +105,7 @@ static char *mount_dir;
 char *journal_device;
 static int sync_kludge;        /* Set using the MKE2FS_SYNC env. option */
 char **fs_types;
+const char *root_dir;  /* Copy files from the specified directory */
 
 static profile_t       profile;
 
@@ -122,7 +117,8 @@ static void usage(void)
        fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
        "[-C cluster-size]\n\t[-i bytes-per-inode] [-I inode-size] "
        "[-J journal-options]\n"
-       "\t[-G flex-group-size] [-N number-of-inodes]\n"
+       "\t[-G flex-group-size] [-N number-of-inodes] "
+       "[-d root-directory]\n"
        "\t[-m reserved-blocks-percentage] [-o creator-os]\n"
        "\t[-g blocks-per-group] [-L volume-label] "
        "[-M last-mounted-directory]\n\t[-O feature[,...]] "
@@ -1527,7 +1523,7 @@ profile_error:
        }
 
        while ((c = getopt (argc, argv,
-                   "b:cg:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
+                   "b:cg:i:jl:m:no:qr:s:t:d:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
                switch (c) {
                case 'b':
                        blocksize = parse_num_blocks2(optarg, -1);
@@ -1715,6 +1711,9 @@ profile_error:
                case 'U':
                        fs_uuid = optarg;
                        break;
+               case 'd':
+                       root_dir = optarg;
+                       break;
                case 'v':
                        verbose = 1;
                        break;
@@ -2984,6 +2983,32 @@ no_journal:
        retval = mk_hugefiles(fs);
        if (retval)
                com_err(program_name, retval, "while creating huge files");
+       /* Copy files from the specified directory */
+       if (root_dir) {
+               if (!quiet)
+                       printf("%s", _("Copying files into the device: "));
+
+               /*
+                * Allocate memory for the hardlinks, we don't need free()
+                * since the lifespan will be over after the fs populated.
+                */
+               if ((hdlinks.hdl = (struct hdlink_s *)
+                               malloc(hdlink_cnt * sizeof(struct hdlink_s))) == NULL) {
+                       fprintf(stderr, "%s", _("\nNot enough memory\n"));
+                       retval = ext2fs_close(fs);
+                       return retval;
+               }
+
+               hdlinks.count = 0;
+               current_fs = fs;
+               root = EXT2_ROOT_INO;
+               retval = populate_fs(root, root_dir);
+               if (retval)
+                       fprintf(stderr, "%s",
+                               _("\nError while populating file system"));
+               else if (!quiet)
+                       printf("%s", _("done\n"));
+       }
 
        if (!quiet)
                printf("%s", _("Writing superblocks and "