Whamcloud - gitweb
Many files:
authorTheodore Ts'o <tytso@mit.edu>
Tue, 29 Apr 1997 17:48:10 +0000 (17:48 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 29 Apr 1997 17:48:10 +0000 (17:48 +0000)
  Checked in e2fsprogs 1.08.

69 files changed:
debugfs/ChangeLog
debugfs/Makefile.in
debugfs/debugfs.8.in
debugfs/debugfs.c
debugfs/ls.c [new file with mode: 0644]
doc/libext2fs.texinfo
e2fsck/ChangeLog
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass1b.c
e2fsck/pass2.c
e2fsck/problem.c
e2fsck/problem.h
include/linux/ext2_fs.h
lib/e2p/ChangeLog
lib/e2p/Makefile.in
lib/e2p/ls.c
lib/ext2fs/ChangeLog
lib/ext2fs/Makefile.in
lib/ext2fs/alloc_tables.c
lib/ext2fs/bitops.h
lib/ext2fs/closefs.c
lib/ext2fs/dblist.c
lib/ext2fs/dll/jump.funcs
lib/ext2fs/ext2fs.h
lib/ext2fs/icount.c
lib/ext2fs/initialize.c
lib/ext2fs/inode.c
lib/ext2fs/openfs.c
lib/ext2fs/version.c [new file with mode: 0644]
lib/ss/test_ss.c
misc/ChangeLog
misc/dumpe2fs.c
misc/mke2fs.8.in
misc/mke2fs.c
misc/tune2fs.8.in
misc/tune2fs.c
tests/ChangeLog
tests/defaults/e_script [moved from tests/defaults/r_script with 52% similarity]
tests/e_brel_bma/name [moved from tests/r_brel_bma/name with 100% similarity]
tests/e_icount_normal/name [new file with mode: 0644]
tests/e_icount_opt/name [new file with mode: 0644]
tests/e_irel_ima/name [moved from tests/r_irel_ima/name with 100% similarity]
tests/f_dupfsblks/expect.1
tests/f_dupsuper/expect.1
tests/f_dupsuper/expect.2
tests/f_illbbitmap/expect.1
tests/f_illibitmap/expect.1
tests/f_illitable/expect.1
tests/f_preen/expect.1
tests/progs/ChangeLog [new file with mode: 0644]
tests/progs/Makefile.in
tests/progs/test_data/bma.setup [moved from tests/progs/rel_test/bma.setup with 100% similarity]
tests/progs/test_data/expect.brel [moved from tests/progs/rel_test/expect.brel with 100% similarity]
tests/progs/test_data/expect.icount [new file with mode: 0644]
tests/progs/test_data/expect.irel [moved from tests/progs/rel_test/expect.irel with 100% similarity]
tests/progs/test_data/ima.setup [moved from tests/progs/rel_test/ima.setup with 100% similarity]
tests/progs/test_data/normal.setup [new file with mode: 0644]
tests/progs/test_data/opt.setup [new file with mode: 0644]
tests/progs/test_data/test.brel [moved from tests/progs/rel_test/test.brel with 100% similarity]
tests/progs/test_data/test.icount [new file with mode: 0644]
tests/progs/test_data/test.irel [moved from tests/progs/rel_test/test.irel with 100% similarity]
tests/progs/test_icount.c [new file with mode: 0644]
tests/progs/test_icount.h [new file with mode: 0644]
tests/progs/test_icount_cmds.ct [new file with mode: 0644]
tests/progs/test_rel.c
tests/test_config
tests/test_script.in

index 75c0c5d..c143fc6 100644 (file)
@@ -1,3 +1,8 @@
+Thu Apr 10 14:36:05 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * ls.c: New file which implements the ls command.  Added the -l
+               option. 
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
index 31ea160..dad1f90 100644 (file)
@@ -16,9 +16,9 @@ MANPAGES=     debugfs.8
 
 MK_CMDS=       ../lib/ss/mk_cmds
 
-DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o lsdel.o dump.o
+DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o lsdel.o dump.o
 
-SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c \
+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
 
index dc6352a..72b12ec 100644 (file)
@@ -150,7 +150,7 @@ which is a link to
 .IR filespec .
 Note this does not adjust the inode reference counts.
 .TP
-.I ls filespec
+.I ls [-l] filespec
 Print a listing of the files in the directory
 .IR filespec .
 .TP
index 0797a88..ded79cc 100644 (file)
@@ -727,78 +727,6 @@ void do_modify_inode(int argc, char *argv[])
        }
 }
 
-/*
- * list directory
- */
-
-struct list_dir_struct {
-       FILE    *f;
-       int     col;
-};
-
-static int list_dir_proc(struct ext2_dir_entry *dirent,
-                        int    offset,
-                        int    blocksize,
-                        char   *buf,
-                        void   *private)
-{
-       char    name[EXT2_NAME_LEN];
-       char    tmp[EXT2_NAME_LEN + 16];
-
-       struct list_dir_struct *ls = (struct list_dir_struct *) private;
-       int     thislen;
-
-       thislen = (dirent->name_len < EXT2_NAME_LEN) ? dirent->name_len :
-               EXT2_NAME_LEN;
-       strncpy(name, dirent->name, thislen);
-       name[thislen] = '\0';
-
-       sprintf(tmp, "%d (%d) %s   ", dirent->inode, dirent->rec_len, name);
-       thislen = strlen(tmp);
-
-       if (ls->col + thislen > 80) {
-               fprintf(ls->f, "\n");
-               ls->col = 0;
-       }
-       fprintf(ls->f, "%s", tmp);
-       ls->col += thislen;
-               
-       return 0;
-}
-
-void do_list_dir(int argc, char *argv[])
-{
-       ino_t   inode;
-       int     retval;
-       struct list_dir_struct ls;
-       
-       if (argc > 2) {
-               com_err(argv[0], 0, "Usage: list_dir [pathname]");
-               return;
-       }
-       if (check_fs_open(argv[0]))
-               return;
-
-       if (argc == 2)
-               inode = string_to_inode(argv[1]);
-       else
-               inode = cwd;
-       if (!inode)
-               return;
-
-       ls.f = open_pager();
-       ls.col = 0;
-       retval = ext2fs_dir_iterate(current_fs, inode,
-                                   DIRENT_FLAG_INCLUDE_EMPTY,
-                                   0, list_dir_proc, &ls);
-       fprintf(ls.f, "\n");
-       close_pager(ls.f);
-       if (retval)
-               com_err(argv[1], retval, "");
-
-       return;
-}
-
 void do_change_working_dir(int argc, char *argv[])
 {
        ino_t   inode;
@@ -1337,6 +1265,7 @@ static void kill_file_by_inode(ino_t inode)
        printf("Kill file by inode %ld\n", inode);
        ext2fs_block_iterate(current_fs, inode, 0, NULL,
                             release_blocks_proc, NULL);
+       printf("\n");
        ext2fs_unmark_inode_bitmap(current_fs->inode_map, inode);
 
        ext2fs_mark_bb_dirty(current_fs);
@@ -1479,7 +1408,7 @@ void main(int argc, char **argv)
 {
        int             retval;
        int             sci_idx;
-       const char      *usage = "Usage: debugfs [-w] [device]";
+       const char      *usage = "Usage: debugfs [[-w] device]";
        char            c;
        int             open_flags = 0;
        char            *request = 0;
diff --git a/debugfs/ls.c b/debugfs/ls.c
new file mode 100644 (file)
index 0000000..98c1d60
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * ls.c --- list directories
+ * 
+ * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+
+#include "debugfs.h"
+
+/*
+ * list directory
+ */
+
+#define LONG_OPT       0x0001
+
+struct list_dir_struct {
+       FILE    *f;
+       int     col;
+       int     options;
+};
+
+static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+                                       
+static void ls_l_file(struct list_dir_struct *ls, char *name, ino_t ino)
+{
+       struct ext2_inode       inode;
+       errcode_t               retval;
+       struct tm               *tm_p;
+       time_t                  modtime;
+       char                    datestr[80];
+
+       retval = ext2fs_read_inode(current_fs, ino, &inode);
+       if (retval) {
+               fprintf(ls->f, "%5d --- error ---  %s\n", name);
+               return;
+       }
+       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,
+               tm_p->tm_hour, tm_p->tm_min);
+       fprintf(ls->f, "%6d %6o  %5d  %5d   %5d %s %s\n", ino, inode.i_mode,
+              inode.i_uid, inode.i_gid, inode.i_size, datestr, name);
+}
+
+static void ls_file(struct list_dir_struct *ls, char *name,
+                   ino_t ino, int rec_len)
+{
+       char    tmp[EXT2_NAME_LEN + 16];
+       int     thislen;
+
+       sprintf(tmp, "%d (%d) %s   ", ino, rec_len, name);
+       thislen = strlen(tmp);
+
+       if (ls->col + thislen > 80) {
+               fprintf(ls->f, "\n");
+               ls->col = 0;
+       }
+       fprintf(ls->f, "%s", tmp);
+       ls->col += thislen;
+}      
+
+
+static int list_dir_proc(struct ext2_dir_entry *dirent,
+                        int    offset,
+                        int    blocksize,
+                        char   *buf,
+                        void   *private)
+{
+       char    name[EXT2_NAME_LEN];
+       char    tmp[EXT2_NAME_LEN + 16];
+
+       struct list_dir_struct *ls = (struct list_dir_struct *) private;
+       int     thislen;
+
+       thislen = (dirent->name_len < EXT2_NAME_LEN) ? dirent->name_len :
+               EXT2_NAME_LEN;
+       strncpy(name, dirent->name, thislen);
+       name[thislen] = '\0';
+
+       if (ls->options & LONG_OPT) 
+               ls_l_file(ls, name, dirent->inode);
+       else
+               ls_file(ls, name, dirent->inode, dirent->rec_len);
+       
+       return 0;
+}
+
+void do_list_dir(int argc, char *argv[])
+{
+       ino_t   inode;
+       int     retval;
+       struct list_dir_struct ls;
+       int     argptr = 1;
+       
+       ls.options = 0;
+       if (check_fs_open(argv[0]))
+               return;
+
+       if ((argc > argptr) && (argv[argptr][0] == '-')) {
+               argptr++;
+               ls.options = LONG_OPT;
+       }
+
+       if (argc <= argptr)
+               inode = cwd;
+       else
+               inode = string_to_inode(argv[argptr]);
+       if (!inode)
+               return;
+
+       ls.f = open_pager();
+       ls.col = 0;
+       retval = ext2fs_dir_iterate(current_fs, inode,
+                                   DIRENT_FLAG_INCLUDE_EMPTY,
+                                   0, list_dir_proc, &ls);
+       fprintf(ls.f, "\n");
+       close_pager(ls.f);
+       if (retval)
+               com_err(argv[1], retval, "");
+
+       return;
+}
+
+
index 9769985..0506e5c 100644 (file)
@@ -1,7 +1,7 @@
 \input texinfo    @c -*-texinfo-*-
 @c %**start of header
 @setfilename libext2fs.info
-@settitle The EXT2FS Library (version 1.07)
+@settitle The EXT2FS Library (version 1.08)
 @synindex tp fn
 @comment %**end of header
 
@@ -60,8 +60,8 @@ by the author.
 
 @title The EXT2FS Library
 @subtitle The EXT2FS Library
-@subtitle Version 1.07
-@subtitle February 1997
+@subtitle Version 1.08
+@subtitle April 1997
 
 @author by Theodore Ts'o
 
@@ -101,7 +101,7 @@ by the Foundation.
 
 @top The EXT2FS Library
 
-This manual documents the EXT2FS Library, version 1.07.
+This manual documents the EXT2FS Library, version 1.08.
 
 @end ifinfo
 
@@ -130,8 +130,7 @@ manipulate an ext2 filesystem.
 * Inode Functions::             
 * Directory functions::         
 * Bitmap Functions::            
-* Badblocks list management::   
-* Directory-block list management::  
+* EXT2 data abstractions::      
 * Byte-swapping functions::     
 * Other functions::             
 @end menu
@@ -505,9 +504,21 @@ EXT2_ET_MISSING_INODE_TABLE.
 @subsection Convenience functions for Inodes
 
 @deftypefun errcode_t ext2fs_get_blocks (ext2_filsys @var{fs}, ino_t @var{ino}, blk_t *@var{blocks})
+
+Returns an array of blocks corresponding to the direct,
+indirect, doubly indirect, and triply indirect blocks as stored in the
+inode structure.
 @end deftypefun
 
 @deftypefun errcode_t ext2fs_check_directory (ext2_filsys @var{fs}, ino_t @var{ino})
+Returns 0 if @var{ino} is a directory, and @code{ENOTDIR} if it is not.
+@end deftypefun
+
+@deftypefun int ext2_inode_has_valid_blocks (struct ext2_inode *@var{inode})
+
+Returns 1 if the inode's block entries actually valid block entries, and
+0 if not.  Inodes which represent devices and fast symbolic links do not
+contain valid block entries.
 @end deftypefun
 
 @c ----------------------------------------------------------------------
@@ -603,7 +614,7 @@ EXT2_ET_MISSING_INODE_TABLE.
 
 @c ----------------------------------------------------------------------
 
-@node Bitmap Functions, Badblocks list management, Directory functions, EXT2FS Library Functions
+@node Bitmap Functions, EXT2 data abstractions, Directory functions, EXT2FS Library Functions
 @comment  node-name,  next,  previous,  up
 @section Bitmap Functions
 
@@ -786,9 +797,24 @@ Return the first inode or block which is stored in the bitmap.
 
 @c ----------------------------------------------------------------------
 
-@node Badblocks list management, Directory-block list management, Bitmap Functions, EXT2FS Library Functions
+@node EXT2 data abstractions, Byte-swapping functions, Bitmap Functions, EXT2FS Library Functions
+@comment  node-name,  next,  previous,  up
+@section EXT2 data abstractions
+
+The ext2 library has a number of abstractions which are useful for ext2
+utility programs.  
+
+@menu
+* Badblocks list management::   
+* Directory-block list management::  
+* Inode count functions::       
+@end menu
+
+@c ----------------------------------------------------------------------
+
+@node Badblocks list management, Directory-block list management, EXT2 data abstractions, EXT2 data abstractions
 @comment  node-name,  next,  previous,  up
-@section Badblocks list management
+@subsection Badblocks list management
 
 
 @deftypefun errcode_t ext2fs_badblocks_list_create (ext2_badblocks_list *@var{ret}, int @var{size})
@@ -824,29 +850,130 @@ Return the first inode or block which is stored in the bitmap.
 
 @c ----------------------------------------------------------------------
 
-@node Directory-block list management, Byte-swapping functions, Badblocks list management, EXT2FS Library Functions
+@node Directory-block list management, Inode count functions, Badblocks list management, EXT2 data abstractions
 @comment  node-name,  next,  previous,  up
-@section Directory-block list management
+@subsection Directory-block list management
+
+The dblist abstraction stores a list of blocks belonging to
+directories.  This list can be useful when a program needs to interate
+over all directory entries in a filesystem; @code{e2fsck} does this in
+pass 2 of its operations, and @code{debugfs} needs to do this when it is
+trying to turn an inode number into a pathname.
 
 @deftypefun errcode_t ext2fs_init_dblist (ext2_filsys @var{fs}, ext2_dblist *@var{ret_dblist})
+
+Creates a dblist data structure and return it in @var{ret_dblist}.
 @end deftypefun
 
 @deftypefun void ext2fs_free_dblist (ext2_dblist @var{dblist})
+
+Free a dblist data structure.
 @end deftypefun
 
-@deftypefun errcode_t ext2fs_add_dir_block (ext2_dblist dblist, ino_t @var{ino}, blk_t @var{blk}, int @var{blockcnt})
+@deftypefun errcode_t ext2fs_add_dir_block (ext2_dblist @var{dblist}, ino_t @var{ino}, blk_t @var{blk}, int @var{blockcnt})
+
+Add an entry to the dblist data structure.  This call records the fact
+that block number @var{blockcnt} of directory inode @var{ino} is stored
+in block @var{blk}.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_set_dir_block (ext2_dblist @var{dblist}, ino_t @var{ino}, blk_t @var{blk}, int @var{blockcnt})
+
+Change an entry in the dblist data structure; this changes the location
+of block number @var{blockcnt} of directory indoe @var{ino} to be block
+@var{blk}. 
 @end deftypefun
 
-@deftypefun errcode_t ext2fs_dblist_iterate (ext2_dblist dblist, int (*func)(ext2_filsys @var{fs}, struct ext2_db_entry *@var{db_info}, void *@var{private}), void *@var{private})
+@deftypefun errcode_t ext2fs_dblist_iterate (ext2_dblist @var{dblist}, int (*func)(ext2_filsys @var{fs}, struct ext2_db_entry *@var{db_info}, void *@var{private}), void *@var{private})
+
+This iterator calls @var{func} for every entry in the dblist data structure.
 @end deftypefun
 
-@deftypefun errcode_t ext2fs_dblist_dir_iterate
-(ext2_dblist dblist, int flags, char *@var{block_buf}, int (*func)(ino_t @var{dir}, int  @var{entry}, struct ext2_dir_entry *@var{dirent}, int @var{offset}, int @var{blocksize}, char *@var{buf}, void *@var{private}), void *@var{private})
+@deftypefun errcode_t ext2fs_dblist_dir_iterate (ext2_dblist @var{dblist}, int flags, char *@var{block_buf}, int (*func)(ino_t @var{dir}, int  @var{entry}, struct ext2_dir_entry *@var{dirent}, int @var{offset}, int @var{blocksize}, char *@var{buf}, void *@var{private}), void *@var{private})
+
+This iterator takes reads in the directory block indicated in each
+dblist entry, and calls @var{func} for each directory entry in each
+directory block.  If @var{dblist} contains all the directory blocks in a
+filesystem, this function provides a convenient way to iterate over all
+directory entries for that filesystem.
 @end deftypefun
 
 @c ----------------------------------------------------------------------
 
-@node Byte-swapping functions, Other functions, Directory-block list management, EXT2FS Library Functions
+@node Inode count functions,  , Directory-block list management, EXT2 data abstractions
+@comment  node-name,  next,  previous,  up
+@subsection Inode count functions
+
+The icount abstraction is a specialized data type used by @code{e2fsck}
+to store how many times a particular inode is referenced by the
+filesystem.  This is used twice; once to store the actual number of times
+that the inode is reference; and once to store the claimed number of times
+the inode is referenced according to the inode structure.
+
+This abstraction is designed to be extremely efficient for storing this
+sort of information, by taking advantage of the following properties of
+inode counts, namely (1) inode counts are very often zero (because
+the inode is currrently not in use), and (2) many files have a inode
+count of 1 (because they are a file which has no additional hard links).
+
+@deftypefun errcode_t ext2fs_create_icount2(ext2_filsys @var{fs}, int @var{flags}, int @var{size}, ext2_icount_t @var{hint}, ext2_icount_t *@var{ret})
+
+Creates an icount stucture for a filesystem @var{fs}, with initial space
+for @var{size} inodes whose count is greater than 1.  The @var{flags}
+parameter is either 0 or @code{EXT2_ICOUNT_OPT_INCREMENT}, which
+indicates that icount structure should be able to increment inode counts
+quickly.  The icount structure is returned in @var{ret}.  The returned
+icount structure initially has a count of zero for all inodes.
+
+The @var{hint} parameter allows the caller to optionally pass in another
+icount structure which is used to initialize the array of inodes whose
+count is greater than 1.  It is used purely as a speed optimization so
+that the icount structure can determine in advance which inodes are
+likely to contain a count grater than 1.
+@end deftypefun
+
+@deftypefun void ext2fs_free_icount(ext2_icount_t @var{icount})
+
+Frees an icount structure.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_icount_fetch(ext2_icount_t @var{icount}, ino_t @var{ino}, __u16 *@var{ret})
+
+Returns in @var{ret} fetches the count for a particular inode @var{ino}.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_icount_increment(ext2_icount_t @var{icount}, ino_t @var{ino}, __u16 *@var{ret})
+
+Increments the ref count for inode @var{ino}.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_icount_decrement(ext2_icount_t @var{icount}, ino_t @var{ino}, __u16 *@var{ret})
+
+Decrements the ref count for inode @var{ino}.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_icount_store(ext2_icount_t @var{icount}, ino_t @var{ino}, __u16 @var{count})
+
+Sets the reference count for inode @var{ino} to be @var{count}.
+@end deftypefun
+
+@deftypefun ino_t ext2fs_get_icount_size(ext2_icount_t @var{icount})
+
+Returns the current number of inodes in @var{icount} which has a count
+greater than 1.
+@end deftypefun
+
+@deftypefun errcode_t ext2fs_icount_validate(ext2_icount_t @var{icount}, FILE *@var{f})
+
+Validates the internal rep invariant of @var{icount}; if there are any
+problems, print out debugging information to @var{f}.  This function is
+intended for debugging and testing use only.
+@end deftypefun
+
+
+@c ----------------------------------------------------------------------
+
+@node Byte-swapping functions, Other functions, EXT2 data abstractions, EXT2FS Library Functions
 @comment  node-name,  next,  previous,  up
 @section Byte-swapping functions
 
@@ -896,11 +1023,29 @@ Return the first inode or block which is stored in the bitmap.
 @deftypefun errcode_t ext2fs_check_if_mounted (const char *@var{file}, int *@var{mount_flags})
 @end deftypefun
 
+/* version.c */
 
-/* valid_blk.c */
-@deftypefun int ext2_inode_has_valid_blocks (struct ext2_inode *@var{inode})
+@deftypefun int ext2fs_get_library_version(const char **@var{ver_string}, const char **@var{date_string})
+
+This function returns the current version of the ext2 library.  The
+return value contains an integer version code, which consists of the
+major version number of the library multiplied by 100, plus the minor
+version number of the library.  Hence, if the library version is 1.08,
+the returned value will be 108.
+
+If @var{ver_string} and/or @var{date_string} are non-NULL, they will be
+set to point at a constant string containing the library version and/or
+release date, respectively.
 @end deftypefun
 
+@deftypefun int ext2fs_parse_version_string(const char *@var{ver_string})
+
+This function takes a version string which may included in an
+application and returns a version code using the same algorithm used by
+@code{ext2fs_get_library_version}.  It can be used by programs included
+in the @code{e2fsprogs} distribution to assure that they are using an
+up-to-date ext2 shared library.
+@end deftypefun
 
 /* inline functions */
 @deftypefun int ext2fs_group_of_blk (ext2_filsys @var{fs}, blk_t @var{blk})
index d37988d..51db19b 100644 (file)
@@ -1,3 +1,38 @@
+Thu Apr 10 13:51:16 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * pass1b.c (clone_file_block): If we clone a directory, we need to
+               update the dblist entry so that we check (and correct) the
+               right directory block.
+
+Sun Apr  6 09:13:12 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * pass1.c (process_block): Don't clear blocks references to
+               filesystem metadata; let pass 1B handle this case.
+
+       * problem.c, problem.h: Add new problem, PR_1B_SHARE_METADATA.
+
+       * pass1b.c (pass1d): Deal with a block which is shared with
+               filesystem metadata.
+
+       * e2fsck.h: Make block_illegal_map be a global variable
+
+Sat Apr  5 11:51:58 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * e2fsck.c, pass1.c (mark_table_blocks): Support the sparse_super
+               feature.
+               (get_backup_sb): New function which attempts to obtain the
+               correct backup superblock (if possible).
+
+Fri Apr  4 10:46:26 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * e2fsck.c (main): Check the version of the library, and warn if
+               the library is out of date; this happens generally due to
+               users who manually install e2fsprogs.
+
+       * pass1.c (pass1_get_blocks): If the passed in inode number for
+               get_blocks isn't what we're expecting pass back
+               EXT2_ET_CALLBACK_NOT_HANDLED.
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
index 9cebae4..c40a442 100644 (file)
@@ -216,6 +216,13 @@ static void sync_disks(NOARGS)
        sync();
 }
 
