TweetFollow Us on Twitter

HFS
Volume Number:2
Issue Number:1
Column Tag:C Workshop

Programming for HFS Compatibility

By Mike Schuster, Consulair Corp.

Foreword

The Apple “Hierarchical File System” is a major advance in Macintosh technology. From the programmer's standpoint, HFS is an an extension to the current file manager. Many calls are the same, some calls have been extended, and there are some new HFS-specific extensions.

Internally, however, HFS is a brand-new file system. The Apple developers have done a wonderful job of making it compatible. HFS must be a part of any serious programmer's understanding.

I had planned for Mike to do two articles, to cover for me during the peak of start-up activity on our VAX AppleTalk contract and preparations for the DECUS Symposium and DEXPO show. His first article, showing how to do “pop-up” menus, was very good.

However, this month's article is so important and so full of useful information, that I have asked him to follow up with a second article, this time covering HFS internals. Next month, Mike will cover the “on-disk structures” of HFS and details of HFS internal data structures. Now onward.

Bob Denny

November, 1985

Programming for HFS Compatibility

Apple's new Hierarchical File System (HFS), shipped with Apple's Hard Disk HD20 and used by Finder 5.0, provides a much more effective mechanism for managing large volumes than the original Macintosh File System (MFS), represented by Finder 4.1 and below. In MFS, all of the files on a volume are indexed in a single directory organized as an unsorted, linear list of files names.

While adequate for small volumes, this structure proved inefficient for handling larger storage devices containing hundreds of files. When a call is made to open a file, an exhaustive, linear search must be performed to find that file's directory entry. As the number of files on the volume increases, these searches become relatively time consuming.

Fig. 1 HFS Directories Explained

The Hierarchical File System abandons this flat, unsorted approach and instead employs a hierarchical file directory, known as the File Catalog. The file catalog organizes and maintains the user's perceived desktop hierarchy of folders (directories) which contain other folders and files. The catalog is organized as a B*-Tree for quick searching and enumeration of files and folders in the hierarchy.

In addition to providing fast access to a large number of files, the catalog provides the Finder with the information it needs to render the desktop, without the substantial overhead of recreating in memory a tree describing the relationships between folders and files.

MFS performs volume space management and file extent mapping using a Allocation Block Map (ABM). In this scheme, space on the volume is allocated in equal sized units called allocation blocks. The ABM contains an entry for each allocation block on the volume. An entry is zero if the corresponding allocation block is free, and otherwise equals the index of the next allocation block in the associated file.

To guarantee fast space management and file access, MFS keeps the entire ABM for each mounted volume in memory. Thus, the ABM must be kept to a reasonable size, constraining the size of an allocation block. For larger volumes, this requirement results in severe storage fragmentation and wastage (in which the size of an allocation block often exceeds the median file size), and forces the partitioning of a storage device into several smaller, independent volumes, only a few of which are mountable at any one time.

The Hierarchical File System abandons the ABM scheme and employs instead a volume space map (VSM) and a hierarchical file block allocation structure. The VSM is used only for space management and contains one bit per allocation block on the volume, requiring an order of magnitude less space than a corresponding ABM. A bit in the VSM is one if the corresponding allocation block is in use, and otherwise is zero. File mapping is based on a B*-Tree structure which provides efficient sequential and random file mapping.

Apple designed the Hierarchical File System to be upwards compatible with the MFS. Apple was quite successful. Most applications written for MFS work correctly under HFS. The Hierarchical File System supports the existing MFS disk volumes and allows all existing MFS calls to access HFS volumes.

File Catalogs and Pathnames

A file catalog organizes the folders and files (both called nodes ) on a volume into a hierarchical tree structure. Folders are equivalent to directories in traditional file systems; they contain other folders and files. Figure 1 shows an example of HFS file and folder layout.

The node at the base of the catalog, named StartUp, is the root folder. By convention, its name is also the name of the volume. Internal nodes are folders that contain other folders and files. Folders and the nodes they contain are connected by branches in the figure.

A folder at the top of a branch is the parent of the folder or file offspring at the bottom. The offspring of StartUp are the folders System Folder, Document Folder, and Application Folder. No two offspring of the same parent may have the same name.

Leaf nodes do not have branches beneath them; they are either empty folders or files. The files Products, Logo, and MacPaint are all leaves.

Every folder in the catalog has a unique directory ID. On an HFS volume, the root folder always has a directory ID of 2; other folders have positive integers as directory ID's. In the figure the directory ID of the node System Folder is 10. Since offspring have unique names, every node in the catalog can be uniquely identified by its name and the directory ID of its parent, which is called the node's parent ID. The node specification pair {parent ID, node name} in fact constitutes the "key" used to search through the B*-Tree for a particular node. It corresponds to the quickest way for HFS to find a file or folder.

Another way to identify a node in a catalog is by a pathname. A pathname is a concatenation of node names, each separated by a colon. The node corresponding to the name on the left of each colon must be the parent of the node corresponding to the name on the right. A pathname identifying the file Status with parent ID 14 is:

StartUp:Document Folder:Sales Folder:Status

A pathname that starts at the root, such as the one above, is called a full pathname. It provides a second way of uniquely identifying a node.

Another way of identifying a node is by a partial pathname, which describes a path to a node starting from any folder in the catalog. Partial pathnames start with a colon, except in the special case where the partial pathname contains only one name. When using partial pathnames, the directory ID of the folder from which the pathname begins must also be specified.

