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