Whamcloud - gitweb
ChangeLog, debug_cmds.ct, debugfs.8.in, debugfs.c, dump.c, ls.c:
authorTheodore Ts'o <tytso@mit.edu>
Sat, 27 May 2000 15:15:40 +0000 (15:15 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 27 May 2000 15:15:40 +0000 (15:15 +0000)
  debugfs.8.in: Documented new behaviour.
  ls.c (ls_l_file): Fix Y2K bug -- was printing 22-May-100 for recent
   files.  Switched to 4-digit years.
  dump.c, debug_cmds.ct (do_rdump): Add new debugfs command "rdump",
   which recursively dumps a directory and its contents.
   (fix_perms): New function.  Break permission-fixing code out of
   dump_file() so it can be called by rdump code as well.
   (dump_file): Call fix_perms().
  debugfs.c, debug_cmds.ct (do_lcd): Add new debugfs command "lcd",
   which changes the cwd on the native filesystem.
  debugfs.c (open_filesystem): Extra args for superblock, blocksize, and
   catastrophic mode.  Changed callers.
   (do_open_filesys, main): Accept new -b, -s, -c options for
   open_filesystem.
ChangeLog, mkdir.c:
  mkdir.c (ext2fs_mkdir): Read the parent directory's inode earlier, so
   that if there's an error reading it, we can more cleanly back out of
   the operation.
version.h:
  Update version file for WIP release.

debugfs/ChangeLog
debugfs/debug_cmds.ct
debugfs/debugfs.8.in
debugfs/debugfs.c
debugfs/dump.c
debugfs/ls.c
lib/ext2fs/ChangeLog
lib/ext2fs/mkdir.c
version.h

index 8026e87..ae9e3b7 100644 (file)
@@ -1,3 +1,26 @@
+2000-05-23  Aaron Crane  <aaronc@pobox.com>
+
+       * debugfs.8.in: Documented new behaviour.
+
+       * ls.c (ls_l_file): Fix Y2K bug -- was printing 22-May-100 for
+               recent files.  Switched to 4-digit years.
+
+       * dump.c, debug_cmds.ct (do_rdump): Add new debugfs command
+               "rdump", which recursively dumps a directory and its
+               contents.
+               (fix_perms): New function.  Break permission-fixing
+               code out of dump_file() so it can be called by rdump
+               code as well.
+               (dump_file): Call fix_perms().
+
+       * debugfs.c, debug_cmds.ct (do_lcd): Add new debugfs command
+               "lcd", which changes the cwd on the native filesystem.
+
+       * debugfs.c (open_filesystem): Extra args for superblock,
+               blocksize, and catastrophic mode.  Changed callers.
+               (do_open_filesys, main): Accept new -b, -s, -c options
+               for open_filesystem.
+
 2000-02-02  Theodore Ts'o  <tytso@valinux.com>
 
        * debugfs.c (dump_inode): Remove #ifdef for i_version
index 983c342..9b2f592 100644 (file)
@@ -112,5 +112,11 @@ request do_dump, "Dump an inode out to a file",
 request do_cat, "Dump an inode out to stdout",
        cat;
 
+request do_lcd, "Change the current directory on your native filesystem",
+       lcd;
+
+request do_rdump, "Recursively dump a directory to the native filesystem",
+       rdump;
+
 end;
 
index c56a6bd..7ac4552 100644 (file)
@@ -8,6 +8,14 @@ debugfs \- ext2 file system debugger
 .SH SYNOPSIS
 .B debugfs
 [
+.B \-b
+blocksize
+]
+[
+.B \-s
+superblock
+]
+[
 .B \-f 
 cmd_file
 ]
@@ -19,7 +27,12 @@ request
 .B \-V
 ]
 [
+[
 .B \-w
+]
+[
+.B \-c
+]
 [
 device
 ]
@@ -40,6 +53,24 @@ file system (e.g /dev/hdXX).
 Specifies that the file system should be opened in read-write mode.
 Without this option, the file system is opened in read-only mode.
 .TP
+.I -c
+Specifies that the file system should be opened in catastrophic mode, in
+which the inode and group bitmaps are not read initially.  This can be
+useful for filesystems with significant corruption, but because of this,
+catastrophic mode forces the filesystem to be opened read-only.
+.TP
+.I -b blocksize
+Forces the use of the given block size for the file system, rather than
+detecting the correct block size as normal.
+.TP
+.I -s superblock
+Causes the file system superblock to be read from the given block number,
+rather than the default (1).  If you give a
+.I -s
+option, you must also give a
+.I -b
+option.
+.TP
 .I -f cmd_file
 Causes 
 .B debugfs
@@ -186,14 +217,18 @@ device numbers must be specified.
 Take the requested list of inode numbers, and print a listing of pathnames
 to those inodes.
 .TP
-.I open [-w] [-f] device
+.I open [-w] [-f] [-c] [-b blocksize] [-s superblock] device
 Open a filesystem for editing.  The 
 .I -w 
 flag causes the filesystem to be opened for writing.  The 
 .I -f 
 flag forces the filesystem to be opened even if there are some unknown 
 or incompatible filesystem features which would normally 
-prevent the filesystem from being opened.
+prevent the filesystem from being opened.  The
+.IR -c ", " -b ", and " -s
+options behave the same as those to
+.B debugfs
+itself.
 .TP
 .I pwd
 Print the current working directory.
@@ -256,6 +291,21 @@ Create a file in the filesystem named
 and copy the contents of
 .I source_file
 into the destination file.
+.TP
+.I lcd directory
+Change the current working directory of the
+.B debugfs
+process to
+.I directory
+on the native filesystem.
+.TP
+.I rdump directory destination
+Recursively dump
+.I directory
+and all its contents (including regular files, symbolic links, and other
+directories) into the named
+.I destination
+which should be an existing directory on the native filesystem.
 .SH SPECIFYING FILES
 Many
 .B debugfs
index ad3abf9..1a93d58 100644 (file)
@@ -43,26 +43,44 @@ extern ss_request_table debug_cmds;
 ext2_filsys current_fs = NULL;
 ino_t  root, cwd;
 
-static void open_filesystem(char *device, int open_flags)
+static void open_filesystem(char *device, int open_flags, blk_t superblock,
+                           blk_t blocksize, int catastrophic)
 {
        int     retval;
+
+       if (superblock != 0 && blocksize == 0) {
+               com_err(device, 0, "if you specify the superblock, you must also specify the block size");
+               current_fs = NULL;
+               return;
+       }
+
+       if (catastrophic && (open_flags & EXT2_FLAG_RW)) {
+               com_err(device, 0,
+                       "opening read-only because of catastrophic mode");
+               open_flags &= ~EXT2_FLAG_RW;
+       }
        
-       retval = ext2fs_open(device, open_flags, 0, 0,
+       retval = ext2fs_open(device, open_flags, superblock, blocksize,
                             unix_io_manager, &current_fs);
        if (retval) {
                com_err(device, retval, "while opening filesystem");
                current_fs = NULL;
                return;
        }
-       retval = ext2fs_read_inode_bitmap(current_fs);
-       if (retval) {
-               com_err(device, retval, "while reading inode bitmap");
-               goto errout;
-       }
-       retval = ext2fs_read_block_bitmap(current_fs);
-       if (retval) {
-               com_err(device, retval, "while reading block bitmap");
-               goto errout;
+
+       if (catastrophic)
+               com_err(device, 0, "catastrophic mode - not reading inode or group bitmaps");
+       else {
+               retval = ext2fs_read_inode_bitmap(current_fs);
+               if (retval) {
+                       com_err(device, retval, "while reading inode bitmap");
+                       goto errout;
+               }
+               retval = ext2fs_read_block_bitmap(current_fs);
+               if (retval) {
+                       com_err(device, retval, "while reading block bitmap");
+                       goto errout;
+               }
        }
        root = cwd = EXT2_ROOT_INO;
        return;
@@ -76,15 +94,19 @@ errout:
 
 void do_open_filesys(int argc, char **argv)
 {
-       const char      *usage = "Usage: open [-w] <device>";
+       const char *usage = "Usage: open [-s superblock] [-b blocksize] [-c] [-w] <device>";
        int     c;
+       int     catastrophic = 0;
+       blk_t   superblock = 0;
+       blk_t   blocksize = 0;
+       char    *tmp;
        int open_flags = 0;
        
        optind = 0;
 #ifdef HAVE_OPTRESET
        optreset = 1;           /* Makes BSD getopt happy */
 #endif
-       while ((c = getopt (argc, argv, "wf")) != EOF) {
+       while ((c = getopt (argc, argv, "wfcb:s:")) != EOF) {
                switch (c) {
                case 'w':
                        open_flags |= EXT2_FLAG_RW;
@@ -92,6 +114,25 @@ void do_open_filesys(int argc, char **argv)
                case 'f':
                        open_flags |= EXT2_FLAG_FORCE;
                        break;
+               case 'c':
+                       catastrophic = 1;
+                       break;
+               case 'b':
+                       blocksize = strtoul(optarg, &tmp, 0);
+                       if (*tmp) {
+                               com_err(argv[0], 0,
+                                       "Bad block size - %s", optarg);
+                               return;
+                       }
+                       break;
+               case 's':
+                       superblock = strtoul(optarg, &tmp, 0);
+                       if (*tmp) {
+                               com_err(argv[0], 0,
+                                       "Bad superblock number - %s", optarg);
+                               return;
+                       }
+                       break;
                default:
                        com_err(argv[0], 0, usage);
                        return;
@@ -103,7 +144,25 @@ void do_open_filesys(int argc, char **argv)
        }
        if (check_fs_not_open(argv[0]))
                return;
-       open_filesystem(argv[optind], open_flags);
+       open_filesystem(argv[optind], open_flags,
+                       superblock, blocksize, catastrophic);
+}
+
+void do_lcd(int argc, char **argv)
+{
+       const char *usage = "Usage: lcd <native dir>";
+
+       if (argc != 2) {
+               com_err(argv[0], 0, usage);
+               return;
+       }
+
+       if (chdir(argv[1]) == -1) {
+               com_err(argv[0], errno,
+                       "while trying to change native directory to %s",
+                       argv[1]);
+               return;
+       }
 }
 
 static void close_filesystem(NOARGS)
@@ -1438,19 +1497,23 @@ int main(int argc, char **argv)
 {
        int             retval;
        int             sci_idx;
-       const char      *usage = "Usage: debugfs [-f cmd_file] [-R request] [-V] [[-w] device]";
+       const char      *usage = "Usage: debugfs [-b blocksize] [-s superblock] [-f cmd_file] [-R request] [-V] [[-w] [-c] device]";
        int             c;
        int             open_flags = 0;
        char            *request = 0;
        int             exit_status = 0;
        char            *cmd_file = 0;
+       blk_t           superblock = 0;
+       blk_t           blocksize = 0;
+       int             catastrophic = 0;
+       char            *tmp;
        
        initialize_ext2_error_table();
        fprintf (stderr, "debugfs %s, %s for EXT2 FS %s, %s\n",
                 E2FSPROGS_VERSION, E2FSPROGS_DATE,
                 EXT2FS_VERSION, EXT2FS_DATE);
 
-       while ((c = getopt (argc, argv, "wR:f:V")) != EOF) {
+       while ((c = getopt (argc, argv, "wcR:f:b:s:V")) != EOF) {
                switch (c) {
                case 'R':
                        request = optarg;
@@ -1461,6 +1524,25 @@ int main(int argc, char **argv)
                case 'w':
                        open_flags = EXT2_FLAG_RW;
                        break;
+               case 'b':
+                       blocksize = strtoul(optarg, &tmp, 0);
+                       if (*tmp) {
+                               com_err(argv[0], 0,
+                                       "Bad block size - %s", optarg);
+                               return 1;
+                       }
+                       break;
+               case 's':
+                       superblock = strtoul(optarg, &tmp, 0);
+                       if (*tmp) {
+                               com_err(argv[0], 0,
+                                       "Bad superblock number - %s", optarg);
+                               return 1;
+                       }
+                       break;
+               case 'c':
+                       catastrophic = 1;
+                       break;
                case 'V':
                        /* Print version number and exit */
                        fprintf(stderr, "\tUsing %s\n",
@@ -1472,7 +1554,8 @@ int main(int argc, char **argv)
                }
        }
        if (optind < argc)
-               open_filesystem(argv[optind], open_flags);
+               open_filesystem(argv[optind], open_flags,
+                               superblock, blocksize, catastrophic);
        
        sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL,
                                       &debug_cmds, &retval);
index d3919dd..55aa4ac 100644 (file)
@@ -61,6 +61,39 @@ static mode_t mode_xlate(__u16 lmode)
        return mode;
 }
 
+static void fix_perms(const char *cmd, const struct ext2_inode *inode,
+                     int fd, const char *name)
+{
+       struct utimbuf ut;
+       int i;
+
+       if (fd != -1)
+               i = fchmod(fd, mode_xlate(inode->i_mode));
+       else
+               i = chmod(name, mode_xlate(inode->i_mode));
+       if (i == -1)
+               com_err(cmd, errno, "while setting permissions of %s", name);
+
+#ifndef HAVE_FCHOWN
+       i = chmod(name, inode->i_uid, inode->i_gid);
+#else
+       if (fd != -1)
+               i = fchown(fd, inode->i_uid, inode->i_gid);
+       else
+               i = chown(name, inode->i_uid, inode->i_gid);
+#endif
+       if (i == -1)
+               com_err(cmd, errno, "while changing ownership of %s", name);
+
+       if (fd != -1)
+               close(fd);
+
+       ut.actime = inode->i_atime;
+       ut.modtime = inode->i_mtime;
+       if (utime(name, &ut) == -1)
+               com_err(cmd, errno, "while setting times of %s", name);
+}
+
 static void dump_file(char *cmdname, ino_t ino, int fd, int preserve,
                      char *outname)
 {
@@ -100,27 +133,9 @@ static void dump_file(char *cmdname, ino_t ino, int fd, int preserve,
                return;
        }
                
-       if (preserve) {
-#ifdef HAVE_FCHOWN
-               if (fchown(fd, inode.i_uid, inode.i_gid) < 0)
-                       com_err("dump_file", errno,
-                               "while changing ownership of %s", outname);
-#else
-               if (chown(outname, inode.i_uid, inode.i_gid) < 0)
-                       com_err("dump_file", errno,
-                               "while changing ownership of %s", outname);
-                       
-#endif
-               if (fchmod(fd, mode_xlate(inode.i_mode)) < 0)
-                       com_err("dump_file", errno,
-                               "while setting permissions of %s", outname);
-               ut.actime = inode.i_atime;
-               ut.modtime = inode.i_mtime;
-               close(fd);
-               if (utime(outname, &ut) < 0)
-                       com_err("dump_file", errno,
-                               "while setting times on %s", outname);
-       } else if (fd != 1)
+       if (preserve)
+               fix_perms("dump_file", &inode, fd, outname);
+       else if (fd != 1)
                close(fd);
                                    
        return;
@@ -176,6 +191,182 @@ void do_dump(int argc, char **argv)
        return;
 }
 
+static void rdump_symlink(ino_t ino, struct ext2_inode *inode,
+                         const char *fullname)
+{
+       ext2_file_t e2_file;
+       char *buf;
+       errcode_t retval;
+
+       buf = malloc(inode->i_size + 1);
+       if (!buf) {
+               com_err("rdump", errno, "while allocating for symlink");
+               goto errout;
+       }
+
+       /* Apparently, this is the right way to detect and handle fast
+        * symlinks; see do_stat() in debugfs.c. */
+       if (inode->i_blocks == 0)
+               strcpy(buf, (char *) inode->i_block);
+       else {
+               unsigned bytes = inode->i_size;
+               char *p = buf;
+               retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
+               if (retval) {
+                       com_err("rdump", retval, "while opening symlink");
+                       goto errout;
+               }
+               for (;;) {
+                       unsigned int got;
+                       retval = ext2fs_file_read(e2_file, p, bytes, &got);
+                       if (retval) {
+                               com_err("rdump", retval, "while reading symlink");
+                               goto errout;
+                       }
+                       bytes -= got;
+                       p += got;
+                       if (got == 0 || bytes == 0)
+                               break;
+               }
+               buf[inode->i_size] = 0;
+               retval = ext2fs_file_close(e2_file);
+               if (retval)
+                       com_err("rdump", retval, "while closing symlink");
+       }
+
+       if (symlink(buf, fullname) == -1) {
+               com_err("rdump", errno, "while creating symlink %s -> %s", buf, fullname);
+               goto errout;
+       }
+
+errout:
+       free(buf);
+}
+
+static int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *);
+
+static void rdump_inode(ino_t ino, struct ext2_inode *inode,
+                       const char *name, const char *dumproot)
+{
+       char *fullname;
+       struct utimbuf ut;
+
+       /* There are more efficient ways to do this, but this method
+        * requires only minimal debugging. */
+       fullname = malloc(strlen(dumproot) + strlen(name) + 2);
+       if (!fullname) {
+               com_err("rdump", errno, "while allocating memory");
+               return;
+       }
+       sprintf(fullname, "%s/%s", dumproot, name);
+
+       if (LINUX_S_ISLNK(inode->i_mode))
+               rdump_symlink(ino, inode, fullname);
+       else if (LINUX_S_ISREG(inode->i_mode)) {
+               int fd;
+               fd = open(fullname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
+               if (fd == -1) {
+                       com_err("rdump", errno, "while dumping %s", fullname);
+                       goto errout;
+               }
+               dump_file("rdump", ino, fd, 1, fullname);
+       }
+       else if (LINUX_S_ISDIR(inode->i_mode) && strcmp(name, ".") && strcmp(name, "..")) {
+               errcode_t retval;
+
+               /* Create the directory with 0700 permissions, because we
+                * expect to have to create entries it.  Then fix its perms
+                * once we've done the traversal. */
+               if (mkdir(fullname, S_IRWXU) == -1) {
+                       com_err("rdump", errno, "while making directory %s", fullname);
+                       goto errout;
+               }
+
+               retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
+                                           rdump_dirent, (void *) fullname);
+               if (retval)
+                       com_err("rdump", retval, "while dumping %s", fullname);
+
+               fix_perms("rdump", inode, -1, fullname);
+       }
+       /* else do nothing (don't dump device files, sockets, fifos, etc.) */
+
+errout:
+       free(fullname);
+}
+
+static int rdump_dirent(struct ext2_dir_entry *dirent, int offset,
+                        int blocksize, char *buf, void *private)
+{
+       char name[EXT2_NAME_LEN];
+       int thislen;
+       const char *dumproot = private;
+       struct ext2_inode inode;
+       errcode_t retval;
+
+       thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN
+                  ? (dirent->name_len & 0xFF) : EXT2_NAME_LEN);
+       strncpy(name, dirent->name, thislen);
+       name[thislen] = 0;
+
+       retval = ext2fs_read_inode(current_fs, dirent->inode, &inode);
+       if (retval) {
+               com_err("rdump", retval, "while dumping %s/%s", dumproot, name);
+               return 0;
+       }
+
+       rdump_inode(dirent->inode, &inode, name, dumproot);
+
+       return 0;
+}
+
+void do_rdump(int argc, char **argv)
+{
+       ino_t ino;
+       struct ext2_inode inode;
+       errcode_t retval;
+       struct stat st;
+       int i;
+       char *p;
+
+       if (argc != 3) {
+               com_err(argv[0], 0, "Usage: rdump <directory> <native directory>");
+               return;
+       }
+
+       if (check_fs_open(argv[0]))
+               return;
+
+       ino = string_to_inode(argv[1]);
+       if (!ino)
+               return;
+
+       /* Ensure ARGV[2] is a directory. */
+       i = stat(argv[2], &st);
+       if (i == -1) {
+               com_err("rdump", errno, "while statting %s", argv[2]);
+               return;
+       }
+       if (!S_ISDIR(st.st_mode)) {
+               com_err("rdump", 0, "%s is not a directory", argv[2]);
+               return;
+       }
+
+       retval = ext2fs_read_inode(current_fs, ino, &inode);
+       if (retval) {
+               com_err("rdump", retval, "while dumping %s", argv[1]);
+               return;
+       }
+
+       p = strrchr(argv[1], '/');
+       if (p)
+               p++;
+       else
+               p = argv[1];
+
+       rdump_inode(ino, &inode, p, argv[2]);
+}
+
 void do_cat(int argc, char **argv)
 {
        ino_t   inode;
index aadf75d..4c96db4 100644 (file)
@@ -48,8 +48,8 @@ static void ls_l_file(struct list_dir_struct *ls, char *name, ino_t ino)
        }
        modtime = inode.i_mtime;
        tm_p = localtime(&modtime);
-       sprintf(datestr, "%2d-%s-%2d %02d:%02d",
-               tm_p->tm_mday, monstr[tm_p->tm_mon], tm_p->tm_year,
+       sprintf(datestr, "%2d-%s-%4d %02d:%02d",
+               tm_p->tm_mday, monstr[tm_p->tm_mon], 1900 + tm_p->tm_year,
                tm_p->tm_hour, tm_p->tm_min);
        fprintf(ls->f, "%6ld %6o  %5d  %5d   ", ino, inode.i_mode,
               inode.i_uid, inode.i_gid);
index 2107c19..9141e84 100644 (file)
@@ -1,3 +1,9 @@
+2000-05-27  Theodore Ts'o  <tytso@valinux.com>
+
+       * mkdir.c (ext2fs_mkdir): Read the parent directory's inode
+               earlier, so that if there's an error reading it, we can
+               more cleanly back out of the operation.
+
 2000-05-25    <tytso@snap.thunk.org>
 
        * getsize.c (ext2fs_get_device_size): Use open64() instead of
index eca9a1d..98c5ccf 100644 (file)
@@ -39,7 +39,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum,
                       const char *name)
 {
        errcode_t               retval;
-       struct ext2_inode       inode;
+       struct ext2_inode       parent_inode, inode;
        ino_t                   ino = inum;
        ino_t                   scratch_ino;
        blk_t                   blk;
@@ -73,6 +73,16 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum,
                goto cleanup;
 
        /*
+        * Get the parent's inode, if necessary
+        */
+       if (parent != ino) {
+               retval = ext2fs_read_inode(fs, parent, &parent_inode);
+               if (retval)
+                       goto cleanup;
+       } else
+               memset(&parent_inode, 0, sizeof(parent_inode));
+
+       /*
         * Create the inode structure....
         */
        memset(&inode, 0, sizeof(struct ext2_inode));
@@ -116,11 +126,8 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum,
         * Update parent inode's counts
         */
        if (parent != ino) {
-               retval = ext2fs_read_inode(fs, parent, &inode);
-               if (retval)
-                       goto cleanup;
-               inode.i_links_count++;
-               retval = ext2fs_write_inode(fs, parent, &inode);
+               parent_inode.i_links_count++;
+               retval = ext2fs_write_inode(fs, parent, &parent_inode);
                if (retval)
                        goto cleanup;
        }
index 4ec26e4..a1bb805 100644 (file)
--- a/version.h
+++ b/version.h
@@ -7,4 +7,4 @@
  */
 
 #define E2FSPROGS_VERSION "1.19-WIP"
-#define E2FSPROGS_DATE "6-Apr-2000"
+#define E2FSPROGS_DATE "27-May-2000"