Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MoreFilesExtras.c
/* |
File: MoreFilesExtras.c |
Description:A collection of useful high-level File Manager routines. |
Author: JL |
Copyright: Copyright: © 1992-1999 by Apple Computer, Inc. |
all rights reserved. |
Disclaimer: 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. |
Change History (most recent first): |
6/25/99 Updated for Metrowerks Codewarror Pro 2.1(KG) |
*/ |
#include <Types.h> |
#include <Traps.h> |
#include <OSUtils.h> |
#include <Errors.h> |
#include <Files.h> |
#include <Devices.h> |
#include <Finder.h> |
#include <Folders.h> |
#include <FSM.h> |
#include <Disks.h> |
#include <Gestalt.h> |
#include <TextUtils.h> |
#include <Script.h> |
#include <Script.h> |
#include <stddef.h> |
#define __COMPILINGMOREFILES |
#include "MoreFiles.h" |
#include "MoreFilesExtras.h" |
#include "MoreDesktopMgr.h" |
#include "FSpCompat.h" |
/*****************************************************************************/ |
/* local data structures */ |
/* The DeleteEnumGlobals structure is used to minimize the amount of |
** stack space used when recursively calling DeleteLevel and to hold |
** global information that might be needed at any time. */ |
#if PRAGMA_ALIGN_SUPPORTED |
#pragma options align=mac68k |
#endif |
struct DeleteEnumGlobals |
{ |
OSErr error; /* temporary holder of results - saves 2 bytes of stack each level */ |
Str63 itemName; /* the name of the current item */ |
UniversalFMPB myPB; /* the parameter block used for PBGetCatInfo calls */ |
}; |
#if PRAGMA_ALIGN_SUPPORTED |
#pragma options align=reset |
#endif |
typedef struct DeleteEnumGlobals DeleteEnumGlobals; |
typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr; |
/*****************************************************************************/ |
pascal void TruncPString(StringPtr destination, |
ConstStr255Param source, |
short maxLength) |
{ |
short charType; |
if ( source != NULL && destination != NULL ) /* don't do anything stupid */ |
{ |
if ( source[0] > maxLength ) |
{ |
/* Make sure the string isn't truncated in the middle of */ |
/* a multi-byte character. */ |
while (maxLength != 0) |
{ |
charType = CharByte((Ptr)&source[1], maxLength); |
if ( (charType == smSingleByte) || (charType == smLastByte) ) |
break; /* source[maxLength] is now a valid last character */ |
--maxLength; |
} |
} |
else |
{ |
maxLength = source[0]; |
} |
/* Set the destination string length */ |
destination[0] = maxLength; |
/* and copy maxLength characters (if needed) */ |
if ( source != destination ) |
{ |
while ( maxLength != 0 ) |
{ |
destination[maxLength] = source[maxLength]; |
--maxLength; |
} |
} |
} |
} |
/*****************************************************************************/ |
pascal Ptr GetTempBuffer(long buffReqSize, |
long *buffActSize) |
{ |
enum |
{ |
kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */ |
}; |
Ptr tempPtr; |
/* Make request a multiple of 1024 bytes */ |
buffReqSize = buffReqSize & 0xfffffc00; |
if ( buffReqSize < 0x00000400 ) |
{ |
/* Request was smaller than 1024 bytes - make it 1024 */ |
buffReqSize = 0x00000400; |
} |
/* Attempt to allocate the memory */ |
tempPtr = NewPtr(buffReqSize); |
/* If request failed, go to backup plan */ |
if ( (tempPtr == NULL) && (buffReqSize > 0x00000400) ) |
{ |
/* |
** Try to get largest 1024-byte block available |
** leaving some slop for the toolbox if possible |
*/ |
long freeMemory = (FreeMem() - kSlopMemory) & 0xfffffc00; |
buffReqSize = MaxBlock() & 0xfffffc00; |
if ( buffReqSize > freeMemory ) |
{ |
buffReqSize = freeMemory; |
} |
if ( buffReqSize == 0 ) |
{ |
buffReqSize = 0x00000400; |
} |
tempPtr = NewPtr(buffReqSize); |
} |
/* Return bytes allocated */ |
if ( tempPtr != NULL ) |
{ |
*buffActSize = buffReqSize; |
} |
else |
{ |
*buffActSize = 0; |
} |
return ( tempPtr ); |
} |
/*****************************************************************************/ |
/* |
** 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 |
{ |
BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */ |
pb->volumeParam.ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */ |
pb->volumeParam.ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */ |
} |
error = PBHGetVInfoSync(pb); |
pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */ |
} |
else |
{ |
error = paramErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync |
** 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 PBXGetVolInfoSync except that ioNamePtr in |
** the parameter block is always returned as NULL (since it might point |
** to the local tempPathname). |
*/ |
pascal OSErr XGetVolumeInfoNoName(ConstStr255Param pathname, |
short vRefNum, |
XVolumeParamPtr pb) |
{ |
Str255 tempPathname; |
long response; |
OSErr error; |
/* Make sure pb parameter is not NULL */ |
if ( pb != NULL ) |
{ |
pb->ioVRefNum = vRefNum; |
pb->ioXVersion = 0; /* this XVolumeParam version (0) */ |
if ( pathname == NULL ) |
{ |
pb->ioNamePtr = NULL; |
pb->ioVolIndex = 0; /* use ioVRefNum only */ |
} |
else |
{ |
BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */ |
pb->ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */ |
pb->ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */ |
} |
#if !__MACOSSEVENFIVEONEORLATER |
/* Is PBXGetVolInfo available? */ |
if ( ( Gestalt(gestaltFSAttr, &response) != noErr ) || ((response & (1L << gestaltFSSupports2TBVols)) == 0) ) |
{ |
/* No, fall back on PBHGetVInfo */ |
error = PBHGetVInfoSync((HParmBlkPtr)pb); |
if ( error == noErr ) |
{ |
/* calculate the ioVTotalBytes and ioVFreeBytes fields */ |
pb->ioVTotalBytes.hi = 0; |
pb->ioVTotalBytes.lo = pb->ioVNmAlBlks * pb->ioVAlBlkSiz; /* calculated total number of bytes on volume */ |
pb->ioVFreeBytes.hi = 0; |
pb->ioVFreeBytes.lo = pb->ioVFrBlk * pb->ioVAlBlkSiz; /* calculated number of free bytes on volume */ |
} |
} |
else |
#endif // !__MACOSSEVENFIVEONEORLATER |
{ |
/* Yes, so use it */ |
error = PBXGetVolInfoSync(pb); |
} |
pb->ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */ |
} |
else |
{ |
error = paramErr; |
} |
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 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 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, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */ |
| REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */ |
| REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr))) |
}; |
return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap), |
uppFSDispatchProcInfo, |
kXGetVolInfoSelector, |
_FSDispatch, |
paramBlock) ); |
} |
#endif |
#if __WANTPASCALELIMINATION |
#define pascal |
#endif |
/*****************************************************************************/ |
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 CheckVolLock(ConstStr255Param pathname, |
short vRefNum) |
{ |
HParamBlockRec pb; |
OSErr error; |
error = GetVolumeInfoNoName(pathname,vRefNum, &pb); |
if ( error == noErr ) |
{ |
if ( (pb.volumeParam.ioVAtrb & 0x0080) != 0 ) |
{ |
error = wPrErr; /* volume locked by hardware */ |
} |
else if ( (pb.volumeParam.ioVAtrb & 0x8000) != 0 ) |
{ |
error = vLckdErr; /* volume locked by software */ |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr GetDriverName(short driverRefNum, |
Str255 driverName) |
{ |
OSErr result; |
DCtlHandle theDctl; |
DRVRHeaderPtr dHeaderPtr; |
theDctl = GetDCtlEntry(driverRefNum); |
if ( theDctl != NULL ) |
{ |
if ( (**theDctl).dCtlFlags & 0x40 ) |
{ |
/* dctlDriver is handle - dereference */ |
dHeaderPtr = *((DRVRHeaderHandle)(**theDctl).dCtlDriver); |
} |
else |
{ |
/* dctlDriver is pointer */ |
dHeaderPtr = (DRVRHeaderPtr)(**theDctl).dCtlDriver; |
} |
BlockMoveData((*dHeaderPtr).drvrName, driverName, (*dHeaderPtr).drvrName[0] + 1); |
result = noErr; |
} |
else |
{ |
driverName[0] = 0; |
result = badUnitErr; /* bad reference number */ |
} |
return ( result ); |
} |
/*****************************************************************************/ |
pascal OSErr FindDrive(ConstStr255Param pathname, |
short vRefNum, |
DrvQElPtr *driveQElementPtr) |
{ |
OSErr result; |
HParamBlockRec hPB; |
short driveNumber; |
*driveQElementPtr = NULL; |
/* First, use GetVolumeInfoNoName to determine the volume */ |
result = GetVolumeInfoNoName(pathname, vRefNum, &hPB); |
if ( result == noErr ) |
{ |
/* |
** The volume can be either online, offline, or ejected. What we find in |
** ioVDrvInfo and ioVDRefNum will tell us which it is. |
** See Inside Macintosh: Files page 2-80 and the Technical Note |
** "FL 34 - VCBs and Drive Numbers : The Real Story" |
** Where we get the drive number depends on the state of the volume. |
*/ |
if ( hPB.volumeParam.ioVDrvInfo != 0 ) |
{ |
/* The volume is online and not ejected */ |
/* Get the drive number */ |
driveNumber = hPB.volumeParam.ioVDrvInfo; |
} |
else |
{ |
/* The volume's is either offline or ejected */ |
/* in either case, the volume is NOT online */ |
/* Is it ejected or just offline? */ |
if ( hPB.volumeParam.ioVDRefNum > 0 ) |
{ |
/* It's ejected, the drive number is ioVDRefNum */ |
driveNumber = hPB.volumeParam.ioVDRefNum; |
} |
else |
{ |
/* It's offline, the drive number is the negative of ioVDRefNum */ |
driveNumber = (short)-hPB.volumeParam.ioVDRefNum; |
} |
} |
/* Get pointer to first element in drive queue */ |
*driveQElementPtr = (DrvQElPtr)(GetDrvQHdr()->qHead); |
/* Search for a matching drive number */ |
while ( (*driveQElementPtr != NULL) && ((*driveQElementPtr)->dQDrive != driveNumber) ) |
{ |
*driveQElementPtr = (DrvQElPtr)(*driveQElementPtr)->qLink; |
} |
if ( *driveQElementPtr == NULL ) |
{ |
/* This should never happen since every volume must have a drive, but... */ |
result = nsDrvErr; |
} |
} |
return ( result ); |
} |
/*****************************************************************************/ |
pascal OSErr GetDiskBlocks(ConstStr255Param pathname, |
short vRefNum, |
unsigned long *numBlocks) |
{ |
/* Various constants for GetDiskBlocks() */ |
enum |
{ |
/* return format list status code */ |
kFmtLstCode = 6, |
/* reference number of .SONY driver */ |
kSonyRefNum = 0xfffb, |
/* values returned by DriveStatus in DrvSts.twoSideFmt */ |
kSingleSided = 0, |
kDoubleSided = -1, |
kSingleSidedSize = 800, /* 400K */ |
kDoubleSidedSize = 1600, /* 800K */ |
/* values in DrvQEl.qType */ |
kWordDrvSiz = 0, |
kLongDrvSiz = 1, |
/* more than enough formatListRecords */ |
kMaxFormatListRecs = 16 |
}; |
DrvQElPtr driveQElementPtr; |
unsigned long blocks; |
ParamBlockRec pb; |
FormatListRec formatListRecords[kMaxFormatListRecs]; |
DrvSts status; |
short formatListRecIndex; |
OSErr result; |
blocks = 0; |
/* Find the drive queue element for this volume */ |
result = FindDrive(pathname, vRefNum, &driveQElementPtr); |
/* |
** Make sure this is a real driver (dQRefNum < 0). |
** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause |
** problems if you try to use it as a driver refNum. |
*/ |
if ( (result == noErr) && (driveQElementPtr->dQRefNum >= 0) ) |
{ |
result = paramErr; |
} |
else |
{ |
/* Attempt to get the drive's format list. */ |
/* (see the Technical Note "What Your Sony Drives For You") */ |
pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive; |
pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum; |
pb.cntrlParam.csCode = kFmtLstCode; |
pb.cntrlParam.csParam[0] = kMaxFormatListRecs; |
*(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0]; |
result = PBStatusSync(&pb); |
if ( result == noErr ) |
{ |
/* The drive supports ReturnFormatList status call. */ |
/* Get the current disk's size. */ |
for( formatListRecIndex = 0; |
formatListRecIndex < pb.cntrlParam.csParam[0]; |
++formatListRecIndex ) |
{ |
if ( (formatListRecords[formatListRecIndex].formatFlags & |
diCIFmtFlagsCurrentMask) != 0 ) |
{ |
blocks = formatListRecords[formatListRecIndex].volSize; |
} |
} |
if ( blocks == 0 ) |
{ |
/* This should never happen */ |
result = paramErr; |
} |
} |
else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum ) |
{ |
/* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ |
result = DriveStatus(driveQElementPtr->dQDrive, &status); |
if ( result == noErr ) |
{ |
switch ( status.twoSideFmt ) |
{ |
case kSingleSided: |
blocks = kSingleSidedSize; |
break; |
case kDoubleSided: |
blocks = kDoubleSidedSize; |
break; |
default: |
/* This should never happen */ |
result = paramErr; |
break; |
} |
} |
} |
else |
{ |
/* The drive is not a floppy and it doesn't support ReturnFormatList */ |
/* so use the dQDrvSz field(s) */ |
result = noErr; /* reset result */ |
switch ( driveQElementPtr->qType ) |
{ |
case kWordDrvSiz: |
blocks = driveQElementPtr->dQDrvSz; |
break; |
case kLongDrvSiz: |
blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) + |
driveQElementPtr->dQDrvSz; |
break; |
default: |
/* This should never happen */ |
result = paramErr; |
break; |
} |
} |
} |
if ( result == noErr ) |
{ |
*numBlocks = blocks; |
} |
return ( result ); |
} |
/*****************************************************************************/ |
pascal OSErr GetVolFileSystemID(ConstStr255Param pathname, |
short vRefNum, |
short *fileSystemID) |
{ |
HParamBlockRec pb; |
OSErr error; |
error = GetVolumeInfoNoName(pathname,vRefNum, &pb); |
if ( error == noErr ) |
{ |
*fileSystemID = pb.volumeParam.ioVFSID; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr GetVolState(ConstStr255Param pathname, |
short vRefNum, |
Boolean *volumeOnline, |
Boolean *volumeEjected, |
Boolean *driveEjectable, |
Boolean *driverWantsEject) |
{ |
HParamBlockRec pb; |
short driveNumber; |
OSErr error; |
error = GetVolumeInfoNoName(pathname,vRefNum, &pb); |
if ( error == noErr ) |
{ |
if ( pb.volumeParam.ioVDrvInfo != 0 ) |
{ |
/* the volume is online and not ejected */ |
*volumeOnline = true; |
*volumeEjected = false; |
/* Get the drive number */ |
driveNumber = pb.volumeParam.ioVDrvInfo; |
} |
else |
{ |
/* the volume's is either offline or ejected */ |
/* in either case, the volume is NOT online */ |
*volumeOnline = false; |
/* Is it ejected? */ |
*volumeEjected = pb.volumeParam.ioVDRefNum > 0; |
if ( *volumeEjected ) |
{ |
/* If ejected, the drive number is ioVDRefNum */ |
driveNumber = pb.volumeParam.ioVDRefNum; |
} |
else |
{ |
/* If offline, the drive number is the negative of ioVDRefNum */ |
driveNumber = (short)-pb.volumeParam.ioVDRefNum; |
} |
} |
{ |
DrvQElPtr drvQElem; |
/* Find the drive queue element by searching the drive queue */ |
drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead); |
while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNumber) ) |
{ |
drvQElem = (DrvQElPtr)drvQElem->qLink; |
} |
if ( drvQElem != NULL ) |
{ |
/* |
** Each drive queue element is preceded by 4 flag bytes. |
** Byte 1 (the second flag byte) has bits that tell us if a |
** drive is ejectable and if its driver wants an eject call. |
** See Inside Macintosh: Files, page 2-85. |
*/ |
{ |
Ptr flagBytePtr; |
/* point to byte 1 of the flag bytes */ |
flagBytePtr = (Ptr)drvQElem; |
flagBytePtr -= 3; |
/* |
** The drive is ejectable if flag byte 1 does not contain |
** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call). |
*/ |
*driveEjectable = (*flagBytePtr != 0x08) && (*flagBytePtr != 0x48); |
/* |
** The driver wants an eject call if flag byte 1 does not contain |
** 0x08 (nonejectable). This may seem like a minor point, but some |
** disk drivers use the Eject request to flush their caches to disk |
** and you wouldn't want to skip that step after unmounting a volume. |
*/ |
*driverWantsEject = (*flagBytePtr != 0x08); |
} |
} |
else |
{ |
/* Didn't find the drive (this should never happen) */ |
*driveEjectable = false; |
*driverWantsEject = false; |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr UnmountAndEject(ConstStr255Param pathname, |
short vRefNum) |
{ |
HParamBlockRec pb; |
short driveNum; |
Boolean ejected, wantsEject; |
DrvQElPtr drvQElem; |
OSErr error; |
error = GetVolumeInfoNoName(pathname, vRefNum, &pb); |
if ( error == noErr ) |
{ |
if ( pb.volumeParam.ioVDrvInfo != 0 ) |
{ |
/* the volume is online and not ejected */ |
ejected = false; |
/* Get the drive number */ |
driveNum = pb.volumeParam.ioVDrvInfo; |
} |
else |
{ |
/* the volume is ejected or offline */ |
/* Is it ejected? */ |
ejected = pb.volumeParam.ioVDRefNum > 0; |
if ( ejected ) |
{ |
/* If ejected, the drive number is ioVDRefNum */ |
driveNum = pb.volumeParam.ioVDRefNum; |
} |
else |
{ |
/* If offline, the drive number is the negative of ioVDRefNum */ |
driveNum = (short)-pb.volumeParam.ioVDRefNum; |
} |
} |
/* find the drive queue element */ |
drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead); |
while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNum) ) |
{ |
drvQElem = (DrvQElPtr)drvQElem->qLink; |
} |
if ( drvQElem != NULL ) |
{ |
/* does the drive want an eject call */ |
wantsEject = (*((Ptr)((Ptr)drvQElem - 3)) != 8); |
} |
else |
{ |
/* didn't find the drive!! */ |
wantsEject = false; |
} |
/* unmount the volume */ |
pb.volumeParam.ioNamePtr = NULL; |
/* ioVRefNum is already filled in from PBHGetVInfo */ |
error = PBUnmountVol((ParmBlkPtr)&pb); |
if ( error == noErr ) |
{ |
if ( wantsEject && !ejected ) |
{ |
/* eject the media from the drive if needed */ |
pb.volumeParam.ioVRefNum = driveNum; |
error = PBEject((ParmBlkPtr)&pb); |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
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 SetDefault(short newVRefNum, |
long newDirID, |
short *oldVRefNum, |
long *oldDirID) |
{ |
OSErr error; |
/* Get the current default volume/directory. */ |
error = HGetVol(NULL, oldVRefNum, oldDirID); |
if ( error == noErr ) |
{ |
/* Set the new default volume/directory */ |
error = HSetVol(NULL, newVRefNum, newDirID); |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr RestoreDefault(short oldVRefNum, |
long oldDirID) |
{ |
OSErr error; |
short defaultVRefNum; |
long defaultDirID; |
long defaultProcID; |
/* Determine if the default volume was a wdRefNum. */ |
error = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID); |
if ( error == noErr ) |
{ |
/* Restore the old default volume/directory, one way or the other. */ |
if ( defaultDirID != fsRtDirID ) |
{ |
/* oldVRefNum was a wdRefNum - use SetVol */ |
error = SetVol(NULL, oldVRefNum); |
} |
else |
{ |
/* oldVRefNum was a real vRefNum - use HSetVol */ |
error = HSetVol(NULL, oldVRefNum, oldDirID); |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr GetDInfo(short vRefNum, |
long dirID, |
ConstStr255Param name, |
DInfo *fndrInfo) |
{ |
CInfoPBRec pb; |
OSErr error; |
error = GetCatInfoNoName(vRefNum, dirID, name, &pb); |
if ( error == noErr ) |
{ |
if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 ) |
{ |
/* it's a directory, return the DInfo */ |
*fndrInfo = pb.dirInfo.ioDrUsrWds; |
} |
else |
{ |
/* oops, a file was passed */ |
error = dirNFErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpGetDInfo(const FSSpec *spec, |
DInfo *fndrInfo) |
{ |
return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) ); |
} |
/*****************************************************************************/ |
pascal OSErr SetDInfo(short vRefNum, |
long dirID, |
ConstStr255Param name, |
const DInfo *fndrInfo) |
{ |
CInfoPBRec 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); |
if ( error == noErr ) |
{ |
if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 ) |
{ |
/* it's a directory, set the DInfo */ |
if ( pb.dirInfo.ioNamePtr == tempName ) |
{ |
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; |
} |
else |
{ |
pb.dirInfo.ioDrDirID = dirID; |
} |
pb.dirInfo.ioDrUsrWds = *fndrInfo; |
error = PBSetCatInfoSync(&pb); |
} |
else |
{ |
/* oops, a file was passed */ |
error = dirNFErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpSetDInfo(const FSSpec *spec, |
const DInfo *fndrInfo) |
{ |
return ( SetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) ); |
} |
/*****************************************************************************/ |
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 FSpGetDirectoryID(const FSSpec *spec, |
long *theDirID, |
Boolean *isDirectory) |
{ |
return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name, |
theDirID, isDirectory) ); |
} |
/*****************************************************************************/ |
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 ); |
} |
/*****************************************************************************/ |
pascal OSErr GetIOACUser(short vRefNum, |
long dirID, |
ConstStr255Param name, |
SInt8 *ioACUser) |
{ |
CInfoPBRec pb; |
OSErr error; |
/* Clear ioACUser before calling PBGetCatInfo since some file systems |
** don't bother to set or clear this field. If ioACUser isn't set by the |
** file system, then you'll get the zero value back (full access) which |
** is the access you have on volumes that don't support ioACUser. |
*/ |
pb.dirInfo.ioACUser = 0; /* ioACUser used to be filler2 */ |
error = GetCatInfoNoName(vRefNum, dirID, name, &pb); |
if ( error == noErr ) |
{ |
if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) |
{ |
/* oops, a file was passed */ |
error = dirNFErr; |
} |
else |
{ |
*ioACUser = pb.dirInfo.ioACUser; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpGetIOACUser(const FSSpec *spec, |
SInt8 *ioACUser) |
{ |
return ( GetIOACUser(spec->vRefNum, spec->parID, spec->name, ioACUser) ); |
} |
/*****************************************************************************/ |
pascal OSErr GetParentID(short vRefNum, |
long dirID, |
ConstStr255Param name, |
long *parID) |
{ |
CInfoPBRec pb; |
Str31 tempName; |
OSErr error; |
short realVRefNum; |
/* 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 ) |
{ |
/* |
** There's a bug in HFS where the wrong parent dir ID can be |
** returned if multiple separators are used at the end of a |
** pathname. For example, if the pathname: |
** 'volumeName:System Folder:Extensions::' |
** is passed, the directory ID of the Extensions folder is |
** returned in the ioFlParID field instead of fsRtDirID. Since |
** multiple separators at the end of a pathname always specifies |
** a directory, we only need to work-around cases where the |
** object is a directory and there are multiple separators at |
** the end of the name parameter. |
*/ |
if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) |
{ |
/* Its a directory */ |
/* is there a pathname? */ |
if ( pb.hFileInfo.ioNamePtr == name ) |
{ |
/* could it contain multiple separators? */ |
if ( name[0] >= 2 ) |
{ |
/* does it contain multiple separators at the end? */ |
if ( (name[name[0]] == ':') && (name[name[0] - 1] == ':') ) |
{ |
/* OK, then do the extra stuff to get the correct parID */ |
/* Get the real vRefNum (this should not fail) */ |
error = DetermineVRefNum(name, vRefNum, &realVRefNum); |
if ( error == noErr ) |
{ |
/* we don't need the parent's name, but add protect against File Sharing problem */ |
tempName[0] = 0; |
pb.dirInfo.ioNamePtr = tempName; |
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); |
/* now, pb.dirInfo.ioDrParID contains the correct parID */ |
} |
} |
} |
} |
} |
if ( error == noErr ) |
{ |
/* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */ |
/* contains the parent ID */ |
*parID = pb.hFileInfo.ioFlParID; |
} |
} |
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 ); |
} |
/*****************************************************************************/ |
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 GetDirItems(short vRefNum, |
long dirID, |
ConstStr255Param name, |
Boolean getFiles, |
Boolean getDirectories, |
FSSpecPtr items, |
short reqItemCount, |
short *actItemCount, |
short *itemIndex) /* start with 1, then use what's returned */ |
{ |
CInfoPBRec pb; |
OSErr error; |
long theDirID; |
Boolean isDirectory; |
FSSpec *endItemsArray; |
if ( *itemIndex > 0 ) |
{ |
/* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */ |
/* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */ |
/* routine would be much faster because of the overhead of DetermineVRefNum and */ |
/* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */ |
/* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */ |
/* pass a big array of FSSpecs so you can get the directory's contents with few calls */ |
/* to this routine. */ |
/* get the real volume reference number */ |
error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum); |
if ( error == noErr ) |
{ |
/* and the real directory ID of this directory (and make sure it IS a directory) */ |
error = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory); |
if ( error == noErr ) |
{ |
if ( isDirectory ) |
{ |
*actItemCount = 0; |
endItemsArray = items + reqItemCount; |
while ( (items < endItemsArray) && (error == noErr) ) |
{ |
pb.hFileInfo.ioNamePtr = (StringPtr) &items->name; |
pb.hFileInfo.ioDirID = theDirID; |
pb.hFileInfo.ioFDirIndex = *itemIndex; |
error = PBGetCatInfoSync(&pb); |
if ( error == noErr ) |
{ |
items->parID = pb.hFileInfo.ioFlParID; /* return item's parID */ |
items->vRefNum = pb.hFileInfo.ioVRefNum; /* return item's vRefNum */ |
++*itemIndex; /* prepare to get next item in directory */ |
if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) |
{ |
if ( getDirectories ) |
{ |
++*actItemCount; /* keep this item */ |
++items; /* point to next item */ |
} |
} |
else |
{ |
if ( getFiles ) |
{ |
++*actItemCount; /* keep this item */ |
++items; /* point to next item */ |
} |
} |
} |
} |
} |
else |
{ |
/* it wasn't a directory */ |
error = dirNFErr; |
} |
} |
} |
} |
else |
{ |
/* bad itemIndex */ |
error = paramErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
static void DeleteLevel(long dirToDelete, |
DeleteEnumGlobalsPtr theGlobals) |
{ |
long savedDir; |
do |
{ |
/* prepare to delete directory */ |
theGlobals->myPB.ciPB.dirInfo.ioNamePtr = (StringPtr)&theGlobals->itemName; |
theGlobals->myPB.ciPB.dirInfo.ioFDirIndex = 1; /* get first item */ |
theGlobals->myPB.ciPB.dirInfo.ioDrDirID = dirToDelete; /* in this directory */ |
theGlobals->error = PBGetCatInfoSync(&(theGlobals->myPB.ciPB)); |
if ( theGlobals->error == noErr ) |
{ |
savedDir = dirToDelete; |
/* We have an item. Is it a file or directory? */ |
if ( (theGlobals->myPB.ciPB.dirInfo.ioFlAttrib & ioDirMask) != 0 ) |
{ |
/* it's a directory */ |
savedDir = theGlobals->myPB.ciPB.dirInfo.ioDrDirID; /* save dirID of directory instead */ |
DeleteLevel(theGlobals->myPB.ciPB.dirInfo.ioDrDirID, theGlobals); /* Delete its contents */ |
theGlobals->myPB.ciPB.dirInfo.ioNamePtr = NULL; /* prepare to delete directory */ |
} |
if ( theGlobals->error == noErr ) |
{ |
theGlobals->myPB.ciPB.dirInfo.ioDrDirID = savedDir; /* restore dirID */ |
theGlobals->myPB.hPB.fileParam.ioFVersNum = 0; /* just in case it's used on an MFS volume... */ |
theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* delete this item */ |
if ( theGlobals->error == fLckdErr ) |
{ |
(void) PBHRstFLockSync(&(theGlobals->myPB.hPB)); /* unlock it */ |
theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* and try again */ |
} |
} |
} |
} while ( theGlobals->error == noErr ); |
if ( theGlobals->error == fnfErr ) |
{ |
theGlobals->error = noErr; |
} |
} |
/*****************************************************************************/ |
pascal OSErr DeleteDirectoryContents(short vRefNum, |
long dirID, |
ConstStr255Param name) |
{ |
DeleteEnumGlobals theGlobals; |
Boolean isDirectory; |
OSErr error; |
/* Get the real dirID and make sure it is a directory. */ |
error = GetDirectoryID(vRefNum, dirID, name, &dirID, &isDirectory); |
if ( error == noErr ) |
{ |
if ( isDirectory ) |
{ |
/* Get the real vRefNum */ |
error = DetermineVRefNum(name, vRefNum, &vRefNum); |
if ( error == noErr ) |
{ |
/* Set up the globals we need to access from the recursive routine. */ |
theGlobals.myPB.ciPB.dirInfo.ioVRefNum = vRefNum; |
/* Here we go into recursion land... */ |
DeleteLevel(dirID, &theGlobals); |
error = theGlobals.error; |
} |
} |
else |
{ |
error = dirNFErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DeleteDirectory(short vRefNum, |
long dirID, |
ConstStr255Param name) |
{ |
OSErr error; |
/* Make sure a directory was specified and then delete its contents */ |
error = DeleteDirectoryContents(vRefNum, dirID, name); |
if ( error == noErr ) |
{ |
error = HDelete(vRefNum, dirID, name); |
if ( error == fLckdErr ) |
{ |
(void) HRstFLock(vRefNum, dirID, name); /* unlock the directory locked by AppleShare */ |
error = HDelete(vRefNum, dirID, name); /* and try again */ |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr CheckObjectLock(short vRefNum, |
long dirID, |
ConstStr255Param name) |
{ |
CInfoPBRec pb; |
OSErr error; |
error = GetCatInfoNoName(vRefNum, dirID, name, &pb); |
if ( error == noErr ) |
{ |
/* check locked bit */ |
if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 ) |
{ |
error = fLckdErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpCheckObjectLock(const FSSpec *spec) |
{ |
return ( CheckObjectLock(spec->vRefNum, spec->parID, spec->name) ); |
} |
/*****************************************************************************/ |
pascal OSErr GetFileSize(short vRefNum, |
long dirID, |
ConstStr255Param fileName, |
long *dataSize, |
long *rsrcSize) |
{ |
HParamBlockRec pb; |
OSErr error; |
pb.fileParam.ioNamePtr = (StringPtr)fileName; |
pb.fileParam.ioVRefNum = vRefNum; |
pb.fileParam.ioFVersNum = 0; |
pb.fileParam.ioDirID = dirID; |
pb.fileParam.ioFDirIndex = 0; |
error = PBHGetFInfoSync(&pb); |
if ( error == noErr ) |
{ |
*dataSize = pb.fileParam.ioFlLgLen; |
*rsrcSize = pb.fileParam.ioFlRLgLen; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpGetFileSize(const FSSpec *spec, |
long *dataSize, |
long *rsrcSize) |
{ |
return ( GetFileSize(spec->vRefNum, spec->parID, spec->name, dataSize, rsrcSize) ); |
} |
/*****************************************************************************/ |
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 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 */ |
{ |
parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */ |
/* 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 ChangeFDFlags(short vRefNum, |
long dirID, |
ConstStr255Param name, |
Boolean setBits, |
unsigned short flagBits) |
{ |
CInfoPBRec pb; |
Str31 tempName; |
OSErr error; |
short realVRefNum; |
long parID; |
/* 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 ) |
{ |
parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */ |
/* set or clear the appropriate bits in the Finder flags */ |
if ( setBits ) |
{ |
/* OR in the bits */ |
pb.hFileInfo.ioFlFndrInfo.fdFlags |= flagBits; |
} |
else |
{ |
/* AND out the bits */ |
pb.hFileInfo.ioFlFndrInfo.fdFlags &= ~flagBits; |
} |
if ( pb.dirInfo.ioNamePtr == tempName ) |
{ |
pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID; |
} |
else |
{ |
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 */ |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpChangeFDFlags(const FSSpec *spec, |
Boolean setBits, |
unsigned short flagBits) |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, setBits, flagBits) ); |
} |
/*****************************************************************************/ |
pascal OSErr SetIsInvisible(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, make it invisible. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsInvisible) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpSetIsInvisible(const FSSpec *spec) |
/* Given a file or directory, make it invisible. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsInvisible) ); |
} |
/*****************************************************************************/ |
pascal OSErr ClearIsInvisible(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, make it visible. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsInvisible) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpClearIsInvisible(const FSSpec *spec) |
/* Given a file or directory, make it visible. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsInvisible) ); |
} |
/*****************************************************************************/ |
pascal OSErr SetNameLocked(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, lock its name. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, true, kNameLocked) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpSetNameLocked(const FSSpec *spec) |
/* Given a file or directory, lock its name. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kNameLocked) ); |
} |
/*****************************************************************************/ |
pascal OSErr ClearNameLocked(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, unlock its name. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, false, kNameLocked) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpClearNameLocked(const FSSpec *spec) |
/* Given a file or directory, unlock its name. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kNameLocked) ); |
} |
/*****************************************************************************/ |
pascal OSErr SetIsStationery(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file, make it a stationery pad. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsStationery) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpSetIsStationery(const FSSpec *spec) |
/* Given a file, make it a stationery pad. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsStationery) ); |
} |
/*****************************************************************************/ |
pascal OSErr ClearIsStationery(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file, clear the stationery bit. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsStationery) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpClearIsStationery(const FSSpec *spec) |
/* Given a file, clear the stationery bit. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsStationery) ); |
} |
/*****************************************************************************/ |
pascal OSErr SetHasCustomIcon(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, indicate that it has a custom icon. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, true, kHasCustomIcon) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpSetHasCustomIcon(const FSSpec *spec) |
/* Given a file or directory, indicate that it has a custom icon. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kHasCustomIcon) ); |
} |
/*****************************************************************************/ |
pascal OSErr ClearHasCustomIcon(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file or directory, indicate that it does not have a custom icon. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasCustomIcon) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpClearHasCustomIcon(const FSSpec *spec) |
/* Given a file or directory, indicate that it does not have a custom icon. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasCustomIcon) ); |
} |
/*****************************************************************************/ |
pascal OSErr ClearHasBeenInited(short vRefNum, |
long dirID, |
ConstStr255Param name) |
/* Given a file, clear its "has been inited" bit. */ |
{ |
return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasBeenInited) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpClearHasBeenInited(const FSSpec *spec) |
/* Given a file, clear its "has been inited" bit. */ |
{ |
return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasBeenInited) ); |
} |
/*****************************************************************************/ |
pascal OSErr CopyFileMgrAttributes(short srcVRefNum, |
long srcDirID, |
ConstStr255Param srcName, |
short dstVRefNum, |
long dstDirID, |
ConstStr255Param dstName, |
Boolean copyLockBit) |
{ |
UniversalFMPB pb; |
Str31 tempName; |
OSErr error; |
Boolean objectIsDirectory; |
pb.ciPB.hFileInfo.ioVRefNum = srcVRefNum; |
pb.ciPB.hFileInfo.ioDirID = srcDirID; |
/* Protection against File Sharing problem */ |
if ( (srcName == NULL) || (srcName[0] == 0) ) |
{ |
tempName[0] = 0; |
pb.ciPB.hFileInfo.ioNamePtr = tempName; |
pb.ciPB.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ |
} |
else |
{ |
pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)srcName; |
pb.ciPB.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ |
} |
error = PBGetCatInfoSync(&pb.ciPB); |
if ( error == noErr ) |
{ |
objectIsDirectory = ( (pb.ciPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 ); |
pb.ciPB.hFileInfo.ioVRefNum = dstVRefNum; |
pb.ciPB.hFileInfo.ioDirID = dstDirID; |
if ( (dstName != NULL) && (dstName[0] == 0) ) |
{ |
pb.ciPB.hFileInfo.ioNamePtr = NULL; |
} |
else |
{ |
pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)dstName; |
} |
/* don't copy the hasBeenInited bit */ |
pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags = ( pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags & 0xfeff ); |
error = PBSetCatInfoSync(&pb.ciPB); |
if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & 0x01) != 0) ) |
{ |
pb.hPB.fileParam.ioFVersNum = 0; |
error = PBHSetFLockSync(&pb.hPB); |
if ( (error != noErr) && (objectIsDirectory) ) |
{ |
error = noErr; /* ignore lock errors if destination is directory */ |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpCopyFileMgrAttributes(const FSSpec *srcSpec, |
const FSSpec *dstSpec, |
Boolean copyLockBit) |
{ |
return ( CopyFileMgrAttributes(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, |
dstSpec->vRefNum, dstSpec->parID, dstSpec->name, |
copyLockBit) ); |
} |
/*****************************************************************************/ |
pascal OSErr HOpenAware(short vRefNum, |
long dirID, |
ConstStr255Param fileName, |
short denyModes, |
short *refNum) |
{ |
HParamBlockRec pb; |
OSErr error; |
GetVolParmsInfoBuffer volParmsInfo; |
long infoSize = sizeof(GetVolParmsInfoBuffer); |
pb.ioParam.ioMisc = NULL; |
pb.fileParam.ioFVersNum = 0; |
pb.fileParam.ioNamePtr = (StringPtr)fileName; |
pb.fileParam.ioVRefNum = vRefNum; |
pb.fileParam.ioDirID = dirID; |
/* get volume attributes */ |
/* this preflighting is needed because Foreign File Access based file systems don't */ |
/* return the correct error result to the OpenDeny call */ |
error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize); |
if ( (error == noErr) && hasOpenDeny(volParmsInfo) ) |
{ |
/* if volume supports OpenDeny, use it and return */ |
pb.accessParam.ioDenyModes = denyModes; |
error = PBHOpenDenySync(&pb); |
*refNum = pb.ioParam.ioRefNum; |
} |
else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ |
{ |
/* OpenDeny isn't supported, so try File Manager Open functions */ |
/* If request includes write permission, then see if the volume is */ |
/* locked by hardware or software. The HFS file system doesn't check */ |
/* for this when a file is opened - you only find out later when you */ |
/* try to write and the write fails with a wPrErr or a vLckdErr. */ |
if ( (denyModes & dmWr) != 0 ) |
{ |
error = CheckVolLock(fileName, vRefNum); |
} |
else |
{ |
error = noErr; |
} |
if ( error == noErr ) |
{ |
/* Set File Manager permissions to closest thing possible */ |
if ( (denyModes == dmWr) || (denyModes == dmRdWr) ) |
{ |
pb.ioParam.ioPermssn = fsRdWrShPerm; |
} |
else |
{ |
pb.ioParam.ioPermssn = denyModes % 4; |
} |
error = PBHOpenDFSync(&pb); /* Try OpenDF */ |
if ( error == paramErr ) |
{ |
error = PBHOpenSync(&pb); /* OpenDF not supported, so try Open */ |
} |
*refNum = pb.ioParam.ioRefNum; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpOpenAware(const FSSpec *spec, |
short denyModes, |
short *refNum) |
{ |
return ( HOpenAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) ); |
} |
/*****************************************************************************/ |
pascal OSErr HOpenRFAware(short vRefNum, |
long dirID, |
ConstStr255Param fileName, |
short denyModes, |
short *refNum) |
{ |
HParamBlockRec pb; |
OSErr error; |
GetVolParmsInfoBuffer volParmsInfo; |
long infoSize = sizeof(GetVolParmsInfoBuffer); |
pb.ioParam.ioMisc = NULL; |
pb.fileParam.ioFVersNum = 0; |
pb.fileParam.ioNamePtr = (StringPtr)fileName; |
pb.fileParam.ioVRefNum = vRefNum; |
pb.fileParam.ioDirID = dirID; |
/* get volume attributes */ |
/* this preflighting is needed because Foreign File Access based file systems don't */ |
/* return the correct error result to the OpenRFDeny call */ |
error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize); |
if ( (error == noErr) && hasOpenDeny(volParmsInfo) ) |
{ |
/* if volume supports OpenRFDeny, use it and return */ |
if ( hasOpenDeny(volParmsInfo) ) |
{ |
pb.accessParam.ioDenyModes = denyModes; |
error = PBHOpenRFDenySync(&pb); |
*refNum = pb.ioParam.ioRefNum; |
} |
} |
else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ |
{ |
/* OpenRFDeny isn't supported, so try File Manager OpenRF function */ |
/* If request includes write permission, then see if the volume is */ |
/* locked by hardware or software. The HFS file system doesn't check */ |
/* for this when a file is opened - you only find out later when you */ |
/* try to write and the write fails with a wPrErr or a vLckdErr. */ |
if ( (denyModes & dmWr) != 0 ) |
{ |
error = CheckVolLock(fileName, vRefNum); |
} |
else |
{ |
error = noErr; |
} |
if ( error == noErr ) |
{ |
/* Set File Manager permissions to closest thing possible */ |
if ( (denyModes == dmWr) || (denyModes == dmRdWr) ) |
{ |
pb.ioParam.ioPermssn = fsRdWrShPerm; |
} |
else |
{ |
pb.ioParam.ioPermssn = denyModes % 4; |
} |
error = PBHOpenRFSync(&pb); |
*refNum = pb.ioParam.ioRefNum; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpOpenRFAware(const FSSpec *spec, |
short denyModes, |
short *refNum) |
{ |
return ( HOpenRFAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSReadNoCache(short refNum, |
long *count, |
void *buffPtr) |
{ |
ParamBlockRec pb; |
OSErr error; |
pb.ioParam.ioRefNum = refNum; |
pb.ioParam.ioBuffer = (Ptr)buffPtr; |
pb.ioParam.ioReqCount = *count; |
pb.ioParam.ioPosMode = fsAtMark + 0x0020; /* fsAtMark + noCacheBit */ |
pb.ioParam.ioPosOffset = 0; |
error = PBReadSync(&pb); |
*count = pb.ioParam.ioActCount; /* always return count */ |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSWriteNoCache(short refNum, |
long *count, |
const void *buffPtr) |
{ |
ParamBlockRec pb; |
OSErr error; |
pb.ioParam.ioRefNum = refNum; |
pb.ioParam.ioBuffer = (Ptr)buffPtr; |
pb.ioParam.ioReqCount = *count; |
pb.ioParam.ioPosMode = fsAtMark + 0x0020; /* fsAtMark + noCacheBit */ |
pb.ioParam.ioPosOffset = 0; |
error = PBWriteSync(&pb); |
*count = pb.ioParam.ioActCount; /* always return count */ |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** See if numBytes bytes of buffer1 are equal to buffer2. |
*/ |
static Boolean EqualMemory(const void *buffer1, const void *buffer2, unsigned long numBytes) |
{ |
register unsigned char *b1 = (unsigned char *)buffer1; |
register unsigned char *b2 = (unsigned char *)buffer2; |
if ( b1 != b2 ) /* if buffer pointers are same, then they are equal */ |
{ |
while ( numBytes > 0 ) |
{ |
/* compare the bytes and then increment the pointers */ |
if ( (*b1++ - *b2++) != 0 ) |
{ |
return ( false ); |
} |
--numBytes; |
} |
} |
return ( true ); |
} |
/*****************************************************************************/ |
/* |
** Read any number of bytes from an open file using read-verify mode. |
** The FSReadVerify function reads any number of bytes from an open file |
** and verifies them against the data in the buffer pointed to by buffPtr. |
** |
** Because of a bug in the HFS file system, only non-block aligned parts of |
** the read are verified against the buffer data and the rest is *copied* |
** into the buffer. Thus, you shouldn't verify against your original data; |
** instead, you should verify against a copy of the original data and then |
** compare the read-verified copy against the original data after calling |
** FSReadVerify. That's why this function isn't exported - it needs the |
** wrapper provided by FSWriteVerify. |
*/ |
static OSErr FSReadVerify(short refNum, |
long *count, |
void *buffPtr) |
{ |
ParamBlockRec pb; |
OSErr result; |
pb.ioParam.ioRefNum = refNum; |
pb.ioParam.ioBuffer = (Ptr)buffPtr; |
pb.ioParam.ioReqCount = *count; |
pb.ioParam.ioPosMode = fsAtMark + rdVerify; |
pb.ioParam.ioPosOffset = 0; |
result = PBReadSync(&pb); |
*count = pb.ioParam.ioActCount; /* always return count */ |
return ( result ); |
} |
/*****************************************************************************/ |
pascal OSErr FSWriteVerify(short refNum, |
long *count, |
const void *buffPtr) |
{ |
Ptr verifyBuffer; |
long position; |
long bufferSize; |
long byteCount; |
long bytesVerified; |
Ptr startVerify; |
OSErr result; |
/* |
** Allocate the verify buffer |
** Try to get get a large enough buffer to verify in one pass. |
** If that fails, use GetTempBuffer to get a buffer. |
*/ |
bufferSize = *count; |
verifyBuffer = NewPtr(bufferSize); |
if ( verifyBuffer == NULL ) |
{ |
verifyBuffer = GetTempBuffer(bufferSize, &bufferSize); |
} |
if ( verifyBuffer != NULL ) |
{ |
/* Save the current position */ |
result = GetFPos(refNum, &position); |
if ( result == noErr ) |
{ |
/* Write the data */ |
result = FSWrite(refNum, count, buffPtr); |
if ( result == noErr ) |
{ |
/* Restore the original position */ |
result = SetFPos(refNum, fsFromStart, position); |
if ( result == noErr ) |
{ |
/* |
** *count = total number of bytes to verify |
** bufferSize = the size of the verify buffer |
** bytesVerified = number of bytes verified |
** byteCount = number of bytes to verify this pass |
** startVerify = position in buffPtr |
*/ |
bytesVerified = 0; |
startVerify = (Ptr)buffPtr; |
while ( (bytesVerified < *count) && ( result == noErr ) ) |
{ |
if ( (*count - bytesVerified) > bufferSize ) |
{ |
byteCount = bufferSize; |
} |
else |
{ |
byteCount = *count - bytesVerified; |
} |
/* |
** Copy the write buffer into the verify buffer. |
** This step is needed because the File Manager |
** compares the data in any non-block aligned |
** data at the beginning and end of the read-verify |
** request back into the file system's cache |
** to the data in verify Buffer. However, the |
** File Manager does not compare any full blocks |
** and instead copies them into the verify buffer |
** so we still have to compare the buffers again |
** after the read-verify request completes. |
*/ |
BlockMoveData(startVerify, verifyBuffer, byteCount); |
/* Read-verify the data back into the verify buffer */ |
result = FSReadVerify(refNum, &byteCount, verifyBuffer); |
if ( result == noErr ) |
{ |
/* See if the buffers are the same */ |
if ( !EqualMemory(verifyBuffer, startVerify, byteCount) ) |
{ |
result = ioErr; |
} |
startVerify += byteCount; |
bytesVerified += byteCount; |
} |
} |
} |
} |
} |
DisposePtr(verifyBuffer); |
} |
else |
{ |
result = memFullErr; |
} |
return ( result ); |
} |
/*****************************************************************************/ |
pascal OSErr CopyFork(short srcRefNum, |
short dstRefNum, |
void *copyBufferPtr, |
long copyBufferSize) |
{ |
ParamBlockRec srcPB; |
ParamBlockRec dstPB; |
OSErr srcError; |
OSErr dstError; |
if ( (copyBufferPtr == NULL) || (copyBufferSize == 0) ) |
return ( paramErr ); |
srcPB.ioParam.ioRefNum = srcRefNum; |
dstPB.ioParam.ioRefNum = dstRefNum; |
/* preallocate the destination fork and */ |
/* ensure the destination fork's EOF is correct after the copy */ |
srcError = PBGetEOFSync(&srcPB); |
if ( srcError != noErr ) |
return ( srcError ); |
dstPB.ioParam.ioMisc = srcPB.ioParam.ioMisc; |
dstError = PBSetEOFSync(&dstPB); |
if ( dstError != noErr ) |
return ( dstError ); |
/* reset source fork's mark */ |
srcPB.ioParam.ioPosMode = fsFromStart; |
srcPB.ioParam.ioPosOffset = 0; |
srcError = PBSetFPosSync(&srcPB); |
if ( srcError != noErr ) |
return ( srcError ); |
/* reset destination fork's mark */ |
dstPB.ioParam.ioPosMode = fsFromStart; |
dstPB.ioParam.ioPosOffset = 0; |
dstError = PBSetFPosSync(&dstPB); |
if ( dstError != noErr ) |
return ( dstError ); |
/* set up fields that won't change in the loop */ |
srcPB.ioParam.ioBuffer = (Ptr)copyBufferPtr; |
srcPB.ioParam.ioPosMode = fsAtMark + 0x0020;/* fsAtMark + noCacheBit */ |
/* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */ |
/* This will make writes on local volumes faster */ |
if ( (copyBufferSize >= 512) && ((copyBufferSize & 0x1ff) != 0) ) |
{ |
srcPB.ioParam.ioReqCount = copyBufferSize & 0xfffffe00; |
} |
else |
{ |
srcPB.ioParam.ioReqCount = copyBufferSize; |
} |
dstPB.ioParam.ioBuffer = (Ptr)copyBufferPtr; |
dstPB.ioParam.ioPosMode = fsAtMark + 0x0020;/* fsAtMark + noCacheBit */ |
while ( (srcError == noErr) && (dstError == noErr) ) |
{ |
srcError = PBReadSync(&srcPB); |
dstPB.ioParam.ioReqCount = srcPB.ioParam.ioActCount; |
dstError = PBWriteSync(&dstPB); |
} |
/* make sure there were no errors at the destination */ |
if ( dstError != noErr ) |
return ( dstError ); |
/* make sure the only error at the source was eofErr */ |
if ( srcError != eofErr ) |
return ( srcError ); |
return ( noErr ); |
} |
/*****************************************************************************/ |
pascal OSErr GetFileLocation(short refNum, |
short *vRefNum, |
long *dirID, |
StringPtr fileName) |
{ |
FCBPBRec pb; |
OSErr error; |
pb.ioNamePtr = fileName; |
pb.ioVRefNum = 0; |
pb.ioRefNum = refNum; |
pb.ioFCBIndx = 0; |
error = PBGetFCBInfoSync(&pb); |
if ( error == noErr ) |
{ |
*vRefNum = pb.ioFCBVRefNum; |
*dirID = pb.ioFCBParID; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpGetFileLocation(short refNum, |
FSSpec *spec) |
{ |
return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) ); |
} |
/*****************************************************************************/ |
pascal OSErr CopyDirectoryAccess(short srcVRefNum, |
long srcDirID, |
ConstStr255Param srcName, |
short dstVRefNum, |
long dstDirID, |
ConstStr255Param dstName) |
{ |
OSErr error; |
GetVolParmsInfoBuffer infoBuffer; /* Where PBGetVolParms dumps its info */ |
long dstServerAdr; /* AppleTalk server address of destination (if any) */ |
long ownerID, groupID, accessRights; |
long tempLong; |
/* See if destination supports directory access control */ |
tempLong = sizeof(infoBuffer); |
error = HGetVolParms(dstName, dstVRefNum, &infoBuffer, &tempLong); |
if ( (error == noErr) && hasAccessCntl(infoBuffer) ) |
{ |
if ( hasAccessCntl(infoBuffer) ) |
{ |
dstServerAdr = infoBuffer.vMServerAdr; |
/* See if source supports directory access control and is on same server */ |
tempLong = sizeof(infoBuffer); |
error = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong); |
if ( error == noErr ) |
{ |
if ( hasAccessCntl(infoBuffer) && (dstServerAdr == infoBuffer.vMServerAdr) ) |
{ |
/* both volumes support directory access control and they are */ |
/* on same server, so copy the access information */ |
error = HGetDirAccess(srcVRefNum, srcDirID, srcName, &ownerID, &groupID, &accessRights); |
if ( error == noErr ) |
{ |
error = HSetDirAccess(dstVRefNum, dstDirID, dstName, ownerID, groupID, accessRights); |
} |
} |
else |
{ |
/* destination doesn't support directory access control or */ |
/* they volumes aren't on the same server */ |
error = paramErr; |
} |
} |
} |
else |
{ |
/* destination doesn't support directory access control */ |
error = paramErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpCopyDirectoryAccess(const FSSpec *srcSpec, |
const FSSpec *dstSpec) |
{ |
return ( CopyDirectoryAccess(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, |
dstSpec->vRefNum, dstSpec->parID, dstSpec->name) ); |
} |
/*****************************************************************************/ |
pascal OSErr HMoveRenameCompat(short vRefNum, |
long srcDirID, |
ConstStr255Param srcName, |
long dstDirID, |
ConstStr255Param dstpathName, |
ConstStr255Param copyName) |
{ |
OSErr error; |
GetVolParmsInfoBuffer volParmsInfo; |
long infoSize; |
short realVRefNum; |
long realParID; |
Str31 realName; |
Boolean isDirectory; |
long tempItemsDirID; |
long uniqueTempDirID; |
Str31 uniqueTempDirName; |
unsigned short uniqueNameoverflow; |
/* Get volume attributes */ |
infoSize = sizeof(GetVolParmsInfoBuffer); |
error = HGetVolParms((StringPtr)srcName, vRefNum, &volParmsInfo, &infoSize); |
if ( (error == noErr) && hasMoveRename(volParmsInfo) ) |
{ |
/* If volume supports move and rename, so use it and return */ |
error = HMoveRename(vRefNum, srcDirID, srcName, dstDirID, dstpathName, copyName); |
} |
else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ |
{ |
/* MoveRename isn't supported by this volume, so do it by hand */ |
/* If copyName isn't supplied, we can simply CatMove and return */ |
if ( copyName == NULL ) |
{ |
error = CatMove(vRefNum, srcDirID, srcName, dstDirID, dstpathName); |
} |
else |
{ |
/* Renaming is required, so we have some work to do... */ |
/* Get the object's real name, real parent ID and real vRefNum */ |
error = GetObjectLocation(vRefNum, srcDirID, (StringPtr)srcName, |
&realVRefNum, &realParID, realName, &isDirectory); |
if ( error == noErr ) |
{ |
/* Find the Temporary Items Folder on that volume */ |
error = FindFolder(realVRefNum, kTemporaryFolderType, kCreateFolder, |
&realVRefNum, &tempItemsDirID); |
if ( error == noErr ) |
{ |
/* Create a new uniquely named folder in the temporary items folder. */ |
/* This is done to avoid the case where 'realName' or 'copyName' already */ |
/* exists in the temporary items folder. */ |
/* Start with current tick count as uniqueTempDirName */ |
NumToString(TickCount(), uniqueTempDirName); |
uniqueNameoverflow = 0; |
do |
{ |
error = DirCreate(realVRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID); |
if ( error == dupFNErr ) |
{ |
/* Duplicate name - change the first character to the next ASCII character */ |
++uniqueTempDirName[1]; |
/* Make sure it isn't a colon! */ |
if ( uniqueTempDirName[1] == ':' ) |
{ |
++uniqueTempDirName[1]; |
} |
/* Don't go too far... */ |
++uniqueNameoverflow; |
} |
} while ( (error == dupFNErr) && (uniqueNameoverflow <= 64) ); /* 64 new files per 1/60th second - not likely! */ |
if ( error == noErr ) |
{ |
/* Move the object to the folder with uniqueTempDirID for renaming */ |
error = CatMove(realVRefNum, realParID, realName, uniqueTempDirID, NULL); |
if ( error == noErr ) |
{ |
/* Rename the object */ |
error = HRename(realVRefNum, uniqueTempDirID, realName, copyName); |
if ( error == noErr ) |
{ |
/* Move object to its new home */ |
error = CatMove(realVRefNum, uniqueTempDirID, copyName, dstDirID, dstpathName); |
if ( error != noErr ) |
{ |
/* Error handling: rename object back to original name - ignore errors */ |
(void) HRename(realVRefNum, uniqueTempDirID, copyName, realName); |
} |
} |
if ( error != noErr ) |
{ |
/* Error handling: move object back to original location - ignore errors */ |
(void) CatMove(realVRefNum, uniqueTempDirID, realName, realParID, NULL); |
} |
} |
/* Done with ourTempDir, so delete it - ignore errors */ |
(void) HDelete(realVRefNum, uniqueTempDirID, NULL); |
} |
} |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpMoveRenameCompat(const FSSpec *srcSpec, |
const FSSpec *dstSpec, |
ConstStr255Param copyName) |
{ |
/* make sure the FSSpecs refer to the same volume */ |
if (srcSpec->vRefNum != dstSpec->vRefNum) |
return (diffVolErr); |
return ( HMoveRenameCompat(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, |
dstSpec->parID, dstSpec->name, copyName) ); |
} |
/*****************************************************************************/ |
pascal OSErr BuildAFPVolMountInfo(short flags, |
char nbpInterval, |
char nbpCount, |
short uamType, |
Str32 zoneName, |
Str32 serverName, |
Str27 volName, |
Str31 userName, |
Str8 userPassword, |
Str8 volPassword, |
AFPVolMountInfoPtr *afpInfoPtr) |
{ |
MyAFPVolMountInfoPtr infoPtr; |
OSErr error; |
/* Allocate the AFPXVolMountInfo record */ |
infoPtr = (MyAFPVolMountInfoPtr)NewPtrClear(sizeof(MyAFPVolMountInfo)); |
if ( infoPtr != NULL ) |
{ |
/* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */ |
infoPtr->length = sizeof(MyAFPVolMountInfo); |
infoPtr->media = AppleShareMediaType; |
infoPtr->flags = flags; |
infoPtr->nbpInterval = nbpInterval; |
infoPtr->nbpCount = nbpCount; |
infoPtr->uamType = uamType; |
infoPtr->zoneNameOffset = offsetof(MyAFPVolMountInfo, zoneName); |
infoPtr->serverNameOffset = offsetof(MyAFPVolMountInfo, serverName); |
infoPtr->volNameOffset = offsetof(MyAFPVolMountInfo, volName); |
infoPtr->userNameOffset = offsetof(MyAFPVolMountInfo, userName); |
infoPtr->userPasswordOffset = offsetof(MyAFPVolMountInfo, userPassword); |
infoPtr->volPasswordOffset = offsetof(MyAFPVolMountInfo, volPassword); |
BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32)); |
BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32)); |
BlockMoveData(volName, infoPtr->volName, sizeof(Str27)); |
BlockMoveData(userName, infoPtr->userName, sizeof(Str31)); |
BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8)); |
BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8)); |
*afpInfoPtr = (AFPVolMountInfoPtr)infoPtr; |
error = noErr; |
} |
else |
{ |
error = memFullErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr, |
short *flags, |
short *uamType, |
StringPtr zoneName, |
StringPtr serverName, |
StringPtr volName, |
StringPtr userName) |
{ |
StringPtr tempPtr; |
OSErr error; |
/* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ |
if ( afpInfoPtr->media == AppleShareMediaType ) |
{ |
*flags = afpInfoPtr->flags; |
*uamType = afpInfoPtr->uamType; |
if ( afpInfoPtr->zoneNameOffset != 0) |
{ |
tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->zoneNameOffset); |
BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1); |
} |
if ( afpInfoPtr->serverNameOffset != 0) |
{ |
tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->serverNameOffset); |
BlockMoveData(tempPtr, serverName, tempPtr[0] + 1); |
} |
if ( afpInfoPtr->volNameOffset != 0) |
{ |
tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->volNameOffset); |
BlockMoveData(tempPtr, volName, tempPtr[0] + 1); |
} |
if ( afpInfoPtr->userNameOffset != 0) |
{ |
tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->userNameOffset); |
BlockMoveData(tempPtr, userName, tempPtr[0] + 1); |
} |
error = noErr; |
} |
else |
{ |
error = paramErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr BuildAFPXVolMountInfo(short flags, |
char nbpInterval, |
char nbpCount, |
short uamType, |
Str32 zoneName, |
Str32 serverName, |
Str27 volName, |
Str31 userName, |
Str8 userPassword, |
Str8 volPassword, |
Str32 uamName, |
unsigned long alternateAddressLength, |
void *alternateAddress, |
AFPXVolMountInfoPtr *afpXInfoPtr) |
{ |
Size infoSize; |
MyAFPXVolMountInfoPtr infoPtr; |
OSErr error; |
/* Calculate the size of the AFPXVolMountInfo record */ |
infoSize = sizeof(MyAFPXVolMountInfo) + alternateAddressLength - 1; |
/* Allocate the AFPXVolMountInfo record */ |
infoPtr = (MyAFPXVolMountInfoPtr)NewPtrClear(infoSize); |
if ( infoPtr != NULL ) |
{ |
/* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */ |
infoPtr->length = infoSize; |
infoPtr->media = AppleShareMediaType; |
infoPtr->flags = flags; |
if ( alternateAddressLength != 0 ) |
{ |
/* make sure the volMountExtendedFlagsBit is set if there's extended address info */ |
infoPtr->flags |= volMountExtendedFlagsMask; |
/* and set the only extendedFlags bit we know about */ |
infoPtr->extendedFlags = kAFPExtendedFlagsAlternateAddressMask; |
} |
else |
{ |
/* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */ |
infoPtr->flags &= ~volMountExtendedFlagsMask; |
/* and clear the extendedFlags */ |
infoPtr->extendedFlags = 0; |
} |
infoPtr->nbpInterval = nbpInterval; |
infoPtr->nbpCount = nbpCount; |
infoPtr->uamType = uamType; |
infoPtr->zoneNameOffset = offsetof(MyAFPXVolMountInfo, zoneName); |
infoPtr->serverNameOffset = offsetof(MyAFPXVolMountInfo, serverName); |
infoPtr->volNameOffset = offsetof(MyAFPXVolMountInfo, volName); |
infoPtr->userNameOffset = offsetof(MyAFPXVolMountInfo, userName); |
infoPtr->userPasswordOffset = offsetof(MyAFPXVolMountInfo, userPassword); |
infoPtr->volPasswordOffset = offsetof(MyAFPXVolMountInfo, volPassword); |
infoPtr->uamNameOffset = offsetof(MyAFPXVolMountInfo, uamName); |
infoPtr->alternateAddressOffset = offsetof(MyAFPXVolMountInfo, alternateAddress); |
BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32)); |
BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32)); |
BlockMoveData(volName, infoPtr->volName, sizeof(Str27)); |
BlockMoveData(userName, infoPtr->userName, sizeof(Str31)); |
BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8)); |
BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8)); |
BlockMoveData(uamName, infoPtr->uamName, sizeof(Str32)); |
BlockMoveData(alternateAddress, infoPtr->alternateAddress, alternateAddressLength); |
*afpXInfoPtr = (AFPXVolMountInfoPtr)infoPtr; |
error = noErr; |
} |
else |
{ |
error = memFullErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr, |
short *flags, |
short *uamType, |
StringPtr zoneName, |
StringPtr serverName, |
StringPtr volName, |
StringPtr userName, |
StringPtr uamName, |
unsigned long *alternateAddressLength, |
AFPAlternateAddress **alternateAddress) |
{ |
StringPtr tempPtr; |
Ptr alternateAddressStart; |
Ptr alternateAddressEnd; |
Size alternateAddressDataSize; |
OSErr error; |
UInt8 addressCount; |
/* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ |
if ( afpXInfoPtr->media == AppleShareMediaType ) |
{ |
/* default to noErr */ |
error = noErr; |
/* Is this an extended record? */ |
if ( (afpXInfoPtr->flags & volMountExtendedFlagsMask) != 0 ) |
{ |
if ( ((afpXInfoPtr->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) != 0) && |
(afpXInfoPtr->alternateAddressOffset != 0) ) |
{ |
alternateAddressStart = (Ptr)((long)afpXInfoPtr + afpXInfoPtr->alternateAddressOffset); |
alternateAddressEnd = alternateAddressStart + 1; /* skip over alternate address version byte */ |
addressCount = *(UInt8*)alternateAddressEnd; /* get the address count */ |
++alternateAddressEnd; /* skip over alternate address count byte */ |
/* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */ |
while ( addressCount != 0 ) |
{ |
/* parse the address list to find the end */ |
alternateAddressEnd += *(UInt8*)alternateAddressEnd; /* add length of each AFPTagData record */ |
--addressCount; |
} |
/* get the size of the alternateAddressData */ |
alternateAddressDataSize = alternateAddressEnd - alternateAddressStart; |
/* allocate memory for it */ |
*alternateAddress = (AFPAlternateAddress *)NewPtr(alternateAddressDataSize); |
if ( *alternateAddress != NULL ) |
{ |
/* and return the data */ |
BlockMoveData(alternateAddressStart, *alternateAddress, alternateAddressDataSize); |
*alternateAddressLength = alternateAddressDataSize; |
} |
else |
{ |
/* no memory - fail now */ |
error = memFullErr; |
} |
} |
if ( error == noErr ) /* fill in more output parameters if everything is OK */ |
{ |
if ( afpXInfoPtr->uamNameOffset != 0 ) |
{ |
tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->uamNameOffset); |
BlockMoveData(tempPtr, uamName, tempPtr[0] + 1); |
} |
} |
} |
if ( error == noErr ) /* fill in more output parameters if everything is OK */ |
{ |
*flags = afpXInfoPtr->flags; |
*uamType = afpXInfoPtr->uamType; |
if ( afpXInfoPtr->zoneNameOffset != 0 ) |
{ |
tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->zoneNameOffset); |
BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1); |
} |
if ( afpXInfoPtr->serverNameOffset != 0 ) |
{ |
tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->serverNameOffset); |
BlockMoveData(tempPtr, serverName, tempPtr[0] + 1); |
} |
if ( afpXInfoPtr->volNameOffset != 0 ) |
{ |
tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->volNameOffset); |
BlockMoveData(tempPtr, volName, tempPtr[0] + 1); |
} |
if ( afpXInfoPtr->userNameOffset != 0 ) |
{ |
tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->userNameOffset); |
BlockMoveData(tempPtr, userName, tempPtr[0] + 1); |
} |
} |
} |
else |
{ |
error = paramErr; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr GetUGEntries(short objType, |
UGEntryPtr entries, |
long reqEntryCount, |
long *actEntryCount, |
long *objID) |
{ |
HParamBlockRec pb; |
OSErr error = noErr; |
UGEntry *endEntryArray; |
pb.objParam.ioObjType = objType; |
*actEntryCount = 0; |
for ( endEntryArray = entries + reqEntryCount; (entries < endEntryArray) && (error == noErr); ++entries ) |
{ |
pb.objParam.ioObjNamePtr = (StringPtr)entries->name; |
pb.objParam.ioObjID = *objID; |
/* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */ |
/* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */ |
/* A CMovePBPtr works OK, but this will be changed in the future back to */ |
/* HParmBlkPtr, so I'm just casting it here. */ |
error = PBGetUGEntrySync(&pb); |
if ( error == noErr ) |
{ |
entries->objID = *objID = pb.objParam.ioObjID; |
entries->objType = objType; |
++*actEntryCount; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-13