I need help with file management

sentient06

Member
Hello everyone,

I've been working on a couple of projects for new Classic Mac software. Yeah, exciting stuff. I've never tried my hands on this before, so I got a bunch of books, I got Inside Macintosh at hand, I've been through tutorials and started coding.

I am working on Mac OS 9.2.2 and CodeWarrior 5 (Pro 8, but it says 5, I don't know, it's confusing). I am planning on compiling for PowerPC and 68k in a fat bundle or maybe separate binaries.

I am still assessing the feasability of my project, but so far I got a SHA-1 implementation I've made in C, converted into a library that can be imported into a C++ project. I also got a small ZLib library at hand. My next challenge is to create, delete and assess the existence of files. Here is where my coding spree came to a halt, and I think I need a hand figuring this out.

My idea is simple: first I create a simple function that will check the existence of a file, and tell me whether it's a regular file or a directory, and if there's an error, report the error. Later, if all is working, I can nest the routine in an object or something.

I make the checks by using flags. I started with boolean flags, called exists, isDir, isFile, error, which I would then pass to my function. It didn't work at all. I've changed the type from booleans to unsigned chars to make the code simpler to work with the libraries from the Toolbox, and I kept getting errors of non-existent file/dir. So I thought maybe that's because the path is relative. So I've added 2 parameters for volume and parent directory, like so:

C++:
   // Variables for volume reference number and directory ID
    short vRefNum = 0;
    long dirID = 0;

    // Handle relative paths by getting the current volume and directory
    err = HGetVol(NULL, &vRefNum, &dirID);
    if (err != noErr) {
        printf("Error getting current volume/directory: %d\n", err);
        return err;
    }

    // Call CheckPathStatus for a relative path (like "abc") using the current directory
    err = CheckPathStatus(path, &exists, &isDir, &isFile, &error, vRefNum, dirID);

My function is there, it's called "CheckPathStatus". Here's the implementation.

C++:
OSErr CheckPathStatus(
    const char* path,
    unsigned char *exists,
    unsigned char *isDir,
    unsigned char *isFile,
    unsigned char *error,
    short vRefNum,   // Volume reference number (for full path handling)
    long dirID       // Directory ID (for full path handling)
) {
    FSSpec fileSpec;
    CInfoPBRec catInfo;
    OSErr err;
    Str255 pPath;  // Pascal string for the path

    *exists = 0;
    *isDir = 0;
    *isFile = 0;
    *error = 0;

    // Convert C string to Pascal string, I can post this function if you want:
    CtoPStr(path, pPath);

    // Convert path to an FSSpec
    err = FSMakeFSSpec(vRefNum, dirID, pPath, &fileSpec);
    if (err != noErr) {
        printf("Error in FSMakeFSSpec: %d\n", err);
        *error = 1;
        return err;
    }

    // Set up the CInfoPBRec to get info about the file
    catInfo.hFileInfo.ioNamePtr = fileSpec.name;
    catInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum;
    catInfo.hFileInfo.ioDirID = fileSpec.parID;
    catInfo.hFileInfo.ioFDirIndex = 0;

    // Get information about the file/directory
    err = PBGetCatInfoSync(&catInfo);
    if (err == noErr) {
        *exists = 1;
        if (catInfo.hFileInfo.ioFlAttrib & ioDirMask) {
            *isDir = 1;
            printf("Path is a directory.\n");
        } else {
            *isFile = 1;
            printf("Path is a regular file.\n");
        }
    } else {
        printf("Error in PBGetCatInfoSync: %d\n", err);
        *error = 1;
    }

    return err;
}

Now, I created a folder in the same dir as the executable called "abc". And I keep getting an error in FSMakeFSSpec of value -43, which means the thing doesn't exist. When running on the debugger, I get a directory id (374 last time I saw) and a negative vRefNum to represent the hard drive with the value -32509.

Does that mean that the HD is unrecognised? What am I doing wrong here? Inside Macintosh only seems to suggest that vRefNum should be zero for the main HD, it doesn't say what happens if the HD isn't found.

Also, the directory does exist, and I'm assuming that my code to take the full path is to blame. But how can it be fixed?

Perhaps I'm using the wrong function?

Does anyone have experience with this? Is there a simpler way of doing this? Am I going insane?

Thanks in advance for any advice.
 
