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