[comp.sys.mac.programmer] Getting the full pathname?

fryd@g.gp.cs.cmu.edu (Michael Fryd) (10/10/89)

I am in the process of getting Scribe to run under MPW on the Mac.  One
of the problems I am trying to solve is how to get the full pathname from
a user specified partial pathname that starts with multiple ':'s?

The syntax "::folderb:filename" is like the Unix "../folderb/filename",
it means go up one level from the current directory, and then get
filename from folderb.

The standard solutions that have been posted all work in the normal case
of the user specifying a simple filename of the form "filename" 
or ":subfolder1:subfolder2:filename", but they give strange
results when the user tries "::folderb:filename".


The file manager understands this syntax.  If the default directory is
"HD:foldera" then a filename of "::folderb:filename" correctly gets
the file "HD:folderb:filename", however all of the standard routines
for getting the full pathname return "HD:foldera::folderb:filename".

Although "HD:foldera::folderb:filename" is a correct path to the file,
I would like to supply the more compact "HD:Folderb:filename".

Is there any way to get the real filename and directory name for an open
file?  I would like to avoid trying to parse the filename myself,  If
I can get the Mac to tell me where the file is, Scribe will have a better
chance of working when system 7 comes out.

Thanks
Michael Fryd			(412) 751-5557
MEFCO, Inc.			Fax: (412) 751-8403
2401 Coulter Road		Arpa: Michael.Fryd@cs.cmu.edu
McKeesport, PA  15131-4251

chewy@apple.com (Paul Snively) (10/11/89)

In article <6464@pt.cs.cmu.edu> fryd@g.gp.cs.cmu.edu (Michael Fryd) writes:
> Is there any way to get the real filename and directory name for an open
> file?  I would like to avoid trying to parse the filename myself,  If
> I can get the Mac to tell me where the file is, Scribe will have a better
> chance of working when system 7 comes out.
> 
> Thanks
> Michael Fryd                    (412) 751-5557
> MEFCO, Inc.                     Fax: (412) 751-8403
> 2401 Coulter Road               Arpa: Michael.Fryd@cs.cmu.edu
> McKeesport, PA  15131-4251

If you really want the best chance of working properly in the future, 
don't use pathnames internally; convert them to volumename/dirID/filename 
form and use that internally.  And if you know you're running under System 7 or later, you may or may not wish to use the fileID.

__________________________________________________________________________
Just because I work for Apple Computer, Inc. doesn't mean that they 
believe what I believe or vice-versa.
__________________________________________________________________________

zebolskyd@yvax.byu.edu (10/14/89)

In article <4665@internal.Apple.COM>, chewy@apple.com (Paul Snively) writes:
>In article <6464@pt.cs.cmu.edu> fryd@g.gp.cs.cmu.edu (Michael Fryd) writes:
>> Is there any way to get the real filename and directory name for an open
>> file?  I would like to avoid trying to parse the filename myself,  If
>> I can get the Mac to tell me where the file is, Scribe will have a better
>> chance of working when system 7 comes out.
>>
>> Thanks
>> Michael Fryd                    (412) 751-5557
>> MEFCO, Inc.                     Fax: (412) 751-8403
>> 2401 Coulter Road               Arpa: Michael.Fryd@cs.cmu.edu
>> McKeesport, PA  15131-4251
>
>If you really want the best chance of working properly in the future,
>don't use pathnames internally; convert them to volumename/dirID/filename
>form and use that internally.  And if you know you're running under System 7
>or later, you may or may not wish to use the fileID.

If you want the _user_ to be able to see the pathname (and find their way to
the file) you can use PBGetWDInfo to get the dirID from your working
directory, then PBGetCatInfo to get that directory's parent's dirID, and
so on until to get to dirID=2, which will be the root. You get the names
along the way from ioNamePtr. That's also how I get the volume name for
the volumename/dirID/filename resource I use to save a file's location
for future _machine_ use. I can send you Modula-2 source code if you want,
but you would probably be better off making your _own_ mistakes instead
of trying to find mine.

--Lyle D. Gunderson   zebolskyd@yvax.byu.edu   CIS: 73760,2354

al@crucible.UUCP (Al Evans) (10/16/89)

In article <850zebolskyd@yvax.byu.edu> zebolskyd@yvax.byu.edu writes:

>If you want the _user_ to be able to see the pathname (and find their way to
>the file) you can use PBGetWDInfo to get the dirID from your working
>directory, then PBGetCatInfo to get that directory's parent's dirID, and
>so on until to get to dirID=2, which will be the root. You get the names
		       ^^^^^^^
      Although this seems to be true, it doesn't seem to be documented :-(

>along the way from ioNamePtr. That's also how I get the volume name for
>the volumename/dirID/filename resource I use to save a file's location
>for future _machine_ use. I can send you Modula-2 source code if you want,
>but you would probably be better off making your _own_ mistakes instead
>of trying to find mine.
>
>--Lyle D. Gunderson   zebolskyd@yvax.byu.edu   CIS: 73760,2354