+static blk_t get_backup_sb(ext2_filsys fs)
+{
+       if (!fs || !fs->super)
+               return 8193;
+       return fs->super->s_blocks_per_group + 1;
+}
+
 #define MIN_CHECK 1
 #define MAX_CHECK 2
 
@@ -224,21 +231,22 @@ static const char *corrupt_msg =
 "filesystem.  If the device is valid and it really contains an ext2\n"
 "filesystem (and not swap or ufs or something else), then the superblock\n"
 "is corrupt, and you might try running e2fsck with an alternate superblock:\n"
-"    e2fsck -b 8193 <device>\n\n";
+"    e2fsck -b %d <device>\n\n";
 
-static void check_super_value(const char *descr, unsigned long value,
-                             int flags, unsigned long min, unsigned long max)
+static void check_super_value(ext2_filsys fs, const char *descr,
+                             unsigned long value, int flags,
+                             unsigned long min, unsigned long max)
 {
        if (((flags & MIN_CHECK) && (value < min)) ||
            ((flags & MAX_CHECK) && (value > max))) {
                printf("Corruption found in superblock.  (%s = %lu).\n",
                       descr, value);
-               printf(corrupt_msg);
+               printf(corrupt_msg, get_backup_sb(fs));
                fatal_error(0);
        }
 }
 
-static void relocate_hint(void)
+static void relocate_hint(ext2_filsys fs)
 {
        static hint_issued = 0;
 
@@ -252,9 +260,9 @@ static void relocate_hint(void)
        printf("Note: if there is several inode or block bitmap blocks\n"
               "which require relocation, or one part of the inode table\n"
               "which must be moved, you may wish to try running e2fsck\n"
-              "the '-b 8193' option first.  The problem may lie only with\n"
-              "the primary block group descriptor, and the backup block\n"
-              "group descriptor may be OK.\n\n");
+              "with the '-b %d' option first.  The problem may lie only\n"
+              "with the primary block group descriptor, and the backup\n"
+              "block group descriptor may be OK.\n\n", get_backup_sb(fs));
        hint_issued = 1;
 }
 
@@ -274,24 +282,24 @@ static void check_super_block(ext2_filsys fs)
        /*
         * Verify the super block constants...
         */
-       check_super_value("inodes_count", s->s_inodes_count,
+       check_super_value(fs, "inodes_count", s->s_inodes_count,
                          MIN_CHECK, 1, 0);
-       check_super_value("blocks_count", s->s_blocks_count,
+       check_super_value(fs, "blocks_count", s->s_blocks_count,
                          MIN_CHECK, 1, 0);
-       check_super_value("first_data_block", s->s_first_data_block,
+       check_super_value(fs, "first_data_block", s->s_first_data_block,
                          MAX_CHECK, 0, s->s_blocks_count);
-       check_super_value("log_frag_size", s->s_log_frag_size,
+       check_super_value(fs, "log_frag_size", s->s_log_frag_size,
                          MAX_CHECK, 0, 2);
-       check_super_value("log_block_size", s->s_log_block_size,
+       check_super_value(fs, "log_block_size", s->s_log_block_size,
                          MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
                          2);
-       check_super_value("frags_per_group", s->s_frags_per_group,
+       check_super_value(fs, "frags_per_group", s->s_frags_per_group,
                          MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
-       check_super_value("blocks_per_group", s->s_blocks_per_group,
+       check_super_value(fs, "blocks_per_group", s->s_blocks_per_group,
                          MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
-       check_super_value("inodes_per_group", s->s_inodes_per_group,
+       check_super_value(fs, "inodes_per_group", s->s_inodes_per_group,
                          MIN_CHECK, 1, 0);
-       check_super_value("r_blocks_count", s->s_r_blocks_count,
+       check_super_value(fs, "r_blocks_count", s->s_r_blocks_count,
                          MAX_CHECK, 0, s->s_blocks_count);
 
        retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
@@ -326,7 +334,7 @@ static void check_super_block(ext2_filsys fs)
                printf("Superblock blocks_per_group = %u, should "
                       "have been %u\n", s->s_blocks_per_group,
                       should_be);
-               printf(corrupt_msg);
+               printf(corrupt_msg, get_backup_sb(fs));
                fatal_error(0);
        }
 
@@ -335,7 +343,7 @@ static void check_super_block(ext2_filsys fs)
                printf("Superblock first_data_block = %u, should "
                       "have been %u\n", s->s_first_data_block,
                       should_be);
-               printf(corrupt_msg);
+               printf(corrupt_msg, get_backup_sb(fs));
                fatal_error(0);
        }
 
@@ -352,7 +360,7 @@ static void check_super_block(ext2_filsys fs)
                        last_block = fs->super->s_blocks_count;
                if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
                    (fs->group_desc[i].bg_block_bitmap >= last_block)) {
-                       relocate_hint();
+                       relocate_hint(fs);
                        pctx.blk = fs->group_desc[i].bg_block_bitmap;
                        if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) {
                                fs->group_desc[i].bg_block_bitmap = 0;
@@ -362,7 +370,7 @@ static void check_super_block(ext2_filsys fs)
                }
                if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
                    (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
-                       relocate_hint();
+                       relocate_hint(fs);
                        pctx.blk = fs->group_desc[i].bg_inode_bitmap;
                        if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) {
                                fs->group_desc[i].bg_inode_bitmap = 0;
@@ -373,7 +381,7 @@ static void check_super_block(ext2_filsys fs)
                if ((fs->group_desc[i].bg_inode_table < first_block) ||
                    ((fs->group_desc[i].bg_inode_table +
                      fs->inode_blocks_per_group - 1) >= last_block)) {
-                       relocate_hint();
+                       relocate_hint(fs);
                        pctx.blk = fs->group_desc[i].bg_inode_table;
                        if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) {
                                fs->group_desc[i].bg_inode_table = 0;
@@ -591,6 +599,9 @@ static void PRS(int argc, char *argv[])
                }
        }
 }
+
+static const char *my_ver_string = E2FSPROGS_VERSION;
+static const char *my_ver_date = E2FSPROGS_DATE;
                                        
 int main (int argc, char *argv[])
 {
@@ -600,6 +611,8 @@ int main (int argc, char *argv[])
        ext2_filsys     fs = 0;
        io_manager      io_ptr;
        struct ext2fs_sb *s;
+       const char      *lib_ver_date;
+       int             my_ver, lib_ver;
        
 #ifdef MTRACE
        mtrace();
@@ -607,6 +620,13 @@ int main (int argc, char *argv[])
 #ifdef MCHECK
        mcheck(0);
 #endif
+       my_ver = ext2fs_parse_version_string(my_ver_string);
+       lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
+       if (my_ver > lib_ver) {
+               fprintf( stderr, "Error: ext2fs library version "
+                       "out of date!\n");
+               show_version_only++;
+       }
        
        init_resource_track(&global_rtrack);
 
@@ -614,12 +634,12 @@ int main (int argc, char *argv[])
 
        if (!preen || show_version_only)
                fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
-                        E2FSPROGS_VERSION, E2FSPROGS_DATE,
-                        EXT2FS_VERSION, EXT2FS_DATE);
+                        my_ver_string, my_ver_date, EXT2FS_VERSION,
+                        EXT2FS_DATE);
 
        if (show_version_only) {
-               fprintf(stderr, "\tUsing %s\n",
-                       error_message(EXT2_ET_BASE));
+               fprintf(stderr, "\tUsing %s, %s\n",
+                       error_message(EXT2_ET_BASE), lib_ver_date);
                exit(0);
        }
        
@@ -663,7 +683,7 @@ restart:
                        printf("%s trying backup blocks...\n",
                               retval ? "Couldn't find ext2 superblock," :
                               "Group descriptors look bad...");
-                       superblock = 8193;
+                       superblock = get_backup_sb(fs);
                        if (fs)
                                ext2fs_close(fs);
                        goto restart;
@@ -683,7 +703,7 @@ restart:
                else if (retval == ENXIO)
                        printf("Possibly non-existent or swap device?\n");
                else
-                       printf(corrupt_msg);
+                       printf(corrupt_msg, get_backup_sb(fs));
                fatal_error(0);
        }
 #ifdef EXT2_CURRENT_REV
@@ -695,18 +715,23 @@ restart:
        }
 #endif
        /*
-        * Check for compatibility with the feature sets.  We have to
-        * check because we need to be more stringent than ext2fs_open
+        * Check for compatibility with the feature sets.  We need to
+        * be more stringent than ext2fs_open().
         */
        s = (struct ext2fs_sb *) fs->super;
-       if (s->s_feature_compat || s->s_feature_incompat ||
-           s->s_feature_ro_compat) {
+       if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
+           (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
                com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
-                       " (%s)", filesystem_name);
+                       "(%s)", filesystem_name);
        get_newer:
                printf ("Get a newer version of e2fsck!\n");
                fatal_error(0);
        }
+       if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
+               com_err(program_name, EXT2_ET_RO_UNSUPP_FEATURE,
+                       "(%s)", filesystem_name);
+               goto get_newer;
+       }
        
        /*
         * If the user specified a specific superblock, presumably the
index 9eb0dad..9efefa3 100644 (file)
@@ -85,6 +85,7 @@ extern ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
 
 extern ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
 extern ext2fs_block_bitmap block_dup_map; /* Blocks which are used by more than once */
+extern ext2fs_block_bitmap block_illegal_map; /* Meta-data blocks */
 
 extern const char *fix_msg[2]; /* Fixed or ignored! */
 extern const char *clear_msg[2]; /* Cleared or ignored! */
index 2b05867..2c760a9 100644 (file)
@@ -217,7 +217,7 @@ void pass1(ext2_filsys fs)
                        "while allocating block_illegal_map");
                fatal_error(0);
        }
