macstuff.c
资源名称:unzip540.zip [点击查看]
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:49k
源码类别:
压缩解压
开发平台:
MultiPlatform
- #include <string.h>
- #include "macstuff.h"
- extern int errno;
- static OSErr GetCommentFromDesktopFile(short vRefNum,
- long dirID,
- ConstStr255Param name,
- Str255 comment);
- static OSErr GetCommentID(short vRefNum,
- long dirID,
- ConstStr255Param name,
- short *commentID);
- static OSErr GetDesktopFileName(short vRefNum,
- Str255 desktopName);
- enum
- {
- kBNDLResType = 'BNDL',
- kFREFResType = 'FREF',
- kIconFamResType = 'ICN#',
- kFCMTResType = 'FCMT',
- kAPPLResType = 'APPL'
- };
- /*****************************************************************************/
- /*
- ** File Manager FSp calls
- */
- /*****************************************************************************/
- pascal OSErr FSMakeFSSpecCompat(short vRefNum,
- long dirID,
- ConstStr255Param fileName,
- FSSpec *spec)
- {
- OSErr result;
- #if !__MACOSSEVENORLATER
- if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
- {
- Boolean isDirectory;
- result = GetObjectLocation(vRefNum, dirID, fileName,
- &(spec->vRefNum), &(spec->parID), spec->name,
- &isDirectory);
- }
- else
- #endif /* !__MACOSSEVENORLATER */
- {
- /* 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. Fixed in Mac OS 8.1 */
- if ( (result == noErr) && (spec->parID == 0) )
- spec->parID = fsRtParID;
- }
- return ( result );
- }
- /*****************************************************************************/
- /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
- #if !__MACOSSEVENORLATER
- static Boolean FSHasFSSpecCalls(void)
- {
- long response;
- #if !GENERATENODATA
- static Boolean tested = false;
- static Boolean result = false;
- #else
- Boolean result = false;
- #endif
- #if !GENERATENODATA
- if ( !tested )
- {
- tested = true;
- #endif
- if ( Gestalt(gestaltFSAttr, &response) == noErr )
- {
- result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
- }
- #if !GENERATENODATA
- }
- #endif
- return ( result );
- }
- #endif /* !__MACOSSEVENORLATER */
- /*****************************************************************************/
- /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
- /* except for FSpExchangeFiles. */
- #if !__MACOSSEVENORLATER
- static Boolean QTHasFSSpecCalls(void)
- {
- long response;
- #if !GENERATENODATA
- static Boolean tested = false;
- static Boolean result = false;
- #else
- Boolean result = false;
- #endif
- #if !GENERATENODATA
- if ( !tested )
- {
- tested = true;
- #endif
- result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
- #if !GENERATENODATA
- }
- #endif
- return ( result );
- }
- #endif /* !__MACOSSEVENORLATER */
- /*
- *----------------------------------------------------------------------
- *
- * FSpGetDefaultDir --
- *
- * This function gets the current default directory.
- *
- * Results:
- * The provided FSSpec is changed to point to the "default"
- * directory. The function returns what ever errors
- * FSMakeFSSpecCompat may encounter.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
- {
- OSErr err;
- short vRefNum = 0;
- long int dirID = 0;
- err = HGetVol(NULL, &vRefNum, &dirID);
- if (err == noErr) {
- err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
- dirSpec);
- }
- return err;
- }
- /*
- *----------------------------------------------------------------------
- *
- * FSpSetDefaultDir --
- *
- * This function sets the default directory to the directory
- * pointed to by the provided FSSpec.
- *
- * Results:
- * The function returns what ever errors HSetVol may encounter.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
- {
- OSErr err;
- /*
- * The following special case is needed to work around a bug
- * in the Macintosh OS. (Acutally PC Exchange.)
- */
- if (dirSpec->parID == fsRtParID) {
- err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
- } else {
- err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
- }
- return err;
- }
- /*
- *----------------------------------------------------------------------
- *
- * FSpFindFolder --
- *
- * This function is a version of the FindFolder function that
- * returns the result as a FSSpec rather than a vRefNum and dirID.
- *
- * Results:
- * Results will be simaler to that of the FindFolder function.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- OSErr
- FSpFindFolder(
- short vRefNum, /* Volume reference number. */
- OSType folderType, /* Folder type taken by FindFolder. */
- Boolean createFolder, /* Should we create it if non-existant. */
- FSSpec *spec) /* Pointer to resulting directory. */
- {
- short foundVRefNum;
- long foundDirID;
- OSErr err;
- err = FindFolder(vRefNum, folderType, createFolder,
- &foundVRefNum, &foundDirID);
- if (err != noErr) {
- return err;
- }
- err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "p", spec);
- return err;
- }
- /*
- *----------------------------------------------------------------------
- *
- * FSpPathFromLocation --
- *
- * This function obtains a full path name for a given macintosh
- * FSSpec. Unlike the More Files function FSpGetFullPath, this
- * function will return a C string in the Handle. It also will
- * create paths for FSSpec that do not yet exist.
- *
- * Results:
- * OSErr code.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- OSErr
- FSpPathFromLocation(
- FSSpec *spec, /* The location we want a path for. */
- int *length, /* Length of the resulting path. */
- Handle *fullPath) /* Handle to path. */
- {
- OSErr err;
- FSSpec tempSpec;
- CInfoPBRec pb;
- *fullPath = NULL;
- /*
- * Make a copy of the input FSSpec that can be modified.
- */
- BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
- if (tempSpec.parID == fsRtParID) {
- /*
- * The object is a volume. Add a colon to make it a full
- * pathname. Allocate a handle for it and we are done.
- */
- tempSpec.name[0] += 2;
- tempSpec.name[tempSpec.name[0] - 1] = ':';
- tempSpec.name[tempSpec.name[0]] = ' ';
- err = 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;
- err = PBGetCatInfoSync(&pb);
- if ((err == noErr) || (err == fnfErr)) {
- /*
- * If the file doesn't currently exist we start over. If the
- * directory exists everything will work just fine. Otherwise we
- * will just fail later. If the object is a directory, append a
- * colon so full pathname ends with colon.
- */
- if (err == fnfErr) {
- BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
- } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
- tempSpec.name[0] += 1;
- tempSpec.name[tempSpec.name[0]] = ':';
- }
- /*
- * Create a new Handle for the object - make it a C string.
- */
- tempSpec.name[0] += 1;
- tempSpec.name[tempSpec.name[0]] = ' ';
- err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
- if (err == noErr) {
- /*
- * Get the ancestor directory names - loop until we have an
- * error or find the root directory.
- */
- pb.dirInfo.ioNamePtr = tempSpec.name;
- pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
- pb.dirInfo.ioDrParID = tempSpec.parID;
- do {
- pb.dirInfo.ioFDirIndex = -1;
- pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
- err = PBGetCatInfoSync(&pb);
- if (err == noErr) {
- /*
- * Append colon to directory name and add
- * directory name to beginning of fullPath.
- */
- ++tempSpec.name[0];
- tempSpec.name[tempSpec.name[0]] = ':';
- (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
- tempSpec.name[0]);
- err = MemError();
- }
- } while ( (err == noErr) &&
- (pb.dirInfo.ioDrDirID != fsRtDirID) );
- }
- }
- }
- /*
- * On error Dispose the handle, set it to NULL & return the err.
- * Otherwise, set the length & return.
- */
- if (err == noErr) {
- *length = GetHandleSize(*fullPath) - 1;
- } else {
- if ( *fullPath != NULL ) {
- DisposeHandle(*fullPath);
- }
- *fullPath = NULL;
- *length = 0;
- }
- return err;
- }
- /*****************************************************************************/
- pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
- long *theDirID,
- Boolean *isDirectory)
- {
- return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
- theDirID, isDirectory) );
- }
- /*****************************************************************************/
- pascal OSErr GetDirectoryID(short vRefNum,
- long dirID,
- ConstStr255Param name,
- long *theDirID,
- Boolean *isDirectory)
- {
- CInfoPBRec pb;
- OSErr error;
- error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
- if ( error == noErr )
- {
- *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
- if ( *isDirectory )
- {
- *theDirID = pb.dirInfo.ioDrDirID;
- }
- else
- {
- *theDirID = pb.hFileInfo.ioFlParID;
- }
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr GetCatInfoNoName(short vRefNum,
- long dirID,
- ConstStr255Param name,
- CInfoPBPtr pb)
- {
- Str31 tempName;
- OSErr error;
- /* Protection against File Sharing problem */
- if ( (name == NULL) || (name[0] == 0) )
- {
- tempName[0] = 0;
- pb->dirInfo.ioNamePtr = tempName;
- pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb->dirInfo.ioNamePtr = (StringPtr)name;
- pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb->dirInfo.ioVRefNum = vRefNum;
- pb->dirInfo.ioDrDirID = dirID;
- error = PBGetCatInfoSync(pb);
- pb->dirInfo.ioNamePtr = NULL;
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr GetObjectLocation(short vRefNum,
- long dirID,
- ConstStr255Param pathname,
- short *realVRefNum,
- long *realParID,
- Str255 realName,
- Boolean *isDirectory)
- {
- OSErr error;
- CInfoPBRec pb;
- Str255 tempPathname;
- /* clear results */
- *realVRefNum = 0;
- *realParID = 0;
- realName[0] = 0;
- /*
- ** Get the real vRefNum
- */
- error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
- if ( error == noErr )
- {
- /*
- ** Determine if the object already exists and if so,
- ** get the real parent directory ID if it's a file
- */
- /* Protection against File Sharing problem */
- if ( (pathname == NULL) || (pathname[0] == 0) )
- {
- tempPathname[0] = 0;
- pb.hFileInfo.ioNamePtr = tempPathname;
- pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- /*
- ** The file system object is present and we have the file's
- ** real parID
- */
- /* Is it a directory or a file? */
- *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
- if ( *isDirectory )
- {
- /*
- ** It's a directory, get its name and parent dirID, and then
- ** we're done
- */
- pb.dirInfo.ioNamePtr = realName;
- pb.dirInfo.ioVRefNum = *realVRefNum;
- /* pb.dirInfo.ioDrDirID already contains the dirID of the
- directory object */
- pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
- error = PBGetCatInfoSync(&pb);
- /* get the parent ID here, because the file system can return the */
- /* wrong parent ID from the last call. */
- *realParID = pb.dirInfo.ioDrParID;
- }
- else
- {
- /*
- ** It's a file - use the parent directory ID from the last call
- ** to GetCatInfoparse, get the file name, and then we're done
- */
- *realParID = pb.hFileInfo.ioFlParID;
- error = GetFilenameFromPathname(pathname, realName);
- }
- }
- else if ( error == fnfErr )
- {
- /*
- ** The file system object is not present - see if its parent is present
- */
- /*
- ** Parse to get the object name from end of pathname
- */
- error = GetFilenameFromPathname(pathname, realName);
- /* if we can't get the object name from the end, we can't continue */
- if ( error == noErr )
- {
- /*
- ** What we want now is the pathname minus the object name
- ** for example:
- ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
- ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
- ** if pathname is ':dir:file' tempPathname becomes ':dir:'
- ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
- ** if pathname is ':file' tempPathname becomes ':'
- ** if pathname is 'file or file:' tempPathname becomes ''
- */
- /* get a copy of the pathname */
- BlockMoveData(pathname, tempPathname, pathname[0] + 1);
- /* remove the object name */
- tempPathname[0] -= realName[0];
- /* and the trailing colon (if any) */
- if ( pathname[pathname[0]] == ':' )
- {
- --tempPathname[0];
- }
- /* OK, now get the parent's directory ID */
- /* Protection against File Sharing problem */
- pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
- if ( tempPathname[0] != 0 )
- {
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- else
- {
- pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- error = PBGetCatInfoSync(&pb);
- *realParID = pb.dirInfo.ioDrDirID;
- *isDirectory = false; /* we don't know what the object is
- really going to be */
- }
- if ( error != noErr )
- {
- error = dirNFErr; /* couldn't find parent directory */
- }
- else
- {
- error = fnfErr; /* we found the parent, but not the file */
- }
- }
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
- short vRefNum,
- short *realVRefNum)
- {
- HParamBlockRec pb;
- OSErr error;
- error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
- if ( error == noErr )
- {
- *realVRefNum = pb.volumeParam.ioVRefNum;
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
- Str255 filename)
- {
- short index;
- short nameEnd;
- OSErr error;
- /* default to no filename */
- filename[0] = 0;
- /* check for no pathname */
- if ( pathname != NULL )
- {
- /* get string length */
- index = pathname[0];
- /* check for empty string */
- if ( index != 0 )
- {
- /* skip over last trailing colon (if any) */
- if ( pathname[index] == ':' )
- {
- --index;
- }
- /* save the end of the string */
- nameEnd = index;
- /* if pathname ends with multiple colons, then this pathname refers */
- /* to a directory, not a file */
- if ( pathname[index] != ':' )
- {
- /* parse backwards until we find a colon or hit the beginning
- of the pathname */
- while ( (index != 0) && (pathname[index] != ':') )
- {
- --index;
- }
- /* if we parsed to the beginning of the pathname and the
- pathname ended */
- /* with a colon, then pathname is a full pathname to a volume,
- not a file */
- if ( (index != 0) || (pathname[pathname[0]] != ':') )
- {
- /* get the filename and return noErr */
- filename[0] = (char)(nameEnd - index);
- BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
- error = noErr;
- }
- else
- {
- /* pathname to a volume, not a file */
- error = notAFileErr;
- }
- }
- else
- {
- /* directory, not a file */
- error = notAFileErr;
- }
- }
- else
- {
- /* empty string isn't a file */
- error = notAFileErr;
- }
- }
- else
- {
- /* NULL pathname isn't a file */
- error = notAFileErr;
- }
- return ( error );
- }
- /*****************************************************************************/
- /*
- ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
- ** in cases where the returned volume name is not needed by the caller.
- ** The pathname and vRefNum parameters are not touched, and the pb
- ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
- ** the parameter block is always returned as NULL (since it might point
- ** to the local tempPathname).
- **
- ** I noticed using this code in several places, so here it is once.
- ** This reduces the code size of MoreFiles.
- */
- pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
- short vRefNum,
- HParmBlkPtr pb)
- {
- Str255 tempPathname;
- OSErr error;
- /* Make sure pb parameter is not NULL */
- if ( pb != NULL )
- {
- pb->volumeParam.ioVRefNum = vRefNum;
- if ( pathname == NULL )
- {
- pb->volumeParam.ioNamePtr = NULL;
- pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
- }
- else
- { /* make a copy of the string and */
- BlockMoveData(pathname, tempPathname, pathname[0] + 1);
- /* use the copy so original isn't trashed */
- pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
- /* use ioNamePtr/ioVRefNum combination */
- pb->volumeParam.ioVolIndex = -1;
- }
- error = PBHGetVInfoSync(pb);
- pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local
- tempPathname, so don't return it */
- }
- else
- {
- error = paramErr;
- }
- return ( error );
- }
- /*****************************************************************************/
- 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 = noErr;
- /* Make a copy of the input FSSpec that can be modified */
- BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
- 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 & ioDirMask) != 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 = InlineGetHandleSize(*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 );
- }
- /*****************************************************************************/
- pascal OSErr FSpLocationFromFullPath(short fullPathLength,
- const void *fullPath,
- FSSpec *spec)
- {
- AliasHandle alias;
- OSErr result;
- Boolean wasChanged;
- Str32 nullString;
- /* Create a minimal alias from the full pathname */
- nullString[0] = 0; /* null string to indicate no zone or server name */
- result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
- nullString, &alias);
- if ( result == noErr )
- {
- /* Let the Alias Manager resolve the alias. */
- result = ResolveAlias(NULL, alias, spec, &wasChanged);
- DisposeHandle((Handle)alias); /* Free up memory used */
- }
- return ( result );
- }
- /*****************************************************************************/
- pascal OSErr GetFullPath(short vRefNum,
- long dirID,
- ConstStr255Param name,
- short *fullPathLength,
- Handle *fullPath)
- {
- OSErr result;
- FSSpec spec;
- *fullPathLength = 0;
- *fullPath = NULL;
- result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
- if ( (result == noErr) || (result == fnfErr) )
- {
- result = FSpGetFullPath(&spec, fullPathLength, fullPath);
- }
- return ( result );
- }
- /*****************************************************************************/
- pascal OSErr ChangeCreatorType(short vRefNum,
- long dirID,
- ConstStr255Param name,
- OSType creator,
- OSType fileType)
- {
- CInfoPBRec pb;
- OSErr error;
- short realVRefNum;
- long parID;
- pb.hFileInfo.ioNamePtr = (StringPtr)name;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) /* if file */
- { /* save parent dirID for BumpDate call */
- parID = pb.hFileInfo.ioFlParID;
- /* If creator not 0x00000000, change creator */
- if ( creator != (OSType)0x00000000 )
- {
- pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
- }
- /* If fileType not 0x00000000, change fileType */
- if ( fileType != (OSType)0x00000000 )
- {
- pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
- }
- pb.hFileInfo.ioDirID = dirID;
- error = PBSetCatInfoSync(&pb); /* now, save the new information
- back to disk */
- if ( (error == noErr) && (parID != fsRtParID) ) /* can't
- bump fsRtParID */
- {
- /* get the real vRefNum in case a full pathname was passed */
- error = DetermineVRefNum(name, vRefNum, &realVRefNum);
- if ( error == noErr )
- {
- error = BumpDate(realVRefNum, parID, NULL);
- /* and bump the parent directory's mod date to wake
- up the Finder */
- /* to the change we just made */
- }
- }
- }
- else
- {
- /* it was a directory, not a file */
- error = notAFileErr;
- }
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
- OSType creator,
- OSType fileType)
- {
- return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
- creator, fileType) );
- }
- /*****************************************************************************/
- pascal OSErr BumpDate(short vRefNum,
- long dirID,
- ConstStr255Param name)
- /* Given a file or directory, change its modification date to the
- current date/time. */
- {
- CInfoPBRec pb;
- Str31 tempName;
- OSErr error;
- unsigned long secs;
- /* Protection against File Sharing problem */
- if ( (name == NULL) || (name[0] == 0) )
- {
- tempName[0] = 0;
- pb.hFileInfo.ioNamePtr = tempName;
- pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb.hFileInfo.ioNamePtr = (StringPtr)name;
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- GetDateTime(&secs);
- /* set mod date to current date, or one second into the future
- if mod date = current date */
- pb.hFileInfo.ioFlMdDat =
- (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
- if ( pb.dirInfo.ioNamePtr == tempName )
- {
- pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
- }
- else
- {
- pb.hFileInfo.ioDirID = dirID;
- }
- error = PBSetCatInfoSync(&pb);
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr FSpBumpDate(const FSSpec *spec)
- {
- return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
- }
- /*****************************************************************************/
- pascal OSErr OnLine(FSSpecPtr volumes,
- short reqVolCount,
- short *actVolCount,
- short *volIndex)
- {
- HParamBlockRec pb;
- OSErr error = noErr;
- FSSpec *endVolArray;
- if ( *volIndex > 0 )
- {
- *actVolCount = 0;
- for ( endVolArray = volumes + reqVolCount;
- (volumes < endVolArray) && (error == noErr); ++volumes )
- {
- pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
- pb.volumeParam.ioVolIndex = *volIndex;
- error = PBHGetVInfoSync(&pb);
- if ( error == noErr )
- {
- volumes->parID = fsRtParID; /* the root directory's
- parent is 1 */
- volumes->vRefNum = pb.volumeParam.ioVRefNum;
- ++*volIndex;
- ++*actVolCount;
- }
- }
- }
- else
- {
- error = paramErr;
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr DTGetComment(short vRefNum,
- long dirID,
- ConstStr255Param name,
- Str255 comment)
- {
- DTPBRec pb;
- OSErr error;
- short dtRefNum;
- Boolean newDTDatabase;
- if (comment != NULL)
- {
- comment[0] = 0; /* return nothing by default */
- /* attempt to open the desktop database */
- error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
- if ( error == noErr )
- {
- /* There was a desktop database and it's now open */
- if ( !newDTDatabase )
- {
- pb.ioDTRefNum = dtRefNum;
- pb.ioNamePtr = (StringPtr)name;
- pb.ioDirID = dirID;
- pb.ioDTBuffer = (Ptr)&comment[1];
- /*
- ** IMPORTANT NOTE #1: Inside Macintosh says that comments
- ** are up to 200 characters. While that may be correct for
- ** the HFS file system's Desktop Manager, other file
- ** systems (such as Apple Photo Access) return up to
- ** 255 characters. Make sure the comment buffer is a Str255
- ** or you'll regret it.
- **
- ** IMPORTANT NOTE #2: Although Inside Macintosh doesn't
- ** mention it, ioDTReqCount is a input field to
- ** PBDTGetCommentSync. Some file systems (like HFS) ignore
- ** ioDTReqCount and always return the full comment --
- ** others (like AppleShare) respect ioDTReqCount and only
- ** return up to ioDTReqCount characters of the comment.
- */
- pb.ioDTReqCount = sizeof(Str255) - 1;
- error = PBDTGetCommentSync(&pb);
- if (error == noErr)
- {
- comment[0] = (unsigned char)pb.ioDTActCount;
- }
- }
- }
- else
- {
- /* There is no desktop database - try the Desktop file */
- error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
- if ( error != noErr )
- {
- error = afpItemNotFound; /* return an expected error */
- }
- }
- }
- else
- {
- error = paramErr;
- }
- return (error);
- }
- /*****************************************************************************/
- pascal OSErr FSpDTGetComment(const FSSpec *spec,
- Str255 comment)
- {
- return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
- }
- /*****************************************************************************/
- pascal OSErr DTSetComment(short vRefNum,
- long dirID,
- ConstStr255Param name,
- ConstStr255Param comment)
- {
- DTPBRec pb;
- OSErr error;
- short dtRefNum;
- Boolean newDTDatabase;
- error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
- if ( error == noErr )
- {
- pb.ioDTRefNum = dtRefNum;
- pb.ioNamePtr = (StringPtr)name;
- pb.ioDirID = dirID;
- pb.ioDTBuffer = (Ptr)&comment[1];
- /* Truncate the comment to 200 characters just in case */
- /* some file system doesn't range check */
- if ( comment[0] <= 200 )
- {
- pb.ioDTReqCount = comment[0];
- }
- else
- {
- pb.ioDTReqCount = 200;
- }
- error = PBDTSetCommentSync(&pb);
- }
- return (error);
- }
- /*****************************************************************************/
- pascal OSErr FSpDTSetComment(const FSSpec *spec,
- ConstStr255Param comment)
- {
- return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
- }
- /*****************************************************************************/
- pascal OSErr DTOpen(ConstStr255Param volName,
- short vRefNum,
- short *dtRefNum,
- Boolean *newDTDatabase)
- {
- OSErr error;
- GetVolParmsInfoBuffer volParmsInfo;
- long infoSize;
- DTPBRec pb;
- /* Check for volume Desktop Manager support before calling */
- infoSize = sizeof(GetVolParmsInfoBuffer);
- error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
- if ( error == noErr )
- {
- if ( hasDesktopMgr(volParmsInfo) )
- {
- pb.ioNamePtr = (StringPtr)volName;
- pb.ioVRefNum = vRefNum;
- error = PBDTOpenInform(&pb);
- /* PBDTOpenInform informs us if the desktop was just created */
- /* by leaving the low bit of ioTagInfo clear (0) */
- *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
- if ( error == paramErr )
- {
- error = PBDTGetPath(&pb);
- /* PBDTGetPath doesn't tell us if the database is new */
- /* so assume it is not new */
- *newDTDatabase = false;
- }
- *dtRefNum = pb.ioDTRefNum;
- }
- else
- {
- error = paramErr;
- }
- }
- return ( error );
- }
- /*****************************************************************************/
- /*
- ** GetCommentFromDesktopFile
- **
- ** Get a file or directory's Finder comment field (if any) from the
- ** Desktop file's 'FCMT' resources.
- */
- static OSErr GetCommentFromDesktopFile(short vRefNum,
- long dirID,
- ConstStr255Param name,
- Str255 comment)
- {
- OSErr error;
- short commentID;
- short realVRefNum;
- Str255 desktopName;
- short savedResFile;
- short dfRefNum;
- StringHandle commentHandle;
- /* Get the comment ID number */
- error = GetCommentID(vRefNum, dirID, name, &commentID);
- if ( error == noErr )
- {
- if ( commentID != 0 ) /* commentID == 0 means there's no comment */
- {
- error = DetermineVRefNum(name, vRefNum, &realVRefNum);
- if ( error == noErr )
- {
- error = GetDesktopFileName(realVRefNum, desktopName);
- if ( error == noErr )
- {
- savedResFile = CurResFile();
- /*
- ** Open the 'Desktop' file in the root directory. (because
- ** opening the resource file could preload unwanted resources,
- ** bracket the call with SetResLoad(s))
- */
- SetResLoad(false);
- dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
- fsRdPerm);
- SetResLoad(true);
- if ( dfRefNum != -1)
- {
- /* Get the comment resource */
- commentHandle = (StringHandle)Get1Resource(kFCMTResType,
- commentID);
- if ( commentHandle != NULL )
- {
- if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
- {
- BlockMoveData(*commentHandle, comment,
- *commentHandle[0] + 1);
- }
- else
- { /* no comment available */
- error = afpItemNotFound;
- }
- }
- else
- { /* no comment available */
- error = afpItemNotFound;
- }
- /* restore the resource chain and close
- the Desktop file */
- UseResFile(savedResFile);
- CloseResFile(dfRefNum);
- }
- else
- {
- error = afpItemNotFound;
- }
- }
- else
- {
- error = afpItemNotFound;
- }
- }
- }
- else
- {
- error = afpItemNotFound; /* no comment available */
- }
- }
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr HGetVolParms(ConstStr255Param volName,
- short vRefNum,
- GetVolParmsInfoBuffer *volParmsInfo,
- long *infoSize)
- {
- HParamBlockRec pb;
- OSErr error;
- pb.ioParam.ioNamePtr = (StringPtr)volName;
- pb.ioParam.ioVRefNum = vRefNum;
- pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
- pb.ioParam.ioReqCount = *infoSize;
- error = PBHGetVolParmsSync(&pb);
- if ( error == noErr )
- {
- *infoSize = pb.ioParam.ioActCount;
- }
- return ( error );
- }
- /*****************************************************************************/
- /*
- ** GetCommentID
- **
- ** Get the comment ID number for the Desktop file's 'FCMT' resource ID from
- ** the file or folders fdComment (frComment) field.
- */
- static OSErr GetCommentID(short vRefNum,
- long dirID,
- ConstStr255Param name,
- short *commentID)
- {
- CInfoPBRec pb;
- OSErr error;
- error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
- *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
- return ( error );
- }
- /*****************************************************************************/
- /*
- ** GetDesktopFileName
- **
- ** Get the name of the Desktop file.
- */
- static OSErr GetDesktopFileName(short vRefNum,
- Str255 desktopName)
- {
- OSErr error;
- HParamBlockRec pb;
- short index;
- Boolean found;
- pb.fileParam.ioNamePtr = desktopName;
- pb.fileParam.ioVRefNum = vRefNum;
- pb.fileParam.ioFVersNum = 0;
- index = 1;
- found = false;
- do
- {
- pb.fileParam.ioDirID = fsRtDirID;
- pb.fileParam.ioFDirIndex = index;
- error = PBHGetFInfoSync(&pb);
- if ( error == noErr )
- {
- if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
- (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
- {
- found = true;
- }
- }
- ++index;
- } while ( (error == noErr) && !found );
- return ( error );
- }
- /*****************************************************************************/
- pascal OSErr XGetVInfo(short volReference,
- StringPtr volName,
- short *vRefNum,
- UnsignedWide *freeBytes,
- UnsignedWide *totalBytes)
- {
- OSErr result;
- long response;
- XVolumeParam pb;
- /* See if large volume support is available */
- if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
- {
- /* Large volume support is available */
- pb.ioVRefNum = volReference;
- pb.ioNamePtr = volName;
- pb.ioXVersion = 0; /* this XVolumeParam version (0) */
- pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
- result = PBXGetVolInfoSync(&pb);
- if ( result == noErr )
- {
- /* The volume name was returned in volName (if not NULL) and */
- /* we have the volume's vRefNum and allocation block size */
- *vRefNum = pb.ioVRefNum;
- /* return the freeBytes and totalBytes */
- *totalBytes = pb.ioVTotalBytes;
- *freeBytes = pb.ioVFreeBytes;
- }
- }
- else
- {
- /* No large volume support */
- /* Use HGetVInfo to get the results */
- result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
- if ( result == noErr )
- {
- /* zero the high longs of totalBytes and freeBytes */
- totalBytes->hi = 0;
- freeBytes->hi = 0;
- }
- }
- return ( result );
- }
- /*****************************************************************************/
- pascal OSErr HGetVInfo(short volReference,
- StringPtr volName,
- short *vRefNum,
- unsigned long *freeBytes,
- unsigned long *totalBytes)
- {
- HParamBlockRec pb;
- unsigned long allocationBlockSize;
- unsigned short numAllocationBlocks;
- unsigned short numFreeBlocks;
- VCB *theVCB;
- Boolean vcbFound;
- OSErr result;
- /* Use the File Manager to get the real vRefNum */
- pb.volumeParam.ioVRefNum = volReference;
- pb.volumeParam.ioNamePtr = volName;
- pb.volumeParam.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
- result = PBHGetVInfoSync(&pb);
- if ( result == noErr )
- {
- /* The volume name was returned in volName (if not NULL) and */
- /* we have the volume's vRefNum and allocation block size */
- *vRefNum = pb.volumeParam.ioVRefNum;
- allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
- /* System 7.5 (and beyond) pins the number of allocation blocks and */
- /* the number of free allocation blocks returned by PBHGetVInfo to */
- /* a value so that when multiplied by the allocation block size, */
- /* the volume will look like it has $7fffffff bytes or less. This */
- /* was done so older applications that use signed math or that use */
- /* the GetVInfo function (which uses signed math) will continue to work. */
- /* However, the unpinned numbers (which we want) are always available */
- /* in the volume's VCB so we'll get those values from the VCB if possible. */
- /* Find the volume's VCB */
- vcbFound = false;
- theVCB = (VCB *)(GetVCBQHdr()->qHead);
- while ( (theVCB != NULL) && !vcbFound )
- {
- /* Check VCB signature before using VCB. Don't have to check for */
- /* MFS (0xd2d7) because they can't get big enough to be pinned */
- if ( theVCB->vcbSigWord == 0x4244 )
- {
- if ( theVCB->vcbVRefNum == *vRefNum )
- {
- vcbFound = true;
- }
- }
- if ( !vcbFound )
- {
- theVCB = (VCB *)(theVCB->qLink);
- }
- }
- if ( theVCB != NULL )
- {
- /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
- /* and the number of free blocks from the VCB. */
- numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
- numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
- }
- else
- {
- /* Didn't find a VCB we can use. Return the number of allocation blocks */
- /* and the number of free blocks returned by PBHGetVInfoSync. */
- numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
- numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
- }
- /* Now, calculate freeBytes and totalBytes using unsigned values */
- *freeBytes = numFreeBlocks * allocationBlockSize;
- *totalBytes = numAllocationBlocks * allocationBlockSize;
- }
- return ( result );
- }
- /*
- ** PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
- ** File Manager requests from CFM-based programs. At some point, Apple
- ** will get around to adding this to the standard libraries you link with
- ** and you'll get a duplicate symbol link error. At that time, just delete
- ** this code (or comment it out).
- **
- ** Non-CFM 68K programs don't needs this glue (and won't get it) because
- ** they instead use the inline assembly glue found in the Files.h interface
- ** file.
- */
- #if __WANTPASCALELIMINATION
- #undef pascal
- #endif
- #if GENERATINGCFM
- pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
- {
- enum
- {
- kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */
- uppFSDispatchProcInfo = kRegisterBased
- | REGISTER_RESULT_LOCATION(kRegisterD0)
- | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */
- | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */
- | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
- };
- return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
- uppFSDispatchProcInfo,
- _FSDispatch,
- kXGetVolInfoSelector,
- paramBlock) );
- }
- #endif
- #if __WANTPASCALELIMINATION
- #define pascal
- #endif
- /*****************************************************************************/
- pascal OSErr GetDirName(short vRefNum,
- long dirID,
- Str31 name)
- {
- CInfoPBRec pb;
- OSErr error;
- if ( name != NULL )
- {
- pb.dirInfo.ioNamePtr = name;
- pb.dirInfo.ioVRefNum = vRefNum;
- pb.dirInfo.ioDrDirID = dirID;
- pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
- error = PBGetCatInfoSync(&pb);
- }
- else
- {
- error = paramErr;
- }
- return ( error );
- }