A partial pathname identifying the file Status with parent ID 12, starting from Document Folder (3) is:

:Sales Folder:Sales Charts:Status

This pathname begins at Document Folder and moves down the tree to Status. It is also possible to move up the tree by using two or more consecutive colons.

A pathname identifying the file Status with parent ID 14, starting from Document Folder is:

:Sales Folder:Sales Charts::Status

Since character strings are limited by the file system to at most 255 characters in length, it may not be possible to identify every node in a catalog with a full pathname.

To access a file deep within a catalog of a large volume, an application must construct a full pathname to reach some intermediate folder along the path to the desired file and obtain that folder's directory ID. Then it must use that directory as the starting point for a partial pathname to reach the file or another folder further along the path.

Working Directories and File System Compatibility

The Hierarchical File System provides yet another way of identifying a particular node in a catalog. An application may specify a particular folder as a working directory and then later use this working directory as a shorthand notation to identify nodes relative to that directory. When the file system creates a working directory, it stores the folder's directory ID as well as a reference to the volume on which the folder resides into a working directory control block (WDCB). The file system then returns a unique working directory reference number (WDRefNum) which the application uses on subsequent calls to the file system to refer to this folder. Each working directory control block also contains an identifier that allows discrimination between working directories set up by different callers. Typically, the identifier equals the application's creator bytes. This convention allows unneeded WDCB to be easily identified when transfering between applications.

Working directories and their reference numbers are the keys to upward compatibility with MFS. Like volume reference numbers, working directory references numbers are negative integers, but the set of WDRefNums are always distinct from the set of VRefNums. Hence, a WDRefNum may be substituted for a VRefNum in any file system call without ambiguity. When a WDRefNum is used in place of a VRefNum, the file system looks up the volume reference number and directory ID from the associated working directory control block.

The HFS Standard File Package uses this scheme to allow the user to select from files in different directories without changing Standard File's external interface. The only difference is that a WDRefNum is returned instead of a VRefNum in the SFReply.vRefNum field. If the application simply passes this value to the PBOpen routine, the desired file will be opened. Existing applications under MFS that use Standard File in this manner will properly run without modification under HFS.

Applications that take the SFReply.vRefNum, convert it to a volume name and then concatenate the SFReply.fName, will not function correctly under HFS -- the user can only open files in the root directory of the volume (in fact, such applications do not even run correctly under MFS; there could be two mounted volumes with the same name). Consult the Macintosh Technical Note #49: "HFS Compatibility Issues" for further information.

File Manager Calls

The Hierarchical File System supports all existing MFS calls to both MFS and HFS volumes and provides a set of additional calls that operate on the catalog hierarchy of HFS volumes directly. HFS also provides a set of extensions to some of the MFS calls that provide additional functionality and information. The table in figure 2 at the end of this article lists each call alphabetically, its trap word, and the structure of the call's I/O parameter block.

HFS calls that are extensions of existing MFS routines use the same trap word as the corresponding MFS call, except that bit 9 of the trap word is set. These calls are listed in the table on the same line as their corresponding MFS call. The entirely new HFS calls share a common trap word A260 (_HFSDispatch); the individual routines are identified by a call identifier word placed in register D0. Like all other calls, _HFSDispatch returns an I/O result code in D0.

All of the HFS calls take a directory ID as an input parameter, specified in the new I/O parameter block field ioDirID. This directory ID is used to refer to the folder itself or, in conjunction with a partial pathname from that folder, to other nodes in the catalog. The specification of a directory ID in the ioDirID field overrides the directory ID specified by a WDRefNum in the ioVRefNum field. If this is undesireable, set ioDirID to zero. If a VRefNum is passed in ioVRefNum, a ioDirID of zero will default to the root directory ID.

The basic functions of the HFS calls are summarized below. (see the Apple User Education publication "The File Manager," 10/8/85 or later, for more information):

PBAllocContig is identical to PBAllocate, but forces the allocation of a single contiguous set of allocation blocks.

PBCatMove moves files or folders from one folder to another on the same volume. The source is specified by ioVRefNum, ioDirID and ioFileName. The destination is specified by ioNewDirID and ioNewName.

PBCloseWD closes a working directory allocated by PBOpenWD.

PBHCreate is identical to PBCreate, but accepts a directory ID in ioDirID.

PBHDelete is identical to PBDelete, but accepts a directory ID in ioDirID. PBDelete and PBHDelete may be used to delete folders, but the folder must be empty before it can be deleted.

PBDirCreate is identical to PBCreate, except that it creates a new folder instead of a file. It accepts a directory ID in ioDirID.

PBGetCatInfo returns a superset of the information returned by PBGetFInfo in an enlarged parameter block. PBGetCatInfo works on folders as well as files. It accepts a directory ID in ioDirID and a value in ioFDirIndex which specifies how the node is to be identified. Information may be returned for a specified node, or for the nth node in a folder.

PBGetFCBInfo returns information about an open file given its path reference number in ioRefNum, or for the nth open file, where n may be limited to count only files on a given volume.

PBHGetFInfo is identical to PBGetFInfo, but accepts a directory ID in ioDirID.

PBHGetVInfo returns a superset of the information returned by PBGetVInfo in an enlarged parameter block.

