fix svn patch breakage in glib
[librecmc/librecmc.git] / obsolete-buildroot / sources / genext2fs.patch
1 diff -urN genext2fs-1.3.orig/Makefile genext2fs-1.3/Makefile
2 --- genext2fs-1.3.orig/Makefile 1969-12-31 17:00:00.000000000 -0700
3 +++ genext2fs-1.3/Makefile      2003-04-21 01:41:42.000000000 -0600
4 @@ -0,0 +1,46 @@
5 +CC=gcc
6 +CFLAGS=-Wall -O0 -g
7 +
8 +SRC=genext2fs.c
9 +OBJS=$(patsubst %.c,%.o, $(SRC))
10 +
11 +all: genext2fs
12 +INSTALL=install
13 +
14 +genext2fs: $(OBJS)
15 +       $(CC) $(CFLAGS) -o $@ $(OBJS) -o $@
16 +
17 +$(OBJS): %.o : %.c
18 +       $(CC) $(CFLAGS) -c $< -o $@
19 +
20 +$(OBJS): Makefile
21 +
22 +install:
23 +       $(INSTALL) -d $(DESTDIR)/usr/bin/
24 +       $(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/
25 +       $(INSTALL) -d $(DESTDIR)/usr/share/man/man8/
26 +       $(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/
27 +
28 +clean:
29 +       rm -rf *.o *.a core genext2fs
30 +       rm -rf test ext2.img
31 +
32 +check: all
33 +       mkdir -p test
34 +       dd if=/dev/zero of=test/zero count=1
35 +       ./genext2fs -b 4096 -d test ext2.img
36 +       
37 +       md5=`md5sum ext2.img | cut -f 1 -d " "`; \
38 +       if [ "$$md5" != "89471302d95f96a76fbb2cff98182cde" ] ; then \
39 +               echo "test failed."; \
40 +       else \
41 +               echo "test succeeded."; \
42 +       fi
43 +       
44 +# test genext2fs by creating the image and comparing checksums
45 +test: all
46 +       sh ./test.sh
47 +
48 +# test genext2fs by actually mounting the created image.
49 +test-mount: all
50 +       sudo sh ./test-mount.sh
51 diff -urN genext2fs-1.3.orig/debian/changelog genext2fs-1.3/debian/changelog
52 --- genext2fs-1.3.orig/debian/changelog 1969-12-31 17:00:00.000000000 -0700
53 +++ genext2fs-1.3/debian/changelog      2003-04-21 01:41:42.000000000 -0600
54 @@ -0,0 +1,17 @@
55 +genext2fs (1.3-2) unstable; urgency=low
56 +
57 +  * apply fix from upstream cvs that appears to fix endian bug 
58 +    (closes: #122411)
59 +  * mention filesystem size limit in manpage (closes: #122729)
60 +  * mention that hard links are not supported in manpage 
61 +    (closes: #155464)
62 +  * add sanity check at the end of the build
63 +
64 + -- David Kimdon <dwhedon@debian.org>  Fri,  8 Mar 2002 23:17:36 -0800
65 +
66 +genext2fs (1.3-1) unstable; urgency=low
67 +
68 +  * Initial Release. (closes: #105263)
69 +
70 + -- David Kimdon <dwhedon@debian.org>  Sat, 14 Jul 2001 13:24:49 -0700
71 +
72 diff -urN genext2fs-1.3.orig/debian/control genext2fs-1.3/debian/control
73 --- genext2fs-1.3.orig/debian/control   1969-12-31 17:00:00.000000000 -0700
74 +++ genext2fs-1.3/debian/control        2003-04-21 01:41:42.000000000 -0600
75 @@ -0,0 +1,19 @@
76 +Source: genext2fs
77 +Section: admin
78 +Priority: optional
79 +Maintainer: David Kimdon <dwhedon@debian.org>
80 +Build-Depends: debhelper (>> 3.0.0)
81 +Standards-Version: 3.5.2
82 +
83 +Package: genext2fs
84 +Architecture: any
85 +Depends: ${shlibs:Depends}
86 +Description: ext2 filesystem generator for embedded systems
87 + `genext2fs' is meant to generate an ext2 filesystem
88 + as a normal (non-root) user. It doesn't require you to mount
89 + the image file to copy files on it. It doesn't even require
90 + you to be the superuser to make device nodes.
91 + .
92 + Warning ! `genext2fs' has been designed for embedded
93 + systems. As such, it will generate a filesystem for single-user
94 + usage: all files/directories/etc... will belong to UID/GID 0
95 diff -urN genext2fs-1.3.orig/debian/copyright genext2fs-1.3/debian/copyright
96 --- genext2fs-1.3.orig/debian/copyright 1969-12-31 17:00:00.000000000 -0700
97 +++ genext2fs-1.3/debian/copyright      2003-04-21 01:41:42.000000000 -0600
98 @@ -0,0 +1,15 @@
99 +This package was debianized by David Kimdon <dwhedon@debian.org> on
100 +Sat, 14 Jul 2001 13:24:49 -0700.
101 +
102 +It was downloaded from http://freshmeat.net/projects/genext2fs/
103 +Upstream Author(s):   Xavier Bestel <xbestel@aplio.fr>
104 +
105 +Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
106 +
107 +This program is free software; you can redistribute it and/or
108 +modify it under the terms of the GNU General Public License
109 +as published by the Free Software Foundation; version
110 +2 of the License.
111 +
112 +On Debian systems, the complete text of the GNU General Public
113 +License can be found in /usr/share/common-licenses/GPL file.
114 diff -urN genext2fs-1.3.orig/debian/rules genext2fs-1.3/debian/rules
115 --- genext2fs-1.3.orig/debian/rules     1969-12-31 17:00:00.000000000 -0700
116 +++ genext2fs-1.3/debian/rules  2003-04-21 01:41:42.000000000 -0600
117 @@ -0,0 +1,70 @@
118 +#!/usr/bin/make -f
119 +# Sample debian/rules that uses debhelper.
120 +# GNU copyright 1997 to 1999 by Joey Hess.
121 +
122 +# Uncomment this to turn on verbose mode.
123 +#export DH_VERBOSE=1
124 +
125 +# This is the debhelper compatability version to use.
126 +export DH_COMPAT=2
127 +
128 +configure: configure-stamp
129 +configure-stamp:
130 +       dh_testdir
131 +       # Add here commands to configure the package.
132 +       # ./configure --prefix=/usr --mandir=/usr/share/man/
133 +
134 +       touch configure-stamp
135 +
136 +build: configure-stamp build-stamp
137 +build-stamp:
138 +       dh_testdir
139 +
140 +       # Add here commands to compile the package.
141 +       $(MAKE)
142 +       $(MAKE) check
143 +
144 +       touch build-stamp
145 +
146 +clean:
147 +       dh_testdir
148 +       dh_testroot
149 +       rm -f build-stamp configure-stamp
150 +
151 +       # Add here commands to clean up after the build process.
152 +       -$(MAKE) clean
153 +
154 +       dh_clean
155 +
156 +install: build
157 +       dh_testdir
158 +       dh_testroot
159 +       dh_clean -k
160 +       dh_installdirs
161 +
162 +       # Add here commands to install the package into debian/genext2fs.
163 +       $(MAKE) install DESTDIR=`pwd`/debian/genext2fs
164 +
165 +
166 +# Build architecture-independent files here.
167 +binary-indep: build install
168 +# We have nothing to do by default.
169 +
170 +# Build architecture-dependent files here.
171 +binary-arch: build install
172 +       dh_testdir
173 +       dh_testroot
174 +       dh_installdocs
175 +       dh_installchangelogs 
176 +       dh_link
177 +       dh_strip
178 +       dh_compress
179 +       dh_fixperms
180 +       dh_installdeb
181 +       dh_shlibdeps
182 +       dh_gencontrol
183 +       dh_md5sums
184 +       dh_builddeb
185 +
186 +binary: binary-indep binary-arch
187 +.PHONY: build clean binary-indep binary-arch binary install configure
188 diff -urN genext2fs-1.3.orig/dev.txt genext2fs-1.3/dev.txt
189 --- genext2fs-1.3.orig/dev.txt  2000-09-28 09:03:19.000000000 -0600
190 +++ genext2fs-1.3/dev.txt       1969-12-31 17:00:00.000000000 -0700
191 @@ -1,94 +0,0 @@
192 -drwx           /dev
193 -crw-   10,190  /dev/lcd
194 -crw-   10,191  /dev/splc781
195 -crw-   4,0     /dev/console
196 -crw-   5,64    /dev/cua0
197 -crw-   5,65    /dev/cua1
198 -crw-   5,66    /dev/cua2
199 -crw-   5,70    /dev/cua6
200 -crw-   5,71    /dev/cua7
201 -crw-   5,72    /dev/cua8
202 -crw-   5,73    /dev/cua9
203 -crw-   29,0    /dev/fb0
204 -crw-   29,32   /dev/fb1
205 -crw-   1,2     /dev/kmem
206 -crw-   1,1     /dev/mem
207 -crw-   1,3     /dev/null
208 -crw-   2,2     /dev/ptyp2
209 -crw-   2,3     /dev/ptyp3
210 -crw-   2,5     /dev/ptyp5
211 -crw-   2,4     /dev/ptyp4
212 -crw-   10,178  /dev/triokb
213 -crw-   2,0     /dev/ptyp0
214 -crw-   2,6     /dev/ptyp6
215 -crw-   2,7     /dev/ptyp7
216 -crw-   2,8     /dev/ptyp8
217 -crw-   2,9     /dev/ptyp9
218 -crw-   2,10    /dev/ptypa
219 -crw-   2,11    /dev/ptypb
220 -crw-   2,12    /dev/ptypc
221 -crw-   2,13    /dev/ptypd
222 -crw-   2,14    /dev/ptype
223 -crw-   2,15    /dev/ptypf
224 -brw-   1,0     /dev/ram0
225 -brw-   1,1     /dev/ram1
226 -brw-   1,2     /dev/ram2
227 -brw-   1,3     /dev/ram3
228 -br--   31,0    /dev/rom0
229 -brw-   31,1    /dev/rom1
230 -brw-   31,2    /dev/rom2
231 -brw-   31,3    /dev/rom3
232 -crw-   5,0     /dev/tty
233 -crw-   4,0     /dev/tty0
234 -crwx   4,1     /dev/tty1
235 -crwx   4,2     /dev/tty2
236 -crwx   4,3     /dev/tty3
237 -crwx   4,4     /dev/tty4
238 -crw-   4,5     /dev/tty5
239 -crwx   4,6     /dev/tty6
240 -crw-   4,7     /dev/tty7
241 -crw-   4,8     /dev/tty8
242 -crw-   4,9     /dev/tty9
243 -crw-   4,64    /dev/ttyS0
244 -crw-   4,65    /dev/ttyS1
245 -crw-   4,66    /dev/ttyS2
246 -crw-   4,67    /dev/ttyS3
247 -crw-   4,68    /dev/ttyS4
248 -crw-   4,69    /dev/ttyS5
249 -crw-   4,70    /dev/ttyS6
250 -crw-   4,71    /dev/ttyS7
251 -crw-   4,72    /dev/ttyS8
252 -crw-   4,73    /dev/ttyS9
253 -crw-   3,0     /dev/ttyp0
254 -crw-   3,1     /dev/ttyp1
255 -crw-   3,2     /dev/ttyp2
256 -crw-   3,3     /dev/ttyp3
257 -crw-   3,4     /dev/ttyp4
258 -crw-   3,5     /dev/ttyp5
259 -crw-   3,6     /dev/ttyp6
260 -crw-   3,7     /dev/ttyp7
261 -crw-   3,8     /dev/ttyp8
262 -crw-   3,9     /dev/ttyp9
263 -crw-   3,10    /dev/ttypa
264 -crw-   3,11    /dev/ttypb
265 -crw-   3,12    /dev/ttypc
266 -crw-   3,13    /dev/ttypd
267 -crw-   3,14    /dev/ttype
268 -crw-   3,15    /dev/ttypf
269 -crw-   1,5     /dev/zero
270 -crwx   10,111  /dev/dtedrv
271 -crwx   4,110   /dev/ttyM
272 -crw-   77,1    /dev/tssnd
273 -crw-   77,2    /dev/tstone
274 -crw-   2,1     /dev/ptyp1
275 -crwx   10,180  /dev/triohook
276 -crw-   90,0    /dev/mtd0
277 -brw-   44,0    /dev/ftl0
278 -crw-   10,175  /dev/tporta
279 -crw-   10,176  /dev/tportb
280 -crwx   10,100  /dev/softmodem
281 -crwx   10,101  /dev/softmodem_signals
282 -crwx   10,181  /dev/triovoice
283 -crw-   5,67    /dev/cua3
284 -crw-   5,68    /dev/cua4
285 -crw-   5,69    /dev/cua5
286 diff -urN genext2fs-1.3.orig/device_table.txt genext2fs-1.3/device_table.txt
287 --- genext2fs-1.3.orig/device_table.txt 1969-12-31 17:00:00.000000000 -0700
288 +++ genext2fs-1.3/device_table.txt      2003-04-21 01:41:42.000000000 -0600
289 @@ -0,0 +1,129 @@
290 +# When building a target filesystem, it is desirable to not have to
291 +# become root and then run 'mknod' a thousand times.  Using a device 
292 +# table you can create device nodes and directories "on the fly".
293 +#
294 +# This is a sample device table file for use with genext2fs.  You can
295 +# do all sorts of interesting things with a device table file.  For
296 +# example, if you want to adjust the permissions on a particular file
297 +# you can just add an entry like:
298 +#   /sbin/foobar        f       2755    0       0       -       -       -       -       -
299 +# and (assuming the file /sbin/foobar exists) it will be made setuid
300 +# root (regardless of what its permissions are on the host filesystem.
301 +# Furthermore, you can use a single table entry to create a many device
302 +# minors.  For example, if I wanted to create /dev/hda and /dev/hda[0-15]
303 +# I could just use the following two table entries:
304 +#   /dev/hda    b       640     0       0       3       0       0       0       -
305 +#   /dev/hda    b       640     0       0       3       1       1       1       15
306 +# 
307 +# Device table entries take the form of:
308 +# <name>    <type>      <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
309 +# where name is the file name,  type can be one of: 
310 +#       f       A regular file
311 +#       d       Directory
312 +#       c       Character special device file
313 +#       b       Block special device file
314 +#       p       Fifo (named pipe)
315 +# uid is the user id for the target file, gid is the group id for the
316 +# target file.  The rest of the entries (major, minor, etc) apply only 
317 +# to device special files.
318 +
319 +# Have fun
320 +# -Erik Andersen <andersen@codepoet.org>
321 +#
322 +
323 +#<name>                <type>  <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
324 +/dev           d       755     0       0       -       -       -       -       -
325 +/dev/mem       c       640     0       0       1       1       0       0       -
326 +/dev/kmem      c       640     0       0       1       2       0       0       -
327 +/dev/null      c       640     0       0       1       3       0       0       -
328 +/dev/zero      c       640     0       0       1       5       0       0       -
329 +/dev/random    c       640     0       0       1       8       0       0       -
330 +/dev/urandom   c       640     0       0       1       9       0       0       -
331 +/dev/tty       c       666     0       0       5       0       0       0       -
332 +/dev/tty       c       666     0       0       4       0       0       1       6
333 +/dev/console   c       640     0       0       5       1       0       0       -
334 +/dev/ram       b       640     0       0       1       1       0       0       -
335 +/dev/ram       b       640     0       0       1       0       0       1       4
336 +/dev/loop      b       640     0       0       7       0       0       1       2
337 +/dev/ptmx      c       666     0       0       5       2       0       0       -
338 +#/dev/ttyS     c       640     0       0       4       64      0       1       4
339 +#/dev/psaux    c       640     0       0       10      1       0       0       -
340 +#/dev/rtc      c       640     0       0       10      135     0       0       -
341 +
342 +# Adjust permissions on some normal files
343 +#/etc/shadow   f       600     0       0       -       -       -       -       -
344 +#/bin/tinylogin        f       4755    0       0       -       -       -       -       -
345 +
346 +# User-mode Linux stuff
347 +/dev/ubda      b       640     0       0       98      0       0       0       -
348 +/dev/ubda      b       640     0       0       98      1       1       1       15
349 +
350 +# IDE Devices
351 +/dev/hda       b       640     0       0       3       0       0       0       -
352 +/dev/hda       b       640     0       0       3       1       1       1       15
353 +/dev/hdb       b       640     0       0       3       64      0       0       -
354 +/dev/hdb       b       640     0       0       3       65      1       1       15
355 +#/dev/hdc      b       640     0       0       22      0       0       0       -
356 +#/dev/hdc      b       640     0       0       22      1       1       1       15
357 +#/dev/hdd      b       640     0       0       22      64      0       0       -
358 +#/dev/hdd      b       640     0       0       22      65      1       1       15
359 +#/dev/hde      b       640     0       0       33      0       0       0       -
360 +#/dev/hde      b       640     0       0       33      1       1       1       15
361 +#/dev/hdf      b       640     0       0       33      64      0       0       -
362 +#/dev/hdf      b       640     0       0       33      65      1       1       15
363 +#/dev/hdg      b       640     0       0       34      0       0       0       -
364 +#/dev/hdg      b       640     0       0       34      1       1       1       15
365 +#/dev/hdh      b       640     0       0       34      64      0       0       -
366 +#/dev/hdh      b       640     0       0       34      65      1       1       15
367 +
368 +# SCSI Devices
369 +#/dev/sda      b       640     0       0       8       0       0       0       -
370 +#/dev/sda      b       640     0       0       8       1       1       1       15
371 +#/dev/sdb      b       640     0       0       8       16      0       0       -
372 +#/dev/sdb      b       640     0       0       8       17      1       1       15
373 +#/dev/sdc      b       640     0       0       8       32      0       0       -
374 +#/dev/sdc      b       640     0       0       8       33      1       1       15
375 +#/dev/sdd      b       640     0       0       8       48      0       0       -
376 +#/dev/sdd      b       640     0       0       8       49      1       1       15
377 +#/dev/sde      b       640     0       0       8       64      0       0       -
378 +#/dev/sde      b       640     0       0       8       65      1       1       15
379 +#/dev/sdf      b       640     0       0       8       80      0       0       -
380 +#/dev/sdf      b       640     0       0       8       81      1       1       15
381 +#/dev/sdg      b       640     0       0       8       96      0       0       -
382 +#/dev/sdg      b       640     0       0       8       97      1       1       15
383 +#/dev/sdh      b       640     0       0       8       112     0       0       -
384 +#/dev/sdh      b       640     0       0       8       113     1       1       15
385 +#/dev/sg               c       640     0       0       21      0       0       1       15
386 +#/dev/scd      b       640     0       0       11      0       0       1       15
387 +#/dev/st               c       640     0       0       9       0       0       1       8
388 +#/dev/nst      c       640     0       0       9       128     0       1       8
389 +#/dev/st       c       640     0       0       9       32      1       1       4
390 +#/dev/st       c       640     0       0       9       64      1       1       4
391 +#/dev/st       c       640     0       0       9       96      1       1       4
392 +
393 +# Floppy disk devices
394 +#/dev/fd               b       640     0       0       2       0       0       1       2
395 +#/dev/fd0d360  b       640     0       0       2       4       0       0       -
396 +#/dev/fd1d360  b       640     0       0       2       5       0       0       -
397 +#/dev/fd0h1200 b       640     0       0       2       8       0       0       -
398 +#/dev/fd1h1200 b       640     0       0       2       9       0       0       -
399 +#/dev/fd0u1440 b       640     0       0       2       28      0       0       -
400 +#/dev/fd1u1440 b       640     0       0       2       29      0       0       -
401 +#/dev/fd0u2880 b       640     0       0       2       32      0       0       -
402 +#/dev/fd1u2880 b       640     0       0       2       33      0       0       -
403 +
404 +# All the proprietary cdrom devices in the world
405 +#/dev/aztcd    b       640     0       0       29      0       0       0       -
406 +#/dev/bpcd     b       640     0       0       41      0       0       0       -
407 +#/dev/capi20   c       640     0       0       68      0       0       1       2
408 +#/dev/cdu31a   b       640     0       0       15      0       0       0       -
409 +#/dev/cdu535   b       640     0       0       24      0       0       0       -
410 +#/dev/cm206cd  b       640     0       0       32      0       0       0       -
411 +#/dev/sjcd     b       640     0       0       18      0       0       0       -
412 +#/dev/sonycd   b       640     0       0       15      0       0       0       -
413 +#/dev/gscd     b       640     0       0       16      0       0       0       -
414 +#/dev/sbpcd    b       640     0       0       25      0       0       0       -
415 +#/dev/sbpcd    b       640     0       0       25      0       0       1       4
416 +#/dev/mcd      b       640     0       0       23      0       0       0       -
417 +#/dev/optcd    b       640     0       0       17      0       0       0       -
418 +
419 diff -urN genext2fs-1.3.orig/genext2fs.8 genext2fs-1.3/genext2fs.8
420 --- genext2fs-1.3.orig/genext2fs.8      1969-12-31 17:00:00.000000000 -0700
421 +++ genext2fs-1.3/genext2fs.8   2003-04-21 01:41:42.000000000 -0600
422 @@ -0,0 +1,125 @@
423 +.\"                                      Hey, EMACS: -*- nroff -*-
424 +.\" First parameter, NAME, should be all caps
425 +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
426 +.\" other parameters are allowed: see man(7), man(1)
427 +.TH GENEXT2FS 8 "July 14, 2001"
428 +.\" Please adjust this date whenever revising the manpage.
429 +.\"
430 +.\" Some roff macros, for reference:
431 +.\" .nh        disable hyphenation
432 +.\" .hy        enable hyphenation
433 +.\" .ad l      left justify
434 +.\" .ad b      justify to both left and right margins
435 +.\" .nf        disable filling
436 +.\" .fi        enable filling
437 +.\" .br        insert line break
438 +.\" .sp <n>    insert n+1 empty lines
439 +.\" for manpage-specific macros, see man(7)
440 +.SH NAME
441 +genext2fs \- ext2 filesystem generator for embedded systems
442 +.SH SYNOPSIS
443 +.B genext2fs
444 +.RI [ options ]  " image"
445 +.SH DESCRIPTION
446 +\fBgenext2fs\fP generates an ext2 filesystem
447 +as a normal (non-root) user. It doesn't require you to mount
448 +the image file to copy files on it. It doesn't even require
449 +you to be the superuser to make device nodes.
450 +.SH OPTIONS
451 +.TP
452 +.BI -x \ image
453 +Use this image as a starting point
454 +.TP
455 +.BI -d \ directory
456 +Add this directory as source
457 +.TP
458 +.BI -f \ FILE
459 +.TP
460 +.BI -D \ FILE
461 +Uses the named FILE as a device table file, to create device 
462 +nodes and directories "on the fly".
463 +.TP
464 +.BI -b \ blocks
465 +Size in blocks
466 +.TP
467 +.BI -i \ inodes
468 +Number of inodes
469 +.TP
470 +.BI -r \ reserved
471 +Number of reserved blocks
472 +.TP
473 +.BI -g \ path
474 +Generate a block map file for this path
475 +.TP
476 +.BI -e \ value
477 +Fill unallocated blocks with value
478 +.TP
479 +.BI -z
480 +Make files with holes
481 +.TP
482 +.BI -U
483 +Squash owners making all files be owned by root
484 +.TP
485 +.BI -P
486 +Squash permissions on all files
487 +.TP
488 +.BI -q
489 +Squash permissions and owners (same as -P -U)
490 +.TP
491 +.BI -v
492 +Print resulting filesystem structure
493 +.TP
494 +.BI -h
495 +Display help
496 +.TP
497 +.SH EXAMPLES
498 +
499 +.EX
500 +.B
501 + genext2fs -b 1440 -d src /dev/fd0
502 +.EE
503 +
504 +All files in the 
505 +.I src
506 +directory will be written to 
507 +.B /dev/fd0
508 +as a new ext2 filesystem image. You can then mount the floppy as
509 +usual.
510 +
511 +.EX
512 +.B
513 + genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
514 +.EE
515 +
516 +This example builds a filesystem from all the files in 
517 +.I src
518 +, then device nodes are created based on the content the device_table file
519 +.I dev.txt.
520 +An example device file follows:
521 +
522 +.EX
523 + #<name>               <type>  <mode>  <uid>   <gid>   <major> <minor> <start> <inc>   <count>
524 + /dev          d       755     0       0       -       -       -       -       -
525 + /dev/mem      c       640     0       0       1       1       0       0       -
526 + /dev/tty      c       666     0       0       5       0       0       0       -
527 + /dev/tty      c       666     0       0       4       0       0       1       6
528 + /dev/loop     b       640     0       0       7       0       0       1       2
529 + /dev/hda      b       640     0       0       3       0       0       0       -
530 + /dev/hda      b       640     0       0       3       1       1       1       16
531 +.EE
532 +
533 +This device table creates the /dev directory, a character device
534 +node /dev/mem (major 1, minor 1), it also creates /dev/tty, 
535 +/dev/tty[0-5], /dev/loop[0-1], /dev/hda, and /dev/hda0 to /dev/hda15
536 +.SH BUGS
537 +\fBgenext2fs\fP does not support hard links.  Hard links present in the input
538 +tree will be represented as separate files in the ext2 image.
539 +
540 +.SH SEE ALSO
541 +.BR mkfs (8),
542 +.BR genromfs (8),
543 +.BR mkisofs (8).
544 +.br
545 +.SH AUTHOR
546 +This manual page was written by David Kimdon <dwhedon@debian.org>,
547 +for the Debian GNU/Linux system (but may be used by others).
548 diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs-1.3/genext2fs.c
549 --- genext2fs-1.3.orig/genext2fs.c      2001-06-18 02:11:32.000000000 -0600
550 +++ genext2fs-1.3/genext2fs.c   2003-04-21 01:48:35.000000000 -0600
551 @@ -1,3 +1,4 @@
552 +/* vi: set sw=8 ts=8: */
553  // genext2fs.c
554  //
555  // ext2 filesystem generator for embedded systems
556 @@ -26,6 +27,22 @@
557  //                     Bugfix: getcwd values for Solaris       xavier.gueguen@col.bsf.alcatel.fr
558  //                     Bugfix: ANSI scanf for non-GNU C        xavier.gueguen@col.bsf.alcatel.fr
559  //     28 Jun 2001     Bugfix: getcwd differs for Solaris/GNU  mike@sowbug.com
560 +//     23 Mar 2002     Bugfix: test for IFCHR or IFBLK was flawed
561 +//     10 Oct 2002     Added comments,makefile targets,        vsundar@ixiacom.com    
562 +//                     endianess swap assert check.  
563 +//                     Copyright (C) 2002 Ixia communications
564 +//     12 Oct 2002     Added support for triple indirection    vsundar@ixiacom.com
565 +//                     Copyright (C) 2002 Ixia communications
566 +//     14 Oct 2002     Added support for groups                vsundar@ixiacom.com
567 +//                     Copyright (C) 2002 Ixia communications
568 +//     5 Jan 2003      Bugfixes: reserved inodes should be set vsundar@usc.edu
569 +//                     only in the first group; directory names
570 +//                     need to be null padded at the end; and 
571 +//                     number of blocks per group should be a 
572 +//                     multiple of 8. Updated md5 values. 
573 +//     6 Jan 2003      Erik Andersen <andersee@debian.org> added
574 +//                         mkfs.jffs2 compatible device table support,
575 +//                         along with -q, -P, -U
576  
577  
578  // `genext2fs' is a mean to generate an ext2 filesystem
579 @@ -33,10 +50,6 @@
580  // the image file to copy files on it. It doesn't even require
581  // you to be the superuser to make device nodes.
582  //
583 -// Warning ! `genext2fs' has been designed for embedded
584 -// systems. As such, it will generate a filesystem for single-user
585 -// usage: all files/directories/etc... will belong to UID/GID 0
586 -//
587  // Example usage:
588  //
589  // # genext2fs -b 1440 -d srcdir /dev/fd0
590 @@ -45,21 +58,15 @@
591  // a new ext2 filesystem image. You can then mount the floppy as
592  // usual.
593  //
594 -// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img
595 +// # genext2fs -b 1024 -d builddir -D device_table.txt flashdisk.img
596  //
597  // This one would build a filesystem from all the files in builddir,
598 -// then would read a devices list and make apropriate nodes. The
599 -// format for the device list is:
600 -//
601 -// drwx            /dev
602 -// crw-    10,190  /dev/lcd
603 -// brw-    1,0     /dev/ram0
604 -// 
605 -// This device list builds the /dev directory, a character device
606 -// node /dev/lcd (major 10, minor 190) and a block device node
607 -// /dev/ram0 (major 1, minor 0)
608 +// then would read the device_table.txt file and make apropriate nodes.
609 +// The format for the device table file is covered in detail in the sample
610 +// device_table.txt file provided with the genext2fs source.
611  
612  
613 +#define _GNU_SOURCE
614  #include <stdio.h>
615  #include <stdlib.h>
616  #include <string.h>
617 @@ -67,6 +74,11 @@
618  #include <stdarg.h>
619  #include <unistd.h>
620  #include <sys/stat.h>
621 +#include <assert.h>
622 +#include <time.h>
623 +#include <ctype.h>
624 +#include <errno.h>
625 +#include <fcntl.h>
626  
627  
628  
629 @@ -76,10 +88,14 @@
630  #define BLOCKSIZE         1024
631  #define BLOCKS_PER_GROUP  8192
632  #define BYTES_PER_INODE   (8*BLOCKSIZE)
633 +/* Percentage of blocks that are reserved.*/
634  #define RESERVED_INODES   5/100
635  
636  
637  // inode block size (why is it != BLOCKSIZE ?!?)
638 +/* The field i_blocks in the ext2 inode stores the number of data blocks
639 +   but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
640 +   INOBLK is the number of such blocks in an actual disk block            */
641  
642  #define INODE_BLOCKSIZE   512
643  #define INOBLK            (BLOCKSIZE / INODE_BLOCKSIZE)
644 @@ -147,6 +163,39 @@
645  
646  #define OP_HOLES     0x01       // make files with holes
647  
648 +/* Defines for accessing group details */
649 +
650 +// Number of groups in the filesystem
651 +#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group )
652 +
653 +// Get group block bitmap (bbm) given the group number
654 +#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
655 +
656 +// Get group inode bitmap (ibm) given the group number
657 +#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
658 +               
659 +// Given an inode number find the group it belongs to
660 +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
661 +
662 +//Given an inode number get the inode bitmap that covers it
663 +#define GRP_GET_INODE_BITMAP(fs,nod) \
664 +       ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
665 +
666 +//Given an inode number find its offset within the inode bitmap that covers it
667 +#define GRP_IBM_OFFSET(fs,nod) \
668 +       ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
669 +
670 +// Given a block number find the group it belongs to
671 +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
672 +       
673 +//Given a block number get the block bitmap that covers it
674 +#define GRP_GET_BLOCK_BITMAP(fs,blk) \
675 +       ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
676 +
677 +//Given a block number find its offset within the block bitmap that covers it
678 +#define GRP_BBM_OFFSET(fs,blk) \
679 +       ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
680 +
681  
682  // used types
683  
684 @@ -287,7 +336,6 @@
685  {
686         groupdescriptor_decl
687         uint32 bg_reserved[3];
688 -       uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];
689  } groupdescriptor;
690  
691  typedef struct
692 @@ -304,6 +352,32 @@
693  
694  typedef uint8 block[BLOCKSIZE];
695  
696 +/* blockwalker fields:
697 +   The blockwalker is used to access all the blocks of a file (including
698 +   the indirection blocks) through repeated calls to walk_bw.  
699 +   
700 +   bpdir -> index into the inode->i_block[]. Indicates level of indirection.
701 +   bnum -> total number of blocks so far accessed. including indirection
702 +           blocks.
703 +   bpind,bpdind,bptind -> index into indirection blocks.
704 +   
705 +   bpind, bpdind, bptind do *NOT* index into single, double and triple
706 +   indirect blocks resp. as you might expect from their names. Instead 
707 +   they are in order the 1st, 2nd & 3rd index to be used
708 +   
709 +   As an example..
710 +   To access data block number 70000:
711 +        bpdir: 15 (we are doing triple indirection)
712 +        bpind: 0 ( index into the triple indirection block)
713 +        bpdind: 16 ( index into the double indirection block)
714 +        bptind: 99 ( index into the single indirection block)
715 +       70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
716 +
717 +   So,for double indirection bpind will index into the double indirection 
718 +   block and bpdind into the single indirection block. For single indirection
719 +   only bpind will be used.
720 +*/
721 +   
722  typedef struct
723  {
724         uint32 bnum;
725 @@ -313,15 +387,14 @@
726         uint32 bptind;
727  } blockwalker;
728  
729 +
730 +/* Filesystem structure that support groups */
731  #if BLOCKSIZE == 1024
732  typedef struct
733  {
734         block zero;          // The famous block 0
735         superblock sb;       // The superblock
736 -       groupdescriptor gd;  // The group desciptor
737 -       block bbm;           // The block bitmap
738 -       block ibm;           // The inode bitmap
739 -       inode itab[0];       // The inode table
740 +       groupdescriptor gd[0]; // The group descriptors
741  } filesystem;
742  #else
743  #error UNHANDLED BLOCKSIZE
744 @@ -389,25 +462,113 @@
745  #undef udecl32
746  #undef utdecl32
747  
748 -char * argv0;
749 +static char * app_name;
750 +static int squash_uids = 0;
751 +static int squash_perms = 0;
752 +static const char *const memory_exhausted = "memory exhausted";
753  
754  // error (un)handling
755 -inline void errexit(const char *fmt, ...)
756 +static void verror_msg(const char *s, va_list p)
757  {
758 -       va_list ap;
759 -       fprintf(stderr, "%s: ", argv0);
760 -       va_start(ap, fmt);
761 -       vfprintf(stderr, fmt, ap);
762 -       va_end(ap);
763 -       fprintf(stderr, "\n");
764 -       exit(1);
765 +       fflush(stdout);
766 +       fprintf(stderr, "%s: ", app_name);
767 +       vfprintf(stderr, s, p);
768 +}
769 +static void error_msg(const char *s, ...)
770 +{
771 +       va_list p;
772 +       va_start(p, s);
773 +       verror_msg(s, p);
774 +       va_end(p);
775 +       putc('\n', stderr);
776 +}
777 +
778 +static void error_msg_and_die(const char *s, ...)
779 +{
780 +       va_list p;
781 +       va_start(p, s);
782 +       verror_msg(s, p);
783 +       va_end(p);
784 +       putc('\n', stderr);
785 +       exit(EXIT_FAILURE);
786 +}
787 +
788 +static void vperror_msg(const char *s, va_list p)
789 +{
790 +       int err = errno;
791 +       if (s == 0)
792 +               s = "";
793 +       verror_msg(s, p);
794 +       if (*s)
795 +               s = ": ";
796 +       fprintf(stderr, "%s%s\n", s, strerror(err));
797 +}
798 +
799 +#if 0
800 +static void perror_msg(const char *s, ...)
801 +{
802 +       va_list p;
803 +       va_start(p, s);
804 +       vperror_msg(s, p);
805 +       va_end(p);
806 +}
807 +#endif
808 +static void perror_msg_and_die(const char *s, ...)
809 +{
810 +       va_list p;
811 +       va_start(p, s);
812 +       vperror_msg(s, p);
813 +       va_end(p);
814 +       exit(EXIT_FAILURE);
815  }
816  
817 -inline void pexit(const char * fname)
818 +static FILE *xfopen(const char *path, const char *mode)
819  {
820 -       fprintf(stderr, "%s: ", argv0);
821 -       perror(fname);
822 -       exit(1);
823 +       FILE *fp;
824 +       if ((fp = fopen(path, mode)) == NULL)
825 +               perror_msg_and_die("%s", path);
826 +       return fp;
827 +}
828 +
829 +static char *xstrdup(const char *s)
830 +{
831 +       char *t;
832 +
833 +       if (s == NULL)
834 +               return NULL;
835 +       t = strdup(s);
836 +       if (t == NULL)
837 +               error_msg_and_die(memory_exhausted);
838 +       return t;
839 +}
840 +
841 +extern void *xrealloc(void *ptr, size_t size)
842 +{
843 +       ptr = realloc(ptr, size);
844 +       if (ptr == NULL && size != 0)
845 +               error_msg_and_die(memory_exhausted);
846 +       return ptr;
847 +}
848 +
849 +static char *xreadlink(const char *path)
850 +{
851 +       static const int GROWBY = 80; /* how large we will grow strings by */
852 +
853 +       char *buf = NULL;
854 +       int bufsize = 0, readsize = 0;
855 +
856 +       do {
857 +               buf = xrealloc(buf, bufsize += GROWBY);
858 +               readsize = readlink(path, buf, bufsize); /* 1st try */
859 +               if (readsize == -1) {
860 +                       perror_msg_and_die("%s:%s", app_name, path);
861 +               }
862 +       }
863 +       while (bufsize < readsize + 1);
864 +
865 +       buf[readsize] = '\0';
866 +
867 +       return buf;
868  }
869  
870  // printf helper macro
871 @@ -423,7 +584,7 @@
872  {
873  }
874  
875 -// rounds a quantity up to a blocksize
876 +/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
877  uint32 rndup(uint32 qty, uint32 siz)
878  {
879         return (qty + (siz - 1)) & ~(siz - 1);
880 @@ -444,7 +605,13 @@
881  // return a given inode from a filesystem
882  inline inode * get_nod(filesystem *fs, uint32 nod)
883  {
884 -       return &fs->itab[nod-1];
885 +       int grp,offset;
886 +       inode *itab;
887 +
888 +       offset = GRP_IBM_OFFSET(fs,nod);
889 +       grp = GRP_GROUP_OF_INODE(fs,nod);
890 +       itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
891 +       return itab+offset-1;
892  }
893  
894  // allocate a given block/inode in the bitmap
895 @@ -479,29 +646,57 @@
896  }
897  
898  // allocate a block
899 -uint32 alloc_blk(filesystem *fs)
900 +uint32 alloc_blk(filesystem *fs, uint32  nod)
901  {
902 -       uint32 bk;
903 -       if(!(bk = allocate(fs->bbm, 0)))
904 -               errexit("couldn't allocate a block (no free space)");
905 -       if(!(fs->gd.bg_free_blocks_count--))
906 -               errexit("group descr. free blocks count == 0 (corrupted fs?)");
907 +       uint32 bk=0;
908 +       uint32 grp,nbgroups;
909 +
910 +       grp = nod/fs->sb.s_inodes_per_group;
911 +       nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / 
912 +                                       fs->sb.s_blocks_per_group;
913 +       if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
914 +               for(grp=0;grp<nbgroups && !bk;grp++)
915 +                       bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
916 +               grp--;
917 +       }
918 +       if (!bk)
919 +               error_msg_and_die("couldn't allocate a block (no free space)");
920 +       if(!(fs->gd[grp].bg_free_blocks_count--))
921 +               error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
922         if(!(fs->sb.s_free_blocks_count--))
923 -               errexit("superblock free blocks count == 0 (corrupted fs?)");
924 -       return bk;
925 +               error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
926 +       return fs->sb.s_blocks_per_group*grp + bk;
927  }
928  
929  // allocate an inode
930  uint32 alloc_nod(filesystem *fs)
931  {
932 -       uint32 nod;
933 -       if(!(nod = allocate(fs->ibm, 0)))
934 -               errexit("couldn't allocate an inode (no free inode)");
935 -       if(!(fs->gd.bg_free_inodes_count--))
936 -               errexit("group descr. free blocks count == 0 (corrupted fs?)");
937 +       uint32 nod=0,best_group=0;
938 +       uint32 grp,nbgroups,avefreei;
939 +
940 +       nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) / 
941 +                                       fs->sb.s_blocks_per_group;
942 +
943 +       /* Distribute inodes amongst all the blocks                           */
944 +       /* For every block group with more than average number of free inodes */
945 +       /* find the one with the most free blocks and allocate node there     */
946 +       /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel      */
947 +       /* We do it for all inodes.                                           */
948 +       avefreei  =  fs->sb.s_free_inodes_count / nbgroups;
949 +       for(grp=0;grp<nbgroups && !nod;grp++) {
950 +               if (fs->gd[grp].bg_free_inodes_count < avefreei)
951 +                       continue;
952 +               if (!best_group || 
953 +                       fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
954 +                       best_group = grp;
955 +       }
956 +       if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
957 +               error_msg_and_die("couldn't allocate an inode (no free inode)");
958 +       if(!(fs->gd[best_group].bg_free_inodes_count--))
959 +               error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
960         if(!(fs->sb.s_free_inodes_count--))
961 -               errexit("superblock free blocks count == 0 (corrupted fs?)");
962 -       return nod;
963 +               error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
964 +       return fs->sb.s_inodes_per_group*best_group+nod;
965  }
966  
967  // print a bitmap allocation
968 @@ -546,14 +741,14 @@
969         {
970                 bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
971                 if(extend) // allocate first block
972 -                       *bkref = hole ? 0 : alloc_blk(fs);
973 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
974         }
975         // direct block
976         else if(bw->bpdir < EXT2_NDIR_BLOCKS)
977         {
978                 bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
979                 if(extend) // allocate block
980 -                       *bkref = hole ? 0 : alloc_blk(fs);
981 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
982         }
983         // first block in indirect block
984         else if(bw->bpdir == EXT2_NDIR_BLOCKS)
985 @@ -562,11 +757,11 @@
986                 bw->bpdir = EXT2_IND_BLOCK;
987                 bw->bpind = 0;
988                 if(extend) // allocate indirect block
989 -                       get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
990 +                       get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
991                 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
992                 bkref = &b[bw->bpind];
993                 if(extend) // allocate first block
994 -                       *bkref = hole ? 0 : alloc_blk(fs);
995 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
996         }
997         // block in indirect block
998         else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
999 @@ -575,7 +770,7 @@
1000                 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1001                 bkref = &b[bw->bpind];
1002                 if(extend) // allocate block
1003 -                       *bkref = hole ? 0 : alloc_blk(fs);
1004 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1005         }
1006         // first block in first indirect block in first double indirect block
1007         else if(bw->bpdir == EXT2_IND_BLOCK)
1008 @@ -585,14 +780,14 @@
1009                 bw->bpind = 0;
1010                 bw->bpdind = 0;
1011                 if(extend) // allocate double indirect block
1012 -                       get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
1013 +                       get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1014                 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1015                 if(extend) // allocate first indirect block
1016 -                       b[bw->bpind] = alloc_blk(fs);
1017 +                       b[bw->bpind] = alloc_blk(fs,nod);
1018                 b = (uint32*)get_blk(fs, b[bw->bpind]);
1019                 bkref = &b[bw->bpdind];
1020                 if(extend) // allocate first block
1021 -                       *bkref = hole ? 0 : alloc_blk(fs);
1022 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1023         }
1024         // block in indirect block in double indirect block
1025         else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
1026 @@ -602,7 +797,7 @@
1027                 b = (uint32*)get_blk(fs, b[bw->bpind]);
1028                 bkref = &b[bw->bpdind];
1029                 if(extend) // allocate block
1030 -                       *bkref = hole ? 0 : alloc_blk(fs);
1031 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1032         }
1033         // first block in indirect block in double indirect block
1034         else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
1035 @@ -612,20 +807,100 @@
1036                 bw->bpind++;
1037                 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1038                 if(extend) // allocate indirect block
1039 -                       b[bw->bpind] = alloc_blk(fs);
1040 +                       b[bw->bpind] = alloc_blk(fs,nod);
1041                 b = (uint32*)get_blk(fs, b[bw->bpind]);
1042                 bkref = &b[bw->bpdind];
1043                 if(extend) // allocate first block
1044 -                       *bkref = hole ? 0 : alloc_blk(fs);
1045 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1046 +       }
1047 +
1048 +       /* Adding support for triple indirection */
1049 +       /* Just starting triple indirection. Allocate the indirection
1050 +          blocks and the first data block
1051 +        */
1052 +       else if (bw->bpdir == EXT2_DIND_BLOCK) 
1053 +       {
1054 +               bw->bnum += 3;
1055 +               bw->bpdir = EXT2_TIND_BLOCK;
1056 +               bw->bpind = 0;
1057 +               bw->bpdind = 0;
1058 +               bw->bptind = 0;
1059 +               if(extend) // allocate triple indirect block
1060 +                       get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1061 +               b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1062 +               if(extend) // allocate first double indirect block
1063 +                       b[bw->bpind] = alloc_blk(fs,nod);
1064 +               b = (uint32*)get_blk(fs, b[bw->bpind]);
1065 +               if(extend) // allocate first indirect block
1066 +                       b[bw->bpdind] = alloc_blk(fs,nod);
1067 +               b = (uint32*)get_blk(fs, b[bw->bpdind]);
1068 +               bkref = &b[bw->bptind];
1069 +               if(extend) // allocate first data block
1070 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1071 +       }
1072 +       /* Still processing a single indirect block down the indirection
1073 +          chain.Allocate a data block for it
1074 +        */
1075 +       else if ( (bw->bpdir == EXT2_TIND_BLOCK) && 
1076 +                 (bw->bptind < BLOCKSIZE/4 -1) )
1077 +       {
1078 +               bw->bptind++;
1079 +               b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1080 +               b = (uint32*)get_blk(fs, b[bw->bpind]);
1081 +               b = (uint32*)get_blk(fs, b[bw->bpdind]);
1082 +               bkref = &b[bw->bptind];
1083 +               if(extend) // allocate data block
1084 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1085 +       }
1086 +       /* Finished processing a single indirect block. But still in the 
1087 +          same double indirect block. Allocate new single indirect block
1088 +          for it and a data block
1089 +        */
1090 +       else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
1091 +                 (bw->bpdind < BLOCKSIZE/4 -1) )
1092 +       {
1093 +               bw->bnum++;
1094 +               bw->bptind = 0;
1095 +               bw->bpdind++;
1096 +               b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1097 +               b = (uint32*)get_blk(fs, b[bw->bpind]);
1098 +               if (extend) // allocate single indirect block
1099 +                       b[bw->bpdind] = alloc_blk(fs,nod);
1100 +               b = (uint32*)get_blk(fs, b[bw->bpdind]);
1101 +               bkref = &b[bw->bptind];
1102 +               if(extend) // allocate first data block
1103 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1104 +       }
1105 +       /* Finished processing a double indirect block. Allocate the next
1106 +          double indirect block and the single,data blocks for it
1107 +        */
1108 +       else if ( (bw->bpdir == EXT2_TIND_BLOCK) && 
1109 +                 (bw->bpind < BLOCKSIZE/4 - 1) )
1110 +       {
1111 +               bw->bnum += 2;
1112 +               bw->bpdind = 0;
1113 +               bw->bptind = 0;
1114 +               bw->bpind++;
1115 +               b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1116 +               if(extend) // allocate double indirect block
1117 +                       b[bw->bpind] = alloc_blk(fs,nod);
1118 +               b = (uint32*)get_blk(fs, b[bw->bpind]);
1119 +               if(extend) // allocate single indirect block
1120 +                       b[bw->bpdind] = alloc_blk(fs,nod);
1121 +               b = (uint32*)get_blk(fs, b[bw->bpdind]);
1122 +               bkref = &b[bw->bptind];
1123 +               if(extend) // allocate first block
1124 +                       *bkref = hole ? 0 : alloc_blk(fs,nod);
1125         }
1126 -       // I don't do triple indirect - it's such a small filesystem ...
1127         else
1128 -               errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod);
1129 +               error_msg_and_die("file too big !"); 
1130 +       /* End change for walking triple indirection */
1131 +
1132         if(*bkref)
1133         {
1134                 bw->bnum++;
1135 -               if(!allocated(fs->bbm, *bkref))
1136 -                       errexit("[block %d of inode %d is unallocated !]", *bkref, nod);
1137 +               if(!allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
1138 +                       error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
1139         }
1140         if(extend)
1141                 get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
1142 @@ -663,23 +938,40 @@
1143  }
1144  
1145  // link an entry (inode #) to a directory
1146 -void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
1147 +void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name, uint32 mode, uid_t uid, gid_t gid, time_t ctime)
1148  {
1149         blockwalker bw;
1150         uint32 bk;
1151         uint8 *b;
1152         directory *d;
1153         int reclen, nlen;
1154 -       if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR)
1155 -               errexit("can't add '%s' to a non-directory", name);
1156 +       inode *node;
1157 +       inode *pnode;
1158 +       
1159 +       /* Squash all permissions so files are owned by root 
1160 +        * and file permissions have group/other perms removed */
1161 +       if (squash_uids) {
1162 +               uid = gid = 0;
1163 +       }
1164 +       if (squash_perms) {
1165 +               if (!S_ISLNK(mode)) {
1166 +                       mode &= ~(S_IWGRP | S_IWOTH);
1167 +                       mode &= ~(S_ISUID | S_ISGID);
1168 +               }
1169 +       }
1170 +
1171 +       pnode = get_nod(fs, dnod);
1172 +
1173 +       if(!S_ISDIR(pnode->i_mode))
1174 +               error_msg_and_die("can't add '%s' to a non-directory", name);
1175         if(!*name)
1176 -               errexit("bad name '%s' (not meaningful)", name);
1177 +               error_msg_and_die("bad name '%s' (not meaningful)", name);
1178         if(strchr(name, '/'))
1179 -               errexit("bad name '%s' (contains a slash)", name);
1180 +               error_msg_and_die("bad name '%s' (contains a slash)", name);
1181         nlen = strlen(name);
1182         reclen = sizeof(directory) + rndup(nlen, 4);
1183         if(reclen > BLOCKSIZE)
1184 -               errexit("bad name '%s' (too long)", name);
1185 +               error_msg_and_die("bad name '%s' (too long)", name);
1186         init_bw(fs, dnod, &bw);
1187         while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
1188         {
1189 @@ -691,9 +983,16 @@
1190                         if((!d->d_inode) && (d->d_rec_len >= reclen))
1191                         {
1192                                 d->d_inode = nod;
1193 -                               get_nod(fs, nod)->i_links_count++;
1194 +                               node = get_nod(fs, nod);
1195 +                               node->i_links_count++;
1196                                 d->d_name_len = nlen;
1197 -                               strncpy(d->d_name, name, nlen);
1198 +                               strncpy(d->d_name, name, rndup(nlen,4));
1199 +                               node->i_mode = mode;
1200 +                               node->i_uid = uid;
1201 +                               node->i_gid = gid;
1202 +                               node->i_atime = ctime;
1203 +                               node->i_ctime = ctime;
1204 +                               node->i_mtime = ctime;
1205                                 return;
1206                         }
1207                         // if entry with enough room (last one?), shrink it & use it
1208 @@ -705,9 +1004,16 @@
1209                                 d = (directory*) (((int8*)d) + d->d_rec_len);
1210                                 d->d_rec_len = reclen;
1211                                 d->d_inode = nod;
1212 -                               get_nod(fs, nod)->i_links_count++;
1213 +                               node = get_nod(fs, nod);
1214 +                               node->i_links_count++;
1215                                 d->d_name_len = nlen;
1216 -                               strncpy(d->d_name, name, nlen);
1217 +                               strncpy(d->d_name, name, rndup(nlen,4));
1218 +                               node->i_mode = mode;
1219 +                               node->i_uid = uid;
1220 +                               node->i_gid = gid;
1221 +                               node->i_atime = ctime;
1222 +                               node->i_ctime = ctime;
1223 +                               node->i_mtime = ctime;
1224                                 return;
1225                         }
1226                 }
1227 @@ -716,10 +1022,17 @@
1228         b = get_workblk();
1229         d = (directory*)b;
1230         d->d_inode = nod;
1231 -       get_nod(fs, nod)->i_links_count++;
1232 +       node = get_nod(fs, nod);
1233 +       node->i_links_count++;
1234         d->d_rec_len = BLOCKSIZE;
1235         d->d_name_len = nlen;
1236 -       strncpy(d->d_name, name, nlen);
1237 +       strncpy(d->d_name, name, rndup(nlen,4));
1238 +       node->i_mode = mode;
1239 +       node->i_uid = uid;
1240 +       node->i_gid = gid;
1241 +       node->i_atime = ctime;
1242 +       node->i_ctime = ctime;
1243 +       node->i_mtime = ctime;
1244         extend_blk(fs, dnod, b, 1);
1245         get_nod(fs, dnod)->i_size += BLOCKSIZE;
1246         free_workblk(b);
1247 @@ -747,7 +1060,7 @@
1248  // find the inode of a full path
1249  uint32 find_path(filesystem *fs, uint32 nod, const char * name)
1250  {
1251 -       char *p, *n, *n2 = strdup(name);
1252 +       char *p, *n, *n2 = xstrdup(name);
1253         n = n2;
1254         while(*n == '/')
1255         {
1256 @@ -770,27 +1083,32 @@
1257  }
1258  
1259  // make a full-fledged directory (i.e. with "." & "..")
1260 -uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode)
1261 +uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
1262 +       uid_t uid, gid_t gid, time_t ctime)
1263  {
1264         uint32 nod;
1265         if((nod = find_dir(fs, parent_nod, name)))
1266                 return nod;
1267                 nod = alloc_nod(fs);
1268 -       get_nod(fs, nod)->i_mode = FM_IFDIR | mode;
1269 -       add2dir(fs, parent_nod, nod, name);
1270 -       add2dir(fs, nod, nod, ".");
1271 -       add2dir(fs, nod, parent_nod, "..");
1272 -       fs->gd.bg_used_dirs_count++;
1273 +       if (!(mode & FM_IFDIR))
1274 +           mode |= FM_IFDIR;
1275 +       add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1276 +       add2dir(fs, nod, nod, ".", mode, uid, gid, ctime);
1277 +       add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime);
1278 +       fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
1279         return nod;
1280  }
1281  
1282  // make a symlink
1283 -uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b)
1284 +uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size,
1285 +       uint8 * b, uid_t uid, gid_t gid, time_t ctime)
1286  {
1287 +       uint32 mode;
1288         uint32 nod = alloc_nod(fs);
1289 +       mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO; 
1290         get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1291         get_nod(fs, nod)->i_size = size;
1292 -       add2dir(fs, parent_nod, nod, name);
1293 +       add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1294         if(size <= 4 * (EXT2_TIND_BLOCK+1))
1295         {
1296                 strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
1297 @@ -801,15 +1119,15 @@
1298  }
1299  
1300  // make a file from a FILE*
1301 -uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f)
1302 +uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, time_t ctime)
1303  {
1304         uint8 * b;
1305         uint32 nod = alloc_nod(fs);
1306 -       get_nod(fs, nod)->i_mode = FM_IFREG | mode;
1307 +       mode |= FM_IFREG;
1308         get_nod(fs, nod)->i_size = size;
1309 -       add2dir(fs, parent_nod, nod, name);
1310 +       add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1311         if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE))))
1312 -               errexit("not enough mem to read file '%s'", name);
1313 +               error_msg_and_die("not enough mem to read file '%s'", name);
1314         memset(b, 0,rndup(size, BLOCKSIZE));
1315         if(f)
1316                 fread(b, size, 1, f);
1317 @@ -824,6 +1142,15 @@
1318  uint32 get_mode(struct stat *st)
1319  {
1320         uint32 mode = 0;
1321 +
1322 +       /* Squash file permissions as needed */
1323 +       if (squash_perms) {
1324 +               if (!S_ISLNK(mode)) {
1325 +                       st->st_mode &= ~(S_IWGRP | S_IWOTH);
1326 +                       st->st_mode &= ~(S_ISUID | S_ISGID);
1327 +               }
1328 +       }
1329 +
1330         if(st->st_mode & S_IRUSR)
1331                 mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
1332         if(st->st_mode & S_IWUSR)
1333 @@ -833,30 +1160,17 @@
1334         return mode;
1335  }
1336  
1337 -// retrieves a mode info from a string
1338 -uint32 get_modestr(const char *p)
1339 -{
1340 -       uint32 mode = 0;
1341 -       if(p[0] == 'r')
1342 -               mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
1343 -       if(p[1] == 'w')
1344 -               mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH;
1345 -       if(p[2] == 'x' || p[2] == 's')
1346 -               mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
1347 -       return mode;
1348 -}
1349 -
1350  // basename of a path - free me
1351  char * basename(const char * fullpath)
1352  {
1353         char * p = strrchr(fullpath, '/');
1354 -       return strdup(p ? p + 1 : fullpath);
1355 +       return xstrdup(p ? p + 1 : fullpath);
1356  }
1357  
1358  // dirname of a path - free me
1359  char * dirname(const char * fullpath)
1360  {
1361 -       char * p, * n = strdup(fullpath);
1362 +       char * p, * n = xstrdup(fullpath);
1363         if((p = strrchr(n, '/')))
1364                 *(p+1) = 0;
1365         else
1366 @@ -864,66 +1178,6 @@
1367         return n;
1368  }
1369  
1370 -// adds entries to the filesystem from a text file
1371 -void add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh)
1372 -{
1373 -       uint32 mode;
1374 -       uint32 nod, nod2;
1375 -       char cmod[11], *path, *name, *dir;
1376 -       int major, minor;
1377 -       while(fscanf(fh, "%10s", cmod))
1378 -       {
1379 -               if(feof(fh))
1380 -                       break;
1381 -               mode = get_modestr(cmod + 1);
1382 -               switch(*cmod)
1383 -               {
1384 -                       case 'd':
1385 -                               fscanf(fh, "%" SCANF_PREFIX "s\n", SCANF_STRING(path));
1386 -                               break;
1387 -                       case 'c':
1388 -                               mode |= FM_IFCHR;
1389 -                               fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
1390 -                               break;
1391 -                       case 'b':
1392 -                               mode |= FM_IFBLK;
1393 -                               fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
1394 -                               break;
1395 -                       case '#':
1396 -                               while(fgetc(fh) != '\n');
1397 -                               continue;
1398 -                       default:
1399 -                               errexit("malformed text input file");
1400 -               }
1401 -               name = basename(path);
1402 -               dir = dirname(path);
1403 -               free(path);
1404 -               if(!(nod = find_path(fs, this_nod, dir)))
1405 -                       errexit("can't find directory '%s' to create '%s''", dir, name);
1406 -               free(dir);
1407 -               if((!strcmp(name, ".")) || (!strcmp(name, "..")))
1408 -               {
1409 -                       free(name);
1410 -                       continue;
1411 -               }
1412 -               switch(*cmod)
1413 -               {
1414 -                       case 'd':
1415 -                               mkdir_fs(fs, nod, name, mode);
1416 -                               break;
1417 -                       case 'c':
1418 -                       case 'b':
1419 -                               nod2 = alloc_nod(fs);
1420 -                               get_nod(fs, nod2)->i_mode = mode;
1421 -                               ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor;
1422 -                               ((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
1423 -                               add2dir(fs, nod, nod2, name);
1424 -                               break;
1425 -               }
1426 -               free(name);
1427 -       }
1428 -}
1429 -
1430  // adds a tree of entries to the filesystem from current dir
1431  void add2fs_from_dir(filesystem *fs, uint32 this_nod)
1432  {
1433 @@ -934,7 +1188,7 @@
1434         struct stat st;
1435         uint8 *b;
1436         if(!(dh = opendir(".")))
1437 -               pexit(".");
1438 +               perror_msg_and_die(".");
1439         while((dent = readdir(dh)))
1440         {
1441                 if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
1442 @@ -948,31 +1202,27 @@
1443                                 get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st);
1444                                 ((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff);
1445                                 ((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8);
1446 -                               add2dir(fs, this_nod, nod, dent->d_name);
1447 +                               add2dir(fs, this_nod, nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
1448                                 break;
1449                         case S_IFLNK:
1450 -                               if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE))))
1451 -                                       errexit("out of memory");
1452 -                               if(readlink(dent->d_name, (char*)b, st.st_size) < 0)
1453 -                                       pexit(dent->d_name);
1454 -                               mklink_fs(fs, this_nod, dent->d_name, st.st_size, b);
1455 +                               b = xreadlink(dent->d_name);
1456 +                               mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime);
1457                                 free(b);
1458                                 break;
1459                         case S_IFREG:
1460 -                               if(!(fh = fopen(dent->d_name, "r")))
1461 -                                       pexit(dent->d_name);
1462 -                               mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh);
1463 +                               fh = xfopen(dent->d_name, "r");
1464 +                               mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime);
1465                                 fclose(fh);
1466                                 break;
1467                         case S_IFDIR:
1468 -                               nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st));
1469 +                               nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
1470                                 if(chdir(dent->d_name) < 0)
1471 -                                       pexit(dent->d_name);
1472 +                                       perror_msg_and_die(dent->d_name);
1473                                 add2fs_from_dir(fs, nod);
1474                                 chdir("..");
1475                                 break;
1476                         default:
1477 -                               fprintf(stderr, "ignoring entry %s", dent->d_name);
1478 +                               error_msg("ignoring entry %s", dent->d_name);
1479                 }
1480         }
1481         closedir(dh);
1482 @@ -981,9 +1231,11 @@
1483  // endianness swap of x-indirect blocks
1484  void swap_goodblocks(filesystem *fs, inode *nod)
1485  {
1486 -       int i;
1487 +       int i,j,done=0;
1488 +       uint32 *b,*b2;
1489 +
1490         int nblk = nod->i_blocks / INOBLK;
1491 -       if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
1492 +       if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1493                 for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1494                         nod->i_block[i] = swab32(nod->i_block[i]);
1495         if(nblk <= EXT2_IND_BLOCK)
1496 @@ -991,20 +1243,55 @@
1497         swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1498         if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
1499                 return;
1500 +       /* Currently this will fail b'cos the number of blocks as stored
1501 +          in i_blocks also includes the indirection blocks (see
1502 +          walk_bw). But this function assumes that i_blocks only
1503 +          stores the count of data blocks ( Actually according to
1504 +          "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
1505 +          i_blocks IS supposed to store the count of data blocks). so
1506 +          with a file of size 268K nblk would be 269.The above check
1507 +          will be false even though double indirection hasn't been
1508 +          started.This is benign as 0 means block 0 which has been
1509 +          zeroed out and therefore points back to itself from any offset
1510 +        */
1511 +       assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1512         for(i = 0; i < BLOCKSIZE/4; i++)
1513 +               /* Should this be...
1514 +               if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
1515 +               */
1516                 if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
1517                         swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1518         swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1519         if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1520                 return;
1521 -       errexit("too big file on the filesystem");
1522 +       /* Adding support for triple indirection */
1523 +       b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1524 +       for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1525 +               b2 = (uint32*)get_blk(fs,b[i]); 
1526 +               for(j=0; j<BLOCKSIZE/4;j++) {
1527 +                       if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 + 
1528 +                                    (BLOCKSIZE/4)*(BLOCKSIZE/4) + 
1529 +                                    i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + 
1530 +                                    j*(BLOCKSIZE/4)) ) 
1531 +                         swap_block(get_blk(fs,b2[j]));
1532 +                       else {
1533 +                         done = 1;
1534 +                         break;
1535 +                       }
1536 +               }
1537 +               swap_block((uint8 *)b2);
1538 +       }
1539 +       swap_block((uint8 *)b);
1540 +       return;
1541  }
1542  
1543  void swap_badblocks(filesystem *fs, inode *nod)
1544  {
1545 -       int i;
1546 +       int i,j,done=0;
1547 +       uint32 *b,*b2;
1548 +
1549         int nblk = nod->i_blocks / INOBLK;
1550 -       if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
1551 +       if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1552                 for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1553                         nod->i_block[i] = swab32(nod->i_block[i]);
1554         if(nblk <= EXT2_IND_BLOCK)
1555 @@ -1012,13 +1299,34 @@
1556         swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1557         if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
1558                 return;
1559 +       /* See comment in swap_goodblocks */
1560 +       assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1561         swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1562         for(i = 0; i < BLOCKSIZE/4; i++)
1563 +               /* See comment in swap_goodblocks */
1564                 if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
1565                         swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1566         if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1567                 return;
1568 -       errexit("too big file on the filesystem");
1569 +       /* Adding support for triple indirection */
1570 +       b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1571 +       swap_block((uint8 *)b);
1572 +       for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1573 +               b2 = (uint32*)get_blk(fs,b[i]); 
1574 +               swap_block((uint8 *)b2);
1575 +               for(j=0; j<BLOCKSIZE/4;j++) {
1576 +                       if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 + 
1577 +                                    (BLOCKSIZE/4)*(BLOCKSIZE/4) + 
1578 +                                    i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + 
1579 +                                    j*(BLOCKSIZE/4)) ) 
1580 +                         swap_block(get_blk(fs,b2[j]));
1581 +                       else {
1582 +                         done = 1;
1583 +                         break;
1584 +                       }
1585 +               }
1586 +       }
1587 +       return;
1588  }
1589  
1590  // endianness swap of the whole filesystem
1591 @@ -1045,7 +1353,8 @@
1592                 swap_goodblocks(fs, nod);
1593                 swap_nod(nod);
1594         }
1595 -       swap_gd(&fs->gd);
1596 +       for(i=0;i<GRP_NBGROUPS(fs);i++)
1597 +               swap_gd(&(fs->gd[i]));
1598         swap_sb(&fs->sb);
1599  }
1600  
1601 @@ -1053,7 +1362,8 @@
1602  {
1603         int i;
1604         swap_sb(&fs->sb);
1605 -       swap_gd(&fs->gd);
1606 +       for(i=0;i<GRP_NBGROUPS(fs);i++)
1607 +               swap_gd(&(fs->gd[i]));
1608         for(i = 1; i < fs->sb.s_inodes_count; i++)
1609         {
1610                 inode *nod = get_nod(fs, i);
1611 @@ -1084,53 +1394,118 @@
1612         directory *d;
1613         uint8 * b;
1614         uint32 nod;
1615 +       uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
1616 +               free_blocks_per_group,nbblocks_per_group;
1617 +       uint32 gd,itbl,ibmpos,bbmpos,itblpos;
1618 +       int j;
1619 +       uint8 *bbm,*ibm;
1620 +       inode *itab0;
1621         
1622         if(nbblocks < 16) // totally arbitrary
1623 -               errexit("too small filesystem");
1624 -       if(nbblocks >BLOCKS_PER_GROUP) // I build only one group
1625 -               errexit("too big filesystem");
1626 +               error_msg_and_die("too small filesystem");
1627 +
1628 +       /* nbblocks is the total number of blocks in the system. First 
1629 +        * calculate how much overhead blocks - inode table blocks,bitmap 
1630 +        * blocks,group descriptor blocks etc. - are needed assuming each 
1631 +        * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with 
1632 +        * this figure. Each group has the same number of blocks. So the fs 
1633 +        * has a size atleast the given value but usually rounded off to a i
1634 +        * higher number.
1635 +        */
1636 +       nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP;
1637 +       nbinodes_per_group = nbinodes/nbgroups +1;
1638 +       nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode));
1639 +       if (nbinodes_per_group < 16)
1640 +               nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
1641 +       overhead_per_group = 3 /*super block,ibm,bbm*/
1642 +                            + /* No. of blocks that the inodes occupy */
1643 +                              nbinodes_per_group *sizeof(inode)/BLOCKSIZE 
1644 +                            + /* No. of blocks that group descriptors occupy */
1645 +                              rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
1646 +       free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */;
1647 +       free_blocks_per_group = free_blocks/nbgroups;
1648 +       if (free_blocks > free_blocks_per_group * nbgroups)
1649 +               free_blocks_per_group++;
1650 +       nbblocks_per_group = free_blocks_per_group + overhead_per_group;
1651 +       /* e2fsck complains if nbblocks_per_group is not a multiple of 8 */
1652 +       nbblocks_per_group = rndup(nbblocks_per_group,8);
1653 +       free_blocks_per_group = nbblocks_per_group - overhead_per_group;
1654 +       if (nbblocks_per_group > BLOCKS_PER_GROUP) {
1655 +               /* Can this happen ? */
1656 +               nbblocks_per_group = BLOCKS_PER_GROUP;
1657 +               free_blocks_per_group = nbblocks_per_group - overhead_per_group;
1658 +       }
1659 +       nbblocks = nbblocks_per_group * nbgroups + 1;
1660 +       
1661 +
1662         if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
1663 -               errexit("not enough memory for filesystem");
1664 +               error_msg_and_die("not enough memory for filesystem");
1665  
1666         // create the superblock for an empty filesystem
1667 -       fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode));
1668 +       fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
1669         fs->sb.s_blocks_count = nbblocks;
1670         fs->sb.s_r_blocks_count = nbresrvd;
1671 -       fs->sb.s_free_blocks_count = nbblocks;
1672 +       fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups;
1673         fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
1674         fs->sb.s_first_data_block = (BLOCKSIZE == 1024);
1675         fs->sb.s_log_block_size = BLOCKSIZE >> 11;
1676         fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
1677 -       fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP;
1678 -       fs->sb.s_frags_per_group = BLOCKS_PER_GROUP;
1679 -       fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
1680 +       fs->sb.s_blocks_per_group = nbblocks_per_group;
1681 +       fs->sb.s_frags_per_group = nbblocks_per_group;
1682 +       fs->sb.s_inodes_per_group = nbinodes_per_group;
1683         fs->sb.s_magic = EXT2_MAGIC_NUMBER;
1684  
1685         // set up groupdescriptors
1686 -       fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE;
1687 -       fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count;
1688 -       fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count;
1689 -       fs->gd.bg_used_dirs_count = 1;
1690 -       fs->gd.bg_block_bitmap = 3;
1691 -       fs->gd.bg_inode_bitmap = 4;
1692 -       fs->gd.bg_inode_table = 5;
1693 -
1694 -       // mark non-filesystem blocks and inodes as allocated
1695 -       for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++)
1696 -               allocate(fs->bbm, i);
1697 -       for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++)
1698 -               allocate(fs->ibm, i);
1699 -
1700 -       // mark system blocsk and inodes as allocated
1701 -       for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++)
1702 -               allocate(fs->bbm, i);
1703 -       for(i = 1; i < EXT2_FIRST_INO; i++)
1704 -               allocate(fs->ibm, i);
1705 -
1706 -       // make root inode and directory
1707 -       fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1708 -       fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
1709 -       fs->itab[EXT2_ROOT_INO-1].i_links_count = 2;
1710 +       gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
1711 +       itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE;
1712 +       for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
1713 +               i<nbgroups;
1714 +               i++, bbmpos += nbblocks_per_group,ibmpos += nbblocks_per_group, 
1715 +               itblpos += nbblocks_per_group)  {
1716 +               
1717 +               fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
1718 +               fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
1719 +               fs->gd[i].bg_used_dirs_count = 0;
1720 +               fs->gd[i].bg_block_bitmap = bbmpos;
1721 +               fs->gd[i].bg_inode_bitmap = ibmpos;
1722 +               fs->gd[i].bg_inode_table = itblpos;
1723 +       }
1724 +
1725 +       /* Mark non-filesystem blocks and inodes as allocated */
1726 +       /* Mark system blocks and inodes as allocated         */
1727 +       for(i = 0; i<nbgroups;i++) {
1728 +
1729 +               /* Block bitmap */
1730 +               bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);    
1731 +               //non-filesystem blocks.
1732 +               for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++)
1733 +                       allocate(bbm, j); 
1734 +               //system blocks
1735 +               for(j = 1; j <= 3+gd+itbl; j++)
1736 +                       allocate(bbm, j); 
1737 +               
1738 +               /* Inode bitmap */
1739 +               ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);    
1740 +               //non-filesystem inodes
1741 +               for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
1742 +                       allocate(ibm, j);
1743 +       }
1744 +
1745 +       /* We have groups now. Add the root filesystem in group 0  */
1746 +       /* Also allocate the system inodes in group 0 and update   */
1747 +       /* directory count and inode count for group 0             */
1748 +
1749 +       ibm = get_blk(fs,fs->gd[0].bg_inode_bitmap);    
1750 +       for(j = 1; j < EXT2_FIRST_INO; j++) {
1751 +               allocate(ibm, j);
1752 +               fs->gd[0].bg_free_inodes_count--;
1753 +       }
1754 +       fs->gd[0].bg_used_dirs_count = 1;
1755 +       itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
1756 +       itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO; 
1757 +       itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
1758 +       itab0[EXT2_ROOT_INO-1].i_links_count = 2;
1759 +
1760         b = get_workblk();
1761         d = (directory*)b;
1762         d->d_inode = EXT2_ROOT_INO;
1763 @@ -1147,9 +1522,14 @@
1764         // make lost+found directory and reserve blocks
1765         if(fs->sb.s_r_blocks_count)
1766         {
1767 -               nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU | FM_IRWXG | FM_IRWXO);
1768 +               nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL));
1769                 memset(b, 0, BLOCKSIZE);
1770                 ((directory*)b)->d_rec_len = BLOCKSIZE;
1771 +               /* We run into problems with e2fsck if directory lost+found grows
1772 +                * bigger than this. Need to find out why this happens - sundar
1773 +                */
1774 +               if (fs->sb.s_r_blocks_count > 2049 ) 
1775 +                       fs->sb.s_r_blocks_count=2049;
1776                 for(i = 1; i < fs->sb.s_r_blocks_count; i++)
1777                         extend_blk(fs, nod, b, 1);
1778                 get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
1779 @@ -1170,24 +1550,24 @@
1780  // loads a filesystem from disk
1781  filesystem * load_fs(FILE * fh, int swapit)
1782  {
1783 -       size_t fssize;
1784 +       size_t fssize = 0;
1785         filesystem *fs;
1786         if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0))
1787 -               pexit("input filesystem image");
1788 +               perror_msg_and_die("input filesystem image");
1789         rewind(fh);
1790         fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
1791         if(fssize < 16) // totally arbitrary
1792 -               errexit("too small filesystem");
1793 -       if(fssize > BLOCKS_PER_GROUP) // I build only one group
1794 -               errexit("too big filesystem");
1795 +               error_msg_and_die("too small filesystem");
1796 +/*     if(fssize > BLOCKS_PER_GROUP) // I build only one group
1797 +               error_msg_and_die("too big filesystem"); */
1798         if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
1799 -               errexit("not enough memory for filesystem");
1800 +               error_msg_and_die("not enough memory for filesystem");
1801         if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
1802 -               pexit("input filesystem image");
1803 +               perror_msg_and_die("input filesystem image");
1804         if(swapit)
1805                 swap_badfs(fs);
1806         if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
1807 -               errexit("not a suitable ext2 filesystem");
1808 +               error_msg_and_die("not a suitable ext2 filesystem");
1809         return fs;
1810  }
1811  
1812 @@ -1230,9 +1610,9 @@
1813         while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
1814         {
1815                 if(fsize <= 0)
1816 -                       errexit("wrong size while saving inode %d", nod);
1817 +                       error_msg_and_die("wrong size while saving inode %d", nod);
1818                 if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
1819 -                       errexit("error while saving inode %d", nod);
1820 +                       error_msg_and_die("error while saving inode %d", nod);
1821                 fsize -= BLOCKSIZE;
1822         }
1823  }
1824 @@ -1250,7 +1630,7 @@
1825         {
1826                 int i, j;
1827                 if(fsize <= 0)
1828 -                       errexit("wrong size while saving inode %d", nod);
1829 +                       error_msg_and_die("wrong size while saving inode %d", nod);
1830                 b = get_blk(fs, bk);
1831                 for(i = 0; i < 64; i++)
1832                 {
1833 @@ -1406,7 +1786,7 @@
1834                         s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved"; 
1835         }
1836         printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
1837 -       if(!allocated(fs->ibm, nod))
1838 +       if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
1839         {
1840                 printf("unallocated\n");
1841                 return;
1842 @@ -1440,24 +1820,46 @@
1843                 default:
1844                         list_blocks(fs, nod);
1845         }
1846 +       printf("Done with inode %d\n",nod);
1847  }
1848  
1849  // describes various fields in a filesystem
1850  void print_fs(filesystem *fs)
1851  {
1852 -       int i;
1853 -       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);
1854 -       printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count);
1855 -       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);
1856 -       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);
1857 -       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);
1858 -       printf("block bitmap allocation:\n");
1859 -       print_bm(fs->bbm, fs->sb.s_blocks_count);
1860 -       printf("inode bitmap allocation:\n");
1861 -       print_bm(fs->ibm, fs->sb.s_inodes_count);
1862 -       for(i=1; i<=fs->sb.s_inodes_count; i++)
1863 -               if(allocated(fs->ibm, i))
1864 -                       print_inode(fs, i);
1865 +       int i,j;
1866 +       uint8 *ibm;
1867 +
1868 +       printf("%d blocks (%d free, %d reserved), first data block: %d\n",
1869 +              fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
1870 +              fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
1871 +       printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
1872 +              fs->sb.s_free_inodes_count);
1873 +       printf("block size = %d, frag size = %d\n",
1874 +              fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
1875 +              fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
1876 +       printf("Number of groups: %d\n",GRP_NBGROUPS(fs));
1877 +       printf("%d blocks per group,%d frags per group,%d inodes per group\n",
1878 +            fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
1879 +            fs->sb.s_inodes_per_group);
1880 +       printf("Size of inode table: %d blocks\n",
1881 +                       fs->sb.s_inodes_per_group * sizeof(inode)/BLOCKSIZE);
1882 +       for (i = 0; i < GRP_NBGROUPS(fs); i++) {
1883 +               printf("Group No: %d\n", i);
1884 +               printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
1885 +                    fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
1886 +                    fs->gd[i].bg_inode_table);
1887 +               printf("Free blocks count: %d\n",fs->gd[i].bg_free_blocks_count);
1888 +               printf("Free inodes count: %d\n",fs->gd[i].bg_free_inodes_count);
1889 +               printf("Used dir count: %d\n",fs->gd[i].bg_used_dirs_count);
1890 +               printf("block bitmap allocation:\n");
1891 +               print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
1892 +               printf("inode bitmap allocation:\n");
1893 +               ibm = GRP_GET_GROUP_IBM(fs, i);
1894 +               print_bm(ibm, fs->sb.s_inodes_per_group);
1895 +               for (j = 1; j <= fs->sb.s_inodes_per_group; j++)
1896 +                       if (allocated(ibm, j))
1897 +                               print_inode(fs, i*fs->sb.s_inodes_per_group + j);
1898 +       }
1899  }
1900  
1901  void dump_fs(filesystem *fs, FILE * fh, int swapit)
1902 @@ -1467,31 +1869,234 @@
1903         if(swapit)
1904                 swap_goodfs(fs);
1905         if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
1906 -               pexit("output filesystem image");
1907 +               perror_msg_and_die("output filesystem image");
1908         if(swapit)
1909                 swap_badfs(fs);
1910  }
1911  
1912 +/*  device table entries take the form of:
1913 +    <path>     <type> <mode>   <uid>   <gid>   <major> <minor> <start> <inc>   <count>
1914 +    /dev/mem     c    640       0       0         1       1       0     0         -
1915 +
1916 +    type can be one of: 
1917 +       f       A regular file
1918 +       d       Directory
1919 +       c       Character special device file
1920 +       b       Block special device file
1921 +       p       Fifo (named pipe)
1922 +
1923 +    I don't bother with symlinks (permissions are irrelevant), hard
1924 +    links (special cases of regular files), or sockets (why bother).
1925 +
1926 +    Regular files must exist in the target root directory.  If a char,
1927 +    block, fifo, or directory does not exist, it will be created.
1928 +*/
1929 +static int interpret_table_entry(filesystem *fs, char *line)
1930 +{
1931 +       char type, *name = NULL, *tmp, *dir, *bname;
1932 +       unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
1933 +       unsigned long start = 0, increment = 1, count = 0;
1934 +       inode *entry;
1935 +       uint32 nod, parent;
1936 +
1937 +       if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
1938 +                               SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
1939 +                               &start, &increment, &count) < 0) 
1940 +       {
1941 +               return 1;
1942 +       }
1943 +
1944 +       if (!strcmp(name, "/")) {
1945 +               error_msg_and_die("Device table entries require absolute paths");
1946 +       }
1947 +
1948 +       /* Check if this file already exists... */
1949 +       switch (type) {
1950 +               case 'd':
1951 +                       mode |= S_IFDIR;
1952 +                       break;
1953 +               case 'f':
1954 +                       mode |= S_IFREG;
1955 +                       break;
1956 +               case 'p':
1957 +                       mode |= S_IFIFO;
1958 +                       break;
1959 +               case 'c':
1960 +                       mode |= S_IFCHR;
1961 +                       break;
1962 +               case 'b':
1963 +                       mode |= S_IFBLK;
1964 +                       break;
1965 +               default:
1966 +                       error_msg_and_die("Unsupported file type");
1967 +       }
1968 +       nod = 0;
1969 +       if (count==0)
1970 +               nod = find_path(fs, EXT2_ROOT_INO, name);
1971 +       if (nod) {
1972 +               /* Ok, we just need to fixup an existing entry 
1973 +                * and we will be all done... */
1974 +               entry = get_nod(fs, nod);
1975 +               entry->i_uid = uid;
1976 +               entry->i_gid = gid;
1977 +               entry->i_mode = mode;
1978 +               if (major) {
1979 +                       dev_t rdev = makedev(major, minor);
1980 +                       ((uint8*)entry->i_block)[0] = (rdev & 0xff);
1981 +                       ((uint8*)entry->i_block)[1] = (rdev >> 8);
1982 +               }
1983 +       } else {
1984 +               /* Try and find our parent now */
1985 +               tmp = xstrdup(name);
1986 +               dir = dirname(tmp);
1987 +               parent = find_path(fs, EXT2_ROOT_INO, dir);
1988 +               free(tmp);
1989 +               if (!parent) {
1990 +                       error_msg ("skipping device_table entry '%s': no parent directory!", name);
1991 +                       free(name);
1992 +                       return 1;
1993 +               }
1994 +
1995 +               tmp = xstrdup(name);
1996 +               bname = xstrdup(basename(tmp));
1997 +               free(tmp);
1998 +               switch (type) {
1999 +                       case 'd':
2000 +                               mkdir_fs(fs, parent, bname, mode|FM_IFDIR, uid, gid, time(NULL));
2001 +                               break;
2002 +                       case 'f':
2003 +#if 0
2004 +                               {
2005 +                                       // This is a bit odd.. This will try to include
2006 +                                       // the file of the same name from your _build_
2007 +                                       // system...  Probably a very bad idea....
2008 +                                       struct stat st;
2009 +                                       FILE *fh = xfopen(name, "r");
2010 +                                       lstat(name, &st);
2011 +                                       mkfile_fs(fs, parent, bname, mode|FM_IFREG, st.st_size, fh, uid, gid, st.st_ctime);
2012 +                                       fclose(fh);
2013 +                               }
2014 +#else
2015 +                               error_msg("ignoring entry %s", name);
2016 +#endif
2017 +                               break;
2018 +                       case 'p':
2019 +                               error_msg("ignoring entry %s", name);
2020 +                               break;
2021 +                       case 'c':
2022 +                       case 'b':
2023 +                               if (count > 0) {
2024 +                                       dev_t rdev;
2025 +                                       char *dname;
2026 +                                       unsigned long i;
2027 +                                       for (i = start; i < count; i++) {
2028 +                                               asprintf(&dname, "%s%lu", bname, i);
2029 +                                               nod = find_path(fs, EXT2_ROOT_INO, dname);
2030 +                                               if (nod) {
2031 +                                                       /* We just need to fixup an existing entry */ 
2032 +                                                       entry = get_nod(fs, nod);
2033 +                                               } else {
2034 +                                                       nod = alloc_nod(fs);
2035 +                                                       add2dir(fs, parent, nod, dname, mode, uid, gid, time(NULL));
2036 +                                                       entry = get_nod(fs, nod);
2037 +                                               }
2038 +                                               entry->i_uid = uid;
2039 +                                               entry->i_gid = gid;
2040 +                                               entry->i_mode = mode;
2041 +                                               rdev = makedev(major, minor + (i * increment - start));
2042 +                                               ((uint8*)entry->i_block)[0] = (rdev & 0xff);
2043 +                                               ((uint8*)entry->i_block)[1] = (rdev >> 8);
2044 +                                               free(dname);
2045 +                                       }
2046 +                               } else {
2047 +                                       dev_t rdev = makedev(major, minor);
2048 +                                       nod = alloc_nod(fs);
2049 +                                       add2dir(fs, parent, nod, bname, mode, uid, gid, time(NULL));
2050 +                                       entry = get_nod(fs, nod);
2051 +                                       ((uint8*)entry->i_block)[0] = (rdev & 0xff);
2052 +                                       ((uint8*)entry->i_block)[1] = (rdev >> 8);
2053 +                               }
2054 +                               break;
2055 +                       default:
2056 +                               error_msg_and_die("Unsupported file type");
2057 +               }
2058 +               free(bname);
2059 +       }
2060 +       free(name);
2061 +       return 0;
2062 +}
2063 +
2064 +static int parse_device_table(filesystem *root, FILE * file)
2065 +{
2066 +       char *line;
2067 +       int status = 0;
2068 +       size_t length = 0;
2069 +
2070 +       /* Turn off squash, since we must ensure that values
2071 +        * entered via the device table are not squashed */
2072 +       squash_uids = 0;
2073 +       squash_perms = 0;
2074 +
2075 +       /* Looks ok so far.  The general plan now is to read in one
2076 +        * line at a time, check for leading comment delimiters ('#'),
2077 +        * then try and parse the line as a device table.  If we fail
2078 +        * to parse things, try and help the poor fool to fix their
2079 +        * device table with a useful error msg... */
2080 +       line = NULL;
2081 +       while (getline(&line, &length, file) != -1) {
2082 +               /* First trim off any whitespace */
2083 +               int len = strlen(line);
2084 +
2085 +               /* trim trailing whitespace */
2086 +               while (len > 0 && isspace(line[len - 1]))
2087 +                       line[--len] = '\0';
2088 +               /* trim leading whitespace */
2089 +               memmove(line, &line[strspn(line, " \n\r\t\v")], len);
2090 +
2091 +               /* How long are we after trimming? */
2092 +               len = strlen(line);
2093 +
2094 +               /* If this is NOT a comment line, try to interpret it */
2095 +               if (len && *line != '#') {
2096 +                       if (interpret_table_entry(root, line))
2097 +                               status = 1;
2098 +               }
2099 +
2100 +               free(line);
2101 +               line = NULL;
2102 +       }
2103 +       fclose(file);
2104 +
2105 +       return status;
2106 +}
2107 +
2108 +/*
2109 +Local Variables:
2110 +c-file-style: "linux"
2111 +c-basic-offset: 4
2112 +tab-width: 4
2113 +End:
2114 +*/
2115 +
2116  void showhelp(void)
2117  {
2118         fprintf(stderr, "Usage: %s [options] image\n"
2119         "Create an ext2 filesystem image from directories/files\n\n"
2120 -       "  -x image                Use this image as a starting point\n"
2121 -       "  -d directory            Add this directory as source\n"
2122 -       "  -f file                 Add nodes (e.g. devices) from this spec file\n"
2123 -       "  -b blocks               Size in blocks\n"
2124 -       "  -i inodes               Number of inodes\n"
2125 -       "  -r reserved             Number of reserved blocks\n"
2126 -       "  -g path                 Generate a block map file for this path\n"
2127 -       "  -e value                Fill unallocated blocks with value\n"
2128 -       "  -z                      Make files with holes\n"
2129 -       "  -v                      Print resulting filesystem structure\n"
2130 -       "  -h                      Show this help\n\n"
2131 -       "Example of spec file:\n"
2132 -       "drwx            /dev\n"
2133 -       "crw-    10,190  /dev/lcd\n"
2134 -       "brw-    1,0     /dev/ram0\n\n"
2135 -       "Report bugs to xavier.bestel@free.fr\n", argv0);
2136 +       "  -x image         Use this image as a starting point\n"
2137 +       "  -d directory     Add this directory as source\n"
2138 +       "  -b blocks        Size in blocks\n"
2139 +       "  -i inodes        Number of inodes\n"
2140 +       "  -r reserved      Number of reserved blocks\n"
2141 +       "  -g path          Generate a block map file for this path\n"
2142 +       "  -e value         Fill unallocated blocks with value\n"
2143 +       "  -z               Make files with holes\n"
2144 +       "  -D,-f            Use the named FILE as a device table file\n"
2145 +       "  -q               Squash permissions and owners making all files be owned by root\n"
2146 +       "  -U               Squash owners making all files be owned by root\n"
2147 +       "  -P               Squash permissions on all files\n"
2148 +       "  -v               Print resulting filesystem structure\n"
2149 +       "  -h               Show this help\n\n"
2150 +       "Report bugs to xavier.bestel@free.fr\n", app_name);
2151  }
2152  
2153  #define MAX_DOPT 128
2154 @@ -1521,21 +2126,17 @@
2155         filesystem *fs;
2156         int i;
2157         int c;
2158 +       struct stat sb;
2159 +       FILE *devtable = NULL;
2160  
2161 -       argv0 = argv[0];
2162 -       if(argc <= 1)
2163 -       {
2164 -               showhelp();
2165 -               exit(1);
2166 -       }
2167 -       while((c = getopt(argc, argv, "x:f:d:b:i:r:g:e:zvh")) != EOF)
2168 +       app_name = argv[0];
2169 +       while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
2170                 switch(c)
2171                 {
2172                         case 'x':
2173                                 fsin = optarg;
2174                                 break;
2175                         case 'd':
2176 -                       case 'f':
2177                                 dopt[didx++] = optarg;
2178                                 break;
2179                         case 'b':
2180 @@ -1556,6 +2157,24 @@
2181                         case 'z':
2182                                 holes = 1;
2183                                 break;
2184 +                       case 'f':
2185 +                       case 'D':
2186 +                               devtable = xfopen(optarg, "r");
2187 +                               if (fstat(fileno(devtable), &sb) < 0)
2188 +                                       perror_msg_and_die(optarg);
2189 +                               if (sb.st_size < 10)
2190 +                                       error_msg_and_die("%s: not a proper device table file", optarg);
2191 +                               break;
2192 +                       case 'q':
2193 +                               squash_uids = 1;
2194 +                               squash_perms = 1;
2195 +                               break;
2196 +                       case 'U':
2197 +                               squash_uids = 1;
2198 +                               break;
2199 +                       case 'P':
2200 +                               squash_perms = 1;
2201 +                               break;
2202                         case 'v':
2203                                 verbose = 1;
2204                                 break;
2205 @@ -1566,16 +2185,14 @@
2206                                 exit(1);
2207                 }
2208         if(optind < (argc - 1))
2209 -               errexit("too many arguments");
2210 +               error_msg_and_die("too many arguments");
2211         if(optind == (argc - 1))
2212                 fsout = argv[optind];
2213         if(fsin)
2214         {
2215                 if(strcmp(fsin, "-"))
2216                 {
2217 -                       FILE * fh = fopen(fsin, "r");
2218 -                       if(!fh)
2219 -                               pexit(fsin);
2220 +                       FILE * fh = xfopen(fsin, "r");
2221                         fs = load_fs(fh, bigendian);
2222                         fclose(fh);
2223                 }
2224 @@ -1585,7 +2202,7 @@
2225         else
2226         {
2227                 if(nbblocks == -1)
2228 -                       errexit("filesystem size unspecified");
2229 +                       error_msg_and_die("filesystem size unspecified");
2230                 if(nbinodes == -1)
2231                         nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
2232                 if(nbresrvd == -1)
2233 @@ -1595,35 +2212,30 @@
2234         for(i = 0; i < didx; i++)
2235         {
2236                 struct stat st;
2237 -               FILE *fh;
2238                 char *pdir;
2239                 stat(dopt[i], &st);
2240                 switch(st.st_mode & S_IFMT)
2241                 {
2242 -                       case S_IFREG:
2243 -                               if(!(fh = fopen(dopt[i], "r")))
2244 -                                       pexit(dopt[i]);
2245 -                               add2fs_from_file(fs, EXT2_ROOT_INO, fh);
2246 -                               fclose(fh);
2247 -                               break;
2248                         case S_IFDIR:
2249                                 if(!(pdir = getcwd(0, GETCWD_SIZE)))
2250 -                                       pexit(dopt[i]);
2251 +                                       perror_msg_and_die(dopt[i]);
2252                                 if(chdir(dopt[i]) < 0)
2253 -                                       pexit(dopt[i]);
2254 +                                       perror_msg_and_die(dopt[i]);
2255                                 add2fs_from_dir(fs, EXT2_ROOT_INO);
2256                                 if(chdir(pdir) < 0)
2257 -                                       pexit(pdir);
2258 +                                       perror_msg_and_die(pdir);
2259                                 free(pdir);
2260                                 break;
2261                         default:
2262 -                               errexit("%s in neither a file nor a directory", dopt[i]);
2263 +                               error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
2264                 }
2265         }
2266         if(emptyval)
2267                 for(i = 1; i < fs->sb.s_blocks_count; i++)
2268 -                       if(!allocated(fs->bbm, i))
2269 +                       if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i)))
2270                                 memset(get_blk(fs, i), emptyval, BLOCKSIZE);
2271 +       if(devtable)
2272 +               parse_device_table(fs, devtable);
2273         if(verbose)
2274                 print_fs(fs);
2275         for(i = 0; i < gidx; i++)
2276 @@ -1633,21 +2245,18 @@
2277                 char *p;
2278                 FILE *fh;
2279                 if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
2280 -                       errexit("path %s not found in filesystem", gopt[i]);
2281 +                       error_msg_and_die("path %s not found in filesystem", gopt[i]);
2282                 while((p = strchr(gopt[i], '/')))
2283                         *p = '_';
2284                 snprintf(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
2285 -               if(!(fh = fopen(fname, "w")))
2286 -                       pexit(fname);
2287 +               fh = xfopen(fname, "w");
2288                 fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
2289                 flist_blocks(fs, nod, fh);
2290                 fclose(fh);
2291         }
2292         if(strcmp(fsout, "-"))
2293         {
2294 -               FILE * fh = fopen(fsout, "w");
2295 -               if(!fh)
2296 -                       pexit(fsout);
2297 +               FILE * fh = xfopen(fsout, "w");
2298                 dump_fs(fs, fh, bigendian);
2299                 fclose(fh);
2300         }
2301 diff -urN genext2fs-1.3.orig/test-mount.sh genext2fs-1.3/test-mount.sh
2302 --- genext2fs-1.3.orig/test-mount.sh    1969-12-31 17:00:00.000000000 -0700
2303 +++ genext2fs-1.3/test-mount.sh 2003-04-21 01:41:42.000000000 -0600
2304 @@ -0,0 +1,96 @@
2305 +#!/bin/sh
2306 +set -e
2307 +
2308 +cleanup () {
2309 +       set +e
2310 +       umount mnt 2>/dev/null
2311 +       rm -rf mnt ext2.img lsout fout test 2>/dev/null
2312 +}
2313 +
2314 +# dtest - Uses the -d directory option of genext2fs
2315 +# Creates an image with a file of given size and verifies it
2316 +# Usage: dtest file-size number-of-blocks 
2317 +dtest () {
2318 +       size=$1; blocks=$2;fname=$size 
2319 +       echo "Testing with file of size $size "
2320 +       mkdir -p test
2321 +       cd test
2322 +       dd if=/dev/zero of=file.$1 bs=1 count=$size 
2323 +       cd ..
2324 +       ./genext2fs -b $blocks -d test ext2.img 
2325 +       md5=`md5sum ext2.img | cut -f1 -d " "`
2326 +       if ! /sbin/e2fsck -fn ext2.img ; then
2327 +               echo "fsck failed"
2328 +               echo FAILED
2329 +               cleanup
2330 +               exit 1
2331 +       fi
2332 +       mkdir -p mnt
2333 +       if ! mount -t ext2 -o loop ext2.img mnt; then
2334 +               echo FAILED
2335 +               cleanup
2336 +               exit 1
2337 +       fi
2338 +       if (! [ -f mnt/file.$fname ]) || \
2339 +                       [ $fname != "`ls -al mnt | grep file.$fname |awk '{print $5}'`" ] ; then
2340 +               echo FAILED
2341 +               cleanup
2342 +               exit 1
2343 +       fi
2344 +       echo PASSED "(md5 checksum for the image: $md5)"
2345 +       cleanup
2346 +}
2347 +
2348 +# ftest - Uses the -f spec-file option of genext2fs
2349 +# Creates an image with the devices mentioned in the given spec 
2350 +# file and verifies it
2351 +# Usage: ftest spec-file number-of-blocks 
2352 +ftest () {
2353 +       fname=$1; blocks=$2; 
2354 +       echo "Testing with devices file $fname"
2355 +       ./genext2fs -b $blocks -f $fname ext2.img
2356 +       md5=`md5sum ext2.img | cut -f 1 -d " "`
2357 +       if ! /sbin/e2fsck -fn ext2.img ; then
2358 +               echo "fsck failed"
2359 +               echo FAILED
2360 +               cleanup
2361 +               exit 1
2362 +       fi
2363 +       mkdir -p mnt
2364 +       if ! mount -t ext2 -o loop ext2.img mnt; then
2365 +               echo FAILED
2366 +               cleanup
2367 +               exit 1
2368 +       fi
2369 +       if ! [ -d mnt/dev ] ; then
2370 +               echo FAILED
2371 +               cleanup
2372 +               exit 1
2373 +       fi
2374 +       cat dev.txt | grep ^[bc] | \
2375 +               awk '{print $1substr($1,2)substr($1,2),$2,$3}'| \
2376 +                       sort -d -k3.6 > fout
2377 +       ls -al mnt/dev | grep ^[bc] | \
2378 +               awk '{ print $1,$5$6,"/dev/"$10}' | \
2379 +                       sort -d -k3.6 > lsout
2380 +       if ! diff fout lsout ; then
2381 +               echo FAILED
2382 +               cleanup
2383 +               exit 1
2384 +       fi
2385 +       echo PASSED "(md5 checksum for the image: $md5)"
2386 +       cleanup
2387 +}
2388 +
2389 +dtest 0 4096 
2390 +dtest 0 8193
2391 +dtest 0 8194
2392 +dtest 1 4096 
2393 +dtest 12288 4096 
2394 +dtest 274432 4096 
2395 +dtest 8388608 9000 
2396 +dtest 16777216 20000
2397 +
2398 +ftest dev.txt 4096 
2399 +
2400 +exit 0
2401 diff -urN genext2fs-1.3.orig/test.sh genext2fs-1.3/test.sh
2402 --- genext2fs-1.3.orig/test.sh  1969-12-31 17:00:00.000000000 -0700
2403 +++ genext2fs-1.3/test.sh       2003-04-21 01:41:42.000000000 -0600
2404 @@ -0,0 +1,53 @@
2405 +#!/bin/sh
2406 +set -e
2407 +
2408 +# dtest - Uses the -d directory option of genext2fs
2409 +# Creates an image with a file of given size and verifies it
2410 +# Usage: dtest file-size number-of-blocks correct-checksum
2411 +dtest () {
2412 +       size=$1; blocks=$2; checksum=$3
2413 +       echo "Testing with file of size $size "
2414 +       mkdir -p test
2415 +       cd test
2416 +       dd if=/dev/zero of=file.$1 bs=1 count=$size 
2417 +       cd ..
2418 +       ./genext2fs -b $blocks -d test ext2.img 
2419 +       md5=`md5sum ext2.img | cut -d" " -f1`
2420 +       rm -rf ext2.img test
2421 +       if [ $md5 == $checksum ] ; then
2422 +               echo PASSED
2423 +       else
2424 +               echo FAILED
2425 +               exit 1
2426 +       fi
2427 +}
2428 +
2429 +# ftest - Uses the -f spec-file option of genext2fs
2430 +# Creates an image with the devices mentioned in the given spec 
2431 +# file and verifies it
2432 +# Usage: ftest spec-file number-of-blocks correct-checksum
2433 +ftest () {
2434 +       fname=$1; blocks=$2; checksum=$3
2435 +       echo "Testing with devices file $fname"
2436 +       ./genext2fs -b $blocks -f $fname ext2.img
2437 +       md5=`md5sum ext2.img | cut -d" " -f1`
2438 +       rm -rf ext2.img
2439 +       if [ $md5 == $checksum ] ; then
2440 +               echo PASSED
2441 +       else
2442 +               echo FAILED
2443 +               exit 1
2444 +       fi
2445 +}
2446 +
2447 +dtest 0 4096 491a43ab93c2e5c186c9f1f72d88e5c5
2448 +dtest 0 8193 6289224f0b7f151994479ba156c43505
2449 +dtest 0 8194 3272c43c25e8d0c3768935861a643a65
2450 +dtest 1 4096 5ee24486d33af88c63080b09d8cadfb5
2451 +dtest 12288 4096 494498364defdc27b2770d1f9c1e3387
2452 +dtest 274432 4096 65c4bd8d30bf563fa5434119a12abff1
2453 +dtest 8388608 9000 9a49b0461ee236b7fd7c452fb6a1f2dc
2454 +dtest 16777216 20000 91e16429c901b68d30f783263f0611b7
2455 +
2456 +ftest dev.txt 4096 921ee9343b0759e16ad8d979d7dd16ec
2457 +exit 0