[unix-pc.sources] REPOST Mtools v1.6

egray@fthood.UUCP (07/16/89)

Several folks have pointed out that they never saw the orginal posting
of Mtools v1.6.  Is it possible that it didn't actually go out???  I
have been having some trouble with my unix-pc.* news feed, so I guess
anything is possible...  So, here is a repost (I think) of the most
current version (with the two patches already installed).

Sorry for any confusion...

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
fthood!egray@uxc.cso.uiuc.edu		Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057
------------------------------------------------------------------------------
This is part 1 (of 2) to the Mtools v1.6 distribution package.  Mtools
is a collection of MSDOS tools to allow you to read and write to MSDOS
formatted diskettes from a Unix based system.

The following MSDOS commands are emulated:

Mtool 		MSDOS
name		equivalent	Description
-----		----		-----------
mcopy		COPY		copy MSDOS files to/from Unix
mdel		DEL/ERASE	delete a MSDOS file
mdir		DIR		display a MSDOS directory
mmd		MD/MKDIR	make a MSDOS sub directory
mrd		RD/RMDIR	remove a MSDOS sub directory
mread		COPY		low level read (copy) a MSDOS file to Unix
mren		REN/RENAME	rename an existing MSDOS file
mtype		TYPE		display contents of a MSDOS file
mwrite		COPY		low level write (copy) a Unix file to MSDOS

Please remember... Providing a custom device driver to suit your floppy
drive is beyond the scope of this program.

As always, there is a shell archive called Unixpc.shar that contains 
the files specific to the AT&T Unix PC 7300/3b1.

Have fun...

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
fthood!egray@uxc.cso.uiuc.edu		Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	Customize
#	Makefile
#	Mcopy.1
#	Mdel.1
#	Mdir.1
#	Mmd.1
#	Mrd.1
#	Mread.1
#	Mren.1
#	Mtype.1
#	Mwrite.1
#	Readme
#	Unixpc.shar
#	convdate.c
#	fixname.c
#	getfat.c
#	init.c
#	isdir.c
#	match.c
#	mcopy.c
# This archive created: Thu Jul  6 08:08:50 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Customize'" '(3088 characters)'
if test -f 'Customize'
then
	echo shar: "will not over-write existing file 'Customize'"
else
sed 's/^X//' << \SHAR_EOF > 'Customize'
XHow to configure Mtools for non-standard disk formats...
X
XThere are three approaches to the problem of trying to read and write
XMSDOS formatted diskettes in a Unix box doesn't have a floppy drive
Xthat meets the physical drive requirements.  For example, if your
XUnix box only has a 80 track floppy, you can:
X
X	1) Get a device driver to "double step" the 80 track drive
X	to read and write to 40 track diskettes.
X
X		Pros: No new hardware costs.
X		Cons: Device drivers are a bitch to write (or
X	  	      	expensive to buy).
X		      Success rates are low when using 80 track
X			drives to write 40 tracks.
X
X	2) Get a conventional device driver and purchase a 40 track
X	drive.  You'll still need the device driver unless your 
X	Unix vendor was thoughtful enough to leave you some "extras".
X
X		Pros: High success rates (40 track to 40 track)
X		Cons: The "foriegn" drive may cause trouble with
X			maintenance contracts
X
X	3) Purchase a 80 track drive for your PC.  This exploits the
X	fact that MSDOS already has a configurable device driver
X	feature.
X
X		Pros: You don't alter your Unix box in any way.
X		Cons: You'll have to process all MSDOS diskettes
X			thru the one PC before using Mtools.
X
X               +--------+          +-----------+
X          +--> | Unix   |          |  IBM PC   |
X          |    | box    |          |  clone    |
X        mtools +--------+          +-----+-----+
X          |    | 80 trk |          | 80  | 40  |        MSDOS
X          +--> | track  | <------> | trk | trk | <----> world
X               +--------+          +-----+-----+
X                                    ^         ^
X                                    |  MSDOS  |
X                                    +- COPY --+
X
XHow to customize Mtools...
X
XThe program can be easily customized to accept non-standard disk
Xformats.  For example, a popular disk format for Unix machines seems to
Xbe 80 track, double sided, 8 sector.  This doesn't conform to any of the
XIBM standard formats, but MSDOS 3.2 (or greater) can be made to format
Xvirtually anything using DRIVPARM (or DRIVER.SYS) in the CONFIG.SYS
Xfile.  Let's take a hypothetical case of a brand X Unix machine with a
X80 track, double sided, 8 sector disk drive.  You could purchase an
Xexternal 80 track drive for your IBM compatible computer and format the
Xnew drive D: under MSDOS with the following in your CONFIG.SYS file
X
X	DRIVPARM=/D:2 /T:80 /S:8 /H:2 /F:2
X		or
X	DEVICE=DRIVER.SYS /D:2 /T:80 /S:8 /H:2 /F:2
X
XThen, you would edit the init.c file to include the new non-standard
Xparameters.  You might need Norton Utilities, or some other program, to
Xdetermine the statistics of the format.  Using our example, the format
Xwould have the following parameters:
X
X	FAT#1	sectors 1 - 3		fat_len = 3
X	FAT#2	sectors 4 - 6		dir_start = 7
X	DIR	sectors 7 - 13		dir_len = 7
X	cluster size is 2 sectors	clus_size = 2
X	there are 633 clusters		num_clus = 633
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!unnet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
X					Directorate of Engineering & Housing
X					Environmental Management Office
X					Fort Hood, TX 76544-5057
SHAR_EOF
if test 3088 -ne "`wc -c < 'Customize'`"
then
	echo shar: "error transmitting 'Customize'" '(should have been 3088 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(2922 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X#       Makefile for MSDOS tools
X#
X
XCFLAGS	= -O
XLDFLAGS	= -s
XLINT	= lint -p
XSHAR	= shar -a
XBINDIR	= /usr/local/bin
XPROGS	= mdir mread mwrite mdel mtype mmd mrd mren mcopy
X
XMDIR	= mdir.o getfat.o init.o search.o match.o convdate.o unixname.o \
X	subdir.o isdir.o
XMREAD	= mread.o getfat.o init.o search.o match.o unixname.o subdir.o \
X	convdate.o
XMWRITE	= mwrite.o getfat.o init.o search.o fixname.o unixname.o putfat.o \
X	subdir.o mkentry.o isdir.o
XMDEL	= mdel.o getfat.o init.o search.o match.o unixname.o putfat.o subdir.o
XMTYPE	= mtype.o getfat.o init.o search.o match.o unixname.o subdir.o
XMMD	= mmd.o getfat.o init.o search.o fixname.o unixname.o putfat.o \
X	subdir.o mkentry.o
XMRD	= mrd.o getfat.o init.o search.o unixname.o putfat.o subdir.o
XMREN	= mren.o getfat.o init.o search.o fixname.o unixname.o putfat.c \
X	subdir.o isdir.o
XMCOPY	= mcopy.o
X
Xall:	$(PROGS)
X
Xmdir:	$(MDIR)
X	$(CC) $(LDFLAGS) $(MDIR) -o mdir
X
Xmread:	$(MREAD)
X	$(CC) $(LDFLAGS) $(MREAD) -o mread
X
Xmwrite:	$(MWRITE)
X	$(CC) $(LDFLAGS) $(MWRITE) -o mwrite
X
Xmdel:	$(MDEL)
X	$(CC) $(LDFLAGS) $(MDEL) -o mdel
X
Xmtype:	$(MTYPE)
X	$(CC) $(LDFLAGS) $(MTYPE) -o mtype
X
Xmmd:	$(MMD)
X	$(CC) $(LDFLAGS) $(MMD) -o mmd
X
Xmrd:	$(MRD)
X	$(CC) $(LDFLAGS) $(MRD) -o mrd
X
Xmren:	$(MREN)
X	$(CC) $(LDFLAGS) $(MREN) -o mren
X
Xmcopy:	$(MCOPY)
X	$(CC) $(LDFLAGS) $(MCOPY) -o mcopy
X
Xinstall:
X	cp mdir $(BINDIR)/mdir
X#	cp Mdir.1 /usr/man/man1/mdir.1
X	cp mread $(BINDIR)/mread
X#	cp Mread.1 /usr/man/man1/mread.1
X	cp mwrite $(BINDIR)/mwrite
X#	cp Mwrite.1 /usr/man/man1/mwrite.1
X	cp mdel $(BINDIR)/mdel
X#	cp Mdel.1 /usr/man/man1/mdel.1
X	cp mtype $(BINDIR)/mtype
X#	cp Mtype.1 /usr/man/man1/mtype.1
X	cp mmd $(BINDIR)/mmd
X#	cp Mmd.1 /usr/man/man1/mmd.1
X	cp mrd $(BINDIR)/mrd
X#	cp Mrd.1 /usr/man/man1/mrd.1
X	cp mren $(BINDIR)/mren
X#	cp Mren.1 /usr/man/man1/mren.1
X	cp mcopy $(BINDIR)/mcopy
X#	cp Mcopy.1 /usr/man/man1/mcopy.1
X
Xclean:
X	rm $(PROGS)
X
Xlint:
X	$(LINT) mdir.c getfat.c init.c search.c match.c convdate.c subdir.c \
X	unixname.c isdir.c
X	$(LINT) mread.c getfat.c init.c search.c match.c unixname.c subdir.c
X	$(LINT) mwrite.c getfat.c init.c search.c fixname.c unixname.c \
X	putfat.c subdir.c mkentry.c isdir.c
X	$(LINT) mdel.c getfat.c init.c search.c match.c unixname.c putfat.c \
X	subdir.c
X	$(LINT) mtype.c getfat.c init.c search.c match.c unixname.c subdir.c
X	$(LINT) mmd.c getfat.c init.c search.c fixname.c unixname.c putfat.c \
X	subdir.c mkentry.c
X	$(LINT) mrd.c getfat.c init.c search.c unixname.c putfat.c subdir.c
X	$(LINT) mren.c getfat.c init.c search.c fixname.c unixname.c putfat.c \
X	subdir.c
X	$(LINT) mcopy.c
X
Xshar:
X	$(SHAR) Customize Makefile Mcopy.1 Mdel.1 Mdir.1 Mmd.1 Mrd.1 \
X	Mread.1 Mren.1 Mtype.1 Mwrite.1 Readme Unixpc.shar convdate.c \
X	fixname.c getfat.c init.c isdir.c match.c mcopy.c > mtools_sh.1
X	$(SHAR) mdel.c mdir.c mkentry.c mmd.c mrd.c mread.c mren.c \
X	msdos.h mtype.c mwrite.c putfat.c search.c subdir.c unixname.c \
X	> mtools_sh.2
X
Xinit.o:	msdos.h
SHAR_EOF
if test 2922 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 2922 characters)'
fi
fi
echo shar: "extracting 'Mcopy.1'" '(1676 characters)'
if test -f 'Mcopy.1'
then
	echo shar: "will not over-write existing file 'Mcopy.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mcopy.1'
X.TH MCOPY 1 local
X.SH NAME
Xmcopy \- copy MSDOS files to/from Unix
X.SH SYNOPSIS
X.B mcopy
X[
X.B -tnvm
X] unixfile a:msdosfile
X.PP
X.B mcopy
X[
X.B -tnvm
X] unixfile [ unixfiles... ] a:msdosdirectory
X.PP
X.B mcopy
X[
X.B -tnm
X] a:msdosfile unixfile
X.PP
X.B mcopy
X[
X.B -tnm
X] a:msdosfile [ a:msdosfiles... ] unixdirectory
X.SH DESCRIPTION
XIn the first two forms,
X.I mcopy
Xcopies the specified Unix file to the named MSDOS file or copies
Xmultiple Unix files to the named MSDOS directory.  The last two forms
Xcopy MSDOS files to Unix.  MSDOS sub directories are supported with
Xeither the '/' or '\e\' separator.  The use of the '\e\' separator or
Xwildcards will require the names to be enclosed in quotes to protect
Xthem from the shell.
X.PP
XThe use of the 'a:' drive designation on the MSDOS files determines the
Xdirection of the transfer.  A missing drive designation implies a Unix
Xfile whose path starts in the current directory 
X.PP
X.I Mcopy
Xwill allow the following command line options:
X.TP
X.B t
XText file transfer.
X.I Mcopy
Xwill translate incoming carriage return/line feeds to line feeds.
X.TP
X.B n
XNo warning.
X.I Mcopy
Xwill not warn the user when overwriting an existing file.
X.TP
X.B v
Xverbose mode.
X.TP
X.B m
XPreserve the file modification time.
X.PP
XIf the target file already exists, and the
X.I -n
Xoption is not in effect,
X.I mcopy
Xasks whether or not to overwrite the file.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmdir(1), mtype(1), mread(1), mwrite(1)
X.SH BUGS
XWildcards are only applied to filenames, not to directory names.
XUnlike MSDOS, the destination directory may not be omitted.
SHAR_EOF
if test 1676 -ne "`wc -c < 'Mcopy.1'`"
then
	echo shar: "error transmitting 'Mcopy.1'" '(should have been 1676 characters)'
fi
fi
echo shar: "extracting 'Mdel.1'" '(869 characters)'
if test -f 'Mdel.1'
then
	echo shar: "will not over-write existing file 'Mdel.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mdel.1'
X.TH MDEL 1 local
X.SH NAME
Xmdel \- delete a MSDOS file
X.SH SYNOPSIS
X.B mdel
X[
X.B -v
X] msdosfile [ msdosfiles...  ]
X.SH DESCRIPTION
X.I Mdel
Xdeletes a file on a MSDOS formatted diskette.  Sub directories are supported
Xwith either the '/' or '\e\' separator.  The use of the '\e\' separator
Xor wildcards will require the names to be enclosed in quotes to protect
Xthem from the shell.
X.PP
X.I Mdel
Xwill allow the following command line option:
X.TP
X.B v
XVerbose mode.  Echo the file names as they are processed.
X.PP
X.I Mdel
Xwill ask for verification prior to removing a read\-only file.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmdir(1)
X.SH BUGS
XAllows multiple arguments, which does not follow the MSDOS convention.
XWildcards are only applied to filenames, not to directory names.
SHAR_EOF
if test 869 -ne "`wc -c < 'Mdel.1'`"
then
	echo shar: "error transmitting 'Mdel.1'" '(should have been 869 characters)'
fi
fi
echo shar: "extracting 'Mdir.1'" '(975 characters)'
if test -f 'Mdir.1'
then
	echo shar: "will not over-write existing file 'Mdir.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mdir.1'
X.TH MDIR 1 local
X.SH NAME
Xmdir \- display a MSDOS directory
X.SH SYNOPSIS
X.B mdir
X[
X.B -w
X] msdosdirectory
X.PP
X.B mdir
X[
X.B -w
X] msdosfile [ msdosfiles...  ] 
X.SH DESCRIPTION
X.I Mdir
Xdisplays the contents of a MSDOS formatted diskette.  Sub directories
Xare supported with either the '/' or '\e\' separator.  The use of 
Xthe '\e\' separator or wildcards will require the names to be enclosed
Xin quotes to protect them from the shell.
X.PP
X.I Mdir
Xwill allow the following command line option:
X.TP
X.B w
XWide output.  This option will print the file names across the page
Xwithout displaying the file size or creation date.
X.PP
XAn error occurs if a component of the path is not a directory.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmtype(1)
X.SH BUGS
XAllows multiple arguments, which does not follow the MSDOS convention.
XWildcards are only applied to filenames, not to directory names.
SHAR_EOF
if test 975 -ne "`wc -c < 'Mdir.1'`"
then
	echo shar: "error transmitting 'Mdir.1'" '(should have been 975 characters)'
fi
fi
echo shar: "extracting 'Mmd.1'" '(906 characters)'
if test -f 'Mmd.1'
then
	echo shar: "will not over-write existing file 'Mmd.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mmd.1'
X.TH MMD 1 local
X.SH NAME
Xmmd \- make a MSDOS sub directory
X.SH SYNOPSIS
X.B mmd
X[
X.B -v
X] msdosdirectory
X.SH DESCRIPTION
X.I Mmd
Xmakes a new directory on a MSDOS formatted diskette.  Sub directories
Xare supported with either the '/' or '\e\' separator.  The use of
Xthe '\e\' separator will require the directory name to be enclosed in
Xquotes to protect it from the shell.
X.PP
X.I Mmd
Xwill allow the following command line option:
X.TP
X.B v
XVerbose mode.  Display the new directory name if the name supplied is
Xinvalid.
X.PP
XReasonable care is taken to create a valid MSDOS directory name.  If an
Xinvalid name is specified,
X.I mmd
Xwill change the name (and display the new name if the verbose mode is
Xset).
X.PP
XAn error occurs if the directory already exists.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmdir(1), mrd(1)
SHAR_EOF
if test 906 -ne "`wc -c < 'Mmd.1'`"
then
	echo shar: "error transmitting 'Mmd.1'" '(should have been 906 characters)'
