1#!/bin/sh
2#
3# This script uses debugfs command to populate the ext2/3/4 filesystem
4# from a given directory.
5#
6
7do_usage () {
8	cat << _EOF
9Usage: populate-extfs.sh <source> <device>
10Create an ext2/ext3/ext4 filesystem from a directory or file
11
12  source: The source directory or file
13  device: The target device
14
15_EOF
16	exit 1
17}
18
19[ $# -ne 2 ] && do_usage
20
21SRCDIR=${1%%/}
22DEVICE=$2
23
24# Find where is the debugfs command if not found in the env.
25if [ -z "$DEBUGFS" ]; then
26	CONTRIB_DIR=$(dirname $(readlink -f $0))
27	DEBUGFS="$CONTRIB_DIR/../debugfs/debugfs"
28fi
29
30{
31	CWD="/"
32	find $SRCDIR | while read FILE; do
33                TGT="${FILE##*/}"
34                DIR="${FILE#$SRCDIR}"
35                DIR="${DIR%$TGT}"
36
37		# Skip the root dir
38		[ ! -z "$DIR" ] || continue
39		[ ! -z "$TGT" ] || continue
40
41		if [ "$DIR" != "$CWD" ]; then
42			echo "cd $DIR"
43			CWD="$DIR"
44		fi
45
46		# Only stat once since stat is a time consuming command
47		STAT=$(stat -c "TYPE=\"%F\";DEVNO=\"0x%t 0x%T\";MODE=\"%f\";U=\"%u\";G=\"%g\"" $FILE)
48		eval $STAT
49
50		case $TYPE in
51		"directory")
52			echo "mkdir $TGT"
53			;;
54		"regular file" | "regular empty file")
55			echo "write $FILE $TGT"
56			;;
57		"symbolic link")
58			LINK_TGT=$(readlink $FILE)
59			echo "symlink $TGT $LINK_TGT"
60			;;
61		"block special file")
62			echo "mknod $TGT b $DEVNO"
63			;;
64		"character special file")
65			echo "mknod $TGT c $DEVNO"
66			;;
67		"fifo")
68			echo "mknod $TGT p"
69			;;
70		*)
71			echo "Unknown/unhandled file type '$TYPE' file: $FILE" 1>&2
72			;;
73		esac
74
75		# Set the file mode
76		echo "sif $TGT mode 0x$MODE"
77
78		# Set uid and gid
79		echo "sif $TGT uid $U"
80		echo "sif $TGT gid $G"
81	done
82
83	# Handle the hard links.
84	# Save the hard links to a file, use the inode number as the filename, for example:
85	# If a and b's inode number is 6775928, save a and b to /tmp/tmp.VrCwHh5gdt/6775928.
86	INODE_DIR=`mktemp -d` || exit 1
87	for i in `find $SRCDIR -type f -links +1 -printf 'INODE=%i###FN=%p\n'`; do
88		eval `echo $i | sed 's$###$ $'`
89		echo ${FN#$SRCDIR} >>$INODE_DIR/$INODE
90	done
91	# Use the debugfs' ln and "sif links_count" to handle them.
92	for i in `ls $INODE_DIR`; do
93		# The link source
94		SRC=`head -1 $INODE_DIR/$i`
95		# Remove the files and link them again except the first one
96		for TGT in `sed -n -e '1!p' $INODE_DIR/$i`; do
97			echo "rm $TGT"
98			echo "ln $SRC $TGT"
99		done
100		LN_CNT=`cat $INODE_DIR/$i | wc -l`
101		# Set the links count
102		echo "sif $SRC links_count $LN_CNT"
103	done
104	rm -fr $INODE_DIR
105} | $DEBUGFS -w -f - $DEVICE
106