/* ** Apple Macintosh Developer Technical Support ** ** Routines for dealing with full pathnames... if you really must. ** ** by Jim Luther, Apple Developer Technical Support Emeritus ** ** File: FullPath.c ** ** Copyright © 1995-1999 Apple Computer, Inc. ** All rights reserved. ** ** You may incorporate this sample code into your applications without ** restriction, though the sample code has been provided "AS IS" and the ** responsibility for its operation is 100% yours. However, what you are ** not permitted to do is to redistribute the source as "DSC Sample Code" ** after having made changes. If you're going to re-distribute the source, ** we require that you make it clear in the source that the code was ** descended from Apple Sample Code, but that you've made changes. */ #include #include #include #include #include #include "UT_MacFiles.h" #define SystemSevenOrLater 1 /*****************************************************************************/ pascal OSErr FSMakeFSSpecCompat(short vRefNum, long dirID, ConstStr255Param fileName, FSSpec *spec) { OSErr result; #if !SystemSevenOrLater if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() ) #endif /* !SystemSevenOrLater */ { /* Let the file system create the FSSpec if it can since it does the job */ /* much more efficiently than I can. */ result = FSMakeFSSpec(vRefNum, dirID, fileName, spec); /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */ /* returned in the parID field when making an FSSpec to the volume's */ /* root directory by passing a full pathname in MakeFSSpec's */ /* fileName parameter. */ if ( (result == noErr) && (spec->parID == 0) ) spec->parID = fsRtParID; } #if !SystemSevenOrLater else { Boolean isDirectory; result = GetObjectLocation(vRefNum, dirID, fileName, &(spec->vRefNum), &(spec->parID), spec->name, &isDirectory); } #endif /* !SystemSevenOrLater */ return ( result ); } /*****************************************************************************/ pascal OSErr FSpGetFullPath(const FSSpec *spec, short *fullPathLength, Handle *fullPath) { OSErr result; OSErr realResult; FSSpec tempSpec; CInfoPBRec pb; *fullPathLength = 0; *fullPath = NULL; /* Default to noErr */ realResult = result = noErr; /* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */ if ( spec->name[0] == 0 ) { result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec); } else { /* Make a copy of the input FSSpec that can be modified */ BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); } if ( result == noErr ) { if ( tempSpec.parID == fsRtParID ) { /* The object is a volume */ /* Add a colon to make it a full pathname */ ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; /* We're done */ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); } else { /* The object isn't a volume */ /* Is the object a file or a directory? */ pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrDirID = tempSpec.parID; pb.dirInfo.ioFDirIndex = 0; result = PBGetCatInfoSync(&pb); // Allow file/directory name at end of path to not exist. realResult = result; if ( (result == noErr) || (result == fnfErr) ) { /* if the object is a directory, append a colon so full pathname ends with colon */ if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) { ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; } /* Put the object name in first */ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); if ( result == noErr ) { /* Get the ancestor directory names */ pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrParID = tempSpec.parID; do /* loop until we have an error or find the root directory */ { pb.dirInfo.ioFDirIndex = -1; pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; result = PBGetCatInfoSync(&pb); if ( result == noErr ) { /* Append colon to directory name */ ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = ':'; /* Add directory name to beginning of fullPath */ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); result = MemError(); } } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) ); } } } } if ( result == noErr ) { /* Return the length */ *fullPathLength = GetHandleSize(*fullPath); result = realResult; // return realResult in case it was fnfErr } else { /* Dispose of the handle and return NULL and zero length */ if ( *fullPath != NULL ) { DisposeHandle(*fullPath); } *fullPath = NULL; *fullPathLength = 0; } return ( result ); } /*****************************************************************************/