[comp.sys.mac.programmer] SFReply.vRefNum -> PathName

torch@attctc.Dallas.TX.US (Jay Finger) (02/09/90)

I'm need a routine that will convert the volume reference number from SFGetFile
into a pathnam.  I assumed that I'd need to convert the working directory
id into a directory id and then use something like GetCatInfo to get
directory names while tracing back to the root.

PBGetWDInfo and PBGetCatInfo don't seem to be returning the data that I'm
expecting.  I don't know if I'm calling them incorrectly or if I'm just
expecting the wrong things.  I don't really have any code to show: I've
simply been trying out all kinds of ways to set up the parameter blocks.

Any advice on how to go about doing this (am I even close?) would be
appreciated, sample code even more so.

Thanks in advance,

Jay Finger,
{ames,mit-eddie}!attctc!torch
ames!torch@attctc

mxmora@unix.SRI.COM (Matt Mora) (02/10/90)

In article <11377@attctc.Dallas.TX.US> torch@attctc.Dallas.TX.US (Jay Finger) writes:
>I'm need a routine that will convert the volume reference number from SFGetFile
>into a pathnam.  I assumed that I'd need to convert the working directory
>id into a directory id and then use something like GetCatInfo to get
>directory names while tracing back to the root.

>Jay Finger,
>{ames,mit-eddie}!attctc!torch
>ames!torch@attctc

Here is some routines from Apple's Source Code Examples. This is from
their Stanadrd file package. It is available via FTP from apple.com



