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.
46 #include <MacErrors.h>
47 #include <MacMemory.h>
55 #include <TextUtils.h>
58 #include <CodeFragments.h>
61 #define __COMPILINGMOREFILES
63 #include "MoreFiles.h"
64 #include "MoreDesktopMgr.h"
65 #include "FSpCompat.h"
67 #include "MoreFilesExtras.h"
69 /*****************************************************************************/
71 /* Functions to get information out of GetVolParmsInfoBuffer. */
73 /* version 1 field getters */
75 pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer
*volParms
)
77 return ( volParms
->vMVersion
);
80 pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer
*volParms
)
82 return ( volParms
->vMAttrib
);
85 pascal Handle
GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer
*volParms
)
87 return ( volParms
->vMLocalHand
);
90 pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer
*volParms
)
92 return ( volParms
->vMServerAdr
);
95 /* version 2 field getters (assume zero result if version < 2) */
97 pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer
*volParms
)
99 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMVolumeGrade
: 0 );
102 pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer
*volParms
)
104 return ( (volParms
->vMVersion
>= 2) ? volParms
->vMForeignPrivID
: 0 );
107 /* version 3 field getters (assume zero result if version < 3) */
109 pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer
*volParms
)
111 return ( (volParms
->vMVersion
>= 3) ? volParms
->vMExtendedAttributes
: 0 );
114 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */
116 pascal Boolean
isNetworkVolume(const GetVolParmsInfoBuffer
*volParms
)
118 return ( volParms
->vMServerAdr
!= 0 );
121 pascal Boolean
hasLimitFCBs(const GetVolParmsInfoBuffer
*volParms
)
123 return ( (volParms
->vMAttrib
& (1L << bLimitFCBs
)) != 0 );
126 pascal Boolean
hasLocalWList(const GetVolParmsInfoBuffer
*volParms
)
128 return ( (volParms
->vMAttrib
& (1L << bLocalWList
)) != 0 );
131 pascal Boolean
hasNoMiniFndr(const GetVolParmsInfoBuffer
*volParms
)
133 return ( (volParms
->vMAttrib
& (1L << bNoMiniFndr
)) != 0 );
136 pascal Boolean
hasNoVNEdit(const GetVolParmsInfoBuffer
*volParms
)
138 return ( (volParms
->vMAttrib
& (1L << bNoVNEdit
)) != 0 );
141 pascal Boolean
hasNoLclSync(const GetVolParmsInfoBuffer
*volParms
)
143 return ( (volParms
->vMAttrib
& (1L << bNoLclSync
)) != 0 );
146 pascal Boolean
hasTrshOffLine(const GetVolParmsInfoBuffer
*volParms
)
148 return ( (volParms
->vMAttrib
& (1L << bTrshOffLine
)) != 0 );
151 pascal Boolean
hasNoSwitchTo(const GetVolParmsInfoBuffer
*volParms
)
153 return ( (volParms
->vMAttrib
& (1L << bNoSwitchTo
)) != 0 );
156 pascal Boolean
hasNoDeskItems(const GetVolParmsInfoBuffer
*volParms
)
158 return ( (volParms
->vMAttrib
& (1L << bNoDeskItems
)) != 0 );
161 pascal Boolean
hasNoBootBlks(const GetVolParmsInfoBuffer
*volParms
)
163 return ( (volParms
->vMAttrib
& (1L << bNoBootBlks
)) != 0 );
166 pascal Boolean
hasAccessCntl(const GetVolParmsInfoBuffer
*volParms
)
168 return ( (volParms
->vMAttrib
& (1L << bAccessCntl
)) != 0 );
171 pascal Boolean
hasNoSysDir(const GetVolParmsInfoBuffer
*volParms
)
173 return ( (volParms
->vMAttrib
& (1L << bNoSysDir
)) != 0 );
176 pascal Boolean
hasExtFSVol(const GetVolParmsInfoBuffer
*volParms
)
178 return ( (volParms
->vMAttrib
& (1L << bHasExtFSVol
)) != 0 );
181 pascal Boolean
hasOpenDeny(const GetVolParmsInfoBuffer
*volParms
)
183 return ( (volParms
->vMAttrib
& (1L << bHasOpenDeny
)) != 0 );
186 pascal Boolean
hasCopyFile(const GetVolParmsInfoBuffer
*volParms
)
188 return ( (volParms
->vMAttrib
& (1L << bHasCopyFile
)) != 0 );
191 pascal Boolean
hasMoveRename(const GetVolParmsInfoBuffer
*volParms
)
193 return ( (volParms
->vMAttrib
& (1L << bHasMoveRename
)) != 0 );
196 pascal Boolean
hasDesktopMgr(const GetVolParmsInfoBuffer
*volParms
)
198 return ( (volParms
->vMAttrib
& (1L << bHasDesktopMgr
)) != 0 );
201 pascal Boolean
hasShortName(const GetVolParmsInfoBuffer
*volParms
)
203 return ( (volParms
->vMAttrib
& (1L << bHasShortName
)) != 0 );
206 pascal Boolean
hasFolderLock(const GetVolParmsInfoBuffer
*volParms
)
208 return ( (volParms
->vMAttrib
& (1L << bHasFolderLock
)) != 0 );
211 pascal Boolean
hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
213 return ( (volParms
->vMAttrib
& (1L << bHasPersonalAccessPrivileges
)) != 0 );
216 pascal Boolean
hasUserGroupList(const GetVolParmsInfoBuffer
*volParms
)
218 return ( (volParms
->vMAttrib
& (1L << bHasUserGroupList
)) != 0 );
221 pascal Boolean
hasCatSearch(const GetVolParmsInfoBuffer
*volParms
)
223 return ( (volParms
->vMAttrib
& (1L << bHasCatSearch
)) != 0 );
226 pascal Boolean
hasFileIDs(const GetVolParmsInfoBuffer
*volParms
)
228 return ( (volParms
->vMAttrib
& (1L << bHasFileIDs
)) != 0 );
231 pascal Boolean
hasBTreeMgr(const GetVolParmsInfoBuffer
*volParms
)
233 return ( (volParms
->vMAttrib
& (1L << bHasBTreeMgr
)) != 0 );
236 pascal Boolean
hasBlankAccessPrivileges(const GetVolParmsInfoBuffer
*volParms
)
238 return ( (volParms
->vMAttrib
& (1L << bHasBlankAccessPrivileges
)) != 0 );
241 pascal Boolean
supportsAsyncRequests(const GetVolParmsInfoBuffer
*volParms
)
243 return ( (volParms
->vMAttrib
& (1L << bSupportsAsyncRequests
)) != 0 );
246 pascal Boolean
supportsTrashVolumeCache(const GetVolParmsInfoBuffer
*volParms
)
248 return ( (volParms
->vMAttrib
& (1L << bSupportsTrashVolumeCache
)) != 0 );
251 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
253 pascal Boolean
volIsEjectable(const GetVolParmsInfoBuffer
*volParms
)
255 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bIsEjectable
)) != 0 );
258 pascal Boolean
volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer
*volParms
)
260 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsHFSPlusAPIs
)) != 0 );
263 pascal Boolean
volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer
*volParms
)
265 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSCatalogSearch
)) != 0 );
268 pascal Boolean
volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer
*volParms
)
270 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSExchangeObjects
)) != 0 );
273 pascal Boolean
volSupports2TBFiles(const GetVolParmsInfoBuffer
*volParms
)
275 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupports2TBFiles
)) != 0 );
278 pascal Boolean
volSupportsLongNames(const GetVolParmsInfoBuffer
*volParms
)
280 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsLongNames
)) != 0 );
283 pascal Boolean
volSupportsMultiScriptNames(const GetVolParmsInfoBuffer
*volParms
)
285 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsMultiScriptNames
)) != 0 );
288 pascal Boolean
volSupportsNamedForks(const GetVolParmsInfoBuffer
*volParms
)
290 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsNamedForks
)) != 0 );
293 pascal Boolean
volSupportsSubtreeIterators(const GetVolParmsInfoBuffer
*volParms
)
295 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsSubtreeIterators
)) != 0 );
298 pascal Boolean
volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer
*volParms
)
300 return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bL2PCanMapFileBlocks
)) != 0 );
303 /*****************************************************************************/
305 /* Functions for testing ioACUser bits. */
307 pascal Boolean
userIsOwner(SInt8 ioACUser
)
309 return ( (ioACUser
& kioACUserNotOwnerMask
) == 0 );
312 pascal Boolean
userHasFullAccess(SInt8 ioACUser
)
314 return ( (ioACUser
& acUserAccessMask
) == acUserFull
);
317 pascal Boolean
userHasDropBoxAccess(SInt8 ioACUser
)
319 return ( (ioACUser
& acUserAccessMask
) == acUserDropBox
);
322 pascal Boolean
userHasBulletinBoard(SInt8 ioACUser
)
324 return ( (ioACUser
& acUserAccessMask
) == acUserBulletinBoard
);
327 pascal Boolean
userHasNoAccess(SInt8 ioACUser
)
329 return ( (ioACUser
& acUserAccessMask
) == acUserNone
);
332 /*****************************************************************************/
334 /* local data structures */
336 /* The DeleteEnumGlobals structure is used to minimize the amount of
337 ** stack space used when recursively calling DeleteLevel and to hold
338 ** global information that might be needed at any time. */
340 #if PRAGMA_STRUCT_ALIGN
341 #pragma options align=mac68k
342 #endif // PRAGMA_STRUCT_ALIGN
343 struct DeleteEnumGlobals
345 OSErr error
; /* temporary holder of results - saves 2 bytes of stack each level */
346 Str63 itemName
; /* the name of the current item */
347 UniversalFMPB myPB
; /* the parameter block used for PBGetCatInfo calls */
349 #if PRAGMA_STRUCT_ALIGN
350 #pragma options align=reset
351 #endif // PRAGMA_STRUCT_ALIGN
353 typedef struct DeleteEnumGlobals DeleteEnumGlobals
;
354 typedef DeleteEnumGlobals
*DeleteEnumGlobalsPtr
;
356 /*****************************************************************************/
359 ** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
360 ** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync
361 ** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined,
362 ** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync.
364 ** Non-CFM 68K programs don't needs this glue (and won't get it) because
365 ** they instead use the inline assembly glue found in the Files.h interface
369 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
371 // Carbon builds and 68K builds don't need this glue
372 #define CallPBXGetVolInfoSync PBXGetVolInfoSync
374 #else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
376 #if __WANTPASCALELIMINATION
378 #endif // __WANTPASCALELIMINATION
380 /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */
381 static pascal OSErr
PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock
)
385 uppFSDispatchProcInfo
= kRegisterBased
386 | REGISTER_RESULT_LOCATION(kRegisterD0
)
387 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr
)))
388 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0
, SIZE_CODE(sizeof(long))) /* selector */
389 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1
, SIZE_CODE(sizeof(long))) /* trap word */
390 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0
, SIZE_CODE(sizeof(XVolumeParamPtr
)))
393 static UniversalProcPtr fsDispatchTrapAddress
= NULL
;
395 /* Is this the first time we've been called? */
396 if ( fsDispatchTrapAddress
== NULL
)
398 /* Yes - Get the trap address of _FSDispatch */
399 fsDispatchTrapAddress
= NGetTrapAddress(_FSDispatch
, OSTrap
);
401 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress
,
402 uppFSDispatchProcInfo
,
409 ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2.
410 ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5.
411 ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib;
412 ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program
413 ** is calling the latest implementation of PBXGetVolInfoSync.
415 static pascal OSErr
CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock
)
417 typedef pascal OSErr (*PBXGetVolInfoProcPtr
) (XVolumeParamPtr paramBlock
);
420 CFragConnectionID connID
;
423 static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr
= NULL
;
425 //* Is this the first time we've been called? */
426 if ( PBXGetVolInfoSyncPtr
== NULL
)
428 /* Yes - Get our connection ID to InterfaceLib */
429 result
= GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch
, kLoadCFrag
, &connID
, &mainAddr
, errMessage
);
430 if ( result
== noErr
)
432 /* See if PBXGetVolInfoSync is in InterfaceLib */
433 if ( FindSymbol(connID
, "\pPBXGetVolInfoSync", &(Ptr
)PBXGetVolInfoSyncPtr
, NULL
) != noErr
)
435 /* Use glue code if symbol isn't found */
436 PBXGetVolInfoSyncPtr
= PBXGetVolInfoSyncGlue
;
440 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */
441 return ( (*PBXGetVolInfoSyncPtr
)(paramBlock
) );
444 #if __WANTPASCALELIMINATION
446 #endif // __WANTPASCALELIMINATION
448 #endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
450 /*****************************************************************************/
452 pascal void TruncPString(StringPtr destination
,
453 ConstStr255Param source
,
458 if ( source
!= NULL
&& destination
!= NULL
) /* don't do anything stupid */
460 if ( source
[0] > maxLength
)
462 /* Make sure the string isn't truncated in the middle of */
463 /* a multi-byte character. */
464 while (maxLength
!= 0)
466 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter
467 charType
= CharacterByteType((Ptr
)&source
[1], maxLength
- 1, smSystemScript
);
468 if ( (charType
== smSingleByte
) || (charType
== smLastByte
) )
469 break; /* source[maxLength] is now a valid last character */
475 maxLength
= source
[0];
477 /* Set the destination string length */
478 destination
[0] = maxLength
;
479 /* and copy maxLength characters (if needed) */
480 if ( source
!= destination
)
482 while ( maxLength
!= 0 )
484 destination
[maxLength
] = source
[maxLength
];
491 /*****************************************************************************/
493 pascal Ptr
GetTempBuffer(long buffReqSize
,
498 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
502 /* Make request a multiple of 1024 bytes */
503 buffReqSize
= buffReqSize
& 0xfffffc00;
505 if ( buffReqSize
< 0x00000400 )
507 /* Request was smaller than 1024 bytes - make it 1024 */
508 buffReqSize
= 0x00000400;
511 /* Attempt to allocate the memory */
512 tempPtr
= NewPtr(buffReqSize
);
514 /* If request failed, go to backup plan */
515 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00000400) )
518 ** Try to get largest 1024-byte block available
519 ** leaving some slop for the toolbox if possible
521 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffffc00;
523 buffReqSize
= MaxBlock() & 0xfffffc00;
525 if ( buffReqSize
> freeMemory
)
527 buffReqSize
= freeMemory
;
530 if ( buffReqSize
== 0 )
532 buffReqSize
= 0x00000400;
535 tempPtr
= NewPtr(buffReqSize
);
538 /* Return bytes allocated */
539 if ( tempPtr
!= NULL
)
541 *buffActSize
= buffReqSize
;
551 /*****************************************************************************/
554 ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
555 ** in cases where the returned volume name is not needed by the caller.
556 ** The pathname and vRefNum parameters are not touched, and the pb
557 ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
558 ** the parameter block is always returned as NULL (since it might point
559 ** to the local tempPathname).
561 ** I noticed using this code in several places, so here it is once.
562 ** This reduces the code size of MoreFiles.
564 pascal OSErr
GetVolumeInfoNoName(ConstStr255Param pathname
,
571 /* Make sure pb parameter is not NULL */
574 pb
->volumeParam
.ioVRefNum
= vRefNum
;
575 if ( pathname
== NULL
)
577 pb
->volumeParam
.ioNamePtr
= NULL
;
578 pb
->volumeParam
.ioVolIndex
= 0; /* use ioVRefNum only */
582 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
583 pb
->volumeParam
.ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
584 pb
->volumeParam
.ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
586 error
= PBHGetVInfoSync(pb
);
587 pb
->volumeParam
.ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
596 /*****************************************************************************/
599 ** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
600 ** in cases where the returned volume name is not needed by the caller.
601 ** The pathname and vRefNum parameters are not touched, and the pb
602 ** parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
603 ** the parameter block is always returned as NULL (since it might point
604 ** to the local tempPathname).
606 pascal OSErr
XGetVolumeInfoNoName(ConstStr255Param pathname
,
613 /* Make sure pb parameter is not NULL */
616 pb
->ioVRefNum
= vRefNum
;
617 pb
->ioXVersion
= 0; /* this XVolumeParam version (0) */
618 if ( pathname
== NULL
)
620 pb
->ioNamePtr
= NULL
;
621 pb
->ioVolIndex
= 0; /* use ioVRefNum only */
625 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */
626 pb
->ioNamePtr
= (StringPtr
)tempPathname
; /* use the copy so original isn't trashed */
627 pb
->ioVolIndex
= -1; /* use ioNamePtr/ioVRefNum combination */
631 #if !TARGET_API_MAC_CARBON
634 /* Is PBXGetVolInfo available? */
635 if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr
) || ((response
& (1L << gestaltFSSupports2TBVols
)) == 0) )
637 /* No, fall back on PBHGetVInfo */
638 error
= PBHGetVInfoSync((HParmBlkPtr
)pb
);
639 if ( error
== noErr
)
641 /* calculate the ioVTotalBytes and ioVFreeBytes fields */
642 pb
->ioVTotalBytes
= U64Multiply(U64SetU(pb
->ioVNmAlBlks
), U64SetU(pb
->ioVAlBlkSiz
));
643 pb
->ioVFreeBytes
= U64Multiply(U64SetU(pb
->ioVFrBlk
), U64SetU(pb
->ioVAlBlkSiz
));
650 error
= CallPBXGetVolInfoSync(pb
);
653 pb
->ioNamePtr
= NULL
; /* ioNamePtr may point to local tempPathname, so don't return it */
662 /*****************************************************************************/
664 pascal OSErr
GetCatInfoNoName(short vRefNum
,
666 ConstStr255Param name
,
672 /* Protection against File Sharing problem */
673 if ( (name
== NULL
) || (name
[0] == 0) )
676 pb
->dirInfo
.ioNamePtr
= tempName
;
677 pb
->dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
681 pb
->dirInfo
.ioNamePtr
= (StringPtr
)name
;
682 pb
->dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
684 pb
->dirInfo
.ioVRefNum
= vRefNum
;
685 pb
->dirInfo
.ioDrDirID
= dirID
;
686 error
= PBGetCatInfoSync(pb
);
687 pb
->dirInfo
.ioNamePtr
= NULL
;
691 /*****************************************************************************/
693 pascal OSErr
DetermineVRefNum(ConstStr255Param pathname
,
700 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
701 if ( error
== noErr
)
703 *realVRefNum
= pb
.volumeParam
.ioVRefNum
;
708 /*****************************************************************************/
710 pascal OSErr
HGetVInfo(short volReference
,
713 unsigned long *freeBytes
,
714 unsigned long *totalBytes
)
720 // get the best values possible from XGetVInfo
721 result
= XGetVInfo(volReference
, volName
, vRefNum
, &freeBytes64
, &totalBytes64
);
722 if ( result
== noErr
)
724 // and pin those values if needed
725 if ( UInt64ToUnsignedWide(freeBytes64
).hi
!= 0 )
727 // pin to maximum 512-byte block aligned value
728 *freeBytes
= 0xfffffe00;
732 *freeBytes
= U32SetU(freeBytes64
);
735 if ( UInt64ToUnsignedWide(totalBytes64
).hi
!= 0 )
737 // pin to maximum 512-byte block aligned value
738 *totalBytes
= 0xfffffe00;
742 *totalBytes
= U32SetU(totalBytes64
);
749 /*****************************************************************************/
751 pascal OSErr
XGetVInfo(short volReference
,
760 #if !TARGET_API_MAC_CARBON
764 #endif // !TARGET_API_MAC_CARBON
766 pb
.ioVRefNum
= volReference
;
767 pb
.ioNamePtr
= volName
;
768 pb
.ioXVersion
= 0; /* this XVolumeParam version (0) */
769 pb
.ioVolIndex
= 0; /* use ioVRefNum only, return volume name */
771 #if !TARGET_API_MAC_CARBON
773 /* See if large volume support is available */
774 if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr
) && ((response
& (1L << gestaltFSSupports2TBVols
)) != 0) )
776 #endif // !TARGET_API_MAC_CARBON
779 /* Large volume support is available */
780 result
= CallPBXGetVolInfoSync(&pb
);
781 if ( result
== noErr
)
783 /* The volume name was returned in volName (if not NULL) and */
784 /* we have the volume's vRefNum and allocation block size */
785 *vRefNum
= pb
.ioVRefNum
;
787 /* return the freeBytes and totalBytes */
788 *totalBytes
= pb
.ioVTotalBytes
;
789 *freeBytes
= pb
.ioVFreeBytes
;
793 #if !TARGET_API_MAC_CARBON
797 /* No large volume support */
798 /* Use PBHGetVInfoSync to get the results */
799 result
= PBHGetVInfoSync((HParmBlkPtr
)&pb
);
800 if ( result
== noErr
)
804 /* The volume name was returned in volName (if not NULL) and */
805 /* we have the volume's vRefNum */
806 *vRefNum
= pb
.ioVRefNum
;
808 /* System 7.5 (and beyond) pins the number of allocation blocks and */
809 /* the number of free allocation blocks returned by PBHGetVInfo to */
810 /* a value so that when multiplied by the allocation block size, */
811 /* the volume will look like it has $7fffffff bytes or less. This */
812 /* was done so older applications that use signed math or that use */
813 /* the GetVInfo function (which uses signed math) will continue to work. */
814 /* However, the unpinned numbers (which we want) are always available */
815 /* in the volume's VCB so we'll get those values from the VCB. */
816 /* Note: Carbon doesn't support the VCB queue, so this code cannot be */
817 /* used (and is conditionalized out) by Carbon applications. */
819 /* Find the volume's VCB */
820 theVCB
= (VCB
*)(GetVCBQHdr()->qHead
);
821 while ( theVCB
!= NULL
)
823 if ( theVCB
->vcbVRefNum
== *vRefNum
)
828 theVCB
= (VCB
*)(theVCB
->qLink
); /* next VCB */
831 if ( theVCB
!= NULL
)
833 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
834 /* and the number of free blocks from the VCB. */
835 *freeBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbFreeBks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
836 *totalBytes
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
840 /* Didn't find a VCB we can use. Return the number of allocation blocks */
841 /* and the number of free blocks returned by PBHGetVInfoSync. */
842 *freeBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVFrBlk
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
843 *totalBytes
= U64Multiply(U64SetU((unsigned short)pb
.ioVNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
));
849 #endif // !TARGET_API_MAC_CARBON
854 /*****************************************************************************/
856 pascal OSErr
CheckVolLock(ConstStr255Param pathname
,
862 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
863 if ( error
== noErr
)
865 if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeHardwareLockMask
) != 0 )
867 error
= wPrErr
; /* volume locked by hardware */
869 else if ( (pb
.volumeParam
.ioVAtrb
& kHFSVolumeSoftwareLockMask
) != 0 )
871 error
= vLckdErr
; /* volume locked by software */
878 /*****************************************************************************/
880 // The following routines call Mac OS routines that are not supported by
888 #if !TARGET_API_MAC_CARBON // {
890 /*****************************************************************************/
892 pascal OSErr
GetDriverName(short driverRefNum
,
897 DRVRHeaderPtr dHeaderPtr
;
899 theDctl
= GetDCtlEntry(driverRefNum
);
900 if ( theDctl
!= NULL
)
902 if ( (**theDctl
).dCtlFlags
& dRAMBasedMask
)
904 /* dctlDriver is handle - dereference */
905 dHeaderPtr
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
);
909 /* dctlDriver is pointer */
910 dHeaderPtr
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
;
912 BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1);
918 result
= badUnitErr
; /* bad reference number */
924 /*****************************************************************************/
926 pascal OSErr
FindDrive(ConstStr255Param pathname
,
928 DrvQElPtr
*driveQElementPtr
)
934 *driveQElementPtr
= NULL
;
936 /* First, use GetVolumeInfoNoName to determine the volume */
937 result
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
);
938 if ( result
== noErr
)
941 ** The volume can be either online, offline, or ejected. What we find in
942 ** ioVDrvInfo and ioVDRefNum will tell us which it is.
943 ** See Inside Macintosh: Files page 2-80 and the Technical Note
944 ** "FL 34 - VCBs and Drive Numbers : The Real Story"
945 ** Where we get the drive number depends on the state of the volume.
947 if ( hPB
.volumeParam
.ioVDrvInfo
!= 0 )
949 /* The volume is online and not ejected */
950 /* Get the drive number */
951 driveNumber
= hPB
.volumeParam
.ioVDrvInfo
;
955 /* The volume's is either offline or ejected */
956 /* in either case, the volume is NOT online */
958 /* Is it ejected or just offline? */
959 if ( hPB
.volumeParam
.ioVDRefNum
> 0 )
961 /* It's ejected, the drive number is ioVDRefNum */
962 driveNumber
= hPB
.volumeParam
.ioVDRefNum
;
966 /* It's offline, the drive number is the negative of ioVDRefNum */
967 driveNumber
= (short)-hPB
.volumeParam
.ioVDRefNum
;
971 /* Get pointer to first element in drive queue */
972 *driveQElementPtr
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
974 /* Search for a matching drive number */
975 while ( (*driveQElementPtr
!= NULL
) && ((*driveQElementPtr
)->dQDrive
!= driveNumber
) )
977 *driveQElementPtr
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
;
980 if ( *driveQElementPtr
== NULL
)
982 /* This should never happen since every volume must have a drive, but... */
990 /*****************************************************************************/
992 pascal OSErr
GetDiskBlocks(ConstStr255Param pathname
,
994 unsigned long *numBlocks
)
996 /* Various constants for GetDiskBlocks() */
999 /* return format list status code */
1002 /* reference number of .SONY driver */
1003 kSonyRefNum
= 0xfffb,
1005 /* values returned by DriveStatus in DrvSts.twoSideFmt */
1008 kSingleSidedSize
= 800, /* 400K */
1009 kDoubleSidedSize
= 1600, /* 800K */
1011 /* values in DrvQEl.qType */
1015 /* more than enough formatListRecords */
1016 kMaxFormatListRecs
= 16
1019 DrvQElPtr driveQElementPtr
;
1020 unsigned long blocks
;
1022 FormatListRec formatListRecords
[kMaxFormatListRecs
];
1024 short formatListRecIndex
;
1029 /* Find the drive queue element for this volume */
1030 result
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
);
1033 ** Make sure this is a real driver (dQRefNum < 0).
1034 ** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
1035 ** problems if you try to use it as a driver refNum.
1037 if ( (result
== noErr
) && (driveQElementPtr
->dQRefNum
>= 0) )
1043 /* Attempt to get the drive's format list. */
1044 /* (see the Technical Note "What Your Sony Drives For You") */
1046 pb
.cntrlParam
.ioVRefNum
= driveQElementPtr
->dQDrive
;
1047 pb
.cntrlParam
.ioCRefNum
= driveQElementPtr
->dQRefNum
;
1048 pb
.cntrlParam
.csCode
= kFmtLstCode
;
1049 pb
.cntrlParam
.csParam
[0] = kMaxFormatListRecs
;
1050 *(long *)&pb
.cntrlParam
.csParam
[1] = (long)&formatListRecords
[0];
1052 result
= PBStatusSync(&pb
);
1054 if ( result
== noErr
)
1056 /* The drive supports ReturnFormatList status call. */
1058 /* Get the current disk's size. */
1059 for( formatListRecIndex
= 0;
1060 formatListRecIndex
< pb
.cntrlParam
.csParam
[0];
1061 ++formatListRecIndex
)
1063 if ( (formatListRecords
[formatListRecIndex
].formatFlags
&
1064 diCIFmtFlagsCurrentMask
) != 0 )
1066 blocks
= formatListRecords
[formatListRecIndex
].volSize
;
1071 /* This should never happen */
1075 else if ( driveQElementPtr
->dQRefNum
== (short)kSonyRefNum
)
1077 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
1079 result
= DriveStatus(driveQElementPtr
->dQDrive
, &status
);
1080 if ( result
== noErr
)
1082 switch ( status
.twoSideFmt
)
1085 blocks
= kSingleSidedSize
;
1088 blocks
= kDoubleSidedSize
;
1091 /* This should never happen */
1099 /* The drive is not a floppy and it doesn't support ReturnFormatList */
1100 /* so use the dQDrvSz field(s) */
1102 result
= noErr
; /* reset result */
1103 switch ( driveQElementPtr
->qType
)
1106 blocks
= driveQElementPtr
->dQDrvSz
;
1109 blocks
= ((unsigned long)driveQElementPtr
->dQDrvSz2
<< 16) +
1110 driveQElementPtr
->dQDrvSz
;
1113 /* This should never happen */
1120 if ( result
== noErr
)
1122 *numBlocks
= blocks
;
1128 /*****************************************************************************/
1130 pascal OSErr
GetVolState(ConstStr255Param pathname
,
1132 Boolean
*volumeOnline
,
1133 Boolean
*volumeEjected
,
1134 Boolean
*driveEjectable
,
1135 Boolean
*driverWantsEject
)
1141 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1142 if ( error
== noErr
)
1144 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1146 /* the volume is online and not ejected */
1147 *volumeOnline
= true;
1148 *volumeEjected
= false;
1150 /* Get the drive number */
1151 driveNumber
= pb
.volumeParam
.ioVDrvInfo
;
1155 /* the volume's is either offline or ejected */
1156 /* in either case, the volume is NOT online */
1157 *volumeOnline
= false;
1159 /* Is it ejected? */
1160 *volumeEjected
= pb
.volumeParam
.ioVDRefNum
> 0;
1162 if ( *volumeEjected
)
1164 /* If ejected, the drive number is ioVDRefNum */
1165 driveNumber
= pb
.volumeParam
.ioVDRefNum
;
1169 /* If offline, the drive number is the negative of ioVDRefNum */
1170 driveNumber
= (short)-pb
.volumeParam
.ioVDRefNum
;
1177 /* Find the drive queue element by searching the drive queue */
1178 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1179 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNumber
) )
1181 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1184 if ( drvQElem
!= NULL
)
1187 ** Each drive queue element is preceded by 4 flag bytes.
1188 ** Byte 1 (the second flag byte) has bits that tell us if a
1189 ** drive is ejectable and if its driver wants an eject call.
1190 ** See Inside Macintosh: Files, page 2-85.
1195 /* point to byte 1 of the flag bytes */
1196 flagBytePtr
= (Ptr
)drvQElem
;
1200 ** The drive is ejectable if flag byte 1 does not contain
1201 ** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
1204 *driveEjectable
= (*flagBytePtr
!= 0x08) && (*flagBytePtr
!= 0x48);
1207 ** The driver wants an eject call if flag byte 1 does not contain
1208 ** 0x08 (nonejectable). This may seem like a minor point, but some
1209 ** disk drivers use the Eject request to flush their caches to disk
1210 ** and you wouldn't want to skip that step after unmounting a volume.
1213 *driverWantsEject
= (*flagBytePtr
!= 0x08);
1218 /* Didn't find the drive (this should never happen) */
1219 *driveEjectable
= false;
1220 *driverWantsEject
= false;
1228 /*****************************************************************************/
1230 #endif // } !TARGET_API_MAC_CARBON
1232 /*****************************************************************************/
1234 pascal OSErr
GetVolFileSystemID(ConstStr255Param pathname
,
1236 short *fileSystemID
)
1241 error
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
);
1242 if ( error
== noErr
)
1244 *fileSystemID
= pb
.volumeParam
.ioVFSID
;
1250 /*****************************************************************************/
1253 // Note: Under Carbon there are no drive numbers, so you cannot call
1254 // Eject with a drive number after unmounting a volume.
1255 // When a Carbon application calls UnmountVol, CarbonLib will make
1256 // sure ejectable media is ejected (leaving ejectable media in the
1257 // disk drive makes no sense to Carbon applications).
1259 pascal OSErr
UnmountAndEject(ConstStr255Param pathname
,
1265 error
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
);
1266 if ( error
== noErr
)
1269 #if !TARGET_API_MAC_CARBON
1272 Boolean ejected
, wantsEject
;
1275 if ( pb
.volumeParam
.ioVDrvInfo
!= 0 )
1277 /* the volume is online and not ejected */
1280 /* Get the drive number */
1281 driveNum
= pb
.volumeParam
.ioVDrvInfo
;
1285 /* the volume is ejected or offline */
1287 /* Is it ejected? */
1288 ejected
= pb
.volumeParam
.ioVDRefNum
> 0;
1292 /* If ejected, the drive number is ioVDRefNum */
1293 driveNum
= pb
.volumeParam
.ioVDRefNum
;
1297 /* If offline, the drive number is the negative of ioVDRefNum */
1298 driveNum
= (short)-pb
.volumeParam
.ioVDRefNum
;
1302 /* find the drive queue element */
1303 drvQElem
= (DrvQElPtr
)(GetDrvQHdr()->qHead
);
1304 while ( (drvQElem
!= NULL
) && (drvQElem
->dQDrive
!= driveNum
) )
1306 drvQElem
= (DrvQElPtr
)drvQElem
->qLink
;
1309 if ( drvQElem
!= NULL
)
1311 /* does the drive want an eject call */
1312 wantsEject
= (*((Ptr
)((Ptr
)drvQElem
- 3)) != 8);
1316 /* didn't find the drive!! */
1320 #endif // !TARGET_API_MAC_CARBON
1322 /* unmount the volume */
1323 pb
.volumeParam
.ioNamePtr
= NULL
;
1324 /* ioVRefNum is already filled in from PBHGetVInfo */
1325 error
= PBUnmountVol((ParmBlkPtr
)&pb
);
1327 #if !TARGET_API_MAC_CARBON
1329 if ( error
== noErr
)
1331 if ( wantsEject
&& !ejected
)
1333 /* eject the media from the drive if needed */
1334 pb
.volumeParam
.ioVRefNum
= driveNum
;
1335 error
= PBEject((ParmBlkPtr
)&pb
);
1339 #endif // !TARGET_API_MAC_CARBON
1346 /*****************************************************************************/
1348 pascal OSErr
OnLine(FSSpecPtr volumes
,
1354 OSErr error
= noErr
;
1355 FSSpec
*endVolArray
;
1357 if ( *volIndex
> 0 )
1360 for ( endVolArray
= volumes
+ reqVolCount
; (volumes
< endVolArray
) && (error
== noErr
); ++volumes
)
1362 pb
.volumeParam
.ioNamePtr
= (StringPtr
) & volumes
->name
;
1363 pb
.volumeParam
.ioVolIndex
= *volIndex
;
1364 error
= PBHGetVInfoSync(&pb
);
1365 if ( error
== noErr
)
1367 volumes
->parID
= fsRtParID
; /* the root directory's parent is 1 */
1368 volumes
->vRefNum
= pb
.volumeParam
.ioVRefNum
;
1382 /*****************************************************************************/
1384 pascal OSErr
SetDefault(short newVRefNum
,
1391 /* Get the current default volume/directory. */
1392 error
= HGetVol(NULL
, oldVRefNum
, oldDirID
);
1393 if ( error
== noErr
)
1395 /* Set the new default volume/directory */
1396 error
= HSetVol(NULL
, newVRefNum
, newDirID
);
1402 /*****************************************************************************/
1404 pascal OSErr
RestoreDefault(short oldVRefNum
,
1409 #if !TARGET_API_MAC_CARBON
1411 short defaultVRefNum
;
1415 /* Determine if the default volume was a wdRefNum. */
1416 error
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
);
1417 if ( error
== noErr
)
1419 /* Restore the old default volume/directory, one way or the other. */
1420 if ( defaultDirID
!= fsRtDirID
)
1422 /* oldVRefNum was a wdRefNum - use SetVol */
1423 error
= SetVol(NULL
, oldVRefNum
);
1428 #endif // !TARGET_API_MAC_CARBON
1430 /* oldVRefNum was a real vRefNum - use HSetVol */
1431 error
= HSetVol(NULL
, oldVRefNum
, oldDirID
);
1433 #if !TARGET_API_MAC_CARBON
1437 #endif // !TARGET_API_MAC_CARBON
1442 /*****************************************************************************/
1444 pascal OSErr
GetDInfo(short vRefNum
,
1446 ConstStr255Param name
,
1452 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1453 if ( error
== noErr
)
1455 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1457 /* it's a directory, return the DInfo */
1458 *fndrInfo
= pb
.dirInfo
.ioDrUsrWds
;
1462 /* oops, a file was passed */
1470 /*****************************************************************************/
1472 pascal OSErr
FSpGetDInfo(const FSSpec
*spec
,
1475 return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1478 /*****************************************************************************/
1480 pascal OSErr
SetDInfo(short vRefNum
,
1482 ConstStr255Param name
,
1483 const DInfo
*fndrInfo
)
1489 /* Protection against File Sharing problem */
1490 if ( (name
== NULL
) || (name
[0] == 0) )
1493 pb
.dirInfo
.ioNamePtr
= tempName
;
1494 pb
.dirInfo
.ioFDirIndex
= -1; /* use ioDirID */
1498 pb
.dirInfo
.ioNamePtr
= (StringPtr
)name
;
1499 pb
.dirInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1501 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1502 pb
.dirInfo
.ioDrDirID
= dirID
;
1503 error
= PBGetCatInfoSync(&pb
);
1504 if ( error
== noErr
)
1506 if ( (pb
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1508 /* it's a directory, set the DInfo */
1509 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
1511 pb
.dirInfo
.ioDrDirID
= pb
.dirInfo
.ioDrParID
;
1515 pb
.dirInfo
.ioDrDirID
= dirID
;
1517 pb
.dirInfo
.ioDrUsrWds
= *fndrInfo
;
1518 error
= PBSetCatInfoSync(&pb
);
1522 /* oops, a file was passed */
1530 /*****************************************************************************/
1532 pascal OSErr
FSpSetDInfo(const FSSpec
*spec
,
1533 const DInfo
*fndrInfo
)
1535 return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) );
1538 /*****************************************************************************/
1540 pascal OSErr
GetDirectoryID(short vRefNum
,
1542 ConstStr255Param name
,
1544 Boolean
*isDirectory
)
1549 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1550 if ( error
== noErr
)
1552 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1555 *theDirID
= pb
.dirInfo
.ioDrDirID
;
1559 *theDirID
= pb
.hFileInfo
.ioFlParID
;
1566 /*****************************************************************************/
1568 pascal OSErr
FSpGetDirectoryID(const FSSpec
*spec
,
1570 Boolean
*isDirectory
)
1572 return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
,
1573 theDirID
, isDirectory
) );
1576 /*****************************************************************************/
1578 pascal OSErr
GetDirName(short vRefNum
,
1587 pb
.dirInfo
.ioNamePtr
= name
;
1588 pb
.dirInfo
.ioVRefNum
= vRefNum
;
1589 pb
.dirInfo
.ioDrDirID
= dirID
;
1590 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1591 error
= PBGetCatInfoSync(&pb
);
1601 /*****************************************************************************/
1603 pascal OSErr
GetIOACUser(short vRefNum
,
1605 ConstStr255Param name
,
1611 /* Clear ioACUser before calling PBGetCatInfo since some file systems
1612 ** don't bother to set or clear this field. If ioACUser isn't set by the
1613 ** file system, then you'll get the zero value back (full access) which
1614 ** is the access you have on volumes that don't support ioACUser.
1616 pb
.dirInfo
.ioACUser
= 0; /* ioACUser used to be filler2 */
1617 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
1618 if ( error
== noErr
)
1620 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 )
1622 /* oops, a file was passed */
1627 *ioACUser
= pb
.dirInfo
.ioACUser
;
1634 /*****************************************************************************/
1636 pascal OSErr
FSpGetIOACUser(const FSSpec
*spec
,
1639 return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) );
1642 /*****************************************************************************/
1644 pascal OSErr
GetParentID(short vRefNum
,
1646 ConstStr255Param name
,
1654 /* Protection against File Sharing problem */
1655 if ( (name
== NULL
) || (name
[0] == 0) )
1658 pb
.hFileInfo
.ioNamePtr
= tempName
;
1659 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1663 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
1664 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1666 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1667 pb
.hFileInfo
.ioDirID
= dirID
;
1668 error
= PBGetCatInfoSync(&pb
);
1669 if ( error
== noErr
)
1672 ** There's a bug in HFS where the wrong parent dir ID can be
1673 ** returned if multiple separators are used at the end of a
1674 ** pathname. For example, if the pathname:
1675 ** 'volumeName:System Folder:Extensions::'
1676 ** is passed, the directory ID of the Extensions folder is
1677 ** returned in the ioFlParID field instead of fsRtDirID. Since
1678 ** multiple separators at the end of a pathname always specifies
1679 ** a directory, we only need to work-around cases where the
1680 ** object is a directory and there are multiple separators at
1681 ** the end of the name parameter.
1683 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
1685 /* Its a directory */
1687 /* is there a pathname? */
1688 if ( pb
.hFileInfo
.ioNamePtr
== name
)
1690 /* could it contain multiple separators? */
1693 /* does it contain multiple separators at the end? */
1694 if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') )
1696 /* OK, then do the extra stuff to get the correct parID */
1698 /* Get the real vRefNum (this should not fail) */
1699 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
1700 if ( error
== noErr
)
1702 /* we don't need the parent's name, but add protect against File Sharing problem */
1704 pb
.dirInfo
.ioNamePtr
= tempName
;
1705 pb
.dirInfo
.ioVRefNum
= realVRefNum
;
1706 /* pb.dirInfo.ioDrDirID already contains the */
1707 /* dirID of the directory object */
1708 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1709 error
= PBGetCatInfoSync(&pb
);
1710 /* now, pb.dirInfo.ioDrParID contains the correct parID */
1717 if ( error
== noErr
)
1719 /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
1720 /* contains the parent ID */
1721 *parID
= pb
.hFileInfo
.ioFlParID
;
1728 /*****************************************************************************/
1730 pascal OSErr
GetFilenameFromPathname(ConstStr255Param pathname
,
1737 /* default to no filename */
1740 /* check for no pathname */
1741 if ( pathname
!= NULL
)
1743 /* get string length */
1744 index
= pathname
[0];
1746 /* check for empty string */
1749 /* skip over last trailing colon (if any) */
1750 if ( pathname
[index
] == ':' )
1755 /* save the end of the string */
1758 /* if pathname ends with multiple colons, then this pathname refers */
1759 /* to a directory, not a file */
1760 if ( pathname
[index
] != ':' )
1762 /* parse backwards until we find a colon or hit the beginning of the pathname */
1763 while ( (index
!= 0) && (pathname
[index
] != ':') )
1768 /* if we parsed to the beginning of the pathname and the pathname ended */
1769 /* with a colon, then pathname is a full pathname to a volume, not a file */
1770 if ( (index
!= 0) || (pathname
[pathname
[0]] != ':') )
1772 /* get the filename and return noErr */
1773 filename
[0] = (char)(nameEnd
- index
);
1774 BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd
- index
);
1779 /* pathname to a volume, not a file */
1780 error
= notAFileErr
;
1785 /* directory, not a file */
1786 error
= notAFileErr
;
1791 /* empty string isn't a file */
1792 error
= notAFileErr
;
1797 /* NULL pathname isn't a file */
1798 error
= notAFileErr
;
1804 /*****************************************************************************/
1806 pascal OSErr
GetObjectLocation(short vRefNum
,
1808 ConstStr255Param pathname
,
1812 Boolean
*isDirectory
)
1816 Str255 tempPathname
;
1824 ** Get the real vRefNum
1826 error
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
);
1827 if ( error
== noErr
)
1830 ** Determine if the object already exists and if so,
1831 ** get the real parent directory ID if it's a file
1834 /* Protection against File Sharing problem */
1835 if ( (pathname
== NULL
) || (pathname
[0] == 0) )
1837 tempPathname
[0] = 0;
1838 pb
.hFileInfo
.ioNamePtr
= tempPathname
;
1839 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1843 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)pathname
;
1844 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1846 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1847 pb
.hFileInfo
.ioDirID
= dirID
;
1848 error
= PBGetCatInfoSync(&pb
);
1849 if ( error
== noErr
)
1852 ** The file system object is present and we have the file's real parID
1855 /* Is it a directory or a file? */
1856 *isDirectory
= (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0;
1860 ** It's a directory, get its name and parent dirID, and then we're done
1863 pb
.dirInfo
.ioNamePtr
= realName
;
1864 pb
.dirInfo
.ioVRefNum
= *realVRefNum
;
1865 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
1866 pb
.dirInfo
.ioFDirIndex
= -1; /* get information about ioDirID */
1867 error
= PBGetCatInfoSync(&pb
);
1869 /* get the parent ID here, because the file system can return the */
1870 /* wrong parent ID from the last call. */
1871 *realParID
= pb
.dirInfo
.ioDrParID
;
1876 ** It's a file - use the parent directory ID from the last call
1877 ** to GetCatInfoparse, get the file name, and then we're done
1879 *realParID
= pb
.hFileInfo
.ioFlParID
;
1880 error
= GetFilenameFromPathname(pathname
, realName
);
1883 else if ( error
== fnfErr
)
1886 ** The file system object is not present - see if its parent is present
1890 ** Parse to get the object name from end of pathname
1892 error
= GetFilenameFromPathname(pathname
, realName
);
1894 /* if we can't get the object name from the end, we can't continue */
1895 if ( error
== noErr
)
1898 ** What we want now is the pathname minus the object name
1900 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
1901 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
1902 ** if pathname is ':dir:file' tempPathname becomes ':dir:'
1903 ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
1904 ** if pathname is ':file' tempPathname becomes ':'
1905 ** if pathname is 'file or file:' tempPathname becomes ''
1908 /* get a copy of the pathname */
1909 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1);
1911 /* remove the object name */
1912 tempPathname
[0] -= realName
[0];
1913 /* and the trailing colon (if any) */
1914 if ( pathname
[pathname
[0]] == ':' )
1919 /* OK, now get the parent's directory ID */
1921 /* Protection against File Sharing problem */
1922 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)tempPathname
;
1923 if ( tempPathname
[0] != 0 )
1925 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
1929 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
1931 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
1932 pb
.hFileInfo
.ioDirID
= dirID
;
1933 error
= PBGetCatInfoSync(&pb
);
1934 *realParID
= pb
.dirInfo
.ioDrDirID
;
1936 *isDirectory
= false; /* we don't know what the object is really going to be */
1939 if ( error
!= noErr
)
1941 error
= dirNFErr
; /* couldn't find parent directory */
1945 error
= fnfErr
; /* we found the parent, but not the file */
1953 /*****************************************************************************/
1955 pascal OSErr
GetDirItems(short vRefNum
,
1957 ConstStr255Param name
,
1959 Boolean getDirectories
,
1962 short *actItemCount
,
1963 short *itemIndex
) /* start with 1, then use what's returned */
1968 Boolean isDirectory
;
1969 FSSpec
*endItemsArray
;
1971 if ( *itemIndex
> 0 )
1973 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
1974 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
1975 /* routine would be much faster because of the overhead of DetermineVRefNum and */
1976 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
1977 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
1978 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
1979 /* to this routine. */
1981 /* get the real volume reference number */
1982 error
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
);
1983 if ( error
== noErr
)
1985 /* and the real directory ID of this directory (and make sure it IS a directory) */
1986 error
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
);
1987 if ( error
== noErr
)
1992 endItemsArray
= items
+ reqItemCount
;
1993 while ( (items
< endItemsArray
) && (error
== noErr
) )
1995 pb
.hFileInfo
.ioNamePtr
= (StringPtr
) &items
->name
;
1996 pb
.hFileInfo
.ioDirID
= theDirID
;
1997 pb
.hFileInfo
.ioFDirIndex
= *itemIndex
;
1998 error
= PBGetCatInfoSync(&pb
);
1999 if ( error
== noErr
)
2001 items
->parID
= pb
.hFileInfo
.ioFlParID
; /* return item's parID */
2002 items
->vRefNum
= pb
.hFileInfo
.ioVRefNum
; /* return item's vRefNum */
2003 ++*itemIndex
; /* prepare to get next item in directory */
2005 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2007 if ( getDirectories
)
2009 ++*actItemCount
; /* keep this item */
2010 ++items
; /* point to next item */
2017 ++*actItemCount
; /* keep this item */
2018 ++items
; /* point to next item */
2026 /* it wasn't a directory */
2041 /*****************************************************************************/
2043 static void DeleteLevel(long dirToDelete
,
2044 DeleteEnumGlobalsPtr theGlobals
)
2050 /* prepare to delete directory */
2051 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= (StringPtr
)&theGlobals
->itemName
;
2052 theGlobals
->myPB
.ciPB
.dirInfo
.ioFDirIndex
= 1; /* get first item */
2053 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= dirToDelete
; /* in this directory */
2054 theGlobals
->error
= PBGetCatInfoSync(&(theGlobals
->myPB
.ciPB
));
2055 if ( theGlobals
->error
== noErr
)
2057 savedDir
= dirToDelete
;
2058 /* We have an item. Is it a file or directory? */
2059 if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
2061 /* it's a directory */
2062 savedDir
= theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
; /* save dirID of directory instead */
2063 DeleteLevel(theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
, theGlobals
); /* Delete its contents */
2064 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr
= NULL
; /* prepare to delete directory */
2066 if ( theGlobals
->error
== noErr
)
2068 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
= savedDir
; /* restore dirID */
2069 theGlobals
->myPB
.hPB
.fileParam
.ioFVersNum
= 0; /* just in case it's used on an MFS volume... */
2070 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* delete this item */
2071 if ( theGlobals
->error
== fLckdErr
)
2073 (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
)); /* unlock it */
2074 theGlobals
->error
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
)); /* and try again */
2078 } while ( theGlobals
->error
== noErr
);
2080 if ( theGlobals
->error
== fnfErr
)
2082 theGlobals
->error
= noErr
;
2086 /*****************************************************************************/
2088 pascal OSErr
DeleteDirectoryContents(short vRefNum
,
2090 ConstStr255Param name
)
2092 DeleteEnumGlobals theGlobals
;
2093 Boolean isDirectory
;
2096 /* Get the real dirID and make sure it is a directory. */
2097 error
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
);
2098 if ( error
== noErr
)
2102 /* Get the real vRefNum */
2103 error
= DetermineVRefNum(name
, vRefNum
, &vRefNum
);
2104 if ( error
== noErr
)
2106 /* Set up the globals we need to access from the recursive routine. */
2107 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum
= vRefNum
;
2109 /* Here we go into recursion land... */
2110 DeleteLevel(dirID
, &theGlobals
);
2111 error
= theGlobals
.error
;
2123 /*****************************************************************************/
2125 pascal OSErr
DeleteDirectory(short vRefNum
,
2127 ConstStr255Param name
)
2131 /* Make sure a directory was specified and then delete its contents */
2132 error
= DeleteDirectoryContents(vRefNum
, dirID
, name
);
2133 if ( error
== noErr
)
2135 error
= HDelete(vRefNum
, dirID
, name
);
2136 if ( error
== fLckdErr
)
2138 (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */
2139 error
= HDelete(vRefNum
, dirID
, name
); /* and try again */
2146 /*****************************************************************************/
2148 pascal OSErr
CheckObjectLock(short vRefNum
,
2150 ConstStr255Param name
)
2155 error
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
);
2156 if ( error
== noErr
)
2158 /* check locked bit */
2159 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0 )
2168 /*****************************************************************************/
2170 pascal OSErr
FSpCheckObjectLock(const FSSpec
*spec
)
2172 return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2175 /*****************************************************************************/
2177 pascal OSErr
GetFileSize(short vRefNum
,
2179 ConstStr255Param fileName
,
2186 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2187 pb
.fileParam
.ioVRefNum
= vRefNum
;
2188 pb
.fileParam
.ioFVersNum
= 0;
2189 pb
.fileParam
.ioDirID
= dirID
;
2190 pb
.fileParam
.ioFDirIndex
= 0;
2191 error
= PBHGetFInfoSync(&pb
);
2192 if ( error
== noErr
)
2194 *dataSize
= pb
.fileParam
.ioFlLgLen
;
2195 *rsrcSize
= pb
.fileParam
.ioFlRLgLen
;
2201 /*****************************************************************************/
2203 pascal OSErr
FSpGetFileSize(const FSSpec
*spec
,
2207 return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) );
2210 /*****************************************************************************/
2212 pascal OSErr
BumpDate(short vRefNum
,
2214 ConstStr255Param name
)
2215 /* Given a file or directory, change its modification date to the current date/time. */
2222 /* Protection against File Sharing problem */
2223 if ( (name
== NULL
) || (name
[0] == 0) )
2226 pb
.hFileInfo
.ioNamePtr
= tempName
;
2227 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2231 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2232 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2234 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2235 pb
.hFileInfo
.ioDirID
= dirID
;
2236 error
= PBGetCatInfoSync(&pb
);
2237 if ( error
== noErr
)
2240 /* set mod date to current date, or one second into the future
2241 if mod date = current date */
2242 pb
.hFileInfo
.ioFlMdDat
= (secs
== pb
.hFileInfo
.ioFlMdDat
) ? (++secs
) : (secs
);
2243 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2245 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2249 pb
.hFileInfo
.ioDirID
= dirID
;
2251 error
= PBSetCatInfoSync(&pb
);
2257 /*****************************************************************************/
2259 pascal OSErr
FSpBumpDate(const FSSpec
*spec
)
2261 return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) );
2264 /*****************************************************************************/
2266 pascal OSErr
ChangeCreatorType(short vRefNum
,
2268 ConstStr255Param name
,
2277 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2278 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2279 pb
.hFileInfo
.ioDirID
= dirID
;
2280 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2281 error
= PBGetCatInfoSync(&pb
);
2282 if ( error
== noErr
)
2284 if ( (pb
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) == 0 ) /* if file */
2286 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2288 /* If creator not 0x00000000, change creator */
2289 if ( creator
!= (OSType
)0x00000000 )
2291 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator
= creator
;
2294 /* If fileType not 0x00000000, change fileType */
2295 if ( fileType
!= (OSType
)0x00000000 )
2297 pb
.hFileInfo
.ioFlFndrInfo
.fdType
= fileType
;
2300 pb
.hFileInfo
.ioDirID
= dirID
;
2301 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2303 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2305 /* get the real vRefNum in case a full pathname was passed */
2306 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2307 if ( error
== noErr
)
2309 error
= BumpDate(realVRefNum
, parID
, NULL
);
2310 /* and bump the parent directory's mod date to wake up the Finder */
2311 /* to the change we just made */
2317 /* it was a directory, not a file */
2318 error
= notAFileErr
;
2325 /*****************************************************************************/
2327 pascal OSErr
FSpChangeCreatorType(const FSSpec
*spec
,
2331 return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) );
2334 /*****************************************************************************/
2336 pascal OSErr
ChangeFDFlags(short vRefNum
,
2338 ConstStr255Param name
,
2340 unsigned short flagBits
)
2348 /* Protection against File Sharing problem */
2349 if ( (name
== NULL
) || (name
[0] == 0) )
2352 pb
.hFileInfo
.ioNamePtr
= tempName
;
2353 pb
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2357 pb
.hFileInfo
.ioNamePtr
= (StringPtr
)name
;
2358 pb
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2360 pb
.hFileInfo
.ioVRefNum
= vRefNum
;
2361 pb
.hFileInfo
.ioDirID
= dirID
;
2362 error
= PBGetCatInfoSync(&pb
);
2363 if ( error
== noErr
)
2365 parID
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */
2367 /* set or clear the appropriate bits in the Finder flags */
2370 /* OR in the bits */
2371 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
|= flagBits
;
2375 /* AND out the bits */
2376 pb
.hFileInfo
.ioFlFndrInfo
.fdFlags
&= ~flagBits
;
2379 if ( pb
.dirInfo
.ioNamePtr
== tempName
)
2381 pb
.hFileInfo
.ioDirID
= pb
.hFileInfo
.ioFlParID
;
2385 pb
.hFileInfo
.ioDirID
= dirID
;
2388 error
= PBSetCatInfoSync(&pb
); /* now, save the new information back to disk */
2390 if ( (error
== noErr
) && (parID
!= fsRtParID
) ) /* can't bump fsRtParID */
2392 /* get the real vRefNum in case a full pathname was passed */
2393 error
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
);
2394 if ( error
== noErr
)
2396 error
= BumpDate(realVRefNum
, parID
, NULL
);
2397 /* and bump the parent directory's mod date to wake up the Finder */
2398 /* to the change we just made */
2406 /*****************************************************************************/
2408 pascal OSErr
FSpChangeFDFlags(const FSSpec
*spec
,
2410 unsigned short flagBits
)
2412 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) );
2415 /*****************************************************************************/
2417 pascal OSErr
SetIsInvisible(short vRefNum
,
2419 ConstStr255Param name
)
2420 /* Given a file or directory, make it invisible. */
2422 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) );
2425 /*****************************************************************************/
2427 pascal OSErr
FSpSetIsInvisible(const FSSpec
*spec
)
2428 /* Given a file or directory, make it invisible. */
2430 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) );
2433 /*****************************************************************************/
2435 pascal OSErr
ClearIsInvisible(short vRefNum
,
2437 ConstStr255Param name
)
2438 /* Given a file or directory, make it visible. */
2440 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) );
2443 /*****************************************************************************/
2445 pascal OSErr
FSpClearIsInvisible(const FSSpec
*spec
)
2446 /* Given a file or directory, make it visible. */
2448 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) );
2451 /*****************************************************************************/
2453 pascal OSErr
SetNameLocked(short vRefNum
,
2455 ConstStr255Param name
)
2456 /* Given a file or directory, lock its name. */
2458 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) );
2461 /*****************************************************************************/
2463 pascal OSErr
FSpSetNameLocked(const FSSpec
*spec
)
2464 /* Given a file or directory, lock its name. */
2466 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) );
2469 /*****************************************************************************/
2471 pascal OSErr
ClearNameLocked(short vRefNum
,
2473 ConstStr255Param name
)
2474 /* Given a file or directory, unlock its name. */
2476 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) );
2479 /*****************************************************************************/
2481 pascal OSErr
FSpClearNameLocked(const FSSpec
*spec
)
2482 /* Given a file or directory, unlock its name. */
2484 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) );
2487 /*****************************************************************************/
2489 pascal OSErr
SetIsStationery(short vRefNum
,
2491 ConstStr255Param name
)
2492 /* Given a file, make it a stationery pad. */
2494 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) );
2497 /*****************************************************************************/
2499 pascal OSErr
FSpSetIsStationery(const FSSpec
*spec
)
2500 /* Given a file, make it a stationery pad. */
2502 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) );
2505 /*****************************************************************************/
2507 pascal OSErr
ClearIsStationery(short vRefNum
,
2509 ConstStr255Param name
)
2510 /* Given a file, clear the stationery bit. */
2512 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) );
2515 /*****************************************************************************/
2517 pascal OSErr
FSpClearIsStationery(const FSSpec
*spec
)
2518 /* Given a file, clear the stationery bit. */
2520 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) );
2523 /*****************************************************************************/
2525 pascal OSErr
SetHasCustomIcon(short vRefNum
,
2527 ConstStr255Param name
)
2528 /* Given a file or directory, indicate that it has a custom icon. */
2530 return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) );
2533 /*****************************************************************************/
2535 pascal OSErr
FSpSetHasCustomIcon(const FSSpec
*spec
)
2536 /* Given a file or directory, indicate that it has a custom icon. */
2538 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) );
2541 /*****************************************************************************/
2543 pascal OSErr
ClearHasCustomIcon(short vRefNum
,
2545 ConstStr255Param name
)
2546 /* Given a file or directory, indicate that it does not have a custom icon. */
2548 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) );
2551 /*****************************************************************************/
2553 pascal OSErr
FSpClearHasCustomIcon(const FSSpec
*spec
)
2554 /* Given a file or directory, indicate that it does not have a custom icon. */
2556 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) );
2559 /*****************************************************************************/
2561 pascal OSErr
ClearHasBeenInited(short vRefNum
,
2563 ConstStr255Param name
)
2564 /* Given a file, clear its "has been inited" bit. */
2566 return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) );
2569 /*****************************************************************************/
2571 pascal OSErr
FSpClearHasBeenInited(const FSSpec
*spec
)
2572 /* Given a file, clear its "has been inited" bit. */
2574 return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) );
2577 /*****************************************************************************/
2579 pascal OSErr
CopyFileMgrAttributes(short srcVRefNum
,
2581 ConstStr255Param srcName
,
2584 ConstStr255Param dstName
,
2585 Boolean copyLockBit
)
2590 Boolean objectIsDirectory
;
2592 pb
.ciPB
.hFileInfo
.ioVRefNum
= srcVRefNum
;
2593 pb
.ciPB
.hFileInfo
.ioDirID
= srcDirID
;
2595 /* Protection against File Sharing problem */
2596 if ( (srcName
== NULL
) || (srcName
[0] == 0) )
2599 pb
.ciPB
.hFileInfo
.ioNamePtr
= tempName
;
2600 pb
.ciPB
.hFileInfo
.ioFDirIndex
= -1; /* use ioDirID */
2604 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)srcName
;
2605 pb
.ciPB
.hFileInfo
.ioFDirIndex
= 0; /* use ioNamePtr and ioDirID */
2607 error
= PBGetCatInfoSync(&pb
.ciPB
);
2608 if ( error
== noErr
)
2610 objectIsDirectory
= ( (pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 );
2611 pb
.ciPB
.hFileInfo
.ioVRefNum
= dstVRefNum
;
2612 pb
.ciPB
.hFileInfo
.ioDirID
= dstDirID
;
2613 if ( (dstName
!= NULL
) && (dstName
[0] == 0) )
2615 pb
.ciPB
.hFileInfo
.ioNamePtr
= NULL
;
2619 pb
.ciPB
.hFileInfo
.ioNamePtr
= (StringPtr
)dstName
;
2621 /* don't copy the hasBeenInited bit */
2622 pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
= ( pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags
& ~kHasBeenInited
);
2623 error
= PBSetCatInfoSync(&pb
.ciPB
);
2624 if ( (error
== noErr
) && (copyLockBit
) && ((pb
.ciPB
.hFileInfo
.ioFlAttrib
& kioFlAttribLockedMask
) != 0) )
2626 pb
.hPB
.fileParam
.ioFVersNum
= 0;
2627 error
= PBHSetFLockSync(&pb
.hPB
);
2628 if ( (error
!= noErr
) && (objectIsDirectory
) )
2630 error
= noErr
; /* ignore lock errors if destination is directory */
2637 /*****************************************************************************/
2639 pascal OSErr
FSpCopyFileMgrAttributes(const FSSpec
*srcSpec
,
2640 const FSSpec
*dstSpec
,
2641 Boolean copyLockBit
)
2643 return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
2644 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
,
2648 /*****************************************************************************/
2650 pascal OSErr
HOpenAware(short vRefNum
,
2652 ConstStr255Param fileName
,
2658 GetVolParmsInfoBuffer volParmsInfo
;
2659 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2661 pb
.ioParam
.ioMisc
= NULL
;
2662 pb
.fileParam
.ioFVersNum
= 0;
2663 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2664 pb
.fileParam
.ioVRefNum
= vRefNum
;
2665 pb
.fileParam
.ioDirID
= dirID
;
2667 /* get volume attributes */
2668 /* this preflighting is needed because Foreign File Access based file systems don't */
2669 /* return the correct error result to the OpenDeny call */
2670 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2671 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2673 /* if volume supports OpenDeny, use it and return */
2674 pb
.accessParam
.ioDenyModes
= denyModes
;
2675 error
= PBHOpenDenySync(&pb
);
2676 *refNum
= pb
.ioParam
.ioRefNum
;
2678 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2680 /* OpenDeny isn't supported, so try File Manager Open functions */
2682 /* If request includes write permission, then see if the volume is */
2683 /* locked by hardware or software. The HFS file system doesn't check */
2684 /* for this when a file is opened - you only find out later when you */
2685 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2687 if ( (denyModes
& dmWr
) != 0 )
2689 error
= CheckVolLock(fileName
, vRefNum
);
2696 if ( error
== noErr
)
2698 /* Set File Manager permissions to closest thing possible */
2699 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2701 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2705 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2708 error
= PBHOpenDFSync(&pb
); /* Try OpenDF */
2709 if ( error
== paramErr
)
2711 error
= PBHOpenSync(&pb
); /* OpenDF not supported, so try Open */
2713 *refNum
= pb
.ioParam
.ioRefNum
;
2720 /*****************************************************************************/
2722 pascal OSErr
FSpOpenAware(const FSSpec
*spec
,
2726 return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2729 /*****************************************************************************/
2731 pascal OSErr
HOpenRFAware(short vRefNum
,
2733 ConstStr255Param fileName
,
2739 GetVolParmsInfoBuffer volParmsInfo
;
2740 long infoSize
= sizeof(GetVolParmsInfoBuffer
);
2742 pb
.ioParam
.ioMisc
= NULL
;
2743 pb
.fileParam
.ioFVersNum
= 0;
2744 pb
.fileParam
.ioNamePtr
= (StringPtr
)fileName
;
2745 pb
.fileParam
.ioVRefNum
= vRefNum
;
2746 pb
.fileParam
.ioDirID
= dirID
;
2748 /* get volume attributes */
2749 /* this preflighting is needed because Foreign File Access based file systems don't */
2750 /* return the correct error result to the OpenRFDeny call */
2751 error
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
);
2752 if ( (error
== noErr
) && hasOpenDeny(&volParmsInfo
) )
2754 /* if volume supports OpenRFDeny, use it and return */
2755 if ( hasOpenDeny(&volParmsInfo
) )
2757 pb
.accessParam
.ioDenyModes
= denyModes
;
2758 error
= PBHOpenRFDenySync(&pb
);
2759 *refNum
= pb
.ioParam
.ioRefNum
;
2762 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2764 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
2766 /* If request includes write permission, then see if the volume is */
2767 /* locked by hardware or software. The HFS file system doesn't check */
2768 /* for this when a file is opened - you only find out later when you */
2769 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2771 if ( (denyModes
& dmWr
) != 0 )
2773 error
= CheckVolLock(fileName
, vRefNum
);
2780 if ( error
== noErr
)
2782 /* Set File Manager permissions to closest thing possible */
2783 if ( (denyModes
== dmWr
) || (denyModes
== dmRdWr
) )
2785 pb
.ioParam
.ioPermssn
= fsRdWrShPerm
;
2789 pb
.ioParam
.ioPermssn
= denyModes
% 4;
2792 error
= PBHOpenRFSync(&pb
);
2793 *refNum
= pb
.ioParam
.ioRefNum
;
2800 /*****************************************************************************/
2802 pascal OSErr
FSpOpenRFAware(const FSSpec
*spec
,
2806 return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) );
2809 /*****************************************************************************/
2811 pascal OSErr
FSReadNoCache(short refNum
,
2818 pb
.ioParam
.ioRefNum
= refNum
;
2819 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2820 pb
.ioParam
.ioReqCount
= *count
;
2821 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2822 pb
.ioParam
.ioPosOffset
= 0;
2823 error
= PBReadSync(&pb
);
2824 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2828 /*****************************************************************************/
2830 pascal OSErr
FSWriteNoCache(short refNum
,
2832 const void *buffPtr
)
2837 pb
.ioParam
.ioRefNum
= refNum
;
2838 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2839 pb
.ioParam
.ioReqCount
= *count
;
2840 pb
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
; /* fsAtMark + noCacheMask */
2841 pb
.ioParam
.ioPosOffset
= 0;
2842 error
= PBWriteSync(&pb
);
2843 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2847 /*****************************************************************************/
2850 ** See if numBytes bytes of buffer1 are equal to buffer2.
2852 static Boolean
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
)
2854 register unsigned char *b1
= (unsigned char *)buffer1
;
2855 register unsigned char *b2
= (unsigned char *)buffer2
;
2857 if ( b1
!= b2
) /* if buffer pointers are same, then they are equal */
2859 while ( numBytes
> 0 )
2861 /* compare the bytes and then increment the pointers */
2862 if ( (*b1
++ - *b2
++) != 0 )
2873 /*****************************************************************************/
2876 ** Read any number of bytes from an open file using read-verify mode.
2877 ** The FSReadVerify function reads any number of bytes from an open file
2878 ** and verifies them against the data in the buffer pointed to by buffPtr.
2880 ** Because of a bug in the HFS file system, only non-block aligned parts of
2881 ** the read are verified against the buffer data and the rest is *copied*
2882 ** into the buffer. Thus, you shouldn't verify against your original data;
2883 ** instead, you should verify against a copy of the original data and then
2884 ** compare the read-verified copy against the original data after calling
2885 ** FSReadVerify. That's why this function isn't exported - it needs the
2886 ** wrapper provided by FSWriteVerify.
2888 static OSErr
FSReadVerify(short refNum
,
2895 pb
.ioParam
.ioRefNum
= refNum
;
2896 pb
.ioParam
.ioBuffer
= (Ptr
)buffPtr
;
2897 pb
.ioParam
.ioReqCount
= *count
;
2898 pb
.ioParam
.ioPosMode
= fsAtMark
+ rdVerify
;
2899 pb
.ioParam
.ioPosOffset
= 0;
2900 result
= PBReadSync(&pb
);
2901 *count
= pb
.ioParam
.ioActCount
; /* always return count */
2905 /*****************************************************************************/
2907 pascal OSErr
FSWriteVerify(short refNum
,
2909 const void *buffPtr
)
2920 ** Allocate the verify buffer
2921 ** Try to get get a large enough buffer to verify in one pass.
2922 ** If that fails, use GetTempBuffer to get a buffer.
2924 bufferSize
= *count
;
2925 verifyBuffer
= NewPtr(bufferSize
);
2926 if ( verifyBuffer
== NULL
)
2928 verifyBuffer
= GetTempBuffer(bufferSize
, &bufferSize
);
2930 if ( verifyBuffer
!= NULL
)
2932 /* Save the current position */
2933 result
= GetFPos(refNum
, &position
);
2934 if ( result
== noErr
)
2936 /* Write the data */
2937 result
= FSWrite(refNum
, count
, buffPtr
);
2938 if ( result
== noErr
)
2940 /* Restore the original position */
2941 result
= SetFPos(refNum
, fsFromStart
, position
);
2942 if ( result
== noErr
)
2945 ** *count = total number of bytes to verify
2946 ** bufferSize = the size of the verify buffer
2947 ** bytesVerified = number of bytes verified
2948 ** byteCount = number of bytes to verify this pass
2949 ** startVerify = position in buffPtr
2952 startVerify
= (Ptr
)buffPtr
;
2953 while ( (bytesVerified
< *count
) && ( result
== noErr
) )
2955 if ( (*count
- bytesVerified
) > bufferSize
)
2957 byteCount
= bufferSize
;
2961 byteCount
= *count
- bytesVerified
;
2964 ** Copy the write buffer into the verify buffer.
2965 ** This step is needed because the File Manager
2966 ** compares the data in any non-block aligned
2967 ** data at the beginning and end of the read-verify
2968 ** request back into the file system's cache
2969 ** to the data in verify Buffer. However, the
2970 ** File Manager does not compare any full blocks
2971 ** and instead copies them into the verify buffer
2972 ** so we still have to compare the buffers again
2973 ** after the read-verify request completes.
2975 BlockMoveData(startVerify
, verifyBuffer
, byteCount
);
2977 /* Read-verify the data back into the verify buffer */
2978 result
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
);
2979 if ( result
== noErr
)
2981 /* See if the buffers are the same */
2982 if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) )
2986 startVerify
+= byteCount
;
2987 bytesVerified
+= byteCount
;
2993 DisposePtr(verifyBuffer
);
2997 result
= memFullErr
;
3002 /*****************************************************************************/
3004 pascal OSErr
CopyFork(short srcRefNum
,
3006 void *copyBufferPtr
,
3007 long copyBufferSize
)
3009 ParamBlockRec srcPB
;
3010 ParamBlockRec dstPB
;
3014 if ( (copyBufferPtr
== NULL
) || (copyBufferSize
== 0) )
3015 return ( paramErr
);
3017 srcPB
.ioParam
.ioRefNum
= srcRefNum
;
3018 dstPB
.ioParam
.ioRefNum
= dstRefNum
;
3020 /* preallocate the destination fork and */
3021 /* ensure the destination fork's EOF is correct after the copy */
3022 srcError
= PBGetEOFSync(&srcPB
);
3023 if ( srcError
!= noErr
)
3024 return ( srcError
);
3025 dstPB
.ioParam
.ioMisc
= srcPB
.ioParam
.ioMisc
;
3026 dstError
= PBSetEOFSync(&dstPB
);
3027 if ( dstError
!= noErr
)
3028 return ( dstError
);
3030 /* reset source fork's mark */
3031 srcPB
.ioParam
.ioPosMode
= fsFromStart
;
3032 srcPB
.ioParam
.ioPosOffset
= 0;
3033 srcError
= PBSetFPosSync(&srcPB
);
3034 if ( srcError
!= noErr
)
3035 return ( srcError
);
3037 /* reset destination fork's mark */
3038 dstPB
.ioParam
.ioPosMode
= fsFromStart
;
3039 dstPB
.ioParam
.ioPosOffset
= 0;
3040 dstError
= PBSetFPosSync(&dstPB
);
3041 if ( dstError
!= noErr
)
3042 return ( dstError
);
3044 /* set up fields that won't change in the loop */
3045 srcPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3046 srcPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3047 /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
3048 /* This will make writes on local volumes faster */
3049 if ( (copyBufferSize
>= 512) && ((copyBufferSize
& 0x1ff) != 0) )
3051 srcPB
.ioParam
.ioReqCount
= copyBufferSize
& 0xfffffe00;
3055 srcPB
.ioParam
.ioReqCount
= copyBufferSize
;
3057 dstPB
.ioParam
.ioBuffer
= (Ptr
)copyBufferPtr
;
3058 dstPB
.ioParam
.ioPosMode
= fsAtMark
+ noCacheMask
;/* fsAtMark + noCacheMask */
3060 while ( (srcError
== noErr
) && (dstError
== noErr
) )
3062 srcError
= PBReadSync(&srcPB
);
3063 dstPB
.ioParam
.ioReqCount
= srcPB
.ioParam
.ioActCount
;
3064 dstError
= PBWriteSync(&dstPB
);
3067 /* make sure there were no errors at the destination */
3068 if ( dstError
!= noErr
)
3069 return ( dstError
);
3071 /* make sure the only error at the source was eofErr */
3072 if ( srcError
!= eofErr
)
3073 return ( srcError
);
3078 /*****************************************************************************/
3080 pascal OSErr
GetFileLocation(short refNum
,
3088 pb
.ioNamePtr
= fileName
;
3090 pb
.ioRefNum
= refNum
;
3092 error
= PBGetFCBInfoSync(&pb
);
3093 if ( error
== noErr
)
3095 *vRefNum
= pb
.ioFCBVRefNum
;
3096 *dirID
= pb
.ioFCBParID
;
3101 /*****************************************************************************/
3103 pascal OSErr
FSpGetFileLocation(short refNum
,
3106 return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) );
3109 /*****************************************************************************/
3111 pascal OSErr
CopyDirectoryAccess(short srcVRefNum
,
3113 ConstStr255Param srcName
,
3116 ConstStr255Param dstName
)
3119 GetVolParmsInfoBuffer infoBuffer
; /* Where PBGetVolParms dumps its info */
3120 long dstServerAdr
; /* AppleTalk server address of destination (if any) */
3121 long ownerID
, groupID
, accessRights
;
3124 /* See if destination supports directory access control */
3125 tempLong
= sizeof(infoBuffer
);
3126 error
= HGetVolParms(dstName
, dstVRefNum
, &infoBuffer
, &tempLong
);
3127 if ( (error
== noErr
) && hasAccessCntl(&infoBuffer
) )
3129 if ( hasAccessCntl(&infoBuffer
) )
3131 dstServerAdr
= infoBuffer
.vMServerAdr
;
3133 /* See if source supports directory access control and is on same server */
3134 tempLong
= sizeof(infoBuffer
);
3135 error
= HGetVolParms(srcName
, srcVRefNum
, &infoBuffer
, &tempLong
);
3136 if ( error
== noErr
)
3138 if ( hasAccessCntl(&infoBuffer
) && (dstServerAdr
== infoBuffer
.vMServerAdr
) )
3140 /* both volumes support directory access control and they are */
3141 /* on same server, so copy the access information */
3142 error
= HGetDirAccess(srcVRefNum
, srcDirID
, srcName
, &ownerID
, &groupID
, &accessRights
);
3143 if ( error
== noErr
)
3145 error
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
);
3150 /* destination doesn't support directory access control or */
3151 /* they volumes aren't on the same server */
3158 /* destination doesn't support directory access control */
3166 /*****************************************************************************/
3168 pascal OSErr
FSpCopyDirectoryAccess(const FSSpec
*srcSpec
,
3169 const FSSpec
*dstSpec
)
3171 return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3172 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) );
3175 /*****************************************************************************/
3177 pascal OSErr
HMoveRenameCompat(short vRefNum
,
3179 ConstStr255Param srcName
,
3181 ConstStr255Param dstpathName
,
3182 ConstStr255Param copyName
)
3185 GetVolParmsInfoBuffer volParmsInfo
;
3190 Boolean isDirectory
;
3191 long tempItemsDirID
;
3192 long uniqueTempDirID
;
3193 Str31 uniqueTempDirName
;
3194 unsigned short uniqueNameoverflow
;
3196 /* Get volume attributes */
3197 infoSize
= sizeof(GetVolParmsInfoBuffer
);
3198 error
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
);
3199 if ( (error
== noErr
) && hasMoveRename(&volParmsInfo
) )
3201 /* If volume supports move and rename, so use it and return */
3202 error
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
);
3204 else if ( (error
== noErr
) || (error
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
3206 /* MoveRename isn't supported by this volume, so do it by hand */
3208 /* If copyName isn't supplied, we can simply CatMove and return */
3209 if ( copyName
== NULL
)
3211 error
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
);
3215 /* Renaming is required, so we have some work to do... */
3217 /* Get the object's real name, real parent ID and real vRefNum */
3218 error
= GetObjectLocation(vRefNum
, srcDirID
, (StringPtr
)srcName
,
3219 &realVRefNum
, &realParID
, realName
, &isDirectory
);
3220 if ( error
== noErr
)
3222 /* Find the Temporary Items Folder on that volume */
3223 error
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
,
3224 &realVRefNum
, &tempItemsDirID
);
3225 if ( error
== noErr
)
3227 /* Create a new uniquely named folder in the temporary items folder. */
3228 /* This is done to avoid the case where 'realName' or 'copyName' already */
3229 /* exists in the temporary items folder. */
3231 /* Start with current tick count as uniqueTempDirName */
3232 NumToString(TickCount(), uniqueTempDirName
);
3233 uniqueNameoverflow
= 0;
3236 error
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
);
3237 if ( error
== dupFNErr
)
3239 /* Duplicate name - change the first character to the next ASCII character */
3240 ++uniqueTempDirName
[1];
3241 /* Make sure it isn't a colon! */
3242 if ( uniqueTempDirName
[1] == ':' )
3244 ++uniqueTempDirName
[1];
3246 /* Don't go too far... */
3247 ++uniqueNameoverflow
;
3249 } while ( (error
== dupFNErr
) && (uniqueNameoverflow
<= 64) ); /* 64 new files per 1/60th second - not likely! */
3250 if ( error
== noErr
)
3252 /* Move the object to the folder with uniqueTempDirID for renaming */
3253 error
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
);
3254 if ( error
== noErr
)
3256 /* Rename the object */
3257 error
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
);
3258 if ( error
== noErr
)
3260 /* Move object to its new home */
3261 error
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
);
3262 if ( error
!= noErr
)
3264 /* Error handling: rename object back to original name - ignore errors */
3265 (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
);
3268 if ( error
!= noErr
)
3270 /* Error handling: move object back to original location - ignore errors */
3271 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
);
3274 /* Done with ourTempDir, so delete it - ignore errors */
3275 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
);
3285 /*****************************************************************************/
3287 pascal OSErr
FSpMoveRenameCompat(const FSSpec
*srcSpec
,
3288 const FSSpec
*dstSpec
,
3289 ConstStr255Param copyName
)
3291 /* make sure the FSSpecs refer to the same volume */
3292 if (srcSpec
->vRefNum
!= dstSpec
->vRefNum
)
3293 return (diffVolErr
);
3294 return ( HMoveRenameCompat(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
,
3295 dstSpec
->parID
, dstSpec
->name
, copyName
) );
3298 /*****************************************************************************/
3300 pascal OSErr
BuildAFPVolMountInfo(short flags
,
3310 AFPVolMountInfoPtr
*afpInfoPtr
)
3312 MyAFPVolMountInfoPtr infoPtr
;
3315 /* Allocate the AFPXVolMountInfo record */
3316 infoPtr
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
));
3317 if ( infoPtr
!= NULL
)
3319 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
3320 infoPtr
->length
= sizeof(MyAFPVolMountInfo
);
3321 infoPtr
->media
= AppleShareMediaType
;
3322 infoPtr
->flags
= flags
;
3323 infoPtr
->nbpInterval
= nbpInterval
;
3324 infoPtr
->nbpCount
= nbpCount
;
3325 infoPtr
->uamType
= uamType
;
3327 infoPtr
->zoneNameOffset
= offsetof(MyAFPVolMountInfo
, zoneName
);
3328 infoPtr
->serverNameOffset
= offsetof(MyAFPVolMountInfo
, serverName
);
3329 infoPtr
->volNameOffset
= offsetof(MyAFPVolMountInfo
, volName
);
3330 infoPtr
->userNameOffset
= offsetof(MyAFPVolMountInfo
, userName
);
3331 infoPtr
->userPasswordOffset
= offsetof(MyAFPVolMountInfo
, userPassword
);
3332 infoPtr
->volPasswordOffset
= offsetof(MyAFPVolMountInfo
, volPassword
);
3334 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3335 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3336 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3337 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3338 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3339 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3341 *afpInfoPtr
= (AFPVolMountInfoPtr
)infoPtr
;
3352 /*****************************************************************************/
3354 pascal OSErr
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
,
3358 StringPtr serverName
,
3365 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3366 if ( afpInfoPtr
->media
== AppleShareMediaType
)
3368 *flags
= afpInfoPtr
->flags
;
3369 *uamType
= afpInfoPtr
->uamType
;
3371 if ( afpInfoPtr
->zoneNameOffset
!= 0)
3373 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->zoneNameOffset
);
3374 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3377 if ( afpInfoPtr
->serverNameOffset
!= 0)
3379 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->serverNameOffset
);
3380 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3383 if ( afpInfoPtr
->volNameOffset
!= 0)
3385 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->volNameOffset
);
3386 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3389 if ( afpInfoPtr
->userNameOffset
!= 0)
3391 tempPtr
= (StringPtr
)((long)afpInfoPtr
+ afpInfoPtr
->userNameOffset
);
3392 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3405 /*****************************************************************************/
3407 pascal OSErr
BuildAFPXVolMountInfo(short flags
,
3418 unsigned long alternateAddressLength
,
3419 void *alternateAddress
,
3420 AFPXVolMountInfoPtr
*afpXInfoPtr
)
3423 MyAFPXVolMountInfoPtr infoPtr
;
3426 /* Calculate the size of the AFPXVolMountInfo record */
3427 infoSize
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength
- 1;
3429 /* Allocate the AFPXVolMountInfo record */
3430 infoPtr
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
);
3431 if ( infoPtr
!= NULL
)
3433 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
3434 infoPtr
->length
= infoSize
;
3435 infoPtr
->media
= AppleShareMediaType
;
3436 infoPtr
->flags
= flags
;
3437 if ( alternateAddressLength
!= 0 )
3439 /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
3440 infoPtr
->flags
|= volMountExtendedFlagsMask
;
3441 /* and set the only extendedFlags bit we know about */
3442 infoPtr
->extendedFlags
= kAFPExtendedFlagsAlternateAddressMask
;
3446 /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
3447 infoPtr
->flags
&= ~volMountExtendedFlagsMask
;
3448 /* and clear the extendedFlags */
3449 infoPtr
->extendedFlags
= 0;
3451 infoPtr
->nbpInterval
= nbpInterval
;
3452 infoPtr
->nbpCount
= nbpCount
;
3453 infoPtr
->uamType
= uamType
;
3455 infoPtr
->zoneNameOffset
= offsetof(MyAFPXVolMountInfo
, zoneName
);
3456 infoPtr
->serverNameOffset
= offsetof(MyAFPXVolMountInfo
, serverName
);
3457 infoPtr
->volNameOffset
= offsetof(MyAFPXVolMountInfo
, volName
);
3458 infoPtr
->userNameOffset
= offsetof(MyAFPXVolMountInfo
, userName
);
3459 infoPtr
->userPasswordOffset
= offsetof(MyAFPXVolMountInfo
, userPassword
);
3460 infoPtr
->volPasswordOffset
= offsetof(MyAFPXVolMountInfo
, volPassword
);
3461 infoPtr
->uamNameOffset
= offsetof(MyAFPXVolMountInfo
, uamName
);
3462 infoPtr
->alternateAddressOffset
= offsetof(MyAFPXVolMountInfo
, alternateAddress
);
3464 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
));
3465 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
));
3466 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
));
3467 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
));
3468 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
));
3469 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
));
3470 BlockMoveData(uamName
, infoPtr
->uamName
, sizeof(Str32
));
3471 BlockMoveData(alternateAddress
, infoPtr
->alternateAddress
, alternateAddressLength
);
3473 *afpXInfoPtr
= (AFPXVolMountInfoPtr
)infoPtr
;
3484 /*****************************************************************************/
3486 pascal OSErr
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
,
3490 StringPtr serverName
,
3494 unsigned long *alternateAddressLength
,
3495 AFPAlternateAddress
**alternateAddress
)
3498 Ptr alternateAddressStart
;
3499 Ptr alternateAddressEnd
;
3500 Size alternateAddressDataSize
;
3504 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3505 if ( afpXInfoPtr
->media
== AppleShareMediaType
)
3507 /* default to noErr */
3510 /* Is this an extended record? */
3511 if ( (afpXInfoPtr
->flags
& volMountExtendedFlagsMask
) != 0 )
3513 if ( ((afpXInfoPtr
->extendedFlags
& kAFPExtendedFlagsAlternateAddressMask
) != 0) &&
3514 (afpXInfoPtr
->alternateAddressOffset
!= 0) )
3517 alternateAddressStart
= (Ptr
)((long)afpXInfoPtr
+ afpXInfoPtr
->alternateAddressOffset
);
3518 alternateAddressEnd
= alternateAddressStart
+ 1; /* skip over alternate address version byte */
3519 addressCount
= *(UInt8
*)alternateAddressEnd
; /* get the address count */
3520 ++alternateAddressEnd
; /* skip over alternate address count byte */
3521 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
3522 while ( addressCount
!= 0 )
3524 /* parse the address list to find the end */
3525 alternateAddressEnd
+= *(UInt8
*)alternateAddressEnd
; /* add length of each AFPTagData record */
3528 /* get the size of the alternateAddressData */
3529 alternateAddressDataSize
= alternateAddressEnd
- alternateAddressStart
;
3530 /* allocate memory for it */
3531 *alternateAddress
= (AFPAlternateAddress
*)NewPtr(alternateAddressDataSize
);
3532 if ( *alternateAddress
!= NULL
)
3534 /* and return the data */
3535 BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
);
3536 *alternateAddressLength
= alternateAddressDataSize
;
3540 /* no memory - fail now */
3545 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3547 if ( afpXInfoPtr
->uamNameOffset
!= 0 )
3549 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->uamNameOffset
);
3550 BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1);
3555 if ( error
== noErr
) /* fill in more output parameters if everything is OK */
3557 *flags
= afpXInfoPtr
->flags
;
3558 *uamType
= afpXInfoPtr
->uamType
;
3560 if ( afpXInfoPtr
->zoneNameOffset
!= 0 )
3562 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->zoneNameOffset
);
3563 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1);
3566 if ( afpXInfoPtr
->serverNameOffset
!= 0 )
3568 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->serverNameOffset
);
3569 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1);
3572 if ( afpXInfoPtr
->volNameOffset
!= 0 )
3574 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->volNameOffset
);
3575 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1);
3578 if ( afpXInfoPtr
->userNameOffset
!= 0 )
3580 tempPtr
= (StringPtr
)((long)afpXInfoPtr
+ afpXInfoPtr
->userNameOffset
);
3581 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1);
3593 /*****************************************************************************/
3595 pascal OSErr
GetUGEntries(short objType
,
3598 long *actEntryCount
,
3602 OSErr error
= noErr
;
3603 UGEntry
*endEntryArray
;
3605 pb
.objParam
.ioObjType
= objType
;
3607 for ( endEntryArray
= entries
+ reqEntryCount
; (entries
< endEntryArray
) && (error
== noErr
); ++entries
)
3609 pb
.objParam
.ioObjNamePtr
= (StringPtr
)entries
->name
;
3610 pb
.objParam
.ioObjID
= *objID
;
3611 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
3612 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
3613 /* A CMovePBPtr works OK, but this will be changed in the future back to */
3614 /* HParmBlkPtr, so I'm just casting it here. */
3615 error
= PBGetUGEntrySync(&pb
);
3616 if ( error
== noErr
)
3618 entries
->objID
= *objID
= pb
.objParam
.ioObjID
;
3619 entries
->objType
= objType
;
3627 /*****************************************************************************/