PBHGetVol returns the default volume and default directory.

PBHGetWDInfo returns information contained in a working directory given its WDRefNum, or for the nth working directory, where n may be limited to count only working directories having a specified descrimination identifier.

PBHSetVInfo allows modification of information associated with a volume.

PBHOpen is identical to PBOpen, but accepts a directory ID in ioDirID.

PBHOpenRF is identical to PBOpenRF, but accepts a directory ID in ioDirID.

PBHOpenWD opens a working directory. PBHOpenWD returns a WDRefNum in ioVRefNum.

PBHRename is identical to PBRename but accepts a directory ID in ioDirID. PBHRename cannot change the directory a file is in. PBRename and PBHRename may be used to rename folders.

PBHRstFLock is identical to PBRstFLock, but accepts a directory ID in ioDirID.

PBSetCatInfo allows modification of a superset of the information modified by PBSetFInfo. It works on folders as well as files.

PBHSetFInfo is identical to PBSetFInfo, but accepts a directory ID in ioDirID.

PBHSetFLock is identical to PBSetFLock, but accepts a directory ID in ioDirID.

PBHSetFVers is identical to PBSetFVers, but accepts a directory ID in ioDirID.

PBHSetVol sets the default volume as well as the default directory.

Example C Code

The following routines are offered as examples of HFS usage. I chose them both to illustrate some of the new calls as well as to provide useful ingredients for inclusion in your own toolbox.

Enumerating a Volume's Files

The first example shows how to enumerate all of the files on all mounted volumes. The function enumerate takes a single argument fileproc; a pointer to a function. Fileproc is an “action routine” that you supply, and is called once for each file found on each volume. It should be declared as:

int fileproc(vrefnum, vp, fp)
 int16 vrefnum;
 HVolumeParam *vp;
 HFileInfoParam *fp;

Each time fileproc is called, it is passed three arguments; a VRefNum or WDRefNum indicating which volume and directory contains the file, a pointer to the volume's information parameter block, and a pointer to the file's information parameter block. Enumerate supports the both MFS and HFS volumes. It is also designed to work on MFS only machines.Enumerate begins by searching for mounted volumes using a loop:

for (vp.ioVolIndex = 1; !PBHGetVInfo(&vp, 0);
 vp.ioVolIndex++ )
 ...

The ioVolIndex field indexes the volumes sequentially, without gaps, so it can be used as a way of finding mounted volumes. The loop terminates when the error nsvErr (no such volume) is returned. The HFS call PBHGetVInfo can be made to a system supporting MFS calls only, since bit 9 in the trap word is ignored by MFS.

After volume information has been obtained, enumerate decides if the volume is HFS or MFS. This is done via the test:

if (FCBLen == -1 || vp.ioVSigWord == mfsSigWord)
 ...

Enumerate first checks the global word FCBLen (address 0x3f6). If this word is -1, the file system supports MFS calls only. Otherwise its value equals the length of the file control block (FCB) and indicates that both MFS and HFS calls are supported by the file system.

If HFS calls are supported, then the volume's file system signature word ioVSigWord is checked. Its value is mfsSigWord (0xd2d7) for MFS volumes and hfsSigWord (0x5456) for HFS volumes. In this test, FCBLen is checked first, since the ioVSigWord field is not defined by MFS.

The files on an MFS volume are found using a loop:

for (dp.ioFDirIndex = 1; !PBGetFInfo(&dp, 0);      dp.ioFDirIndex++)
 ...

The ioFDirIndex field indexes the files sequentially, without gaps, so it can be used as a way of finding all files. The loop terminates when the error nsfErr (no such file) is returned. Fileproc is invoked once for each file.

The files on an HFS volume are found using a breath first search of the volume's file catalog. The algorithm enumerates the offspring of each folder in the catalog, starting at the root, and maintains a queue of those folders that have been encountered in the search, but whose offspring have not yet been enumerated. The field ioVDirCnt, in the volume's information parameter block, specifies the total number of folders in the volume's catalog. Its value is an upper bound on the size of the queue.

Before the offspring of a folder are enumerated, a working directory for the folder is created so that a WDRefNum can be passed to fileproc as its vrefnum argument. The descrimination identifier of the working directory is set to 'ENUM'. Then the offspring of the folder are enumerated using a loop:

for (dp.ioFDirIndex = 1, dp.ioDrDirID = dir; 
 !PBGetCatInfo(&dp, 0); dp.ioFDirIndex++, dp.ioDrDirID = dir)
 ...

The ioFDirIndex field indexes the offspring sequentially, without gaps. The ioDrDirID field in the PBGetCatInfo call is both an input and an output parameter. On input, it equals the folder's directory ID (maintained by the variable dir); on output, it equals the file number or the directory ID of the offspring. The ioDirFlg flag (0x10) in the ioFlAttrib field discriminates the offspring as a folder or a file. If the offspring is a file, fileproc is called, otherwise the folder is placed on the queue. The folder's working directory is closed after the last of its offspring is found. After completing the loop and closing the working directory, enumerate then handles the next folder in the queue, if any.