fi
fi
echo shar: "extracting 'Mrd.1'" '(598 characters)'
if test -f 'Mrd.1'
then
	echo shar: "will not over-write existing file 'Mrd.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mrd.1'
X.TH MRD 1 local
X.SH NAME
Xmrd \- remove a MSDOS sub directory
X.SH SYNOPSIS
X.B mrd
Xmsdosdirectory
X.SH DESCRIPTION
X.I Mrd
Xremoves a directory from a MSDOS formatted diskette.  Sub directories
Xare supported with either the '/' or '\e\' separator.  The use of
Xthe '\e\' separator will require the directory name to be enclosed in
Xquotes to protect it from the shell.
X.PP
XAn error occurs if the directory is not empty.
X.PP
XWildcards are not supported.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmdir(1), mmd(1)
SHAR_EOF
if test 598 -ne "`wc -c < 'Mrd.1'`"
then
	echo shar: "error transmitting 'Mrd.1'" '(should have been 598 characters)'
fi
fi
echo shar: "extracting 'Mread.1'" '(1327 characters)'
if test -f 'Mread.1'
then
	echo shar: "will not over-write existing file 'Mread.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mread.1'
X.TH MREAD 1 local
X.SH NAME
Xmread \- low level read (copy) a MSDOS file to Unix
X.SH SYNOPSIS
X.B mread
X[
X.B -tnm
X] msdosfile unixfile
X.PP
X.B mread
X[
X.B -tnm
X] msdosfile [ msdosfiles... ] unixdirectory
X.SH DESCRIPTION
XIn the first form,
X.I mread
Xcopies the specified MSDOS file to the named Unix file.  The second form
Xof the command copies multiple MSDOS files to the named Unix directory.
XMSDOS sub directories are supported with either the '/' or '\e\'
Xseparator.  The use of the '\e\' separator or wildcards will require the
Xnames to be enclosed in quotes to protect them from the shell.
X.PP
X.I Mread
Xwill allow the following command line options:
X.TP
X.B t
XText file transfer.
X.I Mread
Xwill translate incoming carriage return/line feeds to line feeds.
X.TP
X.B n
XNo warning.
X.I Mread
Xwill not warn the user when overwriting an existing file.
X.TP
X.B m
XPreserve the file modification times.
X.PP
XIf the target file already exists, and the
X.I -n
Xoption is not in effect,
X.I mread
Xasks whether or not to overwrite the file.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmcopy(1), mdir(1), mtype(1), mwrite(1)
X.SH BUGS
XWildcards are only applied to filenames, not to directory names.
XUnlike MSDOS, the destination directory may not be omitted.
SHAR_EOF
if test 1327 -ne "`wc -c < 'Mread.1'`"
then
	echo shar: "error transmitting 'Mread.1'" '(should have been 1327 characters)'
fi
fi
echo shar: "extracting 'Mren.1'" '(1237 characters)'
if test -f 'Mren.1'
then
	echo shar: "will not over-write existing file 'Mren.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mren.1'
X.TH MREN 1 local
X.SH NAME
Xmren \- rename an existing MSDOS file
X.SH SYNOPSIS
X.B mren
X[
X.B -v
X] sourcefile targetfile
X.SH DESCRIPTION
X.I Mren
Xrenames an existing file on a MSDOS formatted diskette.  Sub directories
Xare supported with either the '/' or '\e\' separator.  The use of
Xthe '\e\' separator or wildcards will require the names to be enclosed
Xin quotes to protect them from the shell.
X.PP
X.I Mren
Xwill allow the following command line option:
X.TP
X.B v
XVerbose mode.  Display the new file name if the name supplied is
Xinvalid.
X.PP
XReasonable care is taken to create a valid MSDOS filename.  If an invalid
XMSDOS target name is specified,
X.I mren
Xwill change the name (and prompt the user to accept or reject the new name
Xif the verbose mode is set).
X.PP
XThe path component of the target filename (if supplied) is ignored.  In
Xother words, you may not use
X.I mren
Xto move a file from one sub directory to another.
X.PP 
X.I Mren
Xmay also be used to rename directories.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmwrite(1)
X.SH BUGS
XWildcards are only applied to filenames, not to directory names.
XMSDOS doesn't use ren to rename directories.
SHAR_EOF
if test 1237 -ne "`wc -c < 'Mren.1'`"
then
	echo shar: "error transmitting 'Mren.1'" '(should have been 1237 characters)'
fi
fi
echo shar: "extracting 'Mtype.1'" '(978 characters)'
if test -f 'Mtype.1'
then
	echo shar: "will not over-write existing file 'Mtype.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mtype.1'
X.TH MTYPE 1 local
X.SH NAME
Xmtype \- display contents of a MSDOS file
X.SH SYNOPSIS
X.B mtype
X[
X.B -ts
X] msdosfile [ msdosfiles... ]
X.SH DESCRIPTION
X.I Mtype
Xdisplays the specified MSDOS file on the screen.  MSDOS sub directories
Xare supported with either the '/' or '\e\' separator.  The use of 
Xthe '\e\' separator or wildcards will require the names to be enclosed
Xin quotes to protect them from the shell.
X.PP
X.I Mtype
Xwill allow the following command line options:
X.TP
X.B t
XText file viewing.
X.I Mtype
Xwill translate incoming carriage return/line feeds to line feeds.
X.TP
X.B s
XStrip high bit.
X.I Mtype
Xwill strip the high bit from the data.  Useful for viewing Wordstar files.
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmdir(1), mread(1)
X.SH BUGS
XAllows multiple arguments, which does not follow the MSDOS convention.
XWildcards are only applied to filenames, not to directory names.
SHAR_EOF
if test 978 -ne "`wc -c < 'Mtype.1'`"
then
	echo shar: "error transmitting 'Mtype.1'" '(should have been 978 characters)'
fi
fi
echo shar: "extracting 'Mwrite.1'" '(1594 characters)'
if test -f 'Mwrite.1'
then
	echo shar: "will not over-write existing file 'Mwrite.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Mwrite.1'
X.TH MWRITE 1 local
X.SH NAME
Xmwrite \- low level write (copy) a Unix file to MSDOS
X.SH SYNOPSIS
X.B mwrite
X[
X.B -tnvm
X] unixfile msdosfile
X.PP
X.B mwrite
X[
X.B -tnvm
X] unixfile [ unixfiles... ] msdosdirectory
X.SH DESCRIPTION
XIn the first form,
X.I mwrite
Xcopies the specified Unix file to the named MSDOS file.  The second form
Xof the command copies multiple Unix files to the named MSDOS directory.
XMSDOS sub directories are are supported with either the '/' or '\e\'
Xseparator.  The use of the '\e\' separator will require the names to be
Xenclosed in quotes to protect them from the shell.
X.PP
X.I Mwrite
Xwill allow the following command line options:
X.TP
X.B t
XText file transfer.
X.I Mwrite
Xwill translate incoming line feeds to carriage return/line feeds.
X.TP
X.B n
XNo warning.
X.I Mwrite
Xwill not warn the user when overwriting an existing file.
X.TP
X.B v
XVerbose mode.  Display the new file name if the Unix file name requires
Xconversion.
X.TP
X.B m
XPreserve the file modification times.
X.PP
XIf the target file already exists, and the
X.I -n
Xoption is not in effect,
X.I mwrite
Xasks whether or not to overwrite the file.
X.PP
XReasonable care is taken to create a valid MSDOS filename.  If an
Xinvalid name is specified,
X.I mwrite
Xwill change the name (and display the new name if the verbose mode is
Xset).
X.PP
XThe environmental variable MCWD may be used to establish a current
Xworking directory (relative to the MSDOS diskette).
X.SH SEE ALSO
Xmcopy(1), mdir(1), mread(1)
X.SH BUGS
XWildcards are only applied to filenames, not to directory names.
XUnlike MSDOS, the destination directory may not be omitted.
SHAR_EOF
if test 1594 -ne "`wc -c < 'Mwrite.1'`"
then
	echo shar: "error transmitting 'Mwrite.1'" '(should have been 1594 characters)'
fi
fi
echo shar: "extracting 'Readme'" '(3841 characters)'
if test -f 'Readme'
then
	echo shar: "will not over-write existing file 'Readme'"
else
sed 's/^X//' << \SHAR_EOF > 'Readme'
X				MTOOLS
X			version 1.6.2 - 5 Jul 89
X
XThis is a collection of MSDOS tools to allow you to read and write to
XMSDOS formatted diskettes from a Unix based system.
X
XThe following MSDOS commands are emulated:
X
XMtool 		MSDOS
Xname		equivalent	Description
X-----		----		-----------
Xmcopy		COPY		copy MSDOS files to/from Unix
Xmdel		DEL/ERASE	delete a MSDOS file
Xmdir		DIR		display a MSDOS directory
Xmmd		MD/MKDIR	make a MSDOS sub directory
Xmrd		RD/RMDIR	remove a MSDOS sub directory
Xmread		COPY		low level read (copy) a MSDOS file to Unix
Xmren		REN/RENAME	rename an existing MSDOS file
Xmtype		TYPE		display contents of a MSDOS file
Xmwrite		COPY		low level write (copy) a Unix file to MSDOS
X*		CD		change working directory
X
X	* by use of the environmental variable MCWD
X
XThe formats of IBM PC floppy disk drives are:
X
X   bytes per  sectors per  tracks    number    total     disk   introduced
X    sector      track     per side  of sides  capacity   size    in MSDOS
X     512         8          40        1        160k      5.25      1.0
X     512         9          40        1        180k      5.25      1.1
X     512         8          40        2        320k      5.25      2.0
X     512         9          40        2        360k      5.25      2.0
X     512        15          80        2        1.2M      5.25      3.0
X     512         8          80        2        720k      3.5       3.1
X     512        16          80        2        1.4k      3.5       3.2
X
X
XThe following may be typical Unix device names for the IBM formats:
X
X	/dev/rflp		'generic' used first to test the media
X	/dev/rflp40t8s1s	40 track 8 sector single sided
X	/dev/rflp40t8s2s	40 track 8 sector double sided
X	/dev/rflp40t9s1s	40 track 9 sector single sided
X	/dev/rflp40t9s2s	40 track 9 sector double sided
X	/dev/rflp80t15s2s	80 track 15 sector double sided
X
XThese device names are in the msdos.h file as #defines and must be
Xedited to match the device names on your system.  If your device driver
Xdoes not handle all of the formats shown, then you should leave those
Xparticular devices undefined in the msdos.h file.
X
XThe manuals are very terse...  it's assumed that the reader is already
Xfamiliar with MSDOS.
X
XThe use of the environmental variable MCWD to keep track of the current
Xworking directory is a little awkward, especially since there is no
X'change directory' command.  Bourne shell users will have to type two
Xcommands to initially set their working directory, ie:
X
X	MCWD=/TMP
X	export MCWD
X
XWildcards are only applied to filenames and not to directory names.  For
Xexample '/usr/local/*.c' is appropriate, but '/usr/l*/main.c' is not.
X
XI really wanted to avoid the use of a 'text' mode and a 'data' mode when
Xtransferring files, but I couldn't find a better way.  It gets rather
Xconfusing and it's quite possible to mess up a file if you apply the
Xtext mode when it is not appropriate (ie:  to a COM or EXE file).
XLikewise, if you forget to apply the text mode (to a Unix text file)
Xthen if the file is used under MSDOS, it will be missing carriage
Xreturns.  However, if you aren't going to use the files on your Unix
Xsystem (you just intend to hold the files and then transfer them back to
XMSDOS later) then you shouldn't use the text mode during either mread or
Xmwrite.  This is because, the text mode is only useful if the files are
Xgonna be used under Unix.
X
XThe implementation of the Mcopy command is somewhat clumbsy since the
XMSDOS drive designation "A:" is used.  Mcopy is really a front-end to
Xthe low level Mread and Mwrite commands.
X
XThere are is a shell archives called "Unixpc.shar" that contain files
Xspecific to the AT&T Unix PC 7300/3b1.
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
X					Directorate of Engineering & Housing
X					Environmental Management Office
X					Fort Hood, TX 76544-5057
SHAR_EOF
if test 3841 -ne "`wc -c < 'Readme'`"
then
	echo shar: "error transmitting 'Readme'" '(should have been 3841 characters)'
fi
fi
echo shar: "extracting 'Unixpc.shar'" '(11391 characters)'
if test -f 'Unixpc.shar'
then
	echo shar: "will not over-write existing file 'Unixpc.shar'"
