1 /*
2 These Functions were originally part of More Files version 1.4.8
3
4 More Files fixes many of the broken or underfunctional
5 parts of the file system.
6
7 More Files
8
9 A collection of File Manager and related routines
10
11 by Jim Luther (Apple Macintosh Developer Technical Support Emeritus)
12 with significant code contributions by Nitin Ganatra
13 (Apple Macintosh Developer Technical Support Emeritus)
14 Copyright 1992-1998 Apple Computer, Inc.
15 Portions copyright 1995 Jim Luther
16 All rights reserved.
17
18 The Package "More Files" is distributed under the following
19 license terms:
20
21 "You may incorporate this sample code into your
22 applications without restriction, though the
23 sample code has been provided "AS IS" and the
24 responsibility for its operation is 100% yours.
25 However, what you are not permitted to do is to
26 redistribute the source as "DSC Sample Code" after
27 having made changes. If you're going to
28 redistribute the source, we require that you make
29 it clear in the source that the code was descended
30 from Apple Sample Code, but that you've made
31 changes."
32
33
34 The following changes are made by Info-ZIP:
35
36 - The only changes are made by pasting the functions
37 (mostly found in MoreFilesExtras.c / MoreFiles.c)
38 directly into macstuff.c / macstuff.h and slightly
39 reformatting the text (replacement of TABs by spaces,
40 removal/replacement of non-ASCII characters).
41 The code itself is NOT changed.
42
43 This file has been modified by Info-ZIP for use in MacZip.
44 This file is NOT part of the original package More Files.
45
46 More Files can be found on the MetroWerks CD and Developer CD from
47 Apple. You can also download the latest version from:
48
49 http://members.aol.com/JumpLong/#MoreFiles
50
51 Jim Luther's Home-page:
52 http://members.aol.com/JumpLong/
53
54
55 */
56
57 #include <string.h>
58
59
60 #include "macstuff.h"
61
62
63
64 extern int errno;
65
66 static OSErr GetCommentFromDesktopFile(short vRefNum,
67 long dirID,
68 ConstStr255Param name,
69 Str255 comment);
70
71 static OSErr GetCommentID(short vRefNum,
72 long dirID,
73 ConstStr255Param name,
74 short *commentID);
75
76 static OSErr GetDesktopFileName(short vRefNum,
77 Str255 desktopName);
78
79
80 enum
81 {
82 kBNDLResType = 'BNDL',
83 kFREFResType = 'FREF',
84 kIconFamResType = 'ICN#',
85 kFCMTResType = 'FCMT',
86 kAPPLResType = 'APPL'
87 };
88
89
90 /*****************************************************************************/
91
92 /*
93 ** File Manager FSp calls
94 */
95
96 /*****************************************************************************/
97
FSMakeFSSpecCompat(short vRefNum,long dirID,ConstStr255Param fileName,FSSpec * spec)98 pascal OSErr FSMakeFSSpecCompat(short vRefNum,
99 long dirID,
100 ConstStr255Param fileName,
101 FSSpec *spec)
102 {
103 OSErr result;
104
105 #if !__MACOSSEVENORLATER
106 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
107 {
108 Boolean isDirectory;
109
110 result = GetObjectLocation(vRefNum, dirID, fileName,
111 &(spec->vRefNum), &(spec->parID), spec->name,
112 &isDirectory);
113 }
114 else
115 #endif /* !__MACOSSEVENORLATER */
116 {
117 /* Let the file system create the FSSpec if it can since it does the job */
118 /* much more efficiently than I can. */
119 result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
120
121 /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
122 /* returned in the parID field when making an FSSpec to the volume's */
123 /* root directory by passing a full pathname in MakeFSSpec's */
124 /* fileName parameter. Fixed in Mac OS 8.1 */
125 if ( (result == noErr) && (spec->parID == 0) )
126 spec->parID = fsRtParID;
127 }
128 return ( result );
129 }
130
131
132 /*****************************************************************************/
133 /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
134
135 #if !__MACOSSEVENORLATER
FSHasFSSpecCalls(void)136 static Boolean FSHasFSSpecCalls(void)
137 {
138 long response;
139 #if !GENERATENODATA
140 static Boolean tested = false;
141 static Boolean result = false;
142 #else
143 Boolean result = false;
144 #endif
145
146 #if !GENERATENODATA
147 if ( !tested )
148 {
149 tested = true;
150 #endif
151 if ( Gestalt(gestaltFSAttr, &response) == noErr )
152 {
153 result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
154 }
155 #if !GENERATENODATA
156 }
157 #endif
158 return ( result );
159 }
160 #endif /* !__MACOSSEVENORLATER */
161
162
163
164 /*****************************************************************************/
165 /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
166 /* except for FSpExchangeFiles. */
167
168 #if !__MACOSSEVENORLATER
QTHasFSSpecCalls(void)169 static Boolean QTHasFSSpecCalls(void)
170 {
171 long response;
172 #if !GENERATENODATA
173 static Boolean tested = false;
174 static Boolean result = false;
175 #else
176 Boolean result = false;
177 #endif
178
179 #if !GENERATENODATA
180 if ( !tested )
181 {
182 tested = true;
183 #endif
184 result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
185 #if !GENERATENODATA
186 }
187 #endif
188 return ( result );
189 }
190 #endif /* !__MACOSSEVENORLATER */
191
192
193
194
195 /*
196 *----------------------------------------------------------------------
197 *
198 * FSpGetDefaultDir --
199 *
200 * This function gets the current default directory.
201 *
202 * Results:
203 * The provided FSSpec is changed to point to the "default"
204 * directory. The function returns what ever errors
205 * FSMakeFSSpecCompat may encounter.
206 *
207 * Side effects:
208 * None.
209 *
210 *----------------------------------------------------------------------
211 */
212
FSpGetDefaultDir(FSSpecPtr dirSpec)213 int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
214 {
215 OSErr err;
216 short vRefNum = 0;
217 long int dirID = 0;
218
219 err = HGetVol(NULL, &vRefNum, &dirID);
220
221 if (err == noErr) {
222 err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
223 dirSpec);
224 }
225
226 return err;
227 }
228
229 /*
230 *----------------------------------------------------------------------
231 *
232 * FSpSetDefaultDir --
233 *
234 * This function sets the default directory to the directory
235 * pointed to by the provided FSSpec.
236 *
237 * Results:
238 * The function returns what ever errors HSetVol may encounter.
239 *
240 * Side effects:
241 * None.
242 *
243 *----------------------------------------------------------------------
244 */
245
FSpSetDefaultDir(FSSpecPtr dirSpec)246 int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
247 {
248 OSErr err;
249
250 /*
251 * The following special case is needed to work around a bug
252 * in the Macintosh OS. (Acutally PC Exchange.)
253 */
254
255 if (dirSpec->parID == fsRtParID) {
256 err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
257 } else {
258 err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
259 }
260
261 return err;
262 }
263
264 /*
265 *----------------------------------------------------------------------
266 *
267 * FSpFindFolder --
268 *
269 * This function is a version of the FindFolder function that
270 * returns the result as a FSSpec rather than a vRefNum and dirID.
271 *
272 * Results:
273 * Results will be simaler to that of the FindFolder function.
274 *
275 * Side effects:
276 * None.
277 *
278 *----------------------------------------------------------------------
279 */
280
281 OSErr
FSpFindFolder(short vRefNum,OSType folderType,Boolean createFolder,FSSpec * spec)282 FSpFindFolder(
283 short vRefNum, /* Volume reference number. */
284 OSType folderType, /* Folder type taken by FindFolder. */
285 Boolean createFolder, /* Should we create it if non-existant. */
286 FSSpec *spec) /* Pointer to resulting directory. */
287 {
288 short foundVRefNum;
289 long foundDirID;
290 OSErr err;
291
292 err = FindFolder(vRefNum, folderType, createFolder,
293 &foundVRefNum, &foundDirID);
294 if (err != noErr) {
295 return err;
296 }
297
298 err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
299 return err;
300 }
301
302
303
304 /*
305 *----------------------------------------------------------------------
306 *
307 * FSpPathFromLocation --
308 *
309 * This function obtains a full path name for a given macintosh
310 * FSSpec. Unlike the More Files function FSpGetFullPath, this
311 * function will return a C string in the Handle. It also will
312 * create paths for FSSpec that do not yet exist.
313 *
314 * Results:
315 * OSErr code.
316 *
317 * Side effects:
318 * None.
319 *
320 *----------------------------------------------------------------------
321 */
322
323 OSErr
FSpPathFromLocation(FSSpec * spec,int * length,Handle * fullPath)324 FSpPathFromLocation(
325 FSSpec *spec, /* The location we want a path for. */
326 int *length, /* Length of the resulting path. */
327 Handle *fullPath) /* Handle to path. */
328 {
329 OSErr err;
330 FSSpec tempSpec;
331 CInfoPBRec pb;
332
333 *fullPath = NULL;
334
335 /*
336 * Make a copy of the input FSSpec that can be modified.
337 */
338 BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
339
340 if (tempSpec.parID == fsRtParID) {
341 /*
342 * The object is a volume. Add a colon to make it a full
343 * pathname. Allocate a handle for it and we are done.
344 */
345 tempSpec.name[0] += 2;
346 tempSpec.name[tempSpec.name[0] - 1] = ':';
347 tempSpec.name[tempSpec.name[0]] = '\0';
348
349 err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
350 } else {
351 /*
352 * The object isn't a volume. Is the object a file or a directory?
353 */
354 pb.dirInfo.ioNamePtr = tempSpec.name;
355 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
356 pb.dirInfo.ioDrDirID = tempSpec.parID;
357 pb.dirInfo.ioFDirIndex = 0;
358 err = PBGetCatInfoSync(&pb);
359
360 if ((err == noErr) || (err == fnfErr)) {
361 /*
362 * If the file doesn't currently exist we start over. If the
363 * directory exists everything will work just fine. Otherwise we
364 * will just fail later. If the object is a directory, append a
365 * colon so full pathname ends with colon.
366 */
367 if (err == fnfErr) {
368 BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
369 } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
370 tempSpec.name[0] += 1;
371 tempSpec.name[tempSpec.name[0]] = ':';
372 }
373
374 /*
375 * Create a new Handle for the object - make it a C string.
376 */
377 tempSpec.name[0] += 1;
378 tempSpec.name[tempSpec.name[0]] = '\0';
379 err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
380 if (err == noErr) {
381 /*
382 * Get the ancestor directory names - loop until we have an
383 * error or find the root directory.
384 */
385 pb.dirInfo.ioNamePtr = tempSpec.name;
386 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
387 pb.dirInfo.ioDrParID = tempSpec.parID;
388 do {
389 pb.dirInfo.ioFDirIndex = -1;
390 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
391 err = PBGetCatInfoSync(&pb);
392 if (err == noErr) {
393 /*
394 * Append colon to directory name and add
395 * directory name to beginning of fullPath.
396 */
397 ++tempSpec.name[0];
398 tempSpec.name[tempSpec.name[0]] = ':';
399
400 (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
401 tempSpec.name[0]);
402 err = MemError();
403 }
404 } while ( (err == noErr) &&
405 (pb.dirInfo.ioDrDirID != fsRtDirID) );
406 }
407 }
408 }
409
410 /*
411 * On error Dispose the handle, set it to NULL & return the err.
412 * Otherwise, set the length & return.
413 */
414 if (err == noErr) {
415 *length = GetHandleSize(*fullPath) - 1;
416 } else {
417 if ( *fullPath != NULL ) {
418 DisposeHandle(*fullPath);
419 }
420 *fullPath = NULL;
421 *length = 0;
422 }
423
424 return err;
425 }
426
427
428
429 /*****************************************************************************/
430
FSpGetDirectoryID(const FSSpec * spec,long * theDirID,Boolean * isDirectory)431 pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
432 long *theDirID,
433 Boolean *isDirectory)
434 {
435 return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
436 theDirID, isDirectory) );
437 }
438
439
440 /*****************************************************************************/
441
GetDirectoryID(short vRefNum,long dirID,ConstStr255Param name,long * theDirID,Boolean * isDirectory)442 pascal OSErr GetDirectoryID(short vRefNum,
443 long dirID,
444 ConstStr255Param name,
445 long *theDirID,
446 Boolean *isDirectory)
447 {
448 CInfoPBRec pb;
449 OSErr error;
450
451 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
452 if ( error == noErr )
453 {
454 *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
455 if ( *isDirectory )
456 {
457 *theDirID = pb.dirInfo.ioDrDirID;
458 }
459 else
460 {
461 *theDirID = pb.hFileInfo.ioFlParID;
462 }
463 }
464
465 return ( error );
466 }
467
468
469 /*****************************************************************************/
470
GetCatInfoNoName(short vRefNum,long dirID,ConstStr255Param name,CInfoPBPtr pb)471 pascal OSErr GetCatInfoNoName(short vRefNum,
472 long dirID,
473 ConstStr255Param name,
474 CInfoPBPtr pb)
475 {
476 Str31 tempName;
477 OSErr error;
478
479 /* Protection against File Sharing problem */
480 if ( (name == NULL) || (name[0] == 0) )
481 {
482 tempName[0] = 0;
483 pb->dirInfo.ioNamePtr = tempName;
484 pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
485 }
486 else
487 {
488 pb->dirInfo.ioNamePtr = (StringPtr)name;
489 pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
490 }
491 pb->dirInfo.ioVRefNum = vRefNum;
492 pb->dirInfo.ioDrDirID = dirID;
493 error = PBGetCatInfoSync(pb);
494 pb->dirInfo.ioNamePtr = NULL;
495 return ( error );
496 }
497
498
499
500 /*****************************************************************************/
501
GetObjectLocation(short vRefNum,long dirID,ConstStr255Param pathname,short * realVRefNum,long * realParID,Str255 realName,Boolean * isDirectory)502 pascal OSErr GetObjectLocation(short vRefNum,
503 long dirID,
504 ConstStr255Param pathname,
505 short *realVRefNum,
506 long *realParID,
507 Str255 realName,
508 Boolean *isDirectory)
509 {
510 OSErr error;
511 CInfoPBRec pb;
512 Str255 tempPathname;
513
514 /* clear results */
515 *realVRefNum = 0;
516 *realParID = 0;
517 realName[0] = 0;
518
519 /*
520 ** Get the real vRefNum
521 */
522 error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
523 if ( error == noErr )
524 {
525 /*
526 ** Determine if the object already exists and if so,
527 ** get the real parent directory ID if it's a file
528 */
529
530 /* Protection against File Sharing problem */
531 if ( (pathname == NULL) || (pathname[0] == 0) )
532 {
533 tempPathname[0] = 0;
534 pb.hFileInfo.ioNamePtr = tempPathname;
535 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
536 }
537 else
538 {
539 pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
540 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
541 }
542 pb.hFileInfo.ioVRefNum = vRefNum;
543 pb.hFileInfo.ioDirID = dirID;
544 error = PBGetCatInfoSync(&pb);
545 if ( error == noErr )
546 {
547 /*
548 ** The file system object is present and we have the file's
549 ** real parID
550 */
551
552 /* Is it a directory or a file? */
553 *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
554 if ( *isDirectory )
555 {
556 /*
557 ** It's a directory, get its name and parent dirID, and then
558 ** we're done
559 */
560
561 pb.dirInfo.ioNamePtr = realName;
562 pb.dirInfo.ioVRefNum = *realVRefNum;
563 /* pb.dirInfo.ioDrDirID already contains the dirID of the
564 directory object */
565 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
566 error = PBGetCatInfoSync(&pb);
567
568 /* get the parent ID here, because the file system can return the */
569 /* wrong parent ID from the last call. */
570 *realParID = pb.dirInfo.ioDrParID;
571 }
572 else
573 {
574 /*
575 ** It's a file - use the parent directory ID from the last call
576 ** to GetCatInfoparse, get the file name, and then we're done
577 */
578 *realParID = pb.hFileInfo.ioFlParID;
579 error = GetFilenameFromPathname(pathname, realName);
580 }
581 }
582 else if ( error == fnfErr )
583 {
584 /*
585 ** The file system object is not present - see if its parent is present
586 */
587
588 /*
589 ** Parse to get the object name from end of pathname
590 */
591 error = GetFilenameFromPathname(pathname, realName);
592
593 /* if we can't get the object name from the end, we can't continue */
594 if ( error == noErr )
595 {
596 /*
597 ** What we want now is the pathname minus the object name
598 ** for example:
599 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
600 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
601 ** if pathname is ':dir:file' tempPathname becomes ':dir:'
602 ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
603 ** if pathname is ':file' tempPathname becomes ':'
604 ** if pathname is 'file or file:' tempPathname becomes ''
605 */
606
607 /* get a copy of the pathname */
608 BlockMoveData(pathname, tempPathname, pathname[0] + 1);
609
610 /* remove the object name */
611 tempPathname[0] -= realName[0];
612 /* and the trailing colon (if any) */
613 if ( pathname[pathname[0]] == ':' )
614 {
615 --tempPathname[0];
616 }
617
618 /* OK, now get the parent's directory ID */
619
620 /* Protection against File Sharing problem */
621 pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
622 if ( tempPathname[0] != 0 )
623 {
624 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
625 }
626 else
627 {
628 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
629 }
630 pb.hFileInfo.ioVRefNum = vRefNum;
631 pb.hFileInfo.ioDirID = dirID;
632 error = PBGetCatInfoSync(&pb);
633 *realParID = pb.dirInfo.ioDrDirID;
634
635 *isDirectory = false; /* we don't know what the object is
636 really going to be */
637 }
638
639 if ( error != noErr )
640 {
641 error = dirNFErr; /* couldn't find parent directory */
642 }
643 else
644 {
645 error = fnfErr; /* we found the parent, but not the file */
646 }
647 }
648 }
649
650 return ( error );
651 }
652
653
654
655 /*****************************************************************************/
656
DetermineVRefNum(ConstStr255Param pathname,short vRefNum,short * realVRefNum)657 pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
658 short vRefNum,
659 short *realVRefNum)
660 {
661 HParamBlockRec pb;
662 OSErr error;
663
664 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
665 if ( error == noErr )
666 {
667 *realVRefNum = pb.volumeParam.ioVRefNum;
668 }
669 return ( error );
670 }
671
672
673 /*****************************************************************************/
674
GetFilenameFromPathname(ConstStr255Param pathname,Str255 filename)675 pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
676 Str255 filename)
677 {
678 short index;
679 short nameEnd;
680 OSErr error;
681
682 /* default to no filename */
683 filename[0] = 0;
684
685 /* check for no pathname */
686 if ( pathname != NULL )
687 {
688 /* get string length */
689 index = pathname[0];
690
691 /* check for empty string */
692 if ( index != 0 )
693 {
694 /* skip over last trailing colon (if any) */
695 if ( pathname[index] == ':' )
696 {
697 --index;
698 }
699
700 /* save the end of the string */
701 nameEnd = index;
702
703 /* if pathname ends with multiple colons, then this pathname refers */
704 /* to a directory, not a file */
705 if ( pathname[index] != ':' )
706 {
707 /* parse backwards until we find a colon or hit the beginning
708 of the pathname */
709 while ( (index != 0) && (pathname[index] != ':') )
710 {
711 --index;
712 }
713
714 /* if we parsed to the beginning of the pathname and the
715 pathname ended */
716 /* with a colon, then pathname is a full pathname to a volume,
717 not a file */
718 if ( (index != 0) || (pathname[pathname[0]] != ':') )
719 {
720 /* get the filename and return noErr */
721 filename[0] = (char)(nameEnd - index);
722 BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
723 error = noErr;
724 }
725 else
726 {
727 /* pathname to a volume, not a file */
728 error = notAFileErr;
729 }
730 }
731 else
732 {
733 /* directory, not a file */
734 error = notAFileErr;
735 }
736 }
737 else
738 {
739 /* empty string isn't a file */
740 error = notAFileErr;
741 }
742 }
743 else
744 {
745 /* NULL pathname isn't a file */
746 error = notAFileErr;
747 }
748
749 return ( error );
750 }
751
752
753
754 /*****************************************************************************/
755
756 /*
757 ** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
758 ** in cases where the returned volume name is not needed by the caller.
759 ** The pathname and vRefNum parameters are not touched, and the pb
760 ** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
761 ** the parameter block is always returned as NULL (since it might point
762 ** to the local tempPathname).
763 **
764 ** I noticed using this code in several places, so here it is once.
765 ** This reduces the code size of MoreFiles.
766 */
GetVolumeInfoNoName(ConstStr255Param pathname,short vRefNum,HParmBlkPtr pb)767 pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
768 short vRefNum,
769 HParmBlkPtr pb)
770 {
771 Str255 tempPathname;
772 OSErr error;
773
774 /* Make sure pb parameter is not NULL */
775 if ( pb != NULL )
776 {
777 pb->volumeParam.ioVRefNum = vRefNum;
778 if ( pathname == NULL )
779 {
780 pb->volumeParam.ioNamePtr = NULL;
781 pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
782 }
783 else
784 { /* make a copy of the string and */
785 BlockMoveData(pathname, tempPathname, pathname[0] + 1);
786 /* use the copy so original isn't trashed */
787 pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
788 /* use ioNamePtr/ioVRefNum combination */
789 pb->volumeParam.ioVolIndex = -1;
790 }
791 error = PBHGetVInfoSync(pb);
792 pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local
793 tempPathname, so don't return it */
794 }
795 else
796 {
797 error = paramErr;
798 }
799 return ( error );
800 }
801
802
803
804
805 /*****************************************************************************/
806
FSpGetFullPath(const FSSpec * spec,short * fullPathLength,Handle * fullPath)807 pascal OSErr FSpGetFullPath(const FSSpec *spec,
808 short *fullPathLength,
809 Handle *fullPath)
810 {
811 OSErr result;
812 OSErr realResult;
813 FSSpec tempSpec;
814 CInfoPBRec pb;
815
816 *fullPathLength = 0;
817 *fullPath = NULL;
818
819 /* Default to noErr */
820 realResult = noErr;
821
822 /* Make a copy of the input FSSpec that can be modified */
823 BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
824
825 if ( tempSpec.parID == fsRtParID )
826 {
827 /* The object is a volume */
828
829 /* Add a colon to make it a full pathname */
830 ++tempSpec.name[0];
831 tempSpec.name[tempSpec.name[0]] = ':';
832
833 /* We're done */
834 result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
835 }
836 else
837 {
838 /* The object isn't a volume */
839
840 /* Is the object a file or a directory? */
841 pb.dirInfo.ioNamePtr = tempSpec.name;
842 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
843 pb.dirInfo.ioDrDirID = tempSpec.parID;
844 pb.dirInfo.ioFDirIndex = 0;
845 result = PBGetCatInfoSync(&pb);
846 /* Allow file/directory name at end of path to not exist. */
847 realResult = result;
848 if ( (result == noErr) || (result == fnfErr) )
849 {
850 /* if the object is a directory, append a colon so full pathname
851 ends with colon */
852 if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
853 {
854 ++tempSpec.name[0];
855 tempSpec.name[tempSpec.name[0]] = ':';
856 }
857
858 /* Put the object name in first */
859 result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
860 if ( result == noErr )
861 {
862 /* Get the ancestor directory names */
863 pb.dirInfo.ioNamePtr = tempSpec.name;
864 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
865 pb.dirInfo.ioDrParID = tempSpec.parID;
866 do /* loop until we have an error or find the root directory */
867 {
868 pb.dirInfo.ioFDirIndex = -1;
869 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
870 result = PBGetCatInfoSync(&pb);
871 if ( result == noErr )
872 {
873 /* Append colon to directory name */
874 ++tempSpec.name[0];
875 tempSpec.name[tempSpec.name[0]] = ':';
876
877 /* Add directory name to beginning of fullPath */
878 (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
879 tempSpec.name[0]);
880 result = MemError();
881 }
882 } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
883 }
884 }
885 }
886 if ( result == noErr )
887 {
888 /* Return the length */
889 *fullPathLength = InlineGetHandleSize(*fullPath);
890 result = realResult; /* return realResult in case it was fnfErr */
891 }
892 else
893 {
894 /* Dispose of the handle and return NULL and zero length */
895 if ( *fullPath != NULL )
896 {
897 DisposeHandle(*fullPath);
898 }
899 *fullPath = NULL;
900 *fullPathLength = 0;
901 }
902
903 return ( result );
904 }
905
906
907
908 /*****************************************************************************/
909
FSpLocationFromFullPath(short fullPathLength,const void * fullPath,FSSpec * spec)910 pascal OSErr FSpLocationFromFullPath(short fullPathLength,
911 const void *fullPath,
912 FSSpec *spec)
913 {
914 AliasHandle alias;
915 OSErr result;
916 Boolean wasChanged;
917 Str32 nullString;
918
919 /* Create a minimal alias from the full pathname */
920 nullString[0] = 0; /* null string to indicate no zone or server name */
921 result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
922 nullString, &alias);
923
924 if ( result == noErr )
925 {
926 /* Let the Alias Manager resolve the alias. */
927 result = ResolveAlias(NULL, alias, spec, &wasChanged);
928
929 DisposeHandle((Handle)alias); /* Free up memory used */
930 }
931
932 return ( result );
933 }
934
935
936
937 /*****************************************************************************/
938
GetFullPath(short vRefNum,long dirID,ConstStr255Param name,short * fullPathLength,Handle * fullPath)939 pascal OSErr GetFullPath(short vRefNum,
940 long dirID,
941 ConstStr255Param name,
942 short *fullPathLength,
943 Handle *fullPath)
944 {
945 OSErr result;
946 FSSpec spec;
947
948 *fullPathLength = 0;
949 *fullPath = NULL;
950
951 result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
952 if ( (result == noErr) || (result == fnfErr) )
953 {
954 result = FSpGetFullPath(&spec, fullPathLength, fullPath);
955 }
956
957 return ( result );
958 }
959
960
961
962 /*****************************************************************************/
963
ChangeCreatorType(short vRefNum,long dirID,ConstStr255Param name,OSType creator,OSType fileType)964 pascal OSErr ChangeCreatorType(short vRefNum,
965 long dirID,
966 ConstStr255Param name,
967 OSType creator,
968 OSType fileType)
969 {
970 CInfoPBRec pb;
971 OSErr error;
972 short realVRefNum;
973 long parID;
974
975 pb.hFileInfo.ioNamePtr = (StringPtr)name;
976 pb.hFileInfo.ioVRefNum = vRefNum;
977 pb.hFileInfo.ioDirID = dirID;
978 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
979 error = PBGetCatInfoSync(&pb);
980 if ( error == noErr )
981 {
982 if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) /* if file */
983 { /* save parent dirID for BumpDate call */
984 parID = pb.hFileInfo.ioFlParID;
985
986 /* If creator not 0x00000000, change creator */
987 if ( creator != (OSType)0x00000000 )
988 {
989 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
990 }
991
992 /* If fileType not 0x00000000, change fileType */
993 if ( fileType != (OSType)0x00000000 )
994 {
995 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
996 }
997
998 pb.hFileInfo.ioDirID = dirID;
999 error = PBSetCatInfoSync(&pb); /* now, save the new information
1000 back to disk */
1001
1002 if ( (error == noErr) && (parID != fsRtParID) ) /* can't
1003 bump fsRtParID */
1004 {
1005 /* get the real vRefNum in case a full pathname was passed */
1006 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1007 if ( error == noErr )
1008 {
1009 error = BumpDate(realVRefNum, parID, NULL);
1010 /* and bump the parent directory's mod date to wake
1011 up the Finder */
1012 /* to the change we just made */
1013 }
1014 }
1015 }
1016 else
1017 {
1018 /* it was a directory, not a file */
1019 error = notAFileErr;
1020 }
1021 }
1022
1023 return ( error );
1024 }
1025
1026 /*****************************************************************************/
1027
FSpChangeCreatorType(const FSSpec * spec,OSType creator,OSType fileType)1028 pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
1029 OSType creator,
1030 OSType fileType)
1031 {
1032 return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
1033 creator, fileType) );
1034 }
1035
1036 /*****************************************************************************/
1037
BumpDate(short vRefNum,long dirID,ConstStr255Param name)1038 pascal OSErr BumpDate(short vRefNum,
1039 long dirID,
1040 ConstStr255Param name)
1041 /* Given a file or directory, change its modification date to the
1042 current date/time. */
1043 {
1044 CInfoPBRec pb;
1045 Str31 tempName;
1046 OSErr error;
1047 unsigned long secs;
1048
1049 /* Protection against File Sharing problem */
1050 if ( (name == NULL) || (name[0] == 0) )
1051 {
1052 tempName[0] = 0;
1053 pb.hFileInfo.ioNamePtr = tempName;
1054 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
1055 }
1056 else
1057 {
1058 pb.hFileInfo.ioNamePtr = (StringPtr)name;
1059 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1060 }
1061 pb.hFileInfo.ioVRefNum = vRefNum;
1062 pb.hFileInfo.ioDirID = dirID;
1063 error = PBGetCatInfoSync(&pb);
1064 if ( error == noErr )
1065 {
1066 GetDateTime(&secs);
1067 /* set mod date to current date, or one second into the future
1068 if mod date = current date */
1069 pb.hFileInfo.ioFlMdDat =
1070 (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
1071 if ( pb.dirInfo.ioNamePtr == tempName )
1072 {
1073 pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
1074 }
1075 else
1076 {
1077 pb.hFileInfo.ioDirID = dirID;
1078 }
1079 error = PBSetCatInfoSync(&pb);
1080 }
1081
1082 return ( error );
1083 }
1084
1085 /*****************************************************************************/
1086
FSpBumpDate(const FSSpec * spec)1087 pascal OSErr FSpBumpDate(const FSSpec *spec)
1088 {
1089 return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
1090 }
1091
1092
1093 /*****************************************************************************/
1094
OnLine(FSSpecPtr volumes,short reqVolCount,short * actVolCount,short * volIndex)1095 pascal OSErr OnLine(FSSpecPtr volumes,
1096 short reqVolCount,
1097 short *actVolCount,
1098 short *volIndex)
1099 {
1100 HParamBlockRec pb;
1101 OSErr error = noErr;
1102 FSSpec *endVolArray;
1103
1104 if ( *volIndex > 0 )
1105 {
1106 *actVolCount = 0;
1107 for ( endVolArray = volumes + reqVolCount;
1108 (volumes < endVolArray) && (error == noErr); ++volumes )
1109 {
1110 pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
1111 pb.volumeParam.ioVolIndex = *volIndex;
1112 error = PBHGetVInfoSync(&pb);
1113 if ( error == noErr )
1114 {
1115 volumes->parID = fsRtParID; /* the root directory's
1116 parent is 1 */
1117 volumes->vRefNum = pb.volumeParam.ioVRefNum;
1118 ++*volIndex;
1119 ++*actVolCount;
1120 }
1121 }
1122 }
1123 else
1124 {
1125 error = paramErr;
1126 }
1127
1128 return ( error );
1129 }
1130
1131
1132 /*****************************************************************************/
1133
DTGetComment(short vRefNum,long dirID,ConstStr255Param name,Str255 comment)1134 pascal OSErr DTGetComment(short vRefNum,
1135 long dirID,
1136 ConstStr255Param name,
1137 Str255 comment)
1138 {
1139 DTPBRec pb;
1140 OSErr error;
1141 short dtRefNum;
1142 Boolean newDTDatabase;
1143
1144 if (comment != NULL)
1145 {
1146 comment[0] = 0; /* return nothing by default */
1147
1148 /* attempt to open the desktop database */
1149 error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1150 if ( error == noErr )
1151 {
1152 /* There was a desktop database and it's now open */
1153
1154 if ( !newDTDatabase )
1155 {
1156 pb.ioDTRefNum = dtRefNum;
1157 pb.ioNamePtr = (StringPtr)name;
1158 pb.ioDirID = dirID;
1159 pb.ioDTBuffer = (Ptr)&comment[1];
1160 /*
1161 ** IMPORTANT NOTE #1: Inside Macintosh says that comments
1162 ** are up to 200 characters. While that may be correct for
1163 ** the HFS file system's Desktop Manager, other file
1164 ** systems (such as Apple Photo Access) return up to
1165 ** 255 characters. Make sure the comment buffer is a Str255
1166 ** or you'll regret it.
1167 **
1168 ** IMPORTANT NOTE #2: Although Inside Macintosh doesn't
1169 ** mention it, ioDTReqCount is a input field to
1170 ** PBDTGetCommentSync. Some file systems (like HFS) ignore
1171 ** ioDTReqCount and always return the full comment --
1172 ** others (like AppleShare) respect ioDTReqCount and only
1173 ** return up to ioDTReqCount characters of the comment.
1174 */
1175 pb.ioDTReqCount = sizeof(Str255) - 1;
1176 error = PBDTGetCommentSync(&pb);
1177 if (error == noErr)
1178 {
1179 comment[0] = (unsigned char)pb.ioDTActCount;
1180 }
1181 }
1182 }
1183 else
1184 {
1185 /* There is no desktop database - try the Desktop file */
1186 error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
1187 if ( error != noErr )
1188 {
1189 error = afpItemNotFound; /* return an expected error */
1190 }
1191 }
1192 }
1193 else
1194 {
1195 error = paramErr;
1196 }
1197
1198 return (error);
1199 }
1200
1201 /*****************************************************************************/
1202
FSpDTGetComment(const FSSpec * spec,Str255 comment)1203 pascal OSErr FSpDTGetComment(const FSSpec *spec,
1204 Str255 comment)
1205 {
1206 return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
1207 }
1208
1209
1210 /*****************************************************************************/
1211
DTSetComment(short vRefNum,long dirID,ConstStr255Param name,ConstStr255Param comment)1212 pascal OSErr DTSetComment(short vRefNum,
1213 long dirID,
1214 ConstStr255Param name,
1215 ConstStr255Param comment)
1216 {
1217 DTPBRec pb;
1218 OSErr error;
1219 short dtRefNum;
1220 Boolean newDTDatabase;
1221
1222 error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1223 if ( error == noErr )
1224 {
1225 pb.ioDTRefNum = dtRefNum;
1226 pb.ioNamePtr = (StringPtr)name;
1227 pb.ioDirID = dirID;
1228 pb.ioDTBuffer = (Ptr)&comment[1];
1229 /* Truncate the comment to 200 characters just in case */
1230 /* some file system doesn't range check */
1231 if ( comment[0] <= 200 )
1232 {
1233 pb.ioDTReqCount = comment[0];
1234 }
1235 else
1236 {
1237 pb.ioDTReqCount = 200;
1238 }
1239 error = PBDTSetCommentSync(&pb);
1240 }
1241 return (error);
1242 }
1243
1244 /*****************************************************************************/
1245
FSpDTSetComment(const FSSpec * spec,ConstStr255Param comment)1246 pascal OSErr FSpDTSetComment(const FSSpec *spec,
1247 ConstStr255Param comment)
1248 {
1249 return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
1250 }
1251
1252
1253 /*****************************************************************************/
1254
DTOpen(ConstStr255Param volName,short vRefNum,short * dtRefNum,Boolean * newDTDatabase)1255 pascal OSErr DTOpen(ConstStr255Param volName,
1256 short vRefNum,
1257 short *dtRefNum,
1258 Boolean *newDTDatabase)
1259 {
1260 OSErr error;
1261 GetVolParmsInfoBuffer volParmsInfo;
1262 long infoSize;
1263 DTPBRec pb;
1264
1265 /* Check for volume Desktop Manager support before calling */
1266 infoSize = sizeof(GetVolParmsInfoBuffer);
1267 error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
1268 if ( error == noErr )
1269 {
1270 if ( hasDesktopMgr(volParmsInfo) )
1271 {
1272 pb.ioNamePtr = (StringPtr)volName;
1273 pb.ioVRefNum = vRefNum;
1274 error = PBDTOpenInform(&pb);
1275 /* PBDTOpenInform informs us if the desktop was just created */
1276 /* by leaving the low bit of ioTagInfo clear (0) */
1277 *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
1278 if ( error == paramErr )
1279 {
1280 error = PBDTGetPath(&pb);
1281 /* PBDTGetPath doesn't tell us if the database is new */
1282 /* so assume it is not new */
1283 *newDTDatabase = false;
1284 }
1285 *dtRefNum = pb.ioDTRefNum;
1286 }
1287 else
1288 {
1289 error = paramErr;
1290 }
1291 }
1292 return ( error );
1293 }
1294
1295 /*****************************************************************************/
1296
1297 /*
1298 ** GetCommentFromDesktopFile
1299 **
1300 ** Get a file or directory's Finder comment field (if any) from the
1301 ** Desktop file's 'FCMT' resources.
1302 */
GetCommentFromDesktopFile(short vRefNum,long dirID,ConstStr255Param name,Str255 comment)1303 static OSErr GetCommentFromDesktopFile(short vRefNum,
1304 long dirID,
1305 ConstStr255Param name,
1306 Str255 comment)
1307 {
1308 OSErr error;
1309 short commentID;
1310 short realVRefNum;
1311 Str255 desktopName;
1312 short savedResFile;
1313 short dfRefNum;
1314 StringHandle commentHandle;
1315
1316 /* Get the comment ID number */
1317 error = GetCommentID(vRefNum, dirID, name, &commentID);
1318 if ( error == noErr )
1319 {
1320 if ( commentID != 0 ) /* commentID == 0 means there's no comment */
1321 {
1322 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1323 if ( error == noErr )
1324 {
1325 error = GetDesktopFileName(realVRefNum, desktopName);
1326 if ( error == noErr )
1327 {
1328 savedResFile = CurResFile();
1329 /*
1330 ** Open the 'Desktop' file in the root directory. (because
1331 ** opening the resource file could preload unwanted resources,
1332 ** bracket the call with SetResLoad(s))
1333 */
1334 SetResLoad(false);
1335 dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
1336 fsRdPerm);
1337 SetResLoad(true);
1338
1339 if ( dfRefNum != -1)
1340 {
1341 /* Get the comment resource */
1342 commentHandle = (StringHandle)Get1Resource(kFCMTResType,
1343 commentID);
1344 if ( commentHandle != NULL )
1345 {
1346 if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
1347 {
1348 BlockMoveData(*commentHandle, comment,
1349 *commentHandle[0] + 1);
1350 }
1351 else
1352 { /* no comment available */
1353 error = afpItemNotFound;
1354 }
1355 }
1356 else
1357 { /* no comment available */
1358 error = afpItemNotFound;
1359 }
1360
1361 /* restore the resource chain and close
1362 the Desktop file */
1363 UseResFile(savedResFile);
1364 CloseResFile(dfRefNum);
1365 }
1366 else
1367 {
1368 error = afpItemNotFound;
1369 }
1370 }
1371 else
1372 {
1373 error = afpItemNotFound;
1374 }
1375 }
1376 }
1377 else
1378 {
1379 error = afpItemNotFound; /* no comment available */
1380 }
1381 }
1382
1383 return ( error );
1384 }
1385
1386 /*****************************************************************************/
1387
HGetVolParms(ConstStr255Param volName,short vRefNum,GetVolParmsInfoBuffer * volParmsInfo,long * infoSize)1388 pascal OSErr HGetVolParms(ConstStr255Param volName,
1389 short vRefNum,
1390 GetVolParmsInfoBuffer *volParmsInfo,
1391 long *infoSize)
1392 {
1393 HParamBlockRec pb;
1394 OSErr error;
1395
1396 pb.ioParam.ioNamePtr = (StringPtr)volName;
1397 pb.ioParam.ioVRefNum = vRefNum;
1398 pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
1399 pb.ioParam.ioReqCount = *infoSize;
1400 error = PBHGetVolParmsSync(&pb);
1401 if ( error == noErr )
1402 {
1403 *infoSize = pb.ioParam.ioActCount;
1404 }
1405 return ( error );
1406 }
1407
1408 /*****************************************************************************/
1409 /*
1410 ** GetCommentID
1411 **
1412 ** Get the comment ID number for the Desktop file's 'FCMT' resource ID from
1413 ** the file or folders fdComment (frComment) field.
1414 */
GetCommentID(short vRefNum,long dirID,ConstStr255Param name,short * commentID)1415 static OSErr GetCommentID(short vRefNum,
1416 long dirID,
1417 ConstStr255Param name,
1418 short *commentID)
1419 {
1420 CInfoPBRec pb;
1421 OSErr error;
1422
1423 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1424 *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
1425 return ( error );
1426 }
1427
1428 /*****************************************************************************/
1429
1430 /*
1431 ** GetDesktopFileName
1432 **
1433 ** Get the name of the Desktop file.
1434 */
GetDesktopFileName(short vRefNum,Str255 desktopName)1435 static OSErr GetDesktopFileName(short vRefNum,
1436 Str255 desktopName)
1437 {
1438 OSErr error;
1439 HParamBlockRec pb;
1440 short index;
1441 Boolean found;
1442
1443 pb.fileParam.ioNamePtr = desktopName;
1444 pb.fileParam.ioVRefNum = vRefNum;
1445 pb.fileParam.ioFVersNum = 0;
1446 index = 1;
1447 found = false;
1448 do
1449 {
1450 pb.fileParam.ioDirID = fsRtDirID;
1451 pb.fileParam.ioFDirIndex = index;
1452 error = PBHGetFInfoSync(&pb);
1453 if ( error == noErr )
1454 {
1455 if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
1456 (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
1457 {
1458 found = true;
1459 }
1460 }
1461 ++index;
1462 } while ( (error == noErr) && !found );
1463
1464 return ( error );
1465 }
1466
1467
1468 /*****************************************************************************/
1469
XGetVInfo(short volReference,StringPtr volName,short * vRefNum,UnsignedWide * freeBytes,UnsignedWide * totalBytes)1470 pascal OSErr XGetVInfo(short volReference,
1471 StringPtr volName,
1472 short *vRefNum,
1473 UnsignedWide *freeBytes,
1474 UnsignedWide *totalBytes)
1475 {
1476 OSErr result;
1477 long response;
1478 XVolumeParam pb;
1479
1480 /* See if large volume support is available */
1481 if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
1482 {
1483 /* Large volume support is available */
1484 pb.ioVRefNum = volReference;
1485 pb.ioNamePtr = volName;
1486 pb.ioXVersion = 0; /* this XVolumeParam version (0) */
1487 pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
1488 result = PBXGetVolInfoSync(&pb);
1489 if ( result == noErr )
1490 {
1491 /* The volume name was returned in volName (if not NULL) and */
1492 /* we have the volume's vRefNum and allocation block size */
1493 *vRefNum = pb.ioVRefNum;
1494
1495 /* return the freeBytes and totalBytes */
1496 *totalBytes = pb.ioVTotalBytes;
1497 *freeBytes = pb.ioVFreeBytes;
1498 }
1499 }
1500 else
1501 {
1502 /* No large volume support */
1503
1504 /* Use HGetVInfo to get the results */
1505 result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
1506 if ( result == noErr )
1507 {
1508 /* zero the high longs of totalBytes and freeBytes */
1509 totalBytes->hi = 0;
1510 freeBytes->hi = 0;
1511 }
1512 }
1513 return ( result );
1514 }
1515
1516
1517
1518 /*****************************************************************************/
1519
HGetVInfo(short volReference,StringPtr volName,short * vRefNum,unsigned long * freeBytes,unsigned long * totalBytes)1520 pascal OSErr HGetVInfo(short volReference,
1521 StringPtr volName,
1522 short *vRefNum,
1523 unsigned long *freeBytes,
1524 unsigned long *totalBytes)
1525 {
1526 HParamBlockRec pb;
1527 unsigned long allocationBlockSize;
1528 unsigned short numAllocationBlocks;
1529 unsigned short numFreeBlocks;
1530 VCB *theVCB;
1531 Boolean vcbFound;
1532 OSErr result;
1533
1534 /* Use the File Manager to get the real vRefNum */
1535 pb.volumeParam.ioVRefNum = volReference;
1536 pb.volumeParam.ioNamePtr = volName;
1537 pb.volumeParam.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
1538 result = PBHGetVInfoSync(&pb);
1539
1540 if ( result == noErr )
1541 {
1542 /* The volume name was returned in volName (if not NULL) and */
1543 /* we have the volume's vRefNum and allocation block size */
1544 *vRefNum = pb.volumeParam.ioVRefNum;
1545 allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
1546
1547 /* System 7.5 (and beyond) pins the number of allocation blocks and */
1548 /* the number of free allocation blocks returned by PBHGetVInfo to */
1549 /* a value so that when multiplied by the allocation block size, */
1550 /* the volume will look like it has $7fffffff bytes or less. This */
1551 /* was done so older applications that use signed math or that use */
1552 /* the GetVInfo function (which uses signed math) will continue to work. */
1553 /* However, the unpinned numbers (which we want) are always available */
1554 /* in the volume's VCB so we'll get those values from the VCB if possible. */
1555
1556 /* Find the volume's VCB */
1557 vcbFound = false;
1558 theVCB = (VCB *)(GetVCBQHdr()->qHead);
1559 while ( (theVCB != NULL) && !vcbFound )
1560 {
1561 /* Check VCB signature before using VCB. Don't have to check for */
1562 /* MFS (0xd2d7) because they can't get big enough to be pinned */
1563 if ( theVCB->vcbSigWord == 0x4244 )
1564 {
1565 if ( theVCB->vcbVRefNum == *vRefNum )
1566 {
1567 vcbFound = true;
1568 }
1569 }
1570
1571 if ( !vcbFound )
1572 {
1573 theVCB = (VCB *)(theVCB->qLink);
1574 }
1575 }
1576
1577 if ( theVCB != NULL )
1578 {
1579 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
1580 /* and the number of free blocks from the VCB. */
1581 numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
1582 numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
1583 }
1584 else
1585 {
1586 /* Didn't find a VCB we can use. Return the number of allocation blocks */
1587 /* and the number of free blocks returned by PBHGetVInfoSync. */
1588 numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
1589 numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
1590 }
1591
1592 /* Now, calculate freeBytes and totalBytes using unsigned values */
1593 *freeBytes = numFreeBlocks * allocationBlockSize;
1594 *totalBytes = numAllocationBlocks * allocationBlockSize;
1595 }
1596
1597 return ( result );
1598 }
1599
1600
1601 /*
1602 ** PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
1603 ** File Manager requests from CFM-based programs. At some point, Apple
1604 ** will get around to adding this to the standard libraries you link with
1605 ** and you'll get a duplicate symbol link error. At that time, just delete
1606 ** this code (or comment it out).
1607 **
1608 ** Non-CFM 68K programs don't needs this glue (and won't get it) because
1609 ** they instead use the inline assembly glue found in the Files.h interface
1610 ** file.
1611 */
1612
1613 #if __WANTPASCALELIMINATION
1614 #undef pascal
1615 #endif
1616
1617 #if GENERATINGCFM
PBXGetVolInfoSync(XVolumeParamPtr paramBlock)1618 pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
1619 {
1620 enum
1621 {
1622 kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */
1623
1624 uppFSDispatchProcInfo = kRegisterBased
1625 | REGISTER_RESULT_LOCATION(kRegisterD0)
1626 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
1627 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */
1628 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */
1629 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
1630 };
1631
1632 return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
1633 uppFSDispatchProcInfo,
1634 _FSDispatch,
1635 kXGetVolInfoSelector,
1636 paramBlock) );
1637 }
1638 #endif
1639
1640 #if __WANTPASCALELIMINATION
1641 #define pascal
1642 #endif
1643
1644 /*****************************************************************************/
1645
GetDirName(short vRefNum,long dirID,Str31 name)1646 pascal OSErr GetDirName(short vRefNum,
1647 long dirID,
1648 Str31 name)
1649 {
1650 CInfoPBRec pb;
1651 OSErr error;
1652
1653 if ( name != NULL )
1654 {
1655 pb.dirInfo.ioNamePtr = name;
1656 pb.dirInfo.ioVRefNum = vRefNum;
1657 pb.dirInfo.ioDrDirID = dirID;
1658 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
1659 error = PBGetCatInfoSync(&pb);
1660 }
1661 else
1662 {
1663 error = paramErr;
1664 }
1665
1666 return ( error );
1667 }
1668
1669
1670 /*****************************************************************************/
1671
GetVolFileSystemID(ConstStr255Param pathname,short vRefNum,short * fileSystemID)1672 pascal OSErr GetVolFileSystemID(ConstStr255Param pathname,
1673 short vRefNum,
1674 short *fileSystemID)
1675 {
1676 HParamBlockRec pb;
1677 OSErr error;
1678
1679 error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
1680 if ( error == noErr )
1681 {
1682 *fileSystemID = pb.volumeParam.ioVFSID;
1683 }
1684
1685 return ( error );
1686 }
1687
1688 /*****************************************************************************/
1689
GetDInfo(short vRefNum,long dirID,ConstStr255Param name,DInfo * fndrInfo)1690 pascal OSErr GetDInfo(short vRefNum,
1691 long dirID,
1692 ConstStr255Param name,
1693 DInfo *fndrInfo)
1694 {
1695 CInfoPBRec pb;
1696 OSErr error;
1697
1698 error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1699 if ( error == noErr )
1700 {
1701 if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
1702 {
1703 /* it's a directory, return the DInfo */
1704 *fndrInfo = pb.dirInfo.ioDrUsrWds;
1705 }
1706 else
1707 {
1708 /* oops, a file was passed */
1709 error = dirNFErr;
1710 }
1711 }
1712
1713 return ( error );
1714 }
1715
1716 /*****************************************************************************/
1717
FSpGetDInfo(const FSSpec * spec,DInfo * fndrInfo)1718 pascal OSErr FSpGetDInfo(const FSSpec *spec,
1719 DInfo *fndrInfo)
1720 {
1721 return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
1722 }
1723
1724
1725