enumerate(fileproc)
 int (*fileproc)();
 {
 HVolumeParam vp;
 DirInfoParam dp;
 WDParam wp;
 Str255 vname;
 Str255 dname;
 int32 **dirs;
 int32 *dirp;
 int32 dir;
 int ok;
 
 /* initialize params */
 vp.ioNamePtr = &vname;
 dp.ioNamePtr = &dname;
 wp.ioNamePtr = 0l;
 wp.ioWDProcID = 'ENUM';
 
 /* enumerate each volume */
 for (vp.ioVolIndex = 1; !PBHGetVInfo(&vp, 0); vp.ioVolIndex++)
 {
 dp.ioVRefNum = vp.ioVRefNum;
 
 /* if MFS volume, enumerate each file */
 if (FCBLen == -1 || vp.ioVSigWord == mfsSigWord)
 for (dp.ioFDirIndex = 1; !PBGetFInfo(&dp, 0); dp.ioFDirIndex++)
 (*fileproc)(dp.ioVRefNum, &vp, &dp);
 
 /* if HFS volume, allocate space for directory queue */
 else if (dirs = (int32 **) NewHandle(vp.ioVDirCnt * sizeof(int32)))
 {
 /* place root into directory queue */
 HLock(dirs);
 dirp = *dirs;
 *dirp++ = rootDirID;
 
 /* enumerate directory queue */
 while (dirp > *dirs)
 {
 dir = *--dirp;
 wp.ioVRefNum = dp.ioVRefNum;
 wp.ioWDDirID = dir;
 
 /* open working directory */
 if (!PBOpenWD(&wp, 0))
 {
 /* enumerate files in directory */
 for (dp.ioFDirIndex = 1, dp.ioDrDirID = dir; 
 !PBGetCatInfo(&dp, 0); dp.ioFDirIndex++,
  dp.ioDrDirID = dir)
 {
 /* if offspring is a directory, place on queue */
 if (dp.ioFlAttrib & ioDirFlg)
 *dirp++ = dp.ioDrDirID;
 
 /* if offspring is a file, call argument function */
 else
 (*fileproc)(wp.ioVRefNum, &vp, &dp);
 }
 
 /* all done with working directory */
 PBCloseWD(&wp, 0);
 }
 }
 DisposHandle(dirs);
 }
 }
 }

Constructing a Full Pathname

The second example shows how to determine the full pathname of a working directory identified by its WDRefNum. The function pathname takes a pointer to the resulting string, a WDRefNum, and an integer specifying the maximum length of the string. In a manner similar to the previous example, pathname works for both MFS and HFS volumes, as well as on MFS only machines.

If the argument WDRefNum refers to a MFS volume, or to the root directory of a HFS volume, pathname simply returns the volume's name. Pathname accomplishes this by checking the volume's signature word and comparing the argument WDRefNum to the volume's VRefNum.

If the argument WDRefNum refers to a working directory, then its directory ID is found using the PBGetWDInfo call. Pathname uses this directory ID as a starting point for a walk up the volume's file catalog. At each step toward the root, the PBGetCatInfo call is made to find the folder's name, which is appended to the front of the accumulated pathname via the functions strtac and strntac (the reversed versions of strcat and strncat). As a reference, the definition of strtac follows pathname.

Notice that the ioFDirIndex field of PBGetCatInfo's parameter block is set to -1. This value forces PBGetCatInfo to return information about the folder identified by the directory ID in ioDirID, and to ignore the name (if any) in ioNamePtr. In this way, PBGetCatInfo treats ioNamePtr as an output only field and uses it only to return the folder's name.

char *pathname(pname, wdrefnum, n)
 char *pname;
 int16 wdrefnum;
 int16 n;
 {
 HVolumeParam vp;
 WDParam wp;
 DirInfoParam dp;
 Str255 dname;
 
 /* initialize params */
 pname[0] = '\0';
 n--;
 vp.ioNamePtr = &dname;
 vp.ioVRefNum = wdrefnum;
 vp.ioVolIndex = 0;
 wp.ioNamePtr = 0l;
 wp.ioVRefNum = wdrefnum;
 wp.ioWDIndex = 0;
 wp.ioWDProcID = 0l;
 dp.ioNamePtr = &dname;
 dp.ioFDirIndex = -1;
 
 /* get volume information */
 if (!PBHGetVInfo(&vp, 0))
 /* if MFS or HFS root, return volume name */
 if (FCBLen == -1 || vp.ioVSigWord == mfsSigWord || 
 vp.ioVRefNum == wdrefnum)
 strncat(pname, ptocstr(vp.ioNamePtr), n);
 
 /* get working directory information */
 else if (!PBGetWDInfo(&wp, 0))
 {
 /* traverse path from working directory to root */
 dp.ioVRefNum = wp.ioWDVRefNum;
 dp.ioDrParID = wp.ioWDDirID;
 do
 {
 /* get next node information */
 dp.ioDrDirID = dp.ioDrParID;
 if (PBGetCatInfo(&dp, 0))
 break;
 
 /* concatenate node name to result */
 strntac(strtac(pname, ":"), 
 ptocstr(dp.ioNamePtr), n - 1);
 n -= strlen(dp.ioNamePtr) + 1;
 }
 while (dp.ioDrDirID != rootDirID);

 /* remove last colon */
 pname[strlen(pname) - 1] = '\0';
 }
 return pname;
 }

char *strtac(s1, s2)
 register char *s1, *s2;
 {
 register char *result = s1;
 register int n = strlen(s2);

 while (*s1++)
 ;
 while (--s1 >= result)
 *(s1 + n) = *s1;
 s1++;
 while (*s2)
 *s1++ = *s2++;
 return result;
 }

