[comp.unix.aux] HFS library for AUX

liam@cs.qmc.ac.uk (William Roberts) (08/15/88)

#         This is a shar archive.
#         Remove everything above and including the cut line.
#         Then run the rest of the file through sh.
#--------cut--------cut--------cut--------cut--------cut--------
#! /bin/sh
#  shar:  Shell Archiver
#         Run the following with /bin/sh to create:
#             README
#             README.ptab
#             Makefile
#             copyright
#             document
#             maccopy.1
#             macls.c.patch
# This archive created: Mon Aug 15 17:54:16 WET DST 1988
echo shar: extracting "README" '('1999 chars')'
if test -f README
then
    echo shar: will not overwrite existing file "README"
else
cat << \SHAR_EOF > README
This is the first version of an A/UX library for reading HFS
disk partitions. It was written by Matthew Kempthorne-Ley-Edwards
for the Department of Computer Science at Queen Mary College,
and is supplied as a library of routines plus some include files.

There are two example programs:

        maccopy - copies a MacOS file from the HFS disk to A/UX
        macls   - like ls but operates on the HFS partition

Unfortunately macls is essentially just the Berkeley "ls"
program and therefore cannot be distributed to non-source
licencees: it is therefore included as a context-diff file
suitable for use with patch.

Fortunately, the library works but providing a Mac equivalent
of all of the read-only file system calls, namely

        open read write lseek stat lstat close
        opendir telldir seekdir rewinddir closedir readdir

and the stdio routines

        fopen fseek fread fwrite fclose rewind ftell

together with .h files that redefine the world so that your
program uses the Mac versions rather than the AUX versions. If
you look at the patches for macls then you will see that it
basically cuts out some things we didn't know that A/UX could
do (isatty) and sticks in the right include files, amongst
others "macdir.h". Everything else is completely standard.

For those that want both HFS and AUX, there is an include file
"undodefs.h" which removes these helpful #defines: it is then
up to you to call Mac_X for each routine. For an example, see
the maccopy routine.


THIS IS A PRELIMINARY VERSION - more will be done.

However, you can help us by sending any bug {reports,fixes} to

        aux@qmc-cs.UUCP

together with any suggestions for improvements or additional
information that is needed so that we can WRITE to HFS. The
file "document" contains the information we currently have
about the HFS disk data structures, together with a summary of
what else we need to know...


Hope this is useful to you - please feel free to pass it on
(see the copyright file though).
SHAR_EOF
if test 1999 -ne `wc -c < README`
then
    echo shar: error transmitting "README" '('should be 1999 chars')'
else
    echo README
fi
fi
echo shar: extracting "README.ptab" '('358 chars')'
if test -f README.ptab
then
    echo shar: will not overwrite existing file "README.ptab"
else
cat << \SHAR_EOF > README.ptab
In order to use the maccopy and macls utilities,
the MacOS partition on the hard disk must be accessible as a
device. A suitable ptab entry is

	MacOS:Apple_HFS:0:0:16

which associates the MacOS partition with /dev/dsk/c0d0s16
Such an entry can be generated by

	/etc/pname -c 0 -d 0 -s 16 -t Apple_HFS MacOS

(Or at least, I think that was what we did...)
SHAR_EOF
if test 358 -ne `wc -c < README.ptab`
then
    echo shar: error transmitting "README.ptab" '('should be 358 chars')'
else
    echo README.ptab
fi
fi
echo shar: extracting "Makefile" '('1205 chars')'
if test -f Makefile
then
    echo shar: will not overwrite existing file "Makefile"
else
cat << \SHAR_EOF > Makefile
#
#
# Makefile for Apple mac - unix filestores
#
#       programs
#               macls, maccopy
#
#
#
#       Written by
#
#       Matthew Kempthorne-Ley-Edwards
#
#            Devonshire House
#               34c Gyllyng St.
#                  Falmouth
#                    Cornwall
#                       TR11 3EL
#
#
# (c) 1988 Queen Mary College, University of London
#

CFLAGS  =       -g

GOBJS   =       extents.o fcb.o rootblock.o bstar.o unixdir.o stat.o \
		files.o

GSRCS   =       extents.c fcb.c rootblock.c bstar.c unixdir.c stat.c \
		files.c

SRCS    =       $(GSRCS) macls.c maccopy.c

OBJS    =       $(GOBJS) macls.o maccopy.o

LIBS    =

all     :       libhfs.a macls maccopy

extents.o fcb.o rootblock.o bstar.o : disc.h
unixdir.o stat.o                : macdir.h disc.h
files.o                         : macfile.h macdir.h disc.h
macls.o                         : macfile.h macdir.h disc.h
maccopy.o                       : macfile.h macdir.h disc.h



$(GOBJS)   :    $(GSRCS)

libhfs.a:       ${GOBJS}
	ar ru libhfs.a $?


macls:  macls.o libhfs.a
	cc ${CFLAGS} -o macls macls.o libhfs.a ${LIBS}

maccopy:  maccopy.o libhfs.a
	cc ${CFLAGS} -o maccopy maccopy.o libhfs.a ${LIBS}
SHAR_EOF
if test 1205 -ne `wc -c < Makefile`
then
    echo shar: error transmitting "Makefile" '('should be 1205 chars')'
else
    echo Makefile
fi
fi
echo shar: extracting "copyright" '('515 chars')'
if test -f copyright
then
    echo shar: will not overwrite existing file "copyright"
else
cat << \SHAR_EOF > copyright
/*
 * A/UX HFS library. Version 1.0
 *
 * Copyright: Matthew Kempthorne-Ley-Edwards, August 1988
 *
 * for  Department of Computer Science
 *      Queen Mary College
 *      London  E1 4NS
 *      UK
 *
 * This software is provisional and carries no guarantee of fitness
 * for any purpose. It may be freely copied provided this copyright
 * message included in any such distribution. It may not be sold or
 * incorporated into any product without prior permission of both
 * the author and Queen Mary College.
 */
SHAR_EOF
if test 515 -ne `wc -c < copyright`
then
    echo shar: error transmitting "copyright" '('should be 515 chars')'
else
    echo copyright
fi
fi
echo shar: extracting "document" '('19867 chars')'
if test -f document
then
    echo shar: will not overwrite existing file "document"
else
cat << \SHAR_EOF > document

The Macintosh Filestore Layout.


This document is split into 3 sections, and is basically a reference document.


        Section 1               Disc layout ( of sectors )

        Section 2               How to read files

        Section 3               About BStar trees

        Section 4               The Dir tree file & entries

        Section 5               Things not yet known




The information herein was derived from pages IV-160 to IV-174 of
        the Inside Macintosh books ( Volume IV ).
        ( With some calculated guess work )





############################## SECTION 1 ################################


                                Disc Layout


        1.1 - What sectors hold what info.
        1.2 - What info is stored about the disc ( in sector block 2 )


NOTE :
        The normal discs ( floppys and hard disc ) use 512 byte sectors
        and  1 sector per allocation block ( ie the allocation size is the
        same as the sector size of 512 bytes )


#1.1    The disc is split into 4 sections as shown below.


                +---------------+
        Block 0 |               |
                |  System Start |
                +-             -+       Used for mac boot etc.
        Block 1 |  info         |
                |               |
                +---------------+
        Block 2 | Volume info   |       Information about the disc (See 1.2)
                | - - - - - - - |
                +---------------+
        Block 3 |               |       Bit map holding 1 for used allocation
          .     | Disc Usage    |                       0 if unused
                |  Bit map      |
         a-1    | - - - - - - - |
                +---------------+
          a     | Allocation    |       The disc is then considered as
          .     |       0       |       Allocation blocks of 'n' sectors
          .     +---------------+       each, starting at sector 'a',
         a+n    | Allocation    |       and ending at block 'max'
          .     |       1       |
          .     +---------------+
         a+2n   | Allocation    |
          .     |       2       |       'a' is 'drAlBlSt'
          .     +---------------+                       ( see 1.2 )
         a+3n   | Allocation    |       'max' is 'drNmAlBlks'
          .     |       3       |
          .     +---------------+       'n' is 'drAlBlkSiz'/SECTORSIZE
          .     |               |
          .     |               |
          .     |               |
          .     |               |
          .     |               |
          .     | Last Allocatn |
                | Block (max)   |
                +---------------+



        ######################################################
#1.2                    Volume information sector

          This is a sector which holds information used in reading
        and writing to/from the disc.

        Byte in sector (Length) Name                    Use
                0       2       drSigWord       always $4244 ( check bytes )
                2       4       drCrDate        time of formatting
                6       4       drLsMod         time of last write
                10      2       drAtrb          Disc Locked flags
                12      2       drNmFls*        Number of files in dir
                14      2       drVBMSt         First block in bit map
                16      2       drAllocPtr*
                18      2       drNmAlBlks      Number of allocation blocks
                20      4       drAlBlkSiz      Allocation Block Size
                24      4       drClpSiz        Default clump size
                28      2       drAlBlst        First block in bit map
                30      4       drNxtCNID       next ID number for file/dir
                34      2       drFreeBks       Free Allocation Block count
                36      1       drVN            Volume name length
                37      -       ----            Volume name
                64      4       drVolBkUp       time of last backup
                68      2       drVSeqNum*
                70      4       drWrCnt         Volume Write Count
                74      4       drXTClpSiz      clump size for extents file
                78      4       drCTClpSiz      clump size for Dir file
                82      2       drNmRtDirs      Number of dir's in root
                84      4       drFilCnt        Number of files on disc
                88      4       drDirCnt        Number of dir's on disc
                92      32      drFndrInfo*
                124     2       drVCSize*
                126     2       drVCBMSize*
                128     2       drCtlCSize*
                130     4       drXTFlSize      Length of extents tree file
                134     12      drXTExtRec      Extents tree extents 0,1,2
                146     4       drCTFlSize      Length of CAT tree file
                150     12      drCTExtRec      Dir tree extents 0,1,2


        ( Any Entries marked with a '*' have no known details as yet )


Bytes 10/11 ( drAtrb ) has two single bit flags in it.
                Bit 7 - set if disc locked by hardware ( Read Only )
                Bit 15- set if disc locked by software

A clump is the amount of bytes added to a file space when it is extended.
  This clump is contiguous on the disc, and the larger it is, the less the
file gets fragmented ( split up on the disc ) - see file storeage.




################################ SECTION 2 ###########################


                        How to read files