else
sed 's/^X//' << \SHAR_EOF > 'Unixpc.shar'
X#! /bin/sh
X# This is a shell archive, meaning:
X# 1. Remove everything above the #! /bin/sh line.
X# 2. Save the resulting text in a file.
X# 3. Execute the file with /bin/sh (not csh) to create:
X#	Makefile
X#	init.c
X#	msdos.h
X# This archive created: Wed Jul  5 18:59:43 1989
Xexport PATH; PATH=/bin:/usr/bin:$PATH
Xecho shar: "extracting 'Makefile'" '(2980 characters)'
Xif test -f 'Makefile'
Xthen
X	echo shar: "will not over-write existing file 'Makefile'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'Makefile'
XX#
XX#       Makefile for MSDOS tools
XX#
XX
XXCFLAGS	= -O
XXLD	= ld -s
XXLINT	= lint -p
XXSHAR	= shar -a
XXBINDIR	= /usr/local/bin
XXPROGS	= mdir mread mwrite mdel mtype mmd mrd mren mcopy
XXSHAREDLIB = /lib/crt0s.o /lib/shlib.ifile
XX
XXMDIR	= mdir.o getfat.o init.o search.o match.o convdate.o unixname.o \
XX	subdir.o isdir.o
XXMREAD	= mread.o getfat.o init.o search.o match.o unixname.o subdir.o \
XX	convdate.o
XXMWRITE	= mwrite.o getfat.o init.o search.o fixname.o unixname.o putfat.o \
XX	subdir.o mkentry.o isdir.o
XXMDEL	= mdel.o getfat.o init.o search.o match.o unixname.o putfat.o subdir.o
XXMTYPE	= mtype.o getfat.o init.o search.o match.o unixname.o subdir.o
XXMMD	= mmd.o getfat.o init.o search.o fixname.o unixname.o putfat.o \
XX	subdir.o mkentry.o
XXMRD	= mrd.o getfat.o init.o search.o unixname.o putfat.o subdir.o
XXMREN	= mren.o getfat.o init.o search.o fixname.o unixname.o putfat.o \
XX	subdir.o isdir.o
XXMCOPY	= mcopy.o
XX
XXall:	$(PROGS)
XX
XXmdir:	$(MDIR)
XX	$(LD) $(MDIR) $(SHAREDLIB) -o mdir
XX
XXmread:	$(MREAD)
XX	$(LD) $(MREAD) $(SHAREDLIB) -o mread
XX
XXmwrite:	$(MWRITE)
XX	$(LD) $(MWRITE) $(SHAREDLIB) -o mwrite
XX
XXmdel:	$(MDEL)
XX	$(LD) $(MDEL) $(SHAREDLIB) -o mdel
XX
XXmtype:	$(MTYPE)
XX	$(LD) $(MTYPE) $(SHAREDLIB) -o mtype
XX
XXmmd:	$(MMD)
XX	$(LD) $(MMD) $(SHAREDLIB) -o mmd
XX
XXmrd:	$(MRD)
XX	$(LD) $(MRD) $(SHAREDLIB) -o mrd
XX
XXmren:	$(MREN)
XX	$(LD) $(MREN) $(SHAREDLIB) -o mren
XX
XXmcopy:	$(MCOPY)
XX	$(LD) $(MCOPY) $(SHAREDLIB) -o mcopy
XX
XXinstall:
XX	cp mdir $(BINDIR)/mdir
XX#	cp Mdir.1 /usr/man/man1/mdir.1
XX	cp mread $(BINDIR)/mread
XX#	cp Mread.1 /usr/man/man1/mread.1
XX	cp mwrite $(BINDIR)/mwrite
XX#	cp Mwrite.1 /usr/man/man1/mwrite.1
XX	cp mdel $(BINDIR)/mdel
XX#	cp Mdel.1 /usr/man/man1/mdel.1
XX	cp mtype $(BINDIR)/mtype
XX#	cp Mtype.1 /usr/man/man1/mtype.1
XX	cp mmd $(BINDIR)/mmd
XX#	cp Mmd.1 /usr/man/man1/mmd.1
XX	cp mrd $(BINDIR)/mrd
XX#	cp Mrd.1 /usr/man/man1/mrd.1
XX	cp mren $(BINDIR)/mren
XX#	cp Mren.1 /usr/man/man1/mren.1
XX	cp mcopy $(BINDIR)/mcopy
XX#	cp Mcopy.1 /usr/man/man1/mcopy.1
XX
XXclean:
XX	rm $(PROGS)
XX
XXlint:
XX	$(LINT) mdir.c getfat.c init.c search.c match.c convdate.c subdir.c \
XX	unixname.c isdir.c
XX	$(LINT) mread.c getfat.c init.c search.c match.c unixname.c subdir.c
XX	$(LINT) mwrite.c getfat.c init.c search.c fixname.c unixname.c \
XX	putfat.c subdir.c mkentry.c isdir.c
XX	$(LINT) mdel.c getfat.c init.c search.c match.c unixname.c putfat.c \
XX	subdir.c
XX	$(LINT) mtype.c getfat.c init.c search.c match.c unixname.c subdir.c
XX	$(LINT) mmd.c getfat.c init.c search.c fixname.c unixname.c putfat.c \
XX	subdir.c mkentry.c
XX	$(LINT) mrd.c getfat.c init.c search.c unixname.c putfat.c subdir.c
XX	$(LINT) mren.c getfat.c init.c search.c fixname.c unixname.c putfat.c \
XX	subdir.c
XX	$(LINT) mcopy.c
XX
XXshar:
XX	$(SHAR) Customize Makefile Mcopy.1 Mdel.1 Mdir.1 Mmd.1 Mrd.1 \
XX	Mread.1 Mren.1 Mtype.1 Mwrite.1 Readme Unixpc.shar convdate.c \
XX	fixname.c getfat.c init.c isdir.c match.c mcopy.c > mtools_sh.1
XX	$(SHAR) mdel.c mdir.c mkentry.c mmd.c mrd.c mread.c mren.c \
XX	msdos.h mtype.c mwrite.c putfat.c search.c subdir.c unixname.c \
XX	> mtools_sh.2
XX
XXinit.o:	msdos.h
XSHAR_EOF
Xif test 2980 -ne "`wc -c < 'Makefile'`"
Xthen
X	echo shar: "error transmitting 'Makefile'" '(should have been 2980 characters)'
Xfi
Xfi
Xecho shar: "extracting 'init.c'" '(6148 characters)'
Xif test -f 'init.c'
Xthen
X	echo shar: "will not over-write existing file 'init.c'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'init.c'
XX/*
XX * Initialize a MSDOS diskette.  Get the media signature (1st FAT
XX * entry) and alter the floppy disk controller via 'gdisk' ioctl calls
XX * to match the format of the disk.  Sets a bunch of global variables.
XX * Returns 0 on success, or 1 on failure.
XX */
XX
XX#include <stdio.h>
XX#include <sys/gdioctl.h>
XX#include <ctype.h>
XX#include <signal.h>
XX#include "msdos.h"
XX
XX#undef DUP_FAT
XX
XXextern int fd, dir_len, dir_start, clus_size, fat_len, num_clus;
XXextern unsigned char *fatbuf;
XXextern char *mcwd;
XX
XXint
XXinit(mode)
XXint mode;
XX{
XX	int code, buflen, intr();
XX	unsigned char read_fat(), fat;
XX	char *getenv(), *fixmcwd(), *malloc();
XX	long lseek();
XX	void perror(), exit(), dismount(), move(), reset_dir();
XX	struct gdctl gdbuf;
XX
XX	if ((fd = open(FLOPPY, mode)) < 0) {
XX		perror("init: open");
XX		exit(1);
XX	}
XX					/* get the disk controller info */
XX	if (ioctl(fd, GDGETA, &gdbuf) < 0) {
XX		perror("init: ioctl");
XX		dismount();
XX	}
XX					/* assume some defaults */
XX	gdbuf.params.cyls = 40;		/* number of cylinders */
XX	gdbuf.params.heads = 1;		/* number of heads */
XX	gdbuf.params.psectrk = 8;	/* physical sectors per track */
XX	gdbuf.params.pseccyl = 8;	/* physical sectors per cylinder */
XX	gdbuf.params.flags = 1;		/* disk type flag */
XX	gdbuf.params.step = 0;		/* step rate for controller */
XX	gdbuf.params.sectorsz = 512;	/* sector size */
XX
XX					/* set the default parameters */
XX	if (ioctl(fd, GDSETA, &gdbuf) < 0) {
XX		perror("init: ioctl");
XX		dismount();
XX	}
XX					/* read media signature (1st FAT) */
XX	code = 0;
XX	fat = read_fat();
XX	switch(fat) {
XX		case 0xfe:		/* 40 trk, 8 sect, 1 side */
XX			dir_start = 3;
XX			dir_len = 4;
XX			clus_size = 1;
XX			fat_len = 1;
XX			num_clus = 313;
XX			gdbuf.params.heads = 1;
XX			gdbuf.params.psectrk = 8;
XX			gdbuf.params.pseccyl = 8;
XX			break;
XX		case 0xff:		/* 40 trk, 8 sect, 2 sides */
XX			dir_start = 3;
XX			dir_len = 7;
XX			clus_size = 2;
XX			fat_len = 1;
XX			num_clus = 315;
XX			gdbuf.params.heads = 2;
XX			gdbuf.params.psectrk = 8;
XX			gdbuf.params.pseccyl = 16;
XX			break;
XX		case 0xfc:		/* 40 trk, 9 sect, 1 side */
XX			dir_start = 5;
XX			dir_len = 4;
XX			clus_size = 1;
XX			fat_len = 2;
XX			num_clus = 351;
XX			gdbuf.params.heads = 1;
XX			gdbuf.params.psectrk = 9;
XX			gdbuf.params.pseccyl = 9;
XX			break;
XX		case 0xfd:		/* 40 trk, 9 sect, 2 sides */
XX			dir_start = 5;
XX			dir_len = 7;
XX			clus_size = 2;
XX			fat_len = 2;
XX			num_clus = 354;
XX			gdbuf.params.heads = 2;
XX			gdbuf.params.psectrk = 9;
XX			gdbuf.params.pseccyl = 18;
XX			break;
XX		default:
XX			fprintf(stderr, "Unknown format '%02x'\n", fat);
XX			code = 1;
XX			break;
XX	}
XX	if (code)
XX		return(1);
XX					/* set the new-found parameters */
XX	if (ioctl(fd, GDSETA, &gdbuf) < 0) {
XX		perror("init: ioctl");
XX		dismount();
XX	}
XX
XX	buflen = fat_len * MSECSIZ;
XX	fatbuf = (unsigned char *) malloc((unsigned int) buflen);
XX	move(1);
XX					/* read the FAT sectors */
XX	if (read(fd, (char *) fatbuf, buflen) != buflen) {
XX		perror("init: read");
XX		exit(1);
XX	}
XX					/* set dir_chain to root directory */
XX	reset_dir();
XX					/* get Current Working Directory */
XX	mcwd = fixmcwd(getenv("MCWD"));
XX					/* test it out.. */
XX	if (subdir("")) {
XX		fprintf(stderr, "Environmental variable MCWD needs updating\n");
XX		exit(1);
XX	}
XX					/* catch signals if open for write */
XX	if (mode == 2) {
XX		signal(SIGINT, intr);
XX		signal(SIGTERM, intr);
XX		signal(SIGQUIT, intr);
XX	}
XX	return(0);
XX}
XX
XX/*
XX * Dismount the floppy.  Useful only if one of the above ioctls fail
XX * and leaves the drive light turned on.
XX */
XX
XXvoid
XXdismount()
XX{
XX	struct gdctl gdbuf;
XX	void exit();
XX
XX	ioctl(fd, GDDISMNT, &gdbuf);
XX	exit(1);
XX}
XX
XX/*
XX * Move the read/write head to the next location.  Tries to optimize
XX * the movement by moving relative to current location.  The argument
XX * is a logical sector number.  All errors are fatal.
XX */
XX
XXvoid
XXmove(sector)
XXint sector;
XX{
XX	long cur_loc, next, lseek();
XX	void exit(), perror();
XX					/* get current location */
XX	if ((cur_loc = lseek(fd, 0L, 1)) < 0) {
XX		perror("move: lseek");
XX		exit(1);
XX	}
XX	next = (long) (MSECSIZ * sector) - cur_loc;
XX					/* we're already there */
XX	if (next == 0L)
XX		return;
XX					/* move to next location */
XX	if (lseek(fd, next, 1) < 0) {
XX		perror("move: lseek");
XX		exit(1);
XX	}
XX	return;
XX}
XX
XX/*
XX * Fix MCWD to be a proper directory name.  Always has a leading separator.
XX * Never has a trailing separator (unless it is the path itself).
XX */
XX
XXchar *
XXfixmcwd(dirname)
XXchar *dirname;
XX{
XX	char *s, *ans, *strcpy(), *strcat(), *malloc();
XX
XX	if (dirname == NULL)
XX		return("/");
XX
XX	ans = malloc((unsigned int) strlen(dirname)+2);
XX
XX					/* add a leading separator */
XX	if (*dirname != '/' && *dirname != '\\') {
XX		strcpy(ans, "/");
XX		strcat(ans, dirname);
XX	}
XX	else
XX		strcpy(ans, dirname);
XX					/* translate to upper case */
XX	for (s = ans; *s; ++s) {
XX		if (islower(*s))
XX			*s = toupper(*s);
XX	}
XX					/* if separator alone */
XX	if (strlen(ans) == 1)
XX		return(ans);
XX					/* zap the trailing separator */
XX	s--;
XX	if (*s == '/' || *s == '\\')
XX		*s = '\0';
XX	return(ans);
XX}
XX
XX/*
XX * Read the first byte of the FAT table.  This code serves as a media
XX * signature for the diskette.
XX */
XX
XXunsigned char
XXread_fat()
XX{
XX	unsigned char buf[MSECSIZ];
XX					/* move to boot sector */
XX	if (lseek(fd, (long) MSECSIZ, 0) < 0) {
XX		perror("init: lseek");
XX		exit(1);
XX	}
XX					/* read the first FAT sector */
XX	if (read(fd, (char *) buf, MSECSIZ) != MSECSIZ) {
XX		fprintf(stderr, "Drive empty or latch not closed\n");
XX		exit(1);
XX	}
XX	return(buf[0]);
XX}
XX
XX/*
XX * Do a graceful exit if the program is interupted.  This will reduce
XX * (but not eliminate) the risk of generating a corrupted disk on
XX * a user abort.
XX */
XX
XXint
XXintr()
XX{
XX	void writefat();
XX
XX	writefat();
XX	close(fd);
XX	exit(1);
XX}
XX
XX/*
XX * Write the FAT table to the disk.  Up to now the FAT manipulation has
XX * been done in memory.  All errors are fatal.  (Might not be too smart
XX * to wait till the end of the program to write the table.  Oh well...)
XX */
XX
XXvoid
XXwritefat()
XX{
XX	int buflen;
XX	void move();
XX
XX	move(1);
XX	buflen = fat_len * MSECSIZ;
XX	if (write(fd, (char *) fatbuf, buflen) != buflen) {
XX		perror("writefat: write");
XX		exit(1);
XX	}
XX#ifdef DUP_FAT
XX					/* the duplicate FAT table */
XX	if (write(fd, (char *) fatbuf, buflen) != buflen) {
XX		perror("writefat: write");
XX		exit(1);
XX	}
XX#endif /* DUP_FAT */
XX	return;
XX}
XSHAR_EOF
Xif test 6148 -ne "`wc -c < 'init.c'`"
Xthen
X	echo shar: "error transmitting 'init.c'" '(should have been 6148 characters)'
Xfi
Xfi
Xecho shar: "extracting 'msdos.h'" '(558 characters)'
Xif test -f 'msdos.h'
Xthen
X	echo shar: "will not over-write existing file 'msdos.h'"
Xelse
Xsed 's/^X//' << \SHAR_EOF > 'msdos.h'
XX/*
XX * msdos common header file
XX */
XX
XX#define MSECSIZ	512			/* sector size */
XX#define MDIRSIZ	32			/* directory size */
XX#define CLSTRBUF 1024			/* largest cluster size */
XX#define MAX_PATH 128
XX
XX#define	FLOPPY	"/dev/rfp020"
XX
XXstruct directory {
XX	unsigned char	name[8];	/* file name */
XX	unsigned char	ext[3];		/* file extent */
XX	unsigned char	attr;		/* attribute byte */
XX	unsigned char	reserved[10];	/* ?? */
XX	unsigned char	time[2];		
XX	unsigned char	date[2];
XX	unsigned char	start[2];	/* starting cluster number */
XX	unsigned char	size[4];	/* size of the file */
XX};
XSHAR_EOF
Xif test 558 -ne "`wc -c < 'msdos.h'`"
Xthen
X	echo shar: "error transmitting 'msdos.h'" '(should have been 558 characters)'
Xfi
Xfi
Xexit 0
X#	End of shell archive
SHAR_EOF
if test 11391 -ne "`wc -c < 'Unixpc.shar'`"
then
	echo shar: "error transmitting 'Unixpc.shar'" '(should have been 11391 characters)'
fi
fi
echo shar: "extracting 'convdate.c'" '(2461 characters)'
if test -f 'convdate.c'
then
	echo shar: "will not over-write existing file 'convdate.c'"
else
sed 's/^X//' << \SHAR_EOF > 'convdate.c'
X/*
X * convdate(), convtime(), convstamp()
X */
X#include <stdio.h>
X/*
X * convert MSDOS directory datestamp to ASCII.
X */
X
Xchar *
Xconvdate(date_high, date_low)
Xunsigned date_high, date_low;
X{
X/*
X *	    hi byte     |    low byte
X *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
X *      | | | | | | | | | | | | | | | | |
X *      \   7 bits    /\4 bits/\ 5 bits /
X *         year +80      month     day
X */
X	static char ans[9];
X	unsigned char year, month_hi, month_low, day;
X
X	year = (date_high >> 1) + 80;
X	month_hi = (date_high & 0x1) << 3;
X	month_low = date_low >> 5;
X	day = date_low & 0x1f;
X	sprintf(ans, "%2d-%02d-%02d", month_hi+month_low, day, year);
X	return(ans);
X}
X
X/*
X * Convert MSDOS directory timestamp to ASCII.
X */
X
Xchar *
Xconvtime(time_high, time_low)
Xunsigned time_high, time_low;
X{
X/*
X *	    hi byte     |    low byte
X *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
X *      | | | | | | | | | | | | | | | | |
X *      \  5 bits /\  6 bits  /\ 5 bits /
X *         hour      minutes     sec*2
X */
X	static char ans[7];
X	char am_pm;
X	unsigned char hour, min_hi, min_low;
X
X	hour = time_high >> 3;
X	am_pm = (hour >= 12) ? 'p' : 'a';
X	if (hour > 12)
X		hour = hour -12;
X	if (hour == 0)
X		hour = 12;
X	min_hi = (time_high & 0x7) << 3;
X	min_low = time_low >> 5;
X	sprintf(ans, "%2d:%02d%c", hour, min_hi+min_low, am_pm);
X	return(ans);
X}
X
X/*
X * Convert a MSDOS time & date stamp to the Unix time() format
X */
X
Xlong
Xconvstamp(time_field, date_field)
Xunsigned char *time_field, *date_field;
X{
X	extern long timezone;
X	int year, mon, mday, hour, min, sec, old_leaps;
X	long answer, sec_year, sec_mon, sec_mday, sec_hour, sec_min, sec_leap;
X	static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
X	334};
X					/* disect the parts */
X	year = (date_field[1] >> 1) + 1980;
X	mon = (((date_field[1] & 0x1) << 3) + (date_field[0] >> 5));
X	mday = date_field[0] & 0x1f;
X	hour = time_field[1] >> 3;
X	min = (((time_field[1] & 0x7) << 3) + (time_field[0] >> 5));
X	sec = (time_field[0] & 0x1f) * 2;
X					/* how many previous leap years */
X	old_leaps = (year -1972) / 4;
X	sec_leap = old_leaps * 24 * 60 * 60;
X					/* back off 1 day if before 29 Feb */
X	if (!(year % 4) && mon < 3)
X		sec_leap -= 24 * 60 * 60;
X	sec_year = (year - 1970) * 365 * 24 * 60 * 60;
X	sec_mon = month[mon -1] * 24 * 60 * 60;
X	sec_mday = mday * 24 * 60 * 60;
X	sec_hour = hour * 60 * 60;
X	sec_min = min * 60;
X	
X	answer = sec_leap + sec_year + sec_mon + sec_mday + sec_hour + sec_min + sec + timezone;
X	return(answer);
X}
SHAR_EOF
if test 2461 -ne "`wc -c < 'convdate.c'`"
then
	echo shar: "error transmitting 'convdate.c'" '(should have been 2461 characters)'
fi
fi
echo shar: "extracting 'fixname.c'" '(1871 characters)'
if test -f 'fixname.c'
then
	echo shar: "will not over-write existing file 'fixname.c'"
