[comp.sys.mac.programmer] Problems with PBGetCat and other related things

jtn@ADS.COM (John T. Nelson) (03/04/91)

Grak!  I'm having problems with PBGetCat and PBGetFInfo.  I suspect
the problem is because I am not positioned in the correct directory
but it's difficult to tell where the problem is.  I have a subroutine
called directoryP() which tries to test for a directory in the current
working directory which I previously set using SetVol() in my function
GoToDirectory().

Here's the problem.  A call to PBGetFInfo ALWAYS returns -43 which is
fnfErr in Mac error results lore.  The folder/file I test for is
located by SFPGetFile although it is in the same directory that the
program is run from.  I also have an identical folder located at the
root-most directory (because I suspected my working directory wasn't
really where I thought it was) and yet it still fails.

I set my directories by getting the (long) directory ID of the
directory in which to search and then using PBopenWD to get a refNum I
can then use with SetVol.  Now the funny thing here is that I'm
emulating the code that is used in the Unshar utility recently
distributed on the net. This utility passes a (long) into SetVol which
I think is wrong.  SetVol takes an int... not a long.

The long dirID passed into GoToDirectory() is derived from the global
CurDirSave after doing an SFPGetFile.  Here's the code fragment that
does that:

	if (reply.good) {
		dirVRefNum = reply.vRefNum;
		if (useCurDir) {
			dirDirID = CurDirStore;
		}
		else {
			dirDirID = (long)(reply.fType);
		}
	}
	return(dirDirID);

GoToDirectory(long dirID)
{
long	dID;
/* short dID; */
/* int dID */
	
	wdpb.ioCompletion = NIL;
	wdpb.ioNamePtr = NIL;
	wdpb.ioVRefNum = dirVRefNum;
	wdpb.ioWDDirID = dirID;
	if (PBOpenWD(&wdpb, FALSE) != noErr) {
		return;
	}
	
	dID = dirVRefNum = wdpb.ioVRefNum;
	(void)SetVol(NIL, dID);
}

Boolean directoryP(Str255 file) {
Str255			vName;
int			vRefNum;
CInfoPBRec		cBlock;
OSErr			err;

cBlock.dirInfo.ioCompletion = NIL;
cBlock.dirInfo.ioNamePtr = file;

GetVol(&vName, &vRefNum);

/*cBlock.dirInfo.ioVRefNum = - ( *(short *) SFSaveDisk );*/
cBlock.dirInfo.ioVRefNum = vRefNum;
cBlock.dirInfo.ioFDirIndex = 0;

err = PBGetFInfo(&cBlock, SYNCHRONOUS);
if ( err == fnfErr )
	return FALSE;

if ( cBlock.dirInfo.ioFlAttrib & 0x010 )
	return TRUE;
else
	return FALSE;
}


Any ideas on what I'm doing wrong?



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ORGANIZATION:  Advanced Decision Systems   GEOGRAPHIC: Arlington, VA
UUCP:          kzin!speaker@mimsy.umd.edu  INTERNET:   jtn@potomac.ads.com
SPOKEN:        Dark Hacker                 PHONE:      (703) 243-1611
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

tim@hoptoad.uucp (Tim Maroney) (03/09/91)

In article <$$B&70=@ads.com> jtn@ADS.COM (John T. Nelson) writes:
>
>Grak!  I'm having problems with PBGetCat and PBGetFInfo.
>
>	if (reply.good) {
>		dirVRefNum = reply.vRefNum;
>		if (useCurDir) 
>			dirDirID = CurDirStore;
>		else 	dirDirID = (long)(reply.fType);
>	}
>	return(dirDirID);

First off, I don't know how you could *ever* trust reply.fType to have
a dir ID *after* Standard File returns.  Sure it has one during your
filter procedure, but afterwards?  Completely undocumented.  Even if
you put one there yoruself, Standard File may put something else in.
But let's assume that useCurDir is always true.

>GoToDirectory(long dirID)
>{
>long	dID;
>	
>	wdpb.ioCompletion = NIL;
>	wdpb.ioNamePtr = NIL;
>	wdpb.ioVRefNum = dirVRefNum;
>	wdpb.ioWDDirID = dirID;
>	if (PBOpenWD(&wdpb, FALSE) != noErr) {
>		return;
>	}
>	
>	dID = dirVRefNum = wdpb.ioVRefNum;
>	(void)SetVol(NIL, dID);
>}

Here, in all probability, is your problem.  You are using SF's vRefNum
as a volume reference number, when in fact it's a working directory
reference number.  Then you try to make a new working directory out of
the old WD refnum and a dir ID.  Guaranteed to give some kind of silly
result.  If you want to SetVol to the place SF picked, then just use
the reply.vRefNum, and cut out all this CurDirStore and PBOpenWD
stuff!

>Boolean directoryP(Str255 file) {
>Str255			vName;
>int			vRefNum;
>CInfoPBRec		cBlock;
>OSErr			err;
>
>cBlock.dirInfo.ioCompletion = NIL;
>cBlock.dirInfo.ioNamePtr = file;
>
>GetVol(&vName, &vRefNum);
>
>/*cBlock.dirInfo.ioVRefNum = - ( *(short *) SFSaveDisk );*/
>cBlock.dirInfo.ioVRefNum = vRefNum;
>cBlock.dirInfo.ioFDirIndex = 0;
>
>err = PBGetFInfo(&cBlock, SYNCHRONOUS);
>if ( err == fnfErr )
>	return FALSE;
>
>if ( cBlock.dirInfo.ioFlAttrib & 0x010 )
>	return TRUE;
>else
>	return FALSE;
>}

PBGetFInfo doesn't work on folders.  You have to use PBGetCatInfo.

Here's what I would do -- take the vRefNum from Standard File.  Don't
even bother doing a SetVol.  Use PBGetWDInfo to turn the reply.vRefNum
into a volume reference number and a working directory reference number.
Then put these into a PBGetCatInfo parameter block and do your thing.

Here's a little Pascal routine that illustrates the PBGetWDInfo step.
Read the PBGetCatinfo documentation carefully; and volume IV explains
the relationship of these three kinds of numbers reasonably well, so
I recommend brushing up on it first, cause otherwise, it's really easy
to get lost.

procedure WDtoPair(wdRefNum: integer; var volume: integer; var folder: longint);
	{ find the volume/refnum pair for a working directory }
	var
		wd: WDPBRec;
begin
	wd.ioVRefNum := wdRefNum;
	wd.ioNamePtr := nil;
	wd.ioWDIndex := 0;
	FailOSErr(PBGetWDInfo(@wd, false));
	volume := wd.ioWDVRefNum;
	folder := wd.ioWDDirID;
end;

-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

This message does represent the views of Eclectic Software.