Using the Examples

The final example shows a sample usage of the functions enumerate and pathname. It prints the full pathname of each file on all mounted volumes.

fileproc(wdrefnum, vp, fp)
 int16 wdrefnum;
 HVolumeParam *vp;
 DirInfoParam *fp;
 {
 char name[256];
 
 pathname(name, wdrefnum, sizeof name);
 ptocstr(fp->ioNamePtr);
 printf("%s:%s\n", name, fp->ioNamePtr);
 ctopstr(fp->ioNamePtr);
 }

main()
 {
 enumerate(&fileproc);
 }

Consulair C Version Double-Clickable Application

/* Put the above routines together into a complete program. */
/* This example and glue routines are specific to */
/* Provide a similar front end for your C system. */

#include "stdio.h"
#include "hfs.h"

extern StringPtr ctopstr();
extern char *ptocstr();
extern char *strcat();
extern int strlen();
extern char *strncat();
extern char *strntac();
extern char *strtac();
extern OSErr pbCall0();

#define PBCloseWD(pb, a)  pbCall0(pb, a, 0xA260, 2)
#define PBOpenWD(pb, a)   pbCall0(pb, a, 0xA260, 1)
#define PBGetWDInfo(pb, a)pbCall0(pb, a, 0xA260, 7)

#define PBHGetVInfo(pb, a)pbCall0(pb, a, 0xA207)
#define PBGetCatInfo(pb, a) pbCall0(pb, a, 0xA260, 9)
#define PBGetFInfo(pb, a) pbCall0(pb, a, 0xA00C)

#asm
pbcall0:
 tst.b  d1
 beq.s  @1
 or.w #$400,d2
@1 lea  @2,a0
 move.w d2,(a0)
 move.l d0,a0
 move.w d3,d0
@2 dc.w 0
 rts
#endasm

Fig. 2 New Trap Calls for HFS

MFS Calls Trap Parameter HFS Calls Trap Parameter

PBAllocate A010 IOParam PBAllocContig A210 HIOParam

PBCatMove A260,5 CMoveParam

PBClose A001 IOParam

PBCloseWD A260,2 WDParam

PBCreate A008 FileParam PBHCreate A208 HFileParam

PBDelete A009 FileParam PBHDelete A209 HFileParam

PBDirCreate A260,6 HFileParam

PBEject A017 Param

PBFlushFile A045 IOParam

PBFlushVol A013 Param

PBGetCatInfo A260,9 HFileInfo/DirInfoParam

PBGetEOF A011 IOParam

PBGetFCBInfo A260,8 FCBParam

PBGetFInfo A00C FileParam PBHGetFInfo A20C HFileParam

PBGetFPos A018 IOParam

PBGetVInfo A007 VolumeParam PBHGetVInfo A207 HVolumeParam

PBGetVol A014 Param PBHGetVol A214 WDParam

PBGetWDInfo A260,7 WDParam

PBHSetVInfo A260,11 HVolumeParam

PBMountVol A00F Param

PBOffLine A035 Param

PBOpen A000 IOParam PBHOpen A200 HIOParam

PBOpenRF A00A IOParam PBHOpenRF A20A HIOParam

PBOpenWD A260,1 WDParam

PBRead A002 IOParam

PBRename A00B IOParam PBHRename A20B HIOParam

PBRstFLock A042 FileParam PBHRstFLock A242 HFileParam

PBSetCatInfo A260,10 HFileInfo/DirInfoParam

PBSetEOF A012 IOParam

PBSetFInfo A00D FileParam PBHSetFInfo A20D HFileParam

PBSetFLock A041 FileParam PBHSetFLock A241 HFileParam

PBSetFPos A044 IOParam

PBSetFVers A043 IOParam PBHSetFVers A243 HIOParam

PBSetVol A015 Param PBHSetVol A215 WDParam

PBUnmountVol A00E Param

PBWrite A003 IOParam

hfs.h file for Consulair C
#define int8 char/* 8-bit integer */
#define int16 short/* 16-bit integer */
#define int32 long /* 32-bit integer */
typedef char *Ptr; /* pointer */
typedef Ptr *Handle; /* handle */
typedef int16 (*ProcPtr)(); /* pointer to proc ret int16 */
typedef ProcPtr *ProcHandle;/* handle to proc ret int16 */
#define String(size) struct {unsigned char length; 
 char text[size];}
typedef String(255) Str255; /* max  length pascal str */
typedef Str255 *StringPtr;/* ptr to max  length p str */
typedef StringPtr *StringHandle;  /* handle  max  length p str*/
typedef int16 OSErr; /* operating sys err code */
typedef int32 OSType;/* OS  type code */
typedef Ptr QElemPtr;/* ptr to queue element */

#define FCBLen *((int16 *) 0x3f6)  /* MFS == -1, HFS == length 
 of FCB */
#define mfsSigWord 0xd2d7 /* MFS volume signature */
#define hfsSigWord 0x4244 /* HFS volume signature */
#define rootDirID 2/* HFS root vol dir id */
#define ioDirFlg 0x10/* catalog node dir flag */