Last edited:

David Cook

Well-known member
Using Metrowerks Codewarrior 11, your code works for me.

>> a negative vRefNum to represent the hard drive with the value -32509.

Looks like you have a working directory reference, rather than a volume reference. I wonder if the combination of a working directory and directory (but no volume reference) is messing up FSMakeFSSpec.

"#77: HFS Ruminations Written by: Jim Friedlander June 7, 1986 This Technical Note contains some thoughts concerning HFS. HFS numbers A drive number is a small positive word (e.g. 3). A vRefNum (as opposed to a WDRefNum) is a small negative word (e.g. SFFFE). A wDRe fNun is a large negative word (e.g. $8033). Working Directories A DirID is a long word (e.g. 38). The root directory of an HFS volume always has a dirID of 2."

Earlier in your code, are you calling or setting up some other libraries that might cause GetVol to return a working directory?

- David
 
Last edited:

sentient06

Member
Hi David, thanks for the help. If it works for you it means I don't need to completely burn the code and start all over again, and that's a relief.

Did you simply copy/paste my code or did you add something else?

My code (and the generated binary) is on a secondary disc, hopefully that doesn't change anything, but I thought it be worth mentioning.

Where my function lives I have these libraries:

Code:
#include <Files.h>
#include <stdio.h> // For logging
#include <string.h> // Ditto

On my main file.. I have a lot of junk I left from CodeWarrior's template. That's where I try to find the absolute path.

Code:
#include <Dialogs.h>
#include <Fonts.h>
#include <MacWindows.h>
#include <Menus.h>
#include <QuickDraw.h>
#include <TextEdit.h>

#include <stdio.h>
#include <Files.h>
#include "pFileManagement.h"

I've been trying to figure out what the code is doing, so I ran it again to double check the numbers:

Code:
    printf("vRefNum = %d\n", vRefNum); // -32525 - I think this is junk
    printf("dirID   = %ld\n", dirID); // 374 - This is consistent

vRefNum constantly changes, so I think it's whatever is in memory.

I'm reading the documentation, it says that HGetVol accepts vRefNum, which is a "volume reference number or a working directory reference number", I suppose that's because a file might be in the root dir.

The HGetVol function returns a working directory reference number in the vRefNum parameter if the previous call to HSetVol (or PBHSetVol) passed in a working directory reference number. If, however, you have previously called HSetVol (or PBHSetVol) specifying the target volume with a volume reference number, then HGetVol returns a volume reference number in the vRefNum parameter.

It looks like I can either get a directory or a volume, but not both. I will try passing a zero to FSMakeFSSpec and poke around.
 

cheesestraws

Well-known member
which is a "volume reference number or a working directory reference number", I suppose that's because a file might be in the root dir.

It's also because working directories (and directories as a whole) were bodged onto an API that was designed for a non-heirarchical filing system where all files were just on a volume. It was a clever bodge but it stuck around for a very, very long time...
 

joevt

Well-known member
How do you know abc is in the same directory as that returned by HGetVol?

Go to https://developer.apple.com/library/archive/navigation/#section=Platforms&topic=macOS
Search for files.
Download the MoreFiles sample code.
Use FSpGetFullPath to get the full path of whatever, for debugging.

Anyway, MoreFiles has many other useful functions you should look at.

I think FSMakeFSSpec is only for files that exist.

You can use GetWDInfo to check if a vref is a working directory reference or not and to convert it to a volume reference and directory ID. It is a volume reference if the returned dirID is fsRtDirID.
 

sentient06

Member
It's also because working directories (and directories as a whole) were bodged onto an API that was designed for a non-heirarchical filing system where all files were just on a volume. It was a clever bodge but it stuck around for a very, very long time...

I have no reason to doubt that, it sounds kind of familiar, to be fair. And almost horrifying. :LOL:

How do you know abc is in the same directory as that returned by HGetVol?

I don't. My assumption was that the "default" directory and the "default" volume (as called in the docs) were the ones where the app resides. I couldn't find in Inside Macintosh an explanation for what the default is. (I'm not saying it isn't there, but it's a lot of text to peer through and I didn't find it yet.)

It's a guess, but not totally random. I've noticed that I can, for example, get the pascal string name of the volume where the app resides, so I concluded that the volume would normally default to the one where the app is. Consider this code:

Code:
    Str255 volName;

    err = GetVol(&volName[0], &vRefNum);
    if (err != noErr) {
      printf("Error 1: %d\n", err);
      return err;
    } else {
      printf("> vRefNum = %d\n", vRefNum);
      printf("> volName = %s\n", volName);
    }

It actually gets the string. The vRefNum is still no good to use with FSMakeFSSpec however.

I downloaded the sample code and will take a look. Hopefully there's an easier way. Thanks joevt!
 

cheesestraws

Well-known member
My assumption was that the "default" directory and the "default" volume (as called in the docs) were the ones where the app resides.

I'm pretty sure this isn't a safe assumption. Going from memory, here, so I might be wrong, but I'm fairly sure that in 7.mumble or above, the default directory may well be the user's documents directory.
 

David Cook

Well-known member
Did you simply copy/paste my code or did you add something else?

Pretty much your exact code. I had to flesh out the snipped where it calls CheckPathStatus.

But, I am pretty sure the issue is that you are passing both a working directory (instead of an actual volume reference) and a directory to FSMakeFSSpec. Let's see if that is the case.

You can resolve the actual directory and volume reference from the working directory using PBGetWDInfo.

1728317341235.png

Snippet:

WDPBRec paramBlock; Str31 volumeNamePString; DavidsMemoryClear(&paramBlock, sizeof(WDPBRec)); // My habit is to clear a paramBlock. // Either do the same or set the fields manually to 0. paramBlock.ioVRefNum = vRefNum; // your volume reference that may actually be a working directory paramBlock.ioNamePtr = volumeNamePString; if (PBGetWDInfo(&paramBlock, false) == noErr) { // Actual volume reference. vRefNum = paramBlock.ioWDVRefNum; // Actual directory ID if paramBlock.ioVRefNum was a working directory // directoryId = paramBlock.ioWDDirID; // volumeNamePString is the name of the volume (drive)

Add this to the code before you call CheckPathStatus. I bet you're going to get a small negative number for vRefNum. It will be interesting to see the value you get for paramBlock.ioWDDirID.
 

David Cook

Well-known member
A little background on 'working directories'.

When the Macintosh first shipped, each disk held a flat list of files. That is, there was no such thing as a path. Folders were just eye-candy. It didn't matter if you put the file 'test.txt' in the root of the disk or a folder. To locate a file, a program only needed to ask for 'test.txt' on volume 'My Disk'. The folder location didn't matter.

The downside to this approach is you could NOT have two files with the same name on the same disk, even if the files were in different folders.

They introduced actual paths and true folder support in HFS. But, now you needed three things to locate a file: the file name, the volume (disk) number, and the directory (folder) number. Existing programs weren't coded this way.