(** PathNameFromDirID ****************************************************)
(*
(*  Given a DirID and real vRefnum, this routine will create and return the
(*  full pathname that corresponds to it. It does this by calling PBGetCatInfo
(*  for the given directory, and finding out its name and the DirID of its
(*  parent. It the performs the same operation on the parent, sticking ITS
(*  name onto the beginning of the first directory. This whole process is
(*  carried out until we have processed the root directory (identified with
(*  a DirID of 2.
(*
(*  NOTE: This routine is now A/UX friendly. A/UX likes sub-directories
(*        separated by slashes in a pathname. This routine automatically
(*        uses colons or slashes as separators based on the value of the
(*        global gHasAUX.  This global must be initialized correctly for
(*        this routine to do its thing. However, because of this dependancy
(*        on the idiosyncracies of file systems, generating full pathnames
(*        for other than display purposes is discouraged; it's changed in
(*        the past when A/UX was implemented, and it may change again in
(*        the future it support for other file systems such as ProDOS,
(*        MS-DOS, or OS/2 are added.
(*
(**************************************************************************)

  FUNCTION PathNameFromDirID (DirID:longint; vRefnum:integer):str255;

    VAR
      Block : CInfoPBRec;
      directoryName, FullPathName : str255;

    BEGIN
      FullPathName := '';
      WITH block DO BEGIN
        ioNamePtr := @directoryName;
        ioDrParID := DirId;
      END;

      REPEAT
        WITH block DO BEGIN
          ioVRefNum := vRefNum;
          ioFDirIndex := -1;
          ioDrDirID := block.ioDrParID;
        END;
        err := PBGetCatInfo(@Block,FALSE);

        IF haveAUX THEN BEGIN
          IF directoryName[1] <> '/' THEN BEGIN
            { If this isn't root (i.e. "/"), append a slash ('/') }
            directoryName := concat(directoryName, '/');
          END;
        END ELSE BEGIN
          directoryName := concat(directoryName,':');
        END;
        fullPathName := concat(directoryName,fullPathName);

      UNTIL (block.ioDrDirID = 2);

      PathNameFromDirID := fullPathName;
    END;


(** PathNameFromWD **********************************************)
(*
(*  Given an HFS working directory, this routine returns the full pathname
(*  that corresponds to it. It does this by calling PBGetWDInfo to get the
(*  VRefNum and DirID of the real directory. It then calls PathNameFromDirID,
(*  and returns its result.
(*
(**************************************************************************)

  FUNCTION PathNameFromWD(vRefNum:longint):str255;

    VAR
      myBlock : WDPBRec;

    BEGIN

      {
      { PBGetWDInfo has a bug under A/UX 1.1.  If vRefNum is a real vRefNum
      { and not a wdRefNum, then it returns garbage.  Since A/UX has only 1
      { volume (in the Macintosh sense) and only 1 root directory, this can
      { occur only when a file has been selected in the root directory (/).
      { So we look for this and hardcode the DirID and vRefNum. }

      IF (haveAUX) AND (vRefNum = -1) THEN BEGIN

        PathNameFromWD := PathNameFromDirID(2,-1);

      END ELSE BEGIN

        WITH myBlock DO BEGIN
          ioNamePtr := NIL;
          ioVRefNum := vRefNum;
          ioWDIndex := 0;
          ioWDProcID := 0;
        END;

      { Change the Working Directory number in vRefnum into a real vRefnum }
      { and DirID. The real vRefnum is returned in ioVRefnum, and the real }
      { DirID is returned in ioWDDirID. }

        err := PBGetWDInfo(@myBlock,FALSE);

        WITH myBlock DO
          PathNameFromWD := PathNameFromDirID(ioWDDirID,ioWDVRefnum)
      END;
    END;


-- 
___________________________________________________________
Matthew Mora
SRI International                       mxmora@unix.sri.com
___________________________________________________________

tim@hoptoad.uucp (Tim Maroney) (02/11/90)

The Pascal source posted ignores errors and string lengths, and so it
can easily crash your machine if the path name runs to more than 255
characters or if an error leaves directoryName with a large length
byte.  Here's some C code to do the same thing (MPW C 3.0, but since it
was originally written in LSC 3.0 it shouldn't be hard to convert back).
FullFileName should be passed an empty string in tail if you just want
the name of a folder.


SFVolDir(short wd, short *volume, long *folder)
{	WDPBRec pb; unsigned char name[72];
	pb.ioNamePtr = (StringPtr)name;
	pb.ioVRefNum = wd;
	pb.ioWDIndex = 0;
	pb.ioWDProcID = 0;
	pb.ioWDVRefNum = 0;
	PBGetWDInfo(&pb, false);
	if (pb.ioResult) return pb.ioResult;
	*volume = pb.ioWDVRefNum;
	*folder = pb.ioWDDirID;
	return noErr;
}

FullFileName(StringPtr outname, StringPtr tail, short volume, long dirID)
{	StringHandle name; Str255 text, volname; HVolumeParam hvp;
	CInfoPBRec di; long size; short err;

	/* extract the volume name */
	hvp.ioNamePtr = volname;
	hvp.ioVRefNum = volume;
	hvp.ioVolIndex = 0;
	PBHGetVInfo((HParmBlkPtr)&hvp, false);
	if (hvp.ioVSigWord == 0xd2d7) { outname[0] = 0; return noHFSerr; }

	/* create and initialize the name handle */
	if (tail) {
		if (err = PtrToHand(tail + 1, &name, tail[0])) return err;
		size = tail[0];
	}
	else {	if ((name = NewHandle(0)) == 0) return MemError();
		size = 0;
	}

	/* now start extracting the dirs and prepending them to
	 * the handle
	 */
	for ( ; dirID != 2; dirID = di.dirInfo.ioDrParID) {
		text[0] = 0;
		di.dirInfo.ioNamePtr = text;
		di.dirInfo.ioVRefNum = volume;
		di.dirInfo.ioFDirIndex = -1;
		di.dirInfo.ioDrDirID = dirID;
		PBGetCatInfo(&di, false);
		text[++text[0]] = ':';
		SetHandleSize(name, size += text[0]);
		BlockMove((Ptr)*name, (Ptr)(*name) + text[0], size - text[0]);
		BlockMove((Ptr)text + 1, (Ptr)*name, text[0]);
	}

	/* prepend the volume name onto the handle */
	volname[++volname[0]] = ':';
	SetHandleSize(name, size += volname[0]);
	BlockMove((Ptr)*name, (Ptr)(*name) + volname[0], size - volname[0]);
	BlockMove((Ptr)volname + 1, (Ptr)*name, volname[0]);

	/* copy and delete the handle */
	if (size > 255) {
		DisposHandle(name);
		SysBeep(12);
		outname[0] = 0;
		return tooBigErr;
	}
	outname[0] = size;
	BlockMove((Ptr)*name, (Ptr)outname + 1, size);
	DisposHandle(name);
	return noErr;
}


And on the theory that you might want to convert the name back some day,
here's a routine I use for that.  Notice that it will actually create the
directory if it doesn't exist now.  If this isn't what you want, throw
away the error recovery code.


FullToFolder(StringPtr name, short *volume, long *folder)
{	CInfoPBRec dirInfo; HVolumeParam hvp; short i;
	dirInfo.dirInfo.ioNamePtr = name;
	dirInfo.dirInfo.ioDrDirID = 0;
	dirInfo.dirInfo.ioVRefNum = 0;
	dirInfo.dirInfo.ioFDirIndex = 0;
	if (PBGetCatInfo (&dirInfo, 0) == noErr) {
		if (dirInfo.dirInfo.ioFlAttrib & 0x10) {
			*folder = dirInfo.dirInfo.ioDrDirID;
			hvp.ioNamePtr = name;
			for (i = 0; i < name[0]; i++)
				if (name[i+1] == ':')
					{ name[0] = i + 1; break; }
			hvp.ioVolIndex = -1;
			hvp.ioVRefNum = 0;
			PBHGetVInfo ((HParmBlkPtr)&hvp, 0);
			*volume = hvp.ioVRefNum;
		}
		else {	*volume = 0, *folder = 0; return -1; }
	}
	else if (dirInfo.dirInfo.ioResult == fnfErr
		 || dirInfo.dirInfo.ioResult == dirNFErr)
	{	dirInfo.dirInfo.ioNamePtr = (StringPtr)name;
		dirInfo.dirInfo.ioDrDirID = 0;
		dirInfo.dirInfo.ioVRefNum = 0;
		if (PBDirCreate((HParmBlkPtr)&dirInfo, false) == noErr) {
			*volume = dirInfo.dirInfo.ioVRefNum;
			*folder = dirInfo.dirInfo.ioDrDirID;
		}
		else {	*volume = 0, *folder = 0;
			return dirInfo.dirInfo.ioResult;
		}
	}
	else	{ *volume = 0, *folder = 0; return dirInfo.dirInfo.ioResult; }
	return noErr;
}
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

"The time is gone, the song is over.
 Thought I'd something more to say." - Roger Waters, Time