else
sed 's/^X//' << \SHAR_EOF > 'fixname.c'
X/*
X * Convert a Unix filename to a legal MSDOS name.  Returns a pointer to
X * the 'fixed' name.  Will truncate file and extension names, will
X * substitute the letter 'X' for any illegal character in the name.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "msdos.h"
X
Xchar *
Xfixname(filename, verbose)
Xchar *filename;
Xint verbose;
X{
X	static char *dev[8] = {"CON", "AUX", "COM1", "LPT1", "PRN", "LPT2",
X	"LPT3", "NUL"};
X	char *s, *ans, *name, *ext, *strcpy(), *strpbrk(), *strrchr();
X	char buf[MAX_PATH], *malloc();
X	int dot, modified;
X	register int i;
X
X	strcpy(buf, filename);
X	name = buf;
X					/* zap the leading path */
X	if (s = strrchr(name, '/'))
X		name = s+1;
X	if (s = strrchr(name, '\\'))
X		name = s+1;
X
X	ext = "";
X	dot = 0;
X	for (i=strlen(buf)-1; i>=0; i--) {
X		if (buf[i] == '.' && !dot) {
X			dot = 1;
X			buf[i] = '\0';
X			ext = &buf[i+1];
X		}
X		if (islower(buf[i]))
X			buf[i] = toupper(buf[i]);
X	}
X	if (*name == '\0') {
X		name = "X";
X		if (verbose)
X			printf("\"%s\" Null name component, using \"%s.%s\"\n", filename, name, ext);
X	}
X	for (i=0; i<8; i++) {
X		if (!strcmp(name, dev[i])) {
X			*name = 'X';
X			if (verbose)
X				printf("\"%s\" Is a device name, using \"%s.%s\"\n", filename, name, ext);
X		}
X	}
X	if (strlen(name) > 8) {
X		*(name+8) = '\0';
X		if (verbose)
X			printf("\"%s\" Name too long, using, \"%s.%s\"\n", filename, name, ext);
X	}
X	if (strlen(ext) > 3) {
X		*(ext+3) = '\0';
X		if (verbose)
X			printf("\"%s\" Extension too long, using \"%s.%s\"\n", filename, name, ext);
X	}
X	modified = 0;
X	while (s = strpbrk(name, "^+=/[]:',?*\\<>|\". ")) {
X		modified++;
X		*s = 'X';
X	}
X	while (s = strpbrk(ext, "^+=/[]:',?*\\<>|\". ")) {
X		modified++;
X		*s = 'X';
X	}
X	if (modified && verbose)
X		printf("\"%s\" Contains illegal character(s), using \"%s.%s\"\n", filename, name, ext);
X
X	ans = malloc(12);
X	sprintf(ans, "%-8.8s%-3.3s", name, ext);
X	return(ans);
X}
SHAR_EOF
if test 1871 -ne "`wc -c < 'fixname.c'`"
then
	echo shar: "error transmitting 'fixname.c'" '(should have been 1871 characters)'
fi
fi
echo shar: "extracting 'getfat.c'" '(1365 characters)'
if test -f 'getfat.c'
then
	echo shar: "will not over-write existing file 'getfat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getfat.c'
X/*
X * Get and decode a FAT (file allocation table) entry.  The FAT entries
X * are 1.5 bytes long and switch nibbles (.5 byte) according to whether
X * or not the entry starts on a byte boundary.  Returns the cluster 
X * number on success or -1 on failure.
X */
X
X#include "msdos.h"
X
Xextern int fat_len;
Xextern unsigned char *fatbuf;
X
Xint
Xgetfat(num)
Xint num;
X{
X/*
X *	|    byte n     |   byte n+1    |   byte n+2    |
X *	|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
X *	| | | | | | | | | | | | | | | | | | | | | | | | |
X *	|  n.0  |  n.5  | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
X *	    \_____  \____   \______/________/_____   /
X *	      ____\______\________/   _____/  ____\_/
X *	     /     \      \          /       /     \
X *	| n+1.5 |  n.0  |  n.5  | n+2.0 | n+2.5 | n+1.0 |
X *	|      FAT entry k      |    FAT entry k+1      |
X */
X	unsigned int fat_hi, fat_low, byte_1, byte_2;
X	int start, fat;
X					/* which bytes contain the entry */
X	start = num * 3 / 2;
X	if (start < 0 || start+1 > (fat_len * MSECSIZ))
X		return(-1);
X
X	byte_1 = *(fatbuf + start);
X	byte_2 = *(fatbuf + start + 1);
X					/* (odd) not on byte boundary */
X	if (num % 2) {
X		fat_hi = (byte_2 & 0xff) << 4;
X		fat_low  = (byte_1 & 0xf0) >> 4;
X	}
X					/* (even) on byte boundary */
X	else {
X		fat_hi = (byte_2 & 0xf) << 8;
X		fat_low  = byte_1 & 0xff;
X	}
X	fat = (fat_hi + fat_low) & 0xfff;
X	return(fat);
X}
SHAR_EOF
if test 1365 -ne "`wc -c < 'getfat.c'`"
then
	echo shar: "error transmitting 'getfat.c'" '(should have been 1365 characters)'
fi
fi
echo shar: "extracting 'init.c'" '(6662 characters)'
if test -f 'init.c'
then
	echo shar: "will not over-write existing file 'init.c'"
else
sed 's/^X//' << \SHAR_EOF > 'init.c'
X/*
X * Initialize a MSDOS diskette.  Get the media signature (1st FAT entry)
X * and switch to the proper floppy disk device to match the format
X * of the disk.  Sets a bunch of global variables.  Returns 0 on success,
X * or 1 on failure.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include "msdos.h"
X
X#undef DUP_FAT
X
Xextern int fd, dir_len, dir_start, clus_size, fat_len, num_clus;
Xextern unsigned char *fatbuf;
Xextern char *mcwd;
X
Xint
Xinit(mode)
Xint mode;
X{
X	int code, buflen, intr();
X	unsigned char read_fat(), fat;
X	char *getenv(), *fixmcwd(), *malloc();
X	long lseek();
X	void perror(), exit(), move(), reset_dir();
X
X					/* open the 'generic' floppy */
X	if ((fd = open(FLOPPY, mode)) < 0) {
X		perror("init: open");
X		exit(1);
X	}
X					/* read media signature (1st FAT) */
X	if (!(fat = read_fat())) {
X#ifdef FLP_80_15_2
X		close(fd);
X					/* OK, try the 1.2M version */
X		if ((fd = open(FLP_80_15_2, mode)) < 0) {
X			perror("init: open");
X			exit(1);
X		}
X		fat = read_fat();
X#else /* FLP_80_15_2 */
X		perror("init: read");
X		exit(1);
X#endif /* FLP_80_15_2 */
X	}
X					/* what kind of disk do we have? */
X	code = 0;
X	switch(fat) {
X		case 0:			/* I hope errno hasn't been clobbered */
X			perror("init: read");
X			exit(1);
X		case 0xfe:
X#ifndef FLP_40_8_1
X			fprintf(stderr, "40 track, 8 sector, single sided: not supported\n");
X			code = 1;
X#else /* FLP_40_8_1 */
X			dir_start = 3;
X			dir_len = 4;
X			clus_size = 1;
X			fat_len = 1;
X			num_clus = 313;
X			close(fd);
X			if ((fd = open(FLP_40_8_1, mode)) < 0) {
X				perror("init: open");
X				return(1);
X			}
X#endif /* FLP_40_8_1 */
X			break;
X		case 0xff:
X#ifndef FLP_40_8_2
X			fprintf(stderr, "40 track, 8 sector, double sided: not supported\n");
X			code = 1;
X#else /* FLP_40_8_2 */
X			dir_start = 3;
X			dir_len = 7;
X			clus_size = 2;
X			fat_len = 1;
X			num_clus = 315;
X			close(fd);
X			if ((fd = open(FLP_40_8_2, mode)) < 0) {
X				perror("init: open");
X				return(1);
X			}
X#endif /* FLP_40_8_2 */
X			break;
X		case 0xfc:
X#ifndef FLP_40_9_1
X			fprintf(stderr, "40 track, 9 sector, single sided: not supported\n");
X			code = 1;
X#else /* FLP_40_9_1 */
X			dir_start = 5;
X			dir_len = 4;
X			clus_size = 1;
X			fat_len = 2;
X			num_clus = 351;
X			close(fd);
X			if ((fd = open(FLP_40_9_1, mode)) < 0) {
X				perror("init: open");
X				return(1);
X			}
X#endif /* FLP_40_9_1 */
X			break;
X		case 0xfd:
X#ifndef FLP_40_9_2
X			fprintf(stderr, "40 track, 9 sector, double sided: not supported\n");
X			code = 1;
X#else /* FLP_40_9_2 */
X			dir_start = 5;
X			dir_len = 7;
X			clus_size = 2;
X			fat_len = 2;
X			num_clus = 354;
X			close(fd);
X			if ((fd = open(FLP_40_9_2, mode)) < 0) {
X				perror("init: open");
X				return(1);
X			}
X#endif /* FLP_40_9_2 */
X			break;
X		case 0xf9:		/* all 80 track disks */
X			/*
X			 * All 80 track disk use the same media signature,
X			 * so you'll have to come up with some way of figuring
X			 * out what the drive type is.  If you've only got
X			 * one 80 track drive, this is a moot point.
X			 */
X#ifndef FLP_80_15_2
X			fprintf(stderr, "80 track, 15 sector, double sided: not supported\n");
X			code = 1;
X#else /* FLP_80_15_2 */
X			dir_start = 15;
X			dir_len = 14;
X			clus_size = 1;
X			fat_len = 7;
X			num_clus = 1193;
X			close(fd);
X			if ((fd = open(FLP_80_15_2, mode)) < 0) {
X				perror("init: open");
X				return(1);
X			}
X#endif /* FLP_80_15_2 */
X			break;
X		default:
X			fprintf(stderr, "Unknown format '%02x'\n", fat);
X			code = 1;
X			break;
X	}
X	if (code)
X		return(1);
X
X	buflen = fat_len * MSECSIZ;
X	fatbuf = (unsigned char *) malloc((unsigned int) buflen);
X	move(1);
X					/* read the FAT sectors */
X	if (read(fd, (char *) fatbuf, buflen) != buflen) {
X		perror("init: read");
X		exit(1);
X	}
X					/* set dir_chain to root directory */
X	reset_dir();
X					/* get Current Working Directory */
X	mcwd = fixmcwd(getenv("MCWD"));
X					/* test it out.. */
X	if (subdir("")) {
X		fprintf(stderr, "Environmental variable MCWD needs updating\n");
X		exit(1);
X	}
X					/* catch signals if open for write */
X	if (mode == 2) {
X		signal(SIGINT, intr);
X		signal(SIGTERM, intr);
X		signal(SIGQUIT, intr);
X	}
X	return(0);
X}
X
X/*
X * Move the read/write head to the next location.  Tries to optimize
X * the movement by moving relative to current location.  The argument
X * is a logical sector number.  All errors are fatal.
X */
X
Xvoid
Xmove(sector)
Xint sector;
X{
X	long cur_loc, next, lseek();
X	void exit(), perror();
X					/* get current location */
X	if ((cur_loc = lseek(fd, 0L, 1)) < 0) {
X		perror("move: lseek");
X		exit(1);
X	}
X	next = (long) (MSECSIZ * sector) - cur_loc;
X					/* we're already there */
X	if (next == 0L)
X		return;
X					/* move to next location */
X	if (lseek(fd, next, 1) < 0) {
X		perror("move: lseek");
X		exit(1);
X	}
X	return;
X}
X
X/*
X * Fix MCWD to be a proper directory name.  Always has a leading separator.
X * Never has a trailing separator (unless it is the path itself).
X */
X
Xchar *
Xfixmcwd(dirname)
Xchar *dirname;
X{
X	char *s, *ans, *malloc(), *strcpy(), *strcat();
X
X	if (dirname == NULL)
X		return("/");
X
X	ans = malloc((unsigned int) strlen(dirname)+2);
X					/* add a leading separator */
X	if (*dirname != '/' && *dirname != '\\') {
X		strcpy(ans, "/");
X		strcat(ans, dirname);
X	}
X	else
X		strcpy(ans, dirname);
X					/* translate to upper case */
X	for (s = ans; *s; ++s) {
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X					/* if separator alone */
X	if (strlen(ans) == 1)
X		return(ans);
X					/* zap the trailing separator */
X	s--;
X	if (*s == '/' || *s == '\\')
X		*s = '\0';
X	return(ans);
X}
X
X/*
X * Read the first byte of the FAT table.  This code serves as a media
X * signature for the diskette.
X */
X
Xunsigned char
Xread_fat()
X{
X	unsigned char buf[MSECSIZ];
X					/* move to boot sector */
X	if (lseek(fd, (long) MSECSIZ, 0) < 0) {
X		perror("init: lseek");
X		exit(1);
X	}
X					/* read the first FAT sector */
X	if (read(fd, (char *) buf, MSECSIZ) != MSECSIZ)
X		return('\0');
X
X	return(buf[0]);
X}
X
X/*
X * Do a graceful exit if the program is interupted.  This will reduce
X * (but not eliminate) the risk of generating a corrupted disk on
X * a user abort.
X */
X
Xint
Xintr()
X{
X	void writefat();
X
X	writefat();
X	close(fd);
X	exit(1);
X}
X
X/*
X * Write the FAT table to the disk.  Up to now the FAT manipulation has
X * been done in memory.  All errors are fatal.  (Might not be too smart
X * to wait till the end of the program to write the table.  Oh well...)
X */
X
Xvoid
Xwritefat()
X{
X	int buflen;
X	void move();
X
X	move(1);
X	buflen = fat_len * MSECSIZ;
X	if (write(fd, (char *) fatbuf, buflen) != buflen) {
X		perror("writefat: write");
X		exit(1);
X	}
X#ifdef DUP_FAT
X					/* the duplicate FAT table */
X	if (write(fd, (char *) fatbuf, buflen) != buflen) {
X		perror("writefat: write");
X		exit(1);
X	}
X#endif /* DUP_FAT */
X	return;
X}
SHAR_EOF
if test 6662 -ne "`wc -c < 'init.c'`"
then
	echo shar: "error transmitting 'init.c'" '(should have been 6662 characters)'
fi
fi
echo shar: "extracting 'isdir.c'" '(1001 characters)'
if test -f 'isdir.c'
then
	echo shar: "will not over-write existing file 'isdir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'isdir.c'
X/*
X * Test to see if a filename is a directory.  Subdir() has to be
X * run first...  Returns 1 if true.
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xextern int dir_entries;
X
Xint
Xisdir(path)
Xchar *path;
X{
X	register int entry;
X	char *newname, *unixname(), *strncpy(), name[9], ext[4];
X	struct directory *dir, *search();
X	void free();
X					/* no path */
X	if (*path == '\0')
X		return(0);
X
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0)
X			break;
X					/* if erased */
X		if (dir->name[0] == 0xe5)
X			continue;
X					/* skip if not a directory */
X		if (!(dir->attr & 0x10))
X			continue;
X
X		strncpy(name, (char *) dir->name, 8);
X		strncpy(ext, (char *) dir->ext, 3);
X		name[8] = '\0';
X		ext[3] = '\0';
X
X		newname = unixname(name, ext);
X		if (!strcmp(newname, path)) {
X			free(newname);
X			return(1);
X		}
X		free(newname);
X	}
X					/* if "." or ".." fails, then root */
X	if (!strcmp(path, ".") || !strcmp(path, ".."))
X		return(1);
X
X	return(0);
X}
SHAR_EOF
if test 1001 -ne "`wc -c < 'isdir.c'`"
then
	echo shar: "error transmitting 'isdir.c'" '(should have been 1001 characters)'
fi
fi
echo shar: "extracting 'match.c'" '(1894 characters)'
if test -f 'match.c'
then
	echo shar: "will not over-write existing file 'match.c'"