-       retval = ext2fs_create_icount(fs, 0, 0, &inode_link_info);
+       retval = ext2fs_create_icount2(fs, 0, 0, 0, &inode_link_info);
        if (retval) {
                com_err("ext2fs_create_icount", retval,
                        "while creating inode_link_info");
@@ -821,8 +821,11 @@ int process_block(ext2_filsys fs,
        if (blk < fs->super->s_first_data_block ||
            blk >= fs->super->s_blocks_count)
                problem = PR_1_ILLEGAL_BLOCK_NUM;
-       else if (ext2fs_test_block_bitmap(block_illegal_map, blk))
-               problem = PR_1_BLOCK_OVERLAPS_METADATA;
+#if 0
+       else
+               if (ext2fs_test_block_bitmap(block_illegal_map, blk))
+                       problem = PR_1_BLOCK_OVERLAPS_METADATA;
+#endif
 
        if (problem) {
                p->num_illegal_blocks++;
@@ -1184,21 +1187,23 @@ static void mark_table_blocks(ext2_filsys fs)
                                     fs->group_desc[i].bg_inode_bitmap);
                        }
                }
-                   
-               /*
-                * Mark this group's copy of the superblock
-                */
-               ext2fs_mark_block_bitmap(block_found_map, block);
-               ext2fs_mark_block_bitmap(block_illegal_map, block);
+
+               if (ext2fs_bg_has_super(fs, i)) {
+                       /*
+                        * Mark this group's copy of the superblock
+                        */
+                       ext2fs_mark_block_bitmap(block_found_map, block);
+                       ext2fs_mark_block_bitmap(block_illegal_map, block);
                
-               /*
-                * Mark this group's copy of the descriptors
-                */
-               for (j = 0; j < fs->desc_blocks; j++) {
-                       ext2fs_mark_block_bitmap(block_found_map,
-                                                block + j + 1);
-                       ext2fs_mark_block_bitmap(block_illegal_map,
-                                                block + j + 1);
+                       /*
+                        * Mark this group's copy of the descriptors
+                        */
+                       for (j = 0; j < fs->desc_blocks; j++) {
+                               ext2fs_mark_block_bitmap(block_found_map,
+                                                        block + j + 1);
+                               ext2fs_mark_block_bitmap(block_illegal_map,
+                                                        block + j + 1);
+                       }
                }
                block += fs->super->s_blocks_per_group;
        }
@@ -1214,15 +1219,12 @@ errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
 {
        int     i;
        
-       if (ino == stashed_ino) {
-               for (i=0; i < EXT2_N_BLOCKS; i++)
-                       blocks[i] = stashed_inode->i_block[i];
-               return 0;
-       }
-       printf("INTERNAL ERROR: pass1_get_blocks: unexpected inode #%lu\n",
-              ino);
-       printf("\t(was expecting %lu)\n", stashed_ino);
-       exit(FSCK_ERROR);
+       if (ino != stashed_ino)
+               return EXT2_ET_CALLBACK_NOTHANDLED;
+
+       for (i=0; i < EXT2_N_BLOCKS; i++)
+               blocks[i] = stashed_inode->i_block[i];
+       return 0;
 }
 
 errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode)
index 27ca98b..50865c1 100644 (file)
@@ -277,6 +277,7 @@ int process_pass1b_block(ext2_filsys fs,
 struct search_dir_struct {
        int             count;
        ino_t           first_inode;
+       ino_t           max_inode;
 };
 
 static int search_dirent_proc(ino_t dir, int entry,
@@ -287,6 +288,10 @@ static int search_dirent_proc(ino_t dir, int entry,
        struct search_dir_struct *sd = private;
        struct dup_inode        *p;
        
+       if (dirent->inode > sd->max_inode)
+               /* Should abort this inode, but not everything */
+               return 0;       
+
        if (!dirent->inode || (entry < DIRENT_OTHER_FILE) ||
            !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
                return 0;
@@ -332,6 +337,7 @@ void pass1c(ext2_filsys fs, char *block_buf)
         */
        sd.count = inodes_left;
        sd.first_inode = EXT2_FIRST_INODE(fs->super);
+       sd.max_inode = fs->super->s_inodes_count;
        ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
                                  search_dirent_proc, &sd);
 }      
@@ -345,6 +351,7 @@ static void pass1d(ext2_filsys fs, char *block_buf)
        int     i;
        errcode_t       retval;
        int     file_ok;
+       int     meta_data = 0;
        struct problem_context pctx;
        
        printf("Pass 1D: Reconciling duplicate blocks\n");
@@ -376,6 +383,12 @@ static void pass1d(ext2_filsys fs, char *block_buf)
                                continue;
                        if (q->num_bad > 1)
                                file_ok = 0;
+                       if (ext2fs_test_block_bitmap(block_illegal_map,
+                                                    q->block)) {
+                               file_ok = 0;
+                               meta_data = 1;
+                       }
+                       
                        /*
                         * Add all inodes used by this block to the
                         * shared[] --- which is a unique list, so
@@ -402,11 +415,14 @@ static void pass1d(ext2_filsys fs, char *block_buf)
                pctx.ino = p->ino;
                pctx.dir = p->dir;
                pctx.blkcount = p->num_dupblocks;
-               pctx.num = shared_len;
+               pctx.num = meta_data ? shared_len+1 : shared_len;
                fix_problem(fs, PR_1B_DUP_FILE, &pctx);
                pctx.blkcount = 0;
                pctx.num = 0;
                
+               if (meta_data)
+                       fix_problem(fs, PR_1B_SHARE_METADATA, &pctx);
+               
                for (i = 0; i < shared_len; i++) {
                        for (s = dup_ino; s; s = s->next)
                                if (s->ino == shared[i])
@@ -506,6 +522,7 @@ static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
 
 struct clone_struct {
        errcode_t       errcode;
+       ino_t           dir;
        char    *buf;
 };
 
@@ -533,6 +550,14 @@ static int clone_file_block(ext2_filsys fs,
                                cs->errcode = retval;
                                return BLOCK_ABORT;
                        }
+                       if (cs->dir) {
+                               retval = ext2fs_set_dir_block(fs->dblist,
+                                     cs->dir, new_block, blockcnt);
+                               if (retval) {
+                                       cs->errcode = retval;
+                                       return BLOCK_ABORT;
+                               }
+                       }
                        retval = io_channel_read_blk(fs->io, *block_nr, 1,
                                                     cs->buf);
                        if (retval) {
@@ -569,8 +594,12 @@ static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
 
        cs.errcode = 0;
        cs.buf = malloc(fs->blocksize);
+       cs.dir = 0;
        if (!cs.buf)
                return ENOMEM;
+
+       if (ext2fs_test_inode_bitmap(inode_dir_map, dp->ino))
+               cs.dir = dp->ino;
        
        retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
                                      clone_file_block, &cs);
index 0032c85..8822e8f 100644 (file)
@@ -86,9 +86,8 @@ void pass2(ext2_filsys fs)
 
        if (!preen)
                printf("Pass 2: Checking directory structure\n");
-       size = ext2fs_get_icount_size(inode_link_info) + 10;
-       retval = ext2fs_create_icount(fs, EXT2_ICOUNT_OPT_INCREMENT,
-                                     size, &inode_count);
+       retval = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
+                                      0, inode_link_info, &inode_count);
        if (retval) {
                com_err("ext2fs_create_icount", retval,
                        "while creating inode_count");
index 14908ad..2752633 100644 (file)
@@ -191,6 +191,10 @@ static struct e2fsck_problem problem_table[] = {
          "\t%Q (@i #%i, mod time %IM)\n",
          PROMPT_FIX, PR_MSG_ONLY },
          
+       /* File sharing blocks with filesystem metadata  */     
+       { PR_1B_SHARE_METADATA,
+         "\t<filesystem metadata>\n",
+         PROMPT_FIX, PR_MSG_ONLY },
 
        /* Pass 2 errors */
 
index 91da479..e41cee1 100644 (file)
@@ -125,6 +125,9 @@ struct e2fsck_problem {
 /* List of files sharing duplicate blocks */   
 #define PR_1B_DUP_FILE_LIST    0x011002
 
+/* File sharing blocks with filesystem metadata  */    
+#define PR_1B_SHARE_METADATA   0x011003
+
 /*
  * Pass 2 errors
  */
index 649f7de..a045425 100644 (file)
 #define EXT2FS_VERSION         "0.5b"
 
 /*
+ * Debug code
+ */
+#ifdef EXT2FS_DEBUG
+#      define ext2_debug(f, a...)      { \
+                                       printk ("EXT2-fs DEBUG (%s, %d): %s:", \
+                                               __FILE__, __LINE__, __FUNCTION__); \
+                                       printk (f, ## a); \
+                                       }
+#else
+#      define ext2_debug(f, a...)      /**/
+#endif
+
+/*
  * Special inodes numbers
  */
 #define        EXT2_BAD_INO             1      /* Bad blocks inode */
@@ -47,7 +60,9 @@
 #define EXT2_ACL_DATA_INO       4      /* ACL inode */
 #define EXT2_BOOT_LOADER_INO    5      /* Boot loader inode */
 #define EXT2_UNDEL_DIR_INO      6      /* Undelete directory inode */
-#define EXT2_FIRST_INO         11      /* First non reserved inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO        11
 
 /*
  * The second extended file system magic number
 #else
 # define EXT2_BLOCK_SIZE_BITS(s)       ((s)->s_log_block_size + 10)
 #endif
-#define        EXT2_INODES_PER_BLOCK(s)        (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
 #ifdef __KERNEL__
 #define        EXT2_ADDR_PER_BLOCK_BITS(s)     ((s)->u.ext2_sb.s_addr_per_block_bits)
-#define        EXT2_INODES_PER_BLOCK_BITS(s)   ((s)->u.ext2_sb.s_inodes_per_block_bits)
+#define EXT2_INODE_SIZE(s)             ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s)              ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                EXT2_GOOD_OLD_INODE_SIZE : \
+                                (s)->s_inode_size)
+#define EXT2_FIRST_INO(s)      (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                EXT2_GOOD_OLD_FIRST_INO : \
+                                (s)->s_first_ino)
 #endif
 
 /*
@@ -167,7 +189,9 @@ struct ext2_group_desc
 #define EXT2_IMMUTABLE_FL              0x00000010 /* Immutable file */
 #define EXT2_APPEND_FL                 0x00000020 /* writes to file may only append */
 #define EXT2_NODUMP_FL                 0x00000040 /* do not dump file */
-
+#define EXT2_NOATIME_FL                        0x00000080 /* do not update atime */
+#define EXT2_RESERVED_FL               0x80000000 /* reserved for ext2 lib */
+       
 /*
  * ioctl commands
  */
@@ -314,14 +338,36 @@ struct ext2_super_block {
        __u16   s_magic;                /* Magic signature */
        __u16   s_state;                /* File system state */
        __u16   s_errors;               /* Behaviour when detecting errors */
-       __u16   s_pad;
+       __u16   s_minor_rev_level;      /* minor revision level */
        __u32   s_lastcheck;            /* time of last check */
        __u32   s_checkinterval;        /* max. time between checks */
        __u32   s_creator_os;           /* OS */
        __u32   s_rev_level;            /* Revision level */
        __u16   s_def_resuid;           /* Default uid for reserved blocks */
        __u16   s_def_resgid;           /* Default gid for reserved blocks */
-       __u32   s_reserved[235];        /* Padding to the end of the block */
+       /*
+        * These fields are for EXT2_DYNAMIC_REV superblocks only.
+        *
+        * Note: the difference between the compatible feature set and
+        * the incompatible feature set is that if there is a bit set
+        * in the incompatible feature set that the kernel doesn't
+        * know about, it should refuse to mount the filesystem.
+        * 
+        * e2fsck's requirements are more strict; if it doesn't know
+        * about a feature in either the compatible or incompatible
+        * feature set, it must abort and not try to meddle with
+        * things it doesn't understand...
+        */
+       __u32   s_first_ino;            /* First non-reserved inode */
+       __u16   s_inode_size;           /* size of inode structure */
+       __u16   s_block_group_nr;       /* block group # of this superblock */
+       __u32   s_feature_compat;       /* compatible feature set */
+       __u32   s_feature_incompat;     /* incompatible feature set */
+       __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
+       __u8    s_uuid[16];             /* 128-bit uuid for volume */
+       char    s_volume_name[16];      /* volume name */
+       char    s_last_mounted[64];     /* directory where last mounted */
+       __u32   s_reserved[206];        /* Padding to the end of the block */
 };
 
 /*
@@ -337,8 +383,22 @@ struct ext2_super_block {
  * Revision levels
  */
 #define EXT2_GOOD_OLD_REV      0       /* The good old (original) format */
+#define EXT2_DYNAMIC_REV       1       /* V2 format w/ dynamic inode sizes */
 
 #define EXT2_CURRENT_REV       EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV      EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
+
+#define EXT2_FEATURE_COMPAT_SUPP       0
+#define EXT2_FEATURE_INCOMPAT_SUPP     0
+#define EXT2_FEATURE_RO_COMPAT_SUPP    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
 
 /*
  * Default values for user and/or group using reserved blocks
@@ -391,9 +451,9 @@ struct ext2_dir_entry {
 extern int ext2_permission (struct inode *, int);
 
 /* balloc.c */
-extern int ext2_new_block (struct super_block *, unsigned long,
-                          __u32 *, __u32 *);
-extern void ext2_free_blocks (struct super_block *, unsigned long,
+extern int ext2_new_block (const struct inode *, unsigned long,
+                          __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
                              unsigned long);
 extern unsigned long ext2_count_free_blocks (struct super_block *);
 extern void ext2_check_blocks_bitmap (struct super_block *);
@@ -414,7 +474,7 @@ extern int ext2_write (struct inode *, struct file *, char *, int);
 extern int ext2_sync_file (struct inode *, struct file *);
 
 /* ialloc.c */
-extern struct inode * ext2_new_inode (const struct inode *, int);
+extern struct inode * ext2_new_inode (const struct inode *, int, int *);
 extern void ext2_free_inode (struct inode *);
 extern unsigned long ext2_count_free_inodes (struct super_block *);
 extern void ext2_check_inodes_bitmap (struct super_block *);
@@ -448,7 +508,7 @@ extern int ext2_symlink (struct inode *, const char *, int, const char *);
 extern int ext2_link (struct inode *, struct inode *, const char *, int);
 extern int ext2_mknod (struct inode *, const char *, int, int, int);
 extern int ext2_rename (struct inode *, const char *, int,
-                       struct inode *, const char *, int);
+                       struct inode *, const char *, int, int);
 
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
@@ -462,6 +522,7 @@ extern void ext2_put_super (struct super_block *);
 extern void ext2_write_super (struct super_block *);
 extern int ext2_remount (struct super_block *, int *, char *);
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int init_ext2_fs(void);
 extern void ext2_statfs (struct super_block *, struct statfs *, int);
 
 /* truncate.c */
index 9b18c36..1329eb3 100644 (file)
@@ -1,3 +1,8 @@
+Sat Apr  5 11:48:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * ls.c (list_super): Display the filesystem revision and any
+               features that might be implemented.
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
index f78c98d..b51fb88 100644 (file)
@@ -34,13 +34,13 @@ LIBDIR= e2p
 DLL_ADDRESS = 0x66980000
 DLL_JUMPSIZE = 0x1000
 DLL_GOTSIZE  = 0x1000
-DLL_VERSION = 1.2
+DLL_VERSION = 1.3
 DLL_IMAGE = libe2p
 DLL_STUB = libe2p
 DLL_MYDIR = e2p
 DLL_INSTALL_DIR = $(libdir)
 
-ELF_VERSION = 2.2
+ELF_VERSION = 2.3
 ELF_SO_VERSION = 2
 ELF_IMAGE = libe2p
 ELF_MYDIR = e2p
index a132047..2cbe3d5 100644 (file)
@@ -76,6 +76,10 @@ struct ext2fs_sb {
        __u32   s_reserved[206];        /* Padding to the end of the block */
 };
 
+#ifndef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
+#endif
+
 static void print_user (unsigned short uid)
 {
        struct passwd *pw;
@@ -164,8 +168,6 @@ void list_super (struct ext2_super_block * s)
                                    EXT2_INODE_SIZE(s)) +
                                   EXT2_BLOCK_SIZE(s) - 1) /
                                  EXT2_BLOCK_SIZE(s));
-       printf ("Filesystem magic number:  0x%04X\n", s->s_magic);
-       printf ("Filesystem revision #:    %d\n", s->s_rev_level);
        if (sb->s_volume_name[0]) {
                memset(buf, 0, sizeof(buf));
                strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name));
