]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/morefile/MoreFilesExtras.c
Patch by David Brinegar to fix menubar updating after modal dialog shown
[wxWidgets.git] / src / mac / carbon / morefile / MoreFilesExtras.c
1 /*
2 File: MoreFilesExtras.c
3
4 Contains: A collection of useful high-level File Manager routines
5
6 Version: MoreFiles
7
8 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved.
9
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.
17
18 File Ownership:
19
20 DRI: Jim Luther
21
22 Other Contact: Apple Macintosh Developer Technical Support
23 <http://developer.apple.com/bugreporter/>
24
25 Technology: DTS Sample Code
26
27 Writers:
28
29 (JL) Jim Luther
30
31 Change History (most recent first):
32
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.
41 */
42
43 #include <MacTypes.h>
44 #if !TARGET_CARBON
45 #include <Traps.h>
46 #include <FSM.h>
47 #include <Disks.h>
48 #else
49 #include <HFSVolumes.h>
50 #endif
51 #include <OSUtils.h>
52 #include <MacErrors.h>
53 #include <MacMemory.h>
54 #include <Files.h>
55 #include <Devices.h>
56 #include <Finder.h>
57 #include <Folders.h>
58 #include <Gestalt.h>
59 #include <TextUtils.h>
60 #include <Script.h>
61 #include <Math64.h>
62 #include <CodeFragments.h>
63 #include <stddef.h>
64
65 #define __COMPILINGMOREFILES
66
67 #include "MoreFiles.h"
68 #include "MoreDesktopMgr.h"
69 #include "FSpCompat.h"
70
71 #include "MoreFilesExtras.h"
72
73 /*****************************************************************************/
74
75 /* Functions to get information out of GetVolParmsInfoBuffer. */
76
77 /* version 1 field getters */
78
79 pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer *volParms)
80 {
81 return ( volParms->vMVersion );
82 }
83
84 pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer *volParms)
85 {
86 return ( volParms->vMAttrib );
87 }
88
89 pascal Handle GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer *volParms)
90 {
91 return ( volParms->vMLocalHand );
92 }
93
94 pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer *volParms)
95 {
96 return ( volParms->vMServerAdr );
97 }
98
99 /* version 2 field getters (assume zero result if version < 2) */
100
101 pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer *volParms)
102 {
103 return ( (volParms->vMVersion >= 2) ? volParms->vMVolumeGrade : 0 );
104 }
105
106 pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer *volParms)
107 {
108 return ( (volParms->vMVersion >= 2) ? volParms->vMForeignPrivID : 0 );
109 }
110
111 /* version 3 field getters (assume zero result if version < 3) */
112
113 pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer *volParms)
114 {
115 return ( (volParms->vMVersion >= 3) ? volParms->vMExtendedAttributes : 0 );
116 }
117
118 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */
119
120 pascal Boolean isNetworkVolume(const GetVolParmsInfoBuffer *volParms)
121 {
122 return ( volParms->vMServerAdr != 0 );
123 }
124
125 pascal Boolean hasLimitFCBs(const GetVolParmsInfoBuffer *volParms)
126 {
127 return ( (volParms->vMAttrib & (1L << bLimitFCBs)) != 0 );
128 }
129
130 pascal Boolean hasLocalWList(const GetVolParmsInfoBuffer *volParms)
131 {
132 return ( (volParms->vMAttrib & (1L << bLocalWList)) != 0 );
133 }
134
135 pascal Boolean hasNoMiniFndr(const GetVolParmsInfoBuffer *volParms)
136 {
137 return ( (volParms->vMAttrib & (1L << bNoMiniFndr)) != 0 );
138 }
139
140 pascal Boolean hasNoVNEdit(const GetVolParmsInfoBuffer *volParms)
141 {
142 return ( (volParms->vMAttrib & (1L << bNoVNEdit)) != 0 );
143 }
144
145 pascal Boolean hasNoLclSync(const GetVolParmsInfoBuffer *volParms)
146 {
147 return ( (volParms->vMAttrib & (1L << bNoLclSync)) != 0 );
148 }
149
150 pascal Boolean hasTrshOffLine(const GetVolParmsInfoBuffer *volParms)
151 {
152 return ( (volParms->vMAttrib & (1L << bTrshOffLine)) != 0 );
153 }
154
155 pascal Boolean hasNoSwitchTo(const GetVolParmsInfoBuffer *volParms)
156 {
157 return ( (volParms->vMAttrib & (1L << bNoSwitchTo)) != 0 );
158 }
159
160 pascal Boolean hasNoDeskItems(const GetVolParmsInfoBuffer *volParms)
161 {
162 return ( (volParms->vMAttrib & (1L << bNoDeskItems)) != 0 );
163 }
164
165 pascal Boolean hasNoBootBlks(const GetVolParmsInfoBuffer *volParms)
166 {
167 return ( (volParms->vMAttrib & (1L << bNoBootBlks)) != 0 );
168 }
169
170 pascal Boolean hasAccessCntl(const GetVolParmsInfoBuffer *volParms)
171 {
172 return ( (volParms->vMAttrib & (1L << bAccessCntl)) != 0 );
173 }
174
175 pascal Boolean hasNoSysDir(const GetVolParmsInfoBuffer *volParms)
176 {
177 return ( (volParms->vMAttrib & (1L << bNoSysDir)) != 0 );
178 }
179
180 pascal Boolean hasExtFSVol(const GetVolParmsInfoBuffer *volParms)
181 {
182 return ( (volParms->vMAttrib & (1L << bHasExtFSVol)) != 0 );
183 }
184
185 pascal Boolean hasOpenDeny(const GetVolParmsInfoBuffer *volParms)
186 {
187 return ( (volParms->vMAttrib & (1L << bHasOpenDeny)) != 0 );
188 }
189
190 pascal Boolean hasCopyFile(const GetVolParmsInfoBuffer *volParms)
191 {
192 return ( (volParms->vMAttrib & (1L << bHasCopyFile)) != 0 );
193 }
194
195 pascal Boolean hasMoveRename(const GetVolParmsInfoBuffer *volParms)
196 {
197 return ( (volParms->vMAttrib & (1L << bHasMoveRename)) != 0 );
198 }
199
200 pascal Boolean hasDesktopMgr(const GetVolParmsInfoBuffer *volParms)
201 {
202 return ( (volParms->vMAttrib & (1L << bHasDesktopMgr)) != 0 );
203 }
204
205 pascal Boolean hasShortName(const GetVolParmsInfoBuffer *volParms)
206 {
207 return ( (volParms->vMAttrib & (1L << bHasShortName)) != 0 );
208 }
209
210 pascal Boolean hasFolderLock(const GetVolParmsInfoBuffer *volParms)
211 {
212 return ( (volParms->vMAttrib & (1L << bHasFolderLock)) != 0 );
213 }
214
215 pascal Boolean hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer *volParms)
216 {
217 return ( (volParms->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0 );
218 }
219
220 pascal Boolean hasUserGroupList(const GetVolParmsInfoBuffer *volParms)
221 {
222 return ( (volParms->vMAttrib & (1L << bHasUserGroupList)) != 0 );
223 }
224
225 pascal Boolean hasCatSearch(const GetVolParmsInfoBuffer *volParms)
226 {
227 return ( (volParms->vMAttrib & (1L << bHasCatSearch)) != 0 );
228 }
229
230 pascal Boolean hasFileIDs(const GetVolParmsInfoBuffer *volParms)
231 {
232 return ( (volParms->vMAttrib & (1L << bHasFileIDs)) != 0 );
233 }
234
235 pascal Boolean hasBTreeMgr(const GetVolParmsInfoBuffer *volParms)
236 {
237 return ( (volParms->vMAttrib & (1L << bHasBTreeMgr)) != 0 );
238 }
239
240 pascal Boolean hasBlankAccessPrivileges(const GetVolParmsInfoBuffer *volParms)
241 {
242 return ( (volParms->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0 );
243 }
244
245 pascal Boolean supportsAsyncRequests(const GetVolParmsInfoBuffer *volParms)
246 {
247 return ( (volParms->vMAttrib & (1L << bSupportsAsyncRequests)) != 0 );
248 }
249
250 pascal Boolean supportsTrashVolumeCache(const GetVolParmsInfoBuffer *volParms)
251 {
252 return ( (volParms->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0 );
253 }
254
255 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
256
257 pascal Boolean volIsEjectable(const GetVolParmsInfoBuffer *volParms)
258 {
259 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0 );
260 }
261
262 pascal Boolean volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer *volParms)
263 {
264 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0 );
265 }
266
267 pascal Boolean volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer *volParms)
268 {
269 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0 );
270 }
271
272 pascal Boolean volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer *volParms)
273 {
274 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0 );
275 }
276
277 pascal Boolean volSupports2TBFiles(const GetVolParmsInfoBuffer *volParms)
278 {
279 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0 );
280 }
281
282 pascal Boolean volSupportsLongNames(const GetVolParmsInfoBuffer *volParms)
283 {
284 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0 );
285 }
286
287 pascal Boolean volSupportsMultiScriptNames(const GetVolParmsInfoBuffer *volParms)
288 {
289 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0 );
290 }
291
292 pascal Boolean volSupportsNamedForks(const GetVolParmsInfoBuffer *volParms)
293 {
294 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0 );
295 }
296
297 pascal Boolean volSupportsSubtreeIterators(const GetVolParmsInfoBuffer *volParms)
298 {
299 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0 );
300 }
301
302 pascal Boolean volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer *volParms)
303 {
304 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0 );
305 }
306
307 /*****************************************************************************/
308
309 /* Functions for testing ioACUser bits. */
310
311 pascal Boolean userIsOwner(SInt8 ioACUser)
312 {
313 return ( (ioACUser & kioACUserNotOwnerMask) == 0 );
314 }
315
316 pascal Boolean userHasFullAccess(SInt8 ioACUser)
317 {
318 return ( (ioACUser & acUserAccessMask) == acUserFull );
319 }
320
321 pascal Boolean userHasDropBoxAccess(SInt8 ioACUser)
322 {
323 return ( (ioACUser & acUserAccessMask) == acUserDropBox );
324 }
325
326 pascal Boolean userHasBulletinBoard(SInt8 ioACUser)
327 {
328 return ( (ioACUser & acUserAccessMask) == acUserBulletinBoard );
329 }
330
331 pascal Boolean userHasNoAccess(SInt8 ioACUser)
332 {
333 return ( (ioACUser & acUserAccessMask) == acUserNone );
334 }
335
336 /*****************************************************************************/
337
338 /* local data structures */
339
340 /* The DeleteEnumGlobals structure is used to minimize the amount of
341 ** stack space used when recursively calling DeleteLevel and to hold
342 ** global information that might be needed at any time. */
343
344 #if PRAGMA_STRUCT_ALIGN
345 #pragma options align=mac68k
346 #endif // PRAGMA_STRUCT_ALIGN
347 struct DeleteEnumGlobals
348 {
349 OSErr error; /* temporary holder of results - saves 2 bytes of stack each level */
350 Str63 itemName; /* the name of the current item */
351 UniversalFMPB myPB; /* the parameter block used for PBGetCatInfo calls */
352 };
353 #if PRAGMA_STRUCT_ALIGN
354 #pragma options align=reset
355 #endif // PRAGMA_STRUCT_ALIGN
356
357 typedef struct DeleteEnumGlobals DeleteEnumGlobals;
358 typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr;
359
360 /*****************************************************************************/
361
362 /*
363 ** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
364 ** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync
365 ** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined,
366 ** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync.
367 **
368 ** Non-CFM 68K programs don't needs this glue (and won't get it) because
369 ** they instead use the inline assembly glue found in the Files.h interface
370 ** file.
371 */
372
373 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
374
375 // Carbon builds and 68K builds don't need this glue
376 #define CallPBXGetVolInfoSync PBXGetVolInfoSync
377
378 #else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
379
380 #if __WANTPASCALELIMINATION
381 #undef pascal
382 #endif // __WANTPASCALELIMINATION
383
384 /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */
385 static pascal OSErr PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock)
386 {
387 enum
388 {
389 uppFSDispatchProcInfo = kRegisterBased
390 | REGISTER_RESULT_LOCATION(kRegisterD0)
391 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
392 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */
393 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */
394 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
395 };
396
397 static UniversalProcPtr fsDispatchTrapAddress = NULL;
398
399 /* Is this the first time we've been called? */
400 if ( fsDispatchTrapAddress == NULL )
401 {
402 /* Yes - Get the trap address of _FSDispatch */
403 fsDispatchTrapAddress = NGetTrapAddress(_FSDispatch, OSTrap);
404 }
405 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress,
406 uppFSDispatchProcInfo,
407 kFSMXGetVolInfo,
408 _FSDispatch,
409 paramBlock) );
410 }
411
412 /*
413 ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2.
414 ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5.
415 ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib;
416 ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program
417 ** is calling the latest implementation of PBXGetVolInfoSync.
418 */
419 static pascal OSErr CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock)
420 {
421 typedef pascal OSErr (*PBXGetVolInfoProcPtr) (XVolumeParamPtr paramBlock);
422
423 OSErr result;
424 CFragConnectionID connID;
425 Ptr mainAddr;
426 Str255 errMessage;
427 static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr = NULL;
428
429 //* Is this the first time we've been called? */
430 if ( PBXGetVolInfoSyncPtr == NULL )
431 {
432 /* Yes - Get our connection ID to InterfaceLib */
433 result = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kLoadCFrag, &connID, &mainAddr, errMessage);
434 if ( result == noErr )
435 {
436 /* See if PBXGetVolInfoSync is in InterfaceLib */
437 if ( FindSymbol(connID, "\pPBXGetVolInfoSync", &(Ptr)PBXGetVolInfoSyncPtr, NULL) != noErr )
438 {
439 /* Use glue code if symbol isn't found */
440 PBXGetVolInfoSyncPtr = PBXGetVolInfoSyncGlue;
441 }
442 }
443 }
444 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */
445 return ( (*PBXGetVolInfoSyncPtr)(paramBlock) );
446 }
447
448 #if __WANTPASCALELIMINATION
449 #define pascal
450 #endif // __WANTPASCALELIMINATION
451
452 #endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
453
454 /*****************************************************************************/
455
456 pascal void TruncPString(StringPtr destination,
457 ConstStr255Param source,
458 short maxLength)
459 {
460 short charType;
461
462 if ( source != NULL && destination != NULL ) /* don't do anything stupid */
463 {
464 if ( source[0] > maxLength )
465 {
466 /* Make sure the string isn't truncated in the middle of */
467 /* a multi-byte character. */
468 while (maxLength != 0)
469 {
470 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter
471 charType = CharacterByteType((Ptr)&source[1], maxLength - 1, smSystemScript);
472 if ( (charType == smSingleByte) || (charType == smLastByte) )
473 break; /* source[maxLength] is now a valid last character */
474 --maxLength;
475 }
476 }
477 else
478 {
479 maxLength = source[0];
480 }
481 /* Set the destination string length */
482 destination[0] = maxLength;
483 /* and copy maxLength characters (if needed) */
484 if ( source != destination )
485 {
486 while ( maxLength != 0 )
487 {
488 destination[maxLength] = source[maxLength];
489 --maxLength;
490 }
491 }
492 }
493 }
494
495 /*****************************************************************************/
496
497 static pascal Ptr GetTempBuffer(long buffReqSize,
498 long *buffActSize)
499 {
500 enum
501 {
502 kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
503 };
504 Ptr tempPtr;
505
506 /* Make request a multiple of 1024 bytes */
507 buffReqSize = buffReqSize & 0xfffffc00;
508
509 if ( buffReqSize < 0x00000400 )
510 {
511 /* Request was smaller than 1024 bytes - make it 1024 */
512 buffReqSize = 0x00000400;
513 }
514
515 /* Attempt to allocate the memory */
516 tempPtr = NewPtr(buffReqSize);
517
518 /* If request failed, go to backup plan */
519 if ( (tempPtr == NULL) && (buffReqSize > 0x00000400) )
520 {
521 /*
522 ** Try to get largest 1024-byte block available
523 ** leaving some slop for the toolbox if possible
524 */
525 long freeMemory = (FreeMem() - kSlopMemory) & 0xfffffc00;
526
527 buffReqSize = MaxBlock() & 0xfffffc00;
528
529 if ( buffReqSize > freeMemory )
530 {
531 buffReqSize = freeMemory;
532 }
533
534 if ( buffReqSize == 0 )
535 {
536 buffReqSize = 0x00000400;
537 }
538
539 tempPtr = NewPtr(buffReqSize);
540 }
541
542 /* Return bytes allocated */
543 if ( tempPtr != NULL )
544 {
545 *buffActSize = buffReqSize;
546 }
547 else
548 {
549 *buffActSize = 0;
550 }
551
552 return ( tempPtr );
553 }
554
555 /*****************************************************************************/
556
557 /*
558 ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
559 ** in cases where the returned volume name is not needed by the caller.
560 ** The pathname and vRefNum parameters are not touched, and the pb
561 ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
562 ** the parameter block is always returned as NULL (since it might point
563 ** to the local tempPathname).
564 **
565 ** I noticed using this code in several places, so here it is once.
566 ** This reduces the code size of MoreFiles.
567 */
568 pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
569 short vRefNum,
570 HParmBlkPtr pb)
571 {
572 Str255 tempPathname;
573 OSErr error;
574
575 /* Make sure pb parameter is not NULL */
576 if ( pb != NULL )
577 {
578 pb->volumeParam.ioVRefNum = vRefNum;
579 if ( pathname == NULL )
580 {
581 pb->volumeParam.ioNamePtr = NULL;
582 pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
583 }
584 else
585 {
586 BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
587 pb->volumeParam.ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */
588 pb->volumeParam.ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */
589 }
590 error = PBHGetVInfoSync(pb);
591 pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */
592 }
593 else
594 {
595 error = paramErr;
596 }
597 return ( error );
598 }
599
600 /*****************************************************************************/
601
602 /*
603 ** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
604 ** in cases where the returned volume name is not needed by the caller.
605 ** The pathname and vRefNum parameters are not touched, and the pb
606 ** parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
607 ** the parameter block is always returned as NULL (since it might point
608 ** to the local tempPathname).
609 */
610 pascal OSErr XGetVolumeInfoNoName(ConstStr255Param pathname,
611 short vRefNum,
612 XVolumeParamPtr pb)
613 {
614 Str255 tempPathname;
615 OSErr error;
616
617 /* Make sure pb parameter is not NULL */
618 if ( pb != NULL )
619 {
620 pb->ioVRefNum = vRefNum;
621 pb->ioXVersion = 0; /* this XVolumeParam version (0) */
622 if ( pathname == NULL )
623 {
624 pb->ioNamePtr = NULL;
625 pb->ioVolIndex = 0; /* use ioVRefNum only */
626 }
627 else
628 {
629 BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
630 pb->ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */
631 pb->ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */
632 }
633
634 {
635 #if !TARGET_API_MAC_CARBON
636 long response;
637
638 /* Is PBXGetVolInfo available? */
639 if ( ( Gestalt(gestaltFSAttr, &response) != noErr ) || ((response & (1L << gestaltFSSupports2TBVols)) == 0) )
640 {
641 /* No, fall back on PBHGetVInfo */
642 error = PBHGetVInfoSync((HParmBlkPtr)pb);
643 if ( error == noErr )
644 {
645 /* calculate the ioVTotalBytes and ioVFreeBytes fields */
646 pb->ioVTotalBytes = U64Multiply(U64SetU(pb->ioVNmAlBlks), U64SetU(pb->ioVAlBlkSiz));
647 pb->ioVFreeBytes = U64Multiply(U64SetU(pb->ioVFrBlk), U64SetU(pb->ioVAlBlkSiz));
648 }
649 }
650 else
651 #endif
652 {
653 /* Yes, so use it */
654 error = CallPBXGetVolInfoSync(pb);
655 }
656 }
657 pb->ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */
658 }
659 else
660 {
661 error = paramErr;
662 }
663 return ( error );
664 }
665
666 /*****************************************************************************/
667
668 pascal OSErr GetCatInfoNoName(short vRefNum,
669 long dirID,
670 ConstStr255Param name,
671 CInfoPBPtr pb)
672 {
673 Str31 tempName;
674 OSErr error;
675
676 /* Protection against File Sharing problem */
677 if ( (name == NULL) || (name[0] == 0) )
678 {
679 tempName[0] = 0;
680 pb->dirInfo.ioNamePtr = tempName;
681 pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
682 }
683 else
684 {
685 pb->dirInfo.ioNamePtr = (StringPtr)name;
686 pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
687 }
688 pb->dirInfo.ioVRefNum = vRefNum;
689 pb->dirInfo.ioDrDirID = dirID;
690 error = PBGetCatInfoSync(pb);
691 pb->dirInfo.ioNamePtr = NULL;
692 return ( error );
693 }
694
695 /*****************************************************************************/
696
697 pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
698 short vRefNum,
699 short *realVRefNum)
700 {
701 HParamBlockRec pb;
702 OSErr error;
703
704 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
705 if ( error == noErr )
706 {
707 *realVRefNum = pb.volumeParam.ioVRefNum;
708 }
709 return ( error );
710 }
711
712 /*****************************************************************************/
713
714 pascal OSErr HGetVInfo(short volReference,
715 StringPtr volName,
716 short *vRefNum,
717 unsigned long *freeBytes,
718 unsigned long *totalBytes)
719 {
720 OSErr result;
721 UInt64 freeBytes64;
722 UInt64 totalBytes64;
723
724 // get the best values possible from XGetVInfo
725 result = XGetVInfo(volReference, volName, vRefNum, &freeBytes64, &totalBytes64);
726 if ( result == noErr )
727 {
728 // and pin those values if needed
729 if ( (UInt64ToUnsignedWide(freeBytes64)).hi != 0 )
730 {
731 // pin to maximum 512-byte block aligned value
732 *freeBytes = 0xfffffe00;
733 }
734 else
735 {
736 *freeBytes = U32SetU(freeBytes64);
737 }
738
739 if ( (UInt64ToUnsignedWide(totalBytes64)).hi != 0 )
740 {
741 // pin to maximum 512-byte block aligned value
742 *totalBytes = 0xfffffe00;
743 }
744 else
745 {
746 *totalBytes = U32SetU(totalBytes64);
747 }
748 }
749
750 return ( result );
751 }
752
753 /*****************************************************************************/
754
755 pascal OSErr XGetVInfo(short volReference,
756 StringPtr volName,
757 short *vRefNum,
758 UInt64 *freeBytes,
759 UInt64 *totalBytes)
760 {
761 OSErr result;
762 XVolumeParam pb;
763
764 #if !TARGET_API_MAC_CARBON
765
766 long response;
767
768 #endif // !TARGET_API_MAC_CARBON
769
770 pb.ioVRefNum = volReference;
771 pb.ioNamePtr = volName;
772 pb.ioXVersion = 0; /* this XVolumeParam version (0) */
773 pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
774
775 #if !TARGET_API_MAC_CARBON
776
777 /* See if large volume support is available */
778 if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
779
780 #endif // !TARGET_API_MAC_CARBON
781
782 {
783 /* Large volume support is available */
784 result = CallPBXGetVolInfoSync(&pb);
785 if ( result == noErr )
786 {
787 /* The volume name was returned in volName (if not NULL) and */
788 /* we have the volume's vRefNum and allocation block size */
789 *vRefNum = pb.ioVRefNum;
790
791 /* return the freeBytes and totalBytes */
792 *totalBytes = pb.ioVTotalBytes;
793 *freeBytes = pb.ioVFreeBytes;
794 }
795 }
796
797 #if !TARGET_API_MAC_CARBON
798
799 else
800 {
801 /* No large volume support */
802 /* Use PBHGetVInfoSync to get the results */
803 result = PBHGetVInfoSync((HParmBlkPtr)&pb);
804 if ( result == noErr )
805 {
806 VCB *theVCB;
807
808 /* The volume name was returned in volName (if not NULL) and */
809 /* we have the volume's vRefNum */
810 *vRefNum = pb.ioVRefNum;
811
812 /* System 7.5 (and beyond) pins the number of allocation blocks and */
813 /* the number of free allocation blocks returned by PBHGetVInfo to */
814 /* a value so that when multiplied by the allocation block size, */
815 /* the volume will look like it has $7fffffff bytes or less. This */
816 /* was done so older applications that use signed math or that use */
817 /* the GetVInfo function (which uses signed math) will continue to work. */
818 /* However, the unpinned numbers (which we want) are always available */
819 /* in the volume's VCB so we'll get those values from the VCB. */
820 /* Note: Carbon doesn't support the VCB queue, so this code cannot be */
821 /* used (and is conditionalized out) by Carbon applications. */
822
823 /* Find the volume's VCB */
824 theVCB = (VCB *)(GetVCBQHdr()->qHead);
825 while ( theVCB != NULL )
826 {
827 if ( theVCB->vcbVRefNum == *vRefNum )
828 {
829 break;
830 }
831
832 theVCB = (VCB *)(theVCB->qLink); /* next VCB */
833 }
834
835 if ( theVCB != NULL )
836 {
837 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
838 /* and the number of free blocks from the VCB. */
839 *freeBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbFreeBks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
840 *totalBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
841 }
842 else
843 {
844 /* Didn't find a VCB we can use. Return the number of allocation blocks */
845 /* and the number of free blocks returned by PBHGetVInfoSync. */
846 *freeBytes = U64Multiply(U64SetU((unsigned short)pb.ioVFrBlk), U64SetU((unsigned long)pb.ioVAlBlkSiz));
847 *totalBytes = U64Multiply(U64SetU((unsigned short)pb.ioVNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
848 }
849
850 }
851 }
852
853 #endif // !TARGET_API_MAC_CARBON
854
855 return ( result );
856 }
857
858 /*****************************************************************************/
859
860 pascal OSErr CheckVolLock(ConstStr255Param pathname,
861 short vRefNum)
862 {
863 HParamBlockRec pb;
864 OSErr error;
865
866 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
867 if ( error == noErr )
868 {
869 if ( (pb.volumeParam.ioVAtrb & kHFSVolumeHardwareLockMask) != 0 )
870 {
871 error = wPrErr; /* volume locked by hardware */
872 }
873 else if ( (pb.volumeParam.ioVAtrb & kHFSVolumeSoftwareLockMask) != 0 )
874 {
875 error = vLckdErr; /* volume locked by software */
876 }
877 }
878
879 return ( error );
880 }
881
882 /*****************************************************************************/
883 //
884 // The following routines call Mac OS routines that are not supported by
885 // Carbon:
886 //
887 // GetDriverName
888 // FindDrive
889 // GetDiskBlocks
890 // GetVolState
891
892 #if !TARGET_API_MAC_CARBON // {
893
894 /*****************************************************************************/
895
896 pascal OSErr GetDriverName(short driverRefNum,
897 Str255 driverName)
898 {
899 OSErr result;
900 DCtlHandle theDctl;
901 DRVRHeaderPtr dHeaderPtr;
902
903 theDctl = GetDCtlEntry(driverRefNum);
904 if ( theDctl != NULL )
905 {
906 if ( (**theDctl).dCtlFlags & dRAMBasedMask )
907 {
908 /* dctlDriver is handle - dereference */
909 dHeaderPtr = *((DRVRHeaderHandle)(**theDctl).dCtlDriver);
910 }
911 else
912 {
913 /* dctlDriver is pointer */
914 dHeaderPtr = (DRVRHeaderPtr)(**theDctl).dCtlDriver;
915 }
916 BlockMoveData((*dHeaderPtr).drvrName, driverName, (*dHeaderPtr).drvrName[0] + 1);
917 result = noErr;
918 }
919 else
920 {
921 driverName[0] = 0;
922 result = badUnitErr; /* bad reference number */
923 }
924
925 return ( result );
926 }
927
928 /*****************************************************************************/
929
930 pascal OSErr FindDrive(ConstStr255Param pathname,
931 short vRefNum,
932 DrvQElPtr *driveQElementPtr)
933 {
934 OSErr result;
935 HParamBlockRec hPB;
936 short driveNumber;
937
938 *driveQElementPtr = NULL;
939
940 /* First, use GetVolumeInfoNoName to determine the volume */
941 result = GetVolumeInfoNoName(pathname, vRefNum, &hPB);
942 if ( result == noErr )
943 {
944 /*
945 ** The volume can be either online, offline, or ejected. What we find in
946 ** ioVDrvInfo and ioVDRefNum will tell us which it is.
947 ** See Inside Macintosh: Files page 2-80 and the Technical Note
948 ** "FL 34 - VCBs and Drive Numbers : The Real Story"
949 ** Where we get the drive number depends on the state of the volume.
950 */
951 if ( hPB.volumeParam.ioVDrvInfo != 0 )
952 {
953 /* The volume is online and not ejected */
954 /* Get the drive number */
955 driveNumber = hPB.volumeParam.ioVDrvInfo;
956 }
957 else
958 {
959 /* The volume's is either offline or ejected */
960 /* in either case, the volume is NOT online */
961
962 /* Is it ejected or just offline? */
963 if ( hPB.volumeParam.ioVDRefNum > 0 )
964 {
965 /* It's ejected, the drive number is ioVDRefNum */
966 driveNumber = hPB.volumeParam.ioVDRefNum;
967 }
968 else
969 {
970 /* It's offline, the drive number is the negative of ioVDRefNum */
971 driveNumber = (short)-hPB.volumeParam.ioVDRefNum;
972 }
973 }
974
975 /* Get pointer to first element in drive queue */
976 *driveQElementPtr = (DrvQElPtr)(GetDrvQHdr()->qHead);
977
978 /* Search for a matching drive number */
979 while ( (*driveQElementPtr != NULL) && ((*driveQElementPtr)->dQDrive != driveNumber) )
980 {
981 *driveQElementPtr = (DrvQElPtr)(*driveQElementPtr)->qLink;
982 }
983
984 if ( *driveQElementPtr == NULL )
985 {
986 /* This should never happen since every volume must have a drive, but... */
987 result = nsDrvErr;
988 }
989 }
990
991 return ( result );
992 }
993
994 /*****************************************************************************/
995
996 pascal OSErr GetDiskBlocks(ConstStr255Param pathname,
997 short vRefNum,
998 unsigned long *numBlocks)
999 {
1000 /* Various constants for GetDiskBlocks() */
1001 enum
1002 {
1003 /* return format list status code */
1004 kFmtLstCode = 6,
1005
1006 /* reference number of .SONY driver */
1007 kSonyRefNum = 0xfffb,
1008
1009 /* values returned by DriveStatus in DrvSts.twoSideFmt */
1010 kSingleSided = 0,
1011 kDoubleSided = -1,
1012 kSingleSidedSize = 800, /* 400K */
1013 kDoubleSidedSize = 1600, /* 800K */
1014
1015 /* values in DrvQEl.qType */
1016 kWordDrvSiz = 0,
1017 kLongDrvSiz = 1,
1018
1019 /* more than enough formatListRecords */
1020 kMaxFormatListRecs = 16
1021 };
1022
1023 DrvQElPtr driveQElementPtr;
1024 unsigned long blocks;
1025 ParamBlockRec pb;
1026 FormatListRec formatListRecords[kMaxFormatListRecs];
1027 DrvSts status;
1028 short formatListRecIndex;
1029 OSErr result;
1030
1031 blocks = 0;
1032
1033 /* Find the drive queue element for this volume */
1034 result = FindDrive(pathname, vRefNum, &driveQElementPtr);
1035
1036 /*
1037 ** Make sure this is a real driver (dQRefNum < 0).
1038 ** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
1039 ** problems if you try to use it as a driver refNum.
1040 */
1041 if ( (result == noErr) && (driveQElementPtr->dQRefNum >= 0) )
1042 {
1043 result = paramErr;
1044 }
1045 else
1046 {
1047 /* Attempt to get the drive's format list. */
1048 /* (see the Technical Note "What Your Sony Drives For You") */
1049
1050 pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive;
1051 pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum;
1052 pb.cntrlParam.csCode = kFmtLstCode;
1053 pb.cntrlParam.csParam[0] = kMaxFormatListRecs;
1054 *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0];
1055
1056 result = PBStatusSync(&pb);
1057
1058 if ( result == noErr )
1059 {
1060 /* The drive supports ReturnFormatList status call. */
1061
1062 /* Get the current disk's size. */
1063 for( formatListRecIndex = 0;
1064 formatListRecIndex < pb.cntrlParam.csParam[0];
1065 ++formatListRecIndex )
1066 {
1067 if ( (formatListRecords[formatListRecIndex].formatFlags &
1068 diCIFmtFlagsCurrentMask) != 0 )
1069 {
1070 blocks = formatListRecords[formatListRecIndex].volSize;
1071 }
1072 }
1073 if ( blocks == 0 )
1074 {
1075 /* This should never happen */
1076 result = paramErr;
1077 }
1078 }
1079 else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum )
1080 {
1081 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
1082
1083 result = DriveStatus(driveQElementPtr->dQDrive, &status);
1084 if ( result == noErr )
1085 {
1086 switch ( status.twoSideFmt )
1087 {
1088 case kSingleSided:
1089 blocks = kSingleSidedSize;
1090 break;
1091 case kDoubleSided:
1092 blocks = kDoubleSidedSize;
1093 break;
1094 default:
1095 /* This should never happen */
1096 result = paramErr;
1097 break;
1098 }
1099 }
1100 }
1101 else
1102 {
1103 /* The drive is not a floppy and it doesn't support ReturnFormatList */
1104 /* so use the dQDrvSz field(s) */
1105
1106 result = noErr; /* reset result */
1107 switch ( driveQElementPtr->qType )
1108 {
1109 case kWordDrvSiz:
1110 blocks = driveQElementPtr->dQDrvSz;
1111 break;
1112 case kLongDrvSiz:
1113 blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) +
1114 driveQElementPtr->dQDrvSz;
1115 break;
1116 default:
1117 /* This should never happen */
1118 result = paramErr;
1119 break;
1120 }
1121 }
1122 }
1123
1124 if ( result == noErr )
1125 {
1126 *numBlocks = blocks;
1127 }
1128
1129 return ( result );
1130 }
1131
1132 /*****************************************************************************/
1133
1134 pascal OSErr GetVolState(ConstStr255Param pathname,
1135 short vRefNum,
1136 Boolean *volumeOnline,
1137 Boolean *volumeEjected,
1138 Boolean *driveEjectable,
1139 Boolean *driverWantsEject)
1140 {
1141 HParamBlockRec pb;
1142 short driveNumber;
1143 OSErr error;
1144
1145 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
1146 if ( error == noErr )
1147 {
1148 if ( pb.volumeParam.ioVDrvInfo != 0 )
1149 {
1150 /* the volume is online and not ejected */
1151 *volumeOnline = true;
1152 *volumeEjected = false;
1153
1154 /* Get the drive number */
1155 driveNumber = pb.volumeParam.ioVDrvInfo;
1156 }
1157 else
1158 {
1159 /* the volume's is either offline or ejected */
1160 /* in either case, the volume is NOT online */
1161 *volumeOnline = false;
1162
1163 /* Is it ejected? */
1164 *volumeEjected = pb.volumeParam.ioVDRefNum > 0;
1165
1166 if ( *volumeEjected )
1167 {
1168 /* If ejected, the drive number is ioVDRefNum */
1169 driveNumber = pb.volumeParam.ioVDRefNum;
1170 }
1171 else
1172 {
1173 /* If offline, the drive number is the negative of ioVDRefNum */
1174 driveNumber = (short)-pb.volumeParam.ioVDRefNum;
1175 }
1176 }
1177
1178 {
1179 DrvQElPtr drvQElem;
1180
1181 /* Find the drive queue element by searching the drive queue */
1182 drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
1183 while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNumber) )
1184 {
1185 drvQElem = (DrvQElPtr)drvQElem->qLink;
1186 }
1187
1188 if ( drvQElem != NULL )
1189 {
1190 /*
1191 ** Each drive queue element is preceded by 4 flag bytes.
1192 ** Byte 1 (the second flag byte) has bits that tell us if a
1193 ** drive is ejectable and if its driver wants an eject call.
1194 ** See Inside Macintosh: Files, page 2-85.
1195 */
1196 {
1197 Ptr flagBytePtr;
1198
1199 /* point to byte 1 of the flag bytes */
1200 flagBytePtr = (Ptr)drvQElem;
1201 flagBytePtr -= 3;
1202
1203 /*
1204 ** The drive is ejectable if flag byte 1 does not contain
1205 ** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
1206 */
1207
1208 *driveEjectable = (*flagBytePtr != 0x08) && (*flagBytePtr != 0x48);
1209
1210 /*
1211 ** The driver wants an eject call if flag byte 1 does not contain
1212 ** 0x08 (nonejectable). This may seem like a minor point, but some
1213 ** disk drivers use the Eject request to flush their caches to disk
1214 ** and you wouldn't want to skip that step after unmounting a volume.
1215 */
1216
1217 *driverWantsEject = (*flagBytePtr != 0x08);
1218 }
1219 }
1220 else
1221 {
1222 /* Didn't find the drive (this should never happen) */
1223 *driveEjectable = false;
1224 *driverWantsEject = false;
1225 }
1226 }
1227 }
1228
1229 return ( error );
1230 }
1231
1232 /*****************************************************************************/
1233
1234 #endif // } !TARGET_API_MAC_CARBON
1235
1236 /*****************************************************************************/
1237
1238 pascal OSErr GetVolFileSystemID(ConstStr255Param pathname,
1239 short vRefNum,
1240 short *fileSystemID)
1241 {
1242 HParamBlockRec pb;
1243 OSErr error;
1244
1245 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
1246 if ( error == noErr )
1247 {
1248 *fileSystemID = pb.volumeParam.ioVFSID;
1249 }
1250
1251 return ( error );
1252 }
1253
1254 /*****************************************************************************/
1255
1256 //
1257 // Note: Under Carbon there are no drive numbers, so you cannot call
1258 // Eject with a drive number after unmounting a volume.
1259 // When a Carbon application calls UnmountVol, CarbonLib will make
1260 // sure ejectable media is ejected (leaving ejectable media in the
1261 // disk drive makes no sense to Carbon applications).
1262 //
1263 pascal OSErr UnmountAndEject(ConstStr255Param pathname,
1264 short vRefNum)
1265 {
1266 HParamBlockRec pb;
1267 OSErr error;
1268
1269 error = GetVolumeInfoNoName(pathname, vRefNum, &pb);
1270 if ( error == noErr )
1271 {
1272
1273 #if !TARGET_API_MAC_CARBON
1274
1275 short driveNum;
1276 Boolean ejected, wantsEject;
1277 DrvQElPtr drvQElem;
1278
1279 if ( pb.volumeParam.ioVDrvInfo != 0 )
1280 {
1281 /* the volume is online and not ejected */
1282 ejected = false;
1283
1284 /* Get the drive number */
1285 driveNum = pb.volumeParam.ioVDrvInfo;
1286 }
1287 else
1288 {
1289 /* the volume is ejected or offline */
1290
1291 /* Is it ejected? */
1292 ejected = pb.volumeParam.ioVDRefNum > 0;
1293
1294 if ( ejected )
1295 {
1296 /* If ejected, the drive number is ioVDRefNum */
1297 driveNum = pb.volumeParam.ioVDRefNum;
1298 }
1299 else
1300 {
1301 /* If offline, the drive number is the negative of ioVDRefNum */
1302 driveNum = (short)-pb.volumeParam.ioVDRefNum;
1303 }
1304 }
1305
1306 /* find the drive queue element */
1307 drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
1308 while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNum) )
1309 {
1310 drvQElem = (DrvQElPtr)drvQElem->qLink;
1311 }
1312
1313 if ( drvQElem != NULL )
1314 {
1315 /* does the drive want an eject call */
1316 wantsEject = (*((Ptr)((Ptr)drvQElem - 3)) != 8);
1317 }
1318 else
1319 {
1320 /* didn't find the drive!! */
1321 wantsEject = false;
1322 }
1323
1324 #endif // !TARGET_API_MAC_CARBON
1325
1326 /* unmount the volume */
1327 pb.volumeParam.ioNamePtr = NULL;
1328 /* ioVRefNum is already filled in from PBHGetVInfo */
1329 error = PBUnmountVol((ParmBlkPtr)&pb);
1330
1331 #if !TARGET_API_MAC_CARBON
1332
1333 if ( error == noErr )
1334 {
1335 if ( wantsEject && !ejected )
1336 {
1337 /* eject the media from the drive if needed */
1338 pb.volumeParam.ioVRefNum = driveNum;
1339 error = PBEject((ParmBlkPtr)&pb);
1340 }
1341 }
1342
1343 #endif // !TARGET_API_MAC_CARBON
1344
1345 }
1346
1347 return ( error );
1348 }
1349
1350 /*****************************************************************************/
1351
1352 pascal OSErr OnLine(FSSpecPtr volumes,
1353 short reqVolCount,
1354 short *actVolCount,
1355 short *volIndex)
1356 {
1357 HParamBlockRec pb;
1358 OSErr error = noErr;
1359 FSSpec *endVolArray;
1360
1361 if ( *volIndex > 0 )
1362 {
1363 *actVolCount = 0;
1364 for ( endVolArray = volumes + reqVolCount; (volumes < endVolArray) && (error == noErr); ++volumes )
1365 {
1366 pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
1367 pb.volumeParam.ioVolIndex = *volIndex;
1368 error = PBHGetVInfoSync(&pb);
1369 if ( error == noErr )
1370 {
1371 volumes->parID = fsRtParID; /* the root directory's parent is 1 */
1372 volumes->vRefNum = pb.volumeParam.ioVRefNum;
1373 ++*volIndex;
1374 ++*actVolCount;
1375 }
1376 }
1377 }
1378 else
1379 {
1380 error = paramErr;
1381 }
1382
1383 return ( error );
1384 }
1385
1386 /*****************************************************************************/
1387
1388 pascal OSErr SetDefault(short newVRefNum,
1389 long newDirID,
1390 short *oldVRefNum,
1391 long *oldDirID)
1392 {
1393 OSErr error;
1394
1395 /* Get the current default volume/directory. */
1396 error = HGetVol(NULL, oldVRefNum, oldDirID);
1397 if ( error == noErr )
1398 {
1399 /* Set the new default volume/directory */
1400 error = HSetVol(NULL, newVRefNum, newDirID);
1401 }
1402
1403 return ( error );
1404 }
1405
1406 /*****************************************************************************/
1407
1408 pascal OSErr RestoreDefault(short oldVRefNum,
1409 long oldDirID)
1410 {
1411 OSErr error;
1412
1413 #if !TARGET_API_MAC_CARBON
1414
1415 short defaultVRefNum;
1416 long defaultDirID;
1417 long defaultProcID;
1418
1419 /* Determine if the default volume was a wdRefNum. */
1420 error = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID);
1421 if ( error == noErr )
1422 {
1423 /* Restore the old default volume/directory, one way or the other. */
1424 if ( defaultDirID != fsRtDirID )
1425 {
1426 /* oldVRefNum was a wdRefNum - use SetVol */
1427 error = SetVol(NULL, oldVRefNum);
1428 }
1429 else
1430 {
1431
1432 #endif // !TARGET_API_MAC_CARBON
1433
1434 /* oldVRefNum was a real vRefNum - use HSetVol */
1435 error = HSetVol(NULL, oldVRefNum, oldDirID);
1436
1437 #if !TARGET_API_MAC_CARBON
1438
1439 }
1440 }
1441 #endif // !TARGET_API_MAC_CARBON
1442
1443 return ( error );
1444 }
1445
1446 /*****************************************************************************/
1447
1448 pascal OSErr GetDInfo(short vRefNum,
1449 long dirID,
1450 ConstStr255Param name,
1451 DInfo *fndrInfo)
1452 {
1453 CInfoPBRec pb;
1454 OSErr error;
1455
1456 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1457 if ( error == noErr )
1458 {
1459 if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
1460 {
1461 /* it's a directory, return the DInfo */
1462 *fndrInfo = pb.dirInfo.ioDrUsrWds;
1463 }
1464 else
1465 {
1466 /* oops, a file was passed */
1467 error = dirNFErr;
1468 }
1469 }
1470
1471 return ( error );
1472 }
1473
1474 /*****************************************************************************/
1475
1476 pascal OSErr FSpGetDInfo(const FSSpec *spec,
1477 DInfo *fndrInfo)
1478 {
1479 return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
1480 }
1481
1482 /*****************************************************************************/
1483
1484 pascal OSErr SetDInfo(short vRefNum,
1485 long dirID,
1486 ConstStr255Param name,
1487 const DInfo *fndrInfo)
1488 {
1489 CInfoPBRec pb;
1490 Str31 tempName;
1491 OSErr error;
1492
1493 /* Protection against File Sharing problem */
1494 if ( (name == NULL) || (name[0] == 0) )
1495 {
1496 tempName[0] = 0;
1497 pb.dirInfo.ioNamePtr = tempName;
1498 pb.dirInfo.ioFDirIndex = -1; /* use ioDirID */
1499 }
1500 else
1501 {
1502 pb.dirInfo.ioNamePtr = (StringPtr)name;
1503 pb.dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1504 }
1505 pb.dirInfo.ioVRefNum = vRefNum;
1506 pb.dirInfo.ioDrDirID = dirID;
1507 error = PBGetCatInfoSync(&pb);
1508 if ( error == noErr )
1509 {
1510 if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
1511 {
1512 /* it's a directory, set the DInfo */
1513 if ( pb.dirInfo.ioNamePtr == tempName )
1514 {
1515 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
1516 }
1517 else
1518 {
1519 pb.dirInfo.ioDrDirID = dirID;
1520 }
1521 pb.dirInfo.ioDrUsrWds = *fndrInfo;
1522 error = PBSetCatInfoSync(&pb);
1523 }
1524 else
1525 {
1526 /* oops, a file was passed */
1527 error = dirNFErr;
1528 }
1529 }
1530
1531 return ( error );
1532 }
1533
1534 /*****************************************************************************/
1535
1536 pascal OSErr FSpSetDInfo(const FSSpec *spec,
1537 const DInfo *fndrInfo)
1538 {
1539 return ( SetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
1540 }
1541
1542 /*****************************************************************************/
1543
1544 pascal OSErr GetDirectoryID(short vRefNum,
1545 long dirID,
1546 ConstStr255Param name,
1547 long *theDirID,
1548 Boolean *isDirectory)
1549 {
1550 CInfoPBRec pb;
1551 OSErr error;
1552
1553 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1554 if ( error == noErr )
1555 {
1556 *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
1557 if ( *isDirectory )
1558 {
1559 *theDirID = pb.dirInfo.ioDrDirID;
1560 }
1561 else
1562 {
1563 *theDirID = pb.hFileInfo.ioFlParID;
1564 }
1565 }
1566
1567 return ( error );
1568 }
1569
1570 /*****************************************************************************/
1571
1572 pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
1573 long *theDirID,
1574 Boolean *isDirectory)
1575 {
1576 return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
1577 theDirID, isDirectory) );
1578 }
1579
1580 /*****************************************************************************/
1581
1582 pascal OSErr GetDirName(short vRefNum,
1583 long dirID,
1584 Str31 name)
1585 {
1586 CInfoPBRec pb;
1587 OSErr error;
1588
1589 if ( name != NULL )
1590 {
1591 pb.dirInfo.ioNamePtr = name;
1592 pb.dirInfo.ioVRefNum = vRefNum;
1593 pb.dirInfo.ioDrDirID = dirID;
1594 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
1595 error = PBGetCatInfoSync(&pb);
1596 }
1597 else
1598 {
1599 error = paramErr;
1600 }
1601
1602 return ( error );
1603 }
1604
1605 /*****************************************************************************/
1606
1607 pascal OSErr GetIOACUser(short vRefNum,
1608 long dirID,
1609 ConstStr255Param name,
1610 SInt8 *ioACUser)
1611 {
1612 CInfoPBRec pb;
1613 OSErr error;
1614
1615 /* Clear ioACUser before calling PBGetCatInfo since some file systems
1616 ** don't bother to set or clear this field. If ioACUser isn't set by the
1617 ** file system, then you'll get the zero value back (full access) which
1618 ** is the access you have on volumes that don't support ioACUser.
1619 */
1620 pb.dirInfo.ioACUser = 0; /* ioACUser used to be filler2 */
1621 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1622 if ( error == noErr )
1623 {
1624 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 )
1625 {
1626 /* oops, a file was passed */
1627 error = dirNFErr;
1628 }
1629 else
1630 {
1631 *ioACUser = pb.dirInfo.ioACUser;
1632 }
1633 }
1634
1635 return ( error );
1636 }
1637
1638 /*****************************************************************************/
1639
1640 pascal OSErr FSpGetIOACUser(const FSSpec *spec,
1641 SInt8 *ioACUser)
1642 {
1643 return ( GetIOACUser(spec->vRefNum, spec->parID, spec->name, ioACUser) );
1644 }
1645
1646 /*****************************************************************************/
1647
1648 pascal OSErr GetParentID(short vRefNum,
1649 long dirID,
1650 ConstStr255Param name,
1651 long *parID)
1652 {
1653 CInfoPBRec pb;
1654 Str31 tempName;
1655 OSErr error;
1656 short realVRefNum;
1657
1658 /* Protection against File Sharing problem */
1659 if ( (name == NULL) || (name[0] == 0) )
1660 {
1661 tempName[0] = 0;
1662 pb.hFileInfo.ioNamePtr = tempName;
1663 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
1664 }
1665 else
1666 {
1667 pb.hFileInfo.ioNamePtr = (StringPtr)name;
1668 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1669 }
1670 pb.hFileInfo.ioVRefNum = vRefNum;
1671 pb.hFileInfo.ioDirID = dirID;
1672 error = PBGetCatInfoSync(&pb);
1673 if ( error == noErr )
1674 {
1675 /*
1676 ** There's a bug in HFS where the wrong parent dir ID can be
1677 ** returned if multiple separators are used at the end of a
1678 ** pathname. For example, if the pathname:
1679 ** 'volumeName:System Folder:Extensions::'
1680 ** is passed, the directory ID of the Extensions folder is
1681 ** returned in the ioFlParID field instead of fsRtDirID. Since
1682 ** multiple separators at the end of a pathname always specifies
1683 ** a directory, we only need to work-around cases where the
1684 ** object is a directory and there are multiple separators at
1685 ** the end of the name parameter.
1686 */
1687 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
1688 {
1689 /* Its a directory */
1690
1691 /* is there a pathname? */
1692 if ( pb.hFileInfo.ioNamePtr == name )
1693 {
1694 /* could it contain multiple separators? */
1695 if ( name[0] >= 2 )
1696 {
1697 /* does it contain multiple separators at the end? */
1698 if ( (name[name[0]] == ':') && (name[name[0] - 1] == ':') )
1699 {
1700 /* OK, then do the extra stuff to get the correct parID */
1701
1702 /* Get the real vRefNum (this should not fail) */
1703 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1704 if ( error == noErr )
1705 {
1706 /* we don't need the parent's name, but add protect against File Sharing problem */
1707 tempName[0] = 0;
1708 pb.dirInfo.ioNamePtr = tempName;
1709 pb.dirInfo.ioVRefNum = realVRefNum;
1710 /* pb.dirInfo.ioDrDirID already contains the */
1711 /* dirID of the directory object */
1712 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
1713 error = PBGetCatInfoSync(&pb);
1714 /* now, pb.dirInfo.ioDrParID contains the correct parID */
1715 }
1716 }
1717 }
1718 }
1719 }
1720
1721 if ( error == noErr )
1722 {
1723 /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
1724 /* contains the parent ID */
1725 *parID = pb.hFileInfo.ioFlParID;
1726 }
1727 }
1728
1729 return ( error );
1730 }
1731
1732 /*****************************************************************************/
1733
1734 pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
1735 Str255 filename)
1736 {
1737 short index;
1738 short nameEnd;
1739 OSErr error;
1740
1741 /* default to no filename */
1742 filename[0] = 0;
1743
1744 /* check for no pathname */
1745 if ( pathname != NULL )
1746 {
1747 /* get string length */
1748 index = pathname[0];
1749
1750 /* check for empty string */
1751 if ( index != 0 )
1752 {
1753 /* skip over last trailing colon (if any) */
1754 if ( pathname[index] == ':' )
1755 {
1756 --index;
1757 }
1758
1759 /* save the end of the string */
1760 nameEnd = index;
1761
1762 /* if pathname ends with multiple colons, then this pathname refers */
1763 /* to a directory, not a file */
1764 if ( pathname[index] != ':' )
1765 {
1766 /* parse backwards until we find a colon or hit the beginning of the pathname */
1767 while ( (index != 0) && (pathname[index] != ':') )
1768 {
1769 --index;
1770 }
1771
1772 /* if we parsed to the beginning of the pathname and the pathname ended */
1773 /* with a colon, then pathname is a full pathname to a volume, not a file */
1774 if ( (index != 0) || (pathname[pathname[0]] != ':') )
1775 {
1776 /* get the filename and return noErr */
1777 filename[0] = (char)(nameEnd - index);
1778 BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
1779 error = noErr;
1780 }
1781 else
1782 {
1783 /* pathname to a volume, not a file */
1784 error = notAFileErr;
1785 }
1786 }
1787 else
1788 {
1789 /* directory, not a file */
1790 error = notAFileErr;
1791 }
1792 }
1793 else
1794 {
1795 /* empty string isn't a file */
1796 error = notAFileErr;
1797 }
1798 }
1799 else
1800 {
1801 /* NULL pathname isn't a file */
1802 error = notAFileErr;
1803 }
1804
1805 return ( error );
1806 }
1807
1808 /*****************************************************************************/
1809
1810 pascal OSErr GetObjectLocation(short vRefNum,
1811 long dirID,
1812 ConstStr255Param pathname,
1813 short *realVRefNum,
1814 long *realParID,
1815 Str255 realName,
1816 Boolean *isDirectory)
1817 {
1818 OSErr error;
1819 CInfoPBRec pb;
1820 Str255 tempPathname;
1821
1822 /* clear results */
1823 *realVRefNum = 0;
1824 *realParID = 0;
1825 realName[0] = 0;
1826
1827 /*
1828 ** Get the real vRefNum
1829 */
1830 error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
1831 if ( error == noErr )
1832 {
1833 /*
1834 ** Determine if the object already exists and if so,
1835 ** get the real parent directory ID if it's a file
1836 */
1837
1838 /* Protection against File Sharing problem */
1839 if ( (pathname == NULL) || (pathname[0] == 0) )
1840 {
1841 tempPathname[0] = 0;
1842 pb.hFileInfo.ioNamePtr = tempPathname;
1843 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
1844 }
1845 else
1846 {
1847 pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
1848 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1849 }
1850 pb.hFileInfo.ioVRefNum = vRefNum;
1851 pb.hFileInfo.ioDirID = dirID;
1852 error = PBGetCatInfoSync(&pb);
1853 if ( error == noErr )
1854 {
1855 /*
1856 ** The file system object is present and we have the file's real parID
1857 */
1858
1859 /* Is it a directory or a file? */
1860 *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
1861 if ( *isDirectory )
1862 {
1863 /*
1864 ** It's a directory, get its name and parent dirID, and then we're done
1865 */
1866
1867 pb.dirInfo.ioNamePtr = realName;
1868 pb.dirInfo.ioVRefNum = *realVRefNum;
1869 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
1870 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
1871 error = PBGetCatInfoSync(&pb);
1872
1873 /* get the parent ID here, because the file system can return the */
1874 /* wrong parent ID from the last call. */
1875 *realParID = pb.dirInfo.ioDrParID;
1876 }
1877 else
1878 {
1879 /*
1880 ** It's a file - use the parent directory ID from the last call
1881 ** to GetCatInfoparse, get the file name, and then we're done
1882 */
1883 *realParID = pb.hFileInfo.ioFlParID;
1884 error = GetFilenameFromPathname(pathname, realName);
1885 }
1886 }
1887 else if ( error == fnfErr )
1888 {
1889 /*
1890 ** The file system object is not present - see if its parent is present
1891 */
1892
1893 /*
1894 ** Parse to get the object name from end of pathname
1895 */
1896 error = GetFilenameFromPathname(pathname, realName);
1897
1898 /* if we can't get the object name from the end, we can't continue */
1899 if ( error == noErr )
1900 {
1901 /*
1902 ** What we want now is the pathname minus the object name
1903 ** for example:
1904 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
1905 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
1906 ** if pathname is ':dir:file' tempPathname becomes ':dir:'
1907 ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
1908 ** if pathname is ':file' tempPathname becomes ':'
1909 ** if pathname is 'file or file:' tempPathname becomes ''
1910 */
1911
1912 /* get a copy of the pathname */
1913 BlockMoveData(pathname, tempPathname, pathname[0] + 1);
1914
1915 /* remove the object name */
1916 tempPathname[0] -= realName[0];
1917 /* and the trailing colon (if any) */
1918 if ( pathname[pathname[0]] == ':' )
1919 {
1920 --tempPathname[0];
1921 }
1922
1923 /* OK, now get the parent's directory ID */
1924
1925 /* Protection against File Sharing problem */
1926 pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
1927 if ( tempPathname[0] != 0 )
1928 {
1929 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1930 }
1931 else
1932 {
1933 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
1934 }
1935 pb.hFileInfo.ioVRefNum = vRefNum;
1936 pb.hFileInfo.ioDirID = dirID;
1937 error = PBGetCatInfoSync(&pb);
1938 *realParID = pb.dirInfo.ioDrDirID;
1939
1940 *isDirectory = false; /* we don't know what the object is really going to be */
1941 }
1942
1943 if ( error != noErr )
1944 {
1945 error = dirNFErr; /* couldn't find parent directory */
1946 }
1947 else
1948 {
1949 error = fnfErr; /* we found the parent, but not the file */
1950 }
1951 }
1952 }
1953
1954 return ( error );
1955 }
1956
1957 /*****************************************************************************/
1958
1959 pascal OSErr GetDirItems(short vRefNum,
1960 long dirID,
1961 ConstStr255Param name,
1962 Boolean getFiles,
1963 Boolean getDirectories,
1964 FSSpecPtr items,
1965 short reqItemCount,
1966 short *actItemCount,
1967 short *itemIndex) /* start with 1, then use what's returned */
1968 {
1969 CInfoPBRec pb;
1970 OSErr error;
1971 long theDirID;
1972 Boolean isDirectory;
1973 FSSpec *endItemsArray;
1974
1975 if ( *itemIndex > 0 )
1976 {
1977 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
1978 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
1979 /* routine would be much faster because of the overhead of DetermineVRefNum and */
1980 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
1981 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
1982 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
1983 /* to this routine. */
1984
1985 /* get the real volume reference number */
1986 error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum);
1987 if ( error == noErr )
1988 {
1989 /* and the real directory ID of this directory (and make sure it IS a directory) */
1990 error = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
1991 if ( error == noErr )
1992 {
1993 if ( isDirectory )
1994 {
1995 *actItemCount = 0;
1996 endItemsArray = items + reqItemCount;
1997 while ( (items < endItemsArray) && (error == noErr) )
1998 {
1999 pb.hFileInfo.ioNamePtr = (StringPtr) &items->name;
2000 pb.hFileInfo.ioDirID = theDirID;
2001 pb.hFileInfo.ioFDirIndex = *itemIndex;
2002 error = PBGetCatInfoSync(&pb);
2003 if ( error == noErr )
2004 {
2005 items->parID = pb.hFileInfo.ioFlParID; /* return item's parID */
2006 items->vRefNum = pb.hFileInfo.ioVRefNum; /* return item's vRefNum */
2007 ++*itemIndex; /* prepare to get next item in directory */
2008
2009 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
2010 {
2011 if ( getDirectories )
2012 {
2013 ++*actItemCount; /* keep this item */
2014 ++items; /* point to next item */
2015 }
2016 }
2017 else
2018 {
2019 if ( getFiles )
2020 {
2021 ++*actItemCount; /* keep this item */
2022 ++items; /* point to next item */
2023 }
2024 }
2025 }
2026 }
2027 }
2028 else
2029 {
2030 /* it wasn't a directory */
2031 error = dirNFErr;
2032 }
2033 }
2034 }
2035 }
2036 else
2037 {
2038 /* bad itemIndex */
2039 error = paramErr;
2040 }
2041
2042 return ( error );
2043 }
2044
2045 /*****************************************************************************/
2046
2047 static void DeleteLevel(long dirToDelete,
2048 DeleteEnumGlobalsPtr theGlobals)
2049 {
2050 long savedDir;
2051
2052 do
2053 {
2054 /* prepare to delete directory */
2055 theGlobals->myPB.ciPB.dirInfo.ioNamePtr = (StringPtr)&theGlobals->itemName;
2056 theGlobals->myPB.ciPB.dirInfo.ioFDirIndex = 1; /* get first item */
2057 theGlobals->myPB.ciPB.dirInfo.ioDrDirID = dirToDelete; /* in this directory */
2058 theGlobals->error = PBGetCatInfoSync(&(theGlobals->myPB.ciPB));
2059 if ( theGlobals->error == noErr )
2060 {
2061 savedDir = dirToDelete;
2062 /* We have an item. Is it a file or directory? */
2063 if ( (theGlobals->myPB.ciPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
2064 {
2065 /* it's a directory */
2066 savedDir = theGlobals->myPB.ciPB.dirInfo.ioDrDirID; /* save dirID of directory instead */
2067 DeleteLevel(theGlobals->myPB.ciPB.dirInfo.ioDrDirID, theGlobals); /* Delete its contents */
2068 theGlobals->myPB.ciPB.dirInfo.ioNamePtr = NULL; /* prepare to delete directory */
2069 }
2070 if ( theGlobals->error == noErr )
2071 {
2072 theGlobals->myPB.ciPB.dirInfo.ioDrDirID = savedDir; /* restore dirID */
2073 theGlobals->myPB.hPB.fileParam.ioFVersNum = 0; /* just in case it's used on an MFS volume... */
2074 theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* delete this item */
2075 if ( theGlobals->error == fLckdErr )
2076 {
2077 (void) PBHRstFLockSync(&(theGlobals->myPB.hPB)); /* unlock it */
2078 theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* and try again */
2079 }
2080 }
2081 }
2082 } while ( theGlobals->error == noErr );
2083
2084 if ( theGlobals->error == fnfErr )
2085 {
2086 theGlobals->error = noErr;
2087 }
2088 }
2089
2090 /*****************************************************************************/
2091
2092 pascal OSErr DeleteDirectoryContents(short vRefNum,
2093 long dirID,
2094 ConstStr255Param name)
2095 {
2096 DeleteEnumGlobals theGlobals;
2097 Boolean isDirectory;
2098 OSErr error;
2099
2100 /* Get the real dirID and make sure it is a directory. */
2101 error = GetDirectoryID(vRefNum, dirID, name, &dirID, &isDirectory);
2102 if ( error == noErr )
2103 {
2104 if ( isDirectory )
2105 {
2106 /* Get the real vRefNum */
2107 error = DetermineVRefNum(name, vRefNum, &vRefNum);
2108 if ( error == noErr )
2109 {
2110 /* Set up the globals we need to access from the recursive routine. */
2111 theGlobals.myPB.ciPB.dirInfo.ioVRefNum = vRefNum;
2112
2113 /* Here we go into recursion land... */
2114 DeleteLevel(dirID, &theGlobals);
2115 error = theGlobals.error;
2116 }
2117 }
2118 else
2119 {
2120 error = dirNFErr;
2121 }
2122 }
2123
2124 return ( error );
2125 }
2126
2127 /*****************************************************************************/
2128
2129 pascal OSErr DeleteDirectory(short vRefNum,
2130 long dirID,
2131 ConstStr255Param name)
2132 {
2133 OSErr error;
2134
2135 /* Make sure a directory was specified and then delete its contents */
2136 error = DeleteDirectoryContents(vRefNum, dirID, name);
2137 if ( error == noErr )
2138 {
2139 error = HDelete(vRefNum, dirID, name);
2140 if ( error == fLckdErr )
2141 {
2142 (void) HRstFLock(vRefNum, dirID, name); /* unlock the directory locked by AppleShare */
2143 error = HDelete(vRefNum, dirID, name); /* and try again */
2144 }
2145 }
2146
2147 return ( error );
2148 }
2149
2150 /*****************************************************************************/
2151
2152 pascal OSErr CheckObjectLock(short vRefNum,
2153 long dirID,
2154 ConstStr255Param name)
2155 {
2156 CInfoPBRec pb;
2157 OSErr error;
2158
2159 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
2160 if ( error == noErr )
2161 {
2162 /* check locked bit */
2163 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0 )
2164 {
2165 error = fLckdErr;
2166 }
2167 }
2168
2169 return ( error );
2170 }
2171
2172 /*****************************************************************************/
2173
2174 pascal OSErr FSpCheckObjectLock(const FSSpec *spec)
2175 {
2176 return ( CheckObjectLock(spec->vRefNum, spec->parID, spec->name) );
2177 }
2178
2179 /*****************************************************************************/
2180
2181 pascal OSErr GetFileSize(short vRefNum,
2182 long dirID,
2183 ConstStr255Param fileName,
2184 long *dataSize,
2185 long *rsrcSize)
2186 {
2187 HParamBlockRec pb;
2188 OSErr error;
2189
2190 pb.fileParam.ioNamePtr = (StringPtr)fileName;
2191 pb.fileParam.ioVRefNum = vRefNum;
2192 pb.fileParam.ioFVersNum = 0;
2193 pb.fileParam.ioDirID = dirID;
2194 pb.fileParam.ioFDirIndex = 0;
2195 error = PBHGetFInfoSync(&pb);
2196 if ( error == noErr )
2197 {
2198 *dataSize = pb.fileParam.ioFlLgLen;
2199 *rsrcSize = pb.fileParam.ioFlRLgLen;
2200 }
2201
2202 return ( error );
2203 }
2204
2205 /*****************************************************************************/
2206
2207 pascal OSErr FSpGetFileSize(const FSSpec *spec,
2208 long *dataSize,
2209 long *rsrcSize)
2210 {
2211 return ( GetFileSize(spec->vRefNum, spec->parID, spec->name, dataSize, rsrcSize) );
2212 }
2213
2214 /*****************************************************************************/
2215
2216 pascal OSErr BumpDate(short vRefNum,
2217 long dirID,
2218 ConstStr255Param name)
2219 /* Given a file or directory, change its modification date to the current date/time. */
2220 {
2221 CInfoPBRec pb;
2222 Str31 tempName;
2223 OSErr error;
2224 unsigned long secs;
2225
2226 /* Protection against File Sharing problem */
2227 if ( (name == NULL) || (name[0] == 0) )
2228 {
2229 tempName[0] = 0;
2230 pb.hFileInfo.ioNamePtr = tempName;
2231 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
2232 }
2233 else
2234 {
2235 pb.hFileInfo.ioNamePtr = (StringPtr)name;
2236 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
2237 }
2238 pb.hFileInfo.ioVRefNum = vRefNum;
2239 pb.hFileInfo.ioDirID = dirID;
2240 error = PBGetCatInfoSync(&pb);
2241 if ( error == noErr )
2242 {
2243 GetDateTime(&secs);
2244 /* set mod date to current date, or one second into the future
2245 if mod date = current date */
2246 pb.hFileInfo.ioFlMdDat = (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
2247 if ( pb.dirInfo.ioNamePtr == tempName )
2248 {
2249 pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
2250 }
2251 else
2252 {
2253 pb.hFileInfo.ioDirID = dirID;
2254 }
2255 error = PBSetCatInfoSync(&pb);
2256 }
2257
2258 return ( error );
2259 }
2260
2261 /*****************************************************************************/
2262
2263 pascal OSErr FSpBumpDate(const FSSpec *spec)
2264 {
2265 return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
2266 }
2267
2268 /*****************************************************************************/
2269
2270 pascal OSErr ChangeCreatorType(short vRefNum,
2271 long dirID,
2272 ConstStr255Param name,
2273 OSType creator,
2274 OSType fileType)
2275 {
2276 CInfoPBRec pb;
2277 OSErr error;
2278 short realVRefNum;
2279 long parID;
2280
2281 pb.hFileInfo.ioNamePtr = (StringPtr)name;
2282 pb.hFileInfo.ioVRefNum = vRefNum;
2283 pb.hFileInfo.ioDirID = dirID;
2284 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
2285 error = PBGetCatInfoSync(&pb);
2286 if ( error == noErr )
2287 {
2288 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 ) /* if file */
2289 {
2290 parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
2291
2292 /* If creator not 0x00000000, change creator */
2293 if ( creator != (OSType)0x00000000 )
2294 {
2295 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
2296 }
2297
2298 /* If fileType not 0x00000000, change fileType */
2299 if ( fileType != (OSType)0x00000000 )
2300 {
2301 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
2302 }
2303
2304 pb.hFileInfo.ioDirID = dirID;
2305 error = PBSetCatInfoSync(&pb); /* now, save the new information back to disk */
2306
2307 if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
2308 {
2309 /* get the real vRefNum in case a full pathname was passed */
2310 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
2311 if ( error == noErr )
2312 {
2313 error = BumpDate(realVRefNum, parID, NULL);
2314 /* and bump the parent directory's mod date to wake up the Finder */
2315 /* to the change we just made */
2316 }
2317 }
2318 }
2319 else
2320 {
2321 /* it was a directory, not a file */
2322 error = notAFileErr;
2323 }
2324 }
2325
2326 return ( error );
2327 }
2328
2329 /*****************************************************************************/
2330
2331 pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
2332 OSType creator,
2333 OSType fileType)
2334 {
2335 return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name, creator, fileType) );
2336 }
2337
2338 /*****************************************************************************/
2339
2340 pascal OSErr ChangeFDFlags(short vRefNum,
2341 long dirID,
2342 ConstStr255Param name,
2343 Boolean setBits,
2344 unsigned short flagBits)
2345 {
2346 CInfoPBRec pb;
2347 Str31 tempName;
2348 OSErr error;
2349 short realVRefNum;
2350 long parID;
2351
2352 /* Protection against File Sharing problem */
2353 if ( (name == NULL) || (name[0] == 0) )
2354 {
2355 tempName[0] = 0;
2356 pb.hFileInfo.ioNamePtr = tempName;
2357 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
2358 }
2359 else
2360 {
2361 pb.hFileInfo.ioNamePtr = (StringPtr)name;
2362 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
2363 }
2364 pb.hFileInfo.ioVRefNum = vRefNum;
2365 pb.hFileInfo.ioDirID = dirID;
2366 error = PBGetCatInfoSync(&pb);
2367 if ( error == noErr )
2368 {
2369 parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
2370
2371 /* set or clear the appropriate bits in the Finder flags */
2372 if ( setBits )
2373 {
2374 /* OR in the bits */
2375 pb.hFileInfo.ioFlFndrInfo.fdFlags |= flagBits;
2376 }
2377 else
2378 {
2379 /* AND out the bits */
2380 pb.hFileInfo.ioFlFndrInfo.fdFlags &= ~flagBits;
2381 }
2382
2383 if ( pb.dirInfo.ioNamePtr == tempName )
2384 {
2385 pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
2386 }
2387 else
2388 {
2389 pb.hFileInfo.ioDirID = dirID;
2390 }
2391
2392 error = PBSetCatInfoSync(&pb); /* now, save the new information back to disk */
2393
2394 if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
2395 {
2396 /* get the real vRefNum in case a full pathname was passed */
2397 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
2398 if ( error == noErr )
2399 {
2400 error = BumpDate(realVRefNum, parID, NULL);
2401 /* and bump the parent directory's mod date to wake up the Finder */
2402 /* to the change we just made */
2403 }
2404 }
2405 }
2406
2407 return ( error );
2408 }
2409
2410 /*****************************************************************************/
2411
2412 pascal OSErr FSpChangeFDFlags(const FSSpec *spec,
2413 Boolean setBits,
2414 unsigned short flagBits)
2415 {
2416 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, setBits, flagBits) );
2417 }
2418
2419 /*****************************************************************************/
2420
2421 pascal OSErr SetIsInvisible(short vRefNum,
2422 long dirID,
2423 ConstStr255Param name)
2424 /* Given a file or directory, make it invisible. */
2425 {
2426 return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsInvisible) );
2427 }
2428
2429 /*****************************************************************************/
2430
2431 pascal OSErr FSpSetIsInvisible(const FSSpec *spec)
2432 /* Given a file or directory, make it invisible. */
2433 {
2434 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsInvisible) );
2435 }
2436
2437 /*****************************************************************************/
2438
2439 pascal OSErr ClearIsInvisible(short vRefNum,
2440 long dirID,
2441 ConstStr255Param name)
2442 /* Given a file or directory, make it visible. */
2443 {
2444 return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsInvisible) );
2445 }
2446
2447 /*****************************************************************************/
2448
2449 pascal OSErr FSpClearIsInvisible(const FSSpec *spec)
2450 /* Given a file or directory, make it visible. */
2451 {
2452 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsInvisible) );
2453 }
2454
2455 /*****************************************************************************/
2456
2457 pascal OSErr SetNameLocked(short vRefNum,
2458 long dirID,
2459 ConstStr255Param name)
2460 /* Given a file or directory, lock its name. */
2461 {
2462 return ( ChangeFDFlags(vRefNum, dirID, name, true, kNameLocked) );
2463 }
2464
2465 /*****************************************************************************/
2466
2467 pascal OSErr FSpSetNameLocked(const FSSpec *spec)
2468 /* Given a file or directory, lock its name. */
2469 {
2470 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kNameLocked) );
2471 }
2472
2473 /*****************************************************************************/
2474
2475 pascal OSErr ClearNameLocked(short vRefNum,
2476 long dirID,
2477 ConstStr255Param name)
2478 /* Given a file or directory, unlock its name. */
2479 {
2480 return ( ChangeFDFlags(vRefNum, dirID, name, false, kNameLocked) );
2481 }
2482
2483 /*****************************************************************************/
2484
2485 pascal OSErr FSpClearNameLocked(const FSSpec *spec)
2486 /* Given a file or directory, unlock its name. */
2487 {
2488 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kNameLocked) );
2489 }
2490
2491 /*****************************************************************************/
2492
2493 pascal OSErr SetIsStationery(short vRefNum,
2494 long dirID,
2495 ConstStr255Param name)
2496 /* Given a file, make it a stationery pad. */
2497 {
2498 return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsStationery) );
2499 }
2500
2501 /*****************************************************************************/
2502
2503 pascal OSErr FSpSetIsStationery(const FSSpec *spec)
2504 /* Given a file, make it a stationery pad. */
2505 {
2506 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsStationery) );
2507 }
2508
2509 /*****************************************************************************/
2510
2511 pascal OSErr ClearIsStationery(short vRefNum,
2512 long dirID,
2513 ConstStr255Param name)
2514 /* Given a file, clear the stationery bit. */
2515 {
2516 return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsStationery) );
2517 }
2518
2519 /*****************************************************************************/
2520
2521 pascal OSErr FSpClearIsStationery(const FSSpec *spec)
2522 /* Given a file, clear the stationery bit. */
2523 {
2524 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsStationery) );
2525 }
2526
2527 /*****************************************************************************/
2528
2529 pascal OSErr SetHasCustomIcon(short vRefNum,
2530 long dirID,
2531 ConstStr255Param name)
2532 /* Given a file or directory, indicate that it has a custom icon. */
2533 {
2534 return ( ChangeFDFlags(vRefNum, dirID, name, true, kHasCustomIcon) );
2535 }
2536
2537 /*****************************************************************************/
2538
2539 pascal OSErr FSpSetHasCustomIcon(const FSSpec *spec)
2540 /* Given a file or directory, indicate that it has a custom icon. */
2541 {
2542 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kHasCustomIcon) );
2543 }
2544
2545 /*****************************************************************************/
2546
2547 pascal OSErr ClearHasCustomIcon(short vRefNum,
2548 long dirID,
2549 ConstStr255Param name)
2550 /* Given a file or directory, indicate that it does not have a custom icon. */
2551 {
2552 return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasCustomIcon) );
2553 }
2554
2555 /*****************************************************************************/
2556
2557 pascal OSErr FSpClearHasCustomIcon(const FSSpec *spec)
2558 /* Given a file or directory, indicate that it does not have a custom icon. */
2559 {
2560 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasCustomIcon) );
2561 }
2562
2563 /*****************************************************************************/
2564
2565 pascal OSErr ClearHasBeenInited(short vRefNum,
2566 long dirID,
2567 ConstStr255Param name)
2568 /* Given a file, clear its "has been inited" bit. */
2569 {
2570 return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasBeenInited) );
2571 }
2572
2573 /*****************************************************************************/
2574
2575 pascal OSErr FSpClearHasBeenInited(const FSSpec *spec)
2576 /* Given a file, clear its "has been inited" bit. */
2577 {
2578 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasBeenInited) );
2579 }
2580
2581 /*****************************************************************************/
2582
2583 pascal OSErr CopyFileMgrAttributes(short srcVRefNum,
2584 long srcDirID,
2585 ConstStr255Param srcName,
2586 short dstVRefNum,
2587 long dstDirID,
2588 ConstStr255Param dstName,
2589 Boolean copyLockBit)
2590 {
2591 UniversalFMPB pb;
2592 Str31 tempName;
2593 OSErr error;
2594 Boolean objectIsDirectory;
2595
2596 pb.ciPB.hFileInfo.ioVRefNum = srcVRefNum;
2597 pb.ciPB.hFileInfo.ioDirID = srcDirID;
2598
2599 /* Protection against File Sharing problem */
2600 if ( (srcName == NULL) || (srcName[0] == 0) )
2601 {
2602 tempName[0] = 0;
2603 pb.ciPB.hFileInfo.ioNamePtr = tempName;
2604 pb.ciPB.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
2605 }
2606 else
2607 {
2608 pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)srcName;
2609 pb.ciPB.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
2610 }
2611 error = PBGetCatInfoSync(&pb.ciPB);
2612 if ( error == noErr )
2613 {
2614 objectIsDirectory = ( (pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 );
2615 pb.ciPB.hFileInfo.ioVRefNum = dstVRefNum;
2616 pb.ciPB.hFileInfo.ioDirID = dstDirID;
2617 if ( (dstName != NULL) && (dstName[0] == 0) )
2618 {
2619 pb.ciPB.hFileInfo.ioNamePtr = NULL;
2620 }
2621 else
2622 {
2623 pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)dstName;
2624 }
2625 /* don't copy the hasBeenInited bit */
2626 pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags = ( pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags & ~kHasBeenInited );
2627 error = PBSetCatInfoSync(&pb.ciPB);
2628 if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0) )
2629 {
2630 pb.hPB.fileParam.ioFVersNum = 0;
2631 error = PBHSetFLockSync(&pb.hPB);
2632 if ( (error != noErr) && (objectIsDirectory) )
2633 {
2634 error = noErr; /* ignore lock errors if destination is directory */
2635 }
2636 }
2637 }
2638 return ( error );
2639 }
2640
2641 /*****************************************************************************/
2642
2643 pascal OSErr FSpCopyFileMgrAttributes(const FSSpec *srcSpec,
2644 const FSSpec *dstSpec,
2645 Boolean copyLockBit)
2646 {
2647 return ( CopyFileMgrAttributes(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
2648 dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
2649 copyLockBit) );
2650 }
2651
2652 /*****************************************************************************/
2653
2654 pascal OSErr HOpenAware(short vRefNum,
2655 long dirID,
2656 ConstStr255Param fileName,
2657 short denyModes,
2658 short *refNum)
2659 {
2660 HParamBlockRec pb;
2661 OSErr error;
2662 GetVolParmsInfoBuffer volParmsInfo;
2663 long infoSize = sizeof(GetVolParmsInfoBuffer);
2664
2665 pb.ioParam.ioMisc = NULL;
2666 pb.fileParam.ioFVersNum = 0;
2667 pb.fileParam.ioNamePtr = (StringPtr)fileName;
2668 pb.fileParam.ioVRefNum = vRefNum;
2669 pb.fileParam.ioDirID = dirID;
2670
2671 /* get volume attributes */
2672 /* this preflighting is needed because Foreign File Access based file systems don't */
2673 /* return the correct error result to the OpenDeny call */
2674 error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
2675 if ( (error == noErr) && hasOpenDeny(&volParmsInfo) )
2676 {
2677 /* if volume supports OpenDeny, use it and return */
2678 pb.accessParam.ioDenyModes = denyModes;
2679 error = PBHOpenDenySync(&pb);
2680 *refNum = pb.ioParam.ioRefNum;
2681 }
2682 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2683 {
2684 /* OpenDeny isn't supported, so try File Manager Open functions */
2685
2686 /* If request includes write permission, then see if the volume is */
2687 /* locked by hardware or software. The HFS file system doesn't check */
2688 /* for this when a file is opened - you only find out later when you */
2689 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2690
2691 if ( (denyModes & dmWr) != 0 )
2692 {
2693 error = CheckVolLock(fileName, vRefNum);
2694 }
2695 else
2696 {
2697 error = noErr;
2698 }
2699
2700 if ( error == noErr )
2701 {
2702 /* Set File Manager permissions to closest thing possible */
2703 if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
2704 {
2705 pb.ioParam.ioPermssn = fsRdWrShPerm;
2706 }
2707 else
2708 {
2709 pb.ioParam.ioPermssn = denyModes % 4;
2710 }
2711
2712 error = PBHOpenDFSync(&pb); /* Try OpenDF */
2713 if ( error == paramErr )
2714 {
2715 error = PBHOpenSync(&pb); /* OpenDF not supported, so try Open */
2716 }
2717 *refNum = pb.ioParam.ioRefNum;
2718 }
2719 }
2720
2721 return ( error );
2722 }
2723
2724 /*****************************************************************************/
2725
2726 pascal OSErr FSpOpenAware(const FSSpec *spec,
2727 short denyModes,
2728 short *refNum)
2729 {
2730 return ( HOpenAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
2731 }
2732
2733 /*****************************************************************************/
2734
2735 pascal OSErr HOpenRFAware(short vRefNum,
2736 long dirID,
2737 ConstStr255Param fileName,
2738 short denyModes,
2739 short *refNum)
2740 {
2741 HParamBlockRec pb;
2742 OSErr error;
2743 GetVolParmsInfoBuffer volParmsInfo;
2744 long infoSize = sizeof(GetVolParmsInfoBuffer);
2745
2746 pb.ioParam.ioMisc = NULL;
2747 pb.fileParam.ioFVersNum = 0;
2748 pb.fileParam.ioNamePtr = (StringPtr)fileName;
2749 pb.fileParam.ioVRefNum = vRefNum;
2750 pb.fileParam.ioDirID = dirID;
2751
2752 /* get volume attributes */
2753 /* this preflighting is needed because Foreign File Access based file systems don't */
2754 /* return the correct error result to the OpenRFDeny call */
2755 error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
2756 if ( (error == noErr) && hasOpenDeny(&volParmsInfo) )
2757 {
2758 /* if volume supports OpenRFDeny, use it and return */
2759 if ( hasOpenDeny(&volParmsInfo) )
2760 {
2761 pb.accessParam.ioDenyModes = denyModes;
2762 error = PBHOpenRFDenySync(&pb);
2763 *refNum = pb.ioParam.ioRefNum;
2764 }
2765 }
2766 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
2767 {
2768 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
2769
2770 /* If request includes write permission, then see if the volume is */
2771 /* locked by hardware or software. The HFS file system doesn't check */
2772 /* for this when a file is opened - you only find out later when you */
2773 /* try to write and the write fails with a wPrErr or a vLckdErr. */
2774
2775 if ( (denyModes & dmWr) != 0 )
2776 {
2777 error = CheckVolLock(fileName, vRefNum);
2778 }
2779 else
2780 {
2781 error = noErr;
2782 }
2783
2784 if ( error == noErr )
2785 {
2786 /* Set File Manager permissions to closest thing possible */
2787 if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
2788 {
2789 pb.ioParam.ioPermssn = fsRdWrShPerm;
2790 }
2791 else
2792 {
2793 pb.ioParam.ioPermssn = denyModes % 4;
2794 }
2795
2796 error = PBHOpenRFSync(&pb);
2797 *refNum = pb.ioParam.ioRefNum;
2798 }
2799 }
2800
2801 return ( error );
2802 }
2803
2804 /*****************************************************************************/
2805
2806 pascal OSErr FSpOpenRFAware(const FSSpec *spec,
2807 short denyModes,
2808 short *refNum)
2809 {
2810 return ( HOpenRFAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
2811 }
2812
2813 /*****************************************************************************/
2814
2815 pascal OSErr FSReadNoCache(short refNum,
2816 long *count,
2817 void *buffPtr)
2818 {
2819 ParamBlockRec pb;
2820 OSErr error;
2821
2822 pb.ioParam.ioRefNum = refNum;
2823 pb.ioParam.ioBuffer = (Ptr)buffPtr;
2824 pb.ioParam.ioReqCount = *count;
2825 pb.ioParam.ioPosMode = fsAtMark + noCacheMask; /* fsAtMark + noCacheMask */
2826 pb.ioParam.ioPosOffset = 0;
2827 error = PBReadSync(&pb);
2828 *count = pb.ioParam.ioActCount; /* always return count */
2829 return ( error );
2830 }
2831
2832 /*****************************************************************************/
2833
2834 pascal OSErr FSWriteNoCache(short refNum,
2835 long *count,
2836 const void *buffPtr)
2837 {
2838 ParamBlockRec pb;
2839 OSErr error;
2840
2841 pb.ioParam.ioRefNum = refNum;
2842 pb.ioParam.ioBuffer = (Ptr)buffPtr;
2843 pb.ioParam.ioReqCount = *count;
2844 pb.ioParam.ioPosMode = fsAtMark + noCacheMask; /* fsAtMark + noCacheMask */
2845 pb.ioParam.ioPosOffset = 0;
2846 error = PBWriteSync(&pb);
2847 *count = pb.ioParam.ioActCount; /* always return count */
2848 return ( error );
2849 }
2850
2851 /*****************************************************************************/
2852
2853 /*
2854 ** See if numBytes bytes of buffer1 are equal to buffer2.
2855 */
2856 static Boolean EqualMemory(const void *buffer1, const void *buffer2, unsigned long numBytes)
2857 {
2858 register unsigned char *b1 = (unsigned char *)buffer1;
2859 register unsigned char *b2 = (unsigned char *)buffer2;
2860
2861 if ( b1 != b2 ) /* if buffer pointers are same, then they are equal */
2862 {
2863 while ( numBytes > 0 )
2864 {
2865 /* compare the bytes and then increment the pointers */
2866 if ( (*b1++ - *b2++) != 0 )
2867 {
2868 return ( false );
2869 }
2870 --numBytes;
2871 }
2872 }
2873
2874 return ( true );
2875 }
2876
2877 /*****************************************************************************/
2878
2879 /*
2880 ** Read any number of bytes from an open file using read-verify mode.
2881 ** The FSReadVerify function reads any number of bytes from an open file
2882 ** and verifies them against the data in the buffer pointed to by buffPtr.
2883 **
2884 ** Because of a bug in the HFS file system, only non-block aligned parts of
2885 ** the read are verified against the buffer data and the rest is *copied*
2886 ** into the buffer. Thus, you shouldn't verify against your original data;
2887 ** instead, you should verify against a copy of the original data and then
2888 ** compare the read-verified copy against the original data after calling
2889 ** FSReadVerify. That's why this function isn't exported - it needs the
2890 ** wrapper provided by FSWriteVerify.
2891 */
2892 static OSErr FSReadVerify(short refNum,
2893 long *count,
2894 void *buffPtr)
2895 {
2896 ParamBlockRec pb;
2897 OSErr result;
2898
2899 pb.ioParam.ioRefNum = refNum;
2900 pb.ioParam.ioBuffer = (Ptr)buffPtr;
2901 pb.ioParam.ioReqCount = *count;
2902 pb.ioParam.ioPosMode = fsAtMark + rdVerify;
2903 pb.ioParam.ioPosOffset = 0;
2904 result = PBReadSync(&pb);
2905 *count = pb.ioParam.ioActCount; /* always return count */
2906 return ( result );
2907 }
2908
2909 /*****************************************************************************/
2910
2911 pascal OSErr FSWriteVerify(short refNum,
2912 long *count,
2913 const void *buffPtr)
2914 {
2915 Ptr verifyBuffer;
2916 long position;
2917 long bufferSize;
2918 long byteCount;
2919 long bytesVerified;
2920 Ptr startVerify;
2921 OSErr result;
2922
2923 /*
2924 ** Allocate the verify buffer
2925 ** Try to get get a large enough buffer to verify in one pass.
2926 ** If that fails, use GetTempBuffer to get a buffer.
2927 */
2928 bufferSize = *count;
2929 verifyBuffer = NewPtr(bufferSize);
2930 if ( verifyBuffer == NULL )
2931 {
2932 verifyBuffer = GetTempBuffer(bufferSize, &bufferSize);
2933 }
2934 if ( verifyBuffer != NULL )
2935 {
2936 /* Save the current position */
2937 result = GetFPos(refNum, &position);
2938 if ( result == noErr )
2939 {
2940 /* Write the data */
2941 result = FSWrite(refNum, count, buffPtr);
2942 if ( result == noErr )
2943 {
2944 /* Restore the original position */
2945 result = SetFPos(refNum, fsFromStart, position);
2946 if ( result == noErr )
2947 {
2948 /*
2949 ** *count = total number of bytes to verify
2950 ** bufferSize = the size of the verify buffer
2951 ** bytesVerified = number of bytes verified
2952 ** byteCount = number of bytes to verify this pass
2953 ** startVerify = position in buffPtr
2954 */
2955 bytesVerified = 0;
2956 startVerify = (Ptr)buffPtr;
2957 while ( (bytesVerified < *count) && ( result == noErr ) )
2958 {
2959 if ( (*count - bytesVerified) > bufferSize )
2960 {
2961 byteCount = bufferSize;
2962 }
2963 else
2964 {
2965 byteCount = *count - bytesVerified;
2966 }
2967 /*
2968 ** Copy the write buffer into the verify buffer.
2969 ** This step is needed because the File Manager
2970 ** compares the data in any non-block aligned
2971 ** data at the beginning and end of the read-verify
2972 ** request back into the file system's cache
2973 ** to the data in verify Buffer. However, the
2974 ** File Manager does not compare any full blocks
2975 ** and instead copies them into the verify buffer
2976 ** so we still have to compare the buffers again
2977 ** after the read-verify request completes.
2978 */
2979 BlockMoveData(startVerify, verifyBuffer, byteCount);
2980
2981 /* Read-verify the data back into the verify buffer */
2982 result = FSReadVerify(refNum, &byteCount, verifyBuffer);
2983 if ( result == noErr )
2984 {
2985 /* See if the buffers are the same */
2986 if ( !EqualMemory(verifyBuffer, startVerify, byteCount) )
2987 {
2988 result = ioErr;
2989 }
2990 startVerify += byteCount;
2991 bytesVerified += byteCount;
2992 }
2993 }
2994 }
2995 }
2996 }
2997 DisposePtr(verifyBuffer);
2998 }
2999 else
3000 {
3001 result = memFullErr;
3002 }
3003 return ( result );
3004 }
3005
3006 /*****************************************************************************/
3007
3008 pascal OSErr CopyFork(short srcRefNum,
3009 short dstRefNum,
3010 void *copyBufferPtr,
3011 long copyBufferSize)
3012 {
3013 ParamBlockRec srcPB;
3014 ParamBlockRec dstPB;
3015 OSErr srcError;
3016 OSErr dstError;
3017
3018 if ( (copyBufferPtr == NULL) || (copyBufferSize == 0) )
3019 return ( paramErr );
3020
3021 srcPB.ioParam.ioRefNum = srcRefNum;
3022 dstPB.ioParam.ioRefNum = dstRefNum;
3023
3024 /* preallocate the destination fork and */
3025 /* ensure the destination fork's EOF is correct after the copy */
3026 srcError = PBGetEOFSync(&srcPB);
3027 if ( srcError != noErr )
3028 return ( srcError );
3029 dstPB.ioParam.ioMisc = srcPB.ioParam.ioMisc;
3030 dstError = PBSetEOFSync(&dstPB);
3031 if ( dstError != noErr )
3032 return ( dstError );
3033
3034 /* reset source fork's mark */
3035 srcPB.ioParam.ioPosMode = fsFromStart;
3036 srcPB.ioParam.ioPosOffset = 0;
3037 srcError = PBSetFPosSync(&srcPB);
3038 if ( srcError != noErr )
3039 return ( srcError );
3040
3041 /* reset destination fork's mark */
3042 dstPB.ioParam.ioPosMode = fsFromStart;
3043 dstPB.ioParam.ioPosOffset = 0;
3044 dstError = PBSetFPosSync(&dstPB);
3045 if ( dstError != noErr )
3046 return ( dstError );
3047
3048 /* set up fields that won't change in the loop */
3049 srcPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
3050 srcPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */
3051 /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
3052 /* This will make writes on local volumes faster */
3053 if ( (copyBufferSize >= 512) && ((copyBufferSize & 0x1ff) != 0) )
3054 {
3055 srcPB.ioParam.ioReqCount = copyBufferSize & 0xfffffe00;
3056 }
3057 else
3058 {
3059 srcPB.ioParam.ioReqCount = copyBufferSize;
3060 }
3061 dstPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
3062 dstPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */
3063
3064 while ( (srcError == noErr) && (dstError == noErr) )
3065 {
3066 srcError = PBReadSync(&srcPB);
3067 dstPB.ioParam.ioReqCount = srcPB.ioParam.ioActCount;
3068 dstError = PBWriteSync(&dstPB);
3069 }
3070
3071 /* make sure there were no errors at the destination */
3072 if ( dstError != noErr )
3073 return ( dstError );
3074
3075 /* make sure the only error at the source was eofErr */
3076 if ( srcError != eofErr )
3077 return ( srcError );
3078
3079 return ( noErr );
3080 }
3081
3082 /*****************************************************************************/
3083
3084 pascal OSErr GetFileLocation(short refNum,
3085 short *vRefNum,
3086 long *dirID,
3087 StringPtr fileName)
3088 {
3089 FCBPBRec pb;
3090 OSErr error;
3091
3092 pb.ioNamePtr = fileName;
3093 pb.ioVRefNum = 0;
3094 pb.ioRefNum = refNum;
3095 pb.ioFCBIndx = 0;
3096 error = PBGetFCBInfoSync(&pb);
3097 if ( error == noErr )
3098 {
3099 *vRefNum = pb.ioFCBVRefNum;
3100 *dirID = pb.ioFCBParID;
3101 }
3102 return ( error );
3103 }
3104
3105 /*****************************************************************************/
3106
3107 pascal OSErr FSpGetFileLocation(short refNum,
3108 FSSpec *spec)
3109 {
3110 return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) );
3111 }
3112
3113 /*****************************************************************************/
3114
3115 pascal OSErr CopyDirectoryAccess(short srcVRefNum,
3116 long srcDirID,
3117 ConstStr255Param srcName,
3118 short dstVRefNum,
3119 long dstDirID,
3120 ConstStr255Param dstName)
3121 {
3122 OSErr error;
3123 GetVolParmsInfoBuffer infoBuffer; /* Where PBGetVolParms dumps its info */
3124 long dstServerAdr; /* AppleTalk server address of destination (if any) */
3125 long ownerID, groupID, accessRights;
3126 long tempLong;
3127
3128 /* See if destination supports directory access control */
3129 tempLong = sizeof(infoBuffer);
3130 error = HGetVolParms(dstName, dstVRefNum, &infoBuffer, &tempLong);
3131 if ( (error == noErr) && hasAccessCntl(&infoBuffer) )
3132 {
3133 if ( hasAccessCntl(&infoBuffer) )
3134 {
3135 dstServerAdr = infoBuffer.vMServerAdr;
3136
3137 /* See if source supports directory access control and is on same server */
3138 tempLong = sizeof(infoBuffer);
3139 error = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong);
3140 if ( error == noErr )
3141 {
3142 if ( hasAccessCntl(&infoBuffer) && (dstServerAdr == infoBuffer.vMServerAdr) )
3143 {
3144 /* both volumes support directory access control and they are */
3145 /* on same server, so copy the access information */
3146 error = HGetDirAccess(srcVRefNum, srcDirID, srcName, &ownerID, &groupID, &accessRights);
3147 if ( error == noErr )
3148 {
3149 error = HSetDirAccess(dstVRefNum, dstDirID, dstName, ownerID, groupID, accessRights);
3150 }
3151 }
3152 else
3153 {
3154 /* destination doesn't support directory access control or */
3155 /* they volumes aren't on the same server */
3156 error = paramErr;
3157 }
3158 }
3159 }
3160 else
3161 {
3162 /* destination doesn't support directory access control */
3163 error = paramErr;
3164 }
3165 }
3166
3167 return ( error );
3168 }
3169
3170 /*****************************************************************************/
3171
3172 pascal OSErr FSpCopyDirectoryAccess(const FSSpec *srcSpec,
3173 const FSSpec *dstSpec)
3174 {
3175 return ( CopyDirectoryAccess(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
3176 dstSpec->vRefNum, dstSpec->parID, dstSpec->name) );
3177 }
3178
3179 /*****************************************************************************/
3180
3181 pascal OSErr HMoveRenameCompat(short vRefNum,
3182 long srcDirID,
3183 ConstStr255Param srcName,
3184 long dstDirID,
3185 ConstStr255Param dstpathName,
3186 ConstStr255Param copyName)
3187 {
3188 OSErr error;
3189 GetVolParmsInfoBuffer volParmsInfo;
3190 long infoSize;
3191 short realVRefNum;
3192 long realParID;
3193 Str31 realName;
3194 Boolean isDirectory;
3195 long tempItemsDirID;
3196 long uniqueTempDirID;
3197 Str31 uniqueTempDirName;
3198 unsigned short uniqueNameoverflow;
3199
3200 /* Get volume attributes */
3201 infoSize = sizeof(GetVolParmsInfoBuffer);
3202 error = HGetVolParms((StringPtr)srcName, vRefNum, &volParmsInfo, &infoSize);
3203 if ( (error == noErr) && hasMoveRename(&volParmsInfo) )
3204 {
3205 /* If volume supports move and rename, so use it and return */
3206 error = HMoveRename(vRefNum, srcDirID, srcName, dstDirID, dstpathName, copyName);
3207 }
3208 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
3209 {
3210 /* MoveRename isn't supported by this volume, so do it by hand */
3211
3212 /* If copyName isn't supplied, we can simply CatMove and return */
3213 if ( copyName == NULL )
3214 {
3215 error = CatMove(vRefNum, srcDirID, srcName, dstDirID, dstpathName);
3216 }
3217 else
3218 {
3219 /* Renaming is required, so we have some work to do... */
3220
3221 /* Get the object's real name, real parent ID and real vRefNum */
3222 error = GetObjectLocation(vRefNum, srcDirID, (StringPtr)srcName,
3223 &realVRefNum, &realParID, realName, &isDirectory);
3224 if ( error == noErr )
3225 {
3226 /* Find the Temporary Items Folder on that volume */
3227 error = FindFolder(realVRefNum, kTemporaryFolderType, kCreateFolder,
3228 &realVRefNum, &tempItemsDirID);
3229 if ( error == noErr )
3230 {
3231 /* Create a new uniquely named folder in the temporary items folder. */
3232 /* This is done to avoid the case where 'realName' or 'copyName' already */
3233 /* exists in the temporary items folder. */
3234
3235 /* Start with current tick count as uniqueTempDirName */
3236 NumToString(TickCount(), uniqueTempDirName);
3237 uniqueNameoverflow = 0;
3238 do
3239 {
3240 error = DirCreate(realVRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID);
3241 if ( error == dupFNErr )
3242 {
3243 /* Duplicate name - change the first character to the next ASCII character */
3244 ++uniqueTempDirName[1];
3245 /* Make sure it isn't a colon! */
3246 if ( uniqueTempDirName[1] == ':' )
3247 {
3248 ++uniqueTempDirName[1];
3249 }
3250 /* Don't go too far... */
3251 ++uniqueNameoverflow;
3252 }
3253 } while ( (error == dupFNErr) && (uniqueNameoverflow <= 64) ); /* 64 new files per 1/60th second - not likely! */
3254 if ( error == noErr )
3255 {
3256 /* Move the object to the folder with uniqueTempDirID for renaming */
3257 error = CatMove(realVRefNum, realParID, realName, uniqueTempDirID, NULL);
3258 if ( error == noErr )
3259 {
3260 /* Rename the object */
3261 error = HRename(realVRefNum, uniqueTempDirID, realName, copyName);
3262 if ( error == noErr )
3263 {
3264 /* Move object to its new home */
3265 error = CatMove(realVRefNum, uniqueTempDirID, copyName, dstDirID, dstpathName);
3266 if ( error != noErr )
3267 {
3268 /* Error handling: rename object back to original name - ignore errors */
3269 (void) HRename(realVRefNum, uniqueTempDirID, copyName, realName);
3270 }
3271 }
3272 if ( error != noErr )
3273 {
3274 /* Error handling: move object back to original location - ignore errors */
3275 (void) CatMove(realVRefNum, uniqueTempDirID, realName, realParID, NULL);
3276 }
3277 }
3278 /* Done with ourTempDir, so delete it - ignore errors */
3279 (void) HDelete(realVRefNum, uniqueTempDirID, NULL);
3280 }
3281 }
3282 }
3283 }
3284 }
3285
3286 return ( error );
3287 }
3288
3289 /*****************************************************************************/
3290
3291 pascal OSErr FSpMoveRenameCompat(const FSSpec *srcSpec,
3292 const FSSpec *dstSpec,
3293 ConstStr255Param copyName)
3294 {
3295 /* make sure the FSSpecs refer to the same volume */
3296 if (srcSpec->vRefNum != dstSpec->vRefNum)
3297 return (diffVolErr);
3298 return ( HMoveRenameCompat(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
3299 dstSpec->parID, dstSpec->name, copyName) );
3300 }
3301
3302 /*****************************************************************************/
3303
3304 pascal OSErr BuildAFPVolMountInfo(short flags,
3305 char nbpInterval,
3306 char nbpCount,
3307 short uamType,
3308 Str32 zoneName,
3309 Str32 serverName,
3310 Str27 volName,
3311 Str31 userName,
3312 Str8 userPassword,
3313 Str8 volPassword,
3314 AFPVolMountInfoPtr *afpInfoPtr)
3315 {
3316 MyAFPVolMountInfoPtr infoPtr;
3317 OSErr error;
3318
3319 /* Allocate the AFPXVolMountInfo record */
3320 infoPtr = (MyAFPVolMountInfoPtr)NewPtrClear(sizeof(MyAFPVolMountInfo));
3321 if ( infoPtr != NULL )
3322 {
3323 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
3324 infoPtr->length = sizeof(MyAFPVolMountInfo);
3325 infoPtr->media = AppleShareMediaType;
3326 infoPtr->flags = flags;
3327 infoPtr->nbpInterval = nbpInterval;
3328 infoPtr->nbpCount = nbpCount;
3329 infoPtr->uamType = uamType;
3330
3331 infoPtr->zoneNameOffset = offsetof(MyAFPVolMountInfo, zoneName);
3332 infoPtr->serverNameOffset = offsetof(MyAFPVolMountInfo, serverName);
3333 infoPtr->volNameOffset = offsetof(MyAFPVolMountInfo, volName);
3334 infoPtr->userNameOffset = offsetof(MyAFPVolMountInfo, userName);
3335 infoPtr->userPasswordOffset = offsetof(MyAFPVolMountInfo, userPassword);
3336 infoPtr->volPasswordOffset = offsetof(MyAFPVolMountInfo, volPassword);
3337
3338 BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
3339 BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
3340 BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
3341 BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
3342 BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
3343 BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
3344
3345 *afpInfoPtr = (AFPVolMountInfoPtr)infoPtr;
3346 error = noErr;
3347 }
3348 else
3349 {
3350 error = memFullErr;
3351 }
3352
3353 return ( error );
3354 }
3355
3356 /*****************************************************************************/
3357
3358 pascal OSErr RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr,
3359 short *flags,
3360 short *uamType,
3361 StringPtr zoneName,
3362 StringPtr serverName,
3363 StringPtr volName,
3364 StringPtr userName)
3365 {
3366 StringPtr tempPtr;
3367 OSErr error;
3368
3369 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3370 if ( afpInfoPtr->media == AppleShareMediaType )
3371 {
3372 *flags = afpInfoPtr->flags;
3373 *uamType = afpInfoPtr->uamType;
3374
3375 if ( afpInfoPtr->zoneNameOffset != 0)
3376 {
3377 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->zoneNameOffset);
3378 BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
3379 }
3380
3381 if ( afpInfoPtr->serverNameOffset != 0)
3382 {
3383 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->serverNameOffset);
3384 BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
3385 }
3386
3387 if ( afpInfoPtr->volNameOffset != 0)
3388 {
3389 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->volNameOffset);
3390 BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
3391 }
3392
3393 if ( afpInfoPtr->userNameOffset != 0)
3394 {
3395 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->userNameOffset);
3396 BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
3397 }
3398
3399 error = noErr;
3400 }
3401 else
3402 {
3403 error = paramErr;
3404 }
3405
3406 return ( error );
3407 }
3408
3409 /*****************************************************************************/
3410
3411 pascal OSErr BuildAFPXVolMountInfo(short flags,
3412 char nbpInterval,
3413 char nbpCount,
3414 short uamType,
3415 Str32 zoneName,
3416 Str32 serverName,
3417 Str27 volName,
3418 Str31 userName,
3419 Str8 userPassword,
3420 Str8 volPassword,
3421 Str32 uamName,
3422 unsigned long alternateAddressLength,
3423 void *alternateAddress,
3424 AFPXVolMountInfoPtr *afpXInfoPtr)
3425 {
3426 Size infoSize;
3427 MyAFPXVolMountInfoPtr infoPtr;
3428 OSErr error;
3429
3430 /* Calculate the size of the AFPXVolMountInfo record */
3431 infoSize = sizeof(MyAFPXVolMountInfo) + alternateAddressLength - 1;
3432
3433 /* Allocate the AFPXVolMountInfo record */
3434 infoPtr = (MyAFPXVolMountInfoPtr)NewPtrClear(infoSize);
3435 if ( infoPtr != NULL )
3436 {
3437 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
3438 infoPtr->length = infoSize;
3439 infoPtr->media = AppleShareMediaType;
3440 infoPtr->flags = flags;
3441 if ( alternateAddressLength != 0 )
3442 {
3443 /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
3444 infoPtr->flags |= volMountExtendedFlagsMask;
3445 /* and set the only extendedFlags bit we know about */
3446 infoPtr->extendedFlags = kAFPExtendedFlagsAlternateAddressMask;
3447 }
3448 else
3449 {
3450 /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
3451 infoPtr->flags &= ~volMountExtendedFlagsMask;
3452 /* and clear the extendedFlags */
3453 infoPtr->extendedFlags = 0;
3454 }
3455 infoPtr->nbpInterval = nbpInterval;
3456 infoPtr->nbpCount = nbpCount;
3457 infoPtr->uamType = uamType;
3458
3459 infoPtr->zoneNameOffset = offsetof(MyAFPXVolMountInfo, zoneName);
3460 infoPtr->serverNameOffset = offsetof(MyAFPXVolMountInfo, serverName);
3461 infoPtr->volNameOffset = offsetof(MyAFPXVolMountInfo, volName);
3462 infoPtr->userNameOffset = offsetof(MyAFPXVolMountInfo, userName);
3463 infoPtr->userPasswordOffset = offsetof(MyAFPXVolMountInfo, userPassword);
3464 infoPtr->volPasswordOffset = offsetof(MyAFPXVolMountInfo, volPassword);
3465 infoPtr->uamNameOffset = offsetof(MyAFPXVolMountInfo, uamName);
3466 infoPtr->alternateAddressOffset = offsetof(MyAFPXVolMountInfo, alternateAddress);
3467
3468 BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
3469 BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
3470 BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
3471 BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
3472 BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
3473 BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
3474 BlockMoveData(uamName, infoPtr->uamName, sizeof(Str32));
3475 BlockMoveData(alternateAddress, infoPtr->alternateAddress, alternateAddressLength);
3476
3477 *afpXInfoPtr = (AFPXVolMountInfoPtr)infoPtr;
3478 error = noErr;
3479 }
3480 else
3481 {
3482 error = memFullErr;
3483 }
3484
3485 return ( error );
3486 }
3487
3488 /*****************************************************************************/
3489
3490 pascal OSErr RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr,
3491 short *flags,
3492 short *uamType,
3493 StringPtr zoneName,
3494 StringPtr serverName,
3495 StringPtr volName,
3496 StringPtr userName,
3497 StringPtr uamName,
3498 unsigned long *alternateAddressLength,
3499 AFPAlternateAddress **alternateAddress)
3500 {
3501 StringPtr tempPtr;
3502 Ptr alternateAddressStart;
3503 Ptr alternateAddressEnd;
3504 Size alternateAddressDataSize;
3505 OSErr error;
3506 UInt8 addressCount;
3507
3508 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
3509 if ( afpXInfoPtr->media == AppleShareMediaType )
3510 {
3511 /* default to noErr */
3512 error = noErr;
3513
3514 /* Is this an extended record? */
3515 if ( (afpXInfoPtr->flags & volMountExtendedFlagsMask) != 0 )
3516 {
3517 if ( ((afpXInfoPtr->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) != 0) &&
3518 (afpXInfoPtr->alternateAddressOffset != 0) )
3519 {
3520
3521 alternateAddressStart = (Ptr)((long)afpXInfoPtr + afpXInfoPtr->alternateAddressOffset);
3522 alternateAddressEnd = alternateAddressStart + 1; /* skip over alternate address version byte */
3523 addressCount = *(UInt8*)alternateAddressEnd; /* get the address count */
3524 ++alternateAddressEnd; /* skip over alternate address count byte */
3525 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
3526 while ( addressCount != 0 )
3527 {
3528 /* parse the address list to find the end */
3529 alternateAddressEnd += *(UInt8*)alternateAddressEnd; /* add length of each AFPTagData record */
3530 --addressCount;
3531 }
3532 /* get the size of the alternateAddressData */
3533 alternateAddressDataSize = alternateAddressEnd - alternateAddressStart;
3534 /* allocate memory for it */
3535 *alternateAddress = (AFPAlternateAddress *)NewPtr(alternateAddressDataSize);
3536 if ( *alternateAddress != NULL )
3537 {
3538 /* and return the data */
3539 BlockMoveData(alternateAddressStart, *alternateAddress, alternateAddressDataSize);
3540 *alternateAddressLength = alternateAddressDataSize;
3541 }
3542 else
3543 {
3544 /* no memory - fail now */
3545 error = memFullErr;
3546 }
3547 }
3548
3549 if ( error == noErr ) /* fill in more output parameters if everything is OK */
3550 {
3551 if ( afpXInfoPtr->uamNameOffset != 0 )
3552 {
3553 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->uamNameOffset);
3554 BlockMoveData(tempPtr, uamName, tempPtr[0] + 1);
3555 }
3556 }
3557 }
3558
3559 if ( error == noErr ) /* fill in more output parameters if everything is OK */
3560 {
3561 *flags = afpXInfoPtr->flags;
3562 *uamType = afpXInfoPtr->uamType;
3563
3564 if ( afpXInfoPtr->zoneNameOffset != 0 )
3565 {
3566 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->zoneNameOffset);
3567 BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
3568 }
3569
3570 if ( afpXInfoPtr->serverNameOffset != 0 )
3571 {
3572 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->serverNameOffset);
3573 BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
3574 }
3575
3576 if ( afpXInfoPtr->volNameOffset != 0 )
3577 {
3578 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->volNameOffset);
3579 BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
3580 }
3581
3582 if ( afpXInfoPtr->userNameOffset != 0 )
3583 {
3584 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->userNameOffset);
3585 BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
3586 }
3587 }
3588 }
3589 else
3590 {
3591 error = paramErr;
3592 }
3593
3594 return ( error );
3595 }
3596
3597 /*****************************************************************************/
3598
3599 pascal OSErr GetUGEntries(short objType,
3600 UGEntryPtr entries,
3601 long reqEntryCount,
3602 long *actEntryCount,
3603 long *objID)
3604 {
3605 HParamBlockRec pb;
3606 OSErr error = noErr;
3607 UGEntry *endEntryArray;
3608
3609 pb.objParam.ioObjType = objType;
3610 *actEntryCount = 0;
3611 for ( endEntryArray = entries + reqEntryCount; (entries < endEntryArray) && (error == noErr); ++entries )
3612 {
3613 pb.objParam.ioObjNamePtr = (StringPtr)entries->name;
3614 pb.objParam.ioObjID = *objID;
3615 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
3616 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
3617 /* A CMovePBPtr works OK, but this will be changed in the future back to */
3618 /* HParmBlkPtr, so I'm just casting it here. */
3619 error = PBGetUGEntrySync(&pb);
3620 if ( error == noErr )
3621 {
3622 entries->objID = *objID = pb.objParam.ioObjID;
3623 entries->objType = objType;
3624 ++*actEntryCount;
3625 }
3626 }
3627
3628 return ( error );
3629 }
3630
3631 /*****************************************************************************/
3632