typedef struct 
 {
 OSType fdType;  /* file's type */
 OSType fdCreator; /* file's creator */
 int16 fdFlags;  /* flags */
 int16 fdLocation[2];/* file's location */
 int16 fdFldr;   /* file's window */
 } FInfo, *FInfoPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioRefNum; /* path reference number */
 int8 ioVersNum; /* version number */
 int8 ioPermssn; /* read/write permission */
 Ptr ioMisc;/* miscellaneous */
 Ptr ioBuffer;   /* data buffer */
 int32 ioReqCount; /* requested number of bytes */
 int32 ioActCount; /* actual number of bytes */
 int16 ioPosMode;/* position mode and newline */
 int32 ioPosOffset;/* positioning offset */
 } IOParam, *IOParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioFRefNum;/* path reference number */
 int8 ioFVersNum;/* version number */
 int8 filler1;   /* unused */
 int16 ioFDirIndex;/* sequence number */
 int8 ioFlAttrib;/* attributes */
 int8 ioFlVersNum; /* version number */
 FInfo ioFlFndrInfo; /* finder information */
 int32 ioFlNum;  /* file number */
 int16 ioFlStBlk;/* 1st alloc block of data fork */
 int32 ioFlLgLen;/* logical end-file of data fork */
 int32 ioFlPyLen;/* phys end-file of data fork */
 int16 ioFlRStBlk; /* 1st alloc block of res fork */
 int32 ioFlRLgLen; /* logical end-file of res fork */
 int32 ioFlRPyLen; /* phys end-of-file of res fork */
 int32 ioFlCrDat;/* creation date */
 int32 ioFlMdDat;/* modification date */
 } FileParam, *FileParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int32 filler2;  /* unused */
 int16 ioVolIndex; /* volume index */
 int32 ioVCrDate;/* creation time and date */
 int32 ioVLsBkUp;/* last backup time and date */
 int16 ioVAtrb;  /* attributes */
 int16 ioVNmFls; /* number of files in directory */
 int16 ioVDirSt; /* first block of directory */
 int16 ioVBlLn;  /* length of direct.  in blocks */
 int16 ioVNmAlBlks;/* no. of allocation blocks */
 int32 ioVAlBlkSiz;/* size of allocation block */
 int32 ioVClpSiz;/* no. of bytes to allocate */
 int16 ioAlBlSt; /* 1st allocation block in map */
 int32 ioVNxtFNum; /* next unused file number */
 int16 ioVFrBlk; /* no. of unused alloc blocks */
 } VolumeParam, *VolumeParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioRefNum; /* path reference number */
 int16 filler;   /* unused */
 int32 ioFCBIndx;/* fcb index for _getfcbinfo */
 int32 ioFCBFlNm;/* file number */
 int16 ioFCBFlags; /* flags */
 int16 ioFCBStBlk; /* first allocation block of file */
 int32 ioFCBEOF; /* logical end-of-file */
 int32 ioFCBPLen;/* physical end-of-file */
 int32 ioFCBCrPs;/* mark */
 int16 ioFCBVRefNum; /* volume reference number */
 int32 ioFCBClpSiz;/* file clump size */
 int32 ioFCBParID; /* parent directory id */
 } FCBParam, *FCBParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioRefNum; /* path reference number */
 int8 ioVersNum; /* version number */
 int8 ioPermssn; /* read/write permission */
 Ptr ioMisc;/* miscellaneous */
 Ptr ioBuffer;   /* data buffer */
 int32 ioReqCount; /* requested number of bytes */
 int32 ioActCount; /* actual number of bytes */
 int32 filler;   /* unused */
 int32 ioDirID;  /* directory id */
 } HIOParam, *HIOParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioFRefNum;/* path reference number */
 int16 filler2;  /* unused */
 int16 ioFDirIndex;/* sequence number of file */
 int8 ioFlAttrib;/* attributes */
 int8 filler3;   /* version number */
 FInfo ioFlFndrInfo; /* finder information */
 int32 ioDirID;  /* directory id */
 int16 ioFlStBlk;/* 1st alloc block of data fork */
 int32 ioFlLgLen;/* logical end-file of data fork */
 int32 ioFlPyLen;/* phys end-file of data fork */
 int16 ioFlRStBlk; /* 1st alloca  block of res fork */
 int32 ioFlRLgLen; /* logical end-file of res fork */
 int32 ioFlRPyLen; /* phys end-of-file of res fork */
 int32 ioFlCrDat;/* creation time and date */
 int32 ioFlMdDat;/* modification time and date */
 } HFileParam, *HFileParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int32 filler4;  /* unused */
 int16 ioVolIndex; /* volume index */
 int32 ioVCrDate;/* creation time and date */
 int32 ioVLsMod; /* modification time and date */
 int16 ioVAtrb;  /* attributes */
 int16 ioVNmFls; /* number of files in directory */
 int16 ioVBitMap;/* first block of vol  bitmap */
 int16 ioVAllocPtr;/* vol  space allocation ptr */
 int16 ioVNmAlBlks;/* no. of allocation blocks */
 int32 ioVAlBlkSiz;/* size of allocation block */
 int32 ioVClpSiz;/* default clump size */
 int16 ioAlBlSt; /* first block in block map */
 int32 ioVNxtFNum; /* next free node id */
 int16 ioVFrBlk; /* no.  of unused alloca  blks */
 int16 ioVSigWord; /* volume signature */
 int16 ioVDrvInfo; /* drive number */
 int16 ioVDRefNum; /* driver reference number */
 int16 ioVFSID;  /* file system identifier */
 int32 ioVBkUp;  /* last backup time and date */
 int16 ioVSeqNum;/* seq no. in backup set */
 int32 ioVWrCnt; /* volume write count */
 int32 ioVFilCnt;/* number of files on volume */
 int32 ioVDirCnt;/* no. of directories on vol */
 int32 ioVFndrInfo[8];  /* finder information */
 } HVolumeParam, *HVolumeParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioFRefNum;/* file reference number */
 int16 filler1;  /* unused */
 int16 ioFDirIndex;/* file directory index */
 int8 ioFlAttrib;/* attributes */
 int8 filler2;   /* unused */
 FInfo ioFlFndrInfo; /* finder information */
 int32 ioFlNum;  /* file number */
 int16 ioFlStBlk;/* first alloc blk of data fork */
 int32 ioFlLgLen;/* logical end-of-file data fork */
 int32 ioFlPyLen;/* phys end-of-file data fork */
 int16 ioFlRStBlk; /* 1st alloca blk of res fork */
 int32 ioFlRLgLen; /* logical end-file of res fork */
 int32 ioFlRPyLen; /* phys end-file of res fork */
 int32 ioFlCrDat;/* creation time and date */
 int32 ioFlMdDat;/* modification time and date */
 int32 ioFlBkDat;/* last backup time and date */
 FInfo ioFlXFndrInfo;/* additional finder info */
 int32 ioFlParID;/* parent directory id */
 int32 ioFlClpSiz; /* file's clump size */
 } HFileInfoParam, *HFileInfoParamPtr;

typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 ioFRefNum;/* file reference number */
 int16 filler1;  /* unused */
 int16 ioFDirIndex;/* file directory index */
 int8 ioFlAttrib;/* attributes */
 int8 filler2;   /* unused */
 int16 ioDrUsrWds[8];/* directory's user info */
 int32 ioDrDirID;/* directory id */
 int16 ioDrNmFls;/* number of files in directory */
 int16 filler3[9]; /* unused */
 int32 ioDrCrDat;/* creation time and date */
 int32 ioDrMdDat;/* modification time and date */
 int32 ioDrBkDat;/* last backup time and date */
 int16 ioDrFndrInfo[8]; /* finder information */
 int32 ioDrParID;/* parent id */
 int32 filler4;  /* unused */
 } DirInfoParam, *DirInfoParamPtr;
typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int32 filler1;  /* unused */
 StringPtr ioNewName;/* new name */
 int32 filler2;  /* unused */
 int32 ioNewDirID; /* new directory id */
 int32 filler3[2]; /* unused */
 int32 ioDirID;  /* directory id */
 } CMoveParam, *CMoveParamPtr;
typedef struct
 {
 QElemPtr qLink; /* next queue entry */
 int16 qType;    /* queue entry type */
 int16 ioTrap;   /* routine trap */
 Ptr ioCmdAddr;  /* routine address */
 ProcPtr ioCompletion;  /* completion routine */
 OSErr ioResult; /* result code */
 StringPtr ioNamePtr;/* name */
 int16 ioVRefNum;/* reference number */
 int16 filler1;  /* unused */
 int16 ioWDIndex;/* working directory index */
 int32 ioWDProcID; /* working directory's id */
 int16 ioWDVRefNum;/* working dir vol ref no. */
 int16 filler2[7]; /* unused */
 int32 ioWDDirID;/* working directory's dir id */
 } WDParam, *WDParamPtr;
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

RapidWeaver 8.10.0 - Create template-bas...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
ForkLift 3.5.7 - Powerful file manager:...
ForkLift is a powerful file manager and ferociously fast FTP client clothed in a clean and versatile UI that offers the combination of absolute simplicity and raw power expected from a well-executed... Read more
1Password 8.7.3 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Microsoft Remote Desktop 10.7.7 - Connec...
Microsoft Remote Desktop for Mac is an application that allows connecting to virtual apps or another PC remotely. Discover the power of Windows with Remote Desktop designed to help you manage your... Read more
NeoOffice 2022.1 - Mac-tailored, OpenOff...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
TotalFinder 1.14.2 - Adds tabs, hotkeys,...
Note: TotalFinder is no longer available for sale. Please read this post with announcement here. TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder... Read more
coconutBattery 3.9.8 - Displays info abo...
With coconutBattery you're always aware of your current battery health. It shows you live information about your battery such as how often it was charged and how is the current maximum capacity in... Read more
GraphicConverter 11.6.2 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Spotify 1.1.88.612 - Stream music, creat...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
xScope 4.6 - Onscreen graphic measuremen...
xScope is powerful set of tools that are ideal for measuring, inspecting, and testing on-screen graphics and layouts. Its tools float above your desktop windows and can be accessed via a toolbar,... Read more

Latest Forum Discussions

See All