There are MANY good reasons for never using full pathnames in a Mac
application. But I, too, have stumbled across situations where it
was absolutely necessary. I found that the technique recommended above
works, but was unable to find any guarantee that the root directory
would ALWAYS have dirID=2. As far as I can tell, the following routine
does not rely upon anything undocumented:

-----cut about here--------
{
Returns full pathname to folder specified by startID in thePath, where
startID is the vRefNum/wdRefNum returned by SFGetFile or SFPutFile
}

    PROCEDURE GetCurrentPath (startID : INTEGER; VAR thePath : Str255);
        VAR
            tempName : Str255;
            vParams : CInfoPBRec;
            theError : OSErr;
    BEGIN
        thePath := '';
        tempName := '';
        WITH vParams DO
            BEGIN
                ioCompletion := NIL;
                ioNamePtr := @tempName;
                ioVRefNum := startID;
                ioFDirIndex := -1;
                ioDrDirID := 0;
                REPEAT
                    theError := PBGetCatInfo(@vParams, FALSE);
                    IF (theError = noErr) THEN
                        BEGIN
                            ioDRDirID := ioDRParID;
                            thePath := concat(tempName, ':', thePath);
                            tempName := '';
                        END;
                UNTIL (theError <> noErr);
            END;
    END;
--------cut somewhere near here, too-------------
					--Al Evans--
-- 
Al Evans					"You'd grep to know what
...uunet!execu!sequoia!crucible!al			 you really sed."
							--Referent Blob

keith@Apple.COM (Keith Rollin) (10/16/89)

In article <111@crucible.UUCP> al@crucible.UUCP (Al Evans) writes:
>In article <850zebolskyd@yvax.byu.edu> zebolskyd@yvax.byu.edu writes:
>
>>If you want the _user_ to be able to see the pathname (and find their way to
>>the file) you can use PBGetWDInfo to get the dirID from your working
>>directory, then PBGetCatInfo to get that directory's parent's dirID, and
>>so on until to get to dirID=2, which will be the root. You get the names
>		       ^^^^^^^
>      Although this seems to be true, it doesn't seem to be documented :-(

This *IS* documented. Check out the top of page 92 of Inside Mac IV. In add-
ition, this is the technique used in Technote #238 and DTS Sample Code #18:
Standard File. Finally, there is a constant defined in the MPW headers
(fsRtDirID) that identifies the root as 2.

On the other hand, I, too, have a hard time relying on this bit of information.
Your alternate technique may have merit; I'll have to take a look at it. I'd
probably base my exit condition on a specific error rather than just any old
error, but so far it looks pretty good.

-- 
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc.  ---  Developer Technical Support
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"Argue for your Apple, and sure enough, it's yours" - Keith Rollin, Contusions

spencer@heinlein.osc.edu (Stephen N. Spencer) (10/16/89)

In article <111@crucible.UUCP> al@crucible.UUCP (Al Evans) writes:
>In article <850zebolskyd@yvax.byu.edu> zebolskyd@yvax.byu.edu writes:
>
>>If you want the _user_ to be able to see the pathname (and find their way to
>>the file) you can use PBGetWDInfo to get the dirID from your working
>>directory, then PBGetCatInfo to get that directory's parent's dirID, and
>>so on until to get to dirID=2, which will be the root. You get the names
>		       ^^^^^^^
>      Although this seems to be true, it doesn't seem to be documented :-(
>

Apple seems to use it (the dirID == 2 test for checking for root directory):
look at their sample code concering the Standard File Package.  While not
hard documentation, it does lend some validity to the test.

-=-
Stephen N. Spencer      |"For a successful technology, reality must take
ACCAD, 1224 Kinnear Rd. | precedence over public relations, for Nature
Columbus OH 43212       | cannot be fooled."     - Richard P. Feynman
spencer@heinlein.cgrg.ohio-state.edu OR spencer@cis.ohio-state.edu

al@crucible.UUCP (Al Evans) (10/16/89)

In article <35671@apple.Apple.COM> keith@Apple.COM (Keith Rollin) writes:
>In article <111@crucible.UUCP> al@crucible.UUCP (Al Evans) writes:
>>In article <850zebolskyd@yvax.byu.edu> zebolskyd@yvax.byu.edu writes:
>>
>>>so on until to get to dirID=2, which will be the root. You get the names
>>		       ^^^^^^^
>>      Although this seems to be true, it doesn't seem to be documented :-(
>
>This *IS* documented. Check out the top of page 92 of Inside Mac IV. In add-
>ition, this is the technique used in Technote #238 and DTS Sample Code #18:
>Standard File. Finally, there is a constant defined in the MPW headers
>(fsRtDirID) that identifies the root as 2.

You're right on all counts. Shows how much Mac programming I've been
doing recently. But STILL, I don't trust magic numbers, and prefer to
find alternate solutions -- while I can imagine the dirID of the root
directory changing, I suspect that trying to get information about its
parent will ALWAYS return an error.

>I'd probably base my exit condition on a specific error rather 
>than just any old error, but so far it looks pretty good.