else
sed 's/^X//' << \SHAR_EOF > 'match.c'
X/*
X * Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
X * Not idiot proof!  Returns 1 if match, 0 if not.
X *
X * Ideas for this routine were taken from a program by Rich Salz, mirror!rs
X */
X
X#include <stdio.h>
X
Xint
Xmatch(s, p)
Xchar *s;				/* string to match */
Xchar *p;				/* pattern */
X{
X	int matched, reverse;
X	char first, last;
X
X	for ( ; *p != '\0'; s++, p++) {
X		switch (*p) {
X					/* Literal match with next character */
X		case '\\':
X			p++;
X		default:
X			if (*s != *p)
X				return(0);
X			break;
X					/* match any one character */
X		case '?':
X			if (*s == '\0')
X				return(0);
X			break;
X					/* match everything */
X		case '*':
X					/* if last char in pattern */
X			if (*++p == '\0')
X				return(1);
X					/* search for next char in pattern */
X			matched = 0;
X			while (*s != '\0') {
X				if (*s == *p) {
X					matched = 1;
X					if (!strcmp(s+1,p+1))
X						break;
X				}
X				s++;
X			}
X			if (!matched)
X				return(0);
X			s--;
X			p--;
X			break;
X					/* match range of characters */
X		case '[':
X			first = '\0';
X			matched = 0;
X			reverse = 0;
X			while (*++p != ']') {
X				if (*p == '^') {
X					reverse = 1;
X					p++;
X				}
X				first = *p;
X				if (first == ']' || first == '\0') {
X					fprintf(stderr, "match: Malformed regular expression\n");
X					return(0);
X				}
X					/* if 2nd char is '-' */
X				if (*(p+1) == '-') {
X					p++;
X					/* set last to 3rd char ... */
X					last = *++p;
X					if (last == ']' || last == '\0') {
X						fprintf(stderr, "match: Malformed regular expression\n");
X						return(0);
X					}
X					/* test the range of values */
X					if (*s>=first && *s<=last) {
X						matched = 1;
X						p++;
X						break;
X					}
X					return(0);
X				}
X				if (*s == *p)
X					matched = 1;
X			}
X			if (matched && reverse)
X				return(0);
X			if (!matched)
X				return(0);
X			break;
X		}
X	}
X					/* string ended prematurely ? */
X	if (*s != '\0')
X		return(0);
X	else
X		return(1);
X}
SHAR_EOF
if test 1894 -ne "`wc -c < 'match.c'`"
then
	echo shar: "error transmitting 'match.c'" '(should have been 1894 characters)'
fi
fi
echo shar: "extracting 'mcopy.c'" '(2823 characters)'
if test -f 'mcopy.c'
then
	echo shar: "will not over-write existing file 'mcopy.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mcopy.c'
X/*
X * A front-end to the mread/mwrite commands.
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X
X#define NONE	0
X#define MREAD	1
X#define MWRITE	2
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X	int i, oops, msdos_args, unix_args, destination;
X	char **nargv, *strcpy();
X	void exit();
X					/* get command line options */
X	msdos_args = 0;
X	unix_args = 0;
X	oops = 0;
X	while ((i = getopt(argc, argv, "tnvm")) != EOF) {
X		switch(i) {
X			case 't':
X			case 'n':
X			case 'v':
X			case 'm':
X				break;
X			default:
X				oops = 1;
X				break;
X		}
X	}
X
X	if (oops || (argc - optind) < 2) {
X		fprintf(stderr, "Usage: mcopy [-tnvm] a:msdosfile unixfile\n");
X		fprintf(stderr, "       mcopy [-tnvm] a:msdosfile [a:msdosfiles...] unixdirectory\n");
X		fprintf(stderr, "       mcopy [-tnm] unixfile a:msdosfile\n");
X		fprintf(stderr, "       mcopy [-tnm] unixfile [unixfiles...] a:msdosdirectory\n");
X		exit(1);
X	}
X					/* what is the destination drive? */
X	destination = NONE;
X					/* first file */
X	if (argv[optind][1] == ':') {
X		if (argv[optind][0] == 'a' || argv[optind][0] == 'A')
X			destination = MREAD;
X	}
X					/* last file */
X	if (destination == NONE && argv[argc-1][1] == ':') {
X		if (argv[argc-1][0] == 'a' || argv[argc-1][0] == 'A')
X			destination = MWRITE;
X	}
X	if (destination == NONE) {
X		fprintf(stderr, "mcopy: no 'a:' designation specified\n");
X		exit(1);
X	}
X					/* strip out the fake "drive code" */
X	for (i=optind; i<argc; i++) {
X		if (argv[i][1] == ':') {
X			switch(argv[i][0]) {
X				case 'a':
X				case 'A':
X					if (argv[i][2] == '\0')
X						strcpy(argv[i], ".");
X					else
X						strcpy(argv[i], &argv[i][2]);
X					msdos_args++;
X					break;
X				case 'c':
X				case 'C':
X					fprintf(stderr, "mcopy: 'c:' is not used to designate Unix files\n");
X					exit(1);
X				default:
X					fprintf(stderr, "mcopy: unknown drive '%c:'\n", argv[i][0]);
X					exit(1);
X			}
X			continue;
X		}
X					/* if no drive code, its a unix file */
X		unix_args++;
X	}
X					/* sanity checking */
X	if (!msdos_args || !unix_args) {
X		fprintf(stderr, "mcopy: unresloved destination\n");
X		exit(1);
X	}
X	if ((destination == MWRITE && msdos_args > 1) || (destination == MREAD && unix_args > 1)) {
X		fprintf(stderr, "mcopy: duplicate destination files\n");
X		exit(1);
X	}
X	/*
X	 * Copy the *argv[] array in case your Unix doesn't end the array
X	 * with a null when it passes it to main()
X	 */
X	nargv = (char **) realloc((char *)argv, (argc+1) * sizeof(*argv));
X	nargv[argc] = NULL;
X
X	if (destination == MWRITE) {
X		nargv[0] = "mwrite";
X		execvp("mwrite", nargv);
X	}
X	else {
X		nargv[0] = "mread";
X		execvp("mread", nargv);
X	}
X}
SHAR_EOF
if test 2823 -ne "`wc -c < 'mcopy.c'`"
then
	echo shar: "error transmitting 'mcopy.c'" '(should have been 2823 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (07/16/89)

This is part 2 (of 2) to the Mtools v1.6 distribution package. 

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
fthood!egray@uxc.cso.uiuc.edu		Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /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:
#	mdel.c
#	mdir.c
#	mkentry.c
#	mmd.c
#	mrd.c
#	mread.c
#	mren.c
#	msdos.h
#	mtype.c
#	mwrite.c
#	putfat.c
#	search.c
#	subdir.c
#	unixname.c
# This archive created: Thu Jul  6 08:08:53 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'mdel.c'" '(2881 characters)'
if test -f 'mdel.c'
then
	echo shar: "will not over-write existing file 'mdel.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mdel.c'
X/*
X * Delete a MSDOS file
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int i, ismatch, entry, start, nogo, verbose, fargn;
X	char *filename, *newfile, text[4], tname[9], *getname(), *unixname();
X	char *strncpy(), *getpath(), *pathname, ans[10];
X	void exit(), zapit(), writefat(), writedir(), free();
X	struct directory *dir, *search();
X
X	if (init(2)) {
X		fprintf(stderr, "mdel: Cannot initialize diskette\n");
X		exit(1);
X	}
X
X	if (argc < 2) {
X		fprintf(stderr, "Usage: mdel [-v] msdosfile [msdosfiles...]\n");
X		exit(1);
X	}
X	if (!strcmp(argv[1], "-v")) {
X		verbose = 1;
X		fargn = 2;
X	}
X	else {
X		verbose = 0;
X		fargn = 1;
X	}
X	for (i=fargn; i<argc; i++) {
X		filename = getname(argv[i]);
X		pathname = getpath(argv[i]);
X		if (subdir(pathname)) {
X			free(filename);
X			free(pathname);
X			continue;
X		}
X		nogo = 0;
X		ismatch = 0;
X		for (entry=0; entry<dir_entries; entry++) {
X			dir = search(entry);
X					/* if empty */
X			if (dir->name[0] == 0x0)
X				break;
X					/* if erased */
X			if (dir->name[0] == 0xe5)
X				continue;
X					/* if dir or volume lable */
X			if ((dir->attr & 0x10) || (dir->attr & 0x08))
X				continue;
X
X			strncpy(tname, (char *) dir->name, 8);
X			strncpy(text, (char *) dir->ext, 3);
X			tname[8] = '\0';
X			text[3] = '\0';
X
X			newfile = unixname(tname, text);
X					/* see it if matches the pattern */
X			if (match(newfile, filename)) {
X				if (verbose)
X					printf("Removing %s\n", newfile);
X				ismatch = 1;
X				if (dir->attr & 0x01) {
X					while (!nogo) {
X						printf("mdel: \"%s\" is read only, erase anyway (y/n) ? ", newfile);
X						gets(ans);
X						if (ans[0] == 'y' || ans[0] == 'Y')
X							break;
X						if (ans[0] == 'n' || ans[0] == 'N')
X							nogo = 1;
X					}
X					if (nogo) {
X						free(newfile);
X						continue;
X					}
X				}
X				start = dir->start[1]*0x100 + dir->start[0];
X				zapit(start);
X				dir->name[0] = 0xe5;
X				writedir(entry, dir);
X			}
X			free(newfile);
X		}
X		if (!ismatch)
X			fprintf(stderr, "mdel: File \"%s\" not found\n", filename);
X		free(filename);
X		free(pathname);
X	}
X					/* update the FAT sectors */
X	writefat();
X	close(fd);
X	exit(0);
X}
SHAR_EOF
if test 2881 -ne "`wc -c < 'mdel.c'`"
then
	echo shar: "error transmitting 'mdel.c'" '(should have been 2881 characters)'
fi
fi
echo shar: "extracting 'mdir.c'" '(4882 characters)'
if test -f 'mdir.c'
then
	echo shar: "will not over-write existing file 'mdir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mdir.c'
X/*
X * Display a MSDOS directory
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the current working directory */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int i, entry, files, blocks, fargn, wide, faked;
X	long size;
X	char name[9], ext[4], *date, *time, *convdate(), *convtime();
X	char *strncpy(), newpath[MAX_PATH], *getname(), *getpath(), *pathname;
X	char *newfile, *filename, *unixname(), volume[12], *sep;
X	char *strcpy(), *strcat(), newname[MAX_PATH], *strncat();
X	void exit(), reset_dir(), free();
X	struct directory *dir, *search();
X
X	if (init(0)) {
X		fprintf(stderr, "mdir: Cannot initialize diskette\n");
X		exit(1);
X	}
X					/* find the volume label */
X	reset_dir();
X	volume[0] = '\0';
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0)
X			break;
X					/* if not volume label */
X		if (!(dir->attr & 0x08))
X			continue;
X
X		strncpy(volume, (char *) dir->name, 8);
X		volume[8] = '\0';
X		strncat(volume, (char *) dir->ext, 3);
X		volume[11] = '\0';
X		break;
X	}
X	if (volume[0] == '\0')
X		printf(" Volume in drive has no label\n");
X	else
X		printf(" Volume in drive is %s\n", volume);
X	fargn = 1;
X	wide = 0;
X					/* first argument number */
X	if (argc > 1) {
X		if (!strcmp(argv[1], "-w")) {
X			wide = 1;
X			fargn = 2;
X		}
X	}
X					/* fake an argument */
X	faked = 0;
X	if (argc == fargn) {
X		faked++;
X		argc++;
X	}
X	files = 0;
X	for (i=fargn; i<argc; i++) {
X		if (faked) {
X			filename = getname(".");
X			pathname = getpath(".");
X		}
X		else {
X			filename = getname(argv[i]);
X			pathname = getpath(argv[i]);
X		}
X					/* move to first guess subdirectory */
X					/* required by isdir() */
X		if (subdir(pathname)) {
X			free(filename);
X			free(pathname);
X			continue;
X		}
X					/* is filename really a subdirectory? */
X		if (isdir(filename)) {
X			strcpy(newpath, pathname);
X			if (strcmp(pathname,"/") && strcmp(pathname, "\\")) {
X				if (*pathname != '\0')
X					strcat(newpath, "/");
X			}
X			strcat(newpath, filename);
X					/* move to real subdirectory */
X			if (subdir(newpath)) {
X				free(filename);
X				free(pathname);
X				continue;
X			}
X			strcpy(newname, "*");
X		}
X		else {
X			strcpy(newpath, pathname);
X			strcpy(newname, filename);
X		}
X
X		if (*filename == '\0')
X			strcpy(newname, "*");
X
X		if (*newpath == '/' || *newpath == '\\')
X			printf(" Directory for %s\n\n", newpath);
X		else if (!strcmp(newpath, "."))
X			printf(" Directory for %s\n\n", mcwd);
X		else {
X			if (strlen(mcwd) == 1 || !strlen(newpath))
X				sep = "";
X			else
X				sep = "/";
X			printf(" Directory for %s%s%s\n\n", mcwd, sep, newpath);
X		}
X		for (entry=0; entry<dir_entries; entry++) {
X			dir = search(entry);
X					/* if empty */
X			if (dir->name[0] == 0x0)
X				break;
X					/* if erased */
X			if (dir->name[0] == 0xe5)
X				continue;
X					/* if a volume label */
X			if (dir->attr & 0x08)
X				continue;
X
X			strncpy(name, (char *) dir->name, 8);
X			strncpy(ext, (char *) dir->ext, 3);
X			name[8] = '\0';
X			ext[3] = '\0';
X
X			newfile = unixname(name, ext);
X			if (!match(newfile, newname)) {
X				free(newfile);
X				continue;
X			}
X			free(newfile);
X
X			files++;
X			if (wide && files != 1) {
X				if (!((files-1) % 5))
X					putchar('\n');
X			}
X			date = convdate(dir->date[1], dir->date[0]);
X			time = convtime(dir->time[1], dir->time[0]);
X			size = dir->size[2]*0x10000L + dir->size[1]*0x100 + dir->size[0];
X					/* is a subdirectory */
X			if (dir->attr & 0x10) {
X				if (wide)
X					printf("%-9.9s%-6.6s", name, ext);
X				else
X					printf("%8s %3s  <DIR>     %s  %s\n", name, ext, date, time);
X				continue;
X			}
X			if (wide)
X				printf("%-9.9s%-6.6s", name, ext);
X			else
X				printf("%8s %3s %8d   %s  %s\n", name, ext, size, date, time);
X		}
X		if (argc > 2)
X			putchar('\n');
X
X		free(filename);
X		free(pathname);
X	}
X
X	blocks = getfree() * MSECSIZ;
X	if (!files)
X		printf("File \"%s\" not found\n", newname);
X	else
X		printf("     %3d File(s)     %6ld bytes free\n", files, blocks);
X	close(fd);
X	exit(0);
X}
X
X/*
X * Get the amount of free space on the diskette
X */
X
Xint
Xgetfree()
X{
X	register int i, total;
X
X	total = 0;
X	for (i=2; i<num_clus+2; i++) {
X					/* if getfat returns zero */
X		if (!getfat(i))
X			total += clus_size;
X	}
X	return(total);
X}
SHAR_EOF
if test 4882 -ne "`wc -c < 'mdir.c'`"
then
	echo shar: "error transmitting 'mdir.c'" '(should have been 4882 characters)'
fi
fi
echo shar: "extracting 'mkentry.c'" '(2539 characters)'
if test -f 'mkentry.c'
then
	echo shar: "will not over-write existing file 'mkentry.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mkentry.c'
X/*
X * mk_entry(), grow()
X */
X
X#include <stdio.h>
X#include <time.h>
X#include "msdos.h"
X
Xextern int fd, dir_start, dir_len, clus_size, dir_entries;
Xextern int dir_chain[25];
X
X/*
X * Make a directory entry.  Builds a directory entry based on the
X * name, attribute, starting cluster number, and size.  Returns a pointer
X * to the static directory structure.
X */
X
Xstruct directory *
Xmk_entry(filename, attr, fat, size, date)
Xchar *filename;
Xunsigned char attr;
Xint fat;
Xlong size, date;
X{
X	int i;
X	char *strncpy();
X	static struct directory ndir;
X	struct tm *now, *localtime();
X	unsigned char hour, min_hi, min_low, sec;
X	unsigned char year, month_hi, month_low, day;
X
X	now = localtime(&date);
X	strncpy((char *) ndir.name, filename, 8);
X	strncpy((char *) ndir.ext, filename+8, 3);
X	ndir.attr = attr;
X	for (i=0; i<10; i++)
X		ndir.reserved[i] = '\0';
X	hour = now->tm_hour << 3;
X	min_hi = now->tm_min >> 3;
X	min_low = now->tm_min << 5;
X	sec = now->tm_sec / 2;
X	ndir.time[1] = hour + min_hi;
X	ndir.time[0] = min_low + sec;
X	year = (now->tm_year - 80) << 1;
X	month_hi = (now->tm_mon+1) >> 3;
X	month_low = (now->tm_mon+1) << 5;
X	day = now->tm_mday;
X	ndir.date[1] = year + month_hi;
X	ndir.date[0] = month_low + day;
X	ndir.start[1] = fat / 0x100;
X	ndir.start[0] = fat % 0x100;
X	ndir.size[3] = 0;		/* can't be THAT large */
X	ndir.size[2] = size / 0x10000L;
X	ndir.size[1] = (size % 0x10000L) / 0x100;
X	ndir.size[0] = (size % 0x10000L) % 0x100;
X	return(&ndir);
X}
X
X/*
X * Make a subdirectory grow in length.  Only subdirectories (not root) 
X * may grow.  Returns a 0 on success or 1 on failure (disk full).
X */
X
Xint
Xgrow(fat)
Xint fat;
X{
X	int i, next, last, num, sector, buflen;
X	unsigned char tbuf[CLSTRBUF];
X	void perror(), exit(), move();
X
X	last = nextfat(0);
X	if (last == -1)
X		return(1);
X
X	while (1) {
X		next = getfat(fat);
X		if (next == -1) {
X			fprintf(stderr, "grow: FAT problem\n");
X			exit(1);
X		}
X					/* end of cluster chain */
X		if (next >= 0xff8)
X			break;
X		fat = next;
X	}
X					/* mark the end of the chain */
X	putfat(fat, (unsigned int) last);
X	putfat(last, 0xfff);
X					/* zero the buffer */
X	buflen = clus_size * MSECSIZ;
X	for (i=0; i<buflen; i++)
X		tbuf[i] = '\0';
X
X					/* write the cluster */
X	sector = (last - 2) * clus_size + dir_start + dir_len;
X	move(sector);
X	if (write(fd, (char *) tbuf, buflen) != buflen) {
X		perror("grow: write");
X		exit(1);
X	}
X					/* fix up the globals.... */
X	num = dir_entries / 16;
X	dir_entries += clus_size * 16;
X	dir_chain[num] = sector;
X	if (clus_size == 2)
X		dir_chain[num+1] = sector +1;
X	return(0);
X}
SHAR_EOF
if test 2539 -ne "`wc -c < 'mkentry.c'`"
then
	echo shar: "error transmitting 'mkentry.c'" '(should have been 2539 characters)'