@@ -183,6 +185,22 @@ void list_super (struct ext2_super_block * s)
        } else
                strcpy(buf, "<none>");
        printf("Filesystem UUID:          %s\n", buf);
+       printf ("Filesystem magic number:  0x%04X\n", s->s_magic);
+       printf ("Filesystem revision #:    %d", s->s_rev_level);
+       if (s->s_rev_level == EXT2_GOOD_OLD_REV) {
+               printf(" (original)\n");
+#ifdef EXT2_DYNAMIC_REV
+       } else if (s->s_rev_level == EXT2_DYNAMIC_REV) {
+               printf(" (dynamic)\n");
+#endif
+       } else
+               printf("\n");
+       printf ("Filesystem features:      ");
+       if (s->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+               printf("sparse_super");
+       else
+               printf("(none)");
+       printf("\n");
        printf ("Filesystem state:        ");
        print_fs_state (stdout, s->s_state);
        printf ("\n");
index dd6da6a..e191b7d 100644 (file)
@@ -1,3 +1,73 @@
+Thu Apr 10 13:15:15 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * dblist.c (ext2fs_set_dir_block): New function which sets the
+               block of a dblist entry, given the directory inode and
+               blockcnt.
+
+Sat Apr  5 12:42:42 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * alloc_tables.c (ext2fs_allocate_tables): Allocate the bitmap and
+               inode bitmaps at staggered locations across the block
+               groups, to avoid concentrating the bitmaps on a small
+               number of disks when using striped RAID arrays.
+
+       * initialize.c (ext2fs_initialize): By default, choose the maximum
+               possible number of blocks per group (based on the size of
+               the bitmaps in the blocksize).
+
+Fri Apr  4 11:28:16 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * initialize.c (ext2fs_initialize): Add support for
+               EXT2_COMPAT_SPARSE_SUPER feature.
+
+       * closefs.c (ext2fs_bg_has_super): New function to determine
+               whether or a particular block group should have a
+               superblock and block group descriptor.  Used for the
+               EXT2_COMPAT_SPARSE_SUPER feature is turned on.
+               (ext2fs_flush):  Check ext2fs_bg_has_super to see whether
+               or not the superblock should be written out for the block
+               group. 
+
+       * ext2fs.h (EXT2_COMPAT_SPARSE_SUPER): Define compatibility flag
+               for sparse duplicate superblocks.
+
+       * version.c (ext2fs_get_library_version): New function which
+               returns the library version.
+
+       * version.c (ext2fs_parse_version_string): New function which
+               parses a version string and returns a version number,
+               so application programs can compare version numbers as
+               integers.
+
+Wed Mar 26 00:43:52 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * icount.c (ext2fs_create_icount): Change function so that it also
+               takes a new argument which contains a "hint" icount
+               structure.  This "hint" icount allows the create function
+               to set up the sorted list in advance.  This reduces
+               significantly the amount of data moving needed to insert
+               these inodes into the list later.
+       
+       * icount.c (ext2fs_icount_validate): New function which validates
+               that the icount structure's rep invariant.
+
+       * icount.c (get_icount_el): Completely revamped implementation
+               to subsume put_icount_el().  Put_icount_el() used to
+               use an O(N) implementation to insert in the middle
+               of the icount list.  It now uses a O(ln N) to search
+               for where the icount should be inserted, and then uses
+               a memcpy to move the list down (instead of a for loop).
+       
+       * icount.c (ext2fs_icount_fetch, ext2fs_icount_store,
+               ext2fs_icount_increment, ext2fs_icount_decrement): Check
+               to see if the inode is within bounds; if it isn't, return
+               EINVAL.
+
+       * bitops.h (ext2fs_test_generic_bitmap): Fix error message given
+               when a bad inode number is passed to test_generic_bitmap
+               to be EXT2FS_TEST_ERROR instead of the wrong
+               EXT2FS_UNMARK_ERROR.
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
index 2867dce..cea8490 100644 (file)
@@ -50,7 +50,8 @@ OBJS= ext2_err.o \
        test_io.o \
        unix_io.o \
        unlink.o \
-       valid_blk.o
+       valid_blk.o \
+       version.o
 
 SRCS= ext2_err.c \
        $(srcdir)/alloc.c \
@@ -95,7 +96,8 @@ SRCS= ext2_err.c \
        $(srcdir)/test_io.c \
        $(srcdir)/unix_io.c \
        $(srcdir)/unlink.c \
-       $(srcdir)/valid_blk.c
+       $(srcdir)/valid_blk.c \
+       $(srcdir)/version.c
 
 HFILES= bitops.h ext2fs.h io.h
 
@@ -105,21 +107,21 @@ LIBDIR= ext2fs
 DLL_ADDRESS = 0x66900000
 DLL_JUMPSIZE = 0x1000
 DLL_GOTSIZE  = 0x1000
-DLL_VERSION = 1.1
+DLL_VERSION = 1.2
 DLL_IMAGE = libe2fs
 DLL_STUB = libext2fs
 DLL_LIBS = -L../.. -lcom_err
 DLL_MYDIR = ext2fs
 DLL_INSTALL_DIR = $(libdir)
 
-ELF_VERSION = 2.2
+ELF_VERSION = 2.3
 ELF_SO_VERSION = 2
 ELF_IMAGE = libext2fs
 ELF_MYDIR = ext2fs
 ELF_INSTALL_DIR = $(libdir)
 ELF_OTHER_LIBS = -lc -L../.. -lcom_err
 
-BSDLIB_VERSION = 2.0
+BSDLIB_VERSION = 2.1
 BSDLIB_IMAGE = libext2fs
 BSDLIB_MYDIR = ext2fs
 BSDLIB_INSTALL_DIR = $(libdir)
index 97bceef..4bfc91d 100644 (file)
 errcode_t ext2fs_allocate_tables(ext2_filsys fs)
 {
        errcode_t       retval;
-       blk_t           group_blk, last_blk, new_blk, blk;
+       blk_t           group_blk, start_blk, last_blk, new_blk, blk;
        int             i, j;
 
        group_blk = fs->super->s_first_data_block;
        for (i = 0; i < fs->group_desc_count; i++) {
                last_blk = group_blk + fs->super->s_blocks_per_group;
-               
                /*
-                * Allocate the block bitmap
+                * Allocate the inode table
                 */
-               retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
-                                               1, fs->block_map, &new_blk);
+               start_blk = group_blk + 3 + fs->desc_blocks;
+               retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+                                               fs->inode_blocks_per_group,
+                                               fs->block_map, &new_blk);
                if (retval)
                        return retval;
-               ext2fs_mark_block_bitmap(fs->block_map, new_blk);
-               fs->group_desc[i].bg_block_bitmap = new_blk;
+               for (j=0, blk = new_blk;
+                    j < fs->inode_blocks_per_group;
+                    j++, blk++)
+                       ext2fs_mark_block_bitmap(fs->block_map, blk);
+               fs->group_desc[i].bg_inode_table = new_blk;
 
                /*
-                * ... and the inode bitmap
+                * Allocate the block and inode bitmaps
                 */
-               retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
+               start_blk += fs->inode_blocks_per_group +
+                       ((2 * i) % (last_blk - start_blk));
+               retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
                                                1, fs->block_map, &new_blk);
                if (retval)
                        return retval;
                ext2fs_mark_block_bitmap(fs->block_map, new_blk);
-               fs->group_desc[i].bg_inode_bitmap = new_blk;
+               fs->group_desc[i].bg_block_bitmap = new_blk;
 
-               /*
-                * Finally, allocate the inode table
-                */
-               retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
-                                               fs->inode_blocks_per_group,
-                                               fs->block_map, &new_blk);
+               retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+                                               1, fs->block_map, &new_blk);
                if (retval)
                        return retval;
-               for (j=0, blk = new_blk;
-                    j < fs->inode_blocks_per_group;
-                    j++, blk++)
-                       ext2fs_mark_block_bitmap(fs->block_map, blk);
-               fs->group_desc[i].bg_inode_table = new_blk;
+               ext2fs_mark_block_bitmap(fs->block_map, new_blk);
+               fs->group_desc[i].bg_inode_bitmap = new_blk;
 
                /*
                 * Increment the start of the block group
index 24bd5a7..a20d395 100644 (file)
@@ -353,7 +353,7 @@ _INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
                                        blk_t bitno)
 {
        if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
-               ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
+               ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
                return 0;
        }
        return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
index e24b6b6..a61f878 100644 (file)
 
 #include "ext2fsP.h"
 
+static int test_root(int a, int b)
+{
+       if (a == 0)
+               return 1;
+       while (1) {
+               if (a == 1)
+                       return 1;
+               if (a % b)
+                       return 0;
+               a = a / b;
+       }
+}
+
+int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+{
+#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+       struct ext2fs_sb        *s;
+
+       s = (struct ext2fs_sb *) fs->super;
+       if (!(s->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+               return 1;
+
+       if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
+           test_root(group_block, 7))
+               return 1;
+       
+       return 0;
+#else
+       return 1;
+#endif
+}
+
 errcode_t ext2fs_flush(ext2_filsys fs)
 {
        int             i,j,maxgroup;
@@ -92,6 +124,9 @@ errcode_t ext2fs_flush(ext2_filsys fs)
        maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 :
                fs->group_desc_count;
        for (i = 0; i < maxgroup; i++) {
+               if (!ext2fs_bg_has_super(fs, i))
+                       goto next_group;
+
                if (i !=0 ) {
                        retval = io_channel_write_blk(fs->io, group_block,
                                                      -SUPERBLOCK_SIZE,
@@ -108,6 +143,7 @@ errcode_t ext2fs_flush(ext2_filsys fs)
                                goto errout;
                        group_ptr += fs->blocksize;
                }
+       next_group:
                group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
        }
 
index 72d5840..76c847f 100644 (file)
@@ -128,6 +128,28 @@ errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
 }
 
 /*
+ * Change the directory block to the directory block list
+ */
+errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
+                              int blockcnt)
+{
+       struct ext2_db_entry    *ent;
+       int                     i;
+       
+       EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+       for (i=0; i < dblist->count; i++) {
+               if ((dblist->list[i].ino != ino) ||
+                   (dblist->list[i].blockcnt != blockcnt))
+                       continue;
+               dblist->list[i].blk = blk;
+               dblist->sorted = 0;
+               return 0;
+       }
+       return ENOENT;
+}
+
+/*
  * This function iterates over the directory block list
  */
 errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
@@ -151,7 +173,6 @@ errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
                if (ret & DBLIST_ABORT)
                        return 0;
        }
-       
        return 0;
 }
 
index 825844c..6084372 100644 (file)
 00000000 T _ext2fs_icount_decrement            libext2fs       icount
 00000000 T _ext2fs_icount_store                        libext2fs       icount
 00000000 T _ext2fs_get_icount_size             libext2fs       icount
+00000000 T _ext2fs_create_icount2              libext2fs       icount
+00000000 T _ext2fs_get_library_version         libext2fs       version
+00000000 T _ext2fs_parse_version_string                libext2fs       version
+00000000 T _ext2fs_set_dir_block               libext2fs       dblist
index ce57e13..4e14fd6 100644 (file)
@@ -341,7 +341,19 @@ struct ext2fs_sb {
        char    s_last_mounted[64];     /* directory where last mounted */
        __u32   s_reserved[206];        /* Padding to the end of the block */
 };
-  
+
+/*
+ * Feature set definitions (that might not be in ext2_fs.h
+ * (was EXT2_COMPAT_SPARSE_SUPER)
+ */
+#ifndef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001
+#endif
+
+#define EXT2_LIB_FEATURE_COMPAT_SUPP   0
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP 0
+#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP        EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+
 /*
  * function prototypes
  */
@@ -442,6 +454,7 @@ extern errcode_t ext2fs_check_desc(ext2_filsys fs);
 /* closefs.c */
 extern errcode_t ext2fs_close(ext2_filsys fs);
 extern errcode_t ext2fs_flush(ext2_filsys fs);
+extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
 
 /* cmp_bitmaps.c */
 extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
