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