NOTE: There are 2 special files, called the Dir and the Extent
        files, these hold information about all other files on the disc.



        Files can be thought of in 4 different levels,

        1 - The whole file

        2 - A continuous section of the disc ( can be many for one file )
                ( This is called an extent )

        3 - Allocation Blocks
                ( This is a group of continuous sectors on the disc )

        4 - Sectors
                ( a 512 byte chunk of the disc )


          File          Extents         Allocations      Sectors
        +-------+       +-------+       +-------+       +-------+
        |       |       |       |       |       |       |       |
        |       |       |       |       |+ + + +|       |+ + + +|
        |       |       |Extent |       |       |       |       |
        |       |       |   0   |       |+ + + +|       |+ + + +|
        |       |       |       |       |       |       |       |
        |       |       |+ + + +|       |+++++++|       |+++++++|
        |       |       |       |       |       |       |       |
        |       |       |       |       |+ + + +|       |+ + + +|
        |       |       |Extent |       |       |       |       |
        |       |       |   1   |       |+ + + +|       |+ + + +|
        |       |       |       |       |       |       |       |
        |       |       |+ + + +|       |+++++++|       |+++++++|
        |       |       |       |       |       |       |       |
        |       |       |       |       |+ + + +|       |+ + + +|
        |       |       |       |       |       |       |       |
        |       |       |       |       |+ + + +|       |+ + + +|
        |       |       |Extent |       |       |       |       |
        |       |       |   2   |       |+ + + +|       |+ + + +|
        |       |       |       |       |       |       |       |
        |       |       |+++++++|       |+++++++|       |+++++++|
        |       |       |       |       |       |       |       |
        |       |       |       |       |       |       |       |
        |       |       | etc   |       |       |       |       |

        |       |       |       |       |       |       |       |

        |       |       |       |       |       |       |       |
        +-------+       +-------+       +-------+       +-------+

                                + + + + indicates continuous blocks
                                +++++++ indicates continued else where




        An Extent is a Start-Allocation-Block and a Number-of-Allocation-
        Blocks, So ideally, the file would be in one extent. But if there
        is not a single space that will take it, then another extent can
        be used to hold the second section ( and so on ). This extent gives
        a range of Allocation blocks ( by start number and number of blocks ),
        which then can be mapped on to a range of sectors on the disc.

         The directory and extent files have their first 3 extents
        ( Numbers 0,1 & 2 ) stored in the disc volume information.
         The normal files have their first 3 extents stored in with the
        file information in the directory entry for that file. This
        directory entry is held in the Dir file.

        If any file has more that 3 extents, then the others must be looked
        up in the extents tree file. - This is not normally required as most
        files are only 1 or 2 extents long.

        Each extent gives an area on the disc in which the file is stored,
        There is usually some left over bytes at the end, which are not used.

        A files physical length is the total bytes used on the disc, so when
        reading any file, the 'Logical length' must be used to count to the
        end of the file, so any remaining unused bytes will also be copied.


                To read the file itself, The first extent must be read.
        The first sector of the file can then be calculated from the
        following.
                drAlBlSt+ (drAlSize/SECTORLENGTH)*first_allocation_block
        Then a number of sectors can be read in, which is
                Number_of_allocation_blocks_in_Extent*drAlSize/SECTORLENGTH

        If the number of allocation blocks in the extent is zero, then it
        is unused ( and so are any futher extent records )

        This should be done for each extent, until the file is completely
        read.




    ################################# Section 3 #############################

                                About BStar trees


        BStar trees are a tree structure used to locate infomation
        keeping ALL branches to the SAME optimum length.

        Entries are searched by reference to a key, which is in
        effect a sequence of bytes used to identify a particular piece
        of information. ( Such as a directory number & file name )

        The tree is kept sorted into key order, so that the lowest
        key is at the Left hand side, and the largest key is at the
        right hand side.

        There are 2 diferent types of node in this tree, these are the
        leaf node, and the junction node.

In the junction node, there is a group of records, each record has a key
        and a pointer to another node.