@@ -461,6 +474,8 @@ errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
                                            struct ext2_db_entry *db_info,
                                            void        *private),
                                void *private);
+errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
+                              int blockcnt);
 
 /* dblist_dir.c */
 extern errcode_t
@@ -544,6 +559,8 @@ extern errcode_t ext2fs_check_directory(ext2_filsys fs, ino_t ino);
 
 /* icount.c */
 extern void ext2fs_free_icount(ext2_icount_t icount);
+extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, int size,
+                                      ext2_icount_t hint, ext2_icount_t *ret);
 extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, int size,
                                      ext2_icount_t *ret);
 extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ino_t ino,
@@ -555,6 +572,7 @@ extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ino_t ino,
 extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ino_t ino,
                                     __u16 count);
 extern ino_t ext2fs_get_icount_size(ext2_icount_t icount);
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 
 /* ismounted.c */
 extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
@@ -621,7 +639,12 @@ extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
                              struct ext2_inode *f, int hostorder);
 
 /* valid_blk.c */
-int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
+extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
+
+/* version.c */
+extern int ext2fs_parse_version_string(const char *ver_string);
+extern int ext2fs_get_library_version(const char **ver_string,
+                                     const char **date_string);
 
 /* inline functions */
 extern void ext2fs_mark_super_dirty(ext2_filsys fs);
index b9070a9..7c68680 100644 (file)
@@ -71,13 +71,20 @@ void ext2fs_free_icount(ext2_icount_t icount)
        free(icount);
 }
 
-errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, int size,
-                              ext2_icount_t *ret)
+errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, int size,
+                               ext2_icount_t hint, ext2_icount_t *ret)
 {
        ext2_icount_t   icount;
        errcode_t       retval;
        size_t          bytes;
+       int             i;
 
+       if (hint) {
+               EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
+               if (hint->size > size)
+                       size = hint->size;
+       }
+       
        icount = malloc(sizeof(struct ext2_icount));
        if (!icount)
                return ENOMEM;
@@ -125,8 +132,18 @@ errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, int size,
        icount->cursor = 0;
        icount->num_inodes = fs->super->s_inodes_count;
 
-       *ret = icount;
+       /*
+        * Populate the sorted list with those entries which were
+        * found in the hint icount (since those are ones which will
+        * likely need to be in the sorted list this time around).
+        */
+       if (hint) {
+               for (i=0; i < hint->count; i++)
+                       icount->list[i].ino = hint->list[i].ino;
+               icount->count = hint->count;
+       }
 
+       *ret = icount;
        return 0;
 
 errout:
@@ -134,65 +151,22 @@ errout:
        return(retval);
 }
 
-/*
- * get_icount_el() --- given an inode number, try to find icount
- *     information in the sorted list.  We use a binary search...
- */
-static struct ext2_icount_el *get_icount_el(ext2_icount_t icount, ino_t ino)
+errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, int size,
+                              ext2_icount_t *ret)
 {
-       int     low, high, mid;
-
-       if (!icount || !icount->list || !icount->count)
-               return 0;
-
-       if (icount->multiple &&
-           !ext2fs_test_inode_bitmap(icount->multiple, ino))
-               return 0;
-
-       low = 0;
-       high = icount->count-1;
-       if (ino == icount->list[low].ino) {
-               icount->cursor = low+1;
-               return &icount->list[low];
-       }
-       if  (ino == icount->list[high].ino) {
-               icount->cursor = 0;
-               return &icount->list[high];
-       }
-       if (icount->cursor >= icount->count)
-               icount->cursor = 0;
-       if (ino == icount->list[icount->cursor].ino)
-               return &icount->list[icount->cursor++];
-#if 0
-       printf("Non-cursor get_icount_el: %u\n", ino);
-#endif
-       
-       while (low < high) {
-               mid = (low+high)/2;
-               if (mid == low || mid == high)
-                       break;
-               if (ino == icount->list[mid].ino) {
-                       icount->cursor = mid;
-                       return &icount->list[mid];
-               }
-               if (ino < icount->list[mid].ino)
-                       high = mid;
-               else
-                       low = mid;
-       }
-       return 0;
+       return ext2fs_create_icount2(fs, flags, size, 0, ret);
 }
 
 /*
- * put_icount_el() --- given an inode number, create a new entry in
- *     the sorted list.  This function is optimized for adding values
- *     in ascending order.
+ * insert_icount_el() --- Insert a new entry into the sorted list at a
+ *     specified position.
  */
-static struct ext2_icount_el *put_icount_el(ext2_icount_t icount, ino_t ino)
+static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
+                                           ino_t ino, int pos)
 {
        struct ext2_icount_el *el, *new_list;
        ino_t                   new_size = 0;
-       int                     i, j;
+       int                     num;
 
        if (icount->count >= icount->size) {
                if (icount->count) {
@@ -212,31 +186,112 @@ static struct ext2_icount_el *put_icount_el(ext2_icount_t icount, ino_t ino)
                icount->size = new_size;
                icount->list = new_list;
        }
+       num = icount->count - pos;
+       if (num < 0)
+               return 0;       /* should never happen */
+       if (num) {
+               memmove(&icount->list[pos+1], &icount->list[pos],
+                       sizeof(struct ext2_icount_el) * num);
+       }
+       icount->count++;
+       el = &icount->list[pos];
+       el->count = 0;
+       el->ino = ino;
+       return el;
+}
+
+/*
+ * get_icount_el() --- given an inode number, try to find icount
+ *     information in the sorted list.  If the create flag is set,
+ *     and we can't find an entry, create one in the sorted list.
+ */
+static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
+                                           ino_t ino, int create)
+{
+       float   range;
+       int     low, high, mid;
+       ino_t   lowval, highval;
+
+       if (!icount || !icount->list)
+               return 0;
 
+       if (create && ((icount->count == 0) ||
+                      (ino > icount->list[icount->count-1].ino))) {
+               return insert_icount_el(icount, ino, icount->count);
+       }
+       if (icount->count == 0)
+               return 0;
+       
+       if (icount->cursor >= icount->count)
+               icount->cursor = 0;
+       if (ino == icount->list[icount->cursor].ino)
+               return &icount->list[icount->cursor++];
+#if 0
+       printf("Non-cursor get_icount_el: %u\n", ino);
+#endif
+       low = 0;
+       high = icount->count-1;
+       while (low <= high) {
+#if 0
+               mid = (low+high)/2;
+#else
+               if (low == high)
+                       mid = low;
+               else {
+                       /* Interpolate for efficiency */
+                       lowval = icount->list[low].ino;
+                       highval = icount->list[high].ino;
+
+                       if (ino < lowval)
+                               range = 0;
+                       else if (ino > highval)
+                               range = 1;
+                       else 
+                               range = ((float) (ino - lowval)) /
+                                       (highval - lowval);
+                       mid = low + ((int) (range * (high-low)));
+               }
+#endif
+               if (ino == icount->list[mid].ino) {
+                       icount->cursor = mid+1;
+                       return &icount->list[mid];
+               }
+               if (ino < icount->list[mid].ino)
+                       high = mid-1;
+               else
+                       low = mid+1;
+       }
        /*
-        * Normally, get_icount_el is called with each inode in
-        * sequential order; but once in a while (like when pass 3
-        * needs to recreate the root directory or lost+found
-        * directory) it is called out of order.
+        * If we need to create a new entry, it should be right at
+        * low (where high will be left at low-1).
         */
-       if (icount->count && icount->list[icount->count-1].ino >= ino) {
-               for (i = icount->count-1; i > 0; i--)
-                       if (icount->list[i-1].ino < ino)
-                               break;
-               el = &icount->list[i];
-               if (el->ino != ino) {
-                       for (j = icount->count++; j > i; j--)
-                               icount->list[j] = icount->list[j-1];
-                       el->count = 0;
+       if (create)
+               return insert_icount_el(icount, ino, low);
+       return 0;
+}
+
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
+{
+       errcode_t       ret = 0;
+       int             i;
+       const char *bad = "bad icount";
+       
+       EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+       if (icount->count > icount->size) {
+               fprintf(out, "%s: count > size\n", bad);
+               return EINVAL;
+       }
+       for (i=1; i < icount->count; i++) {
+               if (icount->list[i-1].ino >= icount->list[i].ino) {
+                       fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
+                               bad, i-1, icount->list[i-1].ino,
+                               i, icount->list[i].ino);
+                       ret = EINVAL;
                }
-       } else {
-               el = &icount->list[icount->count++];
-               el->count = 0;
        }
-       el->ino = ino;
-       return el;
+       return ret;
 }
-       
 
 errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ino_t ino, __u16 *ret)
 {
@@ -244,11 +299,19 @@ errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ino_t ino, __u16 *ret)
        
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
+       if (!ino || (ino > icount->num_inodes))
+               return EINVAL;
+
        if (ext2fs_test_inode_bitmap(icount->single, ino)) {
                *ret = 1;
                return 0;
        }
-       el = get_icount_el(icount, ino);
+       if (icount->multiple &&
+           !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
+               *ret = 0;
+               return 0;
+       }
+       el = get_icount_el(icount, ino, 0);
        if (!el) {
                *ret = 0;
                return 0;
@@ -264,14 +327,19 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ino_t ino,
 
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
+       if (!ino || (ino > icount->num_inodes))
+               return EINVAL;
+
        if (ext2fs_test_inode_bitmap(icount->single, ino)) {
                /*
                 * If the existing count is 1, then we know there is
-                * no entry in the list, so use put_icount_el().
+                * no entry in the list.
                 */
-               el = put_icount_el(icount, ino);
+               el = get_icount_el(icount, ino, 1);
                if (!el)
                        return ENOMEM;
+               ext2fs_unmark_inode_bitmap(icount->single, ino);
+               el->count = 2;
        } else if (icount->multiple) {
                /*
                 * The count is either zero or greater than 1; if the
@@ -280,13 +348,10 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ino_t ino,
                 * get_icount_el().
                 */
                if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
-                       el = get_icount_el(icount, ino);
-                       if (!el) {
-                               /* should never happen */
-                               el = put_icount_el(icount, ino);
-                               if (!el)
-                                       return ENOMEM;
-                       }
+                       el = get_icount_el(icount, ino, 1);
+                       if (!el)
+                               return ENOMEM;
+                       el->count++;
                } else {
                        /*
                         * The count was zero; mark the single bitmap
@@ -303,20 +368,16 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ino_t ino,
                 * The count is either zero or greater than 1; try to
                 * find an entry in the list to determine which.
                 */
-               el = get_icount_el(icount, ino);
+               el = get_icount_el(icount, ino, 0);
                if (!el) {
                        /* No entry means the count was zero */
                        goto zero_count;
                }
-               el = put_icount_el(icount, ino);
+               el = get_icount_el(icount, ino, 1);
                if (!el)
                        return ENOMEM;
-       }
-       if (ext2fs_test_inode_bitmap(icount->single, ino)) {
-               ext2fs_unmark_inode_bitmap(icount->single, ino);
-               el->count = 2;
-       } else
                el->count++;
+       }
        if (icount->multiple)
                ext2fs_mark_inode_bitmap(icount->multiple, ino);
        if (ret)