fi
fi
echo shar: "extracting 'mmd.c'" '(4058 characters)'
if test -f 'mmd.c'
then
	echo shar: "will not over-write existing file 'mmd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mmd.c'
X/*
X * Make a MSDOS sub directory
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int entry, slot, fat, dot, fargn, verbose;
X	char *filename, *newfile, *fixname(), *strncpy();
X	char *getpath(), *pathname, tname[9], text[4], *fixed, *unixname();
X	void exit(), putcluster(), writefat(), writedir(), free();
X	struct directory *dir, *search(), *mk_entry();
X	long time(), now;
X
X	if (init(2)) {
X		fprintf(stderr, "mmd: Cannot initialize diskette\n");
X		exit(1);
X	}
X
X	fargn = 1;
X	verbose = 0;
X	if (argc > 1) {
X		if (!strcmp(argv[1], "-v")) {
X			fargn = 2;
X			verbose = 1;
X		}
X	}
X					/* only 1 directory ! */
X	if (argc != fargn+1) {
X		fprintf(stderr, "Usage: mmd [-v] msdosdirectory\n");
X		exit(1);
X	}
X	fixed = fixname(argv[fargn], verbose);
X
X	strncpy(tname, fixed, 8);
X	strncpy(text, fixed+8, 3);
X	tname[8] = '\0';
X	text[3] = '\0';
X
X	filename = unixname(tname, text);
X	pathname = getpath(argv[fargn]);
X
X	if (subdir(pathname))
X		exit(1);
X					/* see if exists and get slot */
X	slot = -1;
X	dot = 0;
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0) {
X			if (slot < 0)
X				slot = entry;
X			break;
X		}
X					/* if erased */
X		if (dir->name[0] == 0xe5) {
X			if (slot < 0)
X				slot = entry;
X			continue;
X		}
X					/* if not a directory */
X		if (!(dir->attr & 0x10))
X			continue;
X
X		strncpy(tname, (char *) dir->name, 8);
X		strncpy(text, (char *) dir->ext, 3);
X		tname[8] = '\0';
X		text[3] = '\0';
X
X		newfile = unixname(tname, text);
X					/* save the 'dot' directory info */
X		if (!strcmp(".", newfile))
X			dot = dir->start[1]*0x100 + dir->start[0];
X
X		if (!strcmp(filename, newfile)) {
X			fprintf(stderr, "mmd: Directory \"%s\" already exists\n", filename);
X			exit(1);
X		}
X		free(newfile);
X	}
X					/* no '.' entry means root directory */
X	if (dot == 0 && slot < 0) {
X		fprintf(stderr, "mmd: No directory slots\n");
X		exit(1);
X	}
X					/* make the directory grow */
X	if (dot && slot < 0) {
X		if (grow(dot)) {
X			fprintf(stderr, "mmd: Disk full\n");
X			exit(1);
X		}
X					/* first slot in 'new' directory */
X		slot = entry;
X	}
X	if ((fat = nextfat(0)) == -1) {
X		fprintf(stderr, "mmd: Disk full\n");
X		exit(1);
X	}
X					/* make directory entry */
X	time(&now);
X	dir = mk_entry(fixed, 0x10, fat, 0L, now);
X	writedir(slot, dir);
X					/* write the cluster */
X	putfat(fat, 0xfff);
X	putcluster(fat, dot);
X					/* write FAT sectors */
X	writefat();
X	close(fd);
X	exit(0);
X}
X
X/*
X * Write a blank directory 'template' to the cluster starting at 'dot'.
X */
X
Xvoid
Xputcluster(dot, dot_dot)
Xint dot, dot_dot;
X{
X	int buflen, start;
X	static struct directory dirs[32];
X	struct directory *mk_entry();
X	void exit(), perror(), move();
X	long time(), now;
X
X	start = (dot - 2)*clus_size + dir_start + dir_len;
X	move(start);
X
X	buflen = clus_size * MSECSIZ;
X					/* make the '.' and '..' entries */	
X	time(&now);
X	dirs[0] = *mk_entry(".          ", 0x10, dot, 0L, now);
X	dirs[1] = *mk_entry("..         ", 0x10, dot_dot, 0L, now);
X
X	if (write(fd, (char *) &dirs[0], buflen) != buflen) {
X		perror("putcluster: write");
X		exit(1);
X	}
X	return;
X}
X
X/*
X * Returns next free cluster or -1 if none are available.
X */
X
Xint
Xnextfat(last)
Xint last;
X{
X	register int i;
X
X	for (i=last+1; i<num_clus+2; i++) {
X		if (!getfat(i))
X			return(i);
X	}
X	return(-1);
X}
SHAR_EOF
if test 4058 -ne "`wc -c < 'mmd.c'`"
then
	echo shar: "error transmitting 'mmd.c'" '(should have been 4058 characters)'
fi
fi
echo shar: "extracting 'mrd.c'" '(3277 characters)'
if test -f 'mrd.c'
then
	echo shar: "will not over-write existing file 'mrd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mrd.c'
X/*
X * Delete a MSDOS sub directory
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int ismatch, entry, start;
X	char *filename, *newfile, text[4], tname[9], *getname();
X	char *strncpy(), *pathname, *getpath(), *unixname();
X	void exit(), zapit(), writefat(), writedir(), free();
X	struct directory *dir, *search();
X
X	if (init(2)) {
X		fprintf(stderr, "mrd: Cannot initialize diskette\n");
X		exit(1);
X	}
X					/* only 1 directory ! */
X	if (argc != 2) {
X		fprintf(stderr, "Usage: mrd mdsosdirectory\n");
X		exit(1);
X	}
X
X	filename = getname(argv[1]);
X	pathname = getpath(argv[1]);
X	if (subdir(pathname))
X		exit(1);
X
X	ismatch = 0;
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0)
X			break;
X					/* if erased */
X		if (dir->name[0] == 0xe5)
X			continue;
X					/* if not dir */
X		if (!(dir->attr & 0x10))
X			continue;
X
X		strncpy(tname, (char *) dir->name, 8);
X		strncpy(text, (char *) dir->ext, 3);
X		tname[8] = '\0';
X		text[3] = '\0';
X
X		newfile = unixname(tname, text);
X		if (!strcmp(newfile, filename)) {
X			start = dir->start[1]*0x100 + dir->start[0];
X			if (!isempty(start)) {
X				fprintf(stderr, "mrd: Directory \"%s\" is not empty\n", filename);
X				exit(1);
X			}
X			if (!start) {
X				fprintf(stderr, "mrd: Can't remove root directory\n");
X				exit(1);
X			}
X			zapit(start);
X			dir->name[0] = 0xe5;
X			writedir(entry, dir);
X			ismatch = 1;
X		}
X		free(newfile);
X	}
X	if (!ismatch) {
X		fprintf(stderr, "mrd: Directory \"%s\" not found\n", filename);
X		exit(1);
X	}
X					/* update the FAT sectors */
X	writefat();
X	close(fd);
X	exit(0);
X}
X
X/*
X * See if directory is empty.  Returns 1 if empty, 0 if not.  Can't use
X * subdir() and search() as it would clobber the globals.
X */
X
Xint
Xisempty(fat)
Xint fat;
X{
X	register int i;
X	int next, buflen, sector;
X	unsigned char tbuf[CLSTRBUF];
X	void perror(), exit(), move();
X
X	while (1) {
X		sector = (fat-2)*clus_size + dir_start + dir_len;
X		move(sector);
X		buflen = clus_size * MSECSIZ;
X		if (read(fd, (char *) tbuf, buflen) != buflen) {
X			perror("isempty: read");
X			exit(1);
X		}
X					/* check first character of name */
X		for (i=0; i<MSECSIZ; i+=MDIRSIZ) {
X			if (tbuf[i] == '.')
X				continue;
X			if (tbuf[i] != 0x0 && tbuf[i] != 0xe5)
X				return(0);
X		}
X					/* get next cluster number */
X		next = getfat(fat);
X		if (next == -1) {
X			fprintf(stderr, "isempty: FAT problem\n");
X			exit(1);
X		}
X					/* end of cluster chain */
X		if (next >= 0xff8)
X			break;
X		fat = next;
X	}
X	return(1);
X}
SHAR_EOF
if test 3277 -ne "`wc -c < 'mrd.c'`"
then
	echo shar: "error transmitting 'mrd.c'" '(should have been 3277 characters)'
fi
fi
echo shar: "extracting 'mread.c'" '(5880 characters)'
if test -f 'mread.c'
then
	echo shar: "will not over-write existing file 'mread.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mread.c'
X/*
X * Read (copy) a MSDOS file to Unix
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "msdos.h"
X
X#define LOWERCASE
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xlong size;
Xlong current;
Xint textmode = 0;
Xint nowarn = 0;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X	int fat, i, ismatch, entry, single, c, oops, mod_time;
X	long mod_date, convstamp();
X	char *filename, *newfile, text[4], tname[9], *getname(), *unixname();
X	char *strncpy(), *pathname, *getpath(), *target, tmp[MAX_PATH];
X	char *strcat(), *strcpy();
X	void perror(), exit(), free();
X	struct directory *dir, *search();
X	struct stat stbuf;
X
X	if (init(0)) {
X		fprintf(stderr, "mread: Cannot initialize diskette\n");
X		exit(1);
X	}
X					/* get command line options */
X	oops = 0;
X	mod_time = 0;
X	while ((c = getopt(argc, argv, "tnm")) != EOF) {
X		switch(c) {
X			case 't':
X				textmode = 1;
X				break;
X			case 'n':
X				nowarn = 1;
X				break;
X			case 'm':
X				mod_time = 1;
X				break;
X			default:
X				oops = 1;
X				break;
X		}
X	}
X
X	if (oops || (argc - optind) < 2) {
X		fprintf(stderr, "Usage: mread [-tn] msdosfile unixfile\n");
X		fprintf(stderr, "    or mread [-tn] msdosfile [msdosfiles...] unixdirectory\n");
X		exit(1);
X	}
X					/* only 1 file to copy... */
X	single = 1;
X	target = argv[argc-1];
X					/* ...unless last arg is a directory */
X	if (!stat(target, &stbuf)) {
X		if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
X			single = 0;	
X	}
X					/* too many arguments */
X	if (single && (argc - optind) != 2) {
X		fprintf(stderr, "mread: too many arguments or destination directory omitted\n");
X		exit(1);
X	}
X
X	for (i=optind; i<argc-1; i++) {
X		filename = getname(argv[i]);
X		pathname = getpath(argv[i]);
X		if (subdir(pathname)) {
X			free(filename);
X			free(pathname);
X			continue;
X		}
X
X		ismatch = 0;
X		for (entry=0; entry<dir_entries; entry++) {
X			dir = search(entry);
X					/* if empty */
X			if (dir->name[0] == 0x0)
X				break;
X					/* if erased */
X			if (dir->name[0] == 0xe5)
X				continue;
X					/* if dir or volume lable */
X			if ((dir->attr & 0x10) || (dir->attr & 0x08))
X				continue;
X
X			strncpy(tname, (char *) dir->name, 8);
X			strncpy(text, (char *) dir->ext, 3);
X			tname[8] = '\0';
X			text[3] = '\0';
X
X			newfile = unixname(tname, text);
X			fat = dir->start[1]*0x100 + dir->start[0];
X			size = dir->size[2]*0x10000L + dir->size[1]*0x100 + dir->size[0];
X			if (mod_time)
X				mod_date = convstamp(dir->time, dir->date);
X			else
X				mod_date = 0L;
X
X					/* if single file */
X			if (single) {
X				if (!strcmp(newfile, filename)) {
X					readit(fat, target, mod_date);
X					ismatch = 1;
X					break;
X				}
X			}
X					/* if multiple files */
X			else {
X				if (match(newfile, filename)) {
X					printf("Copying %s\n", newfile);
X					strcpy(tmp, target);
X					strcat(tmp, "/");
X					strcat(tmp, newfile);
X					readit(fat, tmp, mod_date);
X					ismatch = 1;
X				}
X			}
X			free(newfile);
X		}
X		if (!ismatch)
X			fprintf(stderr, "mread: File \"%s\" not found\n", filename);
X		free(filename);
X		free(pathname);
X	}
X	close(fd);
X	exit(0);
X}
X
X/*
X * Decode the FAT chain given the begining FAT entry, open the named Unix
X * file for write.
X */
X
Xint
Xreadit(fat, target, mod_date)
Xint fat;
Xchar *target;
Xlong mod_date;
X{
X	char ans[10];
X	void exit(), getcluster();
X	FILE *fp;
X	struct stat stbuf;
X	struct utimbuf {
X		time_t actime;
X		time_t modtime;
X	} utbuf;
X
X#ifdef LOWERCASE
X	char *c;
X	c = target;
X	while(*c) {
X		if (isupper(*c))
X			*c = tolower(*c);
X		c++;
X	}
X#endif /* LOWERCASE */
X
X	current = 0L;
X	if (!nowarn) {
X		if (!access(target, 0)) {
X			while (1) {
X				printf("File \"%s\" exists, overwrite (y/n) ? ", target);
X				gets(ans);
X				if (ans[0] == 'n' || ans[0] == 'N')
X					return;
X				if (ans[0] == 'y' || ans[0] == 'Y')
X					break;
X			}
X					/* sanity checking */
X			if (!stat(target, &stbuf)) {
X				if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X					fprintf(stderr, "mread: \"%s\" is not a regular file\n", target);
X					return;
X				}
X			}
X		}
X	}
X
X	if (!(fp = fopen(target, "w"))) {
X		fprintf(stderr, "mread: Can't open \"%s\" for write\n", target);
X		return;
X	}
X
X	while (1) {
X		getcluster(fat, fp);
X					/* get next cluster number */
X		fat = getfat(fat);
X		if (fat == -1) {
X			fprintf(stderr, "mread: FAT problem\n");
X			exit(1);
X		}
X					/* end of cluster chain */
X		if (fat >= 0xff8)
X			break;
X	}
X	fclose(fp);
X					/* preserve mod times ? */
X	if (mod_date != 0L) {
X		utbuf.actime = mod_date;
X		utbuf.modtime = mod_date;
X		utime(target, &utbuf);
X	}
X	return;
X}
X
X/*
X * Read the named cluster, write to the Unix file descriptor.
X */
X
Xvoid
Xgetcluster(num, fp)
Xint num;
XFILE *fp;
X{
X	register int i;
X	int buflen, start;
X	unsigned char buf[CLSTRBUF];
X	void exit(), perror(), move();
X
X	start = (num - 2)*clus_size + dir_start + dir_len;
X	move(start);
X
X	buflen = clus_size * MSECSIZ;
X	if (read(fd, (char *) buf, buflen) != buflen) {
X		perror("getcluster: read");
X		exit(1);
X	}
X					/* stop at size not EOF marker */
X	for (i=0; i<buflen; i++) {
X		current++;
X		if (current > size) 
X			break;
X		if (textmode && buf[i] == '\r')
X			continue;
X		if (textmode && current == size && buf[i] == 0x1a)
X			continue;
X		fputc((char) buf[i], fp);
X	}
X	return;
X}
SHAR_EOF
if test 5880 -ne "`wc -c < 'mread.c'`"
then
	echo shar: "error transmitting 'mread.c'" '(should have been 5880 characters)'
fi
fi
echo shar: "extracting 'mren.c'" '(3153 characters)'
if test -f 'mren.c'
then
	echo shar: "will not over-write existing file 'mren.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mren.c'