In the leaf nodes, there are keys, and asociated data for the entries.

        ( All nodes have sideway links to other nodes on the same level )

        To search for a particular entry, the root node must be found.
                ( it is the only node where both sideway links are 0
        and the level>0 ).

        Then a loop can be entered doing the following

                If the node is a leaf
                search each record in node until key matches or key>record key
                        if match then FOUND else NOTFOUND

                the node is a junction, so...
                search each record in the node untill one that is greater than
                the search key is found ( or it matches )

                        Go to the node pointed to by the pointer after the entry
                        before, ie the one just_LESS_than ( or equal to ) the
                         search key.



        The stucture of a node is as follows

                byte    length  name            use
                0       4       ndFLink         sideways forward link
                4       4       ndBLink         sideways backward link
                8       1       ndType          #FF=leaf, #00=junction
                9       1       ndLevel         0=not used, 1=leaf,
                                                 2,3,4.. junction levels
                10      2       ndNRecs         Number of records in this node
                12..end                         record area


        working backwards from the end of the node, there are a set of double
        byte numbers that give the distance through the node of each record,
        and a double byte number that gives the position of any free space.

        So the record looks something like this...


        byte offset             use

                0       +---------------+
                        | ndFLink       |
                4       +---------------+
                        | ndBLink       |
                8       +---------------+
                        | ndType        |
                9       +---------------+
                        | ndLevel       |
                10      +---------------+
                        | ndNRecs       |
                12      +---------------+
                        |               |
        normally 14     +---------------+ <--------+
                        |               |          |
                        | Record 0      |          |
                        +---------------+ <------+ |  Note that the records can
                        |               |        | |  be of any different
                        | Record 1      |        | |  lengths.
                        +---------------+ <----+ | |
                        |               |      | | |
                        | Record 2      |      | | |
                        +---------------+ <--+ | | |
                        |               |    | | | |
                        | Record 3      |    | | | |
        Free Space      +---------------+ <+ | | | |
                        .               .  | | | | |
                        .               .  | | | | |
                        .               .  | | | | |
        FS pointer 502  +---------------+  | | | | |
                        | Offset        |--+ | | | |    - Free Space pointer
                504     +---------------+    | | | |
                        | Offset        |----+ | | |    - Record 3 pointer
                506     +---------------+      | | |
                        | Offset        |------+ | |    - Recore 2 pointer
                508     +---------------+        | |
                        | Offset        |--------+ |    - Record 1 pointer
                510     +---------------+          |
                        | Offset  000E  |----------+    - Record 0 pointer
        end of node     +---------------+





                ####### The junction node records of the Dir tree #######

        These seem to be accessed by a key made up from the directory number
        that an entry is in, and its name.

        Byte    example                 Use
        0       #25             Length of key
        1       #00             Not used
        2       #00000002       Dir Number
        6       #03             name length
        7       "tmp"           name in ascii

        38(#25) #00000004       node number where entry found

                followed by next record ( if any )

        When searching and comparing keys, the 4 bytes of the Dir number
        can be compared first, to give <,>, or =.
                If '=', then the name can be checked, but when doing this
        you must note that it is not case dependent, so 'c' is less than
        'D' and more than 'A'. Ie case is ignored.  All names seem to be
        padded out to 32 chars with character zero's.







             ########## SECTION 4 - Dir tree entries ###########

These are in the leaf nodes of the Dir file BSTAR tree.



        These hold directory entries and links, and these are stored as
        follows.

        byte    name            use

        0       ckrKeyLen       Key length
        1       ckrResrv1*      reserved
        2       ckrParID        Owning directory ID number ( 4 bytes )
        6       ckrCName        length of name
        7                       name ( in asci bytes )

                in here there is an extra byte of #00 if it is not
        currently on a word boundary, ie... The store is padded to an even
        number of bytes with zeros, so that the following entry starts on an
        even byte boundary.

        There now follows a directory entry of one of three types.

TYPE 1  0       cdrType         =1 ( Entry is a subdirectory entry )
        1       cdrResrv2*      reserved
        2       dirFlags*       flags
        4       dirVal*         Valence
        6       dirDirID        ID of sub dir ( 4 byte number )
        10      dirCrDat        creation date
        14      dirMdDat        modification date
        18      dirBkDat        backup date
        22      dirUsrInfo*
        38      dirFndrInfo*
        54      dirResrv*

TYPE 2  0       cdrType         =2 ( Entry is a file entry )
        1       cdrResrv2*      reserved
        2       filFlags*       flags ( bit 0=1 if file locked )
        4       filUsrWds*
        20      filFlNum        FileNumber
        24      filStBlk*       First allocation block of data fork
        26      filLgLen        Logical length of data fork
        30      filPyLen        Length of data fork ( rounded up to sector )
        34      filRStBlk*      First allocation block of resource fork
        36      filRLgLen       Logical length of resource fork
        40      filRPyLen       length of resource fork to end of allocation
        44      filCrDat        creation date
        48      filMdDat        modification date
        52      filBkDat        date of last backup
        56      filFndrInfo*
        72      filClpSize      default file clump size
        74      filExtRec       first 3 extents of data fork
        86      filRExtRec      first 3 extents of resource fork
        98      filResrv*

TYPE 3  0       cdrType         =3 ( Entry is a link to parent )
        1       cdrResrv2*      reserverd
        2       thdResrv*       reserved
        10      thdParId        4 byte number of parent directory
        14      thdCName        name length
        15                      name of this directory



( Any Entries marked with a '*' have no known details as yet )



        ######################## SECTION 5 ####################

                        Unknown details

        There are a few details that I do not fully understand yet

        These are

                The finder info & reserved bytes in the directory entries

                If the dir tree nodes are 1 sector or 1 allocation_block in
                size - ( It is more likely to be allocation blocks but I am
                not certain )

                Exactly what needs updating when a new file is added to
                the disc, or removed ( erased ).

                How to find the root node of the bstar tree.
                ( At the moment, a scan of all nodes is made )

        The main points are, all of the fields marked with a '*' in this
        document, as these are created for a new file, and If are not set
        properly, then unknown things may happen.

        The inner workings of the extent file is not known.
        though its whereabouts is known. ( From volume info ).
                - This was not looked at in great detail as most files
                can be accessed without looking at this file.
                ( Unless a file write is done, of it is longer than
                3 extents in length ).


#########################################################################

SHAR_EOF
if test 19867 -ne `wc -c < document`
then
    echo shar: error transmitting "document" '('should be 19867 chars')'
else
    echo document
fi
fi
echo shar: extracting "maccopy.1" '('1233 chars')'
if test -f maccopy.1
then
    echo shar: will not overwrite existing file "maccopy.1"
else
cat << \SHAR_EOF > maccopy.1
.TH MACCOPY 1 "Aug 1988" QMC
.SH NAME
maccopy \- copy files from the mac partition to unix
.SH SYNOPSIS
.B maccopy
[
.B macfile
] [
.B unixfile
]
.SH DESCRIPTION
.I Macfile
is copied onto
.IR unixfile .
Only one HFS file can be copied at a time, and it must be named in
full. If it does not live on the default HFS partition, then
.I macfile
should be the device name, a colon, and then the full path name
with folder names separated by "/", the UNIX directory
separator character. Filename parsing is generous, i.e. the
longest matching valid prefix is taken to be the directory
name, so names such as
.I "A/UX\0Startup"
will work correctly as folder names.
.PP
If any non alpha character occurs in the name, a `?' wildcard can
be used, which will match any character in that position. Note
that the
.I macfile
argument normally needs to be enclosed in single or double
quotation marks to force the correct interpretation.
.SH FILES
/dev/dsk/c0d0s16 \(en default HFS partition.
.SH "SEE ALSO"
macls(1)
.SH BUGS
Won't take `*' wildcards, or any name completely made up from
from `?'s. Can't copy from A/UX to HFS.
.SH AUTHOR
.nf
Matthew Kempthorne-Ley-Edwards
Department of Computer Science
Queen Mary College
London  E1 4NS
UK
.fi

SHAR_EOF
if test 1233 -ne `wc -c < maccopy.1`
then
    echo shar: error transmitting "maccopy.1" '('should be 1233 chars')'
else
    echo maccopy.1
fi
fi
echo shar: extracting "macls.c.patch" '('4107 chars')'
if test -f macls.c.patch
then
    echo shar: will not overwrite existing file "macls.c.patch"
else
cat << \SHAR_EOF > macls.c.patch
*** ls.c	Mon Aug 15 15:24:56 1988
--- macls.c	Mon Aug 15 15:09:14 1988
***************
*** 8,13
   * 4.2bsd version for symbolic links, variable length
   * directory entries, block size in the inode, etc.
   */
  #include <sys/param.h>
  #include <sys/stat.h>
  #include <sys/dir.h>

--- 8,20 -----
   * 4.2bsd version for symbolic links, variable length
   * directory entries, block size in the inode, etc.
   */
+ #ifndef BSD
+ 	/* apple only defns */
+ #include <sys/types.h>
+ #include <sys/sysmacros.h>
+ #define dbtob(x)	dtob(x)	/* BSD -> SYS V naming */
+ #endif
+ 
  #include <sys/param.h>
  #include <sys/dir.h>
  
***************
*** 9,15
   * directory entries, block size in the inode, etc.
   */
  #include <sys/param.h>
- #include <sys/stat.h>
  #include <sys/dir.h>
  #include <stdio.h>
  #include <sgtty.h>

--- 16,21 -----
  #endif
  
  #include <sys/param.h>
  #include <sys/dir.h>
  
  /* ******************************************* */
***************
*** 11,16
  #include <sys/param.h>
  #include <sys/stat.h>
  #include <sys/dir.h>
  #include <stdio.h>
  #include <sgtty.h>
  

--- 17,31 -----
  
  #include <sys/param.h>
  #include <sys/dir.h>
+ 
+ /* ******************************************* */
+ #ifndef BSD
+ #include "macdir.h"
+ #else
+ #include <sys/stat.h>
+ #endif
+ /* ******************************************* */
+ 
  #include <stdio.h>
  #include <sgtty.h>
  
***************
*** 14,19
  #include <stdio.h>
  #include <sgtty.h>
  
  #define	kbytes(size)	(((size) + 1023) / 1024)
  
  struct afile {

--- 29,36 -----
  #include <stdio.h>
  #include <sgtty.h>
  
+ 
+ 
  #define	kbytes(size)	(((size) + 1023) / 1024)
  
  struct afile {
***************
*** 40,46
  int	aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1;
  int	qflg, Aflg, Cflg, Fflg, Lflg, Rflg;
  
! int	usetabs;
  
  time_t	now, sixmonthsago, onehourfromnow;
  

--- 57,63 -----
  int	aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg, rflg = 1;
  int	qflg, Aflg, Cflg, Fflg, Lflg, Rflg;
  
! int	usetabs = 1;
  
  time_t	now, sixmonthsago, onehourfromnow;
  
***************
*** 63,69
  	int i;
  	struct afile *fp0, *fplast;
  	register struct afile *fp;
- 	struct sgttyb sgbuf;
  
  	argc--, argv++;
  	if (getuid() == 0)

--- 80,85 -----
  	int i;
  	struct afile *fp0, *fplast;
  	register struct afile *fp;
  
  	argc--, argv++;
  	if (getuid() == 0)
***************
*** 72,77
  	sixmonthsago = now - 6L*30L*24L*60L*60L;
  	onehourfromnow = now + 60L*60L;
  	now += 60;
  	if (isatty(1)) {
  		qflg = Cflg = 1;
  		(void) gtty(1, &sgbuf);

--- 88,94 -----
  	sixmonthsago = now - 6L*30L*24L*60L*60L;
  	onehourfromnow = now + 60L*60L;
  	now += 60;
+ #ifdef BSD
  	if (isatty(1)) {
  		struct sgtty sgbuf;
  
***************
*** 73,78
  	onehourfromnow = now + 60L*60L;
  	now += 60;
  	if (isatty(1)) {
  		qflg = Cflg = 1;
  		(void) gtty(1, &sgbuf);
  		if ((sgbuf.sg_flags & XTABS) == 0)

--- 90,97 -----
  	now += 60;
  #ifdef BSD
  	if (isatty(1)) {
+ 		struct sgtty sgbuf;
+ 
  		qflg = Cflg = 1;
  		(void) gtty(1, &sgbuf);
  		if ((sgbuf.sg_flags & XTABS) == 0)
***************
*** 79,84
  			usetabs = 1;
  	} else
  		usetabs = 1;
  	while (argc > 0 && **argv == '-') {
  		(*argv)++;
  		while (**argv) switch (*(*argv)++) {

--- 98,104 -----
  			usetabs = 1;
  	} else
  		usetabs = 1;
+ #endif
  	while (argc > 0 && **argv == '-') {
  		(*argv)++;
  		while (**argv) switch (*(*argv)++) {
***************
*** 624,629
  #define	NMAX	(sizeof (utmp.ut_name))
  #define SCPYN(a, b)	strncpy(a, b, NMAX)
  
  #define MAXUID	2048
  #define MINUID  -2		/* for nfs */
  #define MAXGID	300

--- 644,650 -----
  #define	NMAX	(sizeof (utmp.ut_name))
  #define SCPYN(a, b)	strncpy(a, b, NMAX)
  
+ #ifndef MAXUID
  #define MAXUID	2048
  #endif
  #define MINUID  -2		/* for nfs */
***************
*** 625,630
  #define SCPYN(a, b)	strncpy(a, b, NMAX)
  
  #define MAXUID	2048
  #define MINUID  -2		/* for nfs */
  #define MAXGID	300
  

--- 646,652 -----
  
  #ifndef MAXUID
  #define MAXUID	2048
+ #endif
  #define MINUID  -2		/* for nfs */
  #define MAXGID	300
  
SHAR_EOF
if test 4107 -ne `wc -c < macls.c.patch`
then
    echo shar: error transmitting "macls.c.patch" '('should be 4107 chars')'
else
    echo macls.c.patch
fi
fi
#         End of shar archive
exit 0
-- 

William Roberts         ARPA: liam@cs.qmc.ac.uk  (gw: cs.ucl.edu)
Queen Mary College      UUCP: liam@qmc-cs.UUCP
LONDON, UK              Tel:  01-975 5250

liam@cs.qmc.ac.uk (William Roberts) (08/15/88)

#         This is a shar archive.
#         Remove everything above and including the cut line.
#         Then run the rest of the file through sh.
#--------cut--------cut--------cut--------cut--------cut--------
#! /bin/sh
#  shar:  Shell Archiver
#         Run the following with /bin/sh to create:
#             bstar.c
#             disc.h
#             extents.c
#             fcb.c
#             files.c
#             maccopy.c
#             macdir.h
#             macfile.h
#             rootblock.c
#             stat.c
#             undodefs.h
#             unixdir.c
# This archive created: Mon Aug 15 17:53:11 WET DST 1988
echo shar: extracting "bstar.c" '('8900 chars')'
if test -f bstar.c
then
    echo shar: will not overwrite existing file "bstar.c"
else
cat << \SHAR_EOF > bstar.c
#include "disc.h"

short GetNextByteFrom(Tree)
bstar *Tree;
{
	return Tree->BSfcb->AllocationBuffer[Tree->BytePos++];
}

short GetNext2BytesFrom(Tree)
bstar *Tree;
{
	short result;
	result=*(short *)(&Tree->BSfcb->AllocationBuffer[Tree->BytePos]);
	Tree->BytePos+=2;
	return result;
}

long GetNext4BytesFrom(Tree)
bstar *Tree;
{
	long result;
	result=*(long *)(&Tree->BSfcb->AllocationBuffer[Tree->BytePos]);
	Tree->BytePos+=4;
	return result;
}

SkipNextNBytesFrom(Distance,Tree)
int     Distance;
bstar   *Tree;
{
	Tree->BytePos+=Distance;
}

		/* Tree Start Record - go to record 'n' in current block */

void TreeStartRecord(RecordNumber,Tree)
bstar *Tree;
short RecordNumber;
{
	if (RecordNumber>=Tree->NDNRecs) {
		printf("bstar-Bad directory record access number\n");
		exit(-1);
	}
	Tree->CurrentRecordNumber=RecordNumber;
	Tree->BytePos=Tree->BSfcb->DeviceInfo.DRALBLKSIZ-(2*(RecordNumber+1));
	Tree->BytePos=GetNext2BytesFrom(Tree);
#ifdef DEBUGBSTAR
	printf("bstar-Record %d at %3d  :",RecordNumber,Tree->BytePos);
#endif
}



void ReadBStarBlock(BlockNumber,Btree)
long BlockNumber;
bstar *Btree;
{
	GotoBlock(Btree->BSfcb,BlockNumber);
	GetAllocationBlock(Btree->BSfcb);

#ifdef DEBUGBSTAR
	printf("bstar-Block %d read.\n",BlockNumber);
#endif

	Btree->BytePos=0;
	Btree->CurrentRecordNumber=0;
	Btree->CurrentSearchBlock=BlockNumber;

	Btree->NDFLink=GetNext4BytesFrom(Btree);
	Btree->NDBLink=GetNext4BytesFrom(Btree);
	Btree->NDType=GetNextByteFrom(Btree);
	Btree->NDLevel=GetNextByteFrom(Btree);
	Btree->NDNRecs=GetNext2BytesFrom(Btree);
}





void MoveToNextDirEntry(Btree)
bstar *Btree;
{
	Btree->CurrentRecordNumber++;
	if (Btree->CurrentRecordNumber >= Btree->NDNRecs) {
		if (Btree->NDFLink==0) {
				Btree->RecordFound=NOTFOUND;
				return;
		}
		ReadBStarBlock(Btree->NDFLink,Btree);
	}
}

			/* cache for device/root block number */
static  char    LastDeviceName[100];
static  int     LastRootBlockNumber;


int GetRootBlockNumber(devicename,dirp)
bstar   *dirp;
{
	int     block=0;
	int     found=9999;

	if (strcmp(devicename,LastDeviceName)==0)
		return LastRootBlockNumber;

	while   (found!=0) {
		ReadBStarBlock(++block,dirp);
		found=dirp->NDFLink+dirp->NDBLink;
		if (dirp->NDLevel==0) found=9999;       /* not found if unused node */
	}
#ifdef DEBUGBSTAR
	printf("bstar-ROOT-BLOCK-LOCATED AT %d  level %d\n",block,dirp->NDLevel);
#endif

	strcpy(LastDeviceName,devicename);
	LastRootBlockNumber=block;
					/* root node is the             */
	return  block;                  /* only single block in level   */
}

long ReadLinkNode(dirp)
bstar *dirp;
{
	long    pid;
	GetNext2BytesFrom(dirp);
	pid=GetNext4BytesFrom(dirp);
#ifdef DEBUGBSTAR
	printf("bstar-ReadLinkNode pid %d - %s\n",pid,
		(char *)(&dirp->BSfcb->AllocationBuffer[dirp->BytePos +1]) );
#endif
	SkipNextNBytesFrom(32,dirp);
	dirp->Pointer=GetNext4BytesFrom(dirp);
	SkipNextNBytesFrom((-36),dirp); /* move pointer to name part */
	return pid;
}

int     CheckNodeName(name,dirp) /* return -1,0,1 if name < = > nodename */
char *name;
bstar *dirp;
{
int     c,byte,nbyte;
int     isresource=0;

	SkipNextNBytesFrom(1,dirp); /* skip name length */
	if (name[0]=='%') isresource=1; /* skip '%'in name */

	for (c=0;c<31;c++) {
		byte=GetNextByteFrom(dirp);
		nbyte=name[c+isresource];

		if (byte>='a' && byte<='z') byte-=32;
		if (nbyte>='a' && nbyte<='z') nbyte-=32;

		if (nbyte=='?') return (-1);

		if (nbyte<byte) return (-1);
		if (nbyte>byte) return (1);
		if (byte=='\0') return (0);
	}
	return 1;
}



void FindFileNumber(Number,name,dirp)
long    Number;
char    *name;
bstar   *dirp;
{
	int     record;
	int     block=(-1);
	long    NodeKey;

#ifdef DEBUGBSTAR
	printf("bstar-FindFileNumber %4d %s\n",Number,name);
#endif
	ReadBStarBlock(dirp->RootBlockNumber,dirp);
	dirp->RecordFound=FOUND;
	while (dirp->NDLevel > 1) {
		record=0;
		block=(-1);
		do {
			if (record>=dirp->NDNRecs) {
				if (block<1) {
					dirp->RecordFound=NOTFOUND;
					return;
				}
				ReadBStarBlock(block,dirp);
				record=(-1);
			} else {
				TreeStartRecord(record,dirp);
				if ((NodeKey=ReadLinkNode(dirp)) > Number) {
					if (block<1) {
						dirp->RecordFound=NOTFOUND;
						return;
					}
					ReadBStarBlock(block,dirp);
					record=(-1);
				} else
				if (NodeKey==Number) {
					if (CheckNodeName(name,dirp)<0) {
						/* nodename>name */
						if (block<1) {
						  dirp->RecordFound=NOTFOUND;
						  return;
						}
						ReadBStarBlock(block,dirp);
						record=(-1);
					} else {
						block=dirp->Pointer;
						record++;
					}
				} else {
					block=dirp->Pointer;
					record++;
				}
			}
		} while (record>0);
	}

		/* now at leaf node level, so skip to PID>=Number */

	for (TreeStartRecord(0,dirp);ReadCatTreeEntry(dirp)<Number;) {
		MoveToNextDirEntry(dirp);
		TreeStartRecord(dirp->CurrentRecordNumber,dirp);
	}
}





/* ********************************************************************************
 * ***                  There now follows the file entry readers                ***
 * ******************************************************************************** */



ReadDirInfo(Tree)
bstar *Tree;
{
	SkipNextNBytesFrom(4,Tree);
	Tree->DirEntry.d_fileno=GetNext4BytesFrom(Tree);
	Tree->ctime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	Tree->mtime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	Tree->atime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	Tree->FileLength=512;
}

ReadFileInfo(Tree)
bstar *Tree;
{
long    LengthR,LengthD;
long    EStart,ELength;
char    tempname[32];
int     c;

	SkipNextNBytesFrom(1,Tree);             /* flags */
	SkipNextNBytesFrom(1,Tree);             /* file type */
	SkipNextNBytesFrom(16,Tree);            /* 16 bytes finder info */
	Tree->DirEntry.d_fileno=GetNext4BytesFrom(Tree);
	SkipNextNBytesFrom(2,Tree);
	LengthD=GetNext4BytesFrom(Tree);
	SkipNextNBytesFrom(4,Tree);
	SkipNextNBytesFrom(2,Tree);
	LengthR=GetNext4BytesFrom(Tree);
	SkipNextNBytesFrom(4,Tree);
	Tree->ctime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	Tree->mtime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	Tree->atime=MacTimeToUnixTime(GetNext4BytesFrom(Tree));
	SkipNextNBytesFrom(16,Tree);
	SkipNextNBytesFrom(2,Tree);

	/* now sort out for Resource or Data file */
			/* Entry with both is Data only */
			/* Resource program is considered else where */
	if (LengthD>0) {        /* data fork */
		Tree->FileLength=LengthD;
		for (c=0;c<3;c++) {
			EStart=GetNext2BytesFrom(Tree);
			ELength=GetNext2BytesFrom(Tree);
			SetExtent(&Tree->Extents[c],EStart,ELength);
		}
	}

	if (LengthR>0 && LengthD>0) { /* copy info to fake dir entry */
		CopyDirToFake(Tree);
	}

	if (LengthR>0) {        /* Resource fork */
		Tree->FileLength=LengthR;
/* This adds a '%' to the start of the name */
/* not realy needed, but there for compatability */
		strcpy(tempname,"%");
		strcat(tempname,Tree->DirEntry.d_name);
		strcpy(Tree->DirEntry.d_name,tempname);
		Tree->DirEntry.d_namlen++;

		SkipNextNBytesFrom(12,Tree);
		for (c=0;c<3;c++) {
			EStart=GetNext2BytesFrom(Tree);
			ELength=GetNext2BytesFrom(Tree);
			SetExtent(&Tree->Extents[c],EStart,ELength);
		}
	}
}

ReadLinkInfo(Tree)
bstar *Tree;
{
	SkipNextNBytesFrom(8,Tree);
	MakeUpDir(Tree,"..",GetNext4BytesFrom(Tree));

	CopyDirToFake(Tree);
	MakeUpDir(Tree,".",Tree->CurrentWorkingDirectory);
}

long ReadCatTreeEntry(Tree)
bstar *Tree;
{
	int     c;
	int     keylength;
	int     BytesToSkip;

	Tree->FakeType=0;
	keylength=GetNextByteFrom(Tree);
	GetNextByteFrom(Tree);          /* ignored byte */
	Tree->ParID=GetNext4BytesFrom(Tree);    /* parent ID*/

	Tree->DirEntry.d_namlen=GetNextByteFrom(Tree);
	for (c=0;c<Tree->DirEntry.d_namlen;c++)
		Tree->DirEntry.d_name[c]=GetNextByteFrom(Tree);
	Tree->DirEntry.d_name[c]=NULL;  /* end marker = NULL */

#ifdef DEBUGBSTAR
	printf("Name read = %s (pid=%d)\n",Tree->DirEntry.d_name,Tree->ParID);
#endif

	BytesToSkip=keylength-Tree->DirEntry.d_namlen-6;
	while (BytesToSkip-->0)
		GetNextByteFrom(Tree);
	if ((Tree->BytePos %2) != 0)
		GetNextByteFrom(Tree);  /* skip to even byte */

	Tree->FileType=GetNextByteFrom(Tree);
	SkipNextNBytesFrom(1,Tree);             /* ignore next byte */
	switch (Tree->FileType) {
		case 1: ReadDirInfo(Tree);break;
		case 2: ReadFileInfo(Tree);break;
		case 3: ReadLinkInfo(Tree);break;
		default : printf("bstar-ReadCatTreeEntry:Bad directory entry %d\n",Tree->FileType);
			exit(-1);               /* PROGRAM GONE WRONG or BAD DISC */
			break;
	}
	return Tree->ParID;
}


CopyDirToFake(Tree)
bstar *Tree;
{
int     c;

	for (c=0;c<3;c++)
		Tree->FakeExtents[c]=Tree->Extents[c];
	Tree->FakeLength=Tree->FileLength;
	Tree->FakeType=Tree->FileType;
	Tree->FakeDirEntry=Tree->DirEntry;
}

CopyDirFromFake(Tree)
bstar *Tree;
{
int     c;

	for (c=0;c<3;c++)
		Tree->Extents[c]=Tree->FakeExtents[c];
	Tree->FileLength=Tree->FakeLength;
	Tree->FileType=Tree->FakeType;
	Tree->DirEntry=Tree->FakeDirEntry;
	Tree->FakeType=0;
}

SHAR_EOF
if test 8900 -ne `wc -c < bstar.c`
then
    echo shar: error transmitting "bstar.c" '('should be 8900 chars')'
else
    echo bstar.c
fi
fi
echo shar: extracting "disc.h" '('3972 chars')'
if test -f disc.h
then
    echo shar: will not overwrite existing file "disc.h"
else
cat << \SHAR_EOF > disc.h
/*
 * A/UX HFS library. Version 1.0
 *
 * Copyright: Matthew Kempthorne-Ley-Edwards, August 1988
 *
 * for  Department of Computer Science
 *      Queen Mary College
 *      London  E1 4NS
 *      UK
 *
 * This software is provisional and carries no guarantee of fitness
 * for any purpose. It may be freely copied provided this copyright
 * message included in any such distribution. It may not be sold or
 * incorporated into any product without prior permission of both
 * the author and Queen Mary College.
 */

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <string.h>

#ifndef rewinddir
#include <sys/dir.h>
#endif
#ifndef S_IFMT
#include <sys/stat.h>
#endif


#define DEFDISCFILE "/dev/dsk/c0d0s16"


#define SECTORLENGTH 512

typedef struct extent {
	u_short Start;
	u_short Length;
	} extent ;

typedef struct device { /* Device info - read from first sector of device */
	char    DeviceName[100];
	int     RootBlockNumber;        /* Block number of root block   */
					/*      in cat tree     */
	int     DeviceFile;             /* File of open device  */
	int     DRALBLKSIZ; /* Allocation Block size ( bytes ) */
	int     DRALBLST;
	extent  DRCTEXTREC[3]; /* Cat tree file extents 0,1,2 */
	} device ;

/* The complete FCB can be made up from the DeviceName and FileIDs & Position in file */

typedef struct fcb {

	/* internal working info */
	device  DeviceInfo;     /* root sector & device info */
	extent  Extent[3];  /* 0,1,2 extents */

	/* current position in file handlers */
	int     CurrentExtentNumber;
	int     CurrentAllocationInExtent;
	int     CurrentPosInAllocation;
	u_char  *AllocationBuffer;
	int     CurrentAllocationInBuffer;
	long    CurrentPos;

	/* info that could be found from the above */
	int     StartBlock;             /* = fcb(ext[curext].start */
	int     AllocationBlockNumber;   /* = StartBlock+fcbCurAlinExt */

	int     FileID;
	int     DirID;
	long    LengthOfFile;

	} fcb ;

typedef struct bstar {

	fcb     *BSfcb;
	long    NDFLink;
	long    NDBLink;
	short   NDType;
	short   NDLevel;
	short   NDNRecs;

	int     CurrentSearchBlock;     /* used in OpenDir name lookup */
	short   RecordFound;
	long    Pointer;
	int     RootBlockNumber;

	int     CurrentRecordNumber;
	long    CurrentWorkingDirectory;
	int     DirEntryNumber;
	short   BytePos;

			/* info about dir entry */

	struct direct DirEntry;
	long    ParID;                  /* dir number of owning dir */
	short   FileType;               /* filetype number 0.1.2 */
	long    FileLength;
	long    mtime,ctime,atime;      /* times of modify,create,archive */

	extent  Extents[3];

			/* info about fake entry ( ie "." or resource part
			   that is not realy in the dir ) */

	short   FakeType;
	extent  FakeExtents[3];
	long    FakeLength;
	struct  direct  FakeDirEntry;

	} bstar;

#define MacTimeToUnixTime(x) x+((70*365+17)*24*60*60)


#define FOUND 1
#define NOTFOUND 0

/* fcb defs */
fcb *OpenFile(),*GetCatExtentFCB(),*OpenCatFile();

/* bstar defs */
short GetNextByteFrom();
short GetNext2BytesFrom();
long GetNext4BytesFrom();
void TreeStartRecord();
void ReadBStarBlock();
void AdvanceTreeSearch();
long ReadCatTreeEntry();

/* rootblock defs */
device OpenDeviceFile();

#define Unix_open(nam,mod,x)            open(nam,mod,x)
#define Unix_read(id,buf,len)           read(id,buf,len)
#define Unix_write(id,buf,len)          write(id,buf,len)
#define Unix_lseek(id,offset,otype)     lseek(id,offset,otype)
#define Unix_close(id)                  close(id)

#define Unix_FILE                       FILE
#define Unix_fopen(name,type)           fopen(name,type)
#define Unix_fseek(id,offset,ptype)     fseek(id,offset,ptype)
#define Unix_fread(buf,len,size,id)     fread(buf,len,size,id)
#define Unix_fwrite(buf,len,size,id)    fwrite(buf,len,size,id)
#define Unix_fclose(id)                 fclose(id)
#define Unix_rewind(id)                 rewind(id)
#define Unix_ftell(id)                  ftell(id)

SHAR_EOF
if test 3972 -ne `wc -c < disc.h`
then
    echo shar: error transmitting "disc.h" '('should be 3972 chars')'
else
    echo disc.h
fi
fi
echo shar: extracting "extents.c" '('4837 chars')'
if test -f extents.c
then
    echo shar: will not overwrite existing file "extents.c"
else
cat << \SHAR_EOF > extents.c
#include "disc.h"

ReadNAllocationBlocks(Number,BlockNumber,address,Device)
long BlockNumber;
char *address[];
device *Device;
{
#ifdef DEBUGEXTENTS
	printf("extents-ReadNAllocationBlocks %d\n",BlockNumber);
#endif
	ReadNSectors(Number,Device->DRALBLKSIZ/SECTORLENGTH*
	    (BlockNumber+Device->DRALBLST),address,Device->DeviceFile);
}

SetExtent(Extent,num1,num2) /* #### TO BE REMOVED ##### */
extent *Extent;
int num1,num2;
{
	Extent->Start=num1;
	Extent->Length=num2;
}

fcb *GetCatExtentFCB(DeviceName)
char *DeviceName;
{
fcb     *FileControlBlock;
device  Device;
extent  ex0,ex1,ex2;

	Device=OpenDeviceFile(DeviceName); /* Find whereabouts of CAT file */
	ex0=Device.DRCTEXTREC[0];
	ex1=Device.DRCTEXTREC[1];
	ex2=Device.DRCTEXTREC[2];
	CloseDeviceFile(Device);           /* Will be reopened in OpenFile */

	FileControlBlock=OpenFile(ex0,ex1,ex2,1,0,0,DeviceName);
	return FileControlBlock;
}

GetAllocationBlock(FileControlBlock)
fcb *FileControlBlock;
{

/*
	FileControlBlock->AllocationBlockNumber =
		FileControlBlock->Extent[FileControlBlock->CurrentExtentNumber].Start
		+ FileControlBlock->CurrentAllocationInExtent ;
*/

	if (FileControlBlock->AllocationBlockNumber !=
	  (FileControlBlock->CurrentAllocationInBuffer)) {
		ReadNAllocationBlocks(1,FileControlBlock->AllocationBlockNumber,
			FileControlBlock->AllocationBuffer,
			&FileControlBlock->DeviceInfo);
		FileControlBlock->CurrentAllocationInBuffer=FileControlBlock->
			AllocationBlockNumber;
	}
}

GetAllocationBlocks(Number,stream,address)
int Number;     /* Number of allocation blocks to read */
fcb *stream;    /* fcb for file */
char *address;  /* where to put data */
{
int     NumberDone;
int     StartBlock;

	StartBlock=stream->Extent[stream->CurrentExtentNumber].Start
		+ stream->CurrentAllocationInExtent;

	NumberDone=stream->Extent[stream->CurrentExtentNumber].Length
		  -stream->CurrentAllocationInExtent;
		/* NumberDone= all allocation blocks to end of extent */
	if (NumberDone>Number) NumberDone=Number;
		/* NumberDone= number of blocks to read */

	ReadNAllocationBlocks(NumberDone,StartBlock,address,&stream->DeviceInfo);
	return NumberDone;
		/* No positional pointers are changed */
}

/* ******************************************************** */
/*                   Readers for memory buffers             */
/* ******************************************************** */


AdvanceAllocation(FileControlBlock)
fcb *FileControlBlock;
{
	FileControlBlock->CurrentPosInAllocation=0;
	FileControlBlock->AllocationBlockNumber++;
	if (FileControlBlock->CurrentAllocationInExtent++ >=
	 FileControlBlock->Extent[FileControlBlock->CurrentExtentNumber].Length)
	{
		FileControlBlock->CurrentExtentNumber++;
		if (FileControlBlock->CurrentExtentNumber >2)
		{
			printf("**** File too fragmented error *****\n");
			exit(-1);
		}
	}
}


short GetNextByte(FileControlBlock)
fcb *FileControlBlock;
{
	int AllocationBlockNumber;
	int Number;
	short byte;

#ifdef DEBUGEXTENTS
	printf("extents-GetNextByte ..");
#endif

	if (FileControlBlock->CurrentPos >= FileControlBlock->LengthOfFile)
		return EOF;

	GetAllocationBlock(FileControlBlock);

	byte=(FileControlBlock->AllocationBuffer[
		FileControlBlock->CurrentPosInAllocation++]);

#ifdef DEBUGEXTENTS
	printf("%d got\n",byte);
#endif

	if (FileControlBlock->CurrentPosInAllocation >=
				 FileControlBlock->DeviceInfo.DRALBLKSIZ)
		AdvanceAllocation(FileControlBlock);

	FileControlBlock->CurrentPos++;
	return byte;
}


GetBlockOfBytes(ptr,NBytes,stream)
char    *ptr;
int     NBytes;
fcb     *stream;
{
int     ReturnValue;
int     bytes;
int     blocks;

	if (stream->CurrentPos >= stream->LengthOfFile)
		return 0;       /* EOF */

#ifdef DEBUGEXTENTS
	printf("extents- BLOCK READ\n");
#endif

	if (stream->LengthOfFile - stream->CurrentPos < NBytes )
		NBytes=stream->LengthOfFile-stream->CurrentPos;

	ReturnValue=NBytes;

	if (stream->CurrentPosInAllocation > 0) {

		/* Now read from Current pos to end of ABlock */

		GetAllocationBlock(stream);
		bytes=(stream->DeviceInfo.DRALBLKSIZ-stream->CurrentPosInAllocation);

		bcopy(stream->AllocationBuffer[stream->CurrentPosInAllocation],ptr,bytes);
		NBytes-=bytes;
		ptr+=bytes;

		AdvanceAllocation(stream);
	}

	while (NBytes>=stream->DeviceInfo.DRALBLKSIZ) {
		/* Now read entire blocks in */

		blocks=GetAllocationBlocks(NBytes/stream->
			DeviceInfo.DRALBLKSIZ,stream,ptr);
		NBytes-=blocks*stream->DeviceInfo.DRALBLKSIZ;
		ptr+=blocks*stream->DeviceInfo.DRALBLKSIZ;

		AdvanceAllocation(stream);
	}

	if (NBytes>0) {

		/* Now read NBytes in from block */

		GetAllocationBlock(stream);
		bcopy(stream->AllocationBuffer,ptr,NBytes);
		stream->CurrentPosInAllocation=NBytes;
	}

#ifdef DEBUGEXTENTS
	printf("extents- BLOCK READ, %d Bytes read\n",ReturnValue);
#endif
	stream->CurrentPos+=ReturnValue;
	return ReturnValue;
}


SHAR_EOF
if test 4837 -ne `wc -c < extents.c`
then
    echo shar: error transmitting "extents.c" '('should be 4837 chars')'
else
    echo extents.c
fi
fi
echo shar: extracting "fcb.c" '('2958 chars')'
if test -f fcb.c
then
    echo shar: will not overwrite existing file "fcb.c"
else
cat << \SHAR_EOF > fcb.c
#include "disc.h"
#include <malloc.h>

fcb *FCB_Open(ex0,ex1,ex2,DeviceName)
extent ex0,ex1,ex2;
char    *DeviceName;
{
	fcb *FileControlBlock;
	FileControlBlock=(fcb *)malloc(sizeof(fcb));
	if (FileControlBlock==NULL) {
		fprintf(stderr,"Out of memory\n");
		exit(-1);
	}

	FileControlBlock->DeviceInfo=OpenDeviceFile(DeviceName);

	FileControlBlock->Extent[0]=ex0;
	FileControlBlock->Extent[1]=ex1;
	FileControlBlock->Extent[2]=ex2;

	FileControlBlock->AllocationBlockNumber=0;
	FileControlBlock->StartBlock=ex0.Start;

	FileControlBlock->LengthOfFile= /* Is a Default = physical length */
		FileControlBlock->DeviceInfo.DRALBLKSIZ*(
		(FileControlBlock->Extent[0].Length) +
		(FileControlBlock->Extent[1].Length) +
		(FileControlBlock->Extent[2].Length) );

	FileControlBlock->CurrentExtentNumber=0;
	FileControlBlock->CurrentAllocationInExtent=0;
	FileControlBlock->CurrentPosInAllocation=0;
	FileControlBlock->CurrentPos=0;

	FileControlBlock->AllocationBuffer=
		(u_char *)malloc(FileControlBlock->DeviceInfo.DRALBLKSIZ);
	if (FileControlBlock->AllocationBuffer==NULL) {
		fprintf(stderr,"Out of memory\n");
		exit(-1);
	}

	FileControlBlock->CurrentAllocationInBuffer=0;

	return FileControlBlock;
}

FCB_Close(ControlBlock)
fcb *ControlBlock;
{
	free(ControlBlock);
}


fcb
*OpenFile(ex0,ex1,ex2,FileID,DirID,Length,DeviceName)
extent ex0,ex1,ex2;
int FileID,DirID;
long Length;
char *DeviceName;
{
	fcb *newfcb;
	newfcb=FCB_Open(ex0,ex1,ex2,DeviceName);
	newfcb->FileID=FileID;
	newfcb->DirID=DirID;
	newfcb->LengthOfFile=Length;
	return newfcb;
}

CloseFile(FileControlBlock)
fcb *FileControlBlock;
{
	CloseDeviceFile(FileControlBlock->DeviceInfo);
	FCB_Close(FileControlBlock);
}

fcb *OpenCatFile(DeviceName) /* #### should be # define */
char *DeviceName;
{
	return GetCatExtentFCB(DeviceName);
}

short ReadByte(FileControlBlock) /* ### should be # define */
fcb *FileControlBlock;
{
	return GetNextByte(FileControlBlock);
}

GotoBlock(FileCB,NewBlockNumber)
fcb *FileCB;
long NewBlockNumber;
{
int     NewExtentNumber=0;
int     BlockNumber=NewBlockNumber;

	while (BlockNumber>FileCB->Extent[NewExtentNumber].Length) {
		BlockNumber-=FileCB->Extent[NewExtentNumber].Length;
		NewExtentNumber++;

	}
	FileCB->CurrentExtentNumber=NewExtentNumber;
	FileCB->CurrentAllocationInExtent=BlockNumber;
	FileCB->StartBlock=FileCB->Extent[NewExtentNumber].Start;
	FileCB->AllocationBlockNumber=FileCB->StartBlock+BlockNumber;
}

GotoByte(FileCB,Position)
fcb *FileCB;
long Position;
{
	int NewBlockNumber;
	int NewExtentNumber=0;

	NewBlockNumber=Position/(FileCB->DeviceInfo.DRALBLKSIZ);

	GotoBlock(FileCB,NewBlockNumber);
	FileCB->CurrentPosInAllocation=Position % FileCB->DeviceInfo.DRALBLKSIZ;
	FileCB->CurrentPos=Position;
}

long GetPosition(FileCB)        /* #### should be # defines */
fcb *FileCB;
{
	return FileCB->CurrentPos;
}

long GetLength(FileCB)          /* #### should be # defines */
fcb *FileCB;
{
	return FileCB->LengthOfFile;
}


SHAR_EOF
if test 2958 -ne `wc -c < fcb.c`
then
    echo shar: error transmitting "fcb.c" '('should be 2958 chars')'
else
    echo fcb.c
fi
fi
echo shar: extracting "files.c" '('3512 chars')'
if test -f files.c
then
    echo shar: will not overwrite existing file "files.c"
else
cat << \SHAR_EOF > files.c
#include "macfile.h"
#include <errno.h>

#define MaxOpenFiles 20

/* *************** FILE returning file ops Open, Read, Seek ******************** */

Mac_FILE *Mac_fopen(FileName,AccessMode)
char	*FileName;
char	*AccessMode;
{
fcb	*OpenedFile;
DIR	*Dir;
char	Device[30];
char	DirDevice[32];
char	*NamePart;
int	c;

	if (strcmp(AccessMode,"r")!=0) return NULL;

	NamePart=GetDeviceNameFrom(FileName,Device);
	strcpy(DirDevice,Device);
	strcat(DirDevice,":/");

#ifdef DEBUGFILES
	printf("files-open device %s with name %s\n",Device,NamePart);
#endif
	Dir=Mac_opendir(DirDevice);
	if (LookUpFile(Dir,NamePart)==NOTFOUND) {
		Mac_closedir(Dir);
		return	NULL;
	}

	OpenedFile=OpenFile(Dir->Extents[0],Dir->Extents[1],Dir->Extents[2],
		Dir->DirEntry.d_fileno,Dir->CurrentWorkingDirectory,
		Dir->FileLength,Device);

	if (OpenedFile==NULL) return NULL;
#ifdef DEBUGFILES
	printf("files-fopen OK\n");
#endif

	return OpenedFile;
}

int Mac_fclose(MacFileRec)
Mac_FILE *MacFileRec;
{
	FCB_Close(MacFileRec);
	return 0;
}

int Mac_fseek(stream,offset,ptrname)
Mac_FILE *stream;
long offset;
int ptrname;
{
long	position;
	switch (ptrname) {
		case 0:	position=offset;break;
		case 1:	position=GetPosition(stream)+offset;break;
		case 2:	position=GetLength(stream)-offset;break;
	}
	if (position<0) position=0;
	if (position>GetLength(stream)) position=GetLength(stream);

	GotoByte(stream,position);
}

void Mac_rewind(stream)
Mac_FILE *stream;
{
	Mac_fseek(stream,0L,0);
}

long Mac_ftell(stream)
Mac_FILE *stream;
{
	return GetPosition(stream);

}

short Mac_getchar(MacFileRec)
Mac_FILE *MacFileRec;
{
	return	ReadByte(MacFileRec);
}

int Mac_fread(ptr,size,nitems,stream)
char	*ptr;
int	size,nitems;
Mac_FILE *stream;
{
	return GetBlockOfBytes(ptr,size*nitems,stream);
}


/*									 */
/* ************* NON file discripter open/read/lseek ******************* */
/*									 */


static	Mac_FILE	*Files[MaxOpenFiles];
static	int	FileNumber[MaxOpenFiles];
static  int	FilesToInit=99;

Mac_open(path,oflag,mode)
char	*path;
int	oflag,mode;
{
int	c;
Mac_FILE	*fil=NULL;

	if (FilesToInit != 0) {
		for (c=0;c<MaxOpenFiles;c++)
			FileNumber[c]=0; /* no file */
		FilesToInit=0;
	}
	if (oflag != O_RDONLY ) {
		errno=EROFS;
		return(-1);
	}
	for (c=0;(c<MaxOpenFiles && FileNumber[c]!=0);c++);
	if (c>=MaxOpenFiles) {
		errno=ENFILE;
		return(-1);
	}

	Files[c]=Mac_fopen(path,"r");

	if (Files[c]==NULL) {
		FileNumber[c]=0;
		errno=ENOENT;	/* file not found */
		return (-1);
	} else FileNumber[c]=Files[c]->FileID;


	return FileNumber[c];
}

int
Mac_read(filedes,buf,nbytes)
int filedes;
char *buf;
int nbytes;
{
Mac_FILE	*fil=NULL;
int	c;

	if (FilesToInit != 0) {
		errno=EBADF;
		return(-1);
	}

	for (c=0;c<MaxOpenFiles;c++) {
		if (FileNumber[c]==filedes) { 
			fil=Files[c];
			break;
		 }
	}

	if (fil==NULL) {
		errno=EBADF;
		return (-1);
	}
	return Mac_fread(buf,1,nbytes,fil);
}

Mac_lseek(filedes,offset,whence)
int filedes;
long offset;
int whence;
{
Mac_FILE	*fil=NULL;
int	c;

	if (FilesToInit != 0) {
		errno=EBADF;
		return(-1);
	}

	for (c=0;c<MaxOpenFiles;c++) {
		if (FileNumber[c]==filedes) fil=Files[c];
	}

	if (fil==NULL) {
		errno=EBADF;
		return (-1);
	}
	Mac_fseek(fil,offset,whence);
	return(0);

}

Mac_close(filedes)
int	filedes;
{
Mac_FILE	*fil=NULL;
int	c;

	if (FilesToInit != 0) {
		errno=EBADF;
		return(-1);
	}
	for (c=0;c<MaxOpenFiles;c++) {
		if (FileNumber[c]==filedes) fil=Files[c];
	}
	if (fil==NULL) {
		errno=EBADF;
		return (-1);
	}
	Mac_fclose(fil);
	return(0);
}



SHAR_EOF
if test 3512 -ne `wc -c < files.c`
then
    echo shar: error transmitting "files.c" '('should be 3512 chars')'
else
    echo files.c
fi
fi
echo shar: extracting "maccopy.c" '('839 chars')'
if test -f maccopy.c
then
    echo shar: will not overwrite existing file "maccopy.c"
else
cat << \SHAR_EOF > maccopy.c
#include "macfile.h"
#include "undodefs.h"

#include <malloc.h>

#define BUFSIZE 50000

main(argc,argv)
int	argc;
char	*argv[];
{
Unix_FILE	*outname;
Mac_FILE	*inname;
char		*Buffer;
int		bytes;

	if (argc!=3) {
		printf("Usage :%s <macname> <unixname>\n",argv[0]);
		exit(-1);
	}

	if ((inname=Mac_fopen(argv[1],"r"))== NULL ) {
		printf("%s not found on mac filestore\n",argv[1]);
		exit(-1);
	}	

	if ((outname=Unix_fopen(argv[2],"w"))==NULL) {
		printf("%s not writeable on unix filestore\n",argv[2]);
		Mac_fclose(inname);
		exit(-1);
	}	

	Buffer=malloc(BUFSIZE);
	if (Buffer==NULL) {
		printf("%s out of memory.\n",argv[0]);
		exit(-1);
	}

	while ((bytes=Mac_fread(Buffer,sizeof(*Buffer),BUFSIZE,inname))>0)
	{
		Unix_fwrite(Buffer,sizeof(*Buffer),bytes,outname);
	}

	Mac_fclose(inname);
	Unix_fclose(outname);

	free(Buffer);
}

SHAR_EOF
if test 839 -ne `wc -c < maccopy.c`
then
    echo shar: error transmitting "maccopy.c" '('should be 839 chars')'
else
    echo maccopy.c
fi
fi
echo shar: extracting "macdir.h" '('579 chars')'
if test -f macdir.h
then
    echo shar: will not overwrite existing file "macdir.h"
else
cat << \SHAR_EOF > macdir.h
#define stat Mac_stat
#define lstat Mac_stat

#include "disc.h"

#define DIR bstar
#define opendir(dirp)		Mac_opendir(dirp)
#define telldir(dirp)		Mac_telldir(dirp)
#define seekdir(dirp,pos)	Mac_seekdir(dirp,pos)
#undef rewinddir
#define rewinddir(dirp)		Mac_seekdir(dirp,(long)0)
#define Mac_rewinddir(dirp)	Mac_seekdir(dirp,(long)0)
#define closedir(dirp)		Mac_closedir(dirp)
#define readdir(dirp)		Mac_readdir(dirp)

extern	DIR	*Mac_opendir();
extern	struct direct *Mac_readdir();
extern	long	Mac_telldir();

extern	char	*GetPathNameFrom();
extern	char	*GetDeviceNameFrom();

SHAR_EOF
if test 579 -ne `wc -c < macdir.h`
then
    echo shar: error transmitting "macdir.h" '('should be 579 chars')'
else
    echo macdir.h
fi
fi
echo shar: extracting "macfile.h" '('568 chars')'
if test -f macfile.h
then
    echo shar: will not overwrite existing file "macfile.h"
else
cat << \SHAR_EOF > macfile.h
#include "macdir.h"

#define Mac_FILE fcb

Mac_FILE *Mac_fopen();
int	Mac_fclose();
int	Mac_fseek();
void	Mac_rewind();
long	Mac_ftell();
short	Mac_getchar();
int	Mac_fread();

#define open(nam,mod,x)		Mac_open(nam,mod,x)
#define read(id,buf,len)	Mac_read(id,buf,len)
#define lseek(id,offset,otype)	Mac_lseek(id,offset,otype)
#define close(id)		Mac_close(id)

#define fopen(name,type)	Mac_fopen(name,type)
#define fclose(id)		Mac_fclose(id)
#define fseek(id,offset,ptype)	Mac_fseek(id,offset,ptype)
#define rewind(id)		Mac_rewind(id)
#define ftell(id)		Mac_ftell(id)

SHAR_EOF
if test 568 -ne `wc -c < macfile.h`
then
    echo shar: error transmitting "macfile.h" '('should be 568 chars')'
else
    echo macfile.h
fi
fi
echo shar: extracting "rootblock.c" '('1624 chars')'
if test -f rootblock.c
then
    echo shar: will not overwrite existing file "rootblock.c"
else
cat << \SHAR_EOF > rootblock.c
#include "disc.h"

/* ***** routines for getting information from the root store **** */


/* ********** sector readers ********** */
/* 				sectors are read as a file
 *				of type device ( open/read/close )
 */

static char rootstore[SECTORLENGTH];	/* temp buffer for root sector */

device OpenDeviceFile(DeviceName)
char *DeviceName;	/* FileName of device - eg /dev/floppy0 */
{
device	Disc;
int	n;

#ifdef DEBUGUTILS
	printf("utils-File open on device %s\n",DeviceName);
#endif

	Disc.DeviceFile=Unix_open(DeviceName,O_RDONLY,0);
	if (Disc.DeviceFile<0) {
		fprintf(stderr,"Cant open device %s !\n",DeviceName);
		exit(-1);
	}
	Disc.RootBlockNumber= -1;	/* Unknown ######## */
	ReadNSectors(1,2,rootstore,Disc.DeviceFile);
	Disc.DRALBLKSIZ=*(long *)(&rootstore[20]);
	Disc.DRALBLST=*(short *)(&rootstore[28]);

	for (n=0;n<3;n++) {
		Disc.DRCTEXTREC[n]=*(extent *)(&rootstore[150+4*n]);
	}

	strcpy(Disc.DeviceName,DeviceName);
	return Disc;
}

CloseDeviceFile(Device)
device Device;
{
#ifdef DEBUGUTILS
	printf("utils-Device file closed\n");
#endif

	Unix_close(Device.DeviceFile);
}

ReadNSectors(NumberOfSectors,SectorNumber,BufferAddress,DiscFile)
int	NumberOfSectors;
int	SectorNumber;
char	*BufferAddress;
int	DiscFile;
{
#ifdef DEBUGUTILS
	printf("utils-Sector #%x read\n",SectorNumber);
#endif
	if (Unix_lseek(DiscFile,SECTORLENGTH*SectorNumber,0)<0) {
		fprintf(stderr,"Cant seek sector %d !\n",SectorNumber);
		exit(-1);
	}
	if (Unix_read(DiscFile,BufferAddress,NumberOfSectors*SECTORLENGTH)
	    <NumberOfSectors*SECTORLENGTH){ 
		fprintf(stderr,"Read fail on sector %d !\n",SectorNumber);
		exit(-1);
	}
}

SHAR_EOF
if test 1624 -ne `wc -c < rootblock.c`
then
    echo shar: error transmitting "rootblock.c" '('should be 1624 chars')'
else
    echo rootblock.c
fi
fi
echo shar: extracting "stat.c" '('1458 chars')'
if test -f stat.c
then
    echo shar: will not overwrite existing file "stat.c"
else
cat << \SHAR_EOF > stat.c
#include "macdir.h"

#define S_AREAD (S_IREAD | S_IREAD>>3 | S_IREAD>>6 )
#define S_AEXEC (S_IEXEC | S_IEXEC>>3 | S_IEXEC>>6 )

int Mac_stat(file,buffer)
char *file;
struct stat *buffer;
{
	DIR	*DirEnt;
	char	OpenDirName[30];

	file=GetDeviceNameFrom(file,OpenDirName);
	strcat(OpenDirName,":/");

#ifdef DEBUGSTAT
	printf("stat-file %s\n",file);
#endif
	DirEnt=Mac_opendir(OpenDirName);
	if (LookUpFile(DirEnt,file)==NOTFOUND) {
		Mac_closedir(DirEnt);
		return (-1);
	}

	buffer->st_ino		=DirEnt->DirEntry.d_fileno;
	buffer->st_dev		=DirEnt->BSfcb->DeviceInfo.DeviceFile;
	buffer->st_rdev		=DirEnt->CurrentWorkingDirectory;
	buffer->st_uid		=geteuid();	/* ### SHOULD CHECK NAME */
	buffer->st_gid		=getegid();	/* IN FINDER INFO ###### */
	buffer->st_ctime	=DirEnt->ctime;
	buffer->st_mtime	=DirEnt->mtime;
	buffer->st_atime	=DirEnt->atime;
	buffer->st_size		=DirEnt->FileLength;
	buffer->st_blksize	=DirEnt->BSfcb->DeviceInfo.DRALBLKSIZ;
	buffer->st_blocks	=(buffer->st_blksize-1+DirEnt->FileLength)
					/buffer->st_blksize;
	buffer->st_nlink	=1;

	switch (DirEnt->FileType) {
	case 1:
		buffer->st_mode	=S_IFDIR | S_AREAD | S_AEXEC;
		buffer->st_nlink=2; /* for . and parent */
		break;
	case 2:
		buffer->st_mode	=S_IFREG | S_AREAD;
		break;
			/* ###### should check executables ######## */
	default: printf("stat - bad file type on file %s\n",file);
	}
	Mac_closedir(DirEnt);
#ifdef DEBUGSTAT
	printf("stat-file %s done\n",file);
#endif
	return 0;
}

SHAR_EOF
if test 1458 -ne `wc -c < stat.c`
then
    echo shar: error transmitting "stat.c" '('should be 1458 chars')'
else
    echo stat.c
fi
fi
echo shar: extracting "undodefs.h" '('373 chars')'
if test -f undodefs.h
then
    echo shar: will not overwrite existing file "undodefs.h"
else
cat << \SHAR_EOF > undodefs.h
/* This MUST be included ONLY if access to the Mac & access to Unix are BOTH 
 * required, Then All open's etc MUST be prefixed with Mac_ or Unix_ 
 *		ie
 *		Mac_FILE* Mac_fopen()
 *	&	Unix_FILE* Unix_fopen()
 */


#undef open
#undef read
#undef write
#undef lseek
#undef close
#undef fopen
#undef fseek
#undef fread
#undef fwrite
#undef fclose
#undef rewind
#undef ftell
SHAR_EOF
if test 373 -ne `wc -c < undodefs.h`
then
    echo shar: error transmitting "undodefs.h" '('should be 373 chars')'
else
    echo undodefs.h
fi
fi
echo shar: extracting "unixdir.c" '('7345 chars')'
if test -f unixdir.c
then
    echo shar: will not overwrite existing file "unixdir.c"
else
cat << \SHAR_EOF > unixdir.c
#include "macdir.h"
#include <malloc.h>

#define MAXDEVICELEN 30

#define ROOTDIRNUMBER 2

/* ************************************************************ */
/*                   unix IO dir handlers                       */
/* ************************************************************ */

DIR *Mac_opendir(filename)
char *filename;
{
	int	isfound;
	char	DeviceName[MAXDEVICELEN];
	char	*dot=".";
	bstar	*DirTree=(bstar *)malloc(sizeof(bstar));

	if (DirTree==NULL) return NULL; /* out of mem */

		/* First get the device if given */

	filename=GetDeviceNameFrom(filename,DeviceName);
	if (*filename=='\0') filename=dot;

#ifdef DEBUGUNIXDIR
	printf("unixdir-OpenDir device '%s', file '%s'\n",DeviceName,filename);
#endif

		/* now open the device */

	DirTree->BSfcb=OpenCatFile(DeviceName);
	DirTree->RootBlockNumber=GetRootBlockNumber(DeviceName,DirTree);

		/* now set up open info */

	DirTree->DirEntry.d_reclen=sizeof(struct direct);
	DirTree->CurrentWorkingDirectory=ROOTDIRNUMBER;
	Mac_rewinddir(DirTree);

		/* now look up given dir name */

	isfound=LookUpFile(DirTree,filename);
	if (isfound==NOTFOUND) {
#ifdef DEBUGUNIXDIR
		printf("unixdir-LookUpFile %s not found\n",filename);
#endif
		CloseFile(DirTree->BSfcb);	/* dir not found */
		return NULL;
	}
	if (DirTree->FileType!=1) {
#ifdef DEBUGUNIXDIR
		printf("unixdir-LookUpFile %s not directory\n",filename);
#endif
		CloseFile(DirTree->BSfcb);	/* dir not found */
		return NULL;
	}
		/* Now set up info about found dir */

	DirTree->CurrentWorkingDirectory=DirTree->DirEntry.d_fileno; /* get subdir number */
	Mac_rewinddir(DirTree);

#ifdef DEBUGUNIXDIR
		printf("unixdir-OpenDir done.\n",filename);
#endif
	return	DirTree;
}

Mac_closedir(dirp)
DIR *dirp;
{
	CloseFile(dirp->BSfcb);
	free(dirp);
#ifdef DEBUGUNIXDIR
	printf("unixdir-Dir closed\n");
#endif
}


struct direct *Mac_readdir(dirp)		/* move on to next (or first) dir entry */
DIR *dirp;				/* ie read current entry         */
					/* and move on pointer is readOK */
{
	long	ParID;

					/* check to see if no more */
	if (dirp->RecordFound==NOTFOUND) return NULL;

				/* if fake entry, read that & null it */
	if (dirp->FakeType>0) {
		CopyDirFromFake(dirp);
		MoveToNextDirEntry(dirp);
	} else {
				/* Read current pointed to entry */
		TreeStartRecord(dirp->CurrentRecordNumber,dirp);
		ParID=ReadCatTreeEntry(dirp);

				/* now if PID<>ID ... no longer in dir */
		if (ParID!=dirp->CurrentWorkingDirectory)
			return NULL;
		if (dirp->FakeType==0) { 
			MoveToNextDirEntry(dirp);
		}
	}
					/* found an entry in this dir */
	dirp->DirEntryNumber++;		/* now move on counter to next dir */

#ifdef DEBUGUNIXDIR
	printf("unixdir-ReadDir found '%s'\n",dirp->DirEntry.d_name);
#endif

	return &(dirp->DirEntry);
}

long Mac_telldir(dirp)
DIR *dirp;
{
	return dirp->DirEntryNumber-1;	/* DirEntryNumber holds next number */
}

Mac_seekdir(dirp,loc)
DIR	*dirp;
long	loc;
{
	int c;
	char	*NullName="";
	if (loc==0 || loc<dirp->DirEntryNumber) { /* rewind */
		FindFileNumber(dirp->CurrentWorkingDirectory,NullName,dirp);
		dirp->FakeType=0;
	}
	for (c=0;c<loc-dirp->DirEntryNumber-1;c++) {
		if (Mac_readdir(dirp)==NULL) return;
	}
}


/* **************************************************************** */
/*                 Programs internal dir lookups                    */
/* **************************************************************** */


		/* GetDeviceNameFrom, strcpy device name from filename */
		/* Returns filename ( Everything after ':' */
char *GetDeviceNameFrom(filename,devicename)
char *filename,*devicename;
{
	int	c;
	char	*filenamepart=filename;
	char	*devicenamepart=devicename;
	for (c=0;(c<MAXDEVICELEN && *filenamepart!='\0');c++) {
		if (*filenamepart==':') {
			*devicenamepart='\0';
			return (++filenamepart);
		}
		*devicenamepart++=*filenamepart++;
	}
	strcpy(devicename,DEFDISCFILE);
	return filename;	/* no device specified */
}


/* HasItASlash - returns number of chars through string untill a '/' */
HasItASlash(filename)
char *filename;
{
	int c;
	for (c=0;c<MAXNAMLEN;c++) {
		if (filename[c]=='/') return (c+1);
		if (filename[c]=='\0') return 0;
	}	/* returns 0 if not found, or number of chars upto(inc) '/'   */
	fprintf(stderr,"unixdir-BAD FILENAME\n");
	exit(-1);
}

/* name1='/' or NULL terminated, name2=NULL terminated */
/*    rets name1 1 char after / */
char* CompareNames(name1,name2)
char *name1,*name2;
{
	for(;;) {
		while ((*name2=='/' && *name1=='/') || ( *name1=='?' && *name2!='\0')) {
			name1++;name2++; }

		if (*name1=='/' && *name2=='\0')
			return ++name1;
		if (*name1=='/') return NULL;
		if (*name1=='\0') return name1;
		if (*name2=='\0') return NULL;
		if (*name1++!=*name2++) return NULL;
	}
}


	/* StripPathNameFrom - get .../ from front of name */
	/*	returns new RHS of name & cwd changed in dirp*/
char *StripPathNameFrom(dirp,filename)
DIR *dirp;
char *filename;
{
	int	found=1;
	int	namelength;
	char	name[MAXNAMLEN];
	char	*names;
	struct direct	namestore,*dp;

	if (*filename=='/') {
		dirp->CurrentWorkingDirectory=ROOTDIRNUMBER;
		filename++;
	}

	if ((namelength=HasItASlash(filename))==0) return filename;

	/* ############# path CACHE check to be put in here ########### */

/* Name has a slash in it - so look up name up to slash to skip first bit of dir */

	strncpy(name,filename,namelength-1);
	name[namelength-1]='\0';
	FindFileNumber(dirp->CurrentWorkingDirectory,name,dirp);

#ifdef DEBUGUNIXDIR
	printf("looking for %s\n",filename);
#endif
	while (found>0) {
		dp=Mac_readdir(dirp);
		if (dp==NULL) return NULL;

		/* now compare file names */
		names=CompareNames(filename,dp->d_name);
		if (names!=NULL) 
		{
#ifdef DEBUGUNIXDIR
		printf("unixdir-match found on %s\n",filename);
#endif
			if (dirp->FileType!=1) {
				if (*names!='\0') {
					return NULL; /* not a directory */
				}
				/* name has a slash in it */
				return filename;
			}
			filename=names;
			dirp->CurrentWorkingDirectory=dirp->DirEntry.d_fileno;

#ifdef DEBUGUNIXDIR
			printf("unixdir-filename left to check = %s\n",filename);
#endif
			found=HasItASlash(filename);
			if (found>0) {
				strncpy(name,filename,found-1);
				name[found-1]='\0';
				FindFileNumber(dirp->CurrentWorkingDirectory,name,dirp);
			}
		}
	}
	return filename;
}

/* LookUpFile - returns NOTFOUND or FOUND and file info in dirp */
LookUpFile(dirp,filename)
DIR *dirp;
char *filename;
{
	filename=StripPathNameFrom(dirp,filename); /* chase path */
	if (filename==NULL) return NOTFOUND;
	return LookUpEntry(dirp,filename);	/* check file */
}

/* LookUpEntry - Looks up a filename in a dir */
LookUpEntry(dirp,filename)
DIR *dirp;
char *filename;
{
	char	*names;
	struct	direct *dp;

	if (strcmp(filename,".")==0 || (*filename=='\0')) {
		MakeUpDir(dirp,".",dirp->CurrentWorkingDirectory);
		return FOUND;
	}

	FindFileNumber(dirp->CurrentWorkingDirectory,filename,dirp);

	for(;;) {
		dp=Mac_readdir(dirp);
		if (dp==NULL) return NOTFOUND;
		/* now compare file names */
		names=CompareNames(filename,dp->d_name);
		if (names!=NULL) {
			return FOUND;
		}
	}
}

/* MakeUpDir - used to make up entries '..' and '.' */
MakeUpDir(dirp,filename,filenumber)
DIR	*dirp;
char	*filename;
long	filenumber;
{
	dirp->DirEntry.d_fileno=filenumber;
	strcpy(dirp->DirEntry.d_name,filename);
	dirp->DirEntry.d_namlen=strlen(filename);
	dirp->FileType=1;
	dirp->FileLength=512;
}


SHAR_EOF
if test 7345 -ne `wc -c < unixdir.c`
then
    echo shar: error transmitting "unixdir.c" '('should be 7345 chars')'
else
    echo unixdir.c
fi
fi
#         End of shar archive
exit 0
-- 

William Roberts         ARPA: liam@cs.qmc.ac.uk  (gw: cs.ucl.edu)
Queen Mary College      UUCP: liam@qmc-cs.UUCP
LONDON, UK              Tel:  01-975 5250