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