X/*
X * Rename an existing MSDOS file
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int entry, ismatch, nogo, fargn, verbose, got_it;
X	char *filename, *newfile, *fixname(), *strncpy(), *unixname();
X	char *getpath(), *pathname, tname[9], text[4], *getname(), *target;
X	char *new, ans[10], *temp, *strcpy();
X	void exit(), writedir(), free();
X	struct directory *dir, *search();
X
X	if (init(2)) {
X		fprintf(stderr, "mren: Cannot initialize diskette\n");
X		exit(1);
X	}
X	fargn = 1;
X	verbose = 0;
X	if (argc > 1) {
X		if (!strcmp(argv[1], "-v")) {
X			fargn = 2;
X			verbose = 1;
X		}
X	}
X	if (argc != fargn+2) {
X		fprintf(stderr, "Usage: mren [-v] sourcefile targetfile\n");
X		exit(1);
X	}
X	filename = getname(argv[fargn]);
X	pathname = getpath(argv[fargn]);
X	if (subdir(pathname))
X		exit(1);
X
X	temp = getname(argv[fargn+1]);
X	target = fixname(argv[fargn+1], verbose);
X
X	strncpy(tname, target, 8);
X	strncpy(text, target+8, 3);
X	tname[8] = '\0';
X	text[3] = '\0';
X
X	new = unixname(tname, text);
X	nogo = 0;
X					/* the name supplied may be altered */
X	if (strcmp(temp, new) && verbose) {
X		while (!nogo) {
X			printf("Do you accept \"%s\" as the new file name (y/n) ? ", new);
X			gets(ans);
X			if (ans[0] == 'y' || ans[0] == 'Y')
X				break;
X			if (ans[0] == 'n' || ans[0] == 'N')
X				nogo = 1;
X		}
X	}
X	if (nogo)
X		exit(0);
X					/* see if exists and do it */
X	ismatch = 0;
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0)
X			break;
X					/* if erased */
X		if (dir->name[0] == 0xe5)
X			continue;
X					/* if volume label */
X		if (dir->attr == 0x08)
X			continue;
X					/* you may rename a directory */
X		strncpy(tname, (char *) dir->name, 8);
X		strncpy(text, (char *) dir->ext, 3);
X		tname[8] = '\0';
X		text[3] = '\0';
X
X		newfile = unixname(tname, text);
X
X					/* if the new name already exists */
X		if (!strcmp(new, newfile)) {
X			fprintf(stderr, "mren: File \"%s\" already exists\n", new);
X			exit(1);
X		}
X					/* if the old name exists */
X		if (!strcmp(filename, newfile)) {
X			ismatch = 1;
X			got_it = entry;
X		}
X		free(newfile);
X	}
X	if (!ismatch) {
X		fprintf(stderr, "mren: File \"%s\" not found\n", filename);
X		exit(1);
X	}
X					/* so go ahead and do it */
X	dir = search(got_it);
X	strncpy((char *) dir->name, target, 8);
X	strncpy((char *) dir->ext, target+8, 3);
X	writedir(got_it, dir);
X
X	close(fd);
X	exit(0);
X}
SHAR_EOF
if test 3153 -ne "`wc -c < 'mren.c'`"
then
	echo shar: "error transmitting 'mren.c'" '(should have been 3153 characters)'
fi
fi
echo shar: "extracting 'msdos.h'" '(868 characters)'
if test -f 'msdos.h'
then
	echo shar: "will not over-write existing file 'msdos.h'"
else
sed 's/^X//' << \SHAR_EOF > 'msdos.h'
X/*
X * msdos common header file
X */
X
X#define MSECSIZ	512			/* sector size */
X#define MDIRSIZ	32			/* directory size */
X#define CLSTRBUF 1024			/* largest cluster size */
X#define MAX_PATH 128
X
X/*
X * If your device driver does not support any of the following formats,
X * then leave those devices undefined.
X */
X
X#define	FLOPPY		"/dev/rflp"
X#define	FLP_40_8_1	"/dev/rflp40t8s1s"
X#define	FLP_40_8_2	"/dev/rflp40t8s2s"
X#define	FLP_40_9_1	"/dev/rflp40t9s1s"
X#define	FLP_40_9_2	"/dev/rflp40t9s2s"
X#define FLP_80_15_2	"/dev/rflp80t15s2s"
X
Xstruct directory {
X	unsigned char	name[8];	/* file name */
X	unsigned char	ext[3];		/* file extent */
X	unsigned char	attr;		/* attribute byte */
X	unsigned char	reserved[10];	/* ?? */
X	unsigned char	time[2];		
X	unsigned char	date[2];
X	unsigned char	start[2];	/* starting cluster number */
X	unsigned char	size[4];	/* size of the file */
X};
SHAR_EOF
if test 868 -ne "`wc -c < 'msdos.h'`"
then
	echo shar: "error transmitting 'msdos.h'" '(should have been 868 characters)'
fi
fi
echo shar: "extracting 'mtype.c'" '(3748 characters)'
if test -f 'mtype.c'
then
	echo shar: "will not over-write existing file 'mtype.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mtype.c'
X/*
X * Display contents of a MSDOS file
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xlong size;
Xlong current;
Xint stripmode = 0;
Xint textmode = 0;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X	int fat, i, ismatch, entry, c, oops;
X	char *filename, *newfile, text[4], tname[9], *getname(), *unixname();
X	char *strncpy(), *pathname, *getpath();
X	void exit(), readit(), free();
X	struct directory *dir, *search();
X
X	if (init(0)) {
X		fprintf(stderr, "mtype: Cannot initialize diskette\n");
X		exit(1);
X	}
X					/* get command line options */
X	oops = 0;
X	while ((c = getopt(argc, argv, "st")) != EOF) {
X		switch(c) {
X			case 's':
X				stripmode = 1;
X				break;
X			case 't':
X				textmode = 1;
X				break;
X			default:
X				oops = 1;
X				break;
X		}
X	}
X
X	if (oops || (argc - optind) < 1) {
X		fprintf(stderr, "Usage: mtype [-st] msdosfile [msdosfiles...]\n");
X		exit(1);
X	}
X
X	for (i=optind; i<argc; i++) {
X		filename = getname(argv[i]);
X		pathname = getpath(argv[i]);
X		if (subdir(pathname)) {
X			free(filename);
X			free(pathname);
X			continue;
X		}
X		ismatch = 0;
X		for (entry=0; entry<dir_entries; entry++) {
X			dir = search(entry);
X					/* if empty */
X			if (dir->name[0] == 0x0)
X				break;
X					/* if erased */
X			if (dir->name[0] == 0xe5)
X				continue;
X					/* if dir or volume label */
X			if ((dir->attr & 0x10) || (dir->attr & 0x08))
X				continue;
X
X			strncpy(tname, (char *) dir->name, 8);
X			strncpy(text, (char *) dir->ext, 3);
X			tname[8] = '\0';
X			text[3] = '\0';
X
X			newfile = unixname(tname, text);
X					/* see it if matches the pattern */
X			if (match(newfile, filename)) {
X				fat = dir->start[1]*0x100 + dir->start[0];
X				size = dir->size[2]*0x10000L + dir->size[1]*0x100 + dir->size[0];
X				readit(fat);
X				ismatch = 1;
X			}
X			free(newfile);
X		}
X		if (!ismatch)
X			fprintf(stderr, "mtype: File \"%s\" not found\n", filename);
X		free(filename);
X		free(pathname);
X	}
X	close(fd);
X	exit(0);
X}
X
X/*
X * Decode the FAT chain given the begining FAT entry.
X */
X
Xvoid
Xreadit(fat)
Xint fat;
X{
X	void getcluster();
X
X	current = 0L;
X	while (1) {
X		getcluster(fat);
X					/* get next cluster number */
X		fat = getfat(fat);
X		if (fat == -1) {
X			fprintf(stderr, "mtype: FAT problem\n");
X			exit(1);
X		}
X					/* end of cluster chain */
X		if (fat >= 0xff8)
X			break;
X	}
X	return;
X}
X
X/*
X * Read the named cluster, output to the stdout.
X */
X
Xvoid
Xgetcluster(num)
Xint num;
X{
X	register int i;
X	int buflen, start;
X	unsigned char buf[CLSTRBUF];
X	void exit(), perror(), move();
X
X	start = (num - 2)*clus_size + dir_start + dir_len;
X	move(start);
X
X	buflen = clus_size * MSECSIZ;
X	if (read(fd, (char *) buf, buflen) != buflen) {
X		perror("getcluster: read");
X		exit(1);
X	}
X					/* stop at size not EOF marker */
X	for (i=0; i<buflen; i++) {
X		current++;
X		if (current > size) 
X			break;
X		if (textmode && buf[i] == '\r')
X			continue;
X		if (textmode && current == size && buf[i] == 0x1a)
X			continue;
X		if (stripmode)
X			putchar(buf[i] & 0x7f);
X		else
X			putchar(buf[i]);
X	}
X	return;
X}
SHAR_EOF
if test 3748 -ne "`wc -c < 'mtype.c'`"
then
	echo shar: "error transmitting 'mtype.c'" '(should have been 3748 characters)'
fi
fi
echo shar: "extracting 'mwrite.c'" '(8266 characters)'
if test -f 'mwrite.c'
then
	echo shar: "will not over-write existing file 'mwrite.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mwrite.c'
X/*
X * Write (copy) a Unix file to MSDOS
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * 					Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "msdos.h"
X
Xint fd;				/* the file descriptor for the floppy */
Xint dir_start;			/* starting sector for directory */
Xint dir_len;			/* length of directory (in sectors) */
Xint dir_entries;		/* number of directory entries */
Xint dir_chain[25];		/* chain of sectors in directory */
Xint clus_size;			/* cluster size (in sectors) */
Xint fat_len;			/* length of FAT table (in sectors) */
Xint num_clus;			/* number of available clusters */
Xunsigned char *fatbuf;		/* the File Allocation Table */
Xchar *mcwd;			/* the Current Working Directory */
X
Xint full = 0;
Xint textmode = 0;
Xint nowarn = 0;
Xlong filesize;
Xint need_nl = 0;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X	int i, entry, ismatch, nogo, slot, start, dot, single;
X	int root, c, oops, verbose, first, mod_time;
X	char *filename, *newfile, tname[9], text[4], *fixname(), *getname();
X	char *unixname(), ans[10], *strncpy(), *pathname, *getpath(), *fixed;
X	char tmp[MAX_PATH], *target, *strcat(), *strcpy();
X	void exit(), zapit(), writefat(), writedir(), free();
X	struct directory *dir, *search(), *writeit();
X
X	if (init(2)) {
X		fprintf(stderr, "mwrite: Cannot initialize diskette\n");
X		exit(1);
X	}
X					/* get command line options */
X	oops = 0;
X	verbose = 0;
X	mod_time = 0;
X	while ((c = getopt(argc, argv, "tnvm")) != EOF) {
X		switch(c) {
X			case 't':
X				textmode = 1;
X				break;
X			case 'n':
X				nowarn = 1;
X				break;
X			case 'v':
X				verbose = 1;
X				break;
X			case 'm':
X				mod_time = 1;
X				break;
X			default:
X				oops = 1;
X				break;
X		}
X	}
X
X	if (oops || (argc - optind) < 2) {
X		fprintf(stderr, "Usage: mwrite [-tnv] unixfile msdosfile\n");
X		fprintf(stderr, "    or mwrite [-tnv] unixfile [unixfiles...] msdosdirectory\n");
X		exit(1);
X	}
X	root = 0;
X	if (!strcmp(argv[argc-1], "/") || !strcmp(argv[argc-1], "\\"))
X		root = 1;
X
X	filename = getname(argv[argc-1]);
X	pathname = getpath(argv[argc-1]);
X					/* test if path is ok first */
X	if (subdir(pathname))
X		exit(1);
X					/* test if last argv is a dir */
X	if (isdir(filename) || root) {
X		if (!strlen(pathname)) {
X					/* don't alter the presence or */
X					/* absence of a leading separator */
X			strcpy(tmp, filename);
X		}
X		else {
X			strcpy(tmp, pathname);
X			strcat(tmp, "/");
X			strcat(tmp, filename);
X		}
X					/* subdir is not recursive */
X		subdir(tmp);
X		single = 0;
X	}
X	else {
X		single = 1;
X					/* too many arguments */
X		if ((argc - optind) != 2) {
X			fprintf(stderr, "mwrite: too many arguments or destination directory omitted\n");
X			exit(1);
X		}
X	}
X
X	for (i=optind; i<argc-1; i++) {
X		if (single)
X			fixed = fixname(argv[argc-1], verbose);
X		else
X			fixed = fixname(argv[i], verbose);
X
X		strncpy(tname, fixed, 8);
X		strncpy(text, fixed+8, 3);
X		tname[8] = '\0';
X		text[3] = '\0';
X
X		target = unixname(tname, text);
X					/* see if exists and get slot */
X		ismatch = 0;
X		slot = -1;
X		dot = 0;
X		nogo = 0;
X		first = 1;
X		for (entry=0; entry<dir_entries; entry++) {
X			dir = search(entry);
X					/* save the '.' entry info */
X			if (first) {
X				first = 0;
X				if ((dir->attr & 0x10) && dir->name[0] == '.') {
X					dot = dir->start[1]*0x100 + dir->start[0];
X					continue;
X				}
X			}
X					/* is empty */
X			if (dir->name[0] == 0x0) {
X				if (slot < 0)
X					slot = entry;
X				break;
X			}
X					/* is erased */
X			if (dir->name[0] == 0xe5) {
X				if (slot < 0)
X					slot = entry;
X				continue;
X			}
X					/* is dir or volume lable */
X			if ((dir->attr & 0x10) || (dir->attr & 0x08))
X				continue;
X
X			strncpy(tname, (char *) dir->name, 8);
X			strncpy(text, (char *) dir->ext, 3);
X			tname[8] = '\0';
X			text[3] = '\0';
X
X			newfile = unixname(tname, text);
X					/* if file exists, delete it first */
X			if (!strcmp(target, newfile)) {
X				ismatch = 1;
X				start = dir->start[1]*0x100 + dir->start[0];
X				if (nowarn) {
X					zapit(start);
X					dir->name[0] = 0xe5;
X					writedir(entry, dir);
X					if (slot < 0)
X						slot = entry;
X				} else {
X					while (1) {
X						printf("File \"%s\" exists, overwrite (y/n) ? ", target);
X						gets(ans);
X						if (ans[0] == 'n' || ans[0] == 'N') {
X							nogo = 1;
X							break;
X						}
X						if (ans[0] == 'y' || ans[0] == 'Y') {
X							zapit(start);
X							dir->name[0] = 0xe5;
X							writedir(entry, dir);
X							if (slot < 0)
X								slot = entry;
X							break;
X						}
X					}
X				}
X			}
X			free(newfile);
X			if (ismatch)
X				break;
X		}
X		if (nogo) {		/* chickened out... */
X			free(fixed);
X			free(target);
X			continue;
X		}
X					/* no '.' entry means root directory */
X		if (dot == 0 && slot < 0) {
X			fprintf(stderr, "mwrite: No directory slots\n");
X			exit(1);
X		}
X					/* make the directory grow */
X		if (dot && slot < 0) {
X			if (grow(dot)) {
X				fprintf(stderr, "mwrite: Disk full\n");
X				exit(1);
X			}
X					/* first entry in 'new' directory */
X			slot = entry;
X		}
X		if (!single)
X			printf("Copying %s\n", target);
X					/* write the file */
X		if (dir = writeit(fixed, argv[i], verbose, mod_time))
X			writedir(slot, dir);
X
X		free(fixed);
X		free(target);
X
X		if (full) {
X			fprintf(stderr, "mwrite: Disk Full\n");
X			break;
X		}
X		if (single)
X			break;
X	}
X					/* write FAT sectors */
X	writefat();
X	close(fd);
X	exit(0);
X}
X
X/*
X * Open the named file for write, create the cluster chain, return the
X * directory structure or NULL on error.
X */
X
Xstruct directory *
Xwriteit(fixed, path, verbose, mod_time)
Xchar *fixed, *path;
Xint verbose, mod_time;
X{
X	FILE *fp;
X	int fat, firstfat, oldfat;
X	long size, time(), now;
X	struct directory *dir, *mk_entry();
X	struct stat stbuf;
X
X	if (stat(path, &stbuf) < 0) {
X		fprintf(stderr, "mwrite: Can't stat \"%s\"\n", path);
X		return(NULL);
X	}
X
X	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
X		if (verbose)
X			fprintf(stderr, "mwrite: \"%s\" is a directory\n", path);
X		return(NULL);
X	}
X
X	if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X		fprintf(stderr, "mwrite: \"%s\" is not a regular file\n", path);
X		return(NULL);
X	}
X	filesize = stbuf.st_size;
X					/* preserve mod time? */
X	if (mod_time)
X		now = stbuf.st_mtime;
X	else
X		time(&now);
X
X	if (!(fp = fopen(path, "r"))) {
X		fprintf(stderr, "mwrite: Can't open \"%s\" for read\n", path);
X		return(NULL);
X	}
X	size = 0L;
X	firstfat = nextfat(0);
X	if (firstfat == -1) {
X		full = 1;
X		return(NULL);
X	}
X	fat = firstfat;
X	while (1) {
X		size += putcluster(fat, fp);
X		if (size >= filesize) {
X			putfat(fat, 0xfff);
X			break;
X		}
X		oldfat = fat;
X					/* get next free cluster */
X		fat = nextfat(oldfat);
X		if (fat == -1) {
X			putfat(oldfat, 0xfff);
X			zapit(firstfat);
X			full = 1;
X			return(NULL);
X		}
X		putfat(oldfat, (unsigned int) fat);
X	}
X	fclose(fp);
X	dir = mk_entry(fixed, 0x20, firstfat, size, now);
X	return(dir);
X}
X
X/*
X * Write to the cluster from the named Unix file descriptor.
X */
X
Xint
Xputcluster(num, fp)
Xint num;
XFILE *fp;
X{
X	int buflen, c, start, current;
X	unsigned char tbuf[CLSTRBUF];
X	void exit(), perror(), move();
X
X	start = (num - 2)*clus_size + dir_start + dir_len;
X	move(start);
X
X	buflen = clus_size * MSECSIZ;
X					/* '\n' to '\r\n' translation */
X	if (textmode) {
X		current = 0;
X		if (need_nl) {
X			tbuf[current++] = '\n';
X			need_nl = 0;
X		}
X		while (current < buflen) {
X			if ((c = fgetc(fp)) == EOF) {
X					/* put a file EOF marker */
X				tbuf[current++] = 0x1a;
X					/* make the file appear larger */
X				filesize++;
X				break;
X			}
X			if (c == '\n') {
X				tbuf[current++] = '\r';
X					/* make the file appear larger */
X				filesize++;
X					/* if at the end of the buffer */
X				if (current == buflen) {
X					need_nl++;
X					break;
X				}
X			}
X			tbuf[current++] = c;
X		}
X	}
X	else {
X		if ((current = fread((char *) tbuf, sizeof(*tbuf), buflen, fp)) < 0) {
X			perror("putcluster: fread");
X			exit(1);
X		}
X	}
X	
X	if (write(fd, (char *) tbuf, buflen) != buflen) {
X		perror("putcluster: write");
X		exit(1);
X	}
X	return(current);
X}
X
X/*
X * Returns next free cluster or -1 if none are available.
X */
X
Xint
Xnextfat(last)
Xint last;
X{
X	register int i;
X
X	for (i=last+1; i<num_clus+2; i++) {
X		if (!getfat(i))
X			return(i);
X	}
X	return(-1);
X
X}
SHAR_EOF
if test 8266 -ne "`wc -c < 'mwrite.c'`"
then
	echo shar: "error transmitting 'mwrite.c'" '(should have been 8266 characters)'
