1 diff -urN genext2fs-1.3.orig/Makefile genext2fs-1.3/Makefile
2 --- genext2fs-1.3.orig/Makefile 1969-12-31 17:00:00.000000000 -0700
3 +++ genext2fs-1.3/Makefile 2003-04-21 01:41:42.000000000 -0600
9 +OBJS=$(patsubst %.c,%.o, $(SRC))
15 + $(CC) $(CFLAGS) -o $@ $(OBJS) -o $@
18 + $(CC) $(CFLAGS) -c $< -o $@
23 + $(INSTALL) -d $(DESTDIR)/usr/bin/
24 + $(INSTALL) -m 755 genext2fs $(DESTDIR)/usr/bin/
25 + $(INSTALL) -d $(DESTDIR)/usr/share/man/man8/
26 + $(INSTALL) -m 644 genext2fs.8 $(DESTDIR)/usr/share/man/man8/
29 + rm -rf *.o *.a core genext2fs
30 + rm -rf test ext2.img
34 + dd if=/dev/zero of=test/zero count=1
35 + ./genext2fs -b 4096 -d test ext2.img
37 + md5=`md5sum ext2.img | cut -f 1 -d " "`; \
38 + if [ "$$md5" != "89471302d95f96a76fbb2cff98182cde" ] ; then \
39 + echo "test failed."; \
41 + echo "test succeeded."; \
44 +# test genext2fs by creating the image and comparing checksums
48 +# test genext2fs by actually mounting the created image.
50 + sudo sh ./test-mount.sh
51 diff -urN genext2fs-1.3.orig/debian/changelog genext2fs-1.3/debian/changelog
52 --- genext2fs-1.3.orig/debian/changelog 1969-12-31 17:00:00.000000000 -0700
53 +++ genext2fs-1.3/debian/changelog 2003-04-21 01:41:42.000000000 -0600
55 +genext2fs (1.3-2) unstable; urgency=low
57 + * apply fix from upstream cvs that appears to fix endian bug
59 + * mention filesystem size limit in manpage (closes: #122729)
60 + * mention that hard links are not supported in manpage
62 + * add sanity check at the end of the build
64 + -- David Kimdon <dwhedon@debian.org> Fri, 8 Mar 2002 23:17:36 -0800
66 +genext2fs (1.3-1) unstable; urgency=low
68 + * Initial Release. (closes: #105263)
70 + -- David Kimdon <dwhedon@debian.org> Sat, 14 Jul 2001 13:24:49 -0700
72 diff -urN genext2fs-1.3.orig/debian/control genext2fs-1.3/debian/control
73 --- genext2fs-1.3.orig/debian/control 1969-12-31 17:00:00.000000000 -0700
74 +++ genext2fs-1.3/debian/control 2003-04-21 01:41:42.000000000 -0600
79 +Maintainer: David Kimdon <dwhedon@debian.org>
80 +Build-Depends: debhelper (>> 3.0.0)
81 +Standards-Version: 3.5.2
85 +Depends: ${shlibs:Depends}
86 +Description: ext2 filesystem generator for embedded systems
87 + `genext2fs' is meant to generate an ext2 filesystem
88 + as a normal (non-root) user. It doesn't require you to mount
89 + the image file to copy files on it. It doesn't even require
90 + you to be the superuser to make device nodes.
92 + Warning ! `genext2fs' has been designed for embedded
93 + systems. As such, it will generate a filesystem for single-user
94 + usage: all files/directories/etc... will belong to UID/GID 0
95 diff -urN genext2fs-1.3.orig/debian/copyright genext2fs-1.3/debian/copyright
96 --- genext2fs-1.3.orig/debian/copyright 1969-12-31 17:00:00.000000000 -0700
97 +++ genext2fs-1.3/debian/copyright 2003-04-21 01:41:42.000000000 -0600
99 +This package was debianized by David Kimdon <dwhedon@debian.org> on
100 +Sat, 14 Jul 2001 13:24:49 -0700.
102 +It was downloaded from http://freshmeat.net/projects/genext2fs/
103 +Upstream Author(s): Xavier Bestel <xbestel@aplio.fr>
105 +Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
107 +This program is free software; you can redistribute it and/or
108 +modify it under the terms of the GNU General Public License
109 +as published by the Free Software Foundation; version
112 +On Debian systems, the complete text of the GNU General Public
113 +License can be found in /usr/share/common-licenses/GPL file.
114 diff -urN genext2fs-1.3.orig/debian/rules genext2fs-1.3/debian/rules
115 --- genext2fs-1.3.orig/debian/rules 1969-12-31 17:00:00.000000000 -0700
116 +++ genext2fs-1.3/debian/rules 2003-04-21 01:41:42.000000000 -0600
119 +# Sample debian/rules that uses debhelper.
120 +# GNU copyright 1997 to 1999 by Joey Hess.
122 +# Uncomment this to turn on verbose mode.
123 +#export DH_VERBOSE=1
125 +# This is the debhelper compatability version to use.
128 +configure: configure-stamp
131 + # Add here commands to configure the package.
132 + # ./configure --prefix=/usr --mandir=/usr/share/man/
134 + touch configure-stamp
136 +build: configure-stamp build-stamp
140 + # Add here commands to compile the package.
149 + rm -f build-stamp configure-stamp
151 + # Add here commands to clean up after the build process.
162 + # Add here commands to install the package into debian/genext2fs.
163 + $(MAKE) install DESTDIR=`pwd`/debian/genext2fs
166 +# Build architecture-independent files here.
167 +binary-indep: build install
168 +# We have nothing to do by default.
170 +# Build architecture-dependent files here.
171 +binary-arch: build install
175 + dh_installchangelogs
186 +binary: binary-indep binary-arch
187 +.PHONY: build clean binary-indep binary-arch binary install configure
188 diff -urN genext2fs-1.3.orig/dev.txt genext2fs-1.3/dev.txt
189 --- genext2fs-1.3.orig/dev.txt 2000-09-28 09:03:19.000000000 -0600
190 +++ genext2fs-1.3/dev.txt 1969-12-31 17:00:00.000000000 -0700
193 -crw- 10,190 /dev/lcd
194 -crw- 10,191 /dev/splc781
195 -crw- 4,0 /dev/console
212 -crw- 10,178 /dev/triokb
218 -crw- 2,10 /dev/ptypa
219 -crw- 2,11 /dev/ptypb
220 -crw- 2,12 /dev/ptypc
221 -crw- 2,13 /dev/ptypd
222 -crw- 2,14 /dev/ptype
223 -crw- 2,15 /dev/ptypf
243 -crw- 4,64 /dev/ttyS0
244 -crw- 4,65 /dev/ttyS1
245 -crw- 4,66 /dev/ttyS2
246 -crw- 4,67 /dev/ttyS3
247 -crw- 4,68 /dev/ttyS4
248 -crw- 4,69 /dev/ttyS5
249 -crw- 4,70 /dev/ttyS6
250 -crw- 4,71 /dev/ttyS7
251 -crw- 4,72 /dev/ttyS8
252 -crw- 4,73 /dev/ttyS9
263 -crw- 3,10 /dev/ttypa
264 -crw- 3,11 /dev/ttypb
265 -crw- 3,12 /dev/ttypc
266 -crw- 3,13 /dev/ttypd
267 -crw- 3,14 /dev/ttype
268 -crw- 3,15 /dev/ttypf
270 -crwx 10,111 /dev/dtedrv
271 -crwx 4,110 /dev/ttyM
272 -crw- 77,1 /dev/tssnd
273 -crw- 77,2 /dev/tstone
275 -crwx 10,180 /dev/triohook
278 -crw- 10,175 /dev/tporta
279 -crw- 10,176 /dev/tportb
280 -crwx 10,100 /dev/softmodem
281 -crwx 10,101 /dev/softmodem_signals
282 -crwx 10,181 /dev/triovoice
286 diff -urN genext2fs-1.3.orig/device_table.txt genext2fs-1.3/device_table.txt
287 --- genext2fs-1.3.orig/device_table.txt 1969-12-31 17:00:00.000000000 -0700
288 +++ genext2fs-1.3/device_table.txt 2003-04-21 01:41:42.000000000 -0600
290 +# When building a target filesystem, it is desirable to not have to
291 +# become root and then run 'mknod' a thousand times. Using a device
292 +# table you can create device nodes and directories "on the fly".
294 +# This is a sample device table file for use with genext2fs. You can
295 +# do all sorts of interesting things with a device table file. For
296 +# example, if you want to adjust the permissions on a particular file
297 +# you can just add an entry like:
298 +# /sbin/foobar f 2755 0 0 - - - - -
299 +# and (assuming the file /sbin/foobar exists) it will be made setuid
300 +# root (regardless of what its permissions are on the host filesystem.
301 +# Furthermore, you can use a single table entry to create a many device
302 +# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
303 +# I could just use the following two table entries:
304 +# /dev/hda b 640 0 0 3 0 0 0 -
305 +# /dev/hda b 640 0 0 3 1 1 1 15
307 +# Device table entries take the form of:
308 +# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
309 +# where name is the file name, type can be one of:
312 +# c Character special device file
313 +# b Block special device file
314 +# p Fifo (named pipe)
315 +# uid is the user id for the target file, gid is the group id for the
316 +# target file. The rest of the entries (major, minor, etc) apply only
317 +# to device special files.
320 +# -Erik Andersen <andersen@codepoet.org>
323 +#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
324 +/dev d 755 0 0 - - - - -
325 +/dev/mem c 640 0 0 1 1 0 0 -
326 +/dev/kmem c 640 0 0 1 2 0 0 -
327 +/dev/null c 640 0 0 1 3 0 0 -
328 +/dev/zero c 640 0 0 1 5 0 0 -
329 +/dev/random c 640 0 0 1 8 0 0 -
330 +/dev/urandom c 640 0 0 1 9 0 0 -
331 +/dev/tty c 666 0 0 5 0 0 0 -
332 +/dev/tty c 666 0 0 4 0 0 1 6
333 +/dev/console c 640 0 0 5 1 0 0 -
334 +/dev/ram b 640 0 0 1 1 0 0 -
335 +/dev/ram b 640 0 0 1 0 0 1 4
336 +/dev/loop b 640 0 0 7 0 0 1 2
337 +/dev/ptmx c 666 0 0 5 2 0 0 -
338 +#/dev/ttyS c 640 0 0 4 64 0 1 4
339 +#/dev/psaux c 640 0 0 10 1 0 0 -
340 +#/dev/rtc c 640 0 0 10 135 0 0 -
342 +# Adjust permissions on some normal files
343 +#/etc/shadow f 600 0 0 - - - - -
344 +#/bin/tinylogin f 4755 0 0 - - - - -
346 +# User-mode Linux stuff
347 +/dev/ubda b 640 0 0 98 0 0 0 -
348 +/dev/ubda b 640 0 0 98 1 1 1 15
351 +/dev/hda b 640 0 0 3 0 0 0 -
352 +/dev/hda b 640 0 0 3 1 1 1 15
353 +/dev/hdb b 640 0 0 3 64 0 0 -
354 +/dev/hdb b 640 0 0 3 65 1 1 15
355 +#/dev/hdc b 640 0 0 22 0 0 0 -
356 +#/dev/hdc b 640 0 0 22 1 1 1 15
357 +#/dev/hdd b 640 0 0 22 64 0 0 -
358 +#/dev/hdd b 640 0 0 22 65 1 1 15
359 +#/dev/hde b 640 0 0 33 0 0 0 -
360 +#/dev/hde b 640 0 0 33 1 1 1 15
361 +#/dev/hdf b 640 0 0 33 64 0 0 -
362 +#/dev/hdf b 640 0 0 33 65 1 1 15
363 +#/dev/hdg b 640 0 0 34 0 0 0 -
364 +#/dev/hdg b 640 0 0 34 1 1 1 15
365 +#/dev/hdh b 640 0 0 34 64 0 0 -
366 +#/dev/hdh b 640 0 0 34 65 1 1 15
369 +#/dev/sda b 640 0 0 8 0 0 0 -
370 +#/dev/sda b 640 0 0 8 1 1 1 15
371 +#/dev/sdb b 640 0 0 8 16 0 0 -
372 +#/dev/sdb b 640 0 0 8 17 1 1 15
373 +#/dev/sdc b 640 0 0 8 32 0 0 -
374 +#/dev/sdc b 640 0 0 8 33 1 1 15
375 +#/dev/sdd b 640 0 0 8 48 0 0 -
376 +#/dev/sdd b 640 0 0 8 49 1 1 15
377 +#/dev/sde b 640 0 0 8 64 0 0 -
378 +#/dev/sde b 640 0 0 8 65 1 1 15
379 +#/dev/sdf b 640 0 0 8 80 0 0 -
380 +#/dev/sdf b 640 0 0 8 81 1 1 15
381 +#/dev/sdg b 640 0 0 8 96 0 0 -
382 +#/dev/sdg b 640 0 0 8 97 1 1 15
383 +#/dev/sdh b 640 0 0 8 112 0 0 -
384 +#/dev/sdh b 640 0 0 8 113 1 1 15
385 +#/dev/sg c 640 0 0 21 0 0 1 15
386 +#/dev/scd b 640 0 0 11 0 0 1 15
387 +#/dev/st c 640 0 0 9 0 0 1 8
388 +#/dev/nst c 640 0 0 9 128 0 1 8
389 +#/dev/st c 640 0 0 9 32 1 1 4
390 +#/dev/st c 640 0 0 9 64 1 1 4
391 +#/dev/st c 640 0 0 9 96 1 1 4
393 +# Floppy disk devices
394 +#/dev/fd b 640 0 0 2 0 0 1 2
395 +#/dev/fd0d360 b 640 0 0 2 4 0 0 -
396 +#/dev/fd1d360 b 640 0 0 2 5 0 0 -
397 +#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
398 +#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
399 +#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
400 +#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
401 +#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
402 +#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
404 +# All the proprietary cdrom devices in the world
405 +#/dev/aztcd b 640 0 0 29 0 0 0 -
406 +#/dev/bpcd b 640 0 0 41 0 0 0 -
407 +#/dev/capi20 c 640 0 0 68 0 0 1 2
408 +#/dev/cdu31a b 640 0 0 15 0 0 0 -
409 +#/dev/cdu535 b 640 0 0 24 0 0 0 -
410 +#/dev/cm206cd b 640 0 0 32 0 0 0 -
411 +#/dev/sjcd b 640 0 0 18 0 0 0 -
412 +#/dev/sonycd b 640 0 0 15 0 0 0 -
413 +#/dev/gscd b 640 0 0 16 0 0 0 -
414 +#/dev/sbpcd b 640 0 0 25 0 0 0 -
415 +#/dev/sbpcd b 640 0 0 25 0 0 1 4
416 +#/dev/mcd b 640 0 0 23 0 0 0 -
417 +#/dev/optcd b 640 0 0 17 0 0 0 -
419 diff -urN genext2fs-1.3.orig/genext2fs.8 genext2fs-1.3/genext2fs.8
420 --- genext2fs-1.3.orig/genext2fs.8 1969-12-31 17:00:00.000000000 -0700
421 +++ genext2fs-1.3/genext2fs.8 2003-04-21 01:41:42.000000000 -0600
423 +.\" Hey, EMACS: -*- nroff -*-
424 +.\" First parameter, NAME, should be all caps
425 +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
426 +.\" other parameters are allowed: see man(7), man(1)
427 +.TH GENEXT2FS 8 "July 14, 2001"
428 +.\" Please adjust this date whenever revising the manpage.
430 +.\" Some roff macros, for reference:
431 +.\" .nh disable hyphenation
432 +.\" .hy enable hyphenation
433 +.\" .ad l left justify
434 +.\" .ad b justify to both left and right margins
435 +.\" .nf disable filling
436 +.\" .fi enable filling
437 +.\" .br insert line break
438 +.\" .sp <n> insert n+1 empty lines
439 +.\" for manpage-specific macros, see man(7)
441 +genext2fs \- ext2 filesystem generator for embedded systems
444 +.RI [ options ] " image"
446 +\fBgenext2fs\fP generates an ext2 filesystem
447 +as a normal (non-root) user. It doesn't require you to mount
448 +the image file to copy files on it. It doesn't even require
449 +you to be the superuser to make device nodes.
453 +Use this image as a starting point
456 +Add this directory as source
461 +Uses the named FILE as a device table file, to create device
462 +nodes and directories "on the fly".
471 +Number of reserved blocks
474 +Generate a block map file for this path
477 +Fill unallocated blocks with value
480 +Make files with holes
483 +Squash owners making all files be owned by root
486 +Squash permissions on all files
489 +Squash permissions and owners (same as -P -U)
492 +Print resulting filesystem structure
501 + genext2fs -b 1440 -d src /dev/fd0
506 +directory will be written to
508 +as a new ext2 filesystem image. You can then mount the floppy as
513 + genext2fs -b 1024 -d src -D device_table.txt flashdisk.img
516 +This example builds a filesystem from all the files in
518 +, then device nodes are created based on the content the device_table file
520 +An example device file follows:
523 + #<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
524 + /dev d 755 0 0 - - - - -
525 + /dev/mem c 640 0 0 1 1 0 0 -
526 + /dev/tty c 666 0 0 5 0 0 0 -
527 + /dev/tty c 666 0 0 4 0 0 1 6
528 + /dev/loop b 640 0 0 7 0 0 1 2
529 + /dev/hda b 640 0 0 3 0 0 0 -
530 + /dev/hda b 640 0 0 3 1 1 1 16
533 +This device table creates the /dev directory, a character device
534 +node /dev/mem (major 1, minor 1), it also creates /dev/tty,
535 +/dev/tty[0-5], /dev/loop[0-1], /dev/hda, and /dev/hda0 to /dev/hda15
537 +\fBgenext2fs\fP does not support hard links. Hard links present in the input
538 +tree will be represented as separate files in the ext2 image.
546 +This manual page was written by David Kimdon <dwhedon@debian.org>,
547 +for the Debian GNU/Linux system (but may be used by others).
548 diff -urN genext2fs-1.3.orig/genext2fs.c genext2fs-1.3/genext2fs.c
549 --- genext2fs-1.3.orig/genext2fs.c 2001-06-18 02:11:32.000000000 -0600
550 +++ genext2fs-1.3/genext2fs.c 2003-04-21 01:48:35.000000000 -0600
552 +/* vi: set sw=8 ts=8: */
555 // ext2 filesystem generator for embedded systems
557 // Bugfix: getcwd values for Solaris xavier.gueguen@col.bsf.alcatel.fr
558 // Bugfix: ANSI scanf for non-GNU C xavier.gueguen@col.bsf.alcatel.fr
559 // 28 Jun 2001 Bugfix: getcwd differs for Solaris/GNU mike@sowbug.com
560 +// 23 Mar 2002 Bugfix: test for IFCHR or IFBLK was flawed
561 +// 10 Oct 2002 Added comments,makefile targets, vsundar@ixiacom.com
562 +// endianess swap assert check.
563 +// Copyright (C) 2002 Ixia communications
564 +// 12 Oct 2002 Added support for triple indirection vsundar@ixiacom.com
565 +// Copyright (C) 2002 Ixia communications
566 +// 14 Oct 2002 Added support for groups vsundar@ixiacom.com
567 +// Copyright (C) 2002 Ixia communications
568 +// 5 Jan 2003 Bugfixes: reserved inodes should be set vsundar@usc.edu
569 +// only in the first group; directory names
570 +// need to be null padded at the end; and
571 +// number of blocks per group should be a
572 +// multiple of 8. Updated md5 values.
573 +// 6 Jan 2003 Erik Andersen <andersee@debian.org> added
574 +// mkfs.jffs2 compatible device table support,
575 +// along with -q, -P, -U
578 // `genext2fs' is a mean to generate an ext2 filesystem
580 // the image file to copy files on it. It doesn't even require
581 // you to be the superuser to make device nodes.
583 -// Warning ! `genext2fs' has been designed for embedded
584 -// systems. As such, it will generate a filesystem for single-user
585 -// usage: all files/directories/etc... will belong to UID/GID 0
589 // # genext2fs -b 1440 -d srcdir /dev/fd0
591 // a new ext2 filesystem image. You can then mount the floppy as
594 -// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img
595 +// # genext2fs -b 1024 -d builddir -D device_table.txt flashdisk.img
597 // This one would build a filesystem from all the files in builddir,
598 -// then would read a devices list and make apropriate nodes. The
599 -// format for the device list is:
602 -// crw- 10,190 /dev/lcd
603 -// brw- 1,0 /dev/ram0
605 -// This device list builds the /dev directory, a character device
606 -// node /dev/lcd (major 10, minor 190) and a block device node
607 -// /dev/ram0 (major 1, minor 0)
608 +// then would read the device_table.txt file and make apropriate nodes.
609 +// The format for the device table file is covered in detail in the sample
610 +// device_table.txt file provided with the genext2fs source.
620 #include <sys/stat.h>
630 #define BLOCKSIZE 1024
631 #define BLOCKS_PER_GROUP 8192
632 #define BYTES_PER_INODE (8*BLOCKSIZE)
633 +/* Percentage of blocks that are reserved.*/
634 #define RESERVED_INODES 5/100
637 // inode block size (why is it != BLOCKSIZE ?!?)
638 +/* The field i_blocks in the ext2 inode stores the number of data blocks
639 + but in terms of 512 bytes. That is what INODE_BLOCKSIZE represents.
640 + INOBLK is the number of such blocks in an actual disk block */
642 #define INODE_BLOCKSIZE 512
643 #define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE)
646 #define OP_HOLES 0x01 // make files with holes
648 +/* Defines for accessing group details */
650 +// Number of groups in the filesystem
651 +#define GRP_NBGROUPS(fs) ( ((fs)->sb.s_blocks_count-1)/(fs)->sb.s_blocks_per_group )
653 +// Get group block bitmap (bbm) given the group number
654 +#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
656 +// Get group inode bitmap (ibm) given the group number
657 +#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
659 +// Given an inode number find the group it belongs to
660 +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
662 +//Given an inode number get the inode bitmap that covers it
663 +#define GRP_GET_INODE_BITMAP(fs,nod) \
664 + ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
666 +//Given an inode number find its offset within the inode bitmap that covers it
667 +#define GRP_IBM_OFFSET(fs,nod) \
668 + ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
670 +// Given a block number find the group it belongs to
671 +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
673 +//Given a block number get the block bitmap that covers it
674 +#define GRP_GET_BLOCK_BITMAP(fs,blk) \
675 + ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
677 +//Given a block number find its offset within the block bitmap that covers it
678 +#define GRP_BBM_OFFSET(fs,blk) \
679 + ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
687 uint32 bg_reserved[3];
688 - uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)];
694 typedef uint8 block[BLOCKSIZE];
696 +/* blockwalker fields:
697 + The blockwalker is used to access all the blocks of a file (including
698 + the indirection blocks) through repeated calls to walk_bw.
700 + bpdir -> index into the inode->i_block[]. Indicates level of indirection.
701 + bnum -> total number of blocks so far accessed. including indirection
703 + bpind,bpdind,bptind -> index into indirection blocks.
705 + bpind, bpdind, bptind do *NOT* index into single, double and triple
706 + indirect blocks resp. as you might expect from their names. Instead
707 + they are in order the 1st, 2nd & 3rd index to be used
710 + To access data block number 70000:
711 + bpdir: 15 (we are doing triple indirection)
712 + bpind: 0 ( index into the triple indirection block)
713 + bpdind: 16 ( index into the double indirection block)
714 + bptind: 99 ( index into the single indirection block)
715 + 70000 = 12 + 256 + 256*256 + 16*256 + 100 (indexing starts from zero)
717 + So,for double indirection bpind will index into the double indirection
718 + block and bpdind into the single indirection block. For single indirection
719 + only bpind will be used.
725 @@ -313,15 +387,14 @@
730 +/* Filesystem structure that support groups */
731 #if BLOCKSIZE == 1024
734 block zero; // The famous block 0
735 superblock sb; // The superblock
736 - groupdescriptor gd; // The group desciptor
737 - block bbm; // The block bitmap
738 - block ibm; // The inode bitmap
739 - inode itab[0]; // The inode table
740 + groupdescriptor gd[0]; // The group descriptors
743 #error UNHANDLED BLOCKSIZE
744 @@ -389,25 +462,113 @@
749 +static char * app_name;
750 +static int squash_uids = 0;
751 +static int squash_perms = 0;
752 +static const char *const memory_exhausted = "memory exhausted";
754 // error (un)handling
755 -inline void errexit(const char *fmt, ...)
756 +static void verror_msg(const char *s, va_list p)
759 - fprintf(stderr, "%s: ", argv0);
761 - vfprintf(stderr, fmt, ap);
763 - fprintf(stderr, "\n");
766 + fprintf(stderr, "%s: ", app_name);
767 + vfprintf(stderr, s, p);
769 +static void error_msg(const char *s, ...)
775 + putc('\n', stderr);
778 +static void error_msg_and_die(const char *s, ...)
784 + putc('\n', stderr);
785 + exit(EXIT_FAILURE);
788 +static void vperror_msg(const char *s, va_list p)
796 + fprintf(stderr, "%s%s\n", s, strerror(err));
800 +static void perror_msg(const char *s, ...)
808 +static void perror_msg_and_die(const char *s, ...)
814 + exit(EXIT_FAILURE);
817 -inline void pexit(const char * fname)
818 +static FILE *xfopen(const char *path, const char *mode)
820 - fprintf(stderr, "%s: ", argv0);
824 + if ((fp = fopen(path, mode)) == NULL)
825 + perror_msg_and_die("%s", path);
829 +static char *xstrdup(const char *s)
837 + error_msg_and_die(memory_exhausted);
841 +extern void *xrealloc(void *ptr, size_t size)
843 + ptr = realloc(ptr, size);
844 + if (ptr == NULL && size != 0)
845 + error_msg_and_die(memory_exhausted);
849 +static char *xreadlink(const char *path)
851 + static const int GROWBY = 80; /* how large we will grow strings by */
854 + int bufsize = 0, readsize = 0;
857 + buf = xrealloc(buf, bufsize += GROWBY);
858 + readsize = readlink(path, buf, bufsize); /* 1st try */
859 + if (readsize == -1) {
860 + perror_msg_and_die("%s:%s", app_name, path);
863 + while (bufsize < readsize + 1);
865 + buf[readsize] = '\0';
870 // printf helper macro
875 -// rounds a quantity up to a blocksize
876 +/* Rounds qty upto a multiple of siz. siz should be a power of 2 */
877 uint32 rndup(uint32 qty, uint32 siz)
879 return (qty + (siz - 1)) & ~(siz - 1);
881 // return a given inode from a filesystem
882 inline inode * get_nod(filesystem *fs, uint32 nod)
884 - return &fs->itab[nod-1];
888 + offset = GRP_IBM_OFFSET(fs,nod);
889 + grp = GRP_GROUP_OF_INODE(fs,nod);
890 + itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
891 + return itab+offset-1;
894 // allocate a given block/inode in the bitmap
895 @@ -479,29 +646,57 @@
899 -uint32 alloc_blk(filesystem *fs)
900 +uint32 alloc_blk(filesystem *fs, uint32 nod)
903 - if(!(bk = allocate(fs->bbm, 0)))
904 - errexit("couldn't allocate a block (no free space)");
905 - if(!(fs->gd.bg_free_blocks_count--))
906 - errexit("group descr. free blocks count == 0 (corrupted fs?)");
908 + uint32 grp,nbgroups;
910 + grp = nod/fs->sb.s_inodes_per_group;
911 + nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
912 + fs->sb.s_blocks_per_group;
913 + if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
914 + for(grp=0;grp<nbgroups && !bk;grp++)
915 + bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
919 + error_msg_and_die("couldn't allocate a block (no free space)");
920 + if(!(fs->gd[grp].bg_free_blocks_count--))
921 + error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
922 if(!(fs->sb.s_free_blocks_count--))
923 - errexit("superblock free blocks count == 0 (corrupted fs?)");
925 + error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
926 + return fs->sb.s_blocks_per_group*grp + bk;
930 uint32 alloc_nod(filesystem *fs)
933 - if(!(nod = allocate(fs->ibm, 0)))
934 - errexit("couldn't allocate an inode (no free inode)");
935 - if(!(fs->gd.bg_free_inodes_count--))
936 - errexit("group descr. free blocks count == 0 (corrupted fs?)");
937 + uint32 nod=0,best_group=0;
938 + uint32 grp,nbgroups,avefreei;
940 + nbgroups = ( fs->sb.s_blocks_count - fs->sb.s_first_data_block + fs->sb.s_blocks_per_group -1 ) /
941 + fs->sb.s_blocks_per_group;
943 + /* Distribute inodes amongst all the blocks */
944 + /* For every block group with more than average number of free inodes */
945 + /* find the one with the most free blocks and allocate node there */
946 + /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
947 + /* We do it for all inodes. */
948 + avefreei = fs->sb.s_free_inodes_count / nbgroups;
949 + for(grp=0;grp<nbgroups && !nod;grp++) {
950 + if (fs->gd[grp].bg_free_inodes_count < avefreei)
953 + fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
956 + if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
957 + error_msg_and_die("couldn't allocate an inode (no free inode)");
958 + if(!(fs->gd[best_group].bg_free_inodes_count--))
959 + error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
960 if(!(fs->sb.s_free_inodes_count--))
961 - errexit("superblock free blocks count == 0 (corrupted fs?)");
963 + error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
964 + return fs->sb.s_inodes_per_group*best_group+nod;
967 // print a bitmap allocation
968 @@ -546,14 +741,14 @@
970 bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
971 if(extend) // allocate first block
972 - *bkref = hole ? 0 : alloc_blk(fs);
973 + *bkref = hole ? 0 : alloc_blk(fs,nod);
976 else if(bw->bpdir < EXT2_NDIR_BLOCKS)
978 bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
979 if(extend) // allocate block
980 - *bkref = hole ? 0 : alloc_blk(fs);
981 + *bkref = hole ? 0 : alloc_blk(fs,nod);
983 // first block in indirect block
984 else if(bw->bpdir == EXT2_NDIR_BLOCKS)
985 @@ -562,11 +757,11 @@
986 bw->bpdir = EXT2_IND_BLOCK;
988 if(extend) // allocate indirect block
989 - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
990 + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
991 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
992 bkref = &b[bw->bpind];
993 if(extend) // allocate first block
994 - *bkref = hole ? 0 : alloc_blk(fs);
995 + *bkref = hole ? 0 : alloc_blk(fs,nod);
997 // block in indirect block
998 else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
1000 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1001 bkref = &b[bw->bpind];
1002 if(extend) // allocate block
1003 - *bkref = hole ? 0 : alloc_blk(fs);
1004 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1006 // first block in first indirect block in first double indirect block
1007 else if(bw->bpdir == EXT2_IND_BLOCK)
1008 @@ -585,14 +780,14 @@
1011 if(extend) // allocate double indirect block
1012 - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs);
1013 + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1014 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1015 if(extend) // allocate first indirect block
1016 - b[bw->bpind] = alloc_blk(fs);
1017 + b[bw->bpind] = alloc_blk(fs,nod);
1018 b = (uint32*)get_blk(fs, b[bw->bpind]);
1019 bkref = &b[bw->bpdind];
1020 if(extend) // allocate first block
1021 - *bkref = hole ? 0 : alloc_blk(fs);
1022 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1024 // block in indirect block in double indirect block
1025 else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
1027 b = (uint32*)get_blk(fs, b[bw->bpind]);
1028 bkref = &b[bw->bpdind];
1029 if(extend) // allocate block
1030 - *bkref = hole ? 0 : alloc_blk(fs);
1031 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1033 // first block in indirect block in double indirect block
1034 else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
1035 @@ -612,20 +807,100 @@
1037 b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1038 if(extend) // allocate indirect block
1039 - b[bw->bpind] = alloc_blk(fs);
1040 + b[bw->bpind] = alloc_blk(fs,nod);
1041 b = (uint32*)get_blk(fs, b[bw->bpind]);
1042 bkref = &b[bw->bpdind];
1043 if(extend) // allocate first block
1044 - *bkref = hole ? 0 : alloc_blk(fs);
1045 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1048 + /* Adding support for triple indirection */
1049 + /* Just starting triple indirection. Allocate the indirection
1050 + blocks and the first data block
1052 + else if (bw->bpdir == EXT2_DIND_BLOCK)
1055 + bw->bpdir = EXT2_TIND_BLOCK;
1059 + if(extend) // allocate triple indirect block
1060 + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
1061 + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1062 + if(extend) // allocate first double indirect block
1063 + b[bw->bpind] = alloc_blk(fs,nod);
1064 + b = (uint32*)get_blk(fs, b[bw->bpind]);
1065 + if(extend) // allocate first indirect block
1066 + b[bw->bpdind] = alloc_blk(fs,nod);
1067 + b = (uint32*)get_blk(fs, b[bw->bpdind]);
1068 + bkref = &b[bw->bptind];
1069 + if(extend) // allocate first data block
1070 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1072 + /* Still processing a single indirect block down the indirection
1073 + chain.Allocate a data block for it
1075 + else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
1076 + (bw->bptind < BLOCKSIZE/4 -1) )
1079 + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1080 + b = (uint32*)get_blk(fs, b[bw->bpind]);
1081 + b = (uint32*)get_blk(fs, b[bw->bpdind]);
1082 + bkref = &b[bw->bptind];
1083 + if(extend) // allocate data block
1084 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1086 + /* Finished processing a single indirect block. But still in the
1087 + same double indirect block. Allocate new single indirect block
1088 + for it and a data block
1090 + else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
1091 + (bw->bpdind < BLOCKSIZE/4 -1) )
1096 + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1097 + b = (uint32*)get_blk(fs, b[bw->bpind]);
1098 + if (extend) // allocate single indirect block
1099 + b[bw->bpdind] = alloc_blk(fs,nod);
1100 + b = (uint32*)get_blk(fs, b[bw->bpdind]);
1101 + bkref = &b[bw->bptind];
1102 + if(extend) // allocate first data block
1103 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1105 + /* Finished processing a double indirect block. Allocate the next
1106 + double indirect block and the single,data blocks for it
1108 + else if ( (bw->bpdir == EXT2_TIND_BLOCK) &&
1109 + (bw->bpind < BLOCKSIZE/4 - 1) )
1115 + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
1116 + if(extend) // allocate double indirect block
1117 + b[bw->bpind] = alloc_blk(fs,nod);
1118 + b = (uint32*)get_blk(fs, b[bw->bpind]);
1119 + if(extend) // allocate single indirect block
1120 + b[bw->bpdind] = alloc_blk(fs,nod);
1121 + b = (uint32*)get_blk(fs, b[bw->bpdind]);
1122 + bkref = &b[bw->bptind];
1123 + if(extend) // allocate first block
1124 + *bkref = hole ? 0 : alloc_blk(fs,nod);
1126 - // I don't do triple indirect - it's such a small filesystem ...
1128 - errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod);
1129 + error_msg_and_die("file too big !");
1130 + /* End change for walking triple indirection */
1135 - if(!allocated(fs->bbm, *bkref))
1136 - errexit("[block %d of inode %d is unallocated !]", *bkref, nod);
1137 + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
1138 + error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
1141 get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
1142 @@ -663,23 +938,40 @@
1145 // link an entry (inode #) to a directory
1146 -void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
1147 +void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name, uint32 mode, uid_t uid, gid_t gid, time_t ctime)
1154 - if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR)
1155 - errexit("can't add '%s' to a non-directory", name);
1159 + /* Squash all permissions so files are owned by root
1160 + * and file permissions have group/other perms removed */
1161 + if (squash_uids) {
1164 + if (squash_perms) {
1165 + if (!S_ISLNK(mode)) {
1166 + mode &= ~(S_IWGRP | S_IWOTH);
1167 + mode &= ~(S_ISUID | S_ISGID);
1171 + pnode = get_nod(fs, dnod);
1173 + if(!S_ISDIR(pnode->i_mode))
1174 + error_msg_and_die("can't add '%s' to a non-directory", name);
1176 - errexit("bad name '%s' (not meaningful)", name);
1177 + error_msg_and_die("bad name '%s' (not meaningful)", name);
1178 if(strchr(name, '/'))
1179 - errexit("bad name '%s' (contains a slash)", name);
1180 + error_msg_and_die("bad name '%s' (contains a slash)", name);
1181 nlen = strlen(name);
1182 reclen = sizeof(directory) + rndup(nlen, 4);
1183 if(reclen > BLOCKSIZE)
1184 - errexit("bad name '%s' (too long)", name);
1185 + error_msg_and_die("bad name '%s' (too long)", name);
1186 init_bw(fs, dnod, &bw);
1187 while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
1189 @@ -691,9 +983,16 @@
1190 if((!d->d_inode) && (d->d_rec_len >= reclen))
1193 - get_nod(fs, nod)->i_links_count++;
1194 + node = get_nod(fs, nod);
1195 + node->i_links_count++;
1196 d->d_name_len = nlen;
1197 - strncpy(d->d_name, name, nlen);
1198 + strncpy(d->d_name, name, rndup(nlen,4));
1199 + node->i_mode = mode;
1200 + node->i_uid = uid;
1201 + node->i_gid = gid;
1202 + node->i_atime = ctime;
1203 + node->i_ctime = ctime;
1204 + node->i_mtime = ctime;
1207 // if entry with enough room (last one?), shrink it & use it
1208 @@ -705,9 +1004,16 @@
1209 d = (directory*) (((int8*)d) + d->d_rec_len);
1210 d->d_rec_len = reclen;
1212 - get_nod(fs, nod)->i_links_count++;
1213 + node = get_nod(fs, nod);
1214 + node->i_links_count++;
1215 d->d_name_len = nlen;
1216 - strncpy(d->d_name, name, nlen);
1217 + strncpy(d->d_name, name, rndup(nlen,4));
1218 + node->i_mode = mode;
1219 + node->i_uid = uid;
1220 + node->i_gid = gid;
1221 + node->i_atime = ctime;
1222 + node->i_ctime = ctime;
1223 + node->i_mtime = ctime;
1227 @@ -716,10 +1022,17 @@
1231 - get_nod(fs, nod)->i_links_count++;
1232 + node = get_nod(fs, nod);
1233 + node->i_links_count++;
1234 d->d_rec_len = BLOCKSIZE;
1235 d->d_name_len = nlen;
1236 - strncpy(d->d_name, name, nlen);
1237 + strncpy(d->d_name, name, rndup(nlen,4));
1238 + node->i_mode = mode;
1239 + node->i_uid = uid;
1240 + node->i_gid = gid;
1241 + node->i_atime = ctime;
1242 + node->i_ctime = ctime;
1243 + node->i_mtime = ctime;
1244 extend_blk(fs, dnod, b, 1);
1245 get_nod(fs, dnod)->i_size += BLOCKSIZE;
1247 @@ -747,7 +1060,7 @@
1248 // find the inode of a full path
1249 uint32 find_path(filesystem *fs, uint32 nod, const char * name)
1251 - char *p, *n, *n2 = strdup(name);
1252 + char *p, *n, *n2 = xstrdup(name);
1256 @@ -770,27 +1083,32 @@
1259 // make a full-fledged directory (i.e. with "." & "..")
1260 -uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode)
1261 +uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode,
1262 + uid_t uid, gid_t gid, time_t ctime)
1265 if((nod = find_dir(fs, parent_nod, name)))
1267 nod = alloc_nod(fs);
1268 - get_nod(fs, nod)->i_mode = FM_IFDIR | mode;
1269 - add2dir(fs, parent_nod, nod, name);
1270 - add2dir(fs, nod, nod, ".");
1271 - add2dir(fs, nod, parent_nod, "..");
1272 - fs->gd.bg_used_dirs_count++;
1273 + if (!(mode & FM_IFDIR))
1275 + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1276 + add2dir(fs, nod, nod, ".", mode, uid, gid, ctime);
1277 + add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime);
1278 + fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
1283 -uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b)
1284 +uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size,
1285 + uint8 * b, uid_t uid, gid_t gid, time_t ctime)
1288 uint32 nod = alloc_nod(fs);
1289 + mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1290 get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1291 get_nod(fs, nod)->i_size = size;
1292 - add2dir(fs, parent_nod, nod, name);
1293 + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1294 if(size <= 4 * (EXT2_TIND_BLOCK+1))
1296 strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
1297 @@ -801,15 +1119,15 @@
1300 // make a file from a FILE*
1301 -uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f)
1302 +uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, time_t ctime)
1305 uint32 nod = alloc_nod(fs);
1306 - get_nod(fs, nod)->i_mode = FM_IFREG | mode;
1308 get_nod(fs, nod)->i_size = size;
1309 - add2dir(fs, parent_nod, nod, name);
1310 + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime);
1311 if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE))))
1312 - errexit("not enough mem to read file '%s'", name);
1313 + error_msg_and_die("not enough mem to read file '%s'", name);
1314 memset(b, 0,rndup(size, BLOCKSIZE));
1316 fread(b, size, 1, f);
1317 @@ -824,6 +1142,15 @@
1318 uint32 get_mode(struct stat *st)
1322 + /* Squash file permissions as needed */
1323 + if (squash_perms) {
1324 + if (!S_ISLNK(mode)) {
1325 + st->st_mode &= ~(S_IWGRP | S_IWOTH);
1326 + st->st_mode &= ~(S_ISUID | S_ISGID);
1330 if(st->st_mode & S_IRUSR)
1331 mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
1332 if(st->st_mode & S_IWUSR)
1333 @@ -833,30 +1160,17 @@
1337 -// retrieves a mode info from a string
1338 -uint32 get_modestr(const char *p)
1342 - mode |= FM_IRUSR | FM_IRGRP | FM_IROTH;
1344 - mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH;
1345 - if(p[2] == 'x' || p[2] == 's')
1346 - mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH;
1350 // basename of a path - free me
1351 char * basename(const char * fullpath)
1353 char * p = strrchr(fullpath, '/');
1354 - return strdup(p ? p + 1 : fullpath);
1355 + return xstrdup(p ? p + 1 : fullpath);
1358 // dirname of a path - free me
1359 char * dirname(const char * fullpath)
1361 - char * p, * n = strdup(fullpath);
1362 + char * p, * n = xstrdup(fullpath);
1363 if((p = strrchr(n, '/')))
1366 @@ -864,66 +1178,6 @@
1370 -// adds entries to the filesystem from a text file
1371 -void add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh)
1375 - char cmod[11], *path, *name, *dir;
1377 - while(fscanf(fh, "%10s", cmod))
1381 - mode = get_modestr(cmod + 1);
1385 - fscanf(fh, "%" SCANF_PREFIX "s\n", SCANF_STRING(path));
1389 - fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
1393 - fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path));
1396 - while(fgetc(fh) != '\n');
1399 - errexit("malformed text input file");
1401 - name = basename(path);
1402 - dir = dirname(path);
1404 - if(!(nod = find_path(fs, this_nod, dir)))
1405 - errexit("can't find directory '%s' to create '%s''", dir, name);
1407 - if((!strcmp(name, ".")) || (!strcmp(name, "..")))
1415 - mkdir_fs(fs, nod, name, mode);
1419 - nod2 = alloc_nod(fs);
1420 - get_nod(fs, nod2)->i_mode = mode;
1421 - ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor;
1422 - ((uint8*)get_nod(fs, nod2)->i_block)[1] = major;
1423 - add2dir(fs, nod, nod2, name);
1430 // adds a tree of entries to the filesystem from current dir
1431 void add2fs_from_dir(filesystem *fs, uint32 this_nod)
1433 @@ -934,7 +1188,7 @@
1436 if(!(dh = opendir(".")))
1438 + perror_msg_and_die(".");
1439 while((dent = readdir(dh)))
1441 if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
1442 @@ -948,31 +1202,27 @@
1443 get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st);
1444 ((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff);
1445 ((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8);
1446 - add2dir(fs, this_nod, nod, dent->d_name);
1447 + add2dir(fs, this_nod, nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
1450 - if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE))))
1451 - errexit("out of memory");
1452 - if(readlink(dent->d_name, (char*)b, st.st_size) < 0)
1453 - pexit(dent->d_name);
1454 - mklink_fs(fs, this_nod, dent->d_name, st.st_size, b);
1455 + b = xreadlink(dent->d_name);
1456 + mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime);
1460 - if(!(fh = fopen(dent->d_name, "r")))
1461 - pexit(dent->d_name);
1462 - mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh);
1463 + fh = xfopen(dent->d_name, "r");
1464 + mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime);
1468 - nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st));
1469 + nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime);
1470 if(chdir(dent->d_name) < 0)
1471 - pexit(dent->d_name);
1472 + perror_msg_and_die(dent->d_name);
1473 add2fs_from_dir(fs, nod);
1477 - fprintf(stderr, "ignoring entry %s", dent->d_name);
1478 + error_msg("ignoring entry %s", dent->d_name);
1482 @@ -981,9 +1231,11 @@
1483 // endianness swap of x-indirect blocks
1484 void swap_goodblocks(filesystem *fs, inode *nod)
1490 int nblk = nod->i_blocks / INOBLK;
1491 - if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
1492 + if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1493 for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1494 nod->i_block[i] = swab32(nod->i_block[i]);
1495 if(nblk <= EXT2_IND_BLOCK)
1496 @@ -991,20 +1243,55 @@
1497 swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1498 if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
1500 + /* Currently this will fail b'cos the number of blocks as stored
1501 + in i_blocks also includes the indirection blocks (see
1502 + walk_bw). But this function assumes that i_blocks only
1503 + stores the count of data blocks ( Actually according to
1504 + "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
1505 + i_blocks IS supposed to store the count of data blocks). so
1506 + with a file of size 268K nblk would be 269.The above check
1507 + will be false even though double indirection hasn't been
1508 + started.This is benign as 0 means block 0 which has been
1509 + zeroed out and therefore points back to itself from any offset
1511 + assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1512 for(i = 0; i < BLOCKSIZE/4; i++)
1513 + /* Should this be...
1514 + if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
1516 if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
1517 swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1518 swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1519 if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1521 - errexit("too big file on the filesystem");
1522 + /* Adding support for triple indirection */
1523 + b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1524 + for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1525 + b2 = (uint32*)get_blk(fs,b[i]);
1526 + for(j=0; j<BLOCKSIZE/4;j++) {
1527 + if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
1528 + (BLOCKSIZE/4)*(BLOCKSIZE/4) +
1529 + i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
1530 + j*(BLOCKSIZE/4)) )
1531 + swap_block(get_blk(fs,b2[j]));
1537 + swap_block((uint8 *)b2);
1539 + swap_block((uint8 *)b);
1543 void swap_badblocks(filesystem *fs, inode *nod)
1549 int nblk = nod->i_blocks / INOBLK;
1550 - if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR)))
1551 + if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
1552 for(i = 0; i <= EXT2_TIND_BLOCK; i++)
1553 nod->i_block[i] = swab32(nod->i_block[i]);
1554 if(nblk <= EXT2_IND_BLOCK)
1555 @@ -1012,13 +1299,34 @@
1556 swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
1557 if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4)
1559 + /* See comment in swap_goodblocks */
1560 + assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
1561 swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
1562 for(i = 0; i < BLOCKSIZE/4; i++)
1563 + /* See comment in swap_goodblocks */
1564 if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i)
1565 swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
1566 if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
1568 - errexit("too big file on the filesystem");
1569 + /* Adding support for triple indirection */
1570 + b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
1571 + swap_block((uint8 *)b);
1572 + for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
1573 + b2 = (uint32*)get_blk(fs,b[i]);
1574 + swap_block((uint8 *)b2);
1575 + for(j=0; j<BLOCKSIZE/4;j++) {
1576 + if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
1577 + (BLOCKSIZE/4)*(BLOCKSIZE/4) +
1578 + i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
1579 + j*(BLOCKSIZE/4)) )
1580 + swap_block(get_blk(fs,b2[j]));
1590 // endianness swap of the whole filesystem
1591 @@ -1045,7 +1353,8 @@
1592 swap_goodblocks(fs, nod);
1596 + for(i=0;i<GRP_NBGROUPS(fs);i++)
1597 + swap_gd(&(fs->gd[i]));
1601 @@ -1053,7 +1362,8 @@
1606 + for(i=0;i<GRP_NBGROUPS(fs);i++)
1607 + swap_gd(&(fs->gd[i]));
1608 for(i = 1; i < fs->sb.s_inodes_count; i++)
1610 inode *nod = get_nod(fs, i);
1611 @@ -1084,53 +1394,118 @@
1615 + uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
1616 + free_blocks_per_group,nbblocks_per_group;
1617 + uint32 gd,itbl,ibmpos,bbmpos,itblpos;
1622 if(nbblocks < 16) // totally arbitrary
1623 - errexit("too small filesystem");
1624 - if(nbblocks >BLOCKS_PER_GROUP) // I build only one group
1625 - errexit("too big filesystem");
1626 + error_msg_and_die("too small filesystem");
1628 + /* nbblocks is the total number of blocks in the system. First
1629 + * calculate how much overhead blocks - inode table blocks,bitmap
1630 + * blocks,group descriptor blocks etc. - are needed assuming each
1631 + * group has BLOCKS_PER_GROUP blocks.Then recalculate nbblocks with
1632 + * this figure. Each group has the same number of blocks. So the fs
1633 + * has a size atleast the given value but usually rounded off to a i
1636 + nbgroups = rndup(nbblocks,BLOCKS_PER_GROUP)/ BLOCKS_PER_GROUP;
1637 + nbinodes_per_group = nbinodes/nbgroups +1;
1638 + nbinodes_per_group = rndup(nbinodes_per_group, BLOCKSIZE/sizeof(inode));
1639 + if (nbinodes_per_group < 16)
1640 + nbinodes_per_group = 16; //minimum number b'cos the first 10 are reserved
1641 + overhead_per_group = 3 /*super block,ibm,bbm*/
1642 + + /* No. of blocks that the inodes occupy */
1643 + nbinodes_per_group *sizeof(inode)/BLOCKSIZE
1644 + + /* No. of blocks that group descriptors occupy */
1645 + rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
1646 + free_blocks = nbblocks - overhead_per_group * nbgroups - 1 /*boot block */;
1647 + free_blocks_per_group = free_blocks/nbgroups;
1648 + if (free_blocks > free_blocks_per_group * nbgroups)
1649 + free_blocks_per_group++;
1650 + nbblocks_per_group = free_blocks_per_group + overhead_per_group;
1651 + /* e2fsck complains if nbblocks_per_group is not a multiple of 8 */
1652 + nbblocks_per_group = rndup(nbblocks_per_group,8);
1653 + free_blocks_per_group = nbblocks_per_group - overhead_per_group;
1654 + if (nbblocks_per_group > BLOCKS_PER_GROUP) {
1655 + /* Can this happen ? */
1656 + nbblocks_per_group = BLOCKS_PER_GROUP;
1657 + free_blocks_per_group = nbblocks_per_group - overhead_per_group;
1659 + nbblocks = nbblocks_per_group * nbgroups + 1;
1662 if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
1663 - errexit("not enough memory for filesystem");
1664 + error_msg_and_die("not enough memory for filesystem");
1666 // create the superblock for an empty filesystem
1667 - fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode));
1668 + fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
1669 fs->sb.s_blocks_count = nbblocks;
1670 fs->sb.s_r_blocks_count = nbresrvd;
1671 - fs->sb.s_free_blocks_count = nbblocks;
1672 + fs->sb.s_free_blocks_count = free_blocks_per_group*nbgroups;
1673 fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
1674 fs->sb.s_first_data_block = (BLOCKSIZE == 1024);
1675 fs->sb.s_log_block_size = BLOCKSIZE >> 11;
1676 fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
1677 - fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP;
1678 - fs->sb.s_frags_per_group = BLOCKS_PER_GROUP;
1679 - fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
1680 + fs->sb.s_blocks_per_group = nbblocks_per_group;
1681 + fs->sb.s_frags_per_group = nbblocks_per_group;
1682 + fs->sb.s_inodes_per_group = nbinodes_per_group;
1683 fs->sb.s_magic = EXT2_MAGIC_NUMBER;
1685 // set up groupdescriptors
1686 - fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE;
1687 - fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count;
1688 - fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count;
1689 - fs->gd.bg_used_dirs_count = 1;
1690 - fs->gd.bg_block_bitmap = 3;
1691 - fs->gd.bg_inode_bitmap = 4;
1692 - fs->gd.bg_inode_table = 5;
1694 - // mark non-filesystem blocks and inodes as allocated
1695 - for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++)
1696 - allocate(fs->bbm, i);
1697 - for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++)
1698 - allocate(fs->ibm, i);
1700 - // mark system blocsk and inodes as allocated
1701 - for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++)
1702 - allocate(fs->bbm, i);
1703 - for(i = 1; i < EXT2_FIRST_INO; i++)
1704 - allocate(fs->ibm, i);
1706 - // make root inode and directory
1707 - fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1708 - fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
1709 - fs->itab[EXT2_ROOT_INO-1].i_links_count = 2;
1710 + gd = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
1711 + itbl = nbinodes_per_group*sizeof(inode)/BLOCKSIZE;
1712 + for(i = 0,bbmpos=2+gd,ibmpos=3+gd,itblpos =4+gd;
1714 + i++, bbmpos += nbblocks_per_group,ibmpos += nbblocks_per_group,
1715 + itblpos += nbblocks_per_group) {
1717 + fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
1718 + fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
1719 + fs->gd[i].bg_used_dirs_count = 0;
1720 + fs->gd[i].bg_block_bitmap = bbmpos;
1721 + fs->gd[i].bg_inode_bitmap = ibmpos;
1722 + fs->gd[i].bg_inode_table = itblpos;
1725 + /* Mark non-filesystem blocks and inodes as allocated */
1726 + /* Mark system blocks and inodes as allocated */
1727 + for(i = 0; i<nbgroups;i++) {
1729 + /* Block bitmap */
1730 + bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
1731 + //non-filesystem blocks.
1732 + for(j=fs->sb.s_blocks_per_group + 1; j <= BLOCKSIZE * 8; j++)
1735 + for(j = 1; j <= 3+gd+itbl; j++)
1738 + /* Inode bitmap */
1739 + ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
1740 + //non-filesystem inodes
1741 + for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
1745 + /* We have groups now. Add the root filesystem in group 0 */
1746 + /* Also allocate the system inodes in group 0 and update */
1747 + /* directory count and inode count for group 0 */
1749 + ibm = get_blk(fs,fs->gd[0].bg_inode_bitmap);
1750 + for(j = 1; j < EXT2_FIRST_INO; j++) {
1752 + fs->gd[0].bg_free_inodes_count--;
1754 + fs->gd[0].bg_used_dirs_count = 1;
1755 + itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
1756 + itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO;
1757 + itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
1758 + itab0[EXT2_ROOT_INO-1].i_links_count = 2;
1762 d->d_inode = EXT2_ROOT_INO;
1763 @@ -1147,9 +1522,14 @@
1764 // make lost+found directory and reserve blocks
1765 if(fs->sb.s_r_blocks_count)
1767 - nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU | FM_IRWXG | FM_IRWXO);
1768 + nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL));
1769 memset(b, 0, BLOCKSIZE);
1770 ((directory*)b)->d_rec_len = BLOCKSIZE;
1771 + /* We run into problems with e2fsck if directory lost+found grows
1772 + * bigger than this. Need to find out why this happens - sundar
1774 + if (fs->sb.s_r_blocks_count > 2049 )
1775 + fs->sb.s_r_blocks_count=2049;
1776 for(i = 1; i < fs->sb.s_r_blocks_count; i++)
1777 extend_blk(fs, nod, b, 1);
1778 get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
1779 @@ -1170,24 +1550,24 @@
1780 // loads a filesystem from disk
1781 filesystem * load_fs(FILE * fh, int swapit)
1784 + size_t fssize = 0;
1786 if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0))
1787 - pexit("input filesystem image");
1788 + perror_msg_and_die("input filesystem image");
1790 fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
1791 if(fssize < 16) // totally arbitrary
1792 - errexit("too small filesystem");
1793 - if(fssize > BLOCKS_PER_GROUP) // I build only one group
1794 - errexit("too big filesystem");
1795 + error_msg_and_die("too small filesystem");
1796 +/* if(fssize > BLOCKS_PER_GROUP) // I build only one group
1797 + error_msg_and_die("too big filesystem"); */
1798 if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
1799 - errexit("not enough memory for filesystem");
1800 + error_msg_and_die("not enough memory for filesystem");
1801 if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
1802 - pexit("input filesystem image");
1803 + perror_msg_and_die("input filesystem image");
1806 if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
1807 - errexit("not a suitable ext2 filesystem");
1808 + error_msg_and_die("not a suitable ext2 filesystem");
1812 @@ -1230,9 +1610,9 @@
1813 while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
1816 - errexit("wrong size while saving inode %d", nod);
1817 + error_msg_and_die("wrong size while saving inode %d", nod);
1818 if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
1819 - errexit("error while saving inode %d", nod);
1820 + error_msg_and_die("error while saving inode %d", nod);
1824 @@ -1250,7 +1630,7 @@
1828 - errexit("wrong size while saving inode %d", nod);
1829 + error_msg_and_die("wrong size while saving inode %d", nod);
1830 b = get_blk(fs, bk);
1831 for(i = 0; i < 64; i++)
1833 @@ -1406,7 +1786,7 @@
1834 s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
1836 printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
1837 - if(!allocated(fs->ibm, nod))
1838 + if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
1840 printf("unallocated\n");
1842 @@ -1440,24 +1820,46 @@
1844 list_blocks(fs, nod);
1846 + printf("Done with inode %d\n",nod);
1849 // describes various fields in a filesystem
1850 void print_fs(filesystem *fs)
1853 - printf("%d blocks (%d free, %d reserved), first data block: %d\n", fs->sb.s_blocks_count, fs->sb.s_free_blocks_count, fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
1854 - printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count);
1855 - printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
1856 - printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group);
1857 - printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table);
1858 - printf("block bitmap allocation:\n");
1859 - print_bm(fs->bbm, fs->sb.s_blocks_count);
1860 - printf("inode bitmap allocation:\n");
1861 - print_bm(fs->ibm, fs->sb.s_inodes_count);
1862 - for(i=1; i<=fs->sb.s_inodes_count; i++)
1863 - if(allocated(fs->ibm, i))
1864 - print_inode(fs, i);
1868 + printf("%d blocks (%d free, %d reserved), first data block: %d\n",
1869 + fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
1870 + fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
1871 + printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
1872 + fs->sb.s_free_inodes_count);
1873 + printf("block size = %d, frag size = %d\n",
1874 + fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
1875 + fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
1876 + printf("Number of groups: %d\n",GRP_NBGROUPS(fs));
1877 + printf("%d blocks per group,%d frags per group,%d inodes per group\n",
1878 + fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
1879 + fs->sb.s_inodes_per_group);
1880 + printf("Size of inode table: %d blocks\n",
1881 + fs->sb.s_inodes_per_group * sizeof(inode)/BLOCKSIZE);
1882 + for (i = 0; i < GRP_NBGROUPS(fs); i++) {
1883 + printf("Group No: %d\n", i);
1884 + printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
1885 + fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
1886 + fs->gd[i].bg_inode_table);
1887 + printf("Free blocks count: %d\n",fs->gd[i].bg_free_blocks_count);
1888 + printf("Free inodes count: %d\n",fs->gd[i].bg_free_inodes_count);
1889 + printf("Used dir count: %d\n",fs->gd[i].bg_used_dirs_count);
1890 + printf("block bitmap allocation:\n");
1891 + print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
1892 + printf("inode bitmap allocation:\n");
1893 + ibm = GRP_GET_GROUP_IBM(fs, i);
1894 + print_bm(ibm, fs->sb.s_inodes_per_group);
1895 + for (j = 1; j <= fs->sb.s_inodes_per_group; j++)
1896 + if (allocated(ibm, j))
1897 + print_inode(fs, i*fs->sb.s_inodes_per_group + j);
1901 void dump_fs(filesystem *fs, FILE * fh, int swapit)
1902 @@ -1467,31 +1869,234 @@
1905 if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
1906 - pexit("output filesystem image");
1907 + perror_msg_and_die("output filesystem image");
1912 +/* device table entries take the form of:
1913 + <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
1914 + /dev/mem c 640 0 0 1 1 0 0 -
1916 + type can be one of:
1919 + c Character special device file
1920 + b Block special device file
1921 + p Fifo (named pipe)
1923 + I don't bother with symlinks (permissions are irrelevant), hard
1924 + links (special cases of regular files), or sockets (why bother).
1926 + Regular files must exist in the target root directory. If a char,
1927 + block, fifo, or directory does not exist, it will be created.
1929 +static int interpret_table_entry(filesystem *fs, char *line)
1931 + char type, *name = NULL, *tmp, *dir, *bname;
1932 + unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
1933 + unsigned long start = 0, increment = 1, count = 0;
1935 + uint32 nod, parent;
1937 + if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
1938 + SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
1939 + &start, &increment, &count) < 0)
1944 + if (!strcmp(name, "/")) {
1945 + error_msg_and_die("Device table entries require absolute paths");
1948 + /* Check if this file already exists... */
1966 + error_msg_and_die("Unsupported file type");
1970 + nod = find_path(fs, EXT2_ROOT_INO, name);
1972 + /* Ok, we just need to fixup an existing entry
1973 + * and we will be all done... */
1974 + entry = get_nod(fs, nod);
1975 + entry->i_uid = uid;
1976 + entry->i_gid = gid;
1977 + entry->i_mode = mode;
1979 + dev_t rdev = makedev(major, minor);
1980 + ((uint8*)entry->i_block)[0] = (rdev & 0xff);
1981 + ((uint8*)entry->i_block)[1] = (rdev >> 8);
1984 + /* Try and find our parent now */
1985 + tmp = xstrdup(name);
1986 + dir = dirname(tmp);
1987 + parent = find_path(fs, EXT2_ROOT_INO, dir);
1990 + error_msg ("skipping device_table entry '%s': no parent directory!", name);
1995 + tmp = xstrdup(name);
1996 + bname = xstrdup(basename(tmp));
2000 + mkdir_fs(fs, parent, bname, mode|FM_IFDIR, uid, gid, time(NULL));
2005 + // This is a bit odd.. This will try to include
2006 + // the file of the same name from your _build_
2007 + // system... Probably a very bad idea....
2009 + FILE *fh = xfopen(name, "r");
2011 + mkfile_fs(fs, parent, bname, mode|FM_IFREG, st.st_size, fh, uid, gid, st.st_ctime);
2015 + error_msg("ignoring entry %s", name);
2019 + error_msg("ignoring entry %s", name);
2027 + for (i = start; i < count; i++) {
2028 + asprintf(&dname, "%s%lu", bname, i);
2029 + nod = find_path(fs, EXT2_ROOT_INO, dname);
2031 + /* We just need to fixup an existing entry */
2032 + entry = get_nod(fs, nod);
2034 + nod = alloc_nod(fs);
2035 + add2dir(fs, parent, nod, dname, mode, uid, gid, time(NULL));
2036 + entry = get_nod(fs, nod);
2038 + entry->i_uid = uid;
2039 + entry->i_gid = gid;
2040 + entry->i_mode = mode;
2041 + rdev = makedev(major, minor + (i * increment - start));
2042 + ((uint8*)entry->i_block)[0] = (rdev & 0xff);
2043 + ((uint8*)entry->i_block)[1] = (rdev >> 8);
2047 + dev_t rdev = makedev(major, minor);
2048 + nod = alloc_nod(fs);
2049 + add2dir(fs, parent, nod, bname, mode, uid, gid, time(NULL));
2050 + entry = get_nod(fs, nod);
2051 + ((uint8*)entry->i_block)[0] = (rdev & 0xff);
2052 + ((uint8*)entry->i_block)[1] = (rdev >> 8);
2056 + error_msg_and_die("Unsupported file type");
2064 +static int parse_device_table(filesystem *root, FILE * file)
2068 + size_t length = 0;
2070 + /* Turn off squash, since we must ensure that values
2071 + * entered via the device table are not squashed */
2075 + /* Looks ok so far. The general plan now is to read in one
2076 + * line at a time, check for leading comment delimiters ('#'),
2077 + * then try and parse the line as a device table. If we fail
2078 + * to parse things, try and help the poor fool to fix their
2079 + * device table with a useful error msg... */
2081 + while (getline(&line, &length, file) != -1) {
2082 + /* First trim off any whitespace */
2083 + int len = strlen(line);
2085 + /* trim trailing whitespace */
2086 + while (len > 0 && isspace(line[len - 1]))
2087 + line[--len] = '\0';
2088 + /* trim leading whitespace */
2089 + memmove(line, &line[strspn(line, " \n\r\t\v")], len);
2091 + /* How long are we after trimming? */
2092 + len = strlen(line);
2094 + /* If this is NOT a comment line, try to interpret it */
2095 + if (len && *line != '#') {
2096 + if (interpret_table_entry(root, line))
2110 +c-file-style: "linux"
2118 fprintf(stderr, "Usage: %s [options] image\n"
2119 "Create an ext2 filesystem image from directories/files\n\n"
2120 - " -x image Use this image as a starting point\n"
2121 - " -d directory Add this directory as source\n"
2122 - " -f file Add nodes (e.g. devices) from this spec file\n"
2123 - " -b blocks Size in blocks\n"
2124 - " -i inodes Number of inodes\n"
2125 - " -r reserved Number of reserved blocks\n"
2126 - " -g path Generate a block map file for this path\n"
2127 - " -e value Fill unallocated blocks with value\n"
2128 - " -z Make files with holes\n"
2129 - " -v Print resulting filesystem structure\n"
2130 - " -h Show this help\n\n"
2131 - "Example of spec file:\n"
2133 - "crw- 10,190 /dev/lcd\n"
2134 - "brw- 1,0 /dev/ram0\n\n"
2135 - "Report bugs to xavier.bestel@free.fr\n", argv0);
2136 + " -x image Use this image as a starting point\n"
2137 + " -d directory Add this directory as source\n"
2138 + " -b blocks Size in blocks\n"
2139 + " -i inodes Number of inodes\n"
2140 + " -r reserved Number of reserved blocks\n"
2141 + " -g path Generate a block map file for this path\n"
2142 + " -e value Fill unallocated blocks with value\n"
2143 + " -z Make files with holes\n"
2144 + " -D,-f Use the named FILE as a device table file\n"
2145 + " -q Squash permissions and owners making all files be owned by root\n"
2146 + " -U Squash owners making all files be owned by root\n"
2147 + " -P Squash permissions on all files\n"
2148 + " -v Print resulting filesystem structure\n"
2149 + " -h Show this help\n\n"
2150 + "Report bugs to xavier.bestel@free.fr\n", app_name);
2153 #define MAX_DOPT 128
2154 @@ -1521,21 +2126,17 @@
2159 + FILE *devtable = NULL;
2167 - while((c = getopt(argc, argv, "x:f:d:b:i:r:g:e:zvh")) != EOF)
2168 + app_name = argv[0];
2169 + while((c = getopt(argc, argv, "x:d:b:i:r:g:e:zvhD:f:qUP")) != EOF)
2177 dopt[didx++] = optarg;
2180 @@ -1556,6 +2157,24 @@
2186 + devtable = xfopen(optarg, "r");
2187 + if (fstat(fileno(devtable), &sb) < 0)
2188 + perror_msg_and_die(optarg);
2189 + if (sb.st_size < 10)
2190 + error_msg_and_die("%s: not a proper device table file", optarg);
2205 @@ -1566,16 +2185,14 @@
2208 if(optind < (argc - 1))
2209 - errexit("too many arguments");
2210 + error_msg_and_die("too many arguments");
2211 if(optind == (argc - 1))
2212 fsout = argv[optind];
2215 if(strcmp(fsin, "-"))
2217 - FILE * fh = fopen(fsin, "r");
2220 + FILE * fh = xfopen(fsin, "r");
2221 fs = load_fs(fh, bigendian);
2224 @@ -1585,7 +2202,7 @@
2228 - errexit("filesystem size unspecified");
2229 + error_msg_and_die("filesystem size unspecified");
2231 nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE);
2233 @@ -1595,35 +2212,30 @@
2234 for(i = 0; i < didx; i++)
2240 switch(st.st_mode & S_IFMT)
2243 - if(!(fh = fopen(dopt[i], "r")))
2245 - add2fs_from_file(fs, EXT2_ROOT_INO, fh);
2249 if(!(pdir = getcwd(0, GETCWD_SIZE)))
2251 + perror_msg_and_die(dopt[i]);
2252 if(chdir(dopt[i]) < 0)
2254 + perror_msg_and_die(dopt[i]);
2255 add2fs_from_dir(fs, EXT2_ROOT_INO);
2258 + perror_msg_and_die(pdir);
2262 - errexit("%s in neither a file nor a directory", dopt[i]);
2263 + error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
2267 for(i = 1; i < fs->sb.s_blocks_count; i++)
2268 - if(!allocated(fs->bbm, i))
2269 + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,i),GRP_BBM_OFFSET(fs,i)))
2270 memset(get_blk(fs, i), emptyval, BLOCKSIZE);
2272 + parse_device_table(fs, devtable);
2275 for(i = 0; i < gidx; i++)
2276 @@ -1633,21 +2245,18 @@
2279 if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
2280 - errexit("path %s not found in filesystem", gopt[i]);
2281 + error_msg_and_die("path %s not found in filesystem", gopt[i]);
2282 while((p = strchr(gopt[i], '/')))
2284 snprintf(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
2285 - if(!(fh = fopen(fname, "w")))
2287 + fh = xfopen(fname, "w");
2288 fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
2289 flist_blocks(fs, nod, fh);
2292 if(strcmp(fsout, "-"))
2294 - FILE * fh = fopen(fsout, "w");
2297 + FILE * fh = xfopen(fsout, "w");
2298 dump_fs(fs, fh, bigendian);
2301 diff -urN genext2fs-1.3.orig/test-mount.sh genext2fs-1.3/test-mount.sh
2302 --- genext2fs-1.3.orig/test-mount.sh 1969-12-31 17:00:00.000000000 -0700
2303 +++ genext2fs-1.3/test-mount.sh 2003-04-21 01:41:42.000000000 -0600
2310 + umount mnt 2>/dev/null
2311 + rm -rf mnt ext2.img lsout fout test 2>/dev/null
2314 +# dtest - Uses the -d directory option of genext2fs
2315 +# Creates an image with a file of given size and verifies it
2316 +# Usage: dtest file-size number-of-blocks
2318 + size=$1; blocks=$2;fname=$size
2319 + echo "Testing with file of size $size "
2322 + dd if=/dev/zero of=file.$1 bs=1 count=$size
2324 + ./genext2fs -b $blocks -d test ext2.img
2325 + md5=`md5sum ext2.img | cut -f1 -d " "`
2326 + if ! /sbin/e2fsck -fn ext2.img ; then
2327 + echo "fsck failed"
2333 + if ! mount -t ext2 -o loop ext2.img mnt; then
2338 + if (! [ -f mnt/file.$fname ]) || \
2339 + [ $fname != "`ls -al mnt | grep file.$fname |awk '{print $5}'`" ] ; then
2344 + echo PASSED "(md5 checksum for the image: $md5)"
2348 +# ftest - Uses the -f spec-file option of genext2fs
2349 +# Creates an image with the devices mentioned in the given spec
2350 +# file and verifies it
2351 +# Usage: ftest spec-file number-of-blocks
2353 + fname=$1; blocks=$2;
2354 + echo "Testing with devices file $fname"
2355 + ./genext2fs -b $blocks -f $fname ext2.img
2356 + md5=`md5sum ext2.img | cut -f 1 -d " "`
2357 + if ! /sbin/e2fsck -fn ext2.img ; then
2358 + echo "fsck failed"
2364 + if ! mount -t ext2 -o loop ext2.img mnt; then
2369 + if ! [ -d mnt/dev ] ; then
2374 + cat dev.txt | grep ^[bc] | \
2375 + awk '{print $1substr($1,2)substr($1,2),$2,$3}'| \
2376 + sort -d -k3.6 > fout
2377 + ls -al mnt/dev | grep ^[bc] | \
2378 + awk '{ print $1,$5$6,"/dev/"$10}' | \
2379 + sort -d -k3.6 > lsout
2380 + if ! diff fout lsout ; then
2385 + echo PASSED "(md5 checksum for the image: $md5)"
2396 +dtest 16777216 20000
2401 diff -urN genext2fs-1.3.orig/test.sh genext2fs-1.3/test.sh
2402 --- genext2fs-1.3.orig/test.sh 1969-12-31 17:00:00.000000000 -0700
2403 +++ genext2fs-1.3/test.sh 2003-04-21 01:41:42.000000000 -0600
2408 +# dtest - Uses the -d directory option of genext2fs
2409 +# Creates an image with a file of given size and verifies it
2410 +# Usage: dtest file-size number-of-blocks correct-checksum
2412 + size=$1; blocks=$2; checksum=$3
2413 + echo "Testing with file of size $size "
2416 + dd if=/dev/zero of=file.$1 bs=1 count=$size
2418 + ./genext2fs -b $blocks -d test ext2.img
2419 + md5=`md5sum ext2.img | cut -d" " -f1`
2420 + rm -rf ext2.img test
2421 + if [ $md5 == $checksum ] ; then
2429 +# ftest - Uses the -f spec-file option of genext2fs
2430 +# Creates an image with the devices mentioned in the given spec
2431 +# file and verifies it
2432 +# Usage: ftest spec-file number-of-blocks correct-checksum
2434 + fname=$1; blocks=$2; checksum=$3
2435 + echo "Testing with devices file $fname"
2436 + ./genext2fs -b $blocks -f $fname ext2.img
2437 + md5=`md5sum ext2.img | cut -d" " -f1`
2439 + if [ $md5 == $checksum ] ; then
2447 +dtest 0 4096 491a43ab93c2e5c186c9f1f72d88e5c5
2448 +dtest 0 8193 6289224f0b7f151994479ba156c43505
2449 +dtest 0 8194 3272c43c25e8d0c3768935861a643a65
2450 +dtest 1 4096 5ee24486d33af88c63080b09d8cadfb5
2451 +dtest 12288 4096 494498364defdc27b2770d1f9c1e3387
2452 +dtest 274432 4096 65c4bd8d30bf563fa5434119a12abff1
2453 +dtest 8388608 9000 9a49b0461ee236b7fd7c452fb6a1f2dc
2454 +dtest 16777216 20000 91e16429c901b68d30f783263f0611b7
2456 +ftest dev.txt 4096 921ee9343b0759e16ad8d979d7dd16ec