Checked in e2fsprogs 1.08.
+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
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
.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
}
}
-/*
- * 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;
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);
{
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;
--- /dev/null
+/*
+ * 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;
+}
+
+
\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
@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
@top The EXT2FS Library
-This manual documents the EXT2FS Library, version 1.07.
+This manual documents the EXT2FS Library, version 1.08.
@end ifinfo
* Inode Functions::
* Directory functions::
* Bitmap Functions::
-* Badblocks list management::
-* Directory-block list management::
+* EXT2 data abstractions::
* Byte-swapping functions::
* Other functions::
@end menu
@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 ----------------------------------------------------------------------
@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
@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})
@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
@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})
+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
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
"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;
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;
}
/*
* 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),
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);
}
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);
}
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;
}
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;
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;
}
}
}
+
+static const char *my_ver_string = E2FSPROGS_VERSION;
+static const char *my_ver_date = E2FSPROGS_DATE;
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();
#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);
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);
}
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;
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
}
#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
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! */
"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");
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++;
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;
}
{
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)
struct search_dir_struct {
int count;
ino_t first_inode;
+ ino_t max_inode;
};
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;
*/
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);
}
int i;
errcode_t retval;
int file_ok;
+ int meta_data = 0;
struct problem_context pctx;
printf("Pass 1D: Reconciling duplicate blocks\n");
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
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])
struct clone_struct {
errcode_t errcode;
+ ino_t dir;
char *buf;
};
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) {
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);
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");
"\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 */
/* 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
*/
#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 */
#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
/*
#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
*/
__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 */
};
/*
* 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
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 *);
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 *);
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 *, ...)
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 */
+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
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
__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;
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));
} 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");
+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
test_io.o \
unix_io.o \
unlink.o \
- valid_blk.o
+ valid_blk.o \
+ version.o
SRCS= ext2_err.c \
$(srcdir)/alloc.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
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)
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
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);
#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;
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,
goto errout;
group_ptr += fs->blocksize;
}
+ next_group:
group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
}
}
/*
+ * 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,
if (ret & DBLIST_ABORT)
return 0;
}
-
return 0;
}
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
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
*/
/* 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,
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
/* 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,
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);
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);
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;
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:
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) {
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)
{
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;
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
* 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
* 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)
{
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)) {
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;
}
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--;
{
struct ext2_icount_el *el;
+ if (!ino || (ino > icount->num_inodes))
+ return EINVAL;
+
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (count == 1) {
*/
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;
}
/*
* Get the icount element
*/
- el = put_icount_el(icount, ino);
+ el = get_icount_el(icount, ino, 1);
if (!el)
return ENOMEM;
el->count = count;
ext2_filsys fs;
errcode_t retval;
struct ext2_super_block *super;
+ struct ext2fs_sb *s;
int frags_per_block;
int rem;
int overhead = 0;
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;
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);
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;
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.
* 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) %
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;
{
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);
* 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));
*/
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;
}
--- /dev/null
+/*
+ * 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);
+}
* $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
+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
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,
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;
}
}
.B \-q
]
[
+.B -s sparse-super-flag
+]
+[
.B \-v
]
[
.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
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;
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 *) ¶m;
+
/* Update our PATH to include /sbin */
if (oldpath) {
char *newpath;
setbuf(stderr, NULL);
initialize_ext2_error_table();
memset(¶m, 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,
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);
}
param.s_log_block_size =
log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+ max = size * 8;
break;
case 'c':
case 't': /* Check for bad blocks */
"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");
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);
}
}
+ 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
*/
* 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[])
.I reserved-blocks-count
]
[
+.B -s sparse-super-flag
+]
+[
.B -u
.I user
]
.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
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;
{
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);
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':
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)
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
{
+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
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=$?
--- /dev/null
+inode counting abstraction optimized for storing inode counts
--- /dev/null
+inode counting abstraction optimized for counting
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
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
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
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
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
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
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.
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)
--- /dev/null
+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.
+
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)
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:
--- /dev/null
+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
--- /dev/null
+-create -i
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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(¶m, 0, sizeof(struct ext2_super_block));
+ param.s_blocks_count = 80000;
+ param.s_inodes_count = 20000;
+ retval = ext2fs_initialize("/dev/null", 0, ¶m,
+ 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);
+}
+
--- /dev/null
+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);
--- /dev/null
+#
+# 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;
return exit_status;
}
-
-
void main(int argc, char **argv)
{
int retval;
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
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