fi
fi
echo shar: "extracting 'putfat.c'" '(2561 characters)'
if test -f 'putfat.c'
then
	echo shar: "will not over-write existing file 'putfat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'putfat.c'
X/*
X * putfat(), writedir(), zapit()
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xextern int fd, fat_len, dir_chain[25];
Xextern unsigned char *fatbuf;
X
X/*
X * Puts a code into the FAT table.  Is the opposite of getfat().  No
X * sanity checking is done on the code.  Returns a 1 on error.
X */
X
Xint
Xputfat(num, code)
Xint num;
Xunsigned int code;
X{
X/*
X *	|    byte n     |   byte n+1    |   byte n+2    |
X *	|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
X *	| | | | | | | | | | | | | | | | | | | | | | | | |
X *	|  n.0  |  n.5  | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
X *	    \_____  \____   \______/________/_____   /
X *	      ____\______\________/   _____/  ____\_/
X *	     /     \      \          /       /     \
X *	| n+1.5 |  n.0  |  n.5  | n+2.0 | n+2.5 | n+1.0 |
X *	|      FAT entry k      |    FAT entry k+1      |
X */
X	int start;
X					/* which bytes contain the entry */
X	start = num * 3 / 2;
X	if (start < 0 || start+1 > (fat_len * MSECSIZ))
X		return(1);
X					/* (odd) not on byte boundary */
X	if (num % 2) {
X		*(fatbuf+start) = (*(fatbuf+start) & 0x0f) + ((code << 4) & 0xf0);
X		*(fatbuf+start+1) = (code >> 4) & 0xff;
X	}
X					/* (even) on byte boundary */
X	else {
X		*(fatbuf+start) = code & 0xff;
X		*(fatbuf+start+1) = (*(fatbuf+start+1) & 0xf0) + ((code >> 8) & 0x0f);
X	}
X	return(0);
X}
X
X/*
X * Write a directory entry.  The first argument is the directory entry
X * number to write to.  The second is a pointer to the directory itself.
X * All errors are fatal.
X */
X
Xvoid
Xwritedir(num, dir)
Xint num;
Xstruct directory *dir;
X{
X	int skip, entry;
X	struct directory dirs[16];
X	void exit(), perror(), move();
X					/* which sector */
X	skip = dir_chain[num / 16];
X
X	move(skip);
X					/* read the sector */
X	if (read(fd, (char *) &dirs[0], MSECSIZ) != MSECSIZ) {
X		perror("writedir: read");
X		exit(1);
X	}
X					/* which entry in sector */
X	entry = num % 16;
X					/* copy the structure */
X	dirs[entry] = *dir;
X	move(skip);
X					/* write the sector */
X	if (write(fd, (char *) &dirs[0], MSECSIZ) != MSECSIZ) {
X		perror("writedir: write");
X		exit(1);
X	}
X	return;
X}
X
X/*
X * Remove a string of FAT entries (delete the file).  The argument is
X * the beginning of the string.  Does not consider the file length, so
X * if FAT is corrupted, watch out!  All errors are fatal.
X */
X
Xvoid
Xzapit(fat)
Xint fat;
X{
X	int next;
X
X	while (1) {
X					/* get next cluster number */
X		next = getfat(fat);
X					/* mark current cluster as empty */
X		if (putfat(fat, 0) || next == -1) {
X			fprintf(stderr, "zapit: FAT problem\n");
X			exit(1);
X		}
X		if (next >= 0xff8)
X			break;
X		fat = next;
X	}
X	return;
X}
SHAR_EOF
if test 2561 -ne "`wc -c < 'putfat.c'`"
then
	echo shar: "error transmitting 'putfat.c'" '(should have been 2561 characters)'
fi
fi
echo shar: "extracting 'search.c'" '(1083 characters)'
if test -f 'search.c'
then
	echo shar: "will not over-write existing file 'search.c'"
else
sed 's/^X//' << \SHAR_EOF > 'search.c'
X/*
X * Search and extract a directory structure.  The argument is the
X * relative directory entry number (no sanity checking).  It returns a
X * pointer to the directory structure at that location.  Attempts to
X * optimize by trying to determine if the buffer needs to be re-read.
X * A call to writedir() will scribble on the real buffer, so watch out!
X */
X
X#include <stdio.h>
X#include "msdos.h"
X				/* dir_chain contains the list of sectors */
X				/* that make up the current directory */
Xextern int fd, dir_chain[25];
X
Xstruct directory *
Xsearch(num)
Xint num;
X{
X	int skip, entry;
X	static int last;
X	static struct directory dirs[16];
X	void exit(), perror(), move();
X
X					/* first call disables optimzation */
X	if (num == 0)
X		last = 0;
X					/* which sector */
X	skip = dir_chain[num / 16];
X					/* don't read it if same sector */
X	if (skip != last) {
X		move(skip);
X					/* read the sector */
X		if (read(fd, (char *) &dirs[0], MSECSIZ) != MSECSIZ) {
X			perror("mread: read");
X			exit(1);
X		}
X	}
X	last = skip;
X					/* which entry in sector */
X	entry = num % 16;
X	return(&dirs[entry]);
X}
SHAR_EOF
if test 1083 -ne "`wc -c < 'search.c'`"
then
	echo shar: "error transmitting 'search.c'" '(should have been 1083 characters)'
fi
fi
echo shar: "extracting 'subdir.c'" '(3775 characters)'
if test -f 'subdir.c'
then
	echo shar: "will not over-write existing file 'subdir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'subdir.c'
X/*
X * subdir(), getdir(), get_chain(), reset_dir()
X */
X
X#include <stdio.h>
X#include "msdos.h"
X
Xextern int dir_chain[25], dir_start, dir_len, dir_entries, clus_size;
Xextern char *mcwd;
Xstatic char lastpath[MAX_PATH];
X
X/*
X * Parse the path names of a sub directory.  Both '/' and '\' are
X * valid separators.  However, the use of '\' will force the operator
X * to use quotes in the command line to protect '\' from the shell.
X * Returns 1 on error.  Attempts to optimize by remembering the last
X * path it parsed
X */
X
Xint
Xsubdir(name)
Xchar *name;
X{
X	char *s, *tmp, tbuf[MAX_PATH], *path, *strcpy(), *strcat();
X	int code;
X	void reset_dir();
X					/* if full pathname */
X	if (*name == '/' || *name == '\\')
X		strcpy(tbuf, name);
X					/* if relative to MCWD */
X	else {
X		if (!strlen(name))
X			strcpy(tbuf, mcwd);
X		else {
X			strcpy(tbuf, mcwd);
X			strcat(tbuf, "/");
X			strcat(tbuf, name);
X		}
X	}
X					/* if paths are same, do nothing */
X	if (!strcmp(tbuf, lastpath))
X		return(0);
X					/* not recursive, start at root */
X	reset_dir();
X	strcpy(lastpath, tbuf);
X					/* zap the leading separator */
X	tmp = tbuf;
X	if (*tmp == '\\' || *tmp == '/')
X		tmp++;
X	for (s = tmp; *s; ++s) {
X		if (*s == '\\' || *s == '/') {
X			path = tmp;
X			*s = '\0';
X			if (getdir(path))
X				return(1);
X			tmp = s+1;
X		}
X	}
X	code = getdir(tmp);
X	return(code);
X}
X
X/*
X * Find the directory and get the starting cluster.  A null directory
X * is ok.  Returns a 1 on error.
X */
X
Xint
Xgetdir(path)
Xchar *path;
X{
X	int entry, start;
X	char *newname, *unixname(), *strncpy(), name[9], ext[4];
X	struct directory *dir, *search();
X	void reset_dir(), free();
X					/* nothing required */
X	if (*path == '\0')
X		return(0);
X
X	for (entry=0; entry<dir_entries; entry++) {
X		dir = search(entry);
X					/* if empty */
X		if (dir->name[0] == 0x0)
X			break;
X					/* if erased */
X		if (dir->name[0] == 0xe5)
X			continue;
X					/* skip if not a directory */
X		if (!(dir->attr & 0x10))
X			continue;
X
X		strncpy(name, (char *) dir->name, 8);
X		strncpy(ext, (char *) dir->ext, 3);
X		name[8] = '\0';
X		ext[3] = '\0';
X
X		newname = unixname(name, ext);
X		if (!strcmp(newname, path)) {
X			start = dir->start[1]*0x100 + dir->start[0];
X					/* if '..' pointing to root */
X			if (!start && !strcmp(path, "..")) {
X				reset_dir();
X				return(0);
X			}
X					/* fill in the directory chain */
X			dir_entries = get_chain(start) * 16;
X			return(0);
X		}
X		free(newname);
X	}
X					/* if '.' or '..', must be root */
X	if (!strcmp(path, ".") || !strcmp(path, "..")) {
X		reset_dir();
X		return(0);
X	}
X	fprintf(stderr, "Path component \"%s\" is not a directory\n", path);
X	return(1);
X}
X
X/*
X * Fill in the global variable dir_chain.  Argument is the starting
X * cluster number.  Info, in this variable is used by search() to 
X * scan a directory.  An arbitrary limit of 25 sectors is placed, this
X * equates to 400 entries.  Returns the number of sectors in the chain.
X */
X
Xint
Xget_chain(num)				/* fill the directory chain */
Xint num;
X{
X	int i, next;
X	void exit();
X
X	i = 0;
X	while (1) {
X		dir_chain[i] = (num - 2)*clus_size + dir_start + dir_len;
X					/* sectors, not clusters! */
X		if (clus_size == 2) {
X			dir_chain[i+1] = dir_chain[i] + 1;
X			i++;
X		}
X		i++;
X		if (i >= 25) {
X			fprintf(stderr, "get_chain: directory too large\n");
X			exit(1);
X		}
X					/* get next cluster number */
X		next = getfat(num);
X		if (next == -1) {
X			fprintf(stderr, "get_chain: FAT problem\n");
X			exit(1);
X		}
X					/* end of cluster chain */
X		if (next >= 0xff8) {
X			break;
X		}
X		num = next;
X	}
X	return(i);
X}
X
X/* 
X * Reset the global variable dir_chain to the root directory.
X */
X
Xvoid
Xreset_dir()
X{
X	register int i;
X
X	for (i=0; i<dir_len; i++)
X		dir_chain[i] = dir_start + i;
X	dir_entries = dir_len * 16;
X					/* disable subdir() optimization */
X	lastpath[0] = '\0';
X	return;
X}
SHAR_EOF
if test 3775 -ne "`wc -c < 'subdir.c'`"
then
	echo shar: "error transmitting 'subdir.c'" '(should have been 3775 characters)'
fi
fi
echo shar: "extracting 'unixname.c'" '(2215 characters)'
if test -f 'unixname.c'
then
	echo shar: "will not over-write existing file 'unixname.c'"
else
sed 's/^X//' << \SHAR_EOF > 'unixname.c'
X/*
X * unixname(), getname(), getpath()
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "msdos.h"
X
X/*
X * Get rid of spaces in a MSDOS 'raw' name (one that has come from the
X * directory structure) so that it can be used for regular expression
X * matching with a unix file name.  Also used to 'unfix' a name that has
X * been altered by fixname().  Returns a pointer to the unix style name.
X */
X
Xchar *
Xunixname(name, ext)
Xchar *name, *ext;
X{
X	char *s, tname[9], text[4], *strcpy(), *strcat(), *strchr();
X	char *ans, *malloc();
X
X	strcpy(tname, name);
X	if (s = strchr(tname, ' '))
X		*s = '\0';
X
X	strcpy(text, ext);
X	if (s = strchr(text, ' '))
X		*s = '\0';
X
X	ans = malloc(13);
X
X	if (*text) {
X		strcpy(ans, tname);
X		strcat(ans, ".");
X		strcat(ans, text);
X	}
X	else
X		strcpy(ans, tname);
X	return(ans);
X}
X
X/*
X * Get name component of filename.  Translates name to upper case.  Returns
X * pointer to new name.
X */
X
Xchar *
Xgetname(filename)
Xchar *filename;
X{
X	char *s, *ans, *malloc(), *temp, *strcpy(), *strrchr();
X	char buf[MAX_PATH];
X
X	strcpy(buf, filename);
X	temp = buf;
X					/* find the last separator */
X	if (s = strrchr(temp, '/'))
X		temp = s+1;
X	if (s = strrchr(temp, '\\'))
X		temp = s+1;
X					/* xlate to upper case */
X	for (s = temp; *s; ++s) {
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X
X	ans = malloc((unsigned int) strlen(temp)+1);
X	strcpy(ans, temp);
X	return(ans);
X}
X
X/*
X * Get the path component of the filename.  Translates to upper case.
X * Returns pointer to path.  Doesn't alter leading separator, always
X * strips trailing separator (unless it is the path itself).
X */
X
Xchar *
Xgetpath(filename)
Xchar *filename;
X{
X	char *s, *temp, *ans, *malloc(), *strcpy(), *strrchr();
X	char buf[MAX_PATH];
X	int has_sep;
X
X	strcpy(buf, filename);
X	temp = buf;
X					/* find last separator */
X	has_sep = 0;
X	if (s = strrchr(temp, '/')) {
X		has_sep++;
X		temp = s;
X	}
X	if (s = strrchr(temp, '\\')) {
X		has_sep++;
X		temp = s;
X	}
X
X	*temp = '\0';
X					/* translate to upper case */
X	for (s = buf; *s; ++s) {
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X					/* if separator alone, put it back */
X	if (!strlen(buf) && has_sep)
X		strcpy(buf, "/");
X
X	ans = malloc((unsigned int) strlen(buf)+1);
X	strcpy(ans, buf);
X	return(ans);
X}
SHAR_EOF
if test 2215 -ne "`wc -c < 'unixname.c'`"
then
	echo shar: "error transmitting 'unixname.c'" '(should have been 2215 characters)'
fi
fi
exit 0
#	End of shell archive