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