Niantic Announces NBA Licensed Augmented...
Niantic took what they had learned from their augmented reality multiplayer game Ingress and applied it to the massively popular Pokemon IP to create the cultural phenomenon known as Pokemon GO back in 2016. Ever since that Pokemon GO explosion back... | Read more »
‘Hero Emblems II’ Review – There’s No Ca...
Seven and a half years ago, the original Hero Emblems ($2.99) was released on the App Store. Just under six years ago, its sequel was formally announced and a trailer was shown. A couple of weeks after that, I played Hero Emblems II ($6.99) for the... | Read more »
Pokemon GO: Starly to feature in July Co...
For the upcoming Community Day, Starly is all set to be the star. In an official blog post, Niantic has shared details about the July community day on 17th, which will run from 11 AM to 2 PM. The event will feature Starly, the Starling Pokemon. [... | Read more »
King's Choice, the medieval-themed...
On the anniversary of its first year of release King's Choice, from ONEMT, is celebrating by rewarding its players with a selection of In-game goodies. There will also be limited-time events and a chance for players to be featured in the special... | Read more »
‘King’s Choice’, the Medieval-Themed RPG...
King’s Choice is celebrating its one year anniversary by rewarding players with a number of special In-game goodies. The game’s publisher, ONEMT, will also be hosting limited-time events, as well as giving players the opportunity to be featured in... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for June 27th, 2022. We’re in the middle of a brutal heat wave here in Japan, and the temperature outside as I write this is 38 degrees Celsius. Wow! Let’s stay inside and play games,... | Read more »
Best iPhone Game Updates: ‘Horizon Chase...
Hello everyone, and welcome to the week! It’s time once again for our look back at the noteworthy updates of the last seven days. A nice variety this week, if I do say so myself. And I do, because who else would be saying anything in an article... | Read more »
Apex Legends Mobile introduces a new Arm...
Apex Legends, the popular EA battle royale, recently made its way to mobile and was well-received. Since the release, Respawn has been actively making additions to the game. And on the same note, Apex Legends Mobile is getting a new mode - Armed... | Read more »
‘Final Fantasy Record Keeper’ Is Shuttin...
Back in March 2015, Square Enix released Final Fantasy Record Keeper (Free) on the US App Store. It has received many updates over the years through collaborations across Square Enix’s other games and more. | Read more »
The Clash Royale 2022 Summer Update is h...
Clash Royale, the 2016 multiplayer battle arena game, developed by Supercell, was a huge success and continues to hold the attention of millions worldwide. [Read more] | Read more »

Price Scanner via MacPrices.net

July 4th Sale at Expercom: $200 off any 16″ M...
Apple reseller Expercom has 16″ M1 Pro and M1 Max MacBook Pros available for $200 off MSRP as part of their July 4th sale. In addition to their MacBook Pro sale prices, take $50 off AppleCare+ when... Read more
10.2″ Apple iPads (WiFi models) are on sale f...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for up to $20-$50 off MSRP for a limited time. Their prices are the lowest price currently available for one of these iPads. All models are... Read more
10-Core M1 Pro 14″ MacBook Pros on sale for $...
B&H Photo is offering $200 discounts on Apple’s new 14″ M1 Pro MacBook Pros with 10-Core CPUs (16GB RAM/1TB SSDs). Free 1-2 day shipping is available to most US addresses, and both models are in... Read more
B&H has 16-inch M1 Pro MacBook Pros in st...
New Space Gray 16″ MacBook Pros with Apple’s M1 Pro CPUs are in stock and on sale today at B&H Photo for $200 off Apple’s MSRP. Sale prices are for M1 Pro models with 512GB or 1TB of SSD storage... Read more
Price drop! 13″ M1 MacBook Pro with 512GB SSD...
Amazon has dropped prices on recently-discontinued 13″ M1 MacBook Pros with a 512GB SSD by $200 off Apple’s original MSRP. Shipping is free: – 2020 13″ MacBook Pro (Space Gray or Silver) M1 CPU/512GB... Read more
Deal Alert! 14″ Apple MacBook Pros with M1 Pr...
Amazon has 14″ MacBook Pros with 8-Core M1 Pro CPUs back on sale for $200 off MSRP, only $1799. Shipping is free. Be sure to make your purchase from Amazon rather than a third-party seller: – 14″ M1... Read more
16″ MacBook Pros with Apple M1 Pro CPUs are b...
Amazon is discounting new 16″ MacBook Pros with 10-Core Apple M1 Pro CPUs by $200 off MSRP again today. Be sure to select Amazon as the seller rather than a third-party seller, and note that Amazon’s... Read more
13″ M1 MacBook Airs with 16GB of RAM availabl...
Apple has 13″ M1 MacBook Airs (8-Core CPU/7-Core GPU) in stock today with 16GB of RAM for $190 off MSRP, Certified Refurbished. Apple includes a standard one-year warranty with these models, each... Read more
Apple Watch SE models are on sale for $50 off...
Amazon has Apple Watch SE GPS models on sale today for $50 off MSRP including free shipping. Their prices are the lowest currently available for SE Watches anywhere: – 40mm Apple Watch SE GPS: $229,... Read more
Apple launches 2022 Back to School promotion:...
Apple has launched their Back to School promotion for 2022, and here are the details. As part of this promotion, Apple will include a free $150 Apple Gift Card with the purchase of any MacBook Air,... Read more

Jobs Board

Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Read more
Sales Floor Associate - *Apple* Blossom Mal...
Sales Floor Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Sephora Beauty Advisor - *Apple* Blossom Ma...
Sephora Beauty Advisor - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Sr Product Manager, *Apple* TV Platforms Ex...
**Job Number** 70594BR **Job Title** Sr Product Manager, Apple TV Platforms Experience, Peacock **Business Segment** Direct-to-Consumer **Sub-Business** DTC Product Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.