[alt.sources] ls2dir: simulate a directory hierarchy based on an ls-lR file

dansmith@well.sf.ca.us (Daniel Smith) (11/13/90)

	Save this part as the README:

	I happened to be learning from the new Sed & Awk handbook a few nights
ago, and ended up writing something I've wanted for a long time.  This
is a sh, sed, and mostly awk script that can create a directory hierarchy
based on a file in ls-lR format.  The files created only have one line,
the permissions, ownership, and file size that was present in the ls-lR.
This should handle ls-lRg (group, 9 fields) files just fine.

	The directory "lsdir" is created first, and the hierarchy starts from
that point.  This script only provides the commands, you should pipe
to sh to actually make the files and directories.  I did this for sanity's
sake, so that you can get a feel for what is going to happen before committing.
Type "ls2dir~ for more usage.

	Some caveats and more hype:

	I just seem to find things faster when I can navigate through
files and directories (if you want my cd, push, and pop aliases/scripts,
let me know).  This could use a perl or sh/grabchars based script as a wrapper
that would make up uucp/ftp commands depending on location in the
resulting hierarchy (think of the restore command...).  I also make
a .dirinfo file in each directory in the form of:

directory path
Total Files: XX Sum of File Sizes: XXXXXXXX

	in the lsdir directory, you'll also find a .totals file such as:

Total Dirs: 15 Files: 382 File Sizes:5316909

	No doubt this could be done in 10 lines of perl (with comments!)

	caveats:

	Don't run this over NFS if you can help it!  I haven't (I know
better than to try this with the uunet ls-lR :-), and if you want to remain
on good terms with those you share the network with, you won't.  Seriously,
this can create *thousands* of files.  Find a local disk and go for it.
A June, 1990 uunet ls-lR took 44 *minutes* on a standalone Sony NEWS 1750.
I haven't bothered trying this on my Sparc at work.  Figure that you will
need 9-10 times as much disk space as the original ls-lR.  It's also possible
that you could run out of inodes.  But it's a good tool nonetheless! :-)
If anything, those making NFS servers can use it to benchmark throughput.
I recommend using this on ls-lR files that have absolute pathnames.

				Daniel

              Daniel Smith, Island Graphics, Marin County, CA
   dansmith@well.sf.ca.us   daniel@island.com   unicom!daniel@pacbell.com
     phone: (415) 491 1000 (w) disclaimer: Island's coffee was laced :-)
             "Salesmen are the Ferengi of the software world"

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	ls2dir
# This archive created: Mon Nov 12 19:17:59 1990
# By:	Daniel Smith (island.com!daniel)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'ls2dir'" '(1858 characters)'
if test -f 'ls2dir'
then
	echo shar: "will not over-write existing file 'ls2dir'"
else
cat << \SHAR_EOF > 'ls2dir'
#! /bin/sh

if [ ! ${1-""} ]; then
	cat << +++
usage: $0 some_ls-lR_file

	You'll see a shell script being created.  You can either
	redirect to a file, or make the directory hierarchy directly
	(it will be under the dir "lsdir") by piping.  examples:

	$0 some_ls-lR_file > some_script
	$0 some_ls-lR_file | sh -x

+++
	exit 1
fi

#	this line is silly, I'm just looking for the inverse of basename(1)
basedir=`grep "/.*:" $1 | head -1 | tr '/' '\012' | sed '/:/d' | tr '\012' '/'`

#	this part adapted from X11 mkdirhier...
parts=`echo lsdir/$basedir | sed 's,\(.\)/\(.\),\1 \2,g' | sed 's,/$,,'`;
path="";
for p in $parts; do
if [ x"$path" = x ]; then
    dir=$p;
else
    dir=$path/$p;
fi;
if [ ! -d $dir ]; then
    echo mkdir $dir;
    echo chmod a+rx $dir;
fi;
path=$dir;
done;


cat $1 | awk  '
BEGIN {
	root = "lsdir"
	totfilestr = "Total Files"
	sumfilestr = "Sum of File Sizes"
	seendir = 0
	seenbase = 0
	filecount = 0
	filesum = 0
	totfilecount = 0
	totdircount = 0
	totfilesum = 0
}

/^.*otal/	{	# kludge to get basedir set...
	if (seenbase == 0) {
		split (base, bdir, ":")
		seenbase++
	}
}


NF == 1 && /:$/ {
	if (seendir > 0) {
		printf ("echo %s > %s/%s/.dirinfo\n", bdir[1], root, bdir[1])

		printf ("echo %s: %d\t%s:%d >> %s/%s/.dirinfo\n", 	\
				 totfilestr, filecount,			\
				sumfilestr, filesum, root, bdir[1])
	}
	seendir = 1
	filesum = 0
	filecount = 0
	totdircount++
	split ($0,bdir,":")
	printf ("mkdir %s/%s\n", root, bdir[1])
	next
}

NF >= 8 && /^-/ {	# handle files
	filesum += $(NF - 4)
	totfilesum += $(NF - 4)
	filecount++
	totfilecount++
	printf ("echo  \"")
	for (i = 1; i < NF; i++)
		printf ("%s ", $i)
	printf ("\" > %s/%s/%s\n", root, bdir[1], $NF)
}

END {
	printf ("echo Total Dirs: %d\tFiles: %d\t File Sizes:%d",\
			totdircount, totfilecount, totfilesum)
	printf (" > %s/.totals\n", root)
} ' base=$basedir -
SHAR_EOF
chmod +x 'ls2dir'
fi
exit 0
#	End of shell archive
-- 
              Daniel Smith, Island Graphics, Marin County, CA
   dansmith@well.sf.ca.us   daniel@island.com   unicom!daniel@pacbell.com
     phone: (415) 491 1000 (w) disclaimer: Island's coffee was laced :-)
             "Salesmen are the Ferengi of the software world"