That's probably a good plan -- though if the routine fails for
any reason OTHER than reaching the top of the directory tree,
your application is in REALLY serious trouble.

					--Al Evans--
-- 
Al Evans					"You'd grep to know what
...uunet!execu!sequoia!crucible!al			 you really sed."
							--Referent Blob

zben@umd5.umd.edu (Ben Cranston) (10/17/89)

In article <6464@pt.cs.cmu.edu> fryd@g.gp.cs.cmu.edu (Michael Fryd) writes:
> ... any way to get the real filename and directory name for an open file.
Emphasis added                                                   ^^^^

Cleaning up my desk last week I came upon a printed listing of the attached
subroutine.  It occurs to me that this could also be an answer to the question
often asked on this forum "how can I get back to the DATA FORK of the file
in whose RESOURCE FORK the currently executing program lives?".  I guess you
could apply this routine to the current resource file path reference number
(hopefully before ever opening any OTHER resource files :-).

Extend this program to (if HFS is running) utilize the fcbDirID field which
should contain the long word directory ID of the directory in which the open
file exists, and fcbCName which contains the file name.  Please see diagram
on page IV-180 for these fields.  The program, as stands, makes use of the
fcbVPtr field which is there in both HFS and MFS FCBs.  Please note also
that the volume name is available at vcbVN in the volume control block.

* Err = GetVRefNum(PathRef, Var VolRef);
* Given a path reference number, return reference number for the volume
* on which the file resides.
*
* This code KNOWS that the path reference number is really an offset into a
* system heap block containing the File Control Blocks.  It performs a few
* sanity checks (detailed below).
*
* Examines incore FCB (II-127) and VCB (II-125).
*
GetVRefNum Entry			;
	Move.L	(A7)+,A1		; Pop return address
*
* Two sanity checks are performed on the PathRefNum.  One, the modulo residue
* should be 2 (because of the length word at the beginning).  Two, the RefNum
* should be less than the length of the FCB buffer.
*
	Move.L	#0,D1			; Clear slack bits
	Move.W	4(A7),D1		; Get PathRefNum argument
	Move.L	FCBSPtr,A0		; Get pointer to FCB block
	Move.W	FSFCBLen,D0		; HFS flag/length of entry
	BMi.S	@010			; If MFS go use constant
	DivU.W	D0,D1			; Compute mod of pointer
	Bra.S	@020			; Go check remainder
@010	;
	DivU.W	#94,D1			; MFS constant FCB size ???
@020	;
	Swap	D1			; Get remainder of division
	Sub.W	#2,D1			; Allow for length word
	BNE.S	@030			; If not zero then error
*
	Move.W	4(A7),D0		; Get PathRefNum argument
	Cmp.W	(A0),D0			; Within size of buffer?
	BHS.S	@030			; If not then error
*
* Sanity checks passed, link to FCB and VCB.
*
	Move.L	fcbVPtr(A0,D0.W),A0	; Link to volume control block
	Move.W	vcbVRefNum(A0),D0	; Get Volume RefNum
	Move.L	#0,D1			; Clear error code
	Bra.S	@040			; Return to caller
*
* Error in input PathRefNum.
*
@030	;
	Move.L	#0,D0			; Return zero to caller
	Move.W	#$FFCD,D1		; Get error code
*
@040	;
	Move.L	(A7),A0			; Get address of VRefNum argument
	Move.W	D0,(A0)			; Set vRefNum argument
	Add.W	#6,A7			; Pop arguments
	Move.W	D1,(A7)			; Set function result
	Jmp	(A1)			; Return to caller
*
	End				; GetVRefNum

I probably disassembled this from some program.  I have no idea what the #94
is all about, according to II-127 the number should be 30!!!  Could anybody
who knows the right number correct this?

It wouldn't be that hard to do this in either Pascal or C...

-- 
Sig     DS.L    ('ZBen')       ; Ben Cranston <zben@Trantor.UMD.EDU>
* Computer Science Center Network Infrastructures Group
* University of Maryland at College Park

zebolskyd@yvax.byu.edu (10/18/89)

In article <111@crucible.UUCP> al@crucible.UUCP (Al Evans) writes:
>In article <850zebolskyd@yvax.byu.edu> zebolskyd@yvax.byu.edu writes:
>
>>If you want the _user_ to be able to see the pathname (and find their way to
>>the file) you can use PBGetWDInfo to get the dirID from your working
>>directory, then PBGetCatInfo to get that directory's parent's dirID, and
>>so on until to get to dirID=2, which will be the root. You get the names
>                       ^^^^^^^
>      Although this seems to be true, it doesn't seem to be documented :-(
>

This _is_ documented, Al, old chum. In IM vol. IV. Where else would a
rank amateur like myself get such information? The reference to the
dirID=2 included the word "always" so I thought it sounded safe to use.
The information was somewhere in the introductory description of HFS, where
paths, etc., are discussed. Page IV-92, line 2. Still, the algorithm
presented earlier, which watched for errors instead, has the merit that
if Apple does not define "always" as I do, it will still work.

Thanks for the information, people!

--Lyle D. Gunderson
zebolskyd@yvax.byu.edu