2 File: MoreFilesExtras.c
4 Contains: A collection of useful high-level File Manager routines
8 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved.
10 You may incorporate this sample code into your applications without
11 restriction, though the sample code has been provided "AS IS" and the
12 responsibility for its operation is 100% yours. However, what you are
13 not permitted to do is to redistribute the source as "DSC Sample Code"
14 after having made changes. If you're going to re-distribute the source,
15 we require that you make it clear in the source that the code was
16 descended from Apple Sample Code, but that you've made changes.
22 Other Contact: Apple Macintosh Developer Technical Support
23 <http://developer.apple.com/bugreporter/>
25 Technology: DTS Sample Code
31 Change History (most recent first):
33 <2> 2/7/01 JL [2500429] Changed null output parameters to real variables when
34 calling GetSharedLibrary to prevent crashes with older versions
35 of CFM. Added standard header. Updated names of includes. Added
36 C function implementations of accessors that used to be macros
37 since the generated Pascal headers no longer contain
38 implementations. Updated various other routines to use new
39 calling convention of the accessor functions.
40 <1> 12/06/99 JL MoreFiles 1.5.
49 #include <HFSVolumes.h>
52 #include <MacErrors.h>
53 #include <MacMemory.h>
59 #include <TextUtils.h>
62 #include <CodeFragments.h>
65 #define __COMPILINGMOREFILES
67 #include "MoreFiles.h"
68 #include "MoreDesktopMgr.h"
69 #include "FSpCompat.h"
71 #include "MoreFilesExtras.h"
73 /*****************************************************************************/
75 /* Functions to get information out of GetVolParmsInfoBuffer. */
77 /* version 1 field getters */
79 pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer
*volParms
)
81 return ( volParms
->vMVersion
);
84 pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer
*volParms
)
86 return ( volParms
->vMAttrib
);
89 pascal Handle
GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer
*volParms
)
91 return ( volParms
->vMLocalHand
);
94 pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer
*volParms
)
96 return ( volParms
->vMServerAdr
);
99 /* version 2 field getters (assume zero result if version < 2) */
101 pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer
*volParms
)
103 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMVolumeGrade
: 0 );
106 pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer
*volParms
)
108 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMForeignPrivID
: 0 );
111 /* version 3 field getters (assume zero result if version < 3) */
113 pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer
*volParms
)
115 return ( (volParms
->vMVersion
>= 3) ? volParms
->vMExtendedAttributes
: 0 );
118 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */
120 pascal Boolean
isNetworkVolume(const GetVolParmsInfoBuffer
*volParms
)
122 return ( volParms
->vMServerAdr
!= 0 );
125 pascal Boolean
hasLimitFCBs(const GetVolParmsInfoBuffer
*volParms
)
127 return ( (volParms
->vMAttrib
& (1L << bLimitFCBs
)) != 0 );
130 pascal Boolean
hasLocalWList(const GetVolParmsInfoBuffer
*volParms
)
132 return ( (volParms
->vMAttrib
& (1L << bLocalWList
)) != 0 );
135 pascal Boolean
hasNoMiniFndr(const GetVolParmsInfoBuffer
*volParms
)
137 return ( (volParms
->vMAttrib
& (1L << bNoMiniFndr
)) != 0 );
140 pascal Boolean
hasNoVNEdit(const GetVolParmsInfoBuffer
*volParms
)
142 return ( (volParms
->vMAttrib
& (1L << bNoVNEdit
)) != 0 );
145 pascal Boolean
hasNoLclSync(const GetVolParmsInfoBuffer
*volParms
)
147 return ( (volParms
->vMAttrib
& (1L << bNoLclSync
)) != 0 );
150 pascal Boolean
hasTrshOffLine(const GetVolParmsInfoBuffer
*volParms
)
152 return ( (volParms
->vMAttrib
& (1L << bTrshOffLine
)) != 0 );
155 pascal Boolean
hasNoSwitchTo(const GetVolParmsInfoBuffer
*volParms
)
157 return ( (volParms
->vMAttrib
& (1L << bNoSwitchTo
)) != 0 );
160 pascal Boolean
hasNoDeskItems(const GetVolParmsInfoBuffer
*volParms
)
162 return ( (volParms
->vMAttrib
& (1L << bNoDeskItems
)) != 0 );
165 pascal Boolean
hasNoBootBlks(const GetVolParmsInfoBuffer
*volParms
)
167 return ( (volParms
->vMAttrib
& (1L << bNoBootBlks
)) != 0 );
170 pascal Boolean
hasAccessCntl(const GetVolParmsInfoBuffer
*volParms
)
172 return ( (volParms
->vMAttrib
& (1L << bAccessCntl
)) != 0 );
175 pascal Boolean
hasNoSysDir(const GetVolParmsInfoBuffer
*volParms
)
177 return ( (volParms
->vMAttrib
& (1L << bNoSysDir
)) != 0 );
180 pascal Boolean
hasExtFSVol(const GetVolParmsInfoBuffer
*volParms
)
182 return ( (volParms
->vMAttrib
& (1L << bHasExtFSVol
)) != 0 );
185 pascal Boolean
hasOpenDeny(const GetVolParmsInfoBuffer
*volParms
)
187 return ( (volParms
->vMAttrib
& (1L << bHasOpenDeny
)) != 0 );
190 pascal Boolean
hasCopyFile(const GetVolParmsInfoBuffer
*volParms
)
192 return ( (volParms
->vMAttrib
& (1L << bHasCopyFile
)) != 0 );
195 pascal Boolean
hasMoveRename(const GetVolParmsInfoBuffer
*volParms
)
197 return ( (volParms
->vMAttrib
& (1L << bHasMoveRename
)) != 0 );
200 pascal Boolean
hasDesktopMgr(const GetVolParmsInfoBuffer
*volParms
)
202 return ( (volParms
->vMAttrib
& (1L << bHasDesktopMgr
)) != 0 );
205 pascal Boolean
hasShortName(const GetVolParmsInfoBuffer
*volParms
)
207 return ( (volParms
->vMAttrib
& (1L << bHasShortName
)) != 0 );
210 pascal Boolean
hasFolderLock(const GetVolParmsInfoBuffer
*volParms
)
212 return ( (volParms
->vMAttrib
& (1L << bHasFolderLock
)) != 0 );
215 pascal Boolean
hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
217 return ( (volParms
->vMAttrib
& (1L << bHasPersonalAccessPrivileges
)) != 0 );
220 pascal Boolean
hasUserGroupList(const GetVolParmsInfoBuffer
*volParms
)
222 return ( (volParms
->vMAttrib
& (1L << bHasUserGroupList
)) != 0 );
225 pascal Boolean
hasCatSearch(const GetVolParmsInfoBuffer
*volParms
)
227 return ( (volParms
->vMAttrib
& (1L << bHasCatSearch
)) != 0 );
230 pascal Boolean
hasFileIDs(const GetVolParmsInfoBuffer
*volParms
)
232 return ( (volParms
->vMAttrib
& (1L << bHasFileIDs
)) != 0 );
235 pascal Boolean
hasBTreeMgr(const GetVolParmsInfoBuffer
*volParms
)
237 return ( (volParms
->vMAttrib
& (1L << bHasBTreeMgr
)) != 0 );
240 pascal Boolean
hasBlankAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
242 return ( (volParms
->vMAttrib
& (1L << bHasBlankAccessPrivileges
)) != 0 );
245 pascal Boolean
supportsAsyncRequests(const GetVolParmsInfoBuffer
*volParms
)
247 return ( (volParms
->vMAttrib
& (1L << bSupportsAsyncRequests
)) != 0 );
250 pascal Boolean
supportsTrashVolumeCache(const GetVolParmsInfoBuffer
*volParms
)
252 return ( (volParms
->vMAttrib
& (1L << bSupportsTrashVolumeCache
)) != 0 );
255 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
257 pascal Boolean
volIsEjectable(const GetVolParmsInfoBuffer
*volParms
)
259 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bIsEjectable
)) != 0 );
262 pascal Boolean
volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer
*volParms
)
264 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsHFSPlusAPIs
)) != 0 );
267 pascal Boolean
volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer
*volParms
)
269 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSCatalogSearch
)) != 0 );
272 pascal Boolean
volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer
*volParms
)
274 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSExchangeObjects
)) != 0 );
277 pascal Boolean
volSupports2TBFiles(const GetVolParmsInfoBuffer
*volParms
)
279 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupports2TBFiles
)) != 0 );
282 pascal Boolean
volSupportsLongNames(const GetVolParmsInfoBuffer
*volParms
)
284 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsLongNames
)) != 0 );
287 pascal Boolean
volSupportsMultiScriptNames(const GetVolParmsInfoBuffer
*volParms
)
289 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsMultiScriptNames
)) != 0 );
292 pascal Boolean
volSupportsNamedForks(const GetVolParmsInfoBuffer
*volParms
)
294 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsNamedForks
)) != 0 );
297 pascal Boolean
volSupportsSubtreeIterators(const GetVolParmsInfoBuffer
*volParms
)
299 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsSubtreeIterators
)) != 0 );
302 pascal Boolean
volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer
*volParms
)
304 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bL2PCanMapFileBlocks
)) != 0 );
307 /*****************************************************************************/
309 /* Functions for testing ioACUser bits. */
311 pascal Boolean
userIsOwner(SInt8 ioACUser
)
313 return ( (ioACUser
& kioACUserNotOwnerMask
) == 0 );
316 pascal Boolean
userHasFullAccess(SInt8 ioACUser
)
318 return ( (ioACUser
& acUserAccessMask
) == acUserFull
);
321 pascal Boolean
userHasDropBoxAccess(SInt8 ioACUser
)
323 return ( (ioACUser
& acUserAccessMask
) == acUserDropBox
);
326 pascal Boolean
userHasBulletinBoard(SInt8 ioACUser
)
328 return ( (ioACUser
& acUserAccessMask
) == acUserBulletinBoard
);
331 pascal Boolean
userHasNoAccess(SInt8 ioACUser
)
333 return ( (ioACUser
& acUserAccessMask
) == acUserNone
);
336 /*****************************************************************************/
338 /* local data structures */
340 /* The DeleteEnumGlobals structure is used to minimize the amount of
341 ** stack space used when recursively calling DeleteLevel and to hold
342 ** global information that might be needed at any time. */
344 #if PRAGMA_STRUCT_ALIGN
345 #pragma options align=mac68k
346 #endif // PRAGMA_STRUCT_ALIGN
347 struct DeleteEnumGlobals
349 OSErr error
; /* temporary holder of results - saves 2 bytes of stack each level */
350 Str63 itemName
; /* the name of the current item */
351 UniversalFMPB myPB
; /* the parameter block used for PBGetCatInfo calls */
353 #if PRAGMA_STRUCT_ALIGN
354 #pragma options align=reset
355 #endif // PRAGMA_STRUCT_ALIGN
357 typedef struct DeleteEnumGlobals DeleteEnumGlobals
;
358 typedef DeleteEnumGlobals
*DeleteEnumGlobalsPtr
;
360 /*****************************************************************************/
363 ** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
364 ** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync
365 ** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined,
366 ** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync.
368 ** Non-CFM 68K programs don't needs this glue (and won't get it) because
369 ** they instead use the inline assembly glue found in the Files.h interface
373 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
375 // Carbon builds and 68K builds don't need this glue
376 #define CallPBXGetVolInfoSync PBXGetVolInfoSync
378 #else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
380 #if __WANTPASCALELIMINATION
382 #endif // __WANTPASCALELIMINATION
384 /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */
385 static pascal OSErr
PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock
)
389 uppFSDispatchProcInfo
= kRegisterBased
390 | REGISTER_RESULT_LOCATION(kRegisterD0
)
391 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr
)))
392 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0
, SIZE_CODE(sizeof(long))) /* selector */
393 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1
, SIZE_CODE(sizeof(long))) /* trap word */
394 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0
, SIZE_CODE(sizeof(XVolumeParamPtr
)))
397 static UniversalProcPtr fsDispatchTrapAddress
= NULL
;
399 /* Is this the first time we've been called? */
400 if ( fsDispatchTrapAddress
== NULL
)
402 /* Yes - Get the trap address of _FSDispatch */
403 fsDispatchTrapAddress
= NGetTrapAddress(_FSDispatch
, OSTrap
);
405 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress
,
406 uppFSDispatchProcInfo
,
413 ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2.
414 ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5.
415 ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib;
416 ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program
417 ** is calling the latest implementation of PBXGetVolInfoSync.
419 static pascal OSErr
CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock
)
421 typedef pascal OSErr (*PBXGetVolInfoProcPtr
) (XVolumeParamPtr paramBlock
);
424 CFragConnectionID connID
;
427 static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr
= NULL
;
429 //* Is this the first time we've been called? */
430 if ( PBXGetVolInfoSyncPtr
== NULL
)
432 /* Yes - Get our connection ID to InterfaceLib */
433 result
= GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch
, kLoadCFrag
, &connID
, &mainAddr
, errMessage
);
434 if ( result
== noErr
)
436 /* See if PBXGetVolInfoSync is in InterfaceLib */
437 if ( FindSymbol(connID
, "\pPBXGetVolInfoSync", &(Ptr
)PBXGetVolInfoSyncPtr
, NULL
) != noErr
)
439 /* Use glue code if symbol isn't found */
440 PBXGetVolInfoSyncPtr
= PBXGetVolInfoSyncGlue
;
444 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */
445 return ( (*PBXGetVolInfoSyncPtr
)(paramBlock
) );
448 #if __WANTPASCALELIMINATION
450 #endif // __WANTPASCALELIMINATION
452 #endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
454 /*****************************************************************************/
456 pascal void TruncPString(StringPtr destination
,
457 ConstStr255Param source
,
462 if ( source
!= NULL
&& destination
!= NULL
) /* don't do anything stupid */
464 if ( source
[0] > maxLength
)
466 /* Make sure the string isn't truncated in the middle of */
467 /* a multi-byte character. */
468 while (maxLength
!= 0)
470 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter
471 charType
= CharacterByteType((Ptr
)&source
[1], maxLength
- 1, smSystemScript
);
472 if ( (charType
== smSingleByte
) || (charType
== smLastByte
) )
473 break; /* source[maxLength] is now a valid last character */
479 maxLength
= source
[0];
481 /* Set the destination string length */
482 destination
[0] = maxLength
;
483 /* and copy maxLength characters (if needed) */
484 if ( source
!= destination
)
486 while ( maxLength
!= 0 )
488 destination
[maxLength
] = source
[maxLength
];
495 /*****************************************************************************/
497 pascal Ptr
GetTempBuffer(long buffReqSize
,
502 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
506 /* Make request a multiple of 1024 bytes */
507 buffReqSize
= buffReqSize
& 0xfffffc00;
509 if ( buffReqSize
< 0x00000400 )
511 /* Request was smaller than 1024 bytes - make it 1024 */
512 buffReqSize
= 0x00000400;
515 /* Attempt to allocate the memory */
516 tempPtr
= NewPtr(buffReqSize
);
518 /* If request failed, go to backup plan */
519 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00000400) )
522 ** Try to get largest 1024-byte block available
523 ** leaving some slop for the toolbox if possible
525 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffffc00;
527 buffReqSize
= MaxBlock() & 0xfffffc00;
529 if ( buffReqSize
> freeMemory
)
531 buffReqSize
= freeMemory
;
534 if ( buffReqSize
== 0 )
536 buffReqSize
= 0x00000400;
539 tempPtr
= NewPtr(buffReqSize
);
542 /* Return bytes allocated */
543 if ( tempPtr
!= NULL
)
545 *buffActSize
= buffReqSize
;
555 /*****************************************************************************/
558 ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
559 ** in cases where the returned volume name is not needed by the caller.
560 ** The pathname and vRefNum parameters are not touched, and the pb
561 ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
562 ** the parameter block is always returned as NULL (since it might point
563 ** to the local tempPathname).
565 ** I noticed using this code in several places, so here it is once.
566 ** This reduces the code size of MoreFiles.
568 pascal OSErr
GetVolumeInfoNoName(ConstStr255Param pathname
,
575 /* Make sure pb parameter is not NULL */
578 pb
->volumeParam
.ioVRefNum
= vRefNum
;
579 if ( pathname
== NULL
)
581 pb
->volumeParam
.ioNamePtr
= NULL
;
582 pb
->volumeParam
.ioVolIndex
= 0; /* use ioVRefNum only */
586 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
587 pb
->volumeParam
.ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
588 pb
->volumeParam
.ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
590 error
= PBHGetVInfoSync(pb
);
591 pb
->volumeParam
.ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
600 /*****************************************************************************/
603 ** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
604 ** in cases where the returned volume name is not needed by the caller.
605 ** The pathname and vRefNum parameters are not touched, and the pb
606 ** parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
607 ** the parameter block is always returned as NULL (since it might point
608 ** to the local tempPathname).
610 pascal OSErr
XGetVolumeInfoNoName(ConstStr255Param pathname
,
617 /* Make sure pb parameter is not NULL */
620 pb
->ioVRefNum
= vRefNum
;
621 pb
->ioXVersion
= 0; /* this XVolumeParam version (0) */
622 if ( pathname
== NULL
)
624 pb
->ioNamePtr
= NULL
;
625 pb
->ioVolIndex
= 0; /* use ioVRefNum only */
629 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
630 pb
->ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
631 pb
->ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
635 #if !TARGET_API_MAC_CARBON
638 /* Is PBXGetVolInfo available? */
639 if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr
) || ((response
& (1L << gestaltFSSupports2TBVols
)) == 0) )
641 /* No, fall back on PBHGetVInfo */
642 error
= PBHGetVInfoSync((HParmBlkPtr
)pb
);
643 if ( error
== noErr
)
645 /* calculate the ioVTotalBytes and ioVFreeBytes fields */
646 pb
->ioVTotalBytes
= U64Multiply(U64SetU(pb
->ioVNmAlBlks
), U64SetU(pb
->ioVAlBlkSiz
));
647 pb
->ioVFreeBytes
= U64Multiply(U64SetU(pb
->ioVFrBlk
), U64SetU(pb
->ioVAlBlkSiz
));
654 error
= CallPBXGetVolInfoSync(pb
);
657 pb
->ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
666 /*****************************************************************************/
668 pascal OSErr
GetCatInfoNoName(short vRefNum
,
670 ConstStr255Param name
,
676 /* Protection against File Sharing problem */
677 if ( (name
== NULL
) || (name
[0] == 0) )
680 pb
->dirInfo
.ioNamePtr
= tempName
;
681 pb
->dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
685 pb
->dirInfo
.ioNamePtr
= (StringPtr
)name
;
686 pb
->dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
688 pb
->dirInfo
.ioVRefNum
= vRefNum
;
689 pb
->dirInfo
.ioDrDirID
= dirID
;
690 error
= PBGetCatInfoSync(pb
);
691 pb
->dirInfo
.ioNamePtr
= NULL
;
695 /*****************************************************************************/
697 pascal OSErr
DetermineVRefNum(ConstStr255Param pathname
,
704 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
705 if ( error
== noErr
)
707 *realVRefNum
= pb
.volumeParam
.ioVRefNum
;
712 /*****************************************************************************/
714 pascal OSErr
HGetVInfo(short volReference
,
717 unsigned long *freeBytes
,
718 unsigned long *totalBytes
)
724 // get the best values possible from XGetVInfo
725 result
= XGetVInfo(volReference
, volName
, vRefNum
, &freeBytes64
, &totalBytes64
);
726 if ( result
== noErr
)
728 // and pin those values if needed
729 if ( UInt64ToUnsignedWide(freeBytes64
).hi
!= 0 )
731 // pin to maximum 512-byte block aligned value
732 *freeBytes
= 0xfffffe00;
736 *freeBytes
= U32SetU(freeBytes64
);
739 if ( UInt64ToUnsignedWide(totalBytes64
).hi
!= 0 )
741 // pin to maximum 512-byte block aligned value
742 *totalBytes
= 0xfffffe00;
746 *totalBytes
= U32SetU(totalBytes64
);
753 /*****************************************************************************/
755 pascal OSErr
XGetVInfo(short volReference
,
764 #if !TARGET_API_MAC_CARBON
768 #endif // !TARGET_API_MAC_CARBON
770 pb
.ioVRefNum
= volReference
;
771 pb
.ioNamePtr
= volName
;
772 pb
.ioXVersion
= 0; /* this XVolumeParam version (0) */
773 pb
.ioVolIndex
= 0; /* use ioVRefNum only, return volume name */
775 #if !TARGET_API_MAC_CARBON
777 /* See if large volume support is available */
778 if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr
) && ((response
& (1L << gestaltFSSupports2TBVols
)) != 0) )
780 #endif // !TARGET_API_MAC_CARBON
783 /* Large volume support is available */
784 result
= CallPBXGetVolInfoSync(&pb
);
785 if ( result
== noErr
)
787 /* The volume name was returned in volName (if not NULL) and */
788 /* we have the volume's vRefNum and allocation block size */
789 *vRefNum
= pb
.ioVRefNum
;
791 /* return the freeBytes and totalBytes */
792 *totalBytes
= pb
.ioVTotalBytes
;
793 *freeBytes
= pb
.ioVFreeBytes
;
797 #if !TARGET_API_MAC_CARBON
801 /* No large volume support */
802 /* Use PBHGetVInfoSync to get the results */
803 result
= PBHGetVInfoSync((HParmBlkPtr
)&pb
);
804 if ( result
== noErr
)
808 /* The volume name was returned in volName (if not NULL) and */
809 /* we have the volume's vRefNum */
810 *vRefNum
= pb
.ioVRefNum
;
812 /* System 7.5 (and beyond) pins the number of allocation blocks and */
813 /* the number of free allocation blocks returned by PBHGetVInfo to */
814 /* a value so that when multiplied by the allocation block size, */
815 /* the volume will look like it has $7fffffff bytes or less. This */
816 /* was done so older applications that use signed math or that use */
817 /* the GetVInfo function (which uses signed math) will continue to work. */
818 /* However, the unpinned numbers (which we want) are always available */
819 /* in the volume's VCB so we'll get those values from the VCB. */
820 /* Note: Carbon doesn't support the VCB queue, so this code cannot be */
821 /* used (and is conditionalized out) by Carbon applications. */
823 /* Find the volume's VCB */
824 theVCB
= (VCB
*)(GetVCBQHdr()->qHead
);
825 while ( theVCB
!= NULL
)
827 if ( theVCB
->vcbVRefNum
== *vRefNum
)
832 theVCB
= (VCB
*)(theVCB
->qLink
); /* next VCB */
835 if ( theVCB
!= NULL
)
837 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
838 /* and the number of free blocks from the VCB. */
839 *freeBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbFreeBks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
840 *totalBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
844 /* Didn't find a VCB we can use. Return the number of allocation blocks */
845 /* and the number of free blocks returned by PBHGetVInfoSync. */
846 *freeBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVFrBlk
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
847 *totalBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
853 #endif // !TARGET_API_MAC_CARBON
858 /*****************************************************************************/
860 pascal OSErr
CheckVolLock(ConstStr255Param pathname
,
866 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
867 if ( error
== noErr
)
869 if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeHardwareLockMask
) != 0 )
871 error
= wPrErr
; /* volume locked by hardware */
873 else if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeSoftwareLockMask
) != 0 )
875 error
= vLckdErr
; /* volume locked by software */
882 /*****************************************************************************/
884 // The following routines call Mac OS routines that are not supported by
892 #if !TARGET_API_MAC_CARBON // {
894 /*****************************************************************************/
896 pascal OSErr
GetDriverName(short driverRefNum
,
901 DRVRHeaderPtr dHeaderPtr
;
903 theDctl
= GetDCtlEntry(driverRefNum
);
904 if ( theDctl
!= NULL
)
906 if ( (**theDctl
).dCtlFlags
& dRAMBasedMask
)
908 /* dctlDriver is handle - dereference */
909 dHeaderPtr
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
);
913 /* dctlDriver is pointer */
914 dHeaderPtr
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
;
916 BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1);
922 result
= badUnitErr
; /* bad reference number */
928 /*****************************************************************************/
930 pascal OSErr
FindDrive(ConstStr255Param pathname
,
932 DrvQElPtr
*driveQElementPtr
)
938 *driveQElementPtr
= NULL
;
940 /* First, use GetVolumeInfoNoName to determine the volume */
941 result
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
);
942 if ( result
== noErr
)
945 ** The volume can be either online, offline, or ejected. What we find in
946 ** ioVDrvInfo and ioVDRefNum will tell us which it is.
947 ** See Inside Macintosh: Files page 2-80 and the Technical Note
948 ** "FL 34 - VCBs and Drive Numbers : The Real Story"
949 ** Where we get the drive number depends on the state of the volume.
951 if ( hPB
.volumeParam
.ioVDrvInfo
!= 0 )
953 /* The volume is online and not ejected */
954 /* Get the drive number */
955 driveNumber
= hPB
.volumeParam
.ioVDrvInfo
;
959 /* The volume's is either offline or ejected */
960 /* in either case, the volume is NOT online */
962 /* Is it ejected or just offline? */
963 if ( hPB
.volumeParam
.ioVDRefNum
> 0 )
965 /* It's ejected, the drive number is ioVDRefNum */
966 driveNumber
= hPB
.volumeParam
.ioVDRefNum
;
970 /* It's offline, the drive number is the negative of ioVDRefNum */
971 driveNumber
= (short)-hPB
.volumeParam
.ioVDRefNum
;
975 /* Get pointer to first element in drive queue */
976 *driveQElementPtr
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
978 /* Search for a matching drive number */
979 while ( (*driveQElementPtr
!= NULL
) && ((*driveQElementPtr
)->dQDrive
!= driveNumber
) )
981 *driveQElementPtr
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
;
984 if ( *driveQElementPtr
== NULL
)
986 /* This should never happen since every volume must have a drive, but... */
994 /*****************************************************************************/
996 pascal OSErr
GetDiskBlocks(ConstStr255Param pathname
,
998 unsigned long *numBlocks
)
1000 /* Various constants for GetDiskBlocks() */
1003 /* return format list status code */
1006 /* reference number of .SONY driver */
1007 kSonyRefNum
= 0xfffb,
1009 /* values returned by DriveStatus in DrvSts.twoSideFmt */
1012 kSingleSidedSize
= 800, /* 400K */
1013 kDoubleSidedSize
= 1600, /* 800K */
1015 /* values in DrvQEl.qType */
1019 /* more than enough formatListRecords */
1020 kMaxFormatListRecs
= 16
1023 DrvQElPtr driveQElementPtr
;
1024 unsigned long blocks
;
1026 FormatListRec formatListRecords
[kMaxFormatListRecs
];
1028 short formatListRecIndex
;
1033 /* Find the drive queue element for this volume */
1034 result
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
);
1037 ** Make sure this is a real driver (dQRefNum < 0).
1038 ** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
1039 ** problems if you try to use it as a driver refNum.
1041 if ( (result
== noErr
) && (driveQElementPtr
->dQRefNum
>= 0) )
1047 /* Attempt to get the drive's format list. */
1048 /* (see the Technical Note "What Your Sony Drives For You") */
1050 pb
.cntrlParam
.ioVRefNum
= driveQElementPtr
->dQDrive
;
1051 pb
.cntrlParam
.ioCRefNum
= driveQElementPtr
->dQRefNum
;
1052 pb
.cntrlParam
.csCode
= kFmtLstCode
;
1053 pb
.cntrlParam
.csParam
[0] = kMaxFormatListRecs
;
1054 *(long *)&pb
.cntrlParam
.csParam
[1] = (long)&formatListRecords
[0];
1056 result
= PBStatusSync(&pb
);
1058 if ( result
== noErr
)
1060 /* The drive supports ReturnFormatList status call. */
1062 /* Get the current disk's size. */
1063 for( formatListRecIndex
= 0;
1064 formatListRecIndex
< pb
.cntrlParam
.csParam
[0];
1065 ++formatListRecIndex
)
1067 if ( (formatListRecords
[formatListRecIndex
].formatFlags
&
1068 diCIFmtFlagsCurrentMask
) != 0 )
1070 blocks
= formatListRecords
[formatListRecIndex
].volSize
;
1075 /* This should never happen */
1079 else if ( driveQElementPtr
->dQRefNum
== (short)kSonyRefNum
)
1081 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
1083 result
= DriveStatus(driveQElementPtr
->dQDrive
, &status
);
1084 if ( result
== noErr
)
1086 switch ( status
.twoSideFmt
)
1089 blocks
= kSingleSidedSize
;
1092 blocks
= kDoubleSidedSize
;
1095 /* This should never happen */
1103 /* The drive is not a floppy and it doesn't support ReturnFormatList */
1104 /* so use the dQDrvSz field(s) */
1106 result
= noErr
; /* reset result */
1107 switch ( driveQElementPtr
->qType
)
1110 blocks
= driveQElementPtr
->dQDrvSz
;
1113 blocks
= ((unsigned long)driveQElementPtr
->dQDrvSz2
<< 16) +
1114 driveQElementPtr
->dQDrvSz
;
1117 /* This should never happen */
1124 if ( result
== noErr
)
1126 *numBlocks
= blocks
;
1132 /*****************************************************************************/
1134 pascal OSErr
GetVolState(ConstStr255Param pathname
,
1136 Boolean
*volumeOnline
,
1137 Boolean
*volumeEjected
,
1138 Boolean
*driveEjectable
,
1139 Boolean
*driverWantsEject
)
1145 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1146 if ( error
== noErr
)
1148 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1150 /* the volume is online and not ejected */
1151 *volumeOnline
= true;
1152 *volumeEjected
= false;
1154 /* Get the drive number */
1155 driveNumber
= pb
.volumeParam
.ioVDrvInfo
;
1159 /* the volume's is either offline or ejected */
1160 /* in either case, the volume is NOT online */
1161 *volumeOnline
= false;
1163 /* Is it ejected? */
1164 *volumeEjected
= pb
.volumeParam
.ioVDRefNum
> 0;
1166 if ( *volumeEjected
)
1168 /* If ejected, the drive number is ioVDRefNum */
1169 driveNumber
= pb
.volumeParam
.ioVDRefNum
;
1173 /* If offline, the drive number is the negative of ioVDRefNum */
1174 driveNumber
= (short)-pb
.volumeParam
.ioVDRefNum
;
1181 /* Find the drive queue element by searching the drive queue */
1182 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1183 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNumber
) )
1185 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1188 if ( drvQElem
!= NULL
)
1191 ** Each drive queue element is preceded by 4 flag bytes.
1192 ** Byte 1 (the second flag byte) has bits that tell us if a
1193 ** drive is ejectable and if its driver wants an eject call.
1194 ** See Inside Macintosh: Files, page 2-85.
1199 /* point to byte 1 of the flag bytes */
1200 flagBytePtr
= (Ptr
)drvQElem
;
1204 ** The drive is ejectable if flag byte 1 does not contain
1205 ** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
1208 *driveEjectable
= (*flagBytePtr
!= 0x08) && (*flagBytePtr
!= 0x48);
1211 ** The driver wants an eject call if flag byte 1 does not contain
1212 ** 0x08 (nonejectable). This may seem like a minor point, but some
1213 ** disk drivers use the Eject request to flush their caches to disk
1214 ** and you wouldn't want to skip that step after unmounting a volume.
1217 *driverWantsEject
= (*flagBytePtr
!= 0x08);
1222 /* Didn't find the drive (this should never happen) */
1223 *driveEjectable
= false;
1224 *driverWantsEject
= false;
1232 /*****************************************************************************/
1234 #endif // } !TARGET_API_MAC_CARBON
1236 /*****************************************************************************/
1238 pascal OSErr
GetVolFileSystemID(ConstStr255Param pathname
,
1240 short *fileSystemID
)
1245 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1246 if ( error
== noErr
)
1248 *fileSystemID
= pb
.volumeParam
.ioVFSID
;
1254 /*****************************************************************************/
1257 // Note: Under Carbon there are no drive numbers, so you cannot call
1258 // Eject with a drive number after unmounting a volume.
1259 // When a Carbon application calls UnmountVol, CarbonLib will make
1260 // sure ejectable media is ejected (leaving ejectable media in the
1261 // disk drive makes no sense to Carbon applications).
1263 pascal OSErr
UnmountAndEject(ConstStr255Param pathname
,
1269 error
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
);
1270 if ( error
== noErr
)
1273 #if !TARGET_API_MAC_CARBON
1276 Boolean ejected
, wantsEject
;
1279 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1281 /* the volume is online and not ejected */
1284 /* Get the drive number */
1285 driveNum
= pb
.volumeParam
.ioVDrvInfo
;
1289 /* the volume is ejected or offline */
1291 /* Is it ejected? */
1292 ejected
= pb
.volumeParam
.ioVDRefNum
> 0;
1296 /* If ejected, the drive number is ioVDRefNum */
1297 driveNum
= pb
.volumeParam
.ioVDRefNum
;
1301 /* If offline, the drive number is the negative of ioVDRefNum */
1302 driveNum
= (short)-pb
.volumeParam
.ioVDRefNum
;
1306 /* find the drive queue element */
1307 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1308 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNum
) )
1310 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1313 if ( drvQElem
!= NULL
)
1315 /* does the drive want an eject call */
1316 wantsEject
= (*((Ptr
)((Ptr
)drvQElem
- 3)) != 8);
1320 /* didn't find the drive!! */
1324 #endif // !TARGET_API_MAC_CARBON
1326 /* unmount the volume */
1327 pb
.volumeParam
.ioNamePtr
= NULL
;
1328 /* ioVRefNum is already filled in from PBHGetVInfo */
1329 error
= PBUnmountVol((ParmBlkPtr
)&pb
);
1331 #if !TARGET_API_MAC_CARBON
1333 if ( error
== noErr
)
1335 if ( wantsEject
&& !ejected
)
1337 /* eject the media from the drive if needed */
1338 pb
.volumeParam
.ioVRefNum
= driveNum
;
1339 error
= PBEject((ParmBlkPtr
)&pb
);
1343 #endif // !TARGET_API_MAC_CARBON
1350 /*****************************************************************************/
1352 pascal OSErr
OnLine(FSSpecPtr volumes
,
1358 OSErr error
= noErr
;
1359 FSSpec
*endVolArray
;
1361 if ( *volIndex
> 0 )
1364 for ( endVolArray
= volumes
+ reqVolCount
; (volumes
< endVolArray
) && (error
== noErr
); ++volumes
)
1366 pb
.volumeParam
.ioNamePtr
= (StringPtr
) & volumes
->name
;
1367 pb
.volumeParam
.ioVolIndex
= *volIndex
;
1368 error
= PBHGetVInfoSync(&pb
);
1369 if ( error
== noErr
)
1371 volumes
->parID
= fsRtParID
; /* the root directory's parent is 1 */
1372 volumes
->vRefNum
= pb
.volumeParam
.ioVRefNum
;
1386 /*****************************************************************************/
1388 pascal OSErr
SetDefault(short newVRefNum
,
1395 /* Get the current default volume/directory. */
1396 error
= HGetVol(NULL
, oldVRefNum
, oldDirID
);
1397 if ( error
== noErr
)
1399 /* Set the new default volume/directory */
1400 error
= HSetVol(NULL
, newVRefNum
, newDirID
);
1406 /*****************************************************************************/
1408 pascal OSErr
RestoreDefault(short oldVRefNum
,
1413 #if !TARGET_API_MAC_CARBON
1415 short defaultVRefNum
;
1419 /* Determine if the default volume was a wdRefNum. */
1420 error
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
);
1421 if ( error
== noErr
)
1423 /* Restore the old default volume/directory, one way or the other. */
1424 if ( defaultDirID
!= fsRtDirID
)
1426 /* oldVRefNum was a wdRefNum - use SetVol */
1427 error
= SetVol(NULL
, oldVRefNum
);
1432 #endif // !TARGET_API_MAC_CARBON
1434 /* oldVRefNum was a real vRefNum - use HSetVol */
1435 error
= HSetVol(NULL
, oldVRefNum
, oldDirID
);
1437 #if !TARGET_API_MAC_CARBON
1441 #endif // !TARGET_API_MAC_CARBON
1446 /*****************************************************************************/
1448 pascal OSErr
GetDInfo(short vRefNum
,
1450 ConstStr255Param name
,
1456 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1457 if ( error
== noErr
)
1459 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1461 /* it's a directory, return the DInfo */
1462 *fndrInfo
= pb
.dirInfo
.ioDrUsrWds
;
1466 /* oops, a file was passed */
1474 /*****************************************************************************/
1476 pascal OSErr
FSpGetDInfo(const FSSpec
*spec
,
1479 return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1482 /*****************************************************************************/
1484 pascal OSErr
SetDInfo(short vRefNum
,
1486 ConstStr255Param name
,
1487 const DInfo
*fndrInfo
)
1493 /* Protection against File Sharing problem */
1494 if ( (name
== NULL
) || (name
[0] == 0) )
1497 pb
.dirInfo
.ioNamePtr
= tempName
;
1498 pb
.dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
1502 pb
.dirInfo
.ioNamePtr
= (StringPtr
)name
;
1503 pb
.dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1505 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1506 pb
.dirInfo
.ioDrDirID
= dirID
;
1507 error
= PBGetCatInfoSync(&pb
);
1508 if ( error
== noErr
)
1510 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1512 /* it's a directory, set the DInfo */
1513 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
1515 pb
.dirInfo
.ioDrDirID
= pb
.dirInfo
.ioDrParID
;
1519 pb
.dirInfo
.ioDrDirID
= dirID
;
1521 pb
.dirInfo
.ioDrUsrWds
= *fndrInfo
;
1522 error
= PBSetCatInfoSync(&pb
);
1526 /* oops, a file was passed */
1534 /*****************************************************************************/
1536 pascal OSErr
FSpSetDInfo(const FSSpec
*spec
,
1537 const DInfo
*fndrInfo
)
1539 return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1542 /*****************************************************************************/
1544 pascal OSErr
GetDirectoryID(short vRefNum
,
1546 ConstStr255Param name
,
1548 Boolean
*isDirectory
)
1553 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1554 if ( error
== noErr
)
1556 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1559 *theDirID
= pb
.dirInfo
.ioDrDirID
;
1563 *theDirID
= pb
.hFileInfo
.ioFlParID
;
1570 /*****************************************************************************/
1572 pascal OSErr
FSpGetDirectoryID(const FSSpec
*spec
,
1574 Boolean
*isDirectory
)
1576 return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
,
1577 theDirID
, isDirectory
) );
1580 /*****************************************************************************/
1582 pascal OSErr
GetDirName(short vRefNum
,
1591 pb
.dirInfo
.ioNamePtr
= name
;
1592 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1593 pb
.dirInfo
.ioDrDirID
= dirID
;
1594 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1595 error
= PBGetCatInfoSync(&pb
);
1605 /*****************************************************************************/
1607 pascal OSErr
GetIOACUser(short vRefNum
,
1609 ConstStr255Param name
,
1615 /* Clear ioACUser before calling PBGetCatInfo since some file systems
1616 ** don't bother to set or clear this field. If ioACUser isn't set by the
1617 ** file system, then you'll get the zero value back (full access) which
1618 ** is the access you have on volumes that don't support ioACUser.
1620 pb
.dirInfo
.ioACUser
= 0; /* ioACUser used to be filler2 */
1621 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1622 if ( error
== noErr
)
1624 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 )
1626 /* oops, a file was passed */
1631 *ioACUser
= pb
.dirInfo
.ioACUser
;
1638 /*****************************************************************************/
1640 pascal OSErr
FSpGetIOACUser(const FSSpec
*spec
,
1643 return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) );
1646 /*****************************************************************************/
1648 pascal OSErr
GetParentID(short vRefNum
,
1650 ConstStr255Param name
,
1658 /* Protection against File Sharing problem */
1659 if ( (name
== NULL
) || (name
[0] == 0) )
1662 pb
.hFileInfo
.ioNamePtr
= tempName
;
1663 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1667 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
1668 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1670 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1671 pb
.hFileInfo
.ioDirID
= dirID
;
1672 error
= PBGetCatInfoSync(&pb
);
1673 if ( error
== noErr
)
1676 ** There's a bug in HFS where the wrong parent dir ID can be
1677 ** returned if multiple separators are used at the end of a
1678 ** pathname. For example, if the pathname:
1679 ** 'volumeName:System Folder:Extensions::'
1680 ** is passed, the directory ID of the Extensions folder is
1681 ** returned in the ioFlParID field instead of fsRtDirID. Since
1682 ** multiple separators at the end of a pathname always specifies
1683 ** a directory, we only need to work-around cases where the
1684 ** object is a directory and there are multiple separators at
1685 ** the end of the name parameter.
1687 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1689 /* Its a directory */
1691 /* is there a pathname? */
1692 if ( pb
.hFileInfo
.ioNamePtr
== name
)
1694 /* could it contain multiple separators? */
1697 /* does it contain multiple separators at the end? */
1698 if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') )
1700 /* OK, then do the extra stuff to get the correct parID */
1702 /* Get the real vRefNum (this should not fail) */
1703 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
1704 if ( error
== noErr
)
1706 /* we don't need the parent's name, but add protect against File Sharing problem */
1708 pb
.dirInfo
.ioNamePtr
= tempName
;
1709 pb
.dirInfo
.ioVRefNum
= realVRefNum
;
1710 /* pb.dirInfo.ioDrDirID already contains the */
1711 /* dirID of the directory object */
1712 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1713 error
= PBGetCatInfoSync(&pb
);
1714 /* now, pb.dirInfo.ioDrParID contains the correct parID */
1721 if ( error
== noErr
)
1723 /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
1724 /* contains the parent ID */
1725 *parID
= pb
.hFileInfo
.ioFlParID
;
1732 /*****************************************************************************/
1734 pascal OSErr
GetFilenameFromPathname(ConstStr255Param pathname
,
1741 /* default to no filename */
1744 /* check for no pathname */
1745 if ( pathname
!= NULL
)
1747 /* get string length */
1748 index
= pathname
[0];
1750 /* check for empty string */
1753 /* skip over last trailing colon (if any) */
1754 if ( pathname
[index
] == ':' )
1759 /* save the end of the string */
1762 /* if pathname ends with multiple colons, then this pathname refers */
1763 /* to a directory, not a file */
1764 if ( pathname
[index
] != ':' )
1766 /* parse backwards until we find a colon or hit the beginning of the pathname */
1767 while ( (index
!= 0) && (pathname
[index
] != ':') )
1772 /* if we parsed to the beginning of the pathname and the pathname ended */
1773 /* with a colon, then pathname is a full pathname to a volume, not a file */
1774 if ( (index
!= 0) || (pathname
[pathname
[0]] != ':') )
1776 /* get the filename and return noErr */
1777 filename
[0] = (char)(nameEnd
- index
);
1778 BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd
- index
);
1783 /* pathname to a volume, not a file */
1784 error
= notAFileErr
;
1789 /* directory, not a file */
1790 error
= notAFileErr
;
1795 /* empty string isn't a file */
1796 error
= notAFileErr
;
1801 /* NULL pathname isn't a file */
1802 error
= notAFileErr
;
1808 /*****************************************************************************/
1810 pascal OSErr
GetObjectLocation(short vRefNum
,
1812 ConstStr255Param pathname
,
1816 Boolean
*isDirectory
)
1820 Str255 tempPathname
;
1828 ** Get the real vRefNum
1830 error
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
);
1831 if ( error
== noErr
)
1834 ** Determine if the object already exists and if so,
1835 ** get the real parent directory ID if it's a file
1838 /* Protection against File Sharing problem */
1839 if ( (pathname
== NULL
) || (pathname
[0] == 0) )
1841 tempPathname
[0] = 0;
1842 pb
.hFileInfo
.ioNamePtr
= tempPathname
;
1843 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1847 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)pathname
;
1848 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1850 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1851 pb
.hFileInfo
.ioDirID
= dirID
;
1852 error
= PBGetCatInfoSync(&pb
);
1853 if ( error
== noErr
)
1856 ** The file system object is present and we have the file's real parID
1859 /* Is it a directory or a file? */
1860 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1864 ** It's a directory, get its name and parent dirID, and then we're done
1867 pb
.dirInfo
.ioNamePtr
= realName
;
1868 pb
.dirInfo
.ioVRefNum
= *realVRefNum
;
1869 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
1870 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1871 error
= PBGetCatInfoSync(&pb
);
1873 /* get the parent ID here, because the file system can return the */
1874 /* wrong parent ID from the last call. */
1875 *realParID
= pb
.dirInfo
.ioDrParID
;
1880 ** It's a file - use the parent directory ID from the last call
1881 ** to GetCatInfoparse, get the file name, and then we're done
1883 *realParID
= pb
.hFileInfo
.ioFlParID
;
1884 error
= GetFilenameFromPathname(pathname
, realName
);
1887 else if ( error
== fnfErr
)
1890 ** The file system object is not present - see if its parent is present
1894 ** Parse to get the object name from end of pathname
1896 error
= GetFilenameFromPathname(pathname
, realName
);
1898 /* if we can't get the object name from the end, we can't continue */
1899 if ( error
== noErr
)
1902 ** What we want now is the pathname minus the object name
1904 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
1905 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
1906 ** if pathname is ':dir:file' tempPathname becomes ':dir:'
1907 ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
1908 ** if pathname is ':file' tempPathname becomes ':'
1909 ** if pathname is 'file or file:' tempPathname becomes ''
1912 /* get a copy of the pathname */
1913 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1);
1915 /* remove the object name */
1916 tempPathname
[0] -= realName
[0];
1917 /* and the trailing colon (if any) */
1918 if ( pathname
[pathname
[0]] == ':' )
1923 /* OK, now get the parent's directory ID */
1925 /* Protection against File Sharing problem */
1926 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)tempPathname
;
1927 if ( tempPathname
[0] != 0 )
1929 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1933 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1935 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1936 pb
.hFileInfo
.ioDirID
= dirID
;
1937 error
= PBGetCatInfoSync(&pb
);
1938 *realParID
= pb
.dirInfo
.ioDrDirID
;
1940 *isDirectory
= false; /* we don't know what the object is really going to be */
1943 if ( error
!= noErr
)
1945 error
= dirNFErr
; /* couldn't find parent directory */
1949 error
= fnfErr
; /* we found the parent, but not the file */
1957 /*****************************************************************************/
1959 pascal OSErr
GetDirItems(short vRefNum
,
1961 ConstStr255Param name
,
1963 Boolean getDirectories
,
1966 short *actItemCount
,
1967 short *itemIndex
) /* start with 1, then use what's returned */
1972 Boolean isDirectory
;
1973 FSSpec
*endItemsArray
;
1975 if ( *itemIndex
> 0 )
1977 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
1978 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
1979 /* routine would be much faster because of the overhead of DetermineVRefNum and */
1980 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
1981 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
1982 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
1983 /* to this routine. */
1985 /* get the real volume reference number */
1986 error
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
);
1987 if ( error
== noErr
)
1989 /* and the real directory ID of this directory (and make sure it IS a directory) */
1990 error
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
);
1991 if ( error
== noErr
)
1996 endItemsArray
= items
+ reqItemCount
;
1997 while ( (items
< endItemsArray
) && (error
== noErr
) )
1999 pb
.hFileInfo
.ioNamePtr
= (StringPtr
) &items
->name
;
2000 pb
.hFileInfo
.ioDirID
= theDirID
;
2001 pb
.hFileInfo
.ioFDirIndex
= *itemIndex
;
2002 error
= PBGetCatInfoSync(&pb
);
2003 if ( error
== noErr
)
2005 items
->parID
= pb
.hFileInfo
.ioFlParID
; /* return item's parID */
2006 items
->vRefNum
= pb
.hFileInfo
.ioVRefNum
; /* return item's vRefNum */
2007 ++*itemIndex
; /* prepare to get next item in directory */
2009 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2011 if ( getDirectories
)
2013 ++*actItemCount
; /* keep this item */
2014 ++items
; /* point to next item */
2021 ++*actItemCount
; /* keep this item */
2022 ++items
; /* point to next item */
2030 /* it wasn't a directory */
2045 /*****************************************************************************/
2047 static void DeleteLevel(long dirToDelete
,
2048 DeleteEnumGlobalsPtr theGlobals
)
2054 /* prepare to delete directory */
2055 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= (StringPtr
)&theGlobals
->itemName
;
2056 theGlobals
->myPB
.ciPB
.dirInfo
.ioFDirIndex
= 1; /* get first item */
2057 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= dirToDelete
; /* in this directory */
2058 theGlobals
->error
= PBGetCatInfoSync(&(theGlobals
->myPB
.ciPB
));
2059 if ( theGlobals
->error
== noErr
)
2061 savedDir
= dirToDelete
;
2062 /* We have an item. Is it a file or directory? */
2063 if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2065 /* it's a directory */
2066 savedDir
= theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
; /* save dirID of directory instead */
2067 DeleteLevel(theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
, theGlobals
); /* Delete its contents */
2068 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= NULL
; /* prepare to delete directory */
2070 if ( theGlobals
->error
== noErr
)
2072 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= savedDir
; /* restore dirID */
2073 theGlobals
->myPB
.hPB
.fileParam
.ioFVersNum
= 0; /* just in case it's used on an MFS volume... */
2074 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* delete this item */
2075 if ( theGlobals
->error
== fLckdErr
)
2077 (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
)); /* unlock it */
2078 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* and try again */
2082 } while ( theGlobals
->error
== noErr
);
2084 if ( theGlobals
->error
== fnfErr
)
2086 theGlobals
->error
= noErr
;
2090 /*****************************************************************************/
2092 pascal OSErr
DeleteDirectoryContents(short vRefNum
,
2094 ConstStr255Param name
)
2096 DeleteEnumGlobals theGlobals
;
2097 Boolean isDirectory
;
2100 /* Get the real dirID and make sure it is a directory. */
2101 error
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
);
2102 if ( error
== noErr
)
2106 /* Get the real vRefNum */
2107 error
= DetermineVRefNum(name
, vRefNum
, &vRefNum
);
2108 if ( error
== noErr
)
2110 /* Set up the globals we need to access from the recursive routine. */
2111 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum
= vRefNum
;
2113 /* Here we go into recursion land... */
2114 DeleteLevel(dirID
, &theGlobals
);
2115 error
= theGlobals
.error
;
2127 /*****************************************************************************/
2129 pascal OSErr
DeleteDirectory(short vRefNum
,
2131 ConstStr255Param name
)
2135 /* Make sure a directory was specified and then delete its contents */
2136 error
= DeleteDirectoryContents(vRefNum
, dirID
, name
);
2137 if ( error
== noErr
)
2139 error
= HDelete(vRefNum
, dirID
, name
);
2140 if ( error
== fLckdErr
)
2142 (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */
2143 error
= HDelete(vRefNum
, dirID
, name
); /* and try again */
2150 /*****************************************************************************/
2152 pascal OSErr
CheckObjectLock(short vRefNum
,
2154 ConstStr255Param name
)
2159 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
2160 if ( error
== noErr
)
2162 /* check locked bit */
2163 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0 )
2172 /*****************************************************************************/
2174 pascal OSErr
FSpCheckObjectLock(const FSSpec
*spec
)
2176 return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2179 /*****************************************************************************/
2181 pascal OSErr
GetFileSize(short vRefNum
,
2183 ConstStr255Param fileName
,
2190 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2191 pb
.fileParam
.ioVRefNum
= vRefNum
;
2192 pb
.fileParam
.ioFVersNum
= 0;
2193 pb
.fileParam
.ioDirID
= dirID
;
2194 pb
.fileParam
.ioFDirIndex
= 0;
2195 error
= PBHGetFInfoSync(&pb
);
2196 if ( error
== noErr
)
2198 *dataSize
= pb
.fileParam
.ioFlLgLen
;
2199 *rsrcSize
= pb
.fileParam
.ioFlRLgLen
;
2205 /*****************************************************************************/
2207 pascal OSErr
FSpGetFileSize(const FSSpec
*spec
,
2211 return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) );
2214 /*****************************************************************************/
2216 pascal OSErr
BumpDate(short vRefNum
,
2218 ConstStr255Param name
)
2219 /* Given a file or directory, change its modification date to the current date/time. */
2226 /* Protection against File Sharing problem */
2227 if ( (name
== NULL
) || (name
[0] == 0) )
2230 pb
.hFileInfo
.ioNamePtr
= tempName
;
2231 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2235 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2236 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2238 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2239 pb
.hFileInfo
.ioDirID
= dirID
;
2240 error
= PBGetCatInfoSync(&pb
);
2241 if ( error
== noErr
)
2244 /* set mod date to current date, or one second into the future
2245 if mod date = current date */
2246 pb
.hFileInfo
.ioFlMdDat
= (secs
== pb
.hFileInfo
.ioFlMdDat
) ? (++secs
) : (secs
);
2247 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2249 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2253 pb
.hFileInfo
.ioDirID
= dirID
;
2255 error
= PBSetCatInfoSync(&pb
);
2261 /*****************************************************************************/
2263 pascal OSErr
FSpBumpDate(const FSSpec
*spec
)
2265 return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2268 /*****************************************************************************/
2270 pascal OSErr
ChangeCreatorType(short vRefNum
,
2272 ConstStr255Param name
,
2281 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2282 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2283 pb
.hFileInfo
.ioDirID
= dirID
;
2284 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2285 error
= PBGetCatInfoSync(&pb
);
2286 if ( error
== noErr
)
2288 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 ) /* if file */
2290 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2292 /* If creator not 0x00000000, change creator */
2293 if ( creator
!= (OSType
)0x00000000 )
2295 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
= creator
;
2298 /* If fileType not 0x00000000, change fileType */
2299 if ( fileType
!= (OSType
)0x00000000 )
2301 pb
.hFileInfo
.ioFlFndrInfo
.fdType
= fileType
;
2304 pb
.hFileInfo
.ioDirID
= dirID
;
2305 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2307 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2309 /* get the real vRefNum in case a full pathname was passed */
2310 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2311 if ( error
== noErr
)
2313 error
= BumpDate(realVRefNum
, parID
, NULL
);
2314 /* and bump the parent directory's mod date to wake up the Finder */
2315 /* to the change we just made */
2321 /* it was a directory, not a file */
2322 error
= notAFileErr
;
2329 /*****************************************************************************/
2331 pascal OSErr
FSpChangeCreatorType(const FSSpec
*spec
,
2335 return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) );
2338 /*****************************************************************************/
2340 pascal OSErr
ChangeFDFlags(short vRefNum
,
2342 ConstStr255Param name
,
2344 unsigned short flagBits
)
2352 /* Protection against File Sharing problem */
2353 if ( (name
== NULL
) || (name
[0] == 0) )
2356 pb
.hFileInfo
.ioNamePtr
= tempName
;
2357 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2361 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2362 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2364 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2365 pb
.hFileInfo
.ioDirID
= dirID
;
2366 error
= PBGetCatInfoSync(&pb
);
2367 if ( error
== noErr
)
2369 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2371 /* set or clear the appropriate bits in the Finder flags */
2374 /* OR in the bits */
2375 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
|= flagBits
;
2379 /* AND out the bits */
2380 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
&= ~flagBits
;
2383 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2385 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2389 pb
.hFileInfo
.ioDirID
= dirID
;
2392 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2394 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2396 /* get the real vRefNum in case a full pathname was passed */
2397 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2398 if ( error
== noErr
)
2400 error
= BumpDate(realVRefNum
, parID
, NULL
);
2401 /* and bump the parent directory's mod date to wake up the Finder */
2402 /* to the change we just made */
2410 /*****************************************************************************/
2412 pascal OSErr
FSpChangeFDFlags(const FSSpec
*spec
,
2414 unsigned short flagBits
)
2416 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) );
2419 /*****************************************************************************/
2421 pascal OSErr
SetIsInvisible(short vRefNum
,
2423 ConstStr255Param name
)
2424 /* Given a file or directory, make it invisible. */
2426 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) );
2429 /*****************************************************************************/
2431 pascal OSErr
FSpSetIsInvisible(const FSSpec
*spec
)
2432 /* Given a file or directory, make it invisible. */
2434 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) );
2437 /*****************************************************************************/
2439 pascal OSErr
ClearIsInvisible(short vRefNum
,
2441 ConstStr255Param name
)
2442 /* Given a file or directory, make it visible. */
2444 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) );
2447 /*****************************************************************************/
2449 pascal OSErr
FSpClearIsInvisible(const FSSpec
*spec
)
2450 /* Given a file or directory, make it visible. */
2452 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) );
2455 /*****************************************************************************/
2457 pascal OSErr
SetNameLocked(short vRefNum
,
2459 ConstStr255Param name
)
2460 /* Given a file or directory, lock its name. */
2462 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) );
2465 /*****************************************************************************/
2467 pascal OSErr
FSpSetNameLocked(const FSSpec
*spec
)
2468 /* Given a file or directory, lock its name. */
2470 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) );
2473 /*****************************************************************************/
2475 pascal OSErr
ClearNameLocked(short vRefNum
,
2477 ConstStr255Param name
)
2478 /* Given a file or directory, unlock its name. */
2480 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) );
2483 /*****************************************************************************/
2485 pascal OSErr
FSpClearNameLocked(const FSSpec
*spec
)
2486 /* Given a file or directory, unlock its name. */
2488 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) );
2491 /*****************************************************************************/
2493 pascal OSErr
SetIsStationery(short vRefNum
,
2495 ConstStr255Param name
)
2496 /* Given a file, make it a stationery pad. */
2498 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) );
2501 /*****************************************************************************/
2503 pascal OSErr
FSpSetIsStationery(const FSSpec
*spec
)
2504 /* Given a file, make it a stationery pad. */
2506 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) );
2509 /*****************************************************************************/
2511 pascal OSErr
ClearIsStationery(short vRefNum
,
2513 ConstStr255Param name
)
2514 /* Given a file, clear the stationery bit. */
2516 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) );
2519 /*****************************************************************************/
2521 pascal OSErr
FSpClearIsStationery(const FSSpec
*spec
)
2522 /* Given a file, clear the stationery bit. */
2524 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) );
2527 /*****************************************************************************/
2529 pascal OSErr
SetHasCustomIcon(short vRefNum
,
2531 ConstStr255Param name
)
2532 /* Given a file or directory, indicate that it has a custom icon. */
2534 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) );
2537 /*****************************************************************************/
2539 pascal OSErr
FSpSetHasCustomIcon(const FSSpec
*spec
)
2540 /* Given a file or directory, indicate that it has a custom icon. */
2542 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) );
2545 /*****************************************************************************/
2547 pascal OSErr
ClearHasCustomIcon(short vRefNum
,
2549 ConstStr255Param name
)
2550 /* Given a file or directory, indicate that it does not have a custom icon. */
2552 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) );
2555 /*****************************************************************************/
2557 pascal OSErr
FSpClearHasCustomIcon(const FSSpec
*spec
)
2558 /* Given a file or directory, indicate that it does not have a custom icon. */
2560 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) );
2563 /*****************************************************************************/
2565 pascal OSErr
ClearHasBeenInited(short vRefNum
,
2567 ConstStr255Param name
)
2568 /* Given a file, clear its "has been inited" bit. */
2570 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) );
2573 /*****************************************************************************/
2575 pascal OSErr
FSpClearHasBeenInited(const FSSpec
*spec
)
2576 /* Given a file, clear its "has been inited" bit. */
2578 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) );
2581 /*****************************************************************************/
2583 pascal OSErr
CopyFileMgrAttributes(short srcVRefNum
,
2585 ConstStr255Param srcName
,
2588 ConstStr255Param dstName
,
2589 Boolean copyLockBit
)
2594 Boolean objectIsDirectory
;
2596 pb
.ciPB
.hFileInfo
.ioVRefNum
= srcVRefNum
;
2597 pb
.ciPB
.hFileInfo
.ioDirID
= srcDirID
;
2599 /* Protection against File Sharing problem */
2600 if ( (srcName
== NULL
) || (srcName
[0] == 0) )
2603 pb
.ciPB
.hFileInfo
.ioNamePtr
= tempName
;
2604 pb
.ciPB
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2608 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)srcName
;
2609 pb
.ciPB
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2611 error
= PBGetCatInfoSync(&pb
.ciPB
);
2612 if ( error
== noErr
)
2614 objectIsDirectory
= ( (pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 );
2615 pb
.ciPB
.hFileInfo
.ioVRefNum
= dstVRefNum
;
2616 pb
.ciPB
.hFileInfo
.ioDirID
= dstDirID
;
2617 if ( (dstName
!= NULL
) && (dstName
[0] == 0) )
2619 pb
.ciPB
.hFileInfo
.ioNamePtr
= NULL
;
2623 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)dstName
;
2625 /* don't copy the hasBeenInited bit */
2626 pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
= ( pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
& ~kHasBeenInited
);
2627 error
= PBSetCatInfoSync(&pb
.ciPB
);
2628 if ( (error
== noErr
) && (copyLockBit
) && ((pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0) )
2630 pb
.hPB
.fileParam
.ioFVersNum
= 0;
2631 error
= PBHSetFLockSync(&pb
.hPB
);
2632 if ( (error
!= noErr
) && (objectIsDirectory
) )
2634 error
= noErr
; /* ignore lock errors if destination is directory */
2641 /*****************************************************************************/
2643 pascal OSErr
FSpCopyFileMgrAttributes(const FSSpec
*srcSpec
,
2644 const FSSpec
*dstSpec
,
2645 Boolean copyLockBit
)
2647 return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
2648 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
,
2652 /*****************************************************************************/
2654 pascal OSErr
HOpenAware(short vRefNum
,
2656 ConstStr255Param fileName
,
2662 GetVolParmsInfoBuffer volParmsInfo
;
2663 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2665 pb
.ioParam
.ioMisc
= NULL
;
2666 pb
.fileParam
.ioFVersNum
= 0;
2667 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2668 pb
.fileParam
.ioVRefNum
= vRefNum
;
2669 pb
.fileParam
.ioDirID
= dirID
;
2671 /* get volume attributes */
2672 /* this preflighting is needed because Foreign File Access based file systems don't */
2673 /* return the correct error result to the OpenDeny call */
2674 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2675 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2677 /* if volume supports OpenDeny, use it and return */
2678 pb
.accessParam
.ioDenyModes
= denyModes
;
2679 error
= PBHOpenDenySync(&pb
);
2680 *refNum
= pb
.ioParam
.ioRefNum
;
2682 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2684 /* OpenDeny isn't supported, so try File Manager Open functions */
2686 /* If request includes write permission, then see if the volume is */
2687 /* locked by hardware or software. The HFS file system doesn't check */
2688 /* for this when a file is opened - you only find out later when you */
2689 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2691 if ( (denyModes
& dmWr
) != 0 )
2693 error
= CheckVolLock(fileName
, vRefNum
);
2700 if ( error
== noErr
)
2702 /* Set File Manager permissions to closest thing possible */
2703 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2705 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2709 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2712 error
= PBHOpenDFSync(&pb
); /* Try OpenDF */
2713 if ( error
== paramErr
)
2715 error
= PBHOpenSync(&pb
); /* OpenDF not supported, so try Open */
2717 *refNum
= pb
.ioParam
.ioRefNum
;
2724 /*****************************************************************************/
2726 pascal OSErr
FSpOpenAware(const FSSpec
*spec
,
2730 return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2733 /*****************************************************************************/
2735 pascal OSErr
HOpenRFAware(short vRefNum
,
2737 ConstStr255Param fileName
,
2743 GetVolParmsInfoBuffer volParmsInfo
;
2744 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2746 pb
.ioParam
.ioMisc
= NULL
;
2747 pb
.fileParam
.ioFVersNum
= 0;
2748 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2749 pb
.fileParam
.ioVRefNum
= vRefNum
;
2750 pb
.fileParam
.ioDirID
= dirID
;
2752 /* get volume attributes */
2753 /* this preflighting is needed because Foreign File Access based file systems don't */
2754 /* return the correct error result to the OpenRFDeny call */
2755 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2756 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2758 /* if volume supports OpenRFDeny, use it and return */
2759 if ( hasOpenDeny(&volParmsInfo
) )
2761 pb
.accessParam
.ioDenyModes
= denyModes
;
2762 error
= PBHOpenRFDenySync(&pb
);
2763 *refNum
= pb
.ioParam
.ioRefNum
;
2766 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2768 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
2770 /* If request includes write permission, then see if the volume is */
2771 /* locked by hardware or software. The HFS file system doesn't check */
2772 /* for this when a file is opened - you only find out later when you */
2773 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2775 if ( (denyModes
& dmWr
) != 0 )
2777 error
= CheckVolLock(fileName
, vRefNum
);
2784 if ( error
== noErr
)
2786 /* Set File Manager permissions to closest thing possible */
2787 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2789 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2793 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2796 error
= PBHOpenRFSync(&pb
);
2797 *refNum
= pb
.ioParam
.ioRefNum
;
2804 /*****************************************************************************/
2806 pascal OSErr
FSpOpenRFAware(const FSSpec
*spec
,
2810 return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2813 /*****************************************************************************/
2815 pascal OSErr
FSReadNoCache(short refNum
,
2822 pb
.ioParam
.ioRefNum
= refNum
;
2823 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2824 pb
.ioParam
.ioReqCount
= *count
;
2825 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2826 pb
.ioParam
.ioPosOffset
= 0;
2827 error
= PBReadSync(&pb
);
2828 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2832 /*****************************************************************************/
2834 pascal OSErr
FSWriteNoCache(short refNum
,
2836 const void *buffPtr
)
2841 pb
.ioParam
.ioRefNum
= refNum
;
2842 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2843 pb
.ioParam
.ioReqCount
= *count
;
2844 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2845 pb
.ioParam
.ioPosOffset
= 0;
2846 error
= PBWriteSync(&pb
);
2847 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2851 /*****************************************************************************/
2854 ** See if numBytes bytes of buffer1 are equal to buffer2.
2856 static Boolean
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
)
2858 register unsigned char *b1
= (unsigned char *)buffer1
;
2859 register unsigned char *b2
= (unsigned char *)buffer2
;
2861 if ( b1
!= b2
) /* if buffer pointers are same, then they are equal */
2863 while ( numBytes
> 0 )
2865 /* compare the bytes and then increment the pointers */
2866 if ( (*b1
++ - *b2
++) != 0 )
2877 /*****************************************************************************/
2880 ** Read any number of bytes from an open file using read-verify mode.
2881 ** The FSReadVerify function reads any number of bytes from an open file
2882 ** and verifies them against the data in the buffer pointed to by buffPtr.
2884 ** Because of a bug in the HFS file system, only non-block aligned parts of
2885 ** the read are verified against the buffer data and the rest is *copied*
2886 ** into the buffer. Thus, you shouldn't verify against your original data;
2887 ** instead, you should verify against a copy of the original data and then
2888 ** compare the read-verified copy against the original data after calling
2889 ** FSReadVerify. That's why this function isn't exported - it needs the
2890 ** wrapper provided by FSWriteVerify.
2892 static OSErr
FSReadVerify(short refNum
,
2899 pb
.ioParam
.ioRefNum
= refNum
;
2900 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2901 pb
.ioParam
.ioReqCount
= *count
;
2902 pb
.ioParam
.ioPosMode
= fsAtMark
+ rdVerify
;
2903 pb
.ioParam
.ioPosOffset
= 0;
2904 result
= PBReadSync(&pb
);
2905 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2909 /*****************************************************************************/
2911 pascal OSErr
FSWriteVerify(short refNum
,
2913 const void *buffPtr
)
2924 ** Allocate the verify buffer
2925 ** Try to get get a large enough buffer to verify in one pass.
2926 ** If that fails, use GetTempBuffer to get a buffer.
2928 bufferSize
= *count
;
2929 verifyBuffer
= NewPtr(bufferSize
);
2930 if ( verifyBuffer
== NULL
)
2932 verifyBuffer
= GetTempBuffer(bufferSize
, &bufferSize
);
2934 if ( verifyBuffer
!= NULL
)
2936 /* Save the current position */
2937 result
= GetFPos(refNum
, &position
);
2938 if ( result
== noErr
)
2940 /* Write the data */
2941 result
= FSWrite(refNum
, count
, buffPtr
);
2942 if ( result
== noErr
)
2944 /* Restore the original position */
2945 result
= SetFPos(refNum
, fsFromStart
, position
);
2946 if ( result
== noErr
)
2949 ** *count = total number of bytes to verify
2950 ** bufferSize = the size of the verify buffer
2951 ** bytesVerified = number of bytes verified
2952 ** byteCount = number of bytes to verify this pass
2953 ** startVerify = position in buffPtr
2956 startVerify
= (Ptr
)buffPtr
;
2957 while ( (bytesVerified
< *count
) && ( result
== noErr
) )
2959 if ( (*count
- bytesVerified
) > bufferSize
)
2961 byteCount
= bufferSize
;
2965 byteCount
= *count
- bytesVerified
;
2968 ** Copy the write buffer into the verify buffer.
2969 ** This step is needed because the File Manager
2970 ** compares the data in any non-block aligned
2971 ** data at the beginning and end of the read-verify
2972 ** request back into the file system's cache
2973 ** to the data in verify Buffer. However, the
2974 ** File Manager does not compare any full blocks
2975 ** and instead copies them into the verify buffer
2976 ** so we still have to compare the buffers again
2977 ** after the read-verify request completes.
2979 BlockMoveData(startVerify
, verifyBuffer
, byteCount
);
2981 /* Read-verify the data back into the verify buffer */
2982 result
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
);
2983 if ( result
== noErr
)
2985 /* See if the buffers are the same */
2986 if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) )
2990 startVerify
+= byteCount
;
2991 bytesVerified
+= byteCount
;
2997 DisposePtr(verifyBuffer
);
3001 result
= memFullErr
;
3006 /*****************************************************************************/
3008 pascal OSErr
CopyFork(short srcRefNum
,
3010 void *copyBufferPtr
,
3011 long copyBufferSize
)
3013 ParamBlockRec srcPB
;
3014 ParamBlockRec dstPB
;
3018 if ( (copyBufferPtr
== NULL
) || (copyBufferSize
== 0) )
3019 return ( paramErr
);
3021 srcPB
.ioParam
.ioRefNum
= srcRefNum
;
3022 dstPB
.ioParam
.ioRefNum
= dstRefNum
;
3024 /* preallocate the destination fork and */
3025 /* ensure the destination fork's EOF is correct after the copy */
3026 srcError
= PBGetEOFSync(&srcPB
);
3027 if ( srcError
!= noErr
)
3028 return ( srcError
);
3029 dstPB
.ioParam
.ioMisc
= srcPB
.ioParam
.ioMisc
;
3030 dstError
= PBSetEOFSync(&dstPB
);
3031 if ( dstError
!= noErr
)
3032 return ( dstError
);
3034 /* reset source fork's mark */
3035 srcPB
.ioParam
.ioPosMode
= fsFromStart
;
3036 srcPB
.ioParam
.ioPosOffset
= 0;
3037 srcError
= PBSetFPosSync(&srcPB
);
3038 if ( srcError
!= noErr
)
3039 return ( srcError
);
3041 /* reset destination fork's mark */
3042 dstPB
.ioParam
.ioPosMode
= fsFromStart
;
3043 dstPB
.ioParam
.ioPosOffset
= 0;
3044 dstError
= PBSetFPosSync(&dstPB
);
3045 if ( dstError
!= noErr
)
3046 return ( dstError
);
3048 /* set up fields that won't change in the loop */
3049 srcPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3050 srcPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3051 /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
3052 /* This will make writes on local volumes faster */
3053 if ( (copyBufferSize
>= 512) && ((copyBufferSize
& 0x1ff) != 0) )
3055 srcPB
.ioParam
.ioReqCount
= copyBufferSize
& 0xfffffe00;
3059 srcPB
.ioParam
.ioReqCount
= copyBufferSize
;
3061 dstPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3062 dstPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3064 while ( (srcError
== noErr
) && (dstError
== noErr
) )
3066 srcError
= PBReadSync(&srcPB
);
3067 dstPB
.ioParam
.ioReqCount
= srcPB
.ioParam
.ioActCount
;
3068 dstError
= PBWriteSync(&dstPB
);
3071 /* make sure there were no errors at the destination */
3072 if ( dstError
!= noErr
)
3073 return ( dstError
);
3075 /* make sure the only error at the source was eofErr */
3076 if ( srcError
!= eofErr
)
3077 return ( srcError
);
3082 /*****************************************************************************/
3084 pascal OSErr
GetFileLocation(short refNum
,
3092 pb
.ioNamePtr
= fileName
;
3094 pb
.ioRefNum
= refNum
;
3096 error
= PBGetFCBInfoSync(&pb
);
3097 if ( error
== noErr
)
3099 *vRefNum
= pb
.ioFCBVRefNum
;
3100 *dirID
= pb
.ioFCBParID
;
3105 /*****************************************************************************/
3107 pascal OSErr
FSpGetFileLocation(short refNum
,
3110 return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) );
3113 /*****************************************************************************/
3115 pascal OSErr
CopyDirectoryAccess(short srcVRefNum
,
3117 ConstStr255Param srcName
,
3120 ConstStr255Param dstName
)
3123 GetVolParmsInfoBuffer infoBuffer
; /* Where PBGetVolParms dumps its info */
3124 long dstServerAdr
; /* AppleTalk server address of destination (if any) */
3125 long ownerID
, groupID
, accessRights
;
3128 /* See if destination supports directory access control */
3129 tempLong
= sizeof(infoBuffer
);
3130 error
= HGetVolParms(dstName
, dstVRefNum
, &infoBuffer
, &tempLong
);
3131 if ( (error
== noErr
) && hasAccessCntl(&infoBuffer
) )
3133 if ( hasAccessCntl(&infoBuffer
) )
3135 dstServerAdr
= infoBuffer
.vMServerAdr
;
3137 /* See if source supports directory access control and is on same server */
3138 tempLong
= sizeof(infoBuffer
);
3139 error
= HGetVolParms(srcName
, srcVRefNum
, &infoBuffer
, &tempLong
);
3140 if ( error
== noErr
)
3142 if ( hasAccessCntl(&infoBuffer
) && (dstServerAdr
== infoBuffer
.vMServerAdr
) )
3144 /* both volumes support directory access control and they are */
3145 /* on same server, so copy the access information */
3146 error
= HGetDirAccess(srcVRefNum
, srcDirID
, srcName
, &ownerID
, &groupID
, &accessRights
);
3147 if ( error
== noErr
)
3149 error
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
);
3154 /* destination doesn't support directory access control or */
3155 /* they volumes aren't on the same server */
3162 /* destination doesn't support directory access control */
3170 /*****************************************************************************/
3172 pascal OSErr
FSpCopyDirectoryAccess(const FSSpec
*srcSpec
,
3173 const FSSpec
*dstSpec
)
3175 return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3176 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) );
3179 /*****************************************************************************/
3181 pascal OSErr
HMoveRenameCompat(short vRefNum
,
3183 ConstStr255Param srcName
,
3185 ConstStr255Param dstpathName
,
3186 ConstStr255Param copyName
)
3189 GetVolParmsInfoBuffer volParmsInfo
;
3194 Boolean isDirectory
;
3195 long tempItemsDirID
;
3196 long uniqueTempDirID
;
3197 Str31 uniqueTempDirName
;
3198 unsigned short uniqueNameoverflow
;
3200 /* Get volume attributes */
3201 infoSize
= sizeof(GetVolParmsInfoBuffer
);
3202 error
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
);
3203 if ( (error
== noErr
) && hasMoveRename(&volParmsInfo
) )
3205 /* If volume supports move and rename, so use it and return */
3206 error
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
);
3208 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
3210 /* MoveRename isn't supported by this volume, so do it by hand */
3212 /* If copyName isn't supplied, we can simply CatMove and return */
3213 if ( copyName
== NULL
)
3215 error
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
);
3219 /* Renaming is required, so we have some work to do... */
3221 /* Get the object's real name, real parent ID and real vRefNum */
3222 error
= GetObjectLocation(vRefNum
, srcDirID
, (StringPtr
)srcName
,
3223 &realVRefNum
, &realParID
, realName
, &isDirectory
);
3224 if ( error
== noErr
)
3226 /* Find the Temporary Items Folder on that volume */
3227 error
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
,
3228 &realVRefNum
, &tempItemsDirID
);
3229 if ( error
== noErr
)
3231 /* Create a new uniquely named folder in the temporary items folder. */
3232 /* This is done to avoid the case where 'realName' or 'copyName' already */
3233 /* exists in the temporary items folder. */
3235 /* Start with current tick count as uniqueTempDirName */
3236 NumToString(TickCount(), uniqueTempDirName
);
3237 uniqueNameoverflow
= 0;
3240 error
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
);
3241 if ( error
== dupFNErr
)
3243 /* Duplicate name - change the first character to the next ASCII character */
3244 ++uniqueTempDirName
[1];
3245 /* Make sure it isn't a colon! */
3246 if ( uniqueTempDirName
[1] == ':' )
3248 ++uniqueTempDirName
[1];
3250 /* Don't go too far... */
3251 ++uniqueNameoverflow
;
3253 } while ( (error
== dupFNErr
) && (uniqueNameoverflow
<= 64) ); /* 64 new files per 1/60th second - not likely! */
3254 if ( error
== noErr
)
3256 /* Move the object to the folder with uniqueTempDirID for renaming */
3257 error
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
);
3258 if ( error
== noErr
)
3260 /* Rename the object */
3261 error
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
);
3262 if ( error
== noErr
)
3264 /* Move object to its new home */
3265 error
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
);
3266 if ( error
!= noErr
)
3268 /* Error handling: rename object back to original name - ignore errors */
3269 (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
);
3272 if ( error
!= noErr
)
3274 /* Error handling: move object back to original location - ignore errors */
3275 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
);
3278 /* Done with ourTempDir, so delete it - ignore errors */
3279 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
);
3289 /*****************************************************************************/
3291 pascal OSErr
FSpMoveRenameCompat(const FSSpec
*srcSpec
,
3292 const FSSpec
*dstSpec
,
3293 ConstStr255Param copyName
)
3295 /* make sure the FSSpecs refer to the same volume */
3296 if (srcSpec
->vRefNum
!= dstSpec
->vRefNum
)
3297 return (diffVolErr
);
3298 return ( HMoveRenameCompat(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3299 dstSpec
->parID
, dstSpec
->name
, copyName
) );
3302 /*****************************************************************************/
3304 pascal OSErr
BuildAFPVolMountInfo(short flags
,
3314 AFPVolMountInfoPtr
*afpInfoPtr
)
3316 MyAFPVolMountInfoPtr infoPtr
;
3319 /* Allocate the AFPXVolMountInfo record */
3320 infoPtr
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
));
3321 if ( infoPtr
!= NULL
)
3323 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
3324 infoPtr
->length
= sizeof(MyAFPVolMountInfo
);
3325 infoPtr
->media
= AppleShareMediaType
;
3326 infoPtr
->flags
= flags
;
3327 infoPtr
->nbpInterval
= nbpInterval
;
3328 infoPtr
->nbpCount
= nbpCount
;
3329 infoPtr
->uamType
= uamType
;
3331 infoPtr
->zoneNameOffset
= offsetof(MyAFPVolMountInfo
, zoneName
);
3332 infoPtr
->serverNameOffset
= offsetof(MyAFPVolMountInfo
, serverName
);
3333 infoPtr
->volNameOffset
= offsetof(MyAFPVolMountInfo
, volName
);
3334 infoPtr
->userNameOffset
= offsetof(MyAFPVolMountInfo
, userName
);
3335 infoPtr
->userPasswordOffset
= offsetof(MyAFPVolMountInfo
, userPassword
);
3336 infoPtr
->volPasswordOffset
= offsetof(MyAFPVolMountInfo
, volPassword
);
3338 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3339 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3340 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3341 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3342 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3343 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3345 *afpInfoPtr
= (AFPVolMountInfoPtr
)infoPtr
;
3356 /*****************************************************************************/
3358 pascal OSErr
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
,
3362 StringPtr serverName
,
3369 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3370 if ( afpInfoPtr
->media
== AppleShareMediaType
)
3372 *flags
= afpInfoPtr
->flags
;
3373 *uamType
= afpInfoPtr
->uamType
;
3375 if ( afpInfoPtr
->zoneNameOffset
!= 0)
3377 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->zoneNameOffset
);
3378 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3381 if ( afpInfoPtr
->serverNameOffset
!= 0)
3383 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->serverNameOffset
);
3384 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3387 if ( afpInfoPtr
->volNameOffset
!= 0)
3389 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->volNameOffset
);
3390 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3393 if ( afpInfoPtr
->userNameOffset
!= 0)
3395 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->userNameOffset
);
3396 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3409 /*****************************************************************************/
3411 pascal OSErr
BuildAFPXVolMountInfo(short flags
,
3422 unsigned long alternateAddressLength
,
3423 void *alternateAddress
,
3424 AFPXVolMountInfoPtr
*afpXInfoPtr
)
3427 MyAFPXVolMountInfoPtr infoPtr
;
3430 /* Calculate the size of the AFPXVolMountInfo record */
3431 infoSize
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength
- 1;
3433 /* Allocate the AFPXVolMountInfo record */
3434 infoPtr
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
);
3435 if ( infoPtr
!= NULL
)
3437 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
3438 infoPtr
->length
= infoSize
;
3439 infoPtr
->media
= AppleShareMediaType
;
3440 infoPtr
->flags
= flags
;
3441 if ( alternateAddressLength
!= 0 )
3443 /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
3444 infoPtr
->flags
|= volMountExtendedFlagsMask
;
3445 /* and set the only extendedFlags bit we know about */
3446 infoPtr
->extendedFlags
= kAFPExtendedFlagsAlternateAddressMask
;
3450 /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
3451 infoPtr
->flags
&= ~volMountExtendedFlagsMask
;
3452 /* and clear the extendedFlags */
3453 infoPtr
->extendedFlags
= 0;
3455 infoPtr
->nbpInterval
= nbpInterval
;
3456 infoPtr
->nbpCount
= nbpCount
;
3457 infoPtr
->uamType
= uamType
;
3459 infoPtr
->zoneNameOffset
= offsetof(MyAFPXVolMountInfo
, zoneName
);
3460 infoPtr
->serverNameOffset
= offsetof(MyAFPXVolMountInfo
, serverName
);
3461 infoPtr
->volNameOffset
= offsetof(MyAFPXVolMountInfo
, volName
);
3462 infoPtr
->userNameOffset
= offsetof(MyAFPXVolMountInfo
, userName
);
3463 infoPtr
->userPasswordOffset
= offsetof(MyAFPXVolMountInfo
, userPassword
);
3464 infoPtr
->volPasswordOffset
= offsetof(MyAFPXVolMountInfo
, volPassword
);
3465 infoPtr
->uamNameOffset
= offsetof(MyAFPXVolMountInfo
, uamName
);
3466 infoPtr
->alternateAddressOffset
= offsetof(MyAFPXVolMountInfo
, alternateAddress
);
3468 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3469 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3470 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3471 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3472 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3473 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3474 BlockMoveData(uamName
, infoPtr
->uamName
, sizeof(Str32
));
3475 BlockMoveData(alternateAddress
, infoPtr
->alternateAddress
, alternateAddressLength
);
3477 *afpXInfoPtr
= (AFPXVolMountInfoPtr
)infoPtr
;
3488 /*****************************************************************************/
3490 pascal OSErr
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
,
3494 StringPtr serverName
,
3498 unsigned long *alternateAddressLength
,
3499 AFPAlternateAddress
**alternateAddress
)
3502 Ptr alternateAddressStart
;
3503 Ptr alternateAddressEnd
;
3504 Size alternateAddressDataSize
;
3508 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3509 if ( afpXInfoPtr
->media
== AppleShareMediaType
)
3511 /* default to noErr */
3514 /* Is this an extended record? */
3515 if ( (afpXInfoPtr
->flags
& volMountExtendedFlagsMask
) != 0 )
3517 if ( ((afpXInfoPtr
->extendedFlags
& kAFPExtendedFlagsAlternateAddressMask
) != 0) &&
3518 (afpXInfoPtr
->alternateAddressOffset
!= 0) )
3521 alternateAddressStart
= (Ptr
)((long)afpXInfoPtr
+ afpXInfoPtr
->alternateAddressOffset
);
3522 alternateAddressEnd
= alternateAddressStart
+ 1; /* skip over alternate address version byte */
3523 addressCount
= *(UInt8
*)alternateAddressEnd
; /* get the address count */
3524 ++alternateAddressEnd
; /* skip over alternate address count byte */
3525 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
3526 while ( addressCount
!= 0 )
3528 /* parse the address list to find the end */
3529 alternateAddressEnd
+= *(UInt8
*)alternateAddressEnd
; /* add length of each AFPTagData record */
3532 /* get the size of the alternateAddressData */
3533 alternateAddressDataSize
= alternateAddressEnd
- alternateAddressStart
;
3534 /* allocate memory for it */
3535 *alternateAddress
= (AFPAlternateAddress
*)NewPtr(alternateAddressDataSize
);
3536 if ( *alternateAddress
!= NULL
)
3538 /* and return the data */
3539 BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
);
3540 *alternateAddressLength
= alternateAddressDataSize
;
3544 /* no memory - fail now */
3549 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3551 if ( afpXInfoPtr
->uamNameOffset
!= 0 )
3553 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->uamNameOffset
);
3554 BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1);
3559 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3561 *flags
= afpXInfoPtr
->flags
;
3562 *uamType
= afpXInfoPtr
->uamType
;
3564 if ( afpXInfoPtr
->zoneNameOffset
!= 0 )
3566 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->zoneNameOffset
);
3567 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3570 if ( afpXInfoPtr
->serverNameOffset
!= 0 )
3572 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->serverNameOffset
);
3573 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3576 if ( afpXInfoPtr
->volNameOffset
!= 0 )
3578 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->volNameOffset
);
3579 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3582 if ( afpXInfoPtr
->userNameOffset
!= 0 )
3584 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->userNameOffset
);
3585 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3597 /*****************************************************************************/
3599 pascal OSErr
GetUGEntries(short objType
,
3602 long *actEntryCount
,
3606 OSErr error
= noErr
;
3607 UGEntry
*endEntryArray
;
3609 pb
.objParam
.ioObjType
= objType
;
3611 for ( endEntryArray
= entries
+ reqEntryCount
; (entries
< endEntryArray
) && (error
== noErr
); ++entries
)
3613 pb
.objParam
.ioObjNamePtr
= (StringPtr
)entries
->name
;
3614 pb
.objParam
.ioObjID
= *objID
;
3615 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
3616 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
3617 /* A CMovePBPtr works OK, but this will be changed in the future back to */
3618 /* HParmBlkPtr, so I'm just casting it here. */
3619 error
= PBGetUGEntrySync(&pb
);
3620 if ( error
== noErr
)
3622 entries
->objID
= *objID
= pb
.objParam
.ioObjID
;
3623 entries
->objType
= objType
;
3631 /*****************************************************************************/