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