-diff -urN genext2fs-1.3.orig/Makefile genext2fs/Makefile
---- genext2fs-1.3.orig/Makefile Wed Dec 31 17:00:00 1969
-+++ genext2fs/Makefile Fri Sep 28 15:48:58 2001
-@@ -0,0 +1,19 @@
+diff -urN genext2fs-1.3.orig/.gdbinit genext2fs-1.3/.gdbinit
+--- genext2fs-1.3.orig/.gdbinit 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/.gdbinit 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,3 @@
++set args -d /home/andersen/CVS/buildroot/build/root -D /home/andersen/CVS/buildroot/sources/device_table.txt /home/andersen/CVS/buildroot/root_fs -i 1915 -b 30000
++b interpret_table_entry
++r
+diff -urN genext2fs-1.3.orig/Makefile genext2fs-1.3/Makefile
+--- genext2fs-1.3.orig/Makefile 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/Makefile 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,46 @@
+CC=gcc
-+CFLAGS=-Wall -O2
++CFLAGS=-Wall -O0 -g
+
+SRC=genext2fs.c
+OBJS=$(patsubst %.c,%.o, $(SRC))
+
-+
+all: genext2fs
++INSTALL=install
+
+genext2fs: $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) -o $@
+
+$(OBJS): Makefile
+
++install:
++ $(INSTALL) -d $(DESTDIR)/usr/bin/
++ $(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/
++ $(INSTALL) -d $(DESTDIR)/usr/share/man/man8/
++ $(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/
++
++clean:
++ rm -rf *.o *.a core genext2fs
++ rm -rf test ext2.img
++
++check: all
++ mkdir -p test
++ dd if=/dev/zero of=test/zero count=1
++ ./genext2fs -b 4096 -d test ext2.img
++
++ md5=`md5sum ext2.img | cut -f 1 -d " "`; \
++ if [ "$$md5" != "89471302d95f96a76fbb2cff98182cde" ] ; then \
++ echo "test failed."; \
++ else \
++ echo "test succeeded."; \
++ fi
++
++# test genext2fs by creating the image and comparing checksums
++test: all
++ sh ./test.sh
++
++# test genext2fs by actually mounting the created image.
++test-mount: all
++ sudo sh ./test-mount.sh
+diff -urN genext2fs-1.3.orig/debian/changelog genext2fs-1.3/debian/changelog
+--- genext2fs-1.3.orig/debian/changelog 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/changelog 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,17 @@
++genext2fs (1.3-2) unstable; urgency=low
++
++ * apply fix from upstream cvs that appears to fix endian bug
++ (closes: #122411)
++ * mention filesystem size limit in manpage (closes: #122729)
++ * mention that hard links are not supported in manpage
++ (closes: #155464)
++ * add sanity check at the end of the build
++
++ -- David Kimdon <dwhedon@debian.org> Fri, 8 Mar 2002 23:17:36 -0800
++
++genext2fs (1.3-1) unstable; urgency=low
++
++ * Initial Release. (closes: #105263)
++
++ -- David Kimdon <dwhedon@debian.org> Sat, 14 Jul 2001 13:24:49 -0700
++
+diff -urN genext2fs-1.3.orig/debian/control genext2fs-1.3/debian/control
+--- genext2fs-1.3.orig/debian/control 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/control 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,19 @@
++Source: genext2fs
++Section: admin
++Priority: optional
++Maintainer: David Kimdon <dwhedon@debian.org>
++Build-Depends: debhelper (>> 3.0.0)
++Standards-Version: 3.5.2
++
++Package: genext2fs
++Architecture: any
++Depends: ${shlibs:Depends}
++Description: ext2 filesystem generator for embedded systems
++ `genext2fs' is meant to generate an ext2 filesystem
++ as a normal (non-root) user. It doesn't require you to mount
++ the image file to copy files on it. It doesn't even require
++ you to be the superuser to make device nodes.
++ .
++ Warning ! `genext2fs' has been designed for embedded
++ systems. As such, it will generate a filesystem for single-user
++ usage: all files/directories/etc... will belong to UID/GID 0
+diff -urN genext2fs-1.3.orig/debian/copyright genext2fs-1.3/debian/copyright
+--- genext2fs-1.3.orig/debian/copyright 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/copyright 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,15 @@
++This package was debianized by David Kimdon <dwhedon@debian.org> on
++Sat, 14 Jul 2001 13:24:49 -0700.
++
++It was downloaded from http://freshmeat.net/projects/genext2fs/
++Upstream Author(s): Xavier Bestel <xbestel@aplio.fr>
++
++Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
++
++This program is free software; you can redistribute it and/or
++modify it under the terms of the GNU General Public License
++as published by the Free Software Foundation; version
++2 of the License.
++
++On Debian systems, the complete text of the GNU General Public
++License can be found in /usr/share/common-licenses/GPL file.
+diff -urN genext2fs-1.3.orig/debian/rules genext2fs-1.3/debian/rules
+--- genext2fs-1.3.orig/debian/rules 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/debian/rules 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,70 @@
++#!/usr/bin/make -f
++# Sample debian/rules that uses debhelper.
++# GNU copyright 1997 to 1999 by Joey Hess.
++
++# Uncomment this to turn on verbose mode.
++#export DH_VERBOSE=1
++
++# This is the debhelper compatability version to use.
++export DH_COMPAT=2
++
++configure: configure-stamp
++configure-stamp:
++ dh_testdir
++ # Add here commands to configure the package.
++ # ./configure --prefix=/usr --mandir=/usr/share/man/
++
++ touch configure-stamp
++
++build: configure-stamp build-stamp
++build-stamp:
++ dh_testdir
++
++ # Add here commands to compile the package.
++ $(MAKE)
++ $(MAKE) check
++
++ touch build-stamp
++
+clean:
-+ rm -f *.o *.a core genext2fs
-diff -urN genext2fs-1.3.orig/dev.txt genext2fs/dev.txt
---- genext2fs-1.3.orig/dev.txt Thu Sep 28 09:03:19 2000
-+++ genext2fs/dev.txt Wed Dec 31 17:00:00 1969
++ dh_testdir
++ dh_testroot
++ rm -f build-stamp configure-stamp
++
++ # Add here commands to clean up after the build process.
++ -$(MAKE) clean
++
++ dh_clean
++
++install: build
++ dh_testdir
++ dh_testroot
++ dh_clean -k
++ dh_installdirs
++
++ # Add here commands to install the package into debian/genext2fs.
++ $(MAKE) install DESTDIR=`pwd`/debian/genext2fs
++
++
++# Build architecture-independent files here.
++binary-indep: build install
++# We have nothing to do by default.
++
++# Build architecture-dependent files here.
++binary-arch: build install
++ dh_testdir
++ dh_testroot
++ dh_installdocs
++ dh_installchangelogs
++ dh_link
++ dh_strip
++ dh_compress
++ dh_fixperms
++ dh_installdeb
++ dh_shlibdeps
++ dh_gencontrol
++ dh_md5sums
++ dh_builddeb
++
++binary: binary-indep binary-arch
++.PHONY: build clean binary-indep binary-arch binary install configure
+diff -urN genext2fs-1.3.orig/dev.txt genext2fs-1.3/dev.txt
+--- genext2fs-1.3.orig/dev.txt 2000-09-28 09:03:19.000000000 -0600
++++ genext2fs-1.3/dev.txt 1969-12-31 17:00:00.000000000 -0700
@@ -1,94 +0,0 @@
-drwx /dev
-crw- 10,190 /dev/lcd
-crw- 5,67 /dev/cua3
-crw- 5,68 /dev/cua4
-crw- 5,69 /dev/cua5
-diff -urN genext2fs-1.3.orig/device_table.txt genext2fs/device_table.txt
---- genext2fs-1.3.orig/device_table.txt Wed Dec 31 17:00:00 1969
-+++ genext2fs/device_table.txt Fri Mar 15 02:14:39 2002
-@@ -0,0 +1,78 @@
-+# device list table
+diff -urN genext2fs-1.3.orig/device_table.txt genext2fs-1.3/device_table.txt
+--- genext2fs-1.3.orig/device_table.txt 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/device_table.txt 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,129 @@
++# When building a target filesystem, it is desirable to not have to
++# become root and then run 'mknod' a thousand times. Using a device
++# table you can create device nodes and directories "on the fly".
++#
++# This is a sample device table file for use with genext2fs. You can
++# do all sorts of interesting things with a device table file. For
++# example, if you want to adjust the permissions on a particular file
++# you can just add an entry like:
++# /sbin/foobar f 2755 0 0 - - - - -
++# and (assuming the file /sbin/foobar exists) it will be made setuid
++# root (regardless of what its permissions are on the host filesystem.
++# Furthermore, you can use a single table entry to create a many device
++# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
++# I could just use the following two table entries:
++# /dev/hda b 640 0 0 3 0 0 0 -
++# /dev/hda b 640 0 0 3 1 1 1 15
++#
++# Device table entries take the form of:
++# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++# where name is the file name, type can be one of:
++# f A regular file
++# d Directory
++# c Character special device file
++# b Block special device file
++# p Fifo (named pipe)
++# uid is the user id for the target file, gid is the group id for the
++# target file. The rest of the entries (major, minor, etc) apply only
++# to device special files.
++
++# Have fun
++# -Erik Andersen <andersen@codepoet.org>
++#
++
+#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+/dev d 755 0 0 - - - - -
-+#
-+# Normal stuff
+/dev/mem c 640 0 0 1 1 0 0 -
+/dev/kmem c 640 0 0 1 2 0 0 -
+/dev/null c 640 0 0 1 3 0 0 -
+/dev/zero c 640 0 0 1 5 0 0 -
+/dev/random c 640 0 0 1 8 0 0 -
+/dev/urandom c 640 0 0 1 9 0 0 -
-+/dev/tty c 640 0 0 5 0 0 0 -
-+/dev/tty c 640 0 0 4 0 0 1 6
++/dev/tty c 666 0 0 5 0 0 0 -
++/dev/tty c 666 0 0 4 0 0 1 6
+/dev/console c 640 0 0 5 1 0 0 -
+/dev/ram b 640 0 0 1 1 0 0 -
+/dev/ram b 640 0 0 1 0 0 1 4
+/dev/loop b 640 0 0 7 0 0 1 2
++/dev/ptmx c 666 0 0 5 2 0 0 -
+#/dev/ttyS c 640 0 0 4 64 0 1 4
+#/dev/psaux c 640 0 0 10 1 0 0 -
+#/dev/rtc c 640 0 0 10 135 0 0 -
-+#/dev/fd b 640 0 0 2 0 0 0 1
-+#
-+# Raid device directories
-+#/dev/cciss d 755 0 0 - - - - -
-+#/dev/ida d 755 0 0 - - - - -
-+#/dev/rd d 755 0 0 - - - - -
-+#
++
++# Adjust permissions on some normal files
++#/etc/shadow f 600 0 0 - - - - -
++#/bin/tinylogin f 4755 0 0 - - - - -
++
++# User-mode Linux stuff
++/dev/ubda b 640 0 0 98 0 0 0 -
++/dev/ubda b 640 0 0 98 1 1 1 15
++
+# IDE Devices
+/dev/hda b 640 0 0 3 0 0 0 -
+/dev/hda b 640 0 0 3 1 1 1 15
+/dev/hdb b 640 0 0 3 64 0 0 -
+/dev/hdb b 640 0 0 3 65 1 1 15
-+/dev/hdc b 640 0 0 22 0 0 0 -
-+/dev/hdc b 640 0 0 22 1 1 1 15
-+/dev/hdd b 640 0 0 22 64 0 0 -
-+/dev/hdd b 640 0 0 22 65 1 1 15
++#/dev/hdc b 640 0 0 22 0 0 0 -
++#/dev/hdc b 640 0 0 22 1 1 1 15
++#/dev/hdd b 640 0 0 22 64 0 0 -
++#/dev/hdd b 640 0 0 22 65 1 1 15
+#/dev/hde b 640 0 0 33 0 0 0 -
+#/dev/hde b 640 0 0 33 1 1 1 15
+#/dev/hdf b 640 0 0 33 64 0 0 -
+#/dev/hdg b 640 0 0 34 1 1 1 15
+#/dev/hdh b 640 0 0 34 64 0 0 -
+#/dev/hdh b 640 0 0 34 65 1 1 15
++
+# SCSI Devices
+#/dev/sda b 640 0 0 8 0 0 0 -
+#/dev/sda b 640 0 0 8 1 1 1 15
+#/dev/sdh b 640 0 0 8 113 1 1 15
+#/dev/sg c 640 0 0 21 0 0 1 15
+#/dev/scd b 640 0 0 11 0 0 1 15
-+#/dev/st c 640 0 0 9 0 0 1 15
++#/dev/st c 640 0 0 9 0 0 1 8
++#/dev/nst c 640 0 0 9 128 0 1 8
++#/dev/st c 640 0 0 9 32 1 1 4
++#/dev/st c 640 0 0 9 64 1 1 4
++#/dev/st c 640 0 0 9 96 1 1 4
++
++# Floppy disk devices
++#/dev/fd b 640 0 0 2 0 0 1 2
++#/dev/fd0d360 b 640 0 0 2 4 0 0 -
++#/dev/fd1d360 b 640 0 0 2 5 0 0 -
++#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
++#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
++#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
++#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
++#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
++#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
++
+# All the proprietary cdrom devices in the world
+#/dev/aztcd b 640 0 0 29 0 0 0 -
+#/dev/bpcd b 640 0 0 41 0 0 0 -
+#/dev/sbpcd b 640 0 0 25 0 0 1 4
+#/dev/mcd b 640 0 0 23 0 0 0 -
+#/dev/optcd b 640 0 0 17 0 0 0 -
-diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs/genext2fs.c
---- genext2fs-1.3.orig/genext2fs.c Fri Mar 15 02:26:01 2002
-+++ genext2fs/genext2fs.c Fri Mar 15 02:25:46 2002
-@@ -26,6 +26,10 @@
++
+diff -urN genext2fs-1.3.orig/genext2fs.8 genext2fs-1.3/genext2fs.8
+--- genext2fs-1.3.orig/genext2fs.8 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/genext2fs.8 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,125 @@
++.\" Hey, EMACS: -*- nroff -*-
++.\" First parameter, NAME, should be all caps
++.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
++.\" other parameters are allowed: see man(7), man(1)
++.TH GENEXT2FS 8 "July 14, 2001"
++.\" Please adjust this date whenever revising the manpage.
++.\"
++.\" Some roff macros, for reference:
++.\" .nh disable hyphenation
++.\" .hy enable hyphenation
++.\" .ad l left justify
++.\" .ad b justify to both left and right margins
++.\" .nf disable filling
++.\" .fi enable filling
++.\" .br insert line break
++.\" .sp <n> insert n+1 empty lines
++.\" for manpage-specific macros, see man(7)
++.SH NAME
++genext2fs \- ext2 filesystem generator for embedded systems
++.SH SYNOPSIS
++.B genext2fs
++.RI [ options ] " image"
++.SH DESCRIPTION
++\fBgenext2fs\fP generates an ext2 filesystem
++as a normal (non-root) user. It doesn't require you to mount
++the image file to copy files on it. It doesn't even require
++you to be the superuser to make device nodes.
++.SH OPTIONS
++.TP
++.BI -x \ image
++Use this image as a starting point
++.TP
++.BI -d \ directory
++Add this directory as source
++.TP
++.BI -f \ FILE
++.TP
++.BI -D \ FILE
++Uses the named FILE as a device table file, to create device
++nodes and directories "on the fly".
++.TP
++.BI -b \ blocks
++Size in blocks
++.TP
++.BI -i \ inodes
++Number of inodes
++.TP
++.BI -r \ reserved
++Number of reserved blocks
++.TP
++.BI -g \ path
++Generate a block map file for this path
++.TP
++.BI -e \ value
++Fill unallocated blocks with value
++.TP
++.BI -z
++Make files with holes
++.TP
++.BI -U
++Squash owners making all files be owned by root
++.TP
++.BI -P
++Squash permissions on all files
++.TP
++.BI -q
++Squash permissions and owners (same as -P -U)
++.TP
++.BI -v
++Print resulting filesystem structure
++.TP
++.BI -h
++Display help
++.TP
++.SH EXAMPLES
++
++.EX
++.B
++ genext2fs -b 1440 -d src /dev/fd0
++.EE
++
++All files in the
++.I src
++directory will be written to
++.B /dev/fd0
++as a new ext2 filesystem image. You can then mount the floppy as
++usual.
++
++.EX
++.B
++ genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
++.EE
++
++This example builds a filesystem from all the files in
++.I src
++, then device nodes are created based on the content the device_table file
++.I dev.txt.
++An example device file follows:
++
++.EX
++ #<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++ /dev d 755 0 0 - - - - -
++ /dev/mem c 640 0 0 1 1 0 0 -
++ /dev/tty c 666 0 0 5 0 0 0 -
++ /dev/tty c 666 0 0 4 0 0 1 6
++ /dev/loop b 640 0 0 7 0 0 1 2
++ /dev/hda b 640 0 0 3 0 0 0 -
++ /dev/hda b 640 0 0 3 1 1 1 16
++.EE
++
++This device table creates the /dev directory, a character device
++node /dev/mem (major 1, minor 1), it also creates /dev/tty,
++/dev/tty[0-5], /dev/loop[0-1], /dev/hda, and /dev/hda0 to /dev/hda15
++.SH BUGS
++\fBgenext2fs\fP does not support hard links. Hard links present in the input
++tree will be represented as separate files in the ext2 image.
++
++.SH SEE ALSO
++.BR mkfs (8),
++.BR genromfs (8),
++.BR mkisofs (8).
++.br
++.SH AUTHOR
++This manual page was written by David Kimdon <dwhedon@debian.org>,
++for the Debian GNU/Linux system (but may be used by others).
+diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs-1.3/genext2fs.c
+--- genext2fs-1.3.orig/genext2fs.c 2001-06-18 02:11:32.000000000 -0600
++++ genext2fs-1.3/genext2fs.c 2003-01-06 08:22:30.000000000 -0700
+@@ -1,3 +1,4 @@
++/* vi: set sw=8 ts=8: */
+ // genext2fs.c
+ //
+ // ext2 filesystem generator for embedded systems
+@@ -26,6 +27,22 @@
// Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr
// Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr
// 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com
-+// 19 Jun 2001 Erik Andersen <andersee@debian.org> added
-+// the -n (nosquash) option.
-+// 03 Mar 2002 Erik Andersen <andersee@debian.org> added
-+// mkfs.jffs2 compatible device table support
++// 23 Mar 2002 Bugfix: test for IFCHR or IFBLK was flawed
++// 10 Oct 2002 Added comments,makefile targets, vsundar@ixiacom.com
++// endianess swap assert check.
++// Copyright (C) 2002 Ixia communications
++// 12 Oct 2002 Added support for triple indirection vsundar@ixiacom.com
++// Copyright (C) 2002 Ixia communications
++// 14 Oct 2002 Added support for groups vsundar@ixiacom.com
++// Copyright (C) 2002 Ixia communications
++// 5 Jan 2003 Bugfixes: reserved inodes should be set vsundar@usc.edu
++// only in the first group; directory names
++// need to be null padded at the end; and
++// number of blocks per group should be a
++// multiple of 8. Updated md5 values.
++// 6 Jan 2003 Erik Andersen <andersee@debian.org> added
++// mkfs.jffs2 compatible device table support,
++// along with -q, -P, -U
// `genext2fs' is a mean to generate an ext2 filesystem
-@@ -33,10 +37,6 @@
+@@ -33,10 +50,6 @@
// the image file to copy files on it. It doesn't even require
// you to be the superuser to make device nodes.
//
// Example usage:
//
// # genext2fs -b 1440 -d srcdir /dev/fd0
-@@ -45,28 +45,24 @@
+@@ -45,21 +58,15 @@
// a new ext2 filesystem image. You can then mount the floppy as
// usual.
//
-// This device list builds the /dev directory, a character device
-// node /dev/lcd (major 10, minor 190) and a block device node
-// /dev/ram0 (major 1, minor 0)
--
-+// then would read a devices table and make apropriate nodes. The
-+// format for the device list is illustrared in the device_table.txt
-+// file which in included with the source
++// then would read the device_table.txt file and make apropriate nodes.
++// The format for the device table file is covered in detail in the sample
++// device_table.txt file provided with the genext2fs source.
+
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
- #include <dirent.h>
+@@ -67,6 +74,11 @@
#include <stdarg.h>
-+#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
++#include <assert.h>
++#include <time.h>
+#include <ctype.h>
++#include <errno.h>
+#include <fcntl.h>
-@@ -390,6 +386,7 @@
+@@ -76,10 +88,14 @@
+ #define BLOCKSIZE 1024
+ #define BLOCKS_PER_GROUP 8192
+ #define BYTES_PER_INODE (8*BLOCKSIZE)
++/* Percentage of blocks that are reserved.*/
+ #define RESERVED_INODES 5/100
+
+
+ // inode block size (why is it != BLOCKSIZE ?!?)
++/* The field i_blocks in the ext2 inode stores the number of data blocks
++ but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
++ INOBLK is the number of such blocks in an actual disk block */
+
+ #define INODE_BLOCKSIZE 512
+ #define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE)
+@@ -147,6 +163,39 @@
+
+ #define OP_HOLES 0x01 // make files with holes
+
++/* Defines for accessing group details */
++
++// Number of groups in the filesystem
++#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group )
++
++// Get group block bitmap (bbm) given the group number
++#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
++
++// Get group inode bitmap (ibm) given the group number
++#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
++
++// Given an inode number find the group it belongs to
++#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
++
++//Given an inode number get the inode bitmap that covers it
++#define GRP_GET_INODE_BITMAP(fs,nod) \
++ ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
++
++//Given an inode number find its offset within the inode bitmap that covers it
++#define GRP_IBM_OFFSET(fs,nod) \
++ ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
++
++// Given a block number find the group it belongs to
++#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
++
++//Given a block number get the block bitmap that covers it
++#define GRP_GET_BLOCK_BITMAP(fs,blk) \
++ ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
++
++//Given a block number find its offset within the block bitmap that covers it
++#define GRP_BBM_OFFSET(fs,blk) \
++ ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
++
+
+ // used types
+
+@@ -287,7 +336,6 @@
+ {
+ groupdescriptor_decl
+ uint32 bg_reserved[3];
+- uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];
+ } groupdescriptor;
+
+ typedef struct
+@@ -304,6 +352,32 @@
+
+ typedef uint8 block[BLOCKSIZE];
+
++/* blockwalker fields:
++ The blockwalker is used to access all the blocks of a file (including
++ the indirection blocks) through repeated calls to walk_bw.
++
++ bpdir -> index into the inode->i_block[]. Indicates level of indirection.
++ bnum -> total number of blocks so far accessed. including indirection
++ blocks.
++ bpind,bpdind,bptind -> index into indirection blocks.
++
++ bpind, bpdind, bptind do *NOT* index into single, double and triple
++ indirect blocks resp. as you might expect from their names. Instead
++ they are in order the 1st, 2nd & 3rd index to be used
++
++ As an example..
++ To access data block number 70000:
++ bpdir: 15 (we are doing triple indirection)
++ bpind: 0 ( index into the triple indirection block)
++ bpdind: 16 ( index into the double indirection block)
++ bptind: 99 ( index into the single indirection block)
++ 70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
++
++ So,for double indirection bpind will index into the double indirection
++ block and bpdind into the single indirection block. For single indirection
++ only bpind will be used.
++*/
++
+ typedef struct
+ {
+ uint32 bnum;
+@@ -313,15 +387,14 @@
+ uint32 bptind;
+ } blockwalker;
+
++
++/* Filesystem structure that support groups */
+ #if BLOCKSIZE == 1024
+ typedef struct
+ {
+ block zero; // The famous block 0
+ superblock sb; // The superblock
+- groupdescriptor gd; // The group desciptor
+- block bbm; // The block bitmap
+- block ibm; // The inode bitmap
+- inode itab[0]; // The inode table
++ groupdescriptor gd[0]; // The group descriptors
+ } filesystem;
+ #else
+ #error UNHANDLED BLOCKSIZE
+@@ -389,25 +462,84 @@
+ #undef udecl32
#undef utdecl32
- char * argv0;
-+int nosquash = 0;
+-char * argv0;
++static char * app_name;
++static int squash_uids = 0;
++static int squash_perms = 0;
++static const char *const memory_exhausted = "memory exhausted";
// error (un)handling
- inline void errexit(const char *fmt, ...)
-@@ -663,14 +660,27 @@
+-inline void errexit(const char *fmt, ...)
++static void verror_msg(const char *s, va_list p)
+ {
+- va_list ap;
+- fprintf(stderr, "%s: ", argv0);
+- va_start(ap, fmt);
+- vfprintf(stderr, fmt, ap);
+- va_end(ap);
+- fprintf(stderr, "\n");
+- exit(1);
++ fflush(stdout);
++ fprintf(stderr, "%s: ", app_name);
++ vfprintf(stderr, s, p);
++}
++static void error_msg(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ verror_msg(s, p);
++ va_end(p);
++ putc('\n', stderr);
++}
++
++static void error_msg_and_die(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ verror_msg(s, p);
++ va_end(p);
++ putc('\n', stderr);
++ exit(EXIT_FAILURE);
++}
++
++static void vperror_msg(const char *s, va_list p)
++{
++ int err = errno;
++ if (s == 0)
++ s = "";
++ verror_msg(s, p);
++ if (*s)
++ s = ": ";
++ fprintf(stderr, "%s%s\n", s, strerror(err));
+ }
+
+-inline void pexit(const char * fname)
++#if 0
++static void perror_msg(const char *s, ...)
++{
++ va_list p;
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++}
++#endif
++static void perror_msg_and_die(const char *s, ...)
+ {
+- fprintf(stderr, "%s: ", argv0);
+- perror(fname);
+- exit(1);
++ va_list p;
++ va_start(p, s);
++ vperror_msg(s, p);
++ va_end(p);
++ exit(EXIT_FAILURE);
++}
++
++static FILE *xfopen(const char *path, const char *mode)
++{
++ FILE *fp;
++ if ((fp = fopen(path, mode)) == NULL)
++ perror_msg_and_die("%s", path);
++ return fp;
++}
++
++extern char *xstrdup(const char *s)
++{
++ char *t;
++
++ if (s == NULL)
++ return NULL;
++ t = strdup(s);
++ if (t == NULL)
++ error_msg_and_die(memory_exhausted);
++ return t;
+ }
+
+ // printf helper macro
+@@ -423,7 +555,7 @@
+ {
+ }
+
+-// rounds a quantity up to a blocksize
++/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
+ uint32 rndup(uint32 qty, uint32 siz)
+ {
+ return (qty + (siz - 1)) & ~(siz - 1);
+@@ -444,7 +576,13 @@
+ // return a given inode from a filesystem
+ inline inode * get_nod(filesystem *fs, uint32 nod)
+ {
+- return &fs->itab[nod-1];
++ int grp,offset;
++ inode *itab;
++
++ offset = GRP_IBM_OFFSET(fs,nod);
++ grp = GRP_GROUP_OF_INODE(fs,nod);
++ itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
++ return itab+offset-1;
+ }
+
+ // allocate a given block/inode in the bitmap
+@@ -479,29 +617,57 @@
+ }
+
+ // allocate a block
+-uint32 alloc_blk(filesystem *fs)
++uint32 alloc_blk(filesystem *fs, uint32 nod)
+ {
+- uint32 bk;
+- if(!(bk = allocate(fs->bbm, 0)))
+- errexit("couldn't allocate a block (no free space)");
+- if(!(fs->gd.bg_free_blocks_count--))
+- errexit("group descr. free blocks count == 0 (corrupted fs?)");
++ uint32 bk=0;
++ uint32 grp,nbgroups;
++
++ grp = nod/fs->sb.s_inodes_per_group;
++ nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
++ fs->sb.s_blocks_per_group;
++ if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
++ for(grp=0;grp<nbgroups && !bk;grp++)
++ bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
++ grp--;
++ }
++ if (!bk)
++ error_msg_and_die("couldn't allocate a block (no free space)");
++ if(!(fs->gd[grp].bg_free_blocks_count--))
++ error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
+ if(!(fs->sb.s_free_blocks_count--))
+- errexit("superblock free blocks count == 0 (corrupted fs?)");
+- return bk;
++ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++ return fs->sb.s_blocks_per_group*grp + bk;
+ }
+
+ // allocate an inode
+ uint32 alloc_nod(filesystem *fs)
+ {
+- uint32 nod;
+- if(!(nod = allocate(fs->ibm, 0)))
+- errexit("couldn't allocate an inode (no free inode)");
+- if(!(fs->gd.bg_free_inodes_count--))
+- errexit("group descr. free blocks count == 0 (corrupted fs?)");
++ uint32 nod=0,best_group=0;
++ uint32 grp,nbgroups,avefreei;
++
++ nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
++ fs->sb.s_blocks_per_group;
++
++ /* Distribute inodes amongst all the blocks */
++ /* For every block group with more than average number of free inodes */
++ /* find the one with the most free blocks and allocate node there */
++ /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
++ /* We do it for all inodes. */
++ avefreei = fs->sb.s_free_inodes_count / nbgroups;
++ for(grp=0;grp<nbgroups && !nod;grp++) {
++ if (fs->gd[grp].bg_free_inodes_count < avefreei)
++ continue;
++ if (!best_group ||
++ fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
++ best_group = grp;
++ }
++ if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
++ error_msg_and_die("couldn't allocate an inode (no free inode)");
++ if(!(fs->gd[best_group].bg_free_inodes_count--))
++ error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
+ if(!(fs->sb.s_free_inodes_count--))
+- errexit("superblock free blocks count == 0 (corrupted fs?)");
+- return nod;
++ error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
++ return fs->sb.s_inodes_per_group*best_group+nod;
+ }
+
+ // print a bitmap allocation
+@@ -546,14 +712,14 @@
+ {
+ bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // direct block
+ else if(bw->bpdir < EXT2_NDIR_BLOCKS)
+ {
+ bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in indirect block
+ else if(bw->bpdir == EXT2_NDIR_BLOCKS)
+@@ -562,11 +728,11 @@
+ bw->bpdir = EXT2_IND_BLOCK;
+ bw->bpind = 0;
+ if(extend) // allocate indirect block
+- get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // block in indirect block
+ else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -575,7 +741,7 @@
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ bkref = &b[bw->bpind];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in first indirect block in first double indirect block
+ else if(bw->bpdir == EXT2_IND_BLOCK)
+@@ -585,14 +751,14 @@
+ bw->bpind = 0;
+ bw->bpdind = 0;
+ if(extend) // allocate double indirect block
+- get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate first indirect block
+- b[bw->bpind] = alloc_blk(fs);
++ b[bw->bpind] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
+@@ -602,7 +768,7 @@
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+ // first block in indirect block in double indirect block
+ else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
+@@ -612,20 +778,100 @@
+ bw->bpind++;
+ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
+ if(extend) // allocate indirect block
+- b[bw->bpind] = alloc_blk(fs);
++ b[bw->bpind] = alloc_blk(fs,nod);
+ b = (uint32*)get_blk(fs, b[bw->bpind]);
+ bkref = &b[bw->bpdind];
+ if(extend) // allocate first block
+- *bkref = hole ? 0 : alloc_blk(fs);
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++
++ /* Adding support for triple indirection */
++ /* Just starting triple indirection. Allocate the indirection
++ blocks and the first data block
++ */
++ else if (bw->bpdir == EXT2_DIND_BLOCK)
++ {
++ bw->bnum += 3;
++ bw->bpdir = EXT2_TIND_BLOCK;
++ bw->bpind = 0;
++ bw->bpdind = 0;
++ bw->bptind = 0;
++ if(extend) // allocate triple indirect block
++ get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ if(extend) // allocate first double indirect block
++ b[bw->bpind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if(extend) // allocate first indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Still processing a single indirect block down the indirection
++ chain.Allocate a data block for it
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bptind < BLOCKSIZE/4 -1) )
++ {
++ bw->bptind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Finished processing a single indirect block. But still in the
++ same double indirect block. Allocate new single indirect block
++ for it and a data block
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bpdind < BLOCKSIZE/4 -1) )
++ {
++ bw->bnum++;
++ bw->bptind = 0;
++ bw->bpdind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if (extend) // allocate single indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first data block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
++ }
++ /* Finished processing a double indirect block. Allocate the next
++ double indirect block and the single,data blocks for it
++ */
++ else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
++ (bw->bpind < BLOCKSIZE/4 - 1) )
++ {
++ bw->bnum += 2;
++ bw->bpdind = 0;
++ bw->bptind = 0;
++ bw->bpind++;
++ b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
++ if(extend) // allocate double indirect block
++ b[bw->bpind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpind]);
++ if(extend) // allocate single indirect block
++ b[bw->bpdind] = alloc_blk(fs,nod);
++ b = (uint32*)get_blk(fs, b[bw->bpdind]);
++ bkref = &b[bw->bptind];
++ if(extend) // allocate first block
++ *bkref = hole ? 0 : alloc_blk(fs,nod);
+ }
+- // I don't do triple indirect - it's such a small filesystem ...
+ else
+- errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod);
++ error_msg_and_die("file too big !");
++ /* End change for walking triple indirection */
++
+ if(*bkref)
+ {
+ bw->bnum++;
+- if(!allocated(fs->bbm, *bkref))
+- errexit("[block %d of inode %d is unallocated !]", *bkref, nod);
++ if(!allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
++ error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
+ }
+ if(extend)
+ get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
+@@ -663,23 +909,40 @@
}
// link an entry (inode #) to a directory
directory *d;
int reclen, nlen;
- if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR)
+- errexit("can't add '%s' to a non-directory", name);
+ inode *node;
+ inode *pnode;
-+
-+ if (nosquash == 0) {
-+ /* Ok, squash everything */
-+ uid = 0;
-+ gid = 0;
-+ if(!S_ISDIR(mode))
-+ mode &= ~(S_IWGRP | S_IWOTH);
-+ mode &= ~(S_ISUID | S_ISGID);
++
++ /* Squash all permissions so files are owned by root
++ * and file permissions have group/other perms removed */
++ if (squash_uids) {
++ uid = gid = 0;
++ }
++ if (squash_perms) {
++ if (!S_ISLNK(mode)) {
++ mode &= ~(S_IWGRP | S_IWOTH);
++ mode &= ~(S_ISUID | S_ISGID);
++ }
+ }
++
+ pnode = get_nod(fs, dnod);
+
+ if(!S_ISDIR(pnode->i_mode))
- errexit("can't add '%s' to a non-directory", name);
++ error_msg_and_die("can't add '%s' to a non-directory", name);
if(!*name)
- errexit("bad name '%s' (not meaningful)", name);
-@@ -691,9 +701,16 @@
+- errexit("bad name '%s' (not meaningful)", name);
++ error_msg_and_die("bad name '%s' (not meaningful)", name);
+ if(strchr(name, '/'))
+- errexit("bad name '%s' (contains a slash)", name);
++ error_msg_and_die("bad name '%s' (contains a slash)", name);
+ nlen = strlen(name);
+ reclen = sizeof(directory) + rndup(nlen, 4);
+ if(reclen > BLOCKSIZE)
+- errexit("bad name '%s' (too long)", name);
++ error_msg_and_die("bad name '%s' (too long)", name);
+ init_bw(fs, dnod, &bw);
+ while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
+ {
+@@ -691,9 +954,16 @@
if((!d->d_inode) && (d->d_rec_len >= reclen))
{
d->d_inode = nod;
+ node = get_nod(fs, nod);
+ node->i_links_count++;
d->d_name_len = nlen;
- strncpy(d->d_name, name, nlen);
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
+ node->i_mode = mode;
+ node->i_uid = uid;
+ node->i_gid = gid;
return;
}
// if entry with enough room (last one?), shrink it & use it
-@@ -705,9 +722,16 @@
+@@ -705,9 +975,16 @@
d = (directory*) (((int8*)d) + d->d_rec_len);
d->d_rec_len = reclen;
d->d_inode = nod;
+ node = get_nod(fs, nod);
+ node->i_links_count++;
d->d_name_len = nlen;
- strncpy(d->d_name, name, nlen);
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
+ node->i_mode = mode;
+ node->i_uid = uid;
+ node->i_gid = gid;
return;
}
}
-@@ -716,10 +740,17 @@
+@@ -716,10 +993,17 @@
b = get_workblk();
d = (directory*)b;
d->d_inode = nod;
+ node->i_links_count++;
d->d_rec_len = BLOCKSIZE;
d->d_name_len = nlen;
- strncpy(d->d_name, name, nlen);
+- strncpy(d->d_name, name, nlen);
++ strncpy(d->d_name, name, rndup(nlen,4));
+ node->i_mode = mode;
+ node->i_uid = uid;
+ node->i_gid = gid;
extend_blk(fs, dnod, b, 1);
get_nod(fs, dnod)->i_size += BLOCKSIZE;
free_workblk(b);
-@@ -770,27 +801,29 @@
+@@ -747,7 +1031,7 @@
+ // find the inode of a full path
+ uint32 find_path(filesystem *fs, uint32 nod, const char * name)
+ {
+- char *p, *n, *n2 = strdup(name);
++ char *p, *n, *n2 = xstrdup(name);
+ n = n2;
+ while(*n == '/')
+ {
+@@ -770,27 +1054,32 @@
}
// make a full-fledged directory (i.e. with "." & "..")
-uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode)
-+uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, uid_t uid, gid_t gid, time_t ctime)
++uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
++ uid_t uid, gid_t gid, time_t ctime)
{
uint32 nod;
if((nod = find_dir(fs, parent_nod, name)))
- add2dir(fs, parent_nod, nod, name);
- add2dir(fs, nod, nod, ".");
- add2dir(fs, nod, parent_nod, "..");
+- fs->gd.bg_used_dirs_count++;
+ if (!(mode & FM_IFDIR))
+ mode |= FM_IFDIR;
+ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
+ add2dir(fs, nod, nod, ".", mode, uid, gid, ctime);
+ add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime);
- fs->gd.bg_used_dirs_count++;
++ fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
return nod;
}
// make a symlink
-uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b)
-+uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b, uid_t uid, gid_t gid, time_t ctime)
++uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size,
++ uint8 * b, uid_t uid, gid_t gid, time_t ctime)
{
+ uint32 mode;
uint32 nod = alloc_nod(fs);
-- get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+ get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
get_nod(fs, nod)->i_size = size;
- add2dir(fs, parent_nod, nod, name);
+ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
if(size <= 4 * (EXT2_TIND_BLOCK+1))
{
strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
-@@ -801,13 +834,13 @@
+@@ -801,15 +1090,15 @@
}
// make a file from a FILE*
- add2dir(fs, parent_nod, nod, name);
+ add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE))))
- errexit("not enough mem to read file '%s'", name);
+- errexit("not enough mem to read file '%s'", name);
++ error_msg_and_die("not enough mem to read file '%s'", name);
memset(b, 0,rndup(size, BLOCKSIZE));
-@@ -824,6 +857,8 @@
+ if(f)
+ fread(b, size, 1, f);
+@@ -824,6 +1113,15 @@
uint32 get_mode(struct stat *st)
{
uint32 mode = 0;
-+ if (nosquash == 1)
-+ return st->st_mode;
++
++ /* Squash file permissions as needed */
++ if (squash_perms) {
++ if (!S_ISLNK(mode)) {
++ st->st_mode &= ~(S_IWGRP | S_IWOTH);
++ st->st_mode &= ~(S_ISUID | S_ISGID);
++ }
++ }
++
if(st->st_mode & S_IRUSR)
mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
if(st->st_mode & S_IWUSR)
-@@ -833,19 +868,6 @@
+@@ -831,32 +1129,19 @@
+ if(st->st_mode & S_IXUSR)
+ mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
return mode;
- }
-
+-}
+-
-// retrieves a mode info from a string
-uint32 get_modestr(const char *p)
-{
- if(p[2] == 'x' || p[2] == 's')
- mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
- return mode;
--}
--
+ }
+
// basename of a path - free me
char * basename(const char * fullpath)
{
-@@ -864,66 +886,6 @@
+ char * p = strrchr(fullpath, '/');
+- return strdup(p ? p + 1 : fullpath);
++ return xstrdup(p ? p + 1 : fullpath);
+ }
+
+ // dirname of a path - free me
+ char * dirname(const char * fullpath)
+ {
+- char * p, * n = strdup(fullpath);
++ char * p, * n = xstrdup(fullpath);
+ if((p = strrchr(n, '/')))
+ *(p+1) = 0;
+ else
+@@ -864,66 +1150,6 @@
return n;
}
// adds a tree of entries to the filesystem from current dir
void add2fs_from_dir(filesystem *fs, uint32 this_nod)
{
-@@ -948,24 +910,24 @@
+@@ -934,7 +1160,7 @@
+ struct stat st;
+ uint8 *b;
+ if(!(dh = opendir(".")))
+- pexit(".");
++ perror_msg_and_die(".");
+ while((dent = readdir(dh)))
+ {
+ if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+@@ -948,31 +1174,30 @@
get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st);
((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff);
((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8);
break;
case S_IFLNK:
if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE))))
- errexit("out of memory");
+- errexit("out of memory");
++ error_msg_and_die("out of memory");
if(readlink(dent->d_name, (char*)b, st.st_size) < 0)
- pexit(dent->d_name);
+- pexit(dent->d_name);
- mklink_fs(fs, this_nod, dent->d_name, st.st_size, b);
++ perror_msg_and_die(dent->d_name);
+ mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime);
free(b);
break;
case S_IFREG:
- if(!(fh = fopen(dent->d_name, "r")))
- pexit(dent->d_name);
+- if(!(fh = fopen(dent->d_name, "r")))
+- pexit(dent->d_name);
- mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh);
++ fh = xfopen(dent->d_name, "r");
+ mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime);
fclose(fh);
break;
- nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st));
+ nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
if(chdir(dent->d_name) < 0)
- pexit(dent->d_name);
+- pexit(dent->d_name);
++ perror_msg_and_die(dent->d_name);
add2fs_from_dir(fs, nod);
-@@ -983,7 +945,7 @@
+ chdir("..");
+ break;
+ default:
+- fprintf(stderr, "ignoring entry %s", dent->d_name);
++ error_msg("ignoring entry %s", dent->d_name);
+ }
+ }
+ closedir(dh);
+@@ -981,9 +1206,11 @@
+ // endianness swap of x-indirect blocks
+ void swap_goodblocks(filesystem *fs, inode *nod)
{
- int i;
+- int i;
++ int i,j,done=0;
++ uint32 *b,*b2;
++
int nblk = nod->i_blocks / INOBLK;
- if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
-+ if(nod->i_size && !nblk)
++ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
for(i = 0; i <= EXT2_TIND_BLOCK; i++)
nod->i_block[i] = swab32(nod->i_block[i]);
if(nblk <= EXT2_IND_BLOCK)
-@@ -1004,7 +966,7 @@
+@@ -991,20 +1218,55 @@
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
+ return;
++ /* Currently this will fail b'cos the number of blocks as stored
++ in i_blocks also includes the indirection blocks (see
++ walk_bw). But this function assumes that i_blocks only
++ stores the count of data blocks ( Actually according to
++ "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
++ i_blocks IS supposed to store the count of data blocks). so
++ with a file of size 268K nblk would be 269.The above check
++ will be false even though double indirection hasn't been
++ started.This is benign as 0 means block 0 which has been
++ zeroed out and therefore points back to itself from any offset
++ */
++ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ for(i = 0; i < BLOCKSIZE/4; i++)
++ /* Should this be...
++ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
++ */
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+- errexit("too big file on the filesystem");
++ /* Adding support for triple indirection */
++ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++ b2 = (uint32*)get_blk(fs,b[i]);
++ for(j=0; j<BLOCKSIZE/4;j++) {
++ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
++ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ j*(BLOCKSIZE/4)) )
++ swap_block(get_blk(fs,b2[j]));
++ else {
++ done = 1;
++ break;
++ }
++ }
++ swap_block((uint8 *)b2);
++ }
++ swap_block((uint8 *)b);
++ return;
+ }
+
+ void swap_badblocks(filesystem *fs, inode *nod)
{
- int i;
+- int i;
++ int i,j,done=0;
++ uint32 *b,*b2;
++
int nblk = nod->i_blocks / INOBLK;
- if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
-+ if(nod->i_size && !nblk)
++ if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
for(i = 0; i <= EXT2_TIND_BLOCK; i++)
nod->i_block[i] = swab32(nod->i_block[i]);
if(nblk <= EXT2_IND_BLOCK)
-@@ -1147,7 +1109,7 @@
+@@ -1012,13 +1274,34 @@
+ swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
+ return;
++ /* See comment in swap_goodblocks */
++ assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ for(i = 0; i < BLOCKSIZE/4; i++)
++ /* See comment in swap_goodblocks */
+ if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
+ swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ return;
+- errexit("too big file on the filesystem");
++ /* Adding support for triple indirection */
++ b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
++ swap_block((uint8 *)b);
++ for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
++ b2 = (uint32*)get_blk(fs,b[i]);
++ swap_block((uint8 *)b2);
++ for(j=0; j<BLOCKSIZE/4;j++) {
++ if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
++ (BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
++ j*(BLOCKSIZE/4)) )
++ swap_block(get_blk(fs,b2[j]));
++ else {
++ done = 1;
++ break;
++ }
++ }
++ }
++ return;
+ }
+
+ // endianness swap of the whole filesystem
+@@ -1045,7 +1328,8 @@
+ swap_goodblocks(fs, nod);
+ swap_nod(nod);
+ }
+- swap_gd(&fs->gd);
++ for(i=0;i<GRP_NBGROUPS(fs);i++)
++ swap_gd(&(fs->gd[i]));
+ swap_sb(&fs->sb);
+ }
+
+@@ -1053,7 +1337,8 @@
+ {
+ int i;
+ swap_sb(&fs->sb);
+- swap_gd(&fs->gd);
++ for(i=0;i<GRP_NBGROUPS(fs);i++)
++ swap_gd(&(fs->gd[i]));
+ for(i = 1; i < fs->sb.s_inodes_count; i++)
+ {
+ inode *nod = get_nod(fs, i);
+@@ -1084,53 +1369,118 @@
+ directory *d;
+ uint8 * b;
+ uint32 nod;
++ uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
++ free_blocks_per_group,nbblocks_per_group;
++ uint32 gd,itbl,ibmpos,bbmpos,itblpos;
++ int j;
++ uint8 *bbm,*ibm;
++ inode *itab0;
+
+ if(nbblocks < 16) // totally arbitrary
+- errexit("too small filesystem");
+- if(nbblocks >BLOCKS_PER_GROUP) // I build only one group
+- errexit("too big filesystem");
++ error_msg_and_die("too small filesystem");
++
++ /* nbblocks is the total number of blocks in the system. First
++ * calculate how much overhead blocks - inode table blocks,bitmap
++ * blocks,group descriptor blocks etc. - are needed assuming each
++ * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with
++ * this figure. Each group has the same number of blocks. So the fs
++ * has a size atleast the given value but usually rounded off to a i
++ * higher number.
++ */
++ nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP;
++ nbinodes_per_group = nbinodes/nbgroups +1;
++ nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode));
++ if (nbinodes_per_group < 16)
++ nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
++ overhead_per_group = 3 /*super block,ibm,bbm*/
++ + /* No. of blocks that the inodes occupy */
++ nbinodes_per_group *sizeof(inode)/BLOCKSIZE
++ + /* No. of blocks that group descriptors occupy */
++ rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++ free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */;
++ free_blocks_per_group = free_blocks/nbgroups;
++ if (free_blocks > free_blocks_per_group * nbgroups)
++ free_blocks_per_group++;
++ nbblocks_per_group = free_blocks_per_group + overhead_per_group;
++ /* e2fsck complains if nbblocks_per_group is not a multiple of 8 */
++ nbblocks_per_group = rndup(nbblocks_per_group,8);
++ free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++ if (nbblocks_per_group > BLOCKS_PER_GROUP) {
++ /* Can this happen ? */
++ nbblocks_per_group = BLOCKS_PER_GROUP;
++ free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++ }
++ nbblocks = nbblocks_per_group * nbgroups + 1;
++
++
+ if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+- errexit("not enough memory for filesystem");
++ error_msg_and_die("not enough memory for filesystem");
+
+ // create the superblock for an empty filesystem
+- fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode));
++ fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
+ fs->sb.s_blocks_count = nbblocks;
+ fs->sb.s_r_blocks_count = nbresrvd;
+- fs->sb.s_free_blocks_count = nbblocks;
++ fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups;
+ fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
+ fs->sb.s_first_data_block = (BLOCKSIZE == 1024);
+ fs->sb.s_log_block_size = BLOCKSIZE >> 11;
+ fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
+- fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP;
+- fs->sb.s_frags_per_group = BLOCKS_PER_GROUP;
+- fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
++ fs->sb.s_blocks_per_group = nbblocks_per_group;
++ fs->sb.s_frags_per_group = nbblocks_per_group;
++ fs->sb.s_inodes_per_group = nbinodes_per_group;
+ fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+
+ // set up groupdescriptors
+- fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE;
+- fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count;
+- fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count;
+- fs->gd.bg_used_dirs_count = 1;
+- fs->gd.bg_block_bitmap = 3;
+- fs->gd.bg_inode_bitmap = 4;
+- fs->gd.bg_inode_table = 5;
+-
+- // mark non-filesystem blocks and inodes as allocated
+- for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++)
+- allocate(fs->bbm, i);
+- for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++)
+- allocate(fs->ibm, i);
+-
+- // mark system blocsk and inodes as allocated
+- for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++)
+- allocate(fs->bbm, i);
+- for(i = 1; i < EXT2_FIRST_INO; i++)
+- allocate(fs->ibm, i);
+-
+- // make root inode and directory
+- fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
+- fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
+- fs->itab[EXT2_ROOT_INO-1].i_links_count = 2;
++ gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
++ itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE;
++ for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
++ i<nbgroups;
++ i++, bbmpos += nbblocks_per_group,ibmpos += nbblocks_per_group,
++ itblpos += nbblocks_per_group) {
++
++ fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
++ fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
++ fs->gd[i].bg_used_dirs_count = 0;
++ fs->gd[i].bg_block_bitmap = bbmpos;
++ fs->gd[i].bg_inode_bitmap = ibmpos;
++ fs->gd[i].bg_inode_table = itblpos;
++ }
++
++ /* Mark non-filesystem blocks and inodes as allocated */
++ /* Mark system blocks and inodes as allocated */
++ for(i = 0; i<nbgroups;i++) {
++
++ /* Block bitmap */
++ bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
++ //non-filesystem blocks.
++ for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++)
++ allocate(bbm, j);
++ //system blocks
++ for(j = 1; j <= 3+gd+itbl; j++)
++ allocate(bbm, j);
++
++ /* Inode bitmap */
++ ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
++ //non-filesystem inodes
++ for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
++ allocate(ibm, j);
++ }
++
++ /* We have groups now. Add the root filesystem in group 0 */
++ /* Also allocate the system inodes in group 0 and update */
++ /* directory count and inode count for group 0 */
++
++ ibm = get_blk(fs,fs->gd[0].bg_inode_bitmap);
++ for(j = 1; j < EXT2_FIRST_INO; j++) {
++ allocate(ibm, j);
++ fs->gd[0].bg_free_inodes_count--;
++ }
++ fs->gd[0].bg_used_dirs_count = 1;
++ itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
++ itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
++ itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
++ itab0[EXT2_ROOT_INO-1].i_links_count = 2;
++
+ b = get_workblk();
+ d = (directory*)b;
+ d->d_inode = EXT2_ROOT_INO;
+@@ -1147,9 +1497,14 @@
// make lost+found directory and reserve blocks
if(fs->sb.s_r_blocks_count)
{
+ nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL));
memset(b, 0, BLOCKSIZE);
((directory*)b)->d_rec_len = BLOCKSIZE;
++ /* We run into problems with e2fsck if directory lost+found grows
++ * bigger than this. Need to find out why this happens - sundar
++ */
++ if (fs->sb.s_r_blocks_count > 2049 )
++ fs->sb.s_r_blocks_count=2049;
for(i = 1; i < fs->sb.s_r_blocks_count; i++)
-@@ -1472,6 +1434,150 @@
+ extend_blk(fs, nod, b, 1);
+ get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
+@@ -1170,24 +1525,24 @@
+ // loads a filesystem from disk
+ filesystem * load_fs(FILE * fh, int swapit)
+ {
+- size_t fssize;
++ size_t fssize = 0;
+ filesystem *fs;
+ if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0))
+- pexit("input filesystem image");
++ perror_msg_and_die("input filesystem image");
+ rewind(fh);
+ fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
+ if(fssize < 16) // totally arbitrary
+- errexit("too small filesystem");
+- if(fssize > BLOCKS_PER_GROUP) // I build only one group
+- errexit("too big filesystem");
++ error_msg_and_die("too small filesystem");
++/* if(fssize > BLOCKS_PER_GROUP) // I build only one group
++ error_msg_and_die("too big filesystem"); */
+ if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
+- errexit("not enough memory for filesystem");
++ error_msg_and_die("not enough memory for filesystem");
+ if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
+- pexit("input filesystem image");
++ perror_msg_and_die("input filesystem image");
+ if(swapit)
swap_badfs(fs);
+ if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
+- errexit("not a suitable ext2 filesystem");
++ error_msg_and_die("not a suitable ext2 filesystem");
+ return fs;
}
-+char *simple_ltoa(unsigned long i)
-+{
-+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
-+ static char local[21];
-+ char *p = local;
-+ *p-- = '\0';
-+ do {
-+ *p-- = '0' + i % 10;
-+ i /= 10;
-+ } while (i > 0);
-+ return p + 1;
-+}
+@@ -1230,9 +1585,9 @@
+ while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
+ {
+ if(fsize <= 0)
+- errexit("wrong size while saving inode %d", nod);
++ error_msg_and_die("wrong size while saving inode %d", nod);
+ if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
+- errexit("error while saving inode %d", nod);
++ error_msg_and_die("error while saving inode %d", nod);
+ fsize -= BLOCKSIZE;
+ }
+ }
+@@ -1250,7 +1605,7 @@
+ {
+ int i, j;
+ if(fsize <= 0)
+- errexit("wrong size while saving inode %d", nod);
++ error_msg_and_die("wrong size while saving inode %d", nod);
+ b = get_blk(fs, bk);
+ for(i = 0; i < 64; i++)
+ {
+@@ -1406,7 +1761,7 @@
+ s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
+ }
+ printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
+- if(!allocated(fs->ibm, nod))
++ if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
+ {
+ printf("unallocated\n");
+ return;
+@@ -1440,24 +1795,46 @@
+ default:
+ list_blocks(fs, nod);
+ }
++ printf("Done with inode %d\n",nod);
+ }
+
+ // describes various fields in a filesystem
+ void print_fs(filesystem *fs)
+ {
+- int i;
+- printf("%d blocks (%d free, %d reserved), first data block: %d\n", fs->sb.s_blocks_count, fs->sb.s_free_blocks_count, fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
+- printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count);
+- printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
+- printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group);
+- printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table);
+- printf("block bitmap allocation:\n");
+- print_bm(fs->bbm, fs->sb.s_blocks_count);
+- printf("inode bitmap allocation:\n");
+- print_bm(fs->ibm, fs->sb.s_inodes_count);
+- for(i=1; i<=fs->sb.s_inodes_count; i++)
+- if(allocated(fs->ibm, i))
+- print_inode(fs, i);
++ int i,j;
++ uint8 *ibm;
++
++ printf("%d blocks (%d free, %d reserved), first data block: %d\n",
++ fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
++ fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
++ printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
++ fs->sb.s_free_inodes_count);
++ printf("block size = %d, frag size = %d\n",
++ fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
++ fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
++ printf("Number of groups: %d\n",GRP_NBGROUPS(fs));
++ printf("%d blocks per group,%d frags per group,%d inodes per group\n",
++ fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
++ fs->sb.s_inodes_per_group);
++ printf("Size of inode table: %d blocks\n",
++ fs->sb.s_inodes_per_group * sizeof(inode)/BLOCKSIZE);
++ for (i = 0; i < GRP_NBGROUPS(fs); i++) {
++ printf("Group No: %d\n", i);
++ printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
++ fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
++ fs->gd[i].bg_inode_table);
++ printf("Free blocks count: %d\n",fs->gd[i].bg_free_blocks_count);
++ printf("Free inodes count: %d\n",fs->gd[i].bg_free_inodes_count);
++ printf("Used dir count: %d\n",fs->gd[i].bg_used_dirs_count);
++ printf("block bitmap allocation:\n");
++ print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
++ printf("inode bitmap allocation:\n");
++ ibm = GRP_GET_GROUP_IBM(fs, i);
++ print_bm(ibm, fs->sb.s_inodes_per_group);
++ for (j = 1; j <= fs->sb.s_inodes_per_group; j++)
++ if (allocated(ibm, j))
++ print_inode(fs, i*fs->sb.s_inodes_per_group + j);
++ }
+ }
+
+ void dump_fs(filesystem *fs, FILE * fh, int swapit)
+@@ -1467,31 +1844,234 @@
+ if(swapit)
+ swap_goodfs(fs);
+ if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
+- pexit("output filesystem image");
++ perror_msg_and_die("output filesystem image");
+ if(swapit)
+ swap_badfs(fs);
+ }
+
++/* device table entries take the form of:
++ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
++ /dev/mem c 640 0 0 1 1 0 0 -
++
++ type can be one of:
++ f A regular file
++ d Directory
++ c Character special device file
++ b Block special device file
++ p Fifo (named pipe)
++
++ I don't bother with symlinks (permissions are irrelevant), hard
++ links (special cases of regular files), or sockets (why bother).
+
-+//# device list table
-+//# <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
-+///dev/mem c 640 0 0 1 1 0 0 -
++ Regular files must exist in the target root directory. If a char,
++ block, fifo, or directory does not exist, it will be created.
++*/
+static int interpret_table_entry(filesystem *fs, char *line)
+{
-+ int status;
-+ char type, *path;
-+ uint32 nod, nod2;
-+ char *name, *dir;
-+ unsigned long uid=0, gid=0, mode=755;
-+ unsigned long major=0, minor=0, start=0, increment=1, count=0;
-+
-+ status = sscanf(line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
-+ SCANF_STRING(path), &type, &mode, &uid, &gid, &major, &minor,
-+ &start, &increment, &count);
-+ if (status<0)
-+ return status;
-+
-+ name = basename(path);
-+ dir = dirname(path);
-+ free(path);
-+ if(!(nod = find_path(fs, EXT2_ROOT_INO, dir)))
-+ errexit("can't find directory '%s' to create '%s''", dir, name);
-+ free(dir);
-+ if((!strcmp(name, ".")) || (!strcmp(name, "..")))
++ char type, *name = NULL, *tmp, *dir, *bname;
++ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
++ unsigned long start = 0, increment = 1, count = 0;
++ inode *entry;
++ uint32 nod, parent;
++
++ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
++ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
++ &start, &increment, &count) < 0)
+ {
-+ free(name);
+ return 1;
+ }
-+
-+ switch(type)
-+ {
++
++ if (!strcmp(name, "/")) {
++ error_msg_and_die("Device table entries require absolute paths");
++ }
++
++ /* Check if this file already exists... */
++ switch (type) {
+ case 'd':
-+ mkdir_fs(fs, nod, name, mode|FM_IFDIR, uid, gid, time(NULL));
++ mode |= S_IFDIR;
++ break;
++ case 'f':
++ mode |= S_IFREG;
++ break;
++ case 'p':
++ mode |= S_IFIFO;
+ break;
+ case 'c':
++ mode |= S_IFCHR;
++ break;
+ case 'b':
-+ mode|= (type=='c')? FM_IFCHR : FM_IFBLK;
-+ if (count > 0) {
-+ int i, last;
-+ char buf[80];
-+ last = start+(count*increment);
-+ for(i = start; i<last; i++) {
-+ nod2 = alloc_nod(fs);
-+ ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor+(i*increment-start);
-+ ((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
-+ strncpy(buf, name, sizeof(buf)-1);
-+ strncat(buf, simple_ltoa(i*increment), sizeof(buf)-1);
-+ buf[79]='\0';
-+ //fprintf(stderr, "start=%ld, i=%d adding '%s'(%ld, %ld)\n", start, i, buf, major, minor+(i*increment-start));
-+ add2dir(fs, nod, nod2, buf, mode, uid, gid, time(NULL));
-+ }
-+ }
-+ else {
-+ nod2 = alloc_nod(fs);
-+ ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor;
-+ ((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
-+ add2dir(fs, nod, nod2, name, mode, uid, gid, time(NULL));
-+ }
++ mode |= S_IFBLK;
+ break;
+ default:
-+ fprintf(stderr,"%s: Type '%c' is not supported\n", path, type);
++ error_msg_and_die("Unsupported file type");
++ }
++ nod = 0;
++ if (count==0)
++ nod = find_path(fs, EXT2_ROOT_INO, name);
++ if (nod) {
++ /* Ok, we just need to fixup an existing entry
++ * and we will be all done... */
++ entry = get_nod(fs, nod);
++ entry->i_uid = uid;
++ entry->i_gid = gid;
++ entry->i_mode = mode;
++ if (major) {
++ dev_t rdev = makedev(major, minor);
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ }
++ } else {
++ /* Try and find our parent now */
++ tmp = xstrdup(name);
++ dir = dirname(tmp);
++ parent = find_path(fs, EXT2_ROOT_INO, dir);
++ free(tmp);
++ if (!parent) {
++ error_msg ("skipping device_table entry '%s': no parent directory!", name);
++ free(name);
++ return 1;
++ }
+
++ tmp = xstrdup(name);
++ bname = xstrdup(basename(tmp));
++ free(tmp);
++ switch (type) {
++ case 'd':
++ mkdir_fs(fs, parent, bname, mode|FM_IFDIR, uid, gid, time(NULL));
++ break;
++ case 'f':
++#if 0
++ {
++ // This is a bit odd.. This will try to include
++ // the file of the same name from your _build_
++ // system... Probably a very bad idea....
++ struct stat st;
++ FILE *fh = xfopen(name, "r");
++ lstat(name, &st);
++ mkfile_fs(fs, parent, bname, mode|FM_IFREG, st.st_size, fh, uid, gid, st.st_ctime);
++ fclose(fh);
++ }
++#else
++ error_msg("ignoring entry %s", name);
++#endif
++ break;
++ case 'p':
++ error_msg("ignoring entry %s", name);
++ break;
++ case 'c':
++ case 'b':
++ if (count > 0) {
++ dev_t rdev;
++ char *dname;
++ unsigned long i;
++ for (i = start; i < count; i++) {
++ asprintf(&dname, "%s%lu", bname, i);
++ nod = find_path(fs, EXT2_ROOT_INO, dname);
++ if (nod) {
++ /* We just need to fixup an existing entry */
++ entry = get_nod(fs, nod);
++ } else {
++ nod = alloc_nod(fs);
++ add2dir(fs, parent, nod, dname, mode, uid, gid, time(NULL));
++ entry = get_nod(fs, nod);
++ }
++ entry->i_uid = uid;
++ entry->i_gid = gid;
++ entry->i_mode = mode;
++ rdev = makedev(major, minor + (i * increment - start));
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ free(dname);
++ }
++ } else {
++ dev_t rdev = makedev(major, minor);
++ nod = alloc_nod(fs);
++ add2dir(fs, parent, nod, bname, mode, uid, gid, time(NULL));
++ entry = get_nod(fs, nod);
++ ((uint8*)entry->i_block)[0] = (rdev & 0xff);
++ ((uint8*)entry->i_block)[1] = (rdev >> 8);
++ }
++ break;
++ default:
++ error_msg_and_die("Unsupported file type");
++ }
++ free(bname);
+ }
+ free(name);
+ return 0;
+}
+
-+int parse_device_table(filesystem *fs, char *filename)
++static int parse_device_table(filesystem *root, FILE * file)
+{
-+ FILE *file;
+ char *line;
+ int status = 0;
+ size_t length = 0;
-+ struct stat statbuf;
+
-+ if (!filename) {
-+ fprintf(stderr, "No filename specified.\n");
-+ return(1);
-+ }
-+ if (!(file = fopen(filename, "r"))) {
-+ perror(filename);
-+ return(1);
-+ }
-+ if (fstat(fileno(file), &statbuf) < 0) {
-+ perror(filename);
-+ return(1);
-+ }
-+
-+ if (statbuf.st_size < 10) {
-+ fprintf(stderr, "%s: not a proper device table file\n", filename);
-+ return(1);
-+ }
++ /* Turn off squash, since we must ensure that values
++ * entered via the device table are not squashed */
++ squash_uids = 0;
++ squash_perms = 0;
+
+ /* Looks ok so far. The general plan now is to read in one
+ * line at a time, check for leading comment delimiters ('#'),
+ while (getline(&line, &length, file) != -1) {
+ /* First trim off any whitespace */
+ int len = strlen(line);
++
+ /* trim trailing whitespace */
-+ while ( len > 0 && isspace(line[len-1]))
-+ line[--len]='\0';
++ while (len > 0 && isspace(line[len - 1]))
++ line[--len] = '\0';
+ /* trim leading whitespace */
+ memmove(line, &line[strspn(line, " \n\r\t\v")], len);
+
++ /* How long are we after trimming? */
++ len = strlen(line);
++
+ /* If this is NOT a comment line, try to interpret it */
-+ if (length && *line!='#') {
-+ if (interpret_table_entry(fs, line))
-+ status=1;
++ if (len && *line != '#') {
++ if (interpret_table_entry(root, line))
++ status = 1;
+ }
+
+ free(line);
+ line = NULL;
+ }
-+
++ fclose(file);
+
+ return status;
+}
void showhelp(void)
{
fprintf(stderr, "Usage: %s [options] image\n"
-@@ -1485,6 +1591,8 @@
- " -g path Generate a block map file for this path\n"
- " -e value Fill unallocated blocks with value\n"
- " -z Make files with holes\n"
-+ " -n Do not squash permissions and owners. By default everythig is\n"
-+ " owned by root. This perserves file permissions and owners.\n"
- " -v Print resulting filesystem structure\n"
- " -h Show this help\n\n"
- "Example of spec file:\n"
-@@ -1520,22 +1628,21 @@
+ "Create an ext2 filesystem image from directories/files\n\n"
+- " -x image Use this image as a starting point\n"
+- " -d directory Add this directory as source\n"
+- " -f file Add nodes (e.g. devices) from this spec file\n"
+- " -b blocks Size in blocks\n"
+- " -i inodes Number of inodes\n"
+- " -r reserved Number of reserved blocks\n"
+- " -g path Generate a block map file for this path\n"
+- " -e value Fill unallocated blocks with value\n"
+- " -z Make files with holes\n"
+- " -v Print resulting filesystem structure\n"
+- " -h Show this help\n\n"
+- "Example of spec file:\n"
+- "drwx /dev\n"
+- "crw- 10,190 /dev/lcd\n"
+- "brw- 1,0 /dev/ram0\n\n"
+- "Report bugs to xavier.bestel@free.fr\n", argv0);
++ " -x image Use this image as a starting point\n"
++ " -d directory Add this directory as source\n"
++ " -b blocks Size in blocks\n"
++ " -i inodes Number of inodes\n"
++ " -r reserved Number of reserved blocks\n"
++ " -g path Generate a block map file for this path\n"
++ " -e value Fill unallocated blocks with value\n"
++ " -z Make files with holes\n"
++ " -D,-f Use the named FILE as a device table file\n"
++ " -q Squash permissions and owners making all files be owned by root\n"
++ " -U Squash owners making all files be owned by root\n"
++ " -P Squash permissions on all files\n"
++ " -v Print resulting filesystem structure\n"
++ " -h Show this help\n\n"
++ "Report bugs to xavier.bestel@free.fr\n", app_name);
+ }
+
+ #define MAX_DOPT 128
+@@ -1520,22 +2100,18 @@
int bigendian = !*(char*)&endian;
filesystem *fs;
int i;
- int c;
+ char c;
-+ char * devtable = NULL;
++ struct stat sb;
++ FILE *devtable = NULL;
- argv0 = argv[0];
+- argv0 = argv[0];
- if(argc <= 1)
- {
- showhelp();
- exit(1);
- }
- while((c = getopt(argc, argv, "x:f:d:b:i:r:g:e:zvh")) != EOF)
-+ while((c = getopt(argc, argv, "D:x:f:d:b:i:r:g:e:zvhn")) != EOF)
++ app_name = argv[0];
++ while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
switch(c)
{
case 'x':
fsin = optarg;
break;
-- case 'd':
-+ case 'D':
- case 'f':
-+ devtable = optarg;
-+ break;
-+ case 'd':
+ case 'd':
+- case 'f':
dopt[didx++] = optarg;
break;
case 'b':
-@@ -1556,6 +1663,9 @@
+@@ -1556,6 +2132,24 @@
case 'z':
holes = 1;
break;
-+ case 'n':
-+ nosquash = 1;
++ case 'f':
++ case 'D':
++ devtable = xfopen(optarg, "r");
++ if (fstat(fileno(devtable), &sb) < 0)
++ perror_msg_and_die(optarg);
++ if (sb.st_size < 10)
++ error_msg_and_die("%s: not a proper device table file", optarg);
++ break;
++ case 'q':
++ squash_uids = 1;
++ squash_perms = 1;
++ break;
++ case 'U':
++ squash_uids = 1;
++ break;
++ case 'P':
++ squash_perms = 1;
+ break;
case 'v':
verbose = 1;
break;
-@@ -1595,17 +1705,10 @@
+@@ -1566,16 +2160,14 @@
+ exit(1);
+ }
+ if(optind < (argc - 1))
+- errexit("too many arguments");
++ error_msg_and_die("too many arguments");
+ if(optind == (argc - 1))
+ fsout = argv[optind];
+ if(fsin)
+ {
+ if(strcmp(fsin, "-"))
+ {
+- FILE * fh = fopen(fsin, "r");
+- if(!fh)
+- pexit(fsin);
++ FILE * fh = xfopen(fsin, "r");
+ fs = load_fs(fh, bigendian);
+ fclose(fh);
+ }
+@@ -1585,7 +2177,7 @@
+ else
+ {
+ if(nbblocks == -1)
+- errexit("filesystem size unspecified");
++ error_msg_and_die("filesystem size unspecified");
+ if(nbinodes == -1)
+ nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
+ if(nbresrvd == -1)
+@@ -1595,35 +2187,30 @@
for(i = 0; i < didx; i++)
{
struct stat st;
- break;
case S_IFDIR:
if(!(pdir = getcwd(0, GETCWD_SIZE)))
- pexit(dopt[i]);
-@@ -1617,13 +1720,15 @@
+- pexit(dopt[i]);
++ perror_msg_and_die(dopt[i]);
+ if(chdir(dopt[i]) < 0)
+- pexit(dopt[i]);
++ perror_msg_and_die(dopt[i]);
+ add2fs_from_dir(fs, EXT2_ROOT_INO);
+ if(chdir(pdir) < 0)
+- pexit(pdir);
++ perror_msg_and_die(pdir);
free(pdir);
break;
default:
- errexit("%s in neither a file nor a directory", dopt[i]);
-+ errexit("%s must be a directory", dopt[i]);
++ error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
}
}
if(emptyval)
for(i = 1; i < fs->sb.s_blocks_count; i++)
- if(!allocated(fs->bbm, i))
+- if(!allocated(fs->bbm, i))
++ if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i)))
memset(get_blk(fs, i), emptyval, BLOCKSIZE);
+ if(devtable)
-+ parse_device_table(fs, devtable);
++ parse_device_table(fs, devtable);
if(verbose)
print_fs(fs);
for(i = 0; i < gidx; i++)
+@@ -1633,21 +2220,18 @@
+ char *p;
+ FILE *fh;
+ if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
+- errexit("path %s not found in filesystem", gopt[i]);
++ error_msg_and_die("path %s not found in filesystem", gopt[i]);
+ while((p = strchr(gopt[i], '/')))
+ *p = '_';
+ snprintf(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
+- if(!(fh = fopen(fname, "w")))
+- pexit(fname);
++ fh = xfopen(fname, "w");
+ fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
+ flist_blocks(fs, nod, fh);
+ fclose(fh);
+ }
+ if(strcmp(fsout, "-"))
+ {
+- FILE * fh = fopen(fsout, "w");
+- if(!fh)
+- pexit(fsout);
++ FILE * fh = xfopen(fsout, "w");
+ dump_fs(fs, fh, bigendian);
+ fclose(fh);
+ }
+diff -urN genext2fs-1.3.orig/test-mount.sh genext2fs-1.3/test-mount.sh
+--- genext2fs-1.3.orig/test-mount.sh 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/test-mount.sh 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,96 @@
++#!/bin/sh
++set -e
++
++cleanup () {
++ set +e
++ umount mnt 2>/dev/null
++ rm -rf mnt ext2.img lsout fout test 2>/dev/null
++}
++
++# dtest - Uses the -d directory option of genext2fs
++# Creates an image with a file of given size and verifies it
++# Usage: dtest file-size number-of-blocks
++dtest () {
++ size=$1; blocks=$2;fname=$size
++ echo "Testing with file of size $size "
++ mkdir -p test
++ cd test
++ dd if=/dev/zero of=file.$1 bs=1 count=$size
++ cd ..
++ ./genext2fs -b $blocks -d test ext2.img
++ md5=`md5sum ext2.img | cut -f1 -d " "`
++ if ! /sbin/e2fsck -fn ext2.img ; then
++ echo "fsck failed"
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ mkdir -p mnt
++ if ! mount -t ext2 -o loop ext2.img mnt; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ if (! [ -f mnt/file.$fname ]) || \
++ [ $fname != "`ls -al mnt | grep file.$fname |awk '{print $5}'`" ] ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ echo PASSED "(md5 checksum for the image: $md5)"
++ cleanup
++}
++
++# ftest - Uses the -f spec-file option of genext2fs
++# Creates an image with the devices mentioned in the given spec
++# file and verifies it
++# Usage: ftest spec-file number-of-blocks
++ftest () {
++ fname=$1; blocks=$2;
++ echo "Testing with devices file $fname"
++ ./genext2fs -b $blocks -f $fname ext2.img
++ md5=`md5sum ext2.img | cut -f 1 -d " "`
++ if ! /sbin/e2fsck -fn ext2.img ; then
++ echo "fsck failed"
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ mkdir -p mnt
++ if ! mount -t ext2 -o loop ext2.img mnt; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ if ! [ -d mnt/dev ] ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ cat dev.txt | grep ^[bc] | \
++ awk '{print $1substr($1,2)substr($1,2),$2,$3}'| \
++ sort -d -k3.6 > fout
++ ls -al mnt/dev | grep ^[bc] | \
++ awk '{ print $1,$5$6,"/dev/"$10}' | \
++ sort -d -k3.6 > lsout
++ if ! diff fout lsout ; then
++ echo FAILED
++ cleanup
++ exit 1
++ fi
++ echo PASSED "(md5 checksum for the image: $md5)"
++ cleanup
++}
++
++dtest 0 4096
++dtest 0 8193
++dtest 0 8194
++dtest 1 4096
++dtest 12288 4096
++dtest 274432 4096
++dtest 8388608 9000
++dtest 16777216 20000
++
++ftest dev.txt 4096
++
++exit 0
+diff -urN genext2fs-1.3.orig/test.sh genext2fs-1.3/test.sh
+--- genext2fs-1.3.orig/test.sh 1969-12-31 17:00:00.000000000 -0700
++++ genext2fs-1.3/test.sh 2003-01-06 08:22:30.000000000 -0700
+@@ -0,0 +1,53 @@
++#!/bin/sh
++set -e
++
++# dtest - Uses the -d directory option of genext2fs
++# Creates an image with a file of given size and verifies it
++# Usage: dtest file-size number-of-blocks correct-checksum
++dtest () {
++ size=$1; blocks=$2; checksum=$3
++ echo "Testing with file of size $size "
++ mkdir -p test
++ cd test
++ dd if=/dev/zero of=file.$1 bs=1 count=$size
++ cd ..
++ ./genext2fs -b $blocks -d test ext2.img
++ md5=`md5sum ext2.img | cut -d" " -f1`
++ rm -rf ext2.img test
++ if [ $md5 == $checksum ] ; then
++ echo PASSED
++ else
++ echo FAILED
++ exit 1
++ fi
++}
++
++# ftest - Uses the -f spec-file option of genext2fs
++# Creates an image with the devices mentioned in the given spec
++# file and verifies it
++# Usage: ftest spec-file number-of-blocks correct-checksum
++ftest () {
++ fname=$1; blocks=$2; checksum=$3
++ echo "Testing with devices file $fname"
++ ./genext2fs -b $blocks -f $fname ext2.img
++ md5=`md5sum ext2.img | cut -d" " -f1`
++ rm -rf ext2.img
++ if [ $md5 == $checksum ] ; then
++ echo PASSED
++ else
++ echo FAILED
++ exit 1
++ fi
++}
++
++dtest 0 4096 491a43ab93c2e5c186c9f1f72d88e5c5
++dtest 0 8193 6289224f0b7f151994479ba156c43505
++dtest 0 8194 3272c43c25e8d0c3768935861a643a65
++dtest 1 4096 5ee24486d33af88c63080b09d8cadfb5
++dtest 12288 4096 494498364defdc27b2770d1f9c1e3387
++dtest 274432 4096 65c4bd8d30bf563fa5434119a12abff1
++dtest 8388608 9000 9a49b0461ee236b7fd7c452fb6a1f2dc
++dtest 16777216 20000 91e16429c901b68d30f783263f0611b7
++
++ftest dev.txt 4096 921ee9343b0759e16ad8d979d7dd16ec
++exit 0