@@ -329,6 +390,9 @@ errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ino_t ino,
 {
        struct ext2_icount_el   *el;
 
+       if (!ino || (ino > icount->num_inodes))
+               return EINVAL;
+
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
        if (ext2fs_test_inode_bitmap(icount->single, ino)) {
@@ -336,7 +400,7 @@ errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ino_t ino,
                if (icount->multiple)
                        ext2fs_unmark_inode_bitmap(icount->multiple, ino);
                else {
-                       el = get_icount_el(icount, ino);
+                       el = get_icount_el(icount, ino, 0);
                        if (el)
                                el->count = 0;
                }
@@ -345,8 +409,12 @@ errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ino_t ino,
                return 0;
        }
 
-       el = get_icount_el(icount, ino);
-       if (!el)
+       if (icount->multiple &&
+           !ext2fs_test_inode_bitmap(icount->multiple, ino))
+               return EINVAL;
+       
+       el = get_icount_el(icount, ino, 0);
+       if (!el || el->count == 0)
                return EINVAL;
 
        el->count--;
@@ -365,6 +433,9 @@ errcode_t ext2fs_icount_store(ext2_icount_t icount, ino_t ino,
 {
        struct ext2_icount_el   *el;
 
+       if (!ino || (ino > icount->num_inodes))
+               return EINVAL;
+
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
        if (count == 1) {
@@ -382,7 +453,7 @@ errcode_t ext2fs_icount_store(ext2_icount_t icount, ino_t ino,
                         */
                        ext2fs_unmark_inode_bitmap(icount->multiple, ino);
                } else {
-                       el = get_icount_el(icount, ino);
+                       el = get_icount_el(icount, ino, 0);
                        if (el)
                                el->count = 0;
                }
@@ -392,7 +463,7 @@ errcode_t ext2fs_icount_store(ext2_icount_t icount, ino_t ino,
        /*
         * Get the icount element
         */
-       el = put_icount_el(icount, ino);
+       el = get_icount_el(icount, ino, 1);
        if (!el)
                return ENOMEM;
        el->count = count;
index 6db5a0c..72f40ea 100644 (file)
@@ -58,6 +58,7 @@ errcode_t ext2fs_initialize(const char *name, int flags,
        ext2_filsys     fs;
        errcode_t       retval;
        struct ext2_super_block *super;
+       struct ext2fs_sb        *s;
        int             frags_per_block;
        int             rem;
        int             overhead = 0;
@@ -91,9 +92,12 @@ errcode_t ext2fs_initialize(const char *name, int flags,
                goto cleanup;
        }
        memset(super, 0, SUPERBLOCK_SIZE);
+       s = (struct ext2fs_sb *) super;
 
 #define set_field(field, default) (super->field = param->field ? \
                                   param->field : (default))
+#define set_ext2_field(field, default) (s->field = param->field ? \
+                                       param->field : (default))
 
        super->s_magic = EXT2_SUPER_MAGIC;
        super->s_state = EXT2_VALID_FS;
@@ -103,7 +107,13 @@ errcode_t ext2fs_initialize(const char *name, int flags,
        set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
        set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
        set_field(s_errors, EXT2_ERRORS_DEFAULT);
-
+       set_ext2_field(s_feature_compat, 0);
+       set_ext2_field(s_feature_incompat, 0);
+       set_ext2_field(s_feature_ro_compat, 0);
+       if (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)
+               return EXT2_ET_UNSUPP_FEATURE;
+       if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)
+               return EXT2_ET_RO_UNSUPP_FEATURE;
 
 #ifdef EXT2_DYNAMIC_REV
        set_field(s_rev_level, EXT2_GOOD_OLD_REV);
@@ -122,7 +132,8 @@ errcode_t ext2fs_initialize(const char *name, int flags,
        fs->fragsize = EXT2_FRAG_SIZE(super);
        frags_per_block = fs->blocksize / fs->fragsize;
        
-       set_field(s_blocks_per_group, 8192); /* default: 8192 blocks/group */
+       /* default: (fs->blocksize*8) blocks/group */
+       set_field(s_blocks_per_group, fs->blocksize*8); 
        super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
        
        super->s_blocks_count = param->s_blocks_count;
@@ -188,16 +199,6 @@ retry:
        super->s_free_inodes_count = super->s_inodes_count;
 
        /*
-        * Overhead is the number of bookkeeping blocks per group.  It
-        * includes the superblock backup, the group descriptor
-        * backups, the inode bitmap, the block bitmap, and the inode
-        * table.
-        */
-       overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
-       super->s_free_blocks_count = super->s_blocks_count -
-               super->s_first_data_block - (overhead*fs->group_desc_count);
-       
-       /*
         * See if the last group is big enough to support the
         * necessary data structures.  If not, we need to get rid of
         * it.
@@ -250,11 +251,8 @@ retry:
         * by this routine), they are accounted for nevertheless.
         */
        group_block = super->s_first_data_block;
+       super->s_free_blocks_count = 0;
        for (i = 0; i < fs->group_desc_count; i++) {
-               for (j=0; j < fs->desc_blocks+1; j++)
-                       ext2fs_mark_block_bitmap(fs->block_map,
-                                                group_block + j);
-
                if (i == fs->group_desc_count-1) {
                        numblocks = (fs->super->s_blocks_count -
                                     fs->super->s_first_data_block) %
@@ -263,8 +261,17 @@ retry:
                                numblocks = fs->super->s_blocks_per_group;
                } else
                        numblocks = fs->super->s_blocks_per_group;
-               numblocks -= 3 + fs->desc_blocks + fs->inode_blocks_per_group;
+
+               if (ext2fs_bg_has_super(fs, i)) {
+                       for (j=0; j < fs->desc_blocks+1; j++)
+                               ext2fs_mark_block_bitmap(fs->block_map,
+                                                        group_block + j);
+                       numblocks -= 1 + fs->desc_blocks;
+               }
+               
+               numblocks -= 2 + fs->inode_blocks_per_group;
                
+               super->s_free_blocks_count += numblocks;
                fs->group_desc[i].bg_free_blocks_count = numblocks;
                fs->group_desc[i].bg_free_inodes_count =
                        fs->super->s_inodes_per_group;
index 8fd5e7e..7194fb0 100644 (file)
@@ -51,6 +51,7 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
 {
        ext2_inode_scan scan;
        errcode_t       retval;
+       errcode_t (*save_get_blocks)(ext2_filsys fs, ino_t ino, blk_t *blocks);
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -59,11 +60,18 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
         * scanning functions require it.
         */
        if (fs->badblocks == 0) {
+               /*
+                * Temporarly save fs->get_blocks and set it to zero,
+                * for compatibility with old e2fsck's.
+                */
+               save_get_blocks = fs->get_blocks;
+               fs->get_blocks = 0;
                retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
                if (retval && fs->badblocks) {
                        badblocks_list_free(fs->badblocks);
                        fs->badblocks = 0;
                }
+               fs->get_blocks = save_get_blocks;
        }
 
        scan = (ext2_inode_scan) malloc(sizeof(struct ext2_struct_inode_scan));
index b2e2393..a1c0d5b 100644 (file)
@@ -126,12 +126,13 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock,
         */
        if (!(flags & EXT2_FLAG_FORCE)) {
                s = (struct ext2fs_sb *) fs->super;
-               if (s->s_feature_incompat) {
+               if (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
                        retval = EXT2_ET_UNSUPP_FEATURE;
                        goto cleanup;
                }
                if ((flags & EXT2_FLAG_RW) &&
-                   s->s_feature_ro_compat) {
+                   (s->s_feature_ro_compat &
+                    ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
                        retval = EXT2_ET_RO_UNSUPP_FEATURE;
                        goto cleanup;
                }
diff --git a/lib/ext2fs/version.c b/lib/ext2fs/version.c
new file mode 100644 (file)
index 0000000..df7236e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * version.c --- Return the version of the ext2 library
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <et/com_err.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <linux/ext2_fs.h>
+#include "ext2fs.h"
+
+#include "../../version.h"
+
+static const char *lib_version = E2FSPROGS_VERSION;
+static const char *lib_date = E2FSPROGS_DATE;
+
+int ext2fs_parse_version_string(const char *ver_string)
+{
+       const char *cp;
+       int version = 0;
+
+       for (cp = lib_version; *cp; cp++) {
+               if (!isdigit(*cp))
+                       continue;
+               version = (version * 10) + (*cp - '0');
+       }
+       return version;
+}
+
+
+int ext2fs_get_library_version(const char **ver_string,
+                              const char **date_string)
+{
+       if (ver_string)
+               *ver_string = lib_version;
+       if (date_string)
+               *date_string = lib_date;
+
+       return ext2fs_parse_version_string(lib_version);
+}
index 64f0e2a..f58e73f 100644 (file)
@@ -9,8 +9,8 @@
  * $Locker$
  *
  * $Log$
- * Revision 1.10  1997/04/29 16:15:48  tytso
- * Checked in e2fsprogs-1.07
+ * Revision 1.11  1997/04/29 17:47:28  tytso
+ * Checked in e2fsprogs 1.08.
  *
  * Revision 1.1  1993/06/03  12:31:25  tytso
  * Initial revision
index 8886779..b761fb4 100644 (file)
@@ -1,3 +1,21 @@
+Thu Apr 10 07:08:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * dumpe2fs.c (list_desc): List the offsets of the inode and block
+               bitmaps, and the inode table.  List the block boundaries
+               for the groups.
+
+Sat Apr  5 11:55:52 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * tune2fs.c (main): Implement the -s flag allows the user to
+               set and reset the sparse superblock flag.
+
+       * mke2fs.c (PRS): By default generate DYNAMIC revision
+               filesystems.  The -s flag controls whether or not the
+               sparse superblock flag is set.
+               (PRS): Change to allow the user to specify the true
+               maximum number of blocks per group to reflect the
+               blocksize. 
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
index 448e4eb..b71900e 100644 (file)
@@ -77,18 +77,27 @@ static void print_free (unsigned long group, char * bitmap,
 static void list_desc (ext2_filsys fs)
 {
        unsigned long i;
+       blk_t   group_blk, next_blk;
        char * block_bitmap = fs->block_map->bitmap;
        char * inode_bitmap = fs->inode_map->bitmap;
 
        printf ("\n");
-       for (i = 0; i < fs->group_desc_count; i++)
-       {
-               printf ("Group %lu:\n", i);
-               printf ("  Block bitmap at %u, Inode bitmap at %u, "
-                       "Inode table at %u\n",
+       group_blk = fs->super->s_first_data_block;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               next_blk = group_blk + fs->super->s_blocks_per_group;
+               if (next_blk > fs->super->s_blocks_count)
+                       next_blk = fs->super->s_blocks_count;
+               printf ("Group %lu: (Blocks %u -- %u)\n", i,
+                       group_blk, next_blk -1 );
+               printf ("  Block bitmap at %u (+%d), "
+                       "Inode bitmap at %u (+%d)\n  "
+                       "Inode table at %u (+%d)\n",
                        fs->group_desc[i].bg_block_bitmap,
+                       fs->group_desc[i].bg_block_bitmap - group_blk,
                        fs->group_desc[i].bg_inode_bitmap,
-                       fs->group_desc[i].bg_inode_table);
+                       fs->group_desc[i].bg_inode_bitmap - group_blk,
+                       fs->group_desc[i].bg_inode_table,
+                       fs->group_desc[i].bg_inode_table - group_blk);
                printf ("  %d free blocks, %d free inodes, %d directories\n",
                        fs->group_desc[i].bg_free_blocks_count,
                        fs->group_desc[i].bg_free_inodes_count,
@@ -102,6 +111,7 @@ static void list_desc (ext2_filsys fs)
                print_free (i, inode_bitmap, fs->super->s_inodes_per_group, 1);
                inode_bitmap += fs->super->s_inodes_per_group / 8;
                printf ("\n");
+               group_blk = next_blk;
        }
 }
 
index 5526551..ab139a4 100644 (file)
@@ -40,6 +40,9 @@ mke2fs \- create a Linux second extended file system
 .B \-q
 ]
 [
+.B -s sparse-super-flag
+]
+[
 .B \-v
 ]
 [
@@ -114,6 +117,11 @@ of the mke2fs executable.
 .I -q
 Quiet execution.  Useful if mke2fs is run in a script.
 .TP
+.I -s sparse-super-flag
+If sparse-super-flag is 1, then turn on the sparse superblock flag.  
+If 0, then turn off the sparse superblock flag.  (Currently, the sparse 
+superblock flag defaults to off.)
+.TP
 .I -v
 Verbose execution.
 .TP
index 3723af5..475397d 100644 (file)
@@ -486,6 +486,8 @@ static void show_stats(ext2_filsys fs)
        col_left = 0;
        for (i = 1; i < fs->group_desc_count; i++) {
                group_block += s->s_blocks_per_group;
+               if (!ext2fs_bg_has_super(fs, i))
+                       continue;
                if (!col_left--) {
                        printf("\n\t");
                        col_left = 8;
@@ -539,11 +541,14 @@ static void PRS(int argc, char *argv[])
        char    c;
        int     size;
        char    * tmp;
+       blk_t   max = 8192;
        int     inode_ratio = 4096;
        int     reserved_ratio = 5;
        errcode_t       retval;
+       int     sparse_option = -1;
        char    *oldpath = getenv("PATH");
-
+       struct ext2fs_sb *param_ext2 = (struct ext2fs_sb *) &param;
+       
        /* Update our PATH to include /sbin  */
        if (oldpath) {
                char *newpath;
@@ -560,6 +565,9 @@ static void PRS(int argc, char *argv[])
        setbuf(stderr, NULL);
        initialize_ext2_error_table();
        memset(&param, 0, sizeof(struct ext2_super_block));
+#ifdef EXT2_DYNAMIC_REV
+       param.s_rev_level = EXT2_DYNAMIC_REV;
+#endif
        
        fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n",
                 E2FSPROGS_VERSION, E2FSPROGS_DATE,
@@ -567,7 +575,7 @@ static void PRS(int argc, char *argv[])
        if (argc && *argv)
                program_name = *argv;
        while ((c = getopt (argc, argv,
-                           "b:cf:g:i:l:m:o:qr:tvI:SFL:M:")) != EOF)
+                           "b:cf:g:i:l:m:o:qr:s:tvI:SFL:M:")) != EOF)
                switch (c) {
                case 'b':
                        size = strtoul(optarg, &tmp, 0);
@@ -578,6 +586,7 @@ static void PRS(int argc, char *argv[])
                        }
                        param.s_log_block_size =
                                log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+                       max = size * 8;
                        break;
                case 'c':
                case 't':       /* Check for bad blocks */
@@ -602,12 +611,6 @@ static void PRS(int argc, char *argv[])
                                        "Illegal number for blocks per group");
                                exit(1);
                        }
-                       if (param.s_blocks_per_group < 256 ||
-                           param.s_blocks_per_group > 8192 || *tmp) {
-                               com_err(program_name, 0,
-                                       "blocks per group count out of range");
-                               exit(1);
-                       }
                        if ((param.s_blocks_per_group % 8) != 0) {
                                com_err(program_name, 0,
                                "blocks per group must be multiple of 8");
@@ -647,6 +650,9 @@ static void PRS(int argc, char *argv[])
                case 'r':
                        param.s_rev_level = atoi(optarg);
                        break;
+               case 's':
+                       sparse_option = atoi(optarg);
+                       break;
 #ifdef EXT2_DYNAMIC_REV
                case 'I':
                        param.s_inode_size = atoi(optarg);
@@ -705,6 +711,15 @@ static void PRS(int argc, char *argv[])
                }
        }
 
+       if (param.s_blocks_per_group) {
+               if (param.s_blocks_per_group < 256 ||
+                   param.s_blocks_per_group > max || *tmp) {
+                       com_err(program_name, 0,
+                               "blocks per group count out of range");
+                       exit(1);
+               }
+       }
+
        /*
         * Calculate number of inodes based on the inode ratio
         */
@@ -716,6 +731,20 @@ static void PRS(int argc, char *argv[])
         * Calculate number of blocks to reserve
         */
        param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
+
+       /*
+        * If we are using revision #1, use the sparse super feature
+        * by default
+        */
+#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+       if ((sparse_option == 1)
+#ifdef EXT2_DYNAMIC_REV
+           || (param.s_rev_level >= EXT2_DYNAMIC_REV) && (!sparse_option)
+#endif
+           ) 
+               param_ext2->s_feature_ro_compat |=
+                       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+#endif
 }
                                        
 int main (int argc, char *argv[])
index 9b92711..0e34085 100644 (file)
@@ -31,6 +31,9 @@ tune2fs \- adjust tunable filesystem parameters on second extended filesystems
 .I reserved-blocks-count
 ]
 [
+.B -s sparse-super-flag
+]
+[
 .B -u
 .I user
 ]
@@ -97,6 +100,10 @@ adjust the reserved blocks percentage on the given device.
 .I -r reserved-blocks-count
 adjust the reserved blocks count on the given device.
 .TP
+.I -s sparse_super_flag
+sets and resets the sparse_superblock flag.  The sparse_superblock feature
+saves space on really big filesystems.
+.TP
 .I -u user
 set the user who can benefit from the reserved blocks.
 .I user
index db3539e..2cd43a6 100644 (file)
@@ -63,6 +63,7 @@ int L_flag = 0;
 int m_flag = 0;
 int M_flag = 0;
 int r_flag = 0;
+int s_flag = -1;
 int u_flag = 0;
 int U_flag = 0;
 int max_mount_count, mount_count;
@@ -93,7 +94,7 @@ static volatile void usage (void)
 {
        fprintf (stderr, "Usage: %s [-c max-mounts-count] [-e errors-behavior] "
                 "[-g group]\n"
-                "\t[-i interval[d|m|w]] [-l] [-m reserved-blocks-percent]\n"
+                "\t[-i interval[d|m|w]] [-l] [-s] [-m reserved-blocks-percent]\n"
                 "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
                 "\t[-L volume-label] [-M last-mounted-dir] [-U UUID] "
                 "device\n", program_name);
@@ -117,7 +118,7 @@ void main (int argc, char ** argv)
        if (argc && *argv)
                program_name = *argv;
        initialize_ext2_error_table();
-       while ((c = getopt (argc, argv, "c:e:g:i:lm:r:u:C:L:M:U:")) != EOF)
+       while ((c = getopt (argc, argv, "c:e:g:i:lm:r:s:u:C:L:M:U:")) != EOF)
                switch (c)
                {
                        case 'c':
@@ -253,6 +254,10 @@ void main (int argc, char ** argv)
                                r_flag = 1;
                                open_flag = EXT2_FLAG_RW;
                                break;
+                       case 's':
+                               s_flag = atoi(optarg);
+                               open_flag = EXT2_FLAG_RW;
+                               break;
                        case 'u':
                                resuid = strtoul (optarg, &tmp, 0);
                                if (*tmp)
@@ -355,6 +360,48 @@ void main (int argc, char ** argv)
                printf ("Setting reserved blocks count to %lu\n",
                        reserved_blocks);
        }
+       if (s_flag == 1) {
+#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+               if (sb->s_feature_ro_compat &
+                   EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+                       fprintf(stderr, "\nThe filesystem already "
+                               " has spare superblocks.\n");
+               else {
+                       sb->s_feature_ro_compat |=
+                               EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+                       fs->super->s_state &= ~EXT2_VALID_FS;
+                       ext2fs_mark_super_dirty(fs);
+                       printf("\nSparse superblock flag set.  "
+                              "Please run e2fsck on the filesystem.\n");
+               }
+#else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
+               com_err (program_name, 0,
+                        "The -s option is not supported by this version -- "
+                        "Recompile with a newer kernel");
+#endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
+       }
+       if (s_flag == 0) {
+#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+               if (!(sb->s_feature_ro_compat &
+                     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+                       fprintf(stderr, "\nThe filesystem already "
+                               " does not support spare superblocks.\n");
+               else {
+                       sb->s_feature_ro_compat &=
+                               ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+                       fs->super->s_state &= ~EXT2_VALID_FS;
+                       fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
+                       ext2fs_mark_super_dirty(fs);
+                       printf("\nSparse superblock flag cleared.  "
+                              "Please run e2fsck on the filesystem.\n");
+               }
+#else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
+               com_err (program_name, 0,
+                        "The -s option is not supported by this version -- "
+                        "Recompile with a newer kernel");
+#endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
+       }
+       
        if (u_flag)
 #ifdef EXT2_DEF_RESUID
        {
index 8850628..4ebb21e 100644 (file)
@@ -1,3 +1,16 @@
+Wed Mar 26 09:29:25 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * e_icount_normal, e_icount_opt: New tests which validate the
+               icount abstraction.
+
+       * test_script.in: New feature; an argument of a single character
+               means do all the tests in that series.
+
+Tue Mar 18 15:11:04 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * test_config (LANG): Set the language to be C so that the brel
+               and irel tests don't fail.
+
 Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
 
        * Release of E2fsprogs version 1.07
similarity index 52%
rename from tests/defaults/r_script
rename to tests/defaults/e_script
index 43e1cc2..d1f460b 100644 (file)
@@ -8,18 +8,28 @@ if [ -f $test_dir/setup ]; then
 fi
 
 if [ "$class"x = x ]; then
-       class=`echo $test_name | sed -e 's/r_\([^_]*\)_\(.*\)/\1/'`
-       instance=`echo $test_name | sed -e 's/r_\([^_]*\)_\(.*\)/\2/'`
+       class=`echo $test_name | sed -e 's/e_\([^_]*\)_\(.*\)/\1/'`
+       instance=`echo $test_name | sed -e 's/e_\([^_]*\)_\(.*\)/\2/'`
 fi
 if [ "$OUT"x = x ]; then
        OUT=$test_name.log
 fi
 if [ "$EXPECT"x = x ]; then
-       EXPECT=$SRCDIR/progs/rel_test/expect.$class
+       EXPECT=$SRCDIR/progs/test_data/expect.$class
 fi
 
-cat $SRCDIR/progs/rel_test/$instance.setup $SRCDIR/progs/rel_test/test.$class \
-    | $TEST_REL -f - > $OUT 2>&1
+if [ "$class" = irel ]; then
+       TEST_PROG=$TEST_REL
+elif [ "$class" = brel ]; then
+       TEST_PROG=$TEST_REL
+elif [ "$class" = icount ]; then
+       TEST_PROG=$TEST_ICOUNT
+else
+       TEST_PROG=/bin/cat
+fi
+
+cat $SRCDIR/progs/test_data/$instance.setup $SRCDIR/progs/test_data/test.$class \
+    | $TEST_PROG -f - > $OUT 2>&1
 
 cmp -s $EXPECT $OUT
 status=$?
similarity index 100%
rename from tests/r_brel_bma/name
rename to tests/e_brel_bma/name
diff --git a/tests/e_icount_normal/name b/tests/e_icount_normal/name
new file mode 100644 (file)
index 0000000..eafa802
--- /dev/null
@@ -0,0 +1 @@
+inode counting abstraction optimized for storing inode counts
diff --git a/tests/e_icount_opt/name b/tests/e_icount_opt/name
new file mode 100644 (file)
index 0000000..5b6b1a5
--- /dev/null
@@ -0,0 +1 @@
+inode counting abstraction optimized for counting
similarity index 100%
rename from tests/r_irel_ima/name
rename to tests/e_irel_ima/name
index 60aaaac..1adda3b 100644 (file)
@@ -1,21 +1,28 @@
 Filesystem did not have a UUID; generating one.
 
 Pass 1: Checking inodes, blocks, and sizes
-Inode 12 has illegal block(s).  Clear? yes
+Duplicate blocks found... invoking duplicate block passes.
+Pass 1B: Rescan for duplicate/bad blocks
+Duplicate/bad block(s) in inode 12: 3 4 6
+Pass 1C: Scan directories for inodes with dup blocks.
+Pass 1D: Reconciling duplicate blocks
+(There are 1 inodes containing duplicate/bad blocks.)
 
-Block #1 (3) overlaps filesystem metadata in inode 12.  CLEARED.
-Block #2 (4) overlaps filesystem metadata in inode 12.  CLEARED.
-Block #3 (6) overlaps filesystem metadata in inode 12.  CLEARED.
-Inode 12, i_size is 4096, should be 1024.  Fix? yes
+File /foo (inode #12, mod time Thu Apr 28 17:57:53 1994) 
+  has 3 duplicate block(s), shared with 1 file(s):
+       <filesystem metadata>
+Clone duplicate/bad blocks? yes
 
-Inode 12, i_blocks is 8, should be 2.  Fix? yes
 
 Pass 2: Checking directory structure
-Directory inode 12 has an unallocated block #1.  Allocate? yes
+Directory inode 12, block 1, offset 0: directory corrupted
+Salvage? yes
 
-Directory inode 12 has an unallocated block #2.  Allocate? yes
+Directory inode 12, block 2, offset 0: directory corrupted
+Salvage? yes
 
-Directory inode 12 has an unallocated block #3.  Allocate? yes
+Directory inode 12, block 3, offset 0: directory corrupted
+Salvage? yes
 
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
index 5cb5468..61603bf 100644 (file)
@@ -1,12 +1,18 @@
 Filesystem did not have a UUID; generating one.
 
 Pass 1: Checking inodes, blocks, and sizes
-Inode 12 has illegal block(s).  Clear? yes
+Duplicate blocks found... invoking duplicate block passes.
+Pass 1B: Rescan for duplicate/bad blocks
+Duplicate/bad block(s) in inode 12: 2 3 1
+Pass 1C: Scan directories for inodes with dup blocks.
+Pass 1D: Reconciling duplicate blocks
+(There are 1 inodes containing duplicate/bad blocks.)
+
+File /termcap (inode #12, mod time Sun Jan  2 08:29:13 1994) 
+  has 3 duplicate block(s), shared with 1 file(s):
+       <filesystem metadata>
+Clone duplicate/bad blocks? yes
 
-Block #4 (2) overlaps filesystem metadata in inode 12.  CLEARED.
-Block #5 (3) overlaps filesystem metadata in inode 12.  CLEARED.
-Block #6 (1) overlaps filesystem metadata in inode 12.  CLEARED.
-Inode 12, i_blocks is 34, should be 28.  Fix? yes
 
 Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
@@ -15,9 +21,7 @@ Pass 5: Checking group summary information
 Fix summary information? yes
 
 Block bitmap differences: -29 -30 -31.  FIXED
-Free blocks count wrong for group 0 (61, counted=64).  FIXED
-Free blocks count wrong (61, counted=64).  FIXED
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 12/32 files (8.3% non-contiguous), 36/100 blocks
+test_filesys: 12/32 files (8.3% non-contiguous), 39/100 blocks
 Exit status is 1
index f5cf22b..8735c4e 100644 (file)
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 12/32 files (8.3% non-contiguous), 36/100 blocks
+test_filesys: 12/32 files (8.3% non-contiguous), 39/100 blocks
 Exit status is 0
index 29fa496..d22dbf2 100644 (file)
@@ -1,9 +1,9 @@
 Note: if there is several inode or block bitmap blocks
 which require relocation, or one part of the inode table
 which must be moved, you may wish to try running e2fsck
-the '-b 8193' option first.  The problem may lie only with
-the primary block group descriptor, and the backup block
-group descriptor may be OK.
+with the '-b 8193' option first.  The problem may lie only
+with the primary block group descriptor, and the backup
+block group descriptor may be OK.
 
 Block bitmap for group 0 is not in group.  (block 4096)
 Relocate? yes
index a296ed8..4e4d996 100644 (file)
@@ -1,9 +1,9 @@
 Note: if there is several inode or block bitmap blocks
 which require relocation, or one part of the inode table
 which must be moved, you may wish to try running e2fsck
-the '-b 8193' option first.  The problem may lie only with
-the primary block group descriptor, and the backup block
-group descriptor may be OK.
+with the '-b 8193' option first.  The problem may lie only
+with the primary block group descriptor, and the backup
+block group descriptor may be OK.
 
 Inode bitmap for group 0 is not in group.  (block 4000)
 Relocate? yes
index 6c6b7f5..e0af316 100644 (file)
@@ -1,9 +1,9 @@
 Note: if there is several inode or block bitmap blocks
 which require relocation, or one part of the inode table
 which must be moved, you may wish to try running e2fsck
-the '-b 8193' option first.  The problem may lie only with
-the primary block group descriptor, and the backup block
-group descriptor may be OK.
+with the '-b 8193' option first.  The problem may lie only
+with the primary block group descriptor, and the backup
+block group descriptor may be OK.
 
 Inode table for group 0 is not in group.  (block 40000)
 WARNING: SEVERE DATA LOSS POSSIBLE.
index 297bb61..824b0ec 100644 (file)
@@ -1,8 +1,8 @@
 which require relocation, or one part of the inode table
 which must be moved, you may wish to try running e2fsck
-the '-b 8193' option first.  The problem may lie only with
-the primary block group descriptor, and the backup block
-group descriptor may be OK.
+with the '-b 8193' option first.  The problem may lie only
+with the primary block group descriptor, and the backup
+block group descriptor may be OK.
 
 test_filesys: Block bitmap for group 0 is not in group.  (block 0)
 
diff --git a/tests/progs/ChangeLog b/tests/progs/ChangeLog
new file mode 100644 (file)
index 0000000..625919e
--- /dev/null
@@ -0,0 +1,4 @@
+Wed Mar 26 15:38:52 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * test_icount.c: New file which tests the icount abstraction.
+
index 5ed3944..434ec21 100644 (file)
@@ -13,10 +13,12 @@ INSTALL = @INSTALL@
 
 MK_CMDS=       ../../lib/ss/mk_cmds
 
-PROGS=         test_rel
+PROGS=         test_rel test_icount
 
 TEST_REL_OBJS= test_rel.o test_rel_cmds.o
 
+TEST_ICOUNT_OBJS=      test_icount.o test_icount_cmds.o
+
 SRCS=  $(srcdir)/test_rel.c 
 
 LIBS= $(LIBEXT2FS) $(LIBSS) $(LIBCOM_ERR)
@@ -27,14 +29,21 @@ DEPLIBS= $(LIBEXT2FS) $(LIBSS) $(LIBCOM_ERR)
 
 all:: $(PROGS)
 
-test_rel: $(TEST_REL_OBJS)
+test_rel: $(TEST_REL_OBJS) $(DEPLIBS)
        $(LD) $(ALL_LDFLAGS) -o test_rel $(TEST_REL_OBJS) $(LIBS)
 
 test_rel_cmds.c: test_rel_cmds.ct
        $(MK_CMDS) $(srcdir)/test_rel_cmds.ct
 
+test_icount: $(TEST_ICOUNT_OBJS) $(DEPLIBS)
+       $(LD) $(ALL_LDFLAGS) -o test_icount $(TEST_ICOUNT_OBJS) $(LIBS)
+
+test_icount_cmds.c: test_icount_cmds.ct
+       $(MK_CMDS) $(srcdir)/test_icount_cmds.ct
+
 clean:
-       $(RM) -f $(PROGS) test_rel_cmds.c \#* *.s *.o *.a *~ core
+       $(RM) -f $(PROGS) test_rel_cmds.c test_icount_cmds.c \
+               \#* *.s *.o *.a *~ core
 
 install:
 
diff --git a/tests/progs/test_data/expect.icount b/tests/progs/test_data/expect.icount
new file mode 100644 (file)
index 0000000..507550f
--- /dev/null
@@ -0,0 +1,191 @@
+test_icount: validate
+Icount structure successfully validated
+test_icount: store 0
+usage: store inode counttest_icount: fetch 0
+fetch: Invalid argument while calling ext2fs_icount_fetch
+test_icount: increment 0
+increment: Invalid argument while calling ext2fs_icount_increment
+test_icount: decrement 0
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: store 20001
+usage: store inode counttest_icount: fetch 20001
+fetch: Invalid argument while calling ext2fs_icount_fetch
+test_icount: increment 20001
+increment: Invalid argument while calling ext2fs_icount_increment
+test_icount: decrement 20001
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: validate
+Icount structure successfully validated
+test_icount: fetch 1
+Count is 0
+test_icount: store 1 1
+test_icount: fetch 1
+Count is 1
+test_icount: store 1 2
+test_icount: fetch 1
+Count is 2
+test_icount: store 1 3
+test_icount: fetch 1
+Count is 3
+test_icount: store 1 1
+test_icount: fetch 1
+Count is 1
+test_icount: store 1 0
+test_icount: fetch 1
+Count is 0
+test_icount: fetch 20000
+Count is 0
+test_icount: store 20000 0
+test_icount: fetch 20000
+Count is 0
+test_icount: store 20000 3
+test_icount: fetch 20000
+Count is 3
+test_icount: store 20000 0
+test_icount: fetch 20000
+Count is 0
+test_icount: store 20000 42
+test_icount: fetch 20000
+Count is 42
+test_icount: store 20000 1
+test_icount: fetch 20000
+Count is 1
+test_icount: store 20000 0
+test_icount: fetch 20000
+Count is 0
+test_icount: get_size
+Size of icount is: 5
+test_icount: decrement 2
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: increment 2
+Count is now 1
+test_icount: fetch 2
+Count is 1
+test_icount: increment 2
+Count is now 2
+test_icount: fetch 2
+Count is 2
+test_icount: increment 2
+Count is now 3
+test_icount: fetch 2
+Count is 3
+test_icount: increment 2
+Count is now 4
+test_icount: fetch 2
+Count is 4
+test_icount: decrement 2
+Count is now 3
+test_icount: fetch 2
+Count is 3
+test_icount: decrement 2
+Count is now 2
+test_icount: fetch 2
+Count is 2
+test_icount: decrement 2
+Count is now 1
+test_icount: fetch 2
+Count is 1
+test_icount: decrement 2
+Count is now 0
+test_icount: decrement 2
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: store 3 1
+test_icount: increment 3
+Count is now 2
+test_icount: fetch 3
+Count is 2
+test_icount: decrement 3
+Count is now 1
+test_icount: fetch 3
+Count is 1
+test_icount: decrement 3
+Count is now 0
+test_icount: store 4 0
+test_icount: fetch 4
+Count is 0
+test_icount: increment 4
+Count is now 1
+test_icount: increment 4
+Count is now 2
+test_icount: fetch 4
+Count is 2
+test_icount: decrement 4
+Count is now 1
+test_icount: decrement 4
+Count is now 0
+test_icount: store 4  42
+test_icount: store 4 0
+test_icount: increment 4
+Count is now 1
+test_icount: increment 4
+Count is now 2
+test_icount: increment 4
+Count is now 3
+test_icount: decrement 4
+Count is now 2
+test_icount: decrement 4
+Count is now 1
+test_icount: decrement 4
+Count is now 0
+test_icount: decrement 4
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: decrement 4
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: store 5 4
+test_icount: decrement 5
+Count is now 3
+test_icount: decrement 5
+Count is now 2
+test_icount: decrement 5
+Count is now 1
+test_icount: decrement 5
+Count is now 0
+test_icount: decrement 5
+decrement: Invalid argument while calling ext2fs_icount_increment
+test_icount: get_size
+Size of icount is: 105
+test_icount: validate
+Icount structure successfully validated
+test_icount: store 10 10
+test_icount: store 20 20
+test_icount: store 30 30
+test_icount: store 40 40
+test_icount: store 50 50
+test_icount: store 60 60
+test_icount: store 70 70
+test_icount: store 80 80
+test_icount: store 90 90
+test_icount: store 100 100
+test_icount: store 15 15
+test_icount: store 25 25
+test_icount: store 35 35
+test_icount: store 45 45
+test_icount: store 55 55
+test_icount: store 65 65
+test_icount: store 75 75
+test_icount: store 85 85
+test_icount: store 95 95
+test_icount: dump
+10: 10
+15: 15
+20: 20
+25: 25
+30: 30
+35: 35
+40: 40
+45: 45
+50: 50
+55: 55
+60: 60
+65: 65
+70: 70
+75: 75
+80: 80
+85: 85
+90: 90
+95: 95
+100: 100
+test_icount: get_size
+Size of icount is: 105
+test_icount: validate
+Icount structure successfully validated
diff --git a/tests/progs/test_data/normal.setup b/tests/progs/test_data/normal.setup
new file mode 100644 (file)
index 0000000..dfc6c41
--- /dev/null
@@ -0,0 +1 @@
+-create
diff --git a/tests/progs/test_data/opt.setup b/tests/progs/test_data/opt.setup
new file mode 100644 (file)
index 0000000..79458b0
--- /dev/null
@@ -0,0 +1 @@
+-create -i
diff --git a/tests/progs/test_data/test.icount b/tests/progs/test_data/test.icount
new file mode 100644 (file)
index 0000000..ea611db
--- /dev/null
@@ -0,0 +1,136 @@
+#
+# This is the test script for the icount abstraction
+#
+# Copyright 1997 by Theodore Ts'o.  This file may be redistributed 
+# under the terms of the GNU Public License.
+#
+#
+# First let's test the boundary cases for illegal arguments
+#
+validate
+store 0
+fetch 0
+increment 0
+decrement 0
+store 20001
+fetch 20001
+increment 20001
+decrement 20001
+validate
+#
+# OK, now let's test fetch and store.  We also test the boundary cases
+# for legal inodes here.
+#
+fetch 1
+store 1 1
+fetch 1
+store 1 2
+fetch 1
+store 1 3
+fetch 1
+store 1 1
+fetch 1
+store 1 0
+fetch 1
+fetch 20000
+store 20000 0
+fetch 20000
+store 20000 3
+fetch 20000
+store 20000 0
+fetch 20000
+store 20000 42
+fetch 20000
+store 20000 1
+fetch 20000
+store 20000 0
+fetch 20000
+get_size
+#
+# Time to test increment.  First increment from 0 (previously unreferenced)
+#
+decrement 2
+increment 2
+fetch 2
+increment 2
+fetch 2
+increment 2
+fetch 2
+increment 2
+fetch 2
+decrement 2
+fetch 2
+decrement 2
+fetch 2
+decrement 2
+fetch 2
+decrement 2
+decrement 2
+#
+# Store 1 then test...
+#
+store 3 1
+increment 3
+fetch 3
+decrement 3
+fetch 3
+decrement 3
+#
+# Store 0 then test
+# 
+store 4 0
+fetch 4
+increment 4
+increment 4
+fetch 4
+decrement 4
+decrement 4
+#
+# Store something, then store 0, then test...
+#
+store 4  42
+store 4 0
+increment 4
+increment 4
+increment 4
+decrement 4
+decrement 4
+decrement 4
+decrement 4
+decrement 4
+#
+# store something, then decrement to zero
+#
+store 5 4
+decrement 5
+decrement 5
+decrement 5
+decrement 5
+decrement 5
+#
+# Test insert
+#
+get_size
+validate
+store 10 10
+store 20 20
+store 30 30
+store 40 40
+store 50 50
+store 60 60
+store 70 70
+store 80 80
+store 90 90
+store 100 100
+store 15 15
+store 25 25
+store 35 35
+store 45 45
+store 55 55
+store 65 65
+store 75 75
+store 85 85
+store 95 95
+dump
+get_size
+validate
diff --git a/tests/progs/test_icount.c b/tests/progs/test_icount.c
new file mode 100644 (file)
index 0000000..588e90f
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * test_icount.c
+ * 
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <fcntl.h>
+
+#include <linux/ext2_fs.h>
+
+#include <et/com_err.h>
+#include <ss/ss.h>
+#include <ext2fs/ext2fs.h>
+#include <ext2fs/irel.h>
+#include <ext2fs/brel.h>
+
+extern ss_request_table test_cmds;
+
+#include "test_icount.h"
+
+ext2_filsys test_fs;
+ext2_icount_t test_icount;
+
+/*
+ * Helper function which assures that the icount structure is valid
+ */
+static int check_icount(char *request)
+{
+       if (test_icount)
+               return 0;
+       com_err(request, 0, "The icount structure must be allocated.");
+       return 1;
+}
+
+/*
+ * Helper function which parses an inode number.
+ */
+static int parse_inode(const char *request, const char *desc,
+                      const char *str, ino_t *ino)
+{
+       char *tmp;
+       
+       *ino = strtoul(str, &tmp, 0);
+       if (*tmp) {
+               com_err(request, 0, "Bad %s - %s", desc, str);
+               return 1;
+       }
+       return 0;
+}
+
+void do_create_icount(int argc, char **argv)
+{
+       errcode_t retval;
+       char *progname;
+       int     flags = 0;
+       ino_t   size = 5;
+
+       progname = *argv;
+       argv++; argc --;
+
+       if (argc && !strcmp("-i", *argv)) {
+               flags |= EXT2_ICOUNT_OPT_INCREMENT;
+               argv++; argc--;
+       }
+       if (argc) {
+               if (parse_inode(progname, "icount size", argv[0], &size))
+                       return;
+               argv++; argc--;
+       }
+#if 0
+       printf("Creating icount... flags=%d, size=%d\n", flags, (int) size);
+#endif
+       retval = ext2fs_create_icount(test_fs, flags, (int) size,
+                                     &test_icount);
+       if (retval) {
+               com_err(progname, retval, "while creating icount");
+               return;
+       }
+}
+
+void do_free_icount(int argc, char **argv)
+{
+       if (check_icount(argv[0]))
+               return;
+
+       ext2fs_free_icount(test_icount);
+       test_icount = 0;
+}
+
+void do_fetch(int argc, char **argv)
+{
+       const char *usage = "usage: %s inode";
+       errcode_t retval;
+       ino_t   ino;
+       __u16   count;
+       
+       if (argc < 2) {
+               printf(usage, argv[0]);
+               return;
+       }
+       if (check_icount(argv[0]))
+               return;
+       if (parse_inode(argv[0], "inode", argv[1], &ino))
+               return;
+       retval = ext2fs_icount_fetch(test_icount, ino, &count);
+       if (retval) {
+               com_err(argv[0], retval, "while calling ext2fs_icount_fetch");
+               return;
+       }
+       printf("Count is %u\n", count);
+}
+
+void do_increment(int argc, char **argv)
+{
+       const char *usage = "usage: %s inode";
+       errcode_t retval;
+       ino_t   ino;
+       __u16   count;
+       
+       if (argc < 2) {
+               printf(usage, argv[0]);
+               return;
+       }
+       if (check_icount(argv[0]))
+               return;
+       if (parse_inode(argv[0], "inode", argv[1], &ino))
+               return;
+       retval = ext2fs_icount_increment(test_icount, ino, &count);
+       if (retval) {
+               com_err(argv[0], retval,
+                       "while calling ext2fs_icount_increment");
+               return;
+       }
+       printf("Count is now %u\n", count);
+}
+
+void do_decrement(int argc, char **argv)
+{
+       const char *usage = "usage: %s inode";
+       errcode_t retval;
+       ino_t   ino;
+       __u16   count;
+       
+       if (argc < 2) {
+               printf(usage, argv[0]);
+               return;
+       }
+       if (check_icount(argv[0]))
+               return;
+       if (parse_inode(argv[0], "inode", argv[1], &ino))
+               return;
+       retval = ext2fs_icount_decrement(test_icount, ino, &count);
+       if (retval) {
+               com_err(argv[0], retval,
+                       "while calling ext2fs_icount_increment");
+               return;
+       }
+       printf("Count is now %u\n", count);
+}
+
+void do_store(int argc, char **argv)
+{
+       const char *usage = "usage: %s inode count";
+       errcode_t retval;
+       ino_t   ino;
+       ino_t   count;
+       
+       if (argc < 3) {
+               printf(usage, argv[0]);
+               return;
+       }
+       if (check_icount(argv[0]))
+               return;
+       if (parse_inode(argv[0], "inode", argv[1], &ino))
+               return;
+       if (parse_inode(argv[0], "count", argv[2], &count))
+               return;
+       if (count > 65535) {
+               printf("Count too large.\n");
+               return;
+       }
+       retval = ext2fs_icount_store(test_icount, ino, (__u16) count);
+       if (retval) {
+               com_err(argv[0], retval,
+                       "while calling ext2fs_icount_store");
+               return;
+       }
+}
+
+void do_dump(int argc, char **argv)
+{
+       errcode_t       retval;
+       ino_t           i;
+       __u16           count;
+
+       if (check_icount(argv[0]))
+               return;
+       for (i=1; i <= test_fs->super->s_inodes_count; i++) {
+               retval = ext2fs_icount_fetch(test_icount, i, &count);
+               if (retval) {
+                       com_err(argv[0], retval,
+                               "while fetching icount for %lu", i);
+                       return;
+               }
+               if (count)
+                       printf("%lu: %u\n", i, count);
+       }
+}
+
+void do_validate(int argc, char **argv)
+{
+       errcode_t       retval;
+       ino_t   size;
+       
+       if (check_icount(argv[0]))
+               return;
+       retval = ext2fs_icount_validate(test_icount, stdout);
+       if (retval) {
+               com_err(argv[0], retval, "while validating icount structure");
+               return;
+       }
+       printf("Icount structure successfully validated\n");
+}
+
+void do_get_size(int argc, char **argv)
+{
+       errcode_t       retval;
+       ino_t   size;
+       
+       if (check_icount(argv[0]))
+               return;
+       size = ext2fs_get_icount_size(test_icount);
+       printf("Size of icount is: %u\n", size);
+}
+
+static int source_file(const char *cmd_file, int sci_idx)
+{
+       FILE            *f;
+       char            buf[256];
+       char            *cp;
+       int             exit_status = 0;
+       int             retval;
+       int             noecho;
+
+       if (strcmp(cmd_file, "-") == 0)
+               f = stdin;
+       else {
+               f = fopen(cmd_file, "r");
+               if (!f) {
+                       perror(cmd_file);
+                       exit(1);
+               }
+       }
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+       while (!feof(f)) {
+               if (fgets(buf, sizeof(buf), f) == NULL)
+                       break;
+               if (buf[0] == '#')
+                       continue;
+               noecho = 0;
+               if (buf[0] == '-') {
+                       noecho = 1;
+                       buf[0] = ' ';
+               }
+               cp = strchr(buf, '\n');
+               if (cp)
+                       *cp = 0;
+               cp = strchr(buf, '\r');
+               if (cp)
+                       *cp = 0;
+               if (!noecho)
+                       printf("test_icount: %s\n", buf);
+               retval = ss_execute_line(sci_idx, buf);
+               if (retval) {
+                       ss_perror(sci_idx, retval, buf);
+                       exit_status++;
+               }
+       }
+       return exit_status;
+}
+
+void main(int argc, char **argv)
+{
+       int             retval;
+       int             sci_idx;
+       const char      *usage = "Usage: test_icount [-R request] [-f cmd_file]";
+       char            c;
+       char            *request = 0;
+       int             exit_status = 0;
+       char            *cmd_file = 0;
+       struct ext2_super_block param;
+       
+       initialize_ext2_error_table();
+
+       /*
+        * Create a sample filesystem structure
+        */
+       memset(&param, 0, sizeof(struct ext2_super_block));
+       param.s_blocks_count = 80000;
+       param.s_inodes_count = 20000;
+       retval = ext2fs_initialize("/dev/null", 0, &param,
+                                  unix_io_manager, &test_fs);
+       if (retval) {
+               com_err("/dev/null", retval, "while setting up test fs");
+               exit(1);
+       }
+
+       while ((c = getopt (argc, argv, "wR:f:")) != EOF) {
+               switch (c) {
+               case 'R':
+                       request = optarg;
+                       break;
+               case 'f':
+                       cmd_file = optarg;
+                       break;
+               default:
+                       com_err(argv[0], 0, usage);
+                       return;
+               }
+       }
+       sci_idx = ss_create_invocation("test_icount", "0.0", (char *) NULL,
+                                      &test_cmds, &retval);
+       if (retval) {
+               ss_perror(sci_idx, retval, "creating invocation");
+               exit(1);
+       }
+
+       (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
+       if (retval) {
+               ss_perror(sci_idx, retval, "adding standard requests");
+               exit (1);
+       }
+       if (request) {
+               retval = 0;
+               retval = ss_execute_line(sci_idx, request);
+               if (retval) {
+                       ss_perror(sci_idx, retval, request);
+                       exit_status++;
+               }
+       } else if (cmd_file) {
+               exit_status = source_file(cmd_file, sci_idx);
+       } else {
+               ss_listen(sci_idx);
+       }
+
+       exit(exit_status);
+}
+
diff --git a/tests/progs/test_icount.h b/tests/progs/test_icount.h
new file mode 100644 (file)
index 0000000..9678a68
--- /dev/null
@@ -0,0 +1,7 @@
+void do_create_icount(int argc, char **argv);
+void do_free_icount(int argc, char **argv);
+void do_fetch(int argc, char **argv);
+void do_increment(int argc, char **argv);
+void do_decrement(int argc, char **argv);
+void do_store(int argc, char **argv);
+void do_get_size(int argc, char **argv);
diff --git a/tests/progs/test_icount_cmds.ct b/tests/progs/test_icount_cmds.ct
new file mode 100644 (file)
index 0000000..c3cc6f4
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
+# under the terms of the GNU Public License.
+#
+command_table test_cmds;
+
+#
+# Icount table commands
+#
+request do_create_icount, "Create an icount structure",
+       create_icount, create;
+
+request do_free_icount, "Free an icount structure",
+       free_icount, free;
+
+request do_fetch, "Fetch an icount entry",
+       fetch;
+
+request do_increment, "Increment an icount entry",
+       increment, inc;
+
+request do_decrement, "Decrement an icount entry",
+       decrement, dec;
+
+request do_store, "Store an icount entry",
+       store;
+
+request do_get_size, "Get the size of the icount structure",
+       get_size;
+
+request do_dump, "Dump the icount structure",
+       dump;
+
+request do_validate, "Validate the icount structure",
+       validate, check;
+
+end;
index d76c1f4..2dfb473 100644 (file)
@@ -707,8 +707,6 @@ static int source_file(const char *cmd_file, int sci_idx)
        return exit_status;
 }
 
-
-
 void main(int argc, char **argv)
 {
        int             retval;
index 6a42476..e1d2df7 100644 (file)
@@ -10,9 +10,12 @@ CHATTR=../misc/chattr
 LSATTR=../misc/lsattr
 DEBUGFS=../debugfs/debugfs
 TEST_REL=../tests/progs/test_rel
+TEST_ICOUNT=../tests/progs/test_icount
 LD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss
 TMPFILE=./test.img
 export LD_LIBRARY_PATH
 TZ=GMT
 export TZ
+LANG=C
+export LANG
 unset PAGER
index fcb4cf3..fb6a848 100644 (file)
@@ -9,7 +9,10 @@ else
   TESTS=
   for i 
   do
-    TESTS="$TESTS $SRCDIR/$i"
+    case $i in
+       [a-zA-Z])       TESTS="$TESTS $SRCDIR/${i}_*" ;;
+       *)              TESTS="$TESTS $SRCDIR/$i" ;;
+    esac
   done
 fi