So, when a user launched a program by double-clicking on a file (or through the OS standard file dialog in a program's File->Open menu), the OS created a 'working' reference that combines the actual volume (disk) reference and directory (folder) reference. Now, when the program says "I'd like to read the file named 'test.txt' that the user just selected on vRefNum -32509", the operating system would say "Ah ha! That vRefNum is too negative to be an actual volume, it must be my hack. I will now look up the real volume and directory id, locate the file, and return the file reference to the program."

This was a pretty nifty trick to keep old programs compatible. It also meant that Inside Macintosh I-III didn't need to be rewritten. The code kept working.

Unfortunately, you now need to know about the hack to make a more 'modern' program work.

- David
 

chelseayr

Well-known member
yeah david that was basically mfs which not surprisingly aptly was short for 'macintosh file system' no?
(and I'm guessing it not surprisingly didn't actually last for that long solo as hfs came out a relatively short time later. of course 'hierarchical' not surprisingly really stood for what it meant when compared to mfs itself at the time hm?)
 

joevt

Well-known member
You can use kCurrentProcess with GetProcessInformation to get the name and/or FSSpec of the current application.
 

sentient06

Member
Pretty much your exact code. I had to flesh out the snipped where it calls CheckPathStatus.

But, I am pretty sure the issue is that you are passing both a working directory (instead of an actual volume reference) and a directory to FSMakeFSSpec. Let's see if that is the case.

...

Snippet:

...

Add this to the code before you call CheckPathStatus. I bet you're going to get a small negative number for vRefNum. It will be interesting to see the value you get for paramBlock.ioWDDirID.

My outputs:

Code:
// Printing variables:
-- vRefNum           = -2
-- directoryId       = 2
-- volumeNamePString = Classic Dev // This is the secondary HD's name
// Printing code:
Error in FSMakeFSSpec: -43
// Printing a string for each error:
File or dir doesn't exist (abc)
// Back to parent call, we just print the error again:
An error occurred while checking the path 'abc'. Error code: -43

It does look less random.

The file still can't be found. If I remove the "abc" name from the request, it correctly returns a directory (I assume the parent dir). If I hard-code "\pabc" as the name of the file, it fails. So I thought I am probably in the wrong dir. So I created a directory on my root, and it worked. So! It's finding the root.

A little background on 'working directories'.

When the Macintosh first shipped, each disk held a flat list of files. That is, there was no such thing as a path. Folders were just eye-candy. It didn't matter if you put the file 'test.txt' in the root of the disk or a folder. To locate a file, a program only needed to ask for 'test.txt' on volume 'My Disk'. The folder location didn't matter.

Yes, I was acquainted with that story, but I didn't realise it reflected on file paths down the line until I actually tried this code.

They introduced actual paths and true folder support in HFS. But, now you needed three things to locate a file: the file name, the volume (disk) number, and the directory (folder) number. Existing programs weren't coded this way.

I read the same thing yesterday in the documentation for one of the functions in the Toolbox. I've also noticed that sometimes the directory id and the volume id seem to be interchangeable in a few functions like GetVol: "
vRefNum: A volume reference number *or* a working directory reference number". :cry:


So, when a user launched a program by double-clicking on a file (or through the OS standard file dialog in a program's File->Open menu), the OS created a 'working' reference that combines the actual volume (disk) reference and directory (folder) reference. Now, when the program says "I'd like to read the file named 'test.txt' that the user just selected on vRefNum -32509", the operating system would say "Ah ha! That vRefNum is too negative to be an actual volume, it must be my hack. I will now look up the real volume and directory id, locate the file, and return the file reference to the program."

Oh boy. So is the volume and directory conflated in a single number? Do I need to untangle them to use FSMakeFSSpec or similar? I've been trying to use vRefNum alone and set either the param destined to it to null or the volume id param, but both yield errors. I did that based on a text from the docs that says that if it is suffiently specified, one parameter is ignored in favour of the other.

Your example makes me think that this negative number looks "random" because of a potential conflation of two numbers. Do you think the reason why the output from this code looks less random is because it's simply finding the root directory in the volume?

I have this vague impression that this is the missing piece of the puzzle for me.

You can use kCurrentProcess with GetProcessInformation to get the name and/or FSSpec of the current application.
I've tried that, it's one of my blocks of commented out codes in my source file. But I don't remember what happened. I will revisit that solution and cross-reference the results with the newer attempts.

Thanks guys, I really appreciate the feedback. There's a lot to unpack here, but I think I have a better grasp on what's going on. It's cool to see that there's still people around interested in this kind of stuff and who can help.

I have a lot of commented code atm, and it's kind of tricky to chat here, check the docs and then type the stuff on Mac OS, as I can't just copy/paste everything, even if I use an emulator, as it doesn't support clipboard. So it takes me a while to type the stuff and test.

I've gone through that MoreFiles source code as well, and there seem to be some gems in it, so I will keep it handy for reference. Thanks for the sugestion!
 

sentient06

Member
Ah OK, so.. if I use GetVol, I get back a working directory reference number. And to break that up I can use PBGetWDInfo to get a ioVRefNum and ioDirID pair.

I will try that. Sorry guys, it's been a slow learning curve.

I commented out my code before pasting yours, David, now I noticed that the vRefNum should go into the WDPBRec. I'll run again with the updates.

UPDATE

Code:
// Using GetVol
-- vRefNum           = -32541
-- volumeNamePString = Classic Dev
Error: -35 // No such volume

Code:
// Using HGetVol
-- vRefNum           = -32541
-- dirID             = 374
-- volumeNamePString = Classic Dev
Error: -35 // No such volume

Code:
// Using GetProcessInformation with kCurrentProcess
-- vRefNum           = -2
-- dirID             = 2
-- volumeNamePString = Classic Dev
Error: -43 // Error from FSMakeFSSpec - File or directory does not exist
// This one actually finds the file in the root dir.

Code:
// Using GetWDInfo
-- vRefNum           = -2
-- dirID             = 2
-- volumeNamePString = Classic Dev
Error: -43 // Same as above

So, my preferred approach is to use GetVol, based on this: https://developer.apple.com/library/archive/technotes/fl/fl_510.html#Section6

It says there to use the "working directory reference number" and break it up. But I'm confused to how that works, as the Working Directory Parameter Block in the docs seem to have only 2 long properties, ioWDProcID and ioWDDirID. There are also 2 words and based on the description I don't really know which one I should use for PBGetWDInfo as the descriptions are a bit.. unclear. I'm not sure about the difference between a directory's id, index and user identifier, and trying all of them yield unknown volume, so I assume I need... a volume id? In that case I can't use GetVol, so I'm back to square one on this approach.
 
Last edited:

sentient06

Member
I rewrote the whole code into a new project and managed to get some stuff to work consistently with the same numbers. I'm now convinced that the issue lies with my attempt to resolve the file name on FSMakeFSSpec. I will see if I can find another function, as this one keeps on failing. I will try a combo of GetWDInfo and PBGetCatInfoSync.
 
Last edited:

sentient06

Member
I got a very odd result with this code, I'd like to ask your opinion:

C++:
#include <Files.h>
#include <stdio.h>
#include <string.h>

void CtoPStr(const char* cString, Str255 pStr) {
  size_t len = strlen(cString);
  pStr[0] = len;
  memcpy(&pStr[1], cString, len);
}

int main(void) {
  const char* path = "abc";
  OSErr err;
  short vRefNum = 0;
  short working_dir_ref_no;
  WDPBRec paramBlock;
  long dirID = 0L;
  Str255 volName;
  Str63 folderName = "";
  CInfoPBRec catInfo;

/**/

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/**/
  printf("GetVol\n");
  err = GetVol(&volName[0], &working_dir_ref_no);
  if (err != noErr) {
    printf("Error %d\n", err);
    return err;
  }
  printf("- working dir no = %d\n", working_dir_ref_no);
/**/
 
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/**/
  printf("GetWDInfo\n");

  err = GetWDInfo(
    working_dir_ref_no,
    &paramBlock.ioWDVRefNum,
    &paramBlock.ioWDDirID,
    &paramBlock.ioWDProcID
  );

  if (err != noErr) {
    printf("Error %d\n", err);
    return err;
  } else {
    printf("- ioWDVRefNum = %d\n", paramBlock.ioWDVRefNum);
    printf("- ioWDProcID  = %d\n", paramBlock.ioWDProcID);
    printf("- ioWDDirID   = %ld\n", paramBlock.ioWDDirID);
  }
 
  paramBlock.ioWDIndex = 0;
  paramBlock.ioNamePtr = NULL;
 
  vRefNum = paramBlock.ioWDVRefNum;
  dirID   = paramBlock.ioWDDirID;
/**/
 
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/**/

  printf("PBGetCatInfoSync\n");
 
  CtoPStr(path, folderName);

  catInfo.hFileInfo.ioNamePtr = "\pabc"; // folderName;
  catInfo.hFileInfo.ioVRefNum = vRefNum;
  catInfo.hFileInfo.ioDirID = dirID;

  err = PBGetCatInfoSync(&catInfo);
  if (err == noErr) {
    if (catInfo.hFileInfo.ioFlAttrib & ioDirMask) {
      printf("Path is a directory.\n");
    } else {
      printf("Path is a regular file.\n");
    }
    printf("- works\n");
  } else {
    printf("- Error %d\n", err);
    
    switch(err) {
      case 0:
        printf("No error");
        break;
      case -35:
        printf("No such volume");
        break;
      case -36:
        printf("I/O error");
        break;
      case -37:
        printf("Bad filename");
        break;
      case -43:
        printf("File not found");
        break;
      case -50:
        printf("No default volume");
        break;
      case -120:
        printf("Directory not found or incomplete pathname");
        break;
      case -5000:
        printf("User does not have the correct access");
        break;
      case -5025:
        printf("Directory not found or incomplete pathname");
        break;
      default:
        printf("No idea!");
        break;
    }
    printf("\n");
  }
 
  printf(">> %s <<\n", catInfo.hFileInfo.ioNamePtr);
  return 0;
}

1728407504963.png

It looks like the PBGetCatInfoSync is running two threads and printing my string check at the end while also printing the result of my directory check at the first nested if block after I assess the result.

Maybe I'm too tired and missed something obvious again. But I did notice there's an async option for PBGetCatInfo, and I didn't find a detailed explanation of PBGetCatInfoSync proper in Inside Macintosh, so I wonder what's up here. Whenever I play with the async param I end up with a crash.
 

joevt

Well-known member
%s is for a cstring.
You need to use %p for pascal strings or something like that.
If your C stdlib doesn't support printing pascal strings, then you could do
"%.*s", catInfo.hFileInfo.ioNamePtr[0], &catInfo.hFileInfo.ioNamePtr[1]

You didn't zero catInfo before using it.
https://developer.apple.com/library/archive/technotes/fl/fl_10.html#//apple_ref/doc/uid/DTS10002436

As suggested previously, use MoreFile and use FSpGetFullPath to get the path of whatever is returned by GetWDInfo.

Do you get a different result if abc is a file instead of a folder?

async methods require a callback function to be passed in the ioCompletion field of the param block. They return immediately and the callback gets called later when the function completes. You don't want to use async stuff unless you want to do some other work while the async function is happening. For example, when copying a file, you could read async the next part of a file while writing async the current part of a file.
 

sentient06

Member
%s is for a cstring.
You need to use %p for pascal strings or something like that.
Youre absolutely right. I half-arsed the printf because it "kinda works", but after making a converter for C strings, it ran normally.

async methods require a callback function to be passed in the ioCompletion field of the param block. They return immediately and the callback gets called later when the function completes. You don't want to use async stuff unless you want to do some other work while the async function is happening. For example, when copying a file, you could read async the next part of a file while writing async the current part of a file.
Got it! Thanks for the explanation! I am taking notes.

So.. I figured out what was happening!

My project has some setting that creates a bundle, very much Mac OS X. So the app "binary" is a directory in disguise and the real binary is nested inside. I'm not sure how to avoid that yet, it must be some project setting I am not familiar with, but I assume it's for Mac OS X classic compatibility?

Anyway, the binary finds the parent directory of the executable itself, meaning it's nested inside the bundle, and not the bundle's directory, so it never finds the file! Super annoying and very simple.

I've improved the version of the code since my last post, and I will make it into a nice little function to look at files. Of course, I don't think there will be many relative path cases, but it's a little thing to keep in mind. I will post the final code here for anyone who would like to make use of it.

Thanks everyone! You da best. I'm guessing this was a bit of drag for you, but I think I've learned a few things, I really appreciate it. Experience is the best teacher. That was my first real taste of Toolbox. I can now carry on with my project and will probably start moving slowly to a GUI. At least I'm now more familiarised with 'Inside Macintosh' and all that.
 

cheesestraws

Well-known member
My project has some setting that creates a bundle, very much Mac OS X. So the app "binary" is a directory in disguise and the real binary is nested inside. I'm not sure how to avoid that yet, it must be some project setting I am not familiar with, but I assume it's for Mac OS X classic compatibility?

Argh, I didn't even consider this. The MacOS / OS X transition was such a mess...
 

joevt

Well-known member
I think in a relative path, you can have :: to represent the parent directory. : represents the current directory. It's like .. and . in Unix. So you could maybe do ::abc to get the abc file in the parent directory or :::abc to get the abc file in the parent of the parent directory.

ioFDirIndex = 0 get info for the named item in the vref/dir. I suppose the parent directory id would be the same as the directory id.
ioFDirIndex = -1 ignores the name and gets info for the vref/dir (including parent directory id).

Is there a flag that says whether your process (app) is a bundle/package instead of a standalone resource file? Perhaps in the Process Manager? Core Foundation framework? Carbon API?

Regarding working directory IDs, they are not a concatenation of vRef and DirID - that would require 48 bits! macOS maintains a list of working directory IDs somewhere. I think you can see the list in MacsBug? There's a limited number of working directory IDs (< 15 bits?) so there's a OpenWD and CloseWD function just like there are similar functions for opening and closing files (frefs are 16 bits) (you can definitely see the file list in MacsBug).
 
Top