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.
50 #include <MacErrors.h>
51 #include <MacMemory.h>
57 #include <TextUtils.h>
60 #include <CodeFragments.h>
63 #define __COMPILINGMOREFILES
65 #include "MoreFiles.h"
66 #include "MoreDesktopMgr.h"
67 #include "FSpCompat.h"
69 #include "MoreFilesExtras.h"
71 /*****************************************************************************/
73 /* Functions to get information out of GetVolParmsInfoBuffer. */
75 /* version 1 field getters */
77 pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer
*volParms
)
79 return ( volParms
->vMVersion
);
82 pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer
*volParms
)
84 return ( volParms
->vMAttrib
);
87 pascal Handle
GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer
*volParms
)
89 return ( volParms
->vMLocalHand
);
92 pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer
*volParms
)
94 return ( volParms
->vMServerAdr
);
97 /* version 2 field getters (assume zero result if version < 2) */
99 pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer
*volParms
)
101 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMVolumeGrade
: 0 );
104 pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer
*volParms
)
106 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMForeignPrivID
: 0 );
109 /* version 3 field getters (assume zero result if version < 3) */
111 pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer
*volParms
)
113 return ( (volParms
->vMVersion
>= 3) ? volParms
->vMExtendedAttributes
: 0 );
116 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */
118 pascal Boolean
isNetworkVolume(const GetVolParmsInfoBuffer
*volParms
)
120 return ( volParms
->vMServerAdr
!= 0 );
123 pascal Boolean
hasLimitFCBs(const GetVolParmsInfoBuffer
*volParms
)
125 return ( (volParms
->vMAttrib
& (1L << bLimitFCBs
)) != 0 );
128 pascal Boolean
hasLocalWList(const GetVolParmsInfoBuffer
*volParms
)
130 return ( (volParms
->vMAttrib
& (1L << bLocalWList
)) != 0 );
133 pascal Boolean
hasNoMiniFndr(const GetVolParmsInfoBuffer
*volParms
)
135 return ( (volParms
->vMAttrib
& (1L << bNoMiniFndr
)) != 0 );
138 pascal Boolean
hasNoVNEdit(const GetVolParmsInfoBuffer
*volParms
)
140 return ( (volParms
->vMAttrib
& (1L << bNoVNEdit
)) != 0 );
143 pascal Boolean
hasNoLclSync(const GetVolParmsInfoBuffer
*volParms
)
145 return ( (volParms
->vMAttrib
& (1L << bNoLclSync
)) != 0 );
148 pascal Boolean
hasTrshOffLine(const GetVolParmsInfoBuffer
*volParms
)
150 return ( (volParms
->vMAttrib
& (1L << bTrshOffLine
)) != 0 );
153 pascal Boolean
hasNoSwitchTo(const GetVolParmsInfoBuffer
*volParms
)
155 return ( (volParms
->vMAttrib
& (1L << bNoSwitchTo
)) != 0 );
158 pascal Boolean
hasNoDeskItems(const GetVolParmsInfoBuffer
*volParms
)
160 return ( (volParms
->vMAttrib
& (1L << bNoDeskItems
)) != 0 );
163 pascal Boolean
hasNoBootBlks(const GetVolParmsInfoBuffer
*volParms
)
165 return ( (volParms
->vMAttrib
& (1L << bNoBootBlks
)) != 0 );
168 pascal Boolean
hasAccessCntl(const GetVolParmsInfoBuffer
*volParms
)
170 return ( (volParms
->vMAttrib
& (1L << bAccessCntl
)) != 0 );
173 pascal Boolean
hasNoSysDir(const GetVolParmsInfoBuffer
*volParms
)
175 return ( (volParms
->vMAttrib
& (1L << bNoSysDir
)) != 0 );
178 pascal Boolean
hasExtFSVol(const GetVolParmsInfoBuffer
*volParms
)
180 return ( (volParms
->vMAttrib
& (1L << bHasExtFSVol
)) != 0 );
183 pascal Boolean
hasOpenDeny(const GetVolParmsInfoBuffer
*volParms
)
185 return ( (volParms
->vMAttrib
& (1L << bHasOpenDeny
)) != 0 );
188 pascal Boolean
hasCopyFile(const GetVolParmsInfoBuffer
*volParms
)
190 return ( (volParms
->vMAttrib
& (1L << bHasCopyFile
)) != 0 );
193 pascal Boolean
hasMoveRename(const GetVolParmsInfoBuffer
*volParms
)
195 return ( (volParms
->vMAttrib
& (1L << bHasMoveRename
)) != 0 );
198 pascal Boolean
hasDesktopMgr(const GetVolParmsInfoBuffer
*volParms
)
200 return ( (volParms
->vMAttrib
& (1L << bHasDesktopMgr
)) != 0 );
203 pascal Boolean
hasShortName(const GetVolParmsInfoBuffer
*volParms
)
205 return ( (volParms
->vMAttrib
& (1L << bHasShortName
)) != 0 );
208 pascal Boolean
hasFolderLock(const GetVolParmsInfoBuffer
*volParms
)
210 return ( (volParms
->vMAttrib
& (1L << bHasFolderLock
)) != 0 );
213 pascal Boolean
hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
215 return ( (volParms
->vMAttrib
& (1L << bHasPersonalAccessPrivileges
)) != 0 );
218 pascal Boolean
hasUserGroupList(const GetVolParmsInfoBuffer
*volParms
)
220 return ( (volParms
->vMAttrib
& (1L << bHasUserGroupList
)) != 0 );
223 pascal Boolean
hasCatSearch(const GetVolParmsInfoBuffer
*volParms
)
225 return ( (volParms
->vMAttrib
& (1L << bHasCatSearch
)) != 0 );
228 pascal Boolean
hasFileIDs(const GetVolParmsInfoBuffer
*volParms
)
230 return ( (volParms
->vMAttrib
& (1L << bHasFileIDs
)) != 0 );
233 pascal Boolean
hasBTreeMgr(const GetVolParmsInfoBuffer
*volParms
)
235 return ( (volParms
->vMAttrib
& (1L << bHasBTreeMgr
)) != 0 );
238 pascal Boolean
hasBlankAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
240 return ( (volParms
->vMAttrib
& (1L << bHasBlankAccessPrivileges
)) != 0 );
243 pascal Boolean
supportsAsyncRequests(const GetVolParmsInfoBuffer
*volParms
)
245 return ( (volParms
->vMAttrib
& (1L << bSupportsAsyncRequests
)) != 0 );
248 pascal Boolean
supportsTrashVolumeCache(const GetVolParmsInfoBuffer
*volParms
)
250 return ( (volParms
->vMAttrib
& (1L << bSupportsTrashVolumeCache
)) != 0 );
253 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
255 pascal Boolean
volIsEjectable(const GetVolParmsInfoBuffer
*volParms
)
257 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bIsEjectable
)) != 0 );
260 pascal Boolean
volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer
*volParms
)
262 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsHFSPlusAPIs
)) != 0 );
265 pascal Boolean
volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer
*volParms
)
267 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSCatalogSearch
)) != 0 );
270 pascal Boolean
volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer
*volParms
)
272 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSExchangeObjects
)) != 0 );
275 pascal Boolean
volSupports2TBFiles(const GetVolParmsInfoBuffer
*volParms
)
277 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupports2TBFiles
)) != 0 );
280 pascal Boolean
volSupportsLongNames(const GetVolParmsInfoBuffer
*volParms
)
282 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsLongNames
)) != 0 );
285 pascal Boolean
volSupportsMultiScriptNames(const GetVolParmsInfoBuffer
*volParms
)
287 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsMultiScriptNames
)) != 0 );
290 pascal Boolean
volSupportsNamedForks(const GetVolParmsInfoBuffer
*volParms
)
292 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsNamedForks
)) != 0 );
295 pascal Boolean
volSupportsSubtreeIterators(const GetVolParmsInfoBuffer
*volParms
)
297 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsSubtreeIterators
)) != 0 );
300 pascal Boolean
volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer
*volParms
)
302 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bL2PCanMapFileBlocks
)) != 0 );
305 /*****************************************************************************/
307 /* Functions for testing ioACUser bits. */
309 pascal Boolean
userIsOwner(SInt8 ioACUser
)
311 return ( (ioACUser
& kioACUserNotOwnerMask
) == 0 );
314 pascal Boolean
userHasFullAccess(SInt8 ioACUser
)
316 return ( (ioACUser
& acUserAccessMask
) == acUserFull
);
319 pascal Boolean
userHasDropBoxAccess(SInt8 ioACUser
)
321 return ( (ioACUser
& acUserAccessMask
) == acUserDropBox
);
324 pascal Boolean
userHasBulletinBoard(SInt8 ioACUser
)
326 return ( (ioACUser
& acUserAccessMask
) == acUserBulletinBoard
);
329 pascal Boolean
userHasNoAccess(SInt8 ioACUser
)
331 return ( (ioACUser
& acUserAccessMask
) == acUserNone
);
334 /*****************************************************************************/
336 /* local data structures */
338 /* The DeleteEnumGlobals structure is used to minimize the amount of
339 ** stack space used when recursively calling DeleteLevel and to hold
340 ** global information that might be needed at any time. */
342 #if PRAGMA_STRUCT_ALIGN
343 #pragma options align=mac68k
344 #endif // PRAGMA_STRUCT_ALIGN
345 struct DeleteEnumGlobals
347 OSErr error
; /* temporary holder of results - saves 2 bytes of stack each level */
348 Str63 itemName
; /* the name of the current item */
349 UniversalFMPB myPB
; /* the parameter block used for PBGetCatInfo calls */
351 #if PRAGMA_STRUCT_ALIGN
352 #pragma options align=reset
353 #endif // PRAGMA_STRUCT_ALIGN
355 typedef struct DeleteEnumGlobals DeleteEnumGlobals
;
356 typedef DeleteEnumGlobals
*DeleteEnumGlobalsPtr
;
358 /*****************************************************************************/
361 ** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
362 ** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync
363 ** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined,
364 ** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync.
366 ** Non-CFM 68K programs don't needs this glue (and won't get it) because
367 ** they instead use the inline assembly glue found in the Files.h interface
371 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
373 // Carbon builds and 68K builds don't need this glue
374 #define CallPBXGetVolInfoSync PBXGetVolInfoSync
376 #else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
378 #if __WANTPASCALELIMINATION
380 #endif // __WANTPASCALELIMINATION
382 /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */
383 static pascal OSErr
PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock
)
387 uppFSDispatchProcInfo
= kRegisterBased
388 | REGISTER_RESULT_LOCATION(kRegisterD0
)
389 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr
)))
390 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0
, SIZE_CODE(sizeof(long))) /* selector */
391 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1
, SIZE_CODE(sizeof(long))) /* trap word */
392 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0
, SIZE_CODE(sizeof(XVolumeParamPtr
)))
395 static UniversalProcPtr fsDispatchTrapAddress
= NULL
;
397 /* Is this the first time we've been called? */
398 if ( fsDispatchTrapAddress
== NULL
)
400 /* Yes - Get the trap address of _FSDispatch */
401 fsDispatchTrapAddress
= NGetTrapAddress(_FSDispatch
, OSTrap
);
403 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress
,
404 uppFSDispatchProcInfo
,
411 ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2.
412 ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5.
413 ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib;
414 ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program
415 ** is calling the latest implementation of PBXGetVolInfoSync.
417 static pascal OSErr
CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock
)
419 typedef pascal OSErr (*PBXGetVolInfoProcPtr
) (XVolumeParamPtr paramBlock
);
422 CFragConnectionID connID
;
425 static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr
= NULL
;
427 //* Is this the first time we've been called? */
428 if ( PBXGetVolInfoSyncPtr
== NULL
)
430 /* Yes - Get our connection ID to InterfaceLib */
431 result
= GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch
, kLoadCFrag
, &connID
, &mainAddr
, errMessage
);
432 if ( result
== noErr
)
434 /* See if PBXGetVolInfoSync is in InterfaceLib */
435 if ( FindSymbol(connID
, "\pPBXGetVolInfoSync", &(Ptr
)PBXGetVolInfoSyncPtr
, NULL
) != noErr
)
437 /* Use glue code if symbol isn't found */
438 PBXGetVolInfoSyncPtr
= PBXGetVolInfoSyncGlue
;
442 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */
443 return ( (*PBXGetVolInfoSyncPtr
)(paramBlock
) );
446 #if __WANTPASCALELIMINATION
448 #endif // __WANTPASCALELIMINATION
450 #endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
452 /*****************************************************************************/
454 pascal void TruncPString(StringPtr destination
,
455 ConstStr255Param source
,
460 if ( source
!= NULL
&& destination
!= NULL
) /* don't do anything stupid */
462 if ( source
[0] > maxLength
)
464 /* Make sure the string isn't truncated in the middle of */
465 /* a multi-byte character. */
466 while (maxLength
!= 0)
468 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter
469 charType
= CharacterByteType((Ptr
)&source
[1], maxLength
- 1, smSystemScript
);
470 if ( (charType
== smSingleByte
) || (charType
== smLastByte
) )
471 break; /* source[maxLength] is now a valid last character */
477 maxLength
= source
[0];
479 /* Set the destination string length */
480 destination
[0] = maxLength
;
481 /* and copy maxLength characters (if needed) */
482 if ( source
!= destination
)
484 while ( maxLength
!= 0 )
486 destination
[maxLength
] = source
[maxLength
];
493 /*****************************************************************************/
495 pascal Ptr
GetTempBuffer(long buffReqSize
,
500 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
504 /* Make request a multiple of 1024 bytes */
505 buffReqSize
= buffReqSize
& 0xfffffc00;
507 if ( buffReqSize
< 0x00000400 )
509 /* Request was smaller than 1024 bytes - make it 1024 */
510 buffReqSize
= 0x00000400;
513 /* Attempt to allocate the memory */
514 tempPtr
= NewPtr(buffReqSize
);
516 /* If request failed, go to backup plan */
517 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00000400) )
520 ** Try to get largest 1024-byte block available
521 ** leaving some slop for the toolbox if possible
523 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffffc00;
525 buffReqSize
= MaxBlock() & 0xfffffc00;
527 if ( buffReqSize
> freeMemory
)
529 buffReqSize
= freeMemory
;
532 if ( buffReqSize
== 0 )
534 buffReqSize
= 0x00000400;
537 tempPtr
= NewPtr(buffReqSize
);
540 /* Return bytes allocated */
541 if ( tempPtr
!= NULL
)
543 *buffActSize
= buffReqSize
;
553 /*****************************************************************************/
556 ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
557 ** in cases where the returned volume name is not needed by the caller.
558 ** The pathname and vRefNum parameters are not touched, and the pb
559 ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
560 ** the parameter block is always returned as NULL (since it might point
561 ** to the local tempPathname).
563 ** I noticed using this code in several places, so here it is once.
564 ** This reduces the code size of MoreFiles.
566 pascal OSErr
GetVolumeInfoNoName(ConstStr255Param pathname
,
573 /* Make sure pb parameter is not NULL */
576 pb
->volumeParam
.ioVRefNum
= vRefNum
;
577 if ( pathname
== NULL
)
579 pb
->volumeParam
.ioNamePtr
= NULL
;
580 pb
->volumeParam
.ioVolIndex
= 0; /* use ioVRefNum only */
584 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
585 pb
->volumeParam
.ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
586 pb
->volumeParam
.ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
588 error
= PBHGetVInfoSync(pb
);
589 pb
->volumeParam
.ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
598 /*****************************************************************************/
601 ** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
602 ** in cases where the returned volume name is not needed by the caller.
603 ** The pathname and vRefNum parameters are not touched, and the pb
604 ** parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
605 ** the parameter block is always returned as NULL (since it might point
606 ** to the local tempPathname).
608 pascal OSErr
XGetVolumeInfoNoName(ConstStr255Param pathname
,
615 /* Make sure pb parameter is not NULL */
618 pb
->ioVRefNum
= vRefNum
;
619 pb
->ioXVersion
= 0; /* this XVolumeParam version (0) */
620 if ( pathname
== NULL
)
622 pb
->ioNamePtr
= NULL
;
623 pb
->ioVolIndex
= 0; /* use ioVRefNum only */
627 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
628 pb
->ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
629 pb
->ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
633 #if !TARGET_API_MAC_CARBON
636 /* Is PBXGetVolInfo available? */
637 if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr
) || ((response
& (1L << gestaltFSSupports2TBVols
)) == 0) )
639 /* No, fall back on PBHGetVInfo */
640 error
= PBHGetVInfoSync((HParmBlkPtr
)pb
);
641 if ( error
== noErr
)
643 /* calculate the ioVTotalBytes and ioVFreeBytes fields */
644 pb
->ioVTotalBytes
= U64Multiply(U64SetU(pb
->ioVNmAlBlks
), U64SetU(pb
->ioVAlBlkSiz
));
645 pb
->ioVFreeBytes
= U64Multiply(U64SetU(pb
->ioVFrBlk
), U64SetU(pb
->ioVAlBlkSiz
));
652 error
= CallPBXGetVolInfoSync(pb
);
655 pb
->ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
664 /*****************************************************************************/
666 pascal OSErr
GetCatInfoNoName(short vRefNum
,
668 ConstStr255Param name
,
674 /* Protection against File Sharing problem */
675 if ( (name
== NULL
) || (name
[0] == 0) )
678 pb
->dirInfo
.ioNamePtr
= tempName
;
679 pb
->dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
683 pb
->dirInfo
.ioNamePtr
= (StringPtr
)name
;
684 pb
->dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
686 pb
->dirInfo
.ioVRefNum
= vRefNum
;
687 pb
->dirInfo
.ioDrDirID
= dirID
;
688 error
= PBGetCatInfoSync(pb
);
689 pb
->dirInfo
.ioNamePtr
= NULL
;
693 /*****************************************************************************/
695 pascal OSErr
DetermineVRefNum(ConstStr255Param pathname
,
702 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
703 if ( error
== noErr
)
705 *realVRefNum
= pb
.volumeParam
.ioVRefNum
;
710 /*****************************************************************************/
712 pascal OSErr
HGetVInfo(short volReference
,
715 unsigned long *freeBytes
,
716 unsigned long *totalBytes
)
722 // get the best values possible from XGetVInfo
723 result
= XGetVInfo(volReference
, volName
, vRefNum
, &freeBytes64
, &totalBytes64
);
724 if ( result
== noErr
)
726 // and pin those values if needed
727 if ( UInt64ToUnsignedWide(freeBytes64
).hi
!= 0 )
729 // pin to maximum 512-byte block aligned value
730 *freeBytes
= 0xfffffe00;
734 *freeBytes
= U32SetU(freeBytes64
);
737 if ( UInt64ToUnsignedWide(totalBytes64
).hi
!= 0 )
739 // pin to maximum 512-byte block aligned value
740 *totalBytes
= 0xfffffe00;
744 *totalBytes
= U32SetU(totalBytes64
);
751 /*****************************************************************************/
753 pascal OSErr
XGetVInfo(short volReference
,
762 #if !TARGET_API_MAC_CARBON
766 #endif // !TARGET_API_MAC_CARBON
768 pb
.ioVRefNum
= volReference
;
769 pb
.ioNamePtr
= volName
;
770 pb
.ioXVersion
= 0; /* this XVolumeParam version (0) */
771 pb
.ioVolIndex
= 0; /* use ioVRefNum only, return volume name */
773 #if !TARGET_API_MAC_CARBON
775 /* See if large volume support is available */
776 if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr
) && ((response
& (1L << gestaltFSSupports2TBVols
)) != 0) )
778 #endif // !TARGET_API_MAC_CARBON
781 /* Large volume support is available */
782 result
= CallPBXGetVolInfoSync(&pb
);
783 if ( result
== noErr
)
785 /* The volume name was returned in volName (if not NULL) and */
786 /* we have the volume's vRefNum and allocation block size */
787 *vRefNum
= pb
.ioVRefNum
;
789 /* return the freeBytes and totalBytes */
790 *totalBytes
= pb
.ioVTotalBytes
;
791 *freeBytes
= pb
.ioVFreeBytes
;
795 #if !TARGET_API_MAC_CARBON
799 /* No large volume support */
800 /* Use PBHGetVInfoSync to get the results */
801 result
= PBHGetVInfoSync((HParmBlkPtr
)&pb
);
802 if ( result
== noErr
)
806 /* The volume name was returned in volName (if not NULL) and */
807 /* we have the volume's vRefNum */
808 *vRefNum
= pb
.ioVRefNum
;
810 /* System 7.5 (and beyond) pins the number of allocation blocks and */
811 /* the number of free allocation blocks returned by PBHGetVInfo to */
812 /* a value so that when multiplied by the allocation block size, */
813 /* the volume will look like it has $7fffffff bytes or less. This */
814 /* was done so older applications that use signed math or that use */
815 /* the GetVInfo function (which uses signed math) will continue to work. */
816 /* However, the unpinned numbers (which we want) are always available */
817 /* in the volume's VCB so we'll get those values from the VCB. */
818 /* Note: Carbon doesn't support the VCB queue, so this code cannot be */
819 /* used (and is conditionalized out) by Carbon applications. */
821 /* Find the volume's VCB */
822 theVCB
= (VCB
*)(GetVCBQHdr()->qHead
);
823 while ( theVCB
!= NULL
)
825 if ( theVCB
->vcbVRefNum
== *vRefNum
)
830 theVCB
= (VCB
*)(theVCB
->qLink
); /* next VCB */
833 if ( theVCB
!= NULL
)
835 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
836 /* and the number of free blocks from the VCB. */
837 *freeBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbFreeBks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
838 *totalBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
842 /* Didn't find a VCB we can use. Return the number of allocation blocks */
843 /* and the number of free blocks returned by PBHGetVInfoSync. */
844 *freeBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVFrBlk
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
845 *totalBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
851 #endif // !TARGET_API_MAC_CARBON
856 /*****************************************************************************/
858 pascal OSErr
CheckVolLock(ConstStr255Param pathname
,
864 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
865 if ( error
== noErr
)
867 if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeHardwareLockMask
) != 0 )
869 error
= wPrErr
; /* volume locked by hardware */
871 else if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeSoftwareLockMask
) != 0 )
873 error
= vLckdErr
; /* volume locked by software */
880 /*****************************************************************************/
882 // The following routines call Mac OS routines that are not supported by
890 #if !TARGET_API_MAC_CARBON // {
892 /*****************************************************************************/
894 pascal OSErr
GetDriverName(short driverRefNum
,
899 DRVRHeaderPtr dHeaderPtr
;
901 theDctl
= GetDCtlEntry(driverRefNum
);
902 if ( theDctl
!= NULL
)
904 if ( (**theDctl
).dCtlFlags
& dRAMBasedMask
)
906 /* dctlDriver is handle - dereference */
907 dHeaderPtr
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
);
911 /* dctlDriver is pointer */
912 dHeaderPtr
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
;
914 BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1);
920 result
= badUnitErr
; /* bad reference number */
926 /*****************************************************************************/
928 pascal OSErr
FindDrive(ConstStr255Param pathname
,
930 DrvQElPtr
*driveQElementPtr
)
936 *driveQElementPtr
= NULL
;
938 /* First, use GetVolumeInfoNoName to determine the volume */
939 result
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
);
940 if ( result
== noErr
)
943 ** The volume can be either online, offline, or ejected. What we find in
944 ** ioVDrvInfo and ioVDRefNum will tell us which it is.
945 ** See Inside Macintosh: Files page 2-80 and the Technical Note
946 ** "FL 34 - VCBs and Drive Numbers : The Real Story"
947 ** Where we get the drive number depends on the state of the volume.
949 if ( hPB
.volumeParam
.ioVDrvInfo
!= 0 )
951 /* The volume is online and not ejected */
952 /* Get the drive number */
953 driveNumber
= hPB
.volumeParam
.ioVDrvInfo
;
957 /* The volume's is either offline or ejected */
958 /* in either case, the volume is NOT online */
960 /* Is it ejected or just offline? */
961 if ( hPB
.volumeParam
.ioVDRefNum
> 0 )
963 /* It's ejected, the drive number is ioVDRefNum */
964 driveNumber
= hPB
.volumeParam
.ioVDRefNum
;
968 /* It's offline, the drive number is the negative of ioVDRefNum */
969 driveNumber
= (short)-hPB
.volumeParam
.ioVDRefNum
;
973 /* Get pointer to first element in drive queue */
974 *driveQElementPtr
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
976 /* Search for a matching drive number */
977 while ( (*driveQElementPtr
!= NULL
) && ((*driveQElementPtr
)->dQDrive
!= driveNumber
) )
979 *driveQElementPtr
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
;
982 if ( *driveQElementPtr
== NULL
)
984 /* This should never happen since every volume must have a drive, but... */
992 /*****************************************************************************/
994 pascal OSErr
GetDiskBlocks(ConstStr255Param pathname
,
996 unsigned long *numBlocks
)
998 /* Various constants for GetDiskBlocks() */
1001 /* return format list status code */
1004 /* reference number of .SONY driver */
1005 kSonyRefNum
= 0xfffb,
1007 /* values returned by DriveStatus in DrvSts.twoSideFmt */
1010 kSingleSidedSize
= 800, /* 400K */
1011 kDoubleSidedSize
= 1600, /* 800K */
1013 /* values in DrvQEl.qType */
1017 /* more than enough formatListRecords */
1018 kMaxFormatListRecs
= 16
1021 DrvQElPtr driveQElementPtr
;
1022 unsigned long blocks
;
1024 FormatListRec formatListRecords
[kMaxFormatListRecs
];
1026 short formatListRecIndex
;
1031 /* Find the drive queue element for this volume */
1032 result
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
);
1035 ** Make sure this is a real driver (dQRefNum < 0).
1036 ** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
1037 ** problems if you try to use it as a driver refNum.
1039 if ( (result
== noErr
) && (driveQElementPtr
->dQRefNum
>= 0) )
1045 /* Attempt to get the drive's format list. */
1046 /* (see the Technical Note "What Your Sony Drives For You") */
1048 pb
.cntrlParam
.ioVRefNum
= driveQElementPtr
->dQDrive
;
1049 pb
.cntrlParam
.ioCRefNum
= driveQElementPtr
->dQRefNum
;
1050 pb
.cntrlParam
.csCode
= kFmtLstCode
;
1051 pb
.cntrlParam
.csParam
[0] = kMaxFormatListRecs
;
1052 *(long *)&pb
.cntrlParam
.csParam
[1] = (long)&formatListRecords
[0];
1054 result
= PBStatusSync(&pb
);
1056 if ( result
== noErr
)
1058 /* The drive supports ReturnFormatList status call. */
1060 /* Get the current disk's size. */
1061 for( formatListRecIndex
= 0;
1062 formatListRecIndex
< pb
.cntrlParam
.csParam
[0];
1063 ++formatListRecIndex
)
1065 if ( (formatListRecords
[formatListRecIndex
].formatFlags
&
1066 diCIFmtFlagsCurrentMask
) != 0 )
1068 blocks
= formatListRecords
[formatListRecIndex
].volSize
;
1073 /* This should never happen */
1077 else if ( driveQElementPtr
->dQRefNum
== (short)kSonyRefNum
)
1079 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
1081 result
= DriveStatus(driveQElementPtr
->dQDrive
, &status
);
1082 if ( result
== noErr
)
1084 switch ( status
.twoSideFmt
)
1087 blocks
= kSingleSidedSize
;
1090 blocks
= kDoubleSidedSize
;
1093 /* This should never happen */
1101 /* The drive is not a floppy and it doesn't support ReturnFormatList */
1102 /* so use the dQDrvSz field(s) */
1104 result
= noErr
; /* reset result */
1105 switch ( driveQElementPtr
->qType
)
1108 blocks
= driveQElementPtr
->dQDrvSz
;
1111 blocks
= ((unsigned long)driveQElementPtr
->dQDrvSz2
<< 16) +
1112 driveQElementPtr
->dQDrvSz
;
1115 /* This should never happen */
1122 if ( result
== noErr
)
1124 *numBlocks
= blocks
;
1130 /*****************************************************************************/
1132 pascal OSErr
GetVolState(ConstStr255Param pathname
,
1134 Boolean
*volumeOnline
,
1135 Boolean
*volumeEjected
,
1136 Boolean
*driveEjectable
,
1137 Boolean
*driverWantsEject
)
1143 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1144 if ( error
== noErr
)
1146 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1148 /* the volume is online and not ejected */
1149 *volumeOnline
= true;
1150 *volumeEjected
= false;
1152 /* Get the drive number */
1153 driveNumber
= pb
.volumeParam
.ioVDrvInfo
;
1157 /* the volume's is either offline or ejected */
1158 /* in either case, the volume is NOT online */
1159 *volumeOnline
= false;
1161 /* Is it ejected? */
1162 *volumeEjected
= pb
.volumeParam
.ioVDRefNum
> 0;
1164 if ( *volumeEjected
)
1166 /* If ejected, the drive number is ioVDRefNum */
1167 driveNumber
= pb
.volumeParam
.ioVDRefNum
;
1171 /* If offline, the drive number is the negative of ioVDRefNum */
1172 driveNumber
= (short)-pb
.volumeParam
.ioVDRefNum
;
1179 /* Find the drive queue element by searching the drive queue */
1180 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1181 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNumber
) )
1183 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1186 if ( drvQElem
!= NULL
)
1189 ** Each drive queue element is preceded by 4 flag bytes.
1190 ** Byte 1 (the second flag byte) has bits that tell us if a
1191 ** drive is ejectable and if its driver wants an eject call.
1192 ** See Inside Macintosh: Files, page 2-85.
1197 /* point to byte 1 of the flag bytes */
1198 flagBytePtr
= (Ptr
)drvQElem
;
1202 ** The drive is ejectable if flag byte 1 does not contain
1203 ** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
1206 *driveEjectable
= (*flagBytePtr
!= 0x08) && (*flagBytePtr
!= 0x48);
1209 ** The driver wants an eject call if flag byte 1 does not contain
1210 ** 0x08 (nonejectable). This may seem like a minor point, but some
1211 ** disk drivers use the Eject request to flush their caches to disk
1212 ** and you wouldn't want to skip that step after unmounting a volume.
1215 *driverWantsEject
= (*flagBytePtr
!= 0x08);
1220 /* Didn't find the drive (this should never happen) */
1221 *driveEjectable
= false;
1222 *driverWantsEject
= false;
1230 /*****************************************************************************/
1232 #endif // } !TARGET_API_MAC_CARBON
1234 /*****************************************************************************/
1236 pascal OSErr
GetVolFileSystemID(ConstStr255Param pathname
,
1238 short *fileSystemID
)
1243 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1244 if ( error
== noErr
)
1246 *fileSystemID
= pb
.volumeParam
.ioVFSID
;
1252 /*****************************************************************************/
1255 // Note: Under Carbon there are no drive numbers, so you cannot call
1256 // Eject with a drive number after unmounting a volume.
1257 // When a Carbon application calls UnmountVol, CarbonLib will make
1258 // sure ejectable media is ejected (leaving ejectable media in the
1259 // disk drive makes no sense to Carbon applications).
1261 pascal OSErr
UnmountAndEject(ConstStr255Param pathname
,
1267 error
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
);
1268 if ( error
== noErr
)
1271 #if !TARGET_API_MAC_CARBON
1274 Boolean ejected
, wantsEject
;
1277 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1279 /* the volume is online and not ejected */
1282 /* Get the drive number */
1283 driveNum
= pb
.volumeParam
.ioVDrvInfo
;
1287 /* the volume is ejected or offline */
1289 /* Is it ejected? */
1290 ejected
= pb
.volumeParam
.ioVDRefNum
> 0;
1294 /* If ejected, the drive number is ioVDRefNum */
1295 driveNum
= pb
.volumeParam
.ioVDRefNum
;
1299 /* If offline, the drive number is the negative of ioVDRefNum */
1300 driveNum
= (short)-pb
.volumeParam
.ioVDRefNum
;
1304 /* find the drive queue element */
1305 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1306 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNum
) )
1308 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1311 if ( drvQElem
!= NULL
)
1313 /* does the drive want an eject call */
1314 wantsEject
= (*((Ptr
)((Ptr
)drvQElem
- 3)) != 8);
1318 /* didn't find the drive!! */
1322 #endif // !TARGET_API_MAC_CARBON
1324 /* unmount the volume */
1325 pb
.volumeParam
.ioNamePtr
= NULL
;
1326 /* ioVRefNum is already filled in from PBHGetVInfo */
1327 error
= PBUnmountVol((ParmBlkPtr
)&pb
);
1329 #if !TARGET_API_MAC_CARBON
1331 if ( error
== noErr
)
1333 if ( wantsEject
&& !ejected
)
1335 /* eject the media from the drive if needed */
1336 pb
.volumeParam
.ioVRefNum
= driveNum
;
1337 error
= PBEject((ParmBlkPtr
)&pb
);
1341 #endif // !TARGET_API_MAC_CARBON
1348 /*****************************************************************************/
1350 pascal OSErr
OnLine(FSSpecPtr volumes
,
1356 OSErr error
= noErr
;
1357 FSSpec
*endVolArray
;
1359 if ( *volIndex
> 0 )
1362 for ( endVolArray
= volumes
+ reqVolCount
; (volumes
< endVolArray
) && (error
== noErr
); ++volumes
)
1364 pb
.volumeParam
.ioNamePtr
= (StringPtr
) & volumes
->name
;
1365 pb
.volumeParam
.ioVolIndex
= *volIndex
;
1366 error
= PBHGetVInfoSync(&pb
);
1367 if ( error
== noErr
)
1369 volumes
->parID
= fsRtParID
; /* the root directory's parent is 1 */
1370 volumes
->vRefNum
= pb
.volumeParam
.ioVRefNum
;
1384 /*****************************************************************************/
1386 pascal OSErr
SetDefault(short newVRefNum
,
1393 /* Get the current default volume/directory. */
1394 error
= HGetVol(NULL
, oldVRefNum
, oldDirID
);
1395 if ( error
== noErr
)
1397 /* Set the new default volume/directory */
1398 error
= HSetVol(NULL
, newVRefNum
, newDirID
);
1404 /*****************************************************************************/
1406 pascal OSErr
RestoreDefault(short oldVRefNum
,
1411 #if !TARGET_API_MAC_CARBON
1413 short defaultVRefNum
;
1417 /* Determine if the default volume was a wdRefNum. */
1418 error
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
);
1419 if ( error
== noErr
)
1421 /* Restore the old default volume/directory, one way or the other. */
1422 if ( defaultDirID
!= fsRtDirID
)
1424 /* oldVRefNum was a wdRefNum - use SetVol */
1425 error
= SetVol(NULL
, oldVRefNum
);
1430 #endif // !TARGET_API_MAC_CARBON
1432 /* oldVRefNum was a real vRefNum - use HSetVol */
1433 error
= HSetVol(NULL
, oldVRefNum
, oldDirID
);
1435 #if !TARGET_API_MAC_CARBON
1439 #endif // !TARGET_API_MAC_CARBON
1444 /*****************************************************************************/
1446 pascal OSErr
GetDInfo(short vRefNum
,
1448 ConstStr255Param name
,
1454 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1455 if ( error
== noErr
)
1457 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1459 /* it's a directory, return the DInfo */
1460 *fndrInfo
= pb
.dirInfo
.ioDrUsrWds
;
1464 /* oops, a file was passed */
1472 /*****************************************************************************/
1474 pascal OSErr
FSpGetDInfo(const FSSpec
*spec
,
1477 return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1480 /*****************************************************************************/
1482 pascal OSErr
SetDInfo(short vRefNum
,
1484 ConstStr255Param name
,
1485 const DInfo
*fndrInfo
)
1491 /* Protection against File Sharing problem */
1492 if ( (name
== NULL
) || (name
[0] == 0) )
1495 pb
.dirInfo
.ioNamePtr
= tempName
;
1496 pb
.dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
1500 pb
.dirInfo
.ioNamePtr
= (StringPtr
)name
;
1501 pb
.dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1503 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1504 pb
.dirInfo
.ioDrDirID
= dirID
;
1505 error
= PBGetCatInfoSync(&pb
);
1506 if ( error
== noErr
)
1508 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1510 /* it's a directory, set the DInfo */
1511 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
1513 pb
.dirInfo
.ioDrDirID
= pb
.dirInfo
.ioDrParID
;
1517 pb
.dirInfo
.ioDrDirID
= dirID
;
1519 pb
.dirInfo
.ioDrUsrWds
= *fndrInfo
;
1520 error
= PBSetCatInfoSync(&pb
);
1524 /* oops, a file was passed */
1532 /*****************************************************************************/
1534 pascal OSErr
FSpSetDInfo(const FSSpec
*spec
,
1535 const DInfo
*fndrInfo
)
1537 return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1540 /*****************************************************************************/
1542 pascal OSErr
GetDirectoryID(short vRefNum
,
1544 ConstStr255Param name
,
1546 Boolean
*isDirectory
)
1551 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1552 if ( error
== noErr
)
1554 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1557 *theDirID
= pb
.dirInfo
.ioDrDirID
;
1561 *theDirID
= pb
.hFileInfo
.ioFlParID
;
1568 /*****************************************************************************/
1570 pascal OSErr
FSpGetDirectoryID(const FSSpec
*spec
,
1572 Boolean
*isDirectory
)
1574 return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
,
1575 theDirID
, isDirectory
) );
1578 /*****************************************************************************/
1580 pascal OSErr
GetDirName(short vRefNum
,
1589 pb
.dirInfo
.ioNamePtr
= name
;
1590 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1591 pb
.dirInfo
.ioDrDirID
= dirID
;
1592 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1593 error
= PBGetCatInfoSync(&pb
);
1603 /*****************************************************************************/
1605 pascal OSErr
GetIOACUser(short vRefNum
,
1607 ConstStr255Param name
,
1613 /* Clear ioACUser before calling PBGetCatInfo since some file systems
1614 ** don't bother to set or clear this field. If ioACUser isn't set by the
1615 ** file system, then you'll get the zero value back (full access) which
1616 ** is the access you have on volumes that don't support ioACUser.
1618 pb
.dirInfo
.ioACUser
= 0; /* ioACUser used to be filler2 */
1619 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1620 if ( error
== noErr
)
1622 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 )
1624 /* oops, a file was passed */
1629 *ioACUser
= pb
.dirInfo
.ioACUser
;
1636 /*****************************************************************************/
1638 pascal OSErr
FSpGetIOACUser(const FSSpec
*spec
,
1641 return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) );
1644 /*****************************************************************************/
1646 pascal OSErr
GetParentID(short vRefNum
,
1648 ConstStr255Param name
,
1656 /* Protection against File Sharing problem */
1657 if ( (name
== NULL
) || (name
[0] == 0) )
1660 pb
.hFileInfo
.ioNamePtr
= tempName
;
1661 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1665 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
1666 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1668 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1669 pb
.hFileInfo
.ioDirID
= dirID
;
1670 error
= PBGetCatInfoSync(&pb
);
1671 if ( error
== noErr
)
1674 ** There's a bug in HFS where the wrong parent dir ID can be
1675 ** returned if multiple separators are used at the end of a
1676 ** pathname. For example, if the pathname:
1677 ** 'volumeName:System Folder:Extensions::'
1678 ** is passed, the directory ID of the Extensions folder is
1679 ** returned in the ioFlParID field instead of fsRtDirID. Since
1680 ** multiple separators at the end of a pathname always specifies
1681 ** a directory, we only need to work-around cases where the
1682 ** object is a directory and there are multiple separators at
1683 ** the end of the name parameter.
1685 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1687 /* Its a directory */
1689 /* is there a pathname? */
1690 if ( pb
.hFileInfo
.ioNamePtr
== name
)
1692 /* could it contain multiple separators? */
1695 /* does it contain multiple separators at the end? */
1696 if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') )
1698 /* OK, then do the extra stuff to get the correct parID */
1700 /* Get the real vRefNum (this should not fail) */
1701 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
1702 if ( error
== noErr
)
1704 /* we don't need the parent's name, but add protect against File Sharing problem */
1706 pb
.dirInfo
.ioNamePtr
= tempName
;
1707 pb
.dirInfo
.ioVRefNum
= realVRefNum
;
1708 /* pb.dirInfo.ioDrDirID already contains the */
1709 /* dirID of the directory object */
1710 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1711 error
= PBGetCatInfoSync(&pb
);
1712 /* now, pb.dirInfo.ioDrParID contains the correct parID */
1719 if ( error
== noErr
)
1721 /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
1722 /* contains the parent ID */
1723 *parID
= pb
.hFileInfo
.ioFlParID
;
1730 /*****************************************************************************/
1732 pascal OSErr
GetFilenameFromPathname(ConstStr255Param pathname
,
1739 /* default to no filename */
1742 /* check for no pathname */
1743 if ( pathname
!= NULL
)
1745 /* get string length */
1746 index
= pathname
[0];
1748 /* check for empty string */
1751 /* skip over last trailing colon (if any) */
1752 if ( pathname
[index
] == ':' )
1757 /* save the end of the string */
1760 /* if pathname ends with multiple colons, then this pathname refers */
1761 /* to a directory, not a file */
1762 if ( pathname
[index
] != ':' )
1764 /* parse backwards until we find a colon or hit the beginning of the pathname */
1765 while ( (index
!= 0) && (pathname
[index
] != ':') )
1770 /* if we parsed to the beginning of the pathname and the pathname ended */
1771 /* with a colon, then pathname is a full pathname to a volume, not a file */
1772 if ( (index
!= 0) || (pathname
[pathname
[0]] != ':') )
1774 /* get the filename and return noErr */
1775 filename
[0] = (char)(nameEnd
- index
);
1776 BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd
- index
);
1781 /* pathname to a volume, not a file */
1782 error
= notAFileErr
;
1787 /* directory, not a file */
1788 error
= notAFileErr
;
1793 /* empty string isn't a file */
1794 error
= notAFileErr
;
1799 /* NULL pathname isn't a file */
1800 error
= notAFileErr
;
1806 /*****************************************************************************/
1808 pascal OSErr
GetObjectLocation(short vRefNum
,
1810 ConstStr255Param pathname
,
1814 Boolean
*isDirectory
)
1818 Str255 tempPathname
;
1826 ** Get the real vRefNum
1828 error
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
);
1829 if ( error
== noErr
)
1832 ** Determine if the object already exists and if so,
1833 ** get the real parent directory ID if it's a file
1836 /* Protection against File Sharing problem */
1837 if ( (pathname
== NULL
) || (pathname
[0] == 0) )
1839 tempPathname
[0] = 0;
1840 pb
.hFileInfo
.ioNamePtr
= tempPathname
;
1841 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1845 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)pathname
;
1846 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1848 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1849 pb
.hFileInfo
.ioDirID
= dirID
;
1850 error
= PBGetCatInfoSync(&pb
);
1851 if ( error
== noErr
)
1854 ** The file system object is present and we have the file's real parID
1857 /* Is it a directory or a file? */
1858 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1862 ** It's a directory, get its name and parent dirID, and then we're done
1865 pb
.dirInfo
.ioNamePtr
= realName
;
1866 pb
.dirInfo
.ioVRefNum
= *realVRefNum
;
1867 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
1868 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1869 error
= PBGetCatInfoSync(&pb
);
1871 /* get the parent ID here, because the file system can return the */
1872 /* wrong parent ID from the last call. */
1873 *realParID
= pb
.dirInfo
.ioDrParID
;
1878 ** It's a file - use the parent directory ID from the last call
1879 ** to GetCatInfoparse, get the file name, and then we're done
1881 *realParID
= pb
.hFileInfo
.ioFlParID
;
1882 error
= GetFilenameFromPathname(pathname
, realName
);
1885 else if ( error
== fnfErr
)
1888 ** The file system object is not present - see if its parent is present
1892 ** Parse to get the object name from end of pathname
1894 error
= GetFilenameFromPathname(pathname
, realName
);
1896 /* if we can't get the object name from the end, we can't continue */
1897 if ( error
== noErr
)
1900 ** What we want now is the pathname minus the object name
1902 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
1903 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
1904 ** if pathname is ':dir:file' tempPathname becomes ':dir:'
1905 ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
1906 ** if pathname is ':file' tempPathname becomes ':'
1907 ** if pathname is 'file or file:' tempPathname becomes ''
1910 /* get a copy of the pathname */
1911 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1);
1913 /* remove the object name */
1914 tempPathname
[0] -= realName
[0];
1915 /* and the trailing colon (if any) */
1916 if ( pathname
[pathname
[0]] == ':' )
1921 /* OK, now get the parent's directory ID */
1923 /* Protection against File Sharing problem */
1924 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)tempPathname
;
1925 if ( tempPathname
[0] != 0 )
1927 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1931 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1933 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1934 pb
.hFileInfo
.ioDirID
= dirID
;
1935 error
= PBGetCatInfoSync(&pb
);
1936 *realParID
= pb
.dirInfo
.ioDrDirID
;
1938 *isDirectory
= false; /* we don't know what the object is really going to be */
1941 if ( error
!= noErr
)
1943 error
= dirNFErr
; /* couldn't find parent directory */
1947 error
= fnfErr
; /* we found the parent, but not the file */
1955 /*****************************************************************************/
1957 pascal OSErr
GetDirItems(short vRefNum
,
1959 ConstStr255Param name
,
1961 Boolean getDirectories
,
1964 short *actItemCount
,
1965 short *itemIndex
) /* start with 1, then use what's returned */
1970 Boolean isDirectory
;
1971 FSSpec
*endItemsArray
;
1973 if ( *itemIndex
> 0 )
1975 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
1976 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
1977 /* routine would be much faster because of the overhead of DetermineVRefNum and */
1978 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
1979 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
1980 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
1981 /* to this routine. */
1983 /* get the real volume reference number */
1984 error
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
);
1985 if ( error
== noErr
)
1987 /* and the real directory ID of this directory (and make sure it IS a directory) */
1988 error
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
);
1989 if ( error
== noErr
)
1994 endItemsArray
= items
+ reqItemCount
;
1995 while ( (items
< endItemsArray
) && (error
== noErr
) )
1997 pb
.hFileInfo
.ioNamePtr
= (StringPtr
) &items
->name
;
1998 pb
.hFileInfo
.ioDirID
= theDirID
;
1999 pb
.hFileInfo
.ioFDirIndex
= *itemIndex
;
2000 error
= PBGetCatInfoSync(&pb
);
2001 if ( error
== noErr
)
2003 items
->parID
= pb
.hFileInfo
.ioFlParID
; /* return item's parID */
2004 items
->vRefNum
= pb
.hFileInfo
.ioVRefNum
; /* return item's vRefNum */
2005 ++*itemIndex
; /* prepare to get next item in directory */
2007 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2009 if ( getDirectories
)
2011 ++*actItemCount
; /* keep this item */
2012 ++items
; /* point to next item */
2019 ++*actItemCount
; /* keep this item */
2020 ++items
; /* point to next item */
2028 /* it wasn't a directory */
2043 /*****************************************************************************/
2045 static void DeleteLevel(long dirToDelete
,
2046 DeleteEnumGlobalsPtr theGlobals
)
2052 /* prepare to delete directory */
2053 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= (StringPtr
)&theGlobals
->itemName
;
2054 theGlobals
->myPB
.ciPB
.dirInfo
.ioFDirIndex
= 1; /* get first item */
2055 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= dirToDelete
; /* in this directory */
2056 theGlobals
->error
= PBGetCatInfoSync(&(theGlobals
->myPB
.ciPB
));
2057 if ( theGlobals
->error
== noErr
)
2059 savedDir
= dirToDelete
;
2060 /* We have an item. Is it a file or directory? */
2061 if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2063 /* it's a directory */
2064 savedDir
= theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
; /* save dirID of directory instead */
2065 DeleteLevel(theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
, theGlobals
); /* Delete its contents */
2066 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= NULL
; /* prepare to delete directory */
2068 if ( theGlobals
->error
== noErr
)
2070 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= savedDir
; /* restore dirID */
2071 theGlobals
->myPB
.hPB
.fileParam
.ioFVersNum
= 0; /* just in case it's used on an MFS volume... */
2072 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* delete this item */
2073 if ( theGlobals
->error
== fLckdErr
)
2075 (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
)); /* unlock it */
2076 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* and try again */
2080 } while ( theGlobals
->error
== noErr
);
2082 if ( theGlobals
->error
== fnfErr
)
2084 theGlobals
->error
= noErr
;
2088 /*****************************************************************************/
2090 pascal OSErr
DeleteDirectoryContents(short vRefNum
,
2092 ConstStr255Param name
)
2094 DeleteEnumGlobals theGlobals
;
2095 Boolean isDirectory
;
2098 /* Get the real dirID and make sure it is a directory. */
2099 error
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
);
2100 if ( error
== noErr
)
2104 /* Get the real vRefNum */
2105 error
= DetermineVRefNum(name
, vRefNum
, &vRefNum
);
2106 if ( error
== noErr
)
2108 /* Set up the globals we need to access from the recursive routine. */
2109 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum
= vRefNum
;
2111 /* Here we go into recursion land... */
2112 DeleteLevel(dirID
, &theGlobals
);
2113 error
= theGlobals
.error
;
2125 /*****************************************************************************/
2127 pascal OSErr
DeleteDirectory(short vRefNum
,
2129 ConstStr255Param name
)
2133 /* Make sure a directory was specified and then delete its contents */
2134 error
= DeleteDirectoryContents(vRefNum
, dirID
, name
);
2135 if ( error
== noErr
)
2137 error
= HDelete(vRefNum
, dirID
, name
);
2138 if ( error
== fLckdErr
)
2140 (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */
2141 error
= HDelete(vRefNum
, dirID
, name
); /* and try again */
2148 /*****************************************************************************/
2150 pascal OSErr
CheckObjectLock(short vRefNum
,
2152 ConstStr255Param name
)
2157 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
2158 if ( error
== noErr
)
2160 /* check locked bit */
2161 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0 )
2170 /*****************************************************************************/
2172 pascal OSErr
FSpCheckObjectLock(const FSSpec
*spec
)
2174 return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2177 /*****************************************************************************/
2179 pascal OSErr
GetFileSize(short vRefNum
,
2181 ConstStr255Param fileName
,
2188 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2189 pb
.fileParam
.ioVRefNum
= vRefNum
;
2190 pb
.fileParam
.ioFVersNum
= 0;
2191 pb
.fileParam
.ioDirID
= dirID
;
2192 pb
.fileParam
.ioFDirIndex
= 0;
2193 error
= PBHGetFInfoSync(&pb
);
2194 if ( error
== noErr
)
2196 *dataSize
= pb
.fileParam
.ioFlLgLen
;
2197 *rsrcSize
= pb
.fileParam
.ioFlRLgLen
;
2203 /*****************************************************************************/
2205 pascal OSErr
FSpGetFileSize(const FSSpec
*spec
,
2209 return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) );
2212 /*****************************************************************************/
2214 pascal OSErr
BumpDate(short vRefNum
,
2216 ConstStr255Param name
)
2217 /* Given a file or directory, change its modification date to the current date/time. */
2224 /* Protection against File Sharing problem */
2225 if ( (name
== NULL
) || (name
[0] == 0) )
2228 pb
.hFileInfo
.ioNamePtr
= tempName
;
2229 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2233 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2234 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2236 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2237 pb
.hFileInfo
.ioDirID
= dirID
;
2238 error
= PBGetCatInfoSync(&pb
);
2239 if ( error
== noErr
)
2242 /* set mod date to current date, or one second into the future
2243 if mod date = current date */
2244 pb
.hFileInfo
.ioFlMdDat
= (secs
== pb
.hFileInfo
.ioFlMdDat
) ? (++secs
) : (secs
);
2245 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2247 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2251 pb
.hFileInfo
.ioDirID
= dirID
;
2253 error
= PBSetCatInfoSync(&pb
);
2259 /*****************************************************************************/
2261 pascal OSErr
FSpBumpDate(const FSSpec
*spec
)
2263 return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2266 /*****************************************************************************/
2268 pascal OSErr
ChangeCreatorType(short vRefNum
,
2270 ConstStr255Param name
,
2279 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2280 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2281 pb
.hFileInfo
.ioDirID
= dirID
;
2282 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2283 error
= PBGetCatInfoSync(&pb
);
2284 if ( error
== noErr
)
2286 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 ) /* if file */
2288 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2290 /* If creator not 0x00000000, change creator */
2291 if ( creator
!= (OSType
)0x00000000 )
2293 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
= creator
;
2296 /* If fileType not 0x00000000, change fileType */
2297 if ( fileType
!= (OSType
)0x00000000 )
2299 pb
.hFileInfo
.ioFlFndrInfo
.fdType
= fileType
;
2302 pb
.hFileInfo
.ioDirID
= dirID
;
2303 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2305 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2307 /* get the real vRefNum in case a full pathname was passed */
2308 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2309 if ( error
== noErr
)
2311 error
= BumpDate(realVRefNum
, parID
, NULL
);
2312 /* and bump the parent directory's mod date to wake up the Finder */
2313 /* to the change we just made */
2319 /* it was a directory, not a file */
2320 error
= notAFileErr
;
2327 /*****************************************************************************/
2329 pascal OSErr
FSpChangeCreatorType(const FSSpec
*spec
,
2333 return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) );
2336 /*****************************************************************************/
2338 pascal OSErr
ChangeFDFlags(short vRefNum
,
2340 ConstStr255Param name
,
2342 unsigned short flagBits
)
2350 /* Protection against File Sharing problem */
2351 if ( (name
== NULL
) || (name
[0] == 0) )
2354 pb
.hFileInfo
.ioNamePtr
= tempName
;
2355 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2359 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2360 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2362 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2363 pb
.hFileInfo
.ioDirID
= dirID
;
2364 error
= PBGetCatInfoSync(&pb
);
2365 if ( error
== noErr
)
2367 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2369 /* set or clear the appropriate bits in the Finder flags */
2372 /* OR in the bits */
2373 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
|= flagBits
;
2377 /* AND out the bits */
2378 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
&= ~flagBits
;
2381 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2383 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2387 pb
.hFileInfo
.ioDirID
= dirID
;
2390 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2392 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2394 /* get the real vRefNum in case a full pathname was passed */
2395 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2396 if ( error
== noErr
)
2398 error
= BumpDate(realVRefNum
, parID
, NULL
);
2399 /* and bump the parent directory's mod date to wake up the Finder */
2400 /* to the change we just made */
2408 /*****************************************************************************/
2410 pascal OSErr
FSpChangeFDFlags(const FSSpec
*spec
,
2412 unsigned short flagBits
)
2414 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) );
2417 /*****************************************************************************/
2419 pascal OSErr
SetIsInvisible(short vRefNum
,
2421 ConstStr255Param name
)
2422 /* Given a file or directory, make it invisible. */
2424 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) );
2427 /*****************************************************************************/
2429 pascal OSErr
FSpSetIsInvisible(const FSSpec
*spec
)
2430 /* Given a file or directory, make it invisible. */
2432 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) );
2435 /*****************************************************************************/
2437 pascal OSErr
ClearIsInvisible(short vRefNum
,
2439 ConstStr255Param name
)
2440 /* Given a file or directory, make it visible. */
2442 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) );
2445 /*****************************************************************************/
2447 pascal OSErr
FSpClearIsInvisible(const FSSpec
*spec
)
2448 /* Given a file or directory, make it visible. */
2450 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) );
2453 /*****************************************************************************/
2455 pascal OSErr
SetNameLocked(short vRefNum
,
2457 ConstStr255Param name
)
2458 /* Given a file or directory, lock its name. */
2460 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) );
2463 /*****************************************************************************/
2465 pascal OSErr
FSpSetNameLocked(const FSSpec
*spec
)
2466 /* Given a file or directory, lock its name. */
2468 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) );
2471 /*****************************************************************************/
2473 pascal OSErr
ClearNameLocked(short vRefNum
,
2475 ConstStr255Param name
)
2476 /* Given a file or directory, unlock its name. */
2478 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) );
2481 /*****************************************************************************/
2483 pascal OSErr
FSpClearNameLocked(const FSSpec
*spec
)
2484 /* Given a file or directory, unlock its name. */
2486 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) );
2489 /*****************************************************************************/
2491 pascal OSErr
SetIsStationery(short vRefNum
,
2493 ConstStr255Param name
)
2494 /* Given a file, make it a stationery pad. */
2496 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) );
2499 /*****************************************************************************/
2501 pascal OSErr
FSpSetIsStationery(const FSSpec
*spec
)
2502 /* Given a file, make it a stationery pad. */
2504 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) );
2507 /*****************************************************************************/
2509 pascal OSErr
ClearIsStationery(short vRefNum
,
2511 ConstStr255Param name
)
2512 /* Given a file, clear the stationery bit. */
2514 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) );
2517 /*****************************************************************************/
2519 pascal OSErr
FSpClearIsStationery(const FSSpec
*spec
)
2520 /* Given a file, clear the stationery bit. */
2522 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) );
2525 /*****************************************************************************/
2527 pascal OSErr
SetHasCustomIcon(short vRefNum
,
2529 ConstStr255Param name
)
2530 /* Given a file or directory, indicate that it has a custom icon. */
2532 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) );
2535 /*****************************************************************************/
2537 pascal OSErr
FSpSetHasCustomIcon(const FSSpec
*spec
)
2538 /* Given a file or directory, indicate that it has a custom icon. */
2540 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) );
2543 /*****************************************************************************/
2545 pascal OSErr
ClearHasCustomIcon(short vRefNum
,
2547 ConstStr255Param name
)
2548 /* Given a file or directory, indicate that it does not have a custom icon. */
2550 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) );
2553 /*****************************************************************************/
2555 pascal OSErr
FSpClearHasCustomIcon(const FSSpec
*spec
)
2556 /* Given a file or directory, indicate that it does not have a custom icon. */
2558 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) );
2561 /*****************************************************************************/
2563 pascal OSErr
ClearHasBeenInited(short vRefNum
,
2565 ConstStr255Param name
)
2566 /* Given a file, clear its "has been inited" bit. */
2568 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) );
2571 /*****************************************************************************/
2573 pascal OSErr
FSpClearHasBeenInited(const FSSpec
*spec
)
2574 /* Given a file, clear its "has been inited" bit. */
2576 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) );
2579 /*****************************************************************************/
2581 pascal OSErr
CopyFileMgrAttributes(short srcVRefNum
,
2583 ConstStr255Param srcName
,
2586 ConstStr255Param dstName
,
2587 Boolean copyLockBit
)
2592 Boolean objectIsDirectory
;
2594 pb
.ciPB
.hFileInfo
.ioVRefNum
= srcVRefNum
;
2595 pb
.ciPB
.hFileInfo
.ioDirID
= srcDirID
;
2597 /* Protection against File Sharing problem */
2598 if ( (srcName
== NULL
) || (srcName
[0] == 0) )
2601 pb
.ciPB
.hFileInfo
.ioNamePtr
= tempName
;
2602 pb
.ciPB
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2606 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)srcName
;
2607 pb
.ciPB
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2609 error
= PBGetCatInfoSync(&pb
.ciPB
);
2610 if ( error
== noErr
)
2612 objectIsDirectory
= ( (pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 );
2613 pb
.ciPB
.hFileInfo
.ioVRefNum
= dstVRefNum
;
2614 pb
.ciPB
.hFileInfo
.ioDirID
= dstDirID
;
2615 if ( (dstName
!= NULL
) && (dstName
[0] == 0) )
2617 pb
.ciPB
.hFileInfo
.ioNamePtr
= NULL
;
2621 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)dstName
;
2623 /* don't copy the hasBeenInited bit */
2624 pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
= ( pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
& ~kHasBeenInited
);
2625 error
= PBSetCatInfoSync(&pb
.ciPB
);
2626 if ( (error
== noErr
) && (copyLockBit
) && ((pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0) )
2628 pb
.hPB
.fileParam
.ioFVersNum
= 0;
2629 error
= PBHSetFLockSync(&pb
.hPB
);
2630 if ( (error
!= noErr
) && (objectIsDirectory
) )
2632 error
= noErr
; /* ignore lock errors if destination is directory */
2639 /*****************************************************************************/
2641 pascal OSErr
FSpCopyFileMgrAttributes(const FSSpec
*srcSpec
,
2642 const FSSpec
*dstSpec
,
2643 Boolean copyLockBit
)
2645 return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
2646 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
,
2650 /*****************************************************************************/
2652 pascal OSErr
HOpenAware(short vRefNum
,
2654 ConstStr255Param fileName
,
2660 GetVolParmsInfoBuffer volParmsInfo
;
2661 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2663 pb
.ioParam
.ioMisc
= NULL
;
2664 pb
.fileParam
.ioFVersNum
= 0;
2665 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2666 pb
.fileParam
.ioVRefNum
= vRefNum
;
2667 pb
.fileParam
.ioDirID
= dirID
;
2669 /* get volume attributes */
2670 /* this preflighting is needed because Foreign File Access based file systems don't */
2671 /* return the correct error result to the OpenDeny call */
2672 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2673 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2675 /* if volume supports OpenDeny, use it and return */
2676 pb
.accessParam
.ioDenyModes
= denyModes
;
2677 error
= PBHOpenDenySync(&pb
);
2678 *refNum
= pb
.ioParam
.ioRefNum
;
2680 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2682 /* OpenDeny isn't supported, so try File Manager Open functions */
2684 /* If request includes write permission, then see if the volume is */
2685 /* locked by hardware or software. The HFS file system doesn't check */
2686 /* for this when a file is opened - you only find out later when you */
2687 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2689 if ( (denyModes
& dmWr
) != 0 )
2691 error
= CheckVolLock(fileName
, vRefNum
);
2698 if ( error
== noErr
)
2700 /* Set File Manager permissions to closest thing possible */
2701 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2703 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2707 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2710 error
= PBHOpenDFSync(&pb
); /* Try OpenDF */
2711 if ( error
== paramErr
)
2713 error
= PBHOpenSync(&pb
); /* OpenDF not supported, so try Open */
2715 *refNum
= pb
.ioParam
.ioRefNum
;
2722 /*****************************************************************************/
2724 pascal OSErr
FSpOpenAware(const FSSpec
*spec
,
2728 return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2731 /*****************************************************************************/
2733 pascal OSErr
HOpenRFAware(short vRefNum
,
2735 ConstStr255Param fileName
,
2741 GetVolParmsInfoBuffer volParmsInfo
;
2742 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2744 pb
.ioParam
.ioMisc
= NULL
;
2745 pb
.fileParam
.ioFVersNum
= 0;
2746 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2747 pb
.fileParam
.ioVRefNum
= vRefNum
;
2748 pb
.fileParam
.ioDirID
= dirID
;
2750 /* get volume attributes */
2751 /* this preflighting is needed because Foreign File Access based file systems don't */
2752 /* return the correct error result to the OpenRFDeny call */
2753 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2754 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2756 /* if volume supports OpenRFDeny, use it and return */
2757 if ( hasOpenDeny(&volParmsInfo
) )
2759 pb
.accessParam
.ioDenyModes
= denyModes
;
2760 error
= PBHOpenRFDenySync(&pb
);
2761 *refNum
= pb
.ioParam
.ioRefNum
;
2764 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2766 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
2768 /* If request includes write permission, then see if the volume is */
2769 /* locked by hardware or software. The HFS file system doesn't check */
2770 /* for this when a file is opened - you only find out later when you */
2771 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2773 if ( (denyModes
& dmWr
) != 0 )
2775 error
= CheckVolLock(fileName
, vRefNum
);
2782 if ( error
== noErr
)
2784 /* Set File Manager permissions to closest thing possible */
2785 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2787 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2791 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2794 error
= PBHOpenRFSync(&pb
);
2795 *refNum
= pb
.ioParam
.ioRefNum
;
2802 /*****************************************************************************/
2804 pascal OSErr
FSpOpenRFAware(const FSSpec
*spec
,
2808 return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2811 /*****************************************************************************/
2813 pascal OSErr
FSReadNoCache(short refNum
,
2820 pb
.ioParam
.ioRefNum
= refNum
;
2821 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2822 pb
.ioParam
.ioReqCount
= *count
;
2823 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2824 pb
.ioParam
.ioPosOffset
= 0;
2825 error
= PBReadSync(&pb
);
2826 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2830 /*****************************************************************************/
2832 pascal OSErr
FSWriteNoCache(short refNum
,
2834 const void *buffPtr
)
2839 pb
.ioParam
.ioRefNum
= refNum
;
2840 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2841 pb
.ioParam
.ioReqCount
= *count
;
2842 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2843 pb
.ioParam
.ioPosOffset
= 0;
2844 error
= PBWriteSync(&pb
);
2845 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2849 /*****************************************************************************/
2852 ** See if numBytes bytes of buffer1 are equal to buffer2.
2854 static Boolean
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
)
2856 register unsigned char *b1
= (unsigned char *)buffer1
;
2857 register unsigned char *b2
= (unsigned char *)buffer2
;
2859 if ( b1
!= b2
) /* if buffer pointers are same, then they are equal */
2861 while ( numBytes
> 0 )
2863 /* compare the bytes and then increment the pointers */
2864 if ( (*b1
++ - *b2
++) != 0 )
2875 /*****************************************************************************/
2878 ** Read any number of bytes from an open file using read-verify mode.
2879 ** The FSReadVerify function reads any number of bytes from an open file
2880 ** and verifies them against the data in the buffer pointed to by buffPtr.
2882 ** Because of a bug in the HFS file system, only non-block aligned parts of
2883 ** the read are verified against the buffer data and the rest is *copied*
2884 ** into the buffer. Thus, you shouldn't verify against your original data;
2885 ** instead, you should verify against a copy of the original data and then
2886 ** compare the read-verified copy against the original data after calling
2887 ** FSReadVerify. That's why this function isn't exported - it needs the
2888 ** wrapper provided by FSWriteVerify.
2890 static OSErr
FSReadVerify(short refNum
,
2897 pb
.ioParam
.ioRefNum
= refNum
;
2898 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2899 pb
.ioParam
.ioReqCount
= *count
;
2900 pb
.ioParam
.ioPosMode
= fsAtMark
+ rdVerify
;
2901 pb
.ioParam
.ioPosOffset
= 0;
2902 result
= PBReadSync(&pb
);
2903 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2907 /*****************************************************************************/
2909 pascal OSErr
FSWriteVerify(short refNum
,
2911 const void *buffPtr
)
2922 ** Allocate the verify buffer
2923 ** Try to get get a large enough buffer to verify in one pass.
2924 ** If that fails, use GetTempBuffer to get a buffer.
2926 bufferSize
= *count
;
2927 verifyBuffer
= NewPtr(bufferSize
);
2928 if ( verifyBuffer
== NULL
)
2930 verifyBuffer
= GetTempBuffer(bufferSize
, &bufferSize
);
2932 if ( verifyBuffer
!= NULL
)
2934 /* Save the current position */
2935 result
= GetFPos(refNum
, &position
);
2936 if ( result
== noErr
)
2938 /* Write the data */
2939 result
= FSWrite(refNum
, count
, buffPtr
);
2940 if ( result
== noErr
)
2942 /* Restore the original position */
2943 result
= SetFPos(refNum
, fsFromStart
, position
);
2944 if ( result
== noErr
)
2947 ** *count = total number of bytes to verify
2948 ** bufferSize = the size of the verify buffer
2949 ** bytesVerified = number of bytes verified
2950 ** byteCount = number of bytes to verify this pass
2951 ** startVerify = position in buffPtr
2954 startVerify
= (Ptr
)buffPtr
;
2955 while ( (bytesVerified
< *count
) && ( result
== noErr
) )
2957 if ( (*count
- bytesVerified
) > bufferSize
)
2959 byteCount
= bufferSize
;
2963 byteCount
= *count
- bytesVerified
;
2966 ** Copy the write buffer into the verify buffer.
2967 ** This step is needed because the File Manager
2968 ** compares the data in any non-block aligned
2969 ** data at the beginning and end of the read-verify
2970 ** request back into the file system's cache
2971 ** to the data in verify Buffer. However, the
2972 ** File Manager does not compare any full blocks
2973 ** and instead copies them into the verify buffer
2974 ** so we still have to compare the buffers again
2975 ** after the read-verify request completes.
2977 BlockMoveData(startVerify
, verifyBuffer
, byteCount
);
2979 /* Read-verify the data back into the verify buffer */
2980 result
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
);
2981 if ( result
== noErr
)
2983 /* See if the buffers are the same */
2984 if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) )
2988 startVerify
+= byteCount
;
2989 bytesVerified
+= byteCount
;
2995 DisposePtr(verifyBuffer
);
2999 result
= memFullErr
;
3004 /*****************************************************************************/
3006 pascal OSErr
CopyFork(short srcRefNum
,
3008 void *copyBufferPtr
,
3009 long copyBufferSize
)
3011 ParamBlockRec srcPB
;
3012 ParamBlockRec dstPB
;
3016 if ( (copyBufferPtr
== NULL
) || (copyBufferSize
== 0) )
3017 return ( paramErr
);
3019 srcPB
.ioParam
.ioRefNum
= srcRefNum
;
3020 dstPB
.ioParam
.ioRefNum
= dstRefNum
;
3022 /* preallocate the destination fork and */
3023 /* ensure the destination fork's EOF is correct after the copy */
3024 srcError
= PBGetEOFSync(&srcPB
);
3025 if ( srcError
!= noErr
)
3026 return ( srcError
);
3027 dstPB
.ioParam
.ioMisc
= srcPB
.ioParam
.ioMisc
;
3028 dstError
= PBSetEOFSync(&dstPB
);
3029 if ( dstError
!= noErr
)
3030 return ( dstError
);
3032 /* reset source fork's mark */
3033 srcPB
.ioParam
.ioPosMode
= fsFromStart
;
3034 srcPB
.ioParam
.ioPosOffset
= 0;
3035 srcError
= PBSetFPosSync(&srcPB
);
3036 if ( srcError
!= noErr
)
3037 return ( srcError
);
3039 /* reset destination fork's mark */
3040 dstPB
.ioParam
.ioPosMode
= fsFromStart
;
3041 dstPB
.ioParam
.ioPosOffset
= 0;
3042 dstError
= PBSetFPosSync(&dstPB
);
3043 if ( dstError
!= noErr
)
3044 return ( dstError
);
3046 /* set up fields that won't change in the loop */
3047 srcPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3048 srcPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3049 /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
3050 /* This will make writes on local volumes faster */
3051 if ( (copyBufferSize
>= 512) && ((copyBufferSize
& 0x1ff) != 0) )
3053 srcPB
.ioParam
.ioReqCount
= copyBufferSize
& 0xfffffe00;
3057 srcPB
.ioParam
.ioReqCount
= copyBufferSize
;
3059 dstPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3060 dstPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3062 while ( (srcError
== noErr
) && (dstError
== noErr
) )
3064 srcError
= PBReadSync(&srcPB
);
3065 dstPB
.ioParam
.ioReqCount
= srcPB
.ioParam
.ioActCount
;
3066 dstError
= PBWriteSync(&dstPB
);
3069 /* make sure there were no errors at the destination */
3070 if ( dstError
!= noErr
)
3071 return ( dstError
);
3073 /* make sure the only error at the source was eofErr */
3074 if ( srcError
!= eofErr
)
3075 return ( srcError
);
3080 /*****************************************************************************/
3082 pascal OSErr
GetFileLocation(short refNum
,
3090 pb
.ioNamePtr
= fileName
;
3092 pb
.ioRefNum
= refNum
;
3094 error
= PBGetFCBInfoSync(&pb
);
3095 if ( error
== noErr
)
3097 *vRefNum
= pb
.ioFCBVRefNum
;
3098 *dirID
= pb
.ioFCBParID
;
3103 /*****************************************************************************/
3105 pascal OSErr
FSpGetFileLocation(short refNum
,
3108 return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) );
3111 /*****************************************************************************/
3113 pascal OSErr
CopyDirectoryAccess(short srcVRefNum
,
3115 ConstStr255Param srcName
,
3118 ConstStr255Param dstName
)
3121 GetVolParmsInfoBuffer infoBuffer
; /* Where PBGetVolParms dumps its info */
3122 long dstServerAdr
; /* AppleTalk server address of destination (if any) */
3123 long ownerID
, groupID
, accessRights
;
3126 /* See if destination supports directory access control */
3127 tempLong
= sizeof(infoBuffer
);
3128 error
= HGetVolParms(dstName
, dstVRefNum
, &infoBuffer
, &tempLong
);
3129 if ( (error
== noErr
) && hasAccessCntl(&infoBuffer
) )
3131 if ( hasAccessCntl(&infoBuffer
) )
3133 dstServerAdr
= infoBuffer
.vMServerAdr
;
3135 /* See if source supports directory access control and is on same server */
3136 tempLong
= sizeof(infoBuffer
);
3137 error
= HGetVolParms(srcName
, srcVRefNum
, &infoBuffer
, &tempLong
);
3138 if ( error
== noErr
)
3140 if ( hasAccessCntl(&infoBuffer
) && (dstServerAdr
== infoBuffer
.vMServerAdr
) )
3142 /* both volumes support directory access control and they are */
3143 /* on same server, so copy the access information */
3144 error
= HGetDirAccess(srcVRefNum
, srcDirID
, srcName
, &ownerID
, &groupID
, &accessRights
);
3145 if ( error
== noErr
)
3147 error
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
);
3152 /* destination doesn't support directory access control or */
3153 /* they volumes aren't on the same server */
3160 /* destination doesn't support directory access control */
3168 /*****************************************************************************/
3170 pascal OSErr
FSpCopyDirectoryAccess(const FSSpec
*srcSpec
,
3171 const FSSpec
*dstSpec
)
3173 return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3174 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) );
3177 /*****************************************************************************/
3179 pascal OSErr
HMoveRenameCompat(short vRefNum
,
3181 ConstStr255Param srcName
,
3183 ConstStr255Param dstpathName
,
3184 ConstStr255Param copyName
)
3187 GetVolParmsInfoBuffer volParmsInfo
;
3192 Boolean isDirectory
;
3193 long tempItemsDirID
;
3194 long uniqueTempDirID
;
3195 Str31 uniqueTempDirName
;
3196 unsigned short uniqueNameoverflow
;
3198 /* Get volume attributes */
3199 infoSize
= sizeof(GetVolParmsInfoBuffer
);
3200 error
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
);
3201 if ( (error
== noErr
) && hasMoveRename(&volParmsInfo
) )
3203 /* If volume supports move and rename, so use it and return */
3204 error
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
);
3206 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
3208 /* MoveRename isn't supported by this volume, so do it by hand */
3210 /* If copyName isn't supplied, we can simply CatMove and return */
3211 if ( copyName
== NULL
)
3213 error
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
);
3217 /* Renaming is required, so we have some work to do... */
3219 /* Get the object's real name, real parent ID and real vRefNum */
3220 error
= GetObjectLocation(vRefNum
, srcDirID
, (StringPtr
)srcName
,
3221 &realVRefNum
, &realParID
, realName
, &isDirectory
);
3222 if ( error
== noErr
)
3224 /* Find the Temporary Items Folder on that volume */
3225 error
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
,
3226 &realVRefNum
, &tempItemsDirID
);
3227 if ( error
== noErr
)
3229 /* Create a new uniquely named folder in the temporary items folder. */
3230 /* This is done to avoid the case where 'realName' or 'copyName' already */
3231 /* exists in the temporary items folder. */
3233 /* Start with current tick count as uniqueTempDirName */
3234 NumToString(TickCount(), uniqueTempDirName
);
3235 uniqueNameoverflow
= 0;
3238 error
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
);
3239 if ( error
== dupFNErr
)
3241 /* Duplicate name - change the first character to the next ASCII character */
3242 ++uniqueTempDirName
[1];
3243 /* Make sure it isn't a colon! */
3244 if ( uniqueTempDirName
[1] == ':' )
3246 ++uniqueTempDirName
[1];
3248 /* Don't go too far... */
3249 ++uniqueNameoverflow
;
3251 } while ( (error
== dupFNErr
) && (uniqueNameoverflow
<= 64) ); /* 64 new files per 1/60th second - not likely! */
3252 if ( error
== noErr
)
3254 /* Move the object to the folder with uniqueTempDirID for renaming */
3255 error
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
);
3256 if ( error
== noErr
)
3258 /* Rename the object */
3259 error
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
);
3260 if ( error
== noErr
)
3262 /* Move object to its new home */
3263 error
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
);
3264 if ( error
!= noErr
)
3266 /* Error handling: rename object back to original name - ignore errors */
3267 (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
);
3270 if ( error
!= noErr
)
3272 /* Error handling: move object back to original location - ignore errors */
3273 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
);
3276 /* Done with ourTempDir, so delete it - ignore errors */
3277 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
);
3287 /*****************************************************************************/
3289 pascal OSErr
FSpMoveRenameCompat(const FSSpec
*srcSpec
,
3290 const FSSpec
*dstSpec
,
3291 ConstStr255Param copyName
)
3293 /* make sure the FSSpecs refer to the same volume */
3294 if (srcSpec
->vRefNum
!= dstSpec
->vRefNum
)
3295 return (diffVolErr
);
3296 return ( HMoveRenameCompat(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3297 dstSpec
->parID
, dstSpec
->name
, copyName
) );
3300 /*****************************************************************************/
3302 pascal OSErr
BuildAFPVolMountInfo(short flags
,
3312 AFPVolMountInfoPtr
*afpInfoPtr
)
3314 MyAFPVolMountInfoPtr infoPtr
;
3317 /* Allocate the AFPXVolMountInfo record */
3318 infoPtr
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
));
3319 if ( infoPtr
!= NULL
)
3321 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
3322 infoPtr
->length
= sizeof(MyAFPVolMountInfo
);
3323 infoPtr
->media
= AppleShareMediaType
;
3324 infoPtr
->flags
= flags
;
3325 infoPtr
->nbpInterval
= nbpInterval
;
3326 infoPtr
->nbpCount
= nbpCount
;
3327 infoPtr
->uamType
= uamType
;
3329 infoPtr
->zoneNameOffset
= offsetof(MyAFPVolMountInfo
, zoneName
);
3330 infoPtr
->serverNameOffset
= offsetof(MyAFPVolMountInfo
, serverName
);
3331 infoPtr
->volNameOffset
= offsetof(MyAFPVolMountInfo
, volName
);
3332 infoPtr
->userNameOffset
= offsetof(MyAFPVolMountInfo
, userName
);
3333 infoPtr
->userPasswordOffset
= offsetof(MyAFPVolMountInfo
, userPassword
);
3334 infoPtr
->volPasswordOffset
= offsetof(MyAFPVolMountInfo
, volPassword
);
3336 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3337 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3338 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3339 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3340 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3341 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3343 *afpInfoPtr
= (AFPVolMountInfoPtr
)infoPtr
;
3354 /*****************************************************************************/
3356 pascal OSErr
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
,
3360 StringPtr serverName
,
3367 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3368 if ( afpInfoPtr
->media
== AppleShareMediaType
)
3370 *flags
= afpInfoPtr
->flags
;
3371 *uamType
= afpInfoPtr
->uamType
;
3373 if ( afpInfoPtr
->zoneNameOffset
!= 0)
3375 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->zoneNameOffset
);
3376 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3379 if ( afpInfoPtr
->serverNameOffset
!= 0)
3381 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->serverNameOffset
);
3382 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3385 if ( afpInfoPtr
->volNameOffset
!= 0)
3387 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->volNameOffset
);
3388 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3391 if ( afpInfoPtr
->userNameOffset
!= 0)
3393 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->userNameOffset
);
3394 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3407 /*****************************************************************************/
3409 pascal OSErr
BuildAFPXVolMountInfo(short flags
,
3420 unsigned long alternateAddressLength
,
3421 void *alternateAddress
,
3422 AFPXVolMountInfoPtr
*afpXInfoPtr
)
3425 MyAFPXVolMountInfoPtr infoPtr
;
3428 /* Calculate the size of the AFPXVolMountInfo record */
3429 infoSize
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength
- 1;
3431 /* Allocate the AFPXVolMountInfo record */
3432 infoPtr
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
);
3433 if ( infoPtr
!= NULL
)
3435 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
3436 infoPtr
->length
= infoSize
;
3437 infoPtr
->media
= AppleShareMediaType
;
3438 infoPtr
->flags
= flags
;
3439 if ( alternateAddressLength
!= 0 )
3441 /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
3442 infoPtr
->flags
|= volMountExtendedFlagsMask
;
3443 /* and set the only extendedFlags bit we know about */
3444 infoPtr
->extendedFlags
= kAFPExtendedFlagsAlternateAddressMask
;
3448 /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
3449 infoPtr
->flags
&= ~volMountExtendedFlagsMask
;
3450 /* and clear the extendedFlags */
3451 infoPtr
->extendedFlags
= 0;
3453 infoPtr
->nbpInterval
= nbpInterval
;
3454 infoPtr
->nbpCount
= nbpCount
;
3455 infoPtr
->uamType
= uamType
;
3457 infoPtr
->zoneNameOffset
= offsetof(MyAFPXVolMountInfo
, zoneName
);
3458 infoPtr
->serverNameOffset
= offsetof(MyAFPXVolMountInfo
, serverName
);
3459 infoPtr
->volNameOffset
= offsetof(MyAFPXVolMountInfo
, volName
);
3460 infoPtr
->userNameOffset
= offsetof(MyAFPXVolMountInfo
, userName
);
3461 infoPtr
->userPasswordOffset
= offsetof(MyAFPXVolMountInfo
, userPassword
);
3462 infoPtr
->volPasswordOffset
= offsetof(MyAFPXVolMountInfo
, volPassword
);
3463 infoPtr
->uamNameOffset
= offsetof(MyAFPXVolMountInfo
, uamName
);
3464 infoPtr
->alternateAddressOffset
= offsetof(MyAFPXVolMountInfo
, alternateAddress
);
3466 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3467 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3468 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3469 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3470 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3471 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3472 BlockMoveData(uamName
, infoPtr
->uamName
, sizeof(Str32
));
3473 BlockMoveData(alternateAddress
, infoPtr
->alternateAddress
, alternateAddressLength
);
3475 *afpXInfoPtr
= (AFPXVolMountInfoPtr
)infoPtr
;
3486 /*****************************************************************************/
3488 pascal OSErr
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
,
3492 StringPtr serverName
,
3496 unsigned long *alternateAddressLength
,
3497 AFPAlternateAddress
**alternateAddress
)
3500 Ptr alternateAddressStart
;
3501 Ptr alternateAddressEnd
;
3502 Size alternateAddressDataSize
;
3506 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3507 if ( afpXInfoPtr
->media
== AppleShareMediaType
)
3509 /* default to noErr */
3512 /* Is this an extended record? */
3513 if ( (afpXInfoPtr
->flags
& volMountExtendedFlagsMask
) != 0 )
3515 if ( ((afpXInfoPtr
->extendedFlags
& kAFPExtendedFlagsAlternateAddressMask
) != 0) &&
3516 (afpXInfoPtr
->alternateAddressOffset
!= 0) )
3519 alternateAddressStart
= (Ptr
)((long)afpXInfoPtr
+ afpXInfoPtr
->alternateAddressOffset
);
3520 alternateAddressEnd
= alternateAddressStart
+ 1; /* skip over alternate address version byte */
3521 addressCount
= *(UInt8
*)alternateAddressEnd
; /* get the address count */
3522 ++alternateAddressEnd
; /* skip over alternate address count byte */
3523 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
3524 while ( addressCount
!= 0 )
3526 /* parse the address list to find the end */
3527 alternateAddressEnd
+= *(UInt8
*)alternateAddressEnd
; /* add length of each AFPTagData record */
3530 /* get the size of the alternateAddressData */
3531 alternateAddressDataSize
= alternateAddressEnd
- alternateAddressStart
;
3532 /* allocate memory for it */
3533 *alternateAddress
= (AFPAlternateAddress
*)NewPtr(alternateAddressDataSize
);
3534 if ( *alternateAddress
!= NULL
)
3536 /* and return the data */
3537 BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
);
3538 *alternateAddressLength
= alternateAddressDataSize
;
3542 /* no memory - fail now */
3547 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3549 if ( afpXInfoPtr
->uamNameOffset
!= 0 )
3551 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->uamNameOffset
);
3552 BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1);
3557 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3559 *flags
= afpXInfoPtr
->flags
;
3560 *uamType
= afpXInfoPtr
->uamType
;
3562 if ( afpXInfoPtr
->zoneNameOffset
!= 0 )
3564 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->zoneNameOffset
);
3565 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3568 if ( afpXInfoPtr
->serverNameOffset
!= 0 )
3570 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->serverNameOffset
);
3571 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3574 if ( afpXInfoPtr
->volNameOffset
!= 0 )
3576 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->volNameOffset
);
3577 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3580 if ( afpXInfoPtr
->userNameOffset
!= 0 )
3582 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->userNameOffset
);
3583 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3595 /*****************************************************************************/
3597 pascal OSErr
GetUGEntries(short objType
,
3600 long *actEntryCount
,
3604 OSErr error
= noErr
;
3605 UGEntry
*endEntryArray
;
3607 pb
.objParam
.ioObjType
= objType
;
3609 for ( endEntryArray
= entries
+ reqEntryCount
; (entries
< endEntryArray
) && (error
== noErr
); ++entries
)
3611 pb
.objParam
.ioObjNamePtr
= (StringPtr
)entries
->name
;
3612 pb
.objParam
.ioObjID
= *objID
;
3613 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
3614 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
3615 /* A CMovePBPtr works OK, but this will be changed in the future back to */
3616 /* HParmBlkPtr, so I'm just casting it here. */
3617 error
= PBGetUGEntrySync(&pb
);
3618 if ( error
== noErr
)
3620 entries
->objID
= *objID
= pb
.objParam
.ioObjID
;
3621 entries
->objType
= objType
;
3629 /*****************************************************************************/