2
These Functions were originally part of More Files version 1.4.8
4
More Files fixes many of the broken or underfunctional
5
parts of the file system.
9
A collection of File Manager and related routines
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
18
The Package "More Files" is distributed under the following
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
34
The following changes are made by Info-ZIP:
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.
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.
46
More Files can be found on the MetroWerks CD and Developer CD from
47
Apple. You can also download the latest version from:
49
http://members.aol.com/JumpLong/#MoreFiles
51
Jim Luther's Home-page:
52
http://members.aol.com/JumpLong/
66
static OSErr GetCommentFromDesktopFile(short vRefNum,
68
ConstStr255Param name,
71
static OSErr GetCommentID(short vRefNum,
73
ConstStr255Param name,
76
static OSErr GetDesktopFileName(short vRefNum,
82
kBNDLResType = 'BNDL',
83
kFREFResType = 'FREF',
84
kIconFamResType = 'ICN#',
85
kFCMTResType = 'FCMT',
90
/*****************************************************************************/
93
** File Manager FSp calls
96
/*****************************************************************************/
98
pascal OSErr FSMakeFSSpecCompat(short vRefNum,
100
ConstStr255Param fileName,
105
#if !__MACOSSEVENORLATER
106
if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
110
result = GetObjectLocation(vRefNum, dirID, fileName,
111
&(spec->vRefNum), &(spec->parID), spec->name,
115
#endif /* !__MACOSSEVENORLATER */
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);
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;
132
/*****************************************************************************/
133
/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
135
#if !__MACOSSEVENORLATER
136
static Boolean FSHasFSSpecCalls(void)
140
static Boolean tested = false;
141
static Boolean result = false;
143
Boolean result = false;
151
if ( Gestalt(gestaltFSAttr, &response) == noErr )
153
result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
160
#endif /* !__MACOSSEVENORLATER */
164
/*****************************************************************************/
165
/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
166
/* except for FSpExchangeFiles. */
168
#if !__MACOSSEVENORLATER
169
static Boolean QTHasFSSpecCalls(void)
173
static Boolean tested = false;
174
static Boolean result = false;
176
Boolean result = false;
184
result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
190
#endif /* !__MACOSSEVENORLATER */
196
*----------------------------------------------------------------------
198
* FSpGetDefaultDir --
200
* This function gets the current default directory.
203
* The provided FSSpec is changed to point to the "default"
204
* directory. The function returns what ever errors
205
* FSMakeFSSpecCompat may encounter.
210
*----------------------------------------------------------------------
213
int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
219
err = HGetVol(NULL, &vRefNum, &dirID);
222
err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
230
*----------------------------------------------------------------------
232
* FSpSetDefaultDir --
234
* This function sets the default directory to the directory
235
* pointed to by the provided FSSpec.
238
* The function returns what ever errors HSetVol may encounter.
243
*----------------------------------------------------------------------
246
int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
251
* The following special case is needed to work around a bug
252
* in the Macintosh OS. (Acutally PC Exchange.)
255
if (dirSpec->parID == fsRtParID) {
256
err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
258
err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
265
*----------------------------------------------------------------------
269
* This function is a version of the FindFolder function that
270
* returns the result as a FSSpec rather than a vRefNum and dirID.
273
* Results will be simaler to that of the FindFolder function.
278
*----------------------------------------------------------------------
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. */
292
err = FindFolder(vRefNum, folderType, createFolder,
293
&foundVRefNum, &foundDirID);
298
err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
305
*----------------------------------------------------------------------
307
* FSpPathFromLocation --
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.
320
*----------------------------------------------------------------------
325
FSSpec *spec, /* The location we want a path for. */
326
int *length, /* Length of the resulting path. */
327
Handle *fullPath) /* Handle to path. */
336
* Make a copy of the input FSSpec that can be modified.
338
BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
340
if (tempSpec.parID == fsRtParID) {
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.
345
tempSpec.name[0] += 2;
346
tempSpec.name[tempSpec.name[0] - 1] = ':';
347
tempSpec.name[tempSpec.name[0]] = '\0';
349
err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
352
* The object isn't a volume. Is the object a file or a directory?
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);
360
if ((err == noErr) || (err == fnfErr)) {
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.
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]] = ':';
375
* Create a new Handle for the object - make it a C string.
377
tempSpec.name[0] += 1;
378
tempSpec.name[tempSpec.name[0]] = '\0';
379
err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
382
* Get the ancestor directory names - loop until we have an
383
* error or find the root directory.
385
pb.dirInfo.ioNamePtr = tempSpec.name;
386
pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
387
pb.dirInfo.ioDrParID = tempSpec.parID;
389
pb.dirInfo.ioFDirIndex = -1;
390
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
391
err = PBGetCatInfoSync(&pb);
394
* Append colon to directory name and add
395
* directory name to beginning of fullPath.
398
tempSpec.name[tempSpec.name[0]] = ':';
400
(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
404
} while ( (err == noErr) &&
405
(pb.dirInfo.ioDrDirID != fsRtDirID) );
411
* On error Dispose the handle, set it to NULL & return the err.
412
* Otherwise, set the length & return.
415
*length = GetHandleSize(*fullPath) - 1;
417
if ( *fullPath != NULL ) {
418
DisposeHandle(*fullPath);
429
/*****************************************************************************/
431
pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
433
Boolean *isDirectory)
435
return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
436
theDirID, isDirectory) );
440
/*****************************************************************************/
442
pascal OSErr GetDirectoryID(short vRefNum,
444
ConstStr255Param name,
446
Boolean *isDirectory)
451
error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
452
if ( error == noErr )
454
*isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
457
*theDirID = pb.dirInfo.ioDrDirID;
461
*theDirID = pb.hFileInfo.ioFlParID;
469
/*****************************************************************************/
471
pascal OSErr GetCatInfoNoName(short vRefNum,
473
ConstStr255Param name,
479
/* Protection against File Sharing problem */
480
if ( (name == NULL) || (name[0] == 0) )
483
pb->dirInfo.ioNamePtr = tempName;
484
pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
488
pb->dirInfo.ioNamePtr = (StringPtr)name;
489
pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
491
pb->dirInfo.ioVRefNum = vRefNum;
492
pb->dirInfo.ioDrDirID = dirID;
493
error = PBGetCatInfoSync(pb);
494
pb->dirInfo.ioNamePtr = NULL;
500
/*****************************************************************************/
502
pascal OSErr GetObjectLocation(short vRefNum,
504
ConstStr255Param pathname,
508
Boolean *isDirectory)
520
** Get the real vRefNum
522
error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
523
if ( error == noErr )
526
** Determine if the object already exists and if so,
527
** get the real parent directory ID if it's a file
530
/* Protection against File Sharing problem */
531
if ( (pathname == NULL) || (pathname[0] == 0) )
534
pb.hFileInfo.ioNamePtr = tempPathname;
535
pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
539
pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
540
pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
542
pb.hFileInfo.ioVRefNum = vRefNum;
543
pb.hFileInfo.ioDirID = dirID;
544
error = PBGetCatInfoSync(&pb);
545
if ( error == noErr )
548
** The file system object is present and we have the file's
552
/* Is it a directory or a file? */
553
*isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
557
** It's a directory, get its name and parent dirID, and then
561
pb.dirInfo.ioNamePtr = realName;
562
pb.dirInfo.ioVRefNum = *realVRefNum;
563
/* pb.dirInfo.ioDrDirID already contains the dirID of the
565
pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
566
error = PBGetCatInfoSync(&pb);
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;
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
578
*realParID = pb.hFileInfo.ioFlParID;
579
error = GetFilenameFromPathname(pathname, realName);
582
else if ( error == fnfErr )
585
** The file system object is not present - see if its parent is present
589
** Parse to get the object name from end of pathname
591
error = GetFilenameFromPathname(pathname, realName);
593
/* if we can't get the object name from the end, we can't continue */
594
if ( error == noErr )
597
** What we want now is the pathname minus the object name
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 ''
607
/* get a copy of the pathname */
608
BlockMoveData(pathname, tempPathname, pathname[0] + 1);
610
/* remove the object name */
611
tempPathname[0] -= realName[0];
612
/* and the trailing colon (if any) */
613
if ( pathname[pathname[0]] == ':' )
618
/* OK, now get the parent's directory ID */
620
/* Protection against File Sharing problem */
621
pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
622
if ( tempPathname[0] != 0 )
624
pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
628
pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
630
pb.hFileInfo.ioVRefNum = vRefNum;
631
pb.hFileInfo.ioDirID = dirID;
632
error = PBGetCatInfoSync(&pb);
633
*realParID = pb.dirInfo.ioDrDirID;
635
*isDirectory = false; /* we don't know what the object is
636
really going to be */
639
if ( error != noErr )
641
error = dirNFErr; /* couldn't find parent directory */
645
error = fnfErr; /* we found the parent, but not the file */
655
/*****************************************************************************/
657
pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
664
error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
665
if ( error == noErr )
667
*realVRefNum = pb.volumeParam.ioVRefNum;
673
/*****************************************************************************/
675
pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
682
/* default to no filename */
685
/* check for no pathname */
686
if ( pathname != NULL )
688
/* get string length */
691
/* check for empty string */
694
/* skip over last trailing colon (if any) */
695
if ( pathname[index] == ':' )
700
/* save the end of the string */
703
/* if pathname ends with multiple colons, then this pathname refers */
704
/* to a directory, not a file */
705
if ( pathname[index] != ':' )
707
/* parse backwards until we find a colon or hit the beginning
709
while ( (index != 0) && (pathname[index] != ':') )
714
/* if we parsed to the beginning of the pathname and the
716
/* with a colon, then pathname is a full pathname to a volume,
718
if ( (index != 0) || (pathname[pathname[0]] != ':') )
720
/* get the filename and return noErr */
721
filename[0] = (char)(nameEnd - index);
722
BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
727
/* pathname to a volume, not a file */
733
/* directory, not a file */
739
/* empty string isn't a file */
745
/* NULL pathname isn't a file */
754
/*****************************************************************************/
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).
764
** I noticed using this code in several places, so here it is once.
765
** This reduces the code size of MoreFiles.
767
pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
774
/* Make sure pb parameter is not NULL */
777
pb->volumeParam.ioVRefNum = vRefNum;
778
if ( pathname == NULL )
780
pb->volumeParam.ioNamePtr = NULL;
781
pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
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;
791
error = PBHGetVInfoSync(pb);
792
pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local
793
tempPathname, so don't return it */
805
/*****************************************************************************/
807
pascal OSErr FSpGetFullPath(const FSSpec *spec,
808
short *fullPathLength,
819
/* Default to noErr */
822
/* Make a copy of the input FSSpec that can be modified */
823
BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
825
if ( tempSpec.parID == fsRtParID )
827
/* The object is a volume */
829
/* Add a colon to make it a full pathname */
831
tempSpec.name[tempSpec.name[0]] = ':';
834
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
838
/* The object isn't a volume */
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. */
848
if ( (result == noErr) || (result == fnfErr) )
850
/* if the object is a directory, append a colon so full pathname
852
if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
855
tempSpec.name[tempSpec.name[0]] = ':';
858
/* Put the object name in first */
859
result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
860
if ( result == noErr )
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 */
868
pb.dirInfo.ioFDirIndex = -1;
869
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
870
result = PBGetCatInfoSync(&pb);
871
if ( result == noErr )
873
/* Append colon to directory name */
875
tempSpec.name[tempSpec.name[0]] = ':';
877
/* Add directory name to beginning of fullPath */
878
(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
882
} while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
886
if ( result == noErr )
888
/* Return the length */
889
*fullPathLength = InlineGetHandleSize(*fullPath);
890
result = realResult; /* return realResult in case it was fnfErr */
894
/* Dispose of the handle and return NULL and zero length */
895
if ( *fullPath != NULL )
897
DisposeHandle(*fullPath);
908
/*****************************************************************************/
910
pascal OSErr FSpLocationFromFullPath(short fullPathLength,
911
const void *fullPath,
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,
924
if ( result == noErr )
926
/* Let the Alias Manager resolve the alias. */
927
result = ResolveAlias(NULL, alias, spec, &wasChanged);
929
DisposeHandle((Handle)alias); /* Free up memory used */
937
/*****************************************************************************/
939
pascal OSErr GetFullPath(short vRefNum,
941
ConstStr255Param name,
942
short *fullPathLength,
951
result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
952
if ( (result == noErr) || (result == fnfErr) )
954
result = FSpGetFullPath(&spec, fullPathLength, fullPath);
962
/*****************************************************************************/
964
pascal OSErr ChangeCreatorType(short vRefNum,
966
ConstStr255Param name,
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 )
982
if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) /* if file */
983
{ /* save parent dirID for BumpDate call */
984
parID = pb.hFileInfo.ioFlParID;
986
/* If creator not 0x00000000, change creator */
987
if ( creator != (OSType)0x00000000 )
989
pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
992
/* If fileType not 0x00000000, change fileType */
993
if ( fileType != (OSType)0x00000000 )
995
pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
998
pb.hFileInfo.ioDirID = dirID;
999
error = PBSetCatInfoSync(&pb); /* now, save the new information
1002
if ( (error == noErr) && (parID != fsRtParID) ) /* can't
1005
/* get the real vRefNum in case a full pathname was passed */
1006
error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1007
if ( error == noErr )
1009
error = BumpDate(realVRefNum, parID, NULL);
1010
/* and bump the parent directory's mod date to wake
1012
/* to the change we just made */
1018
/* it was a directory, not a file */
1019
error = notAFileErr;
1026
/*****************************************************************************/
1028
pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
1032
return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
1033
creator, fileType) );
1036
/*****************************************************************************/
1038
pascal OSErr BumpDate(short vRefNum,
1040
ConstStr255Param name)
1041
/* Given a file or directory, change its modification date to the
1042
current date/time. */
1049
/* Protection against File Sharing problem */
1050
if ( (name == NULL) || (name[0] == 0) )
1053
pb.hFileInfo.ioNamePtr = tempName;
1054
pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
1058
pb.hFileInfo.ioNamePtr = (StringPtr)name;
1059
pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
1061
pb.hFileInfo.ioVRefNum = vRefNum;
1062
pb.hFileInfo.ioDirID = dirID;
1063
error = PBGetCatInfoSync(&pb);
1064
if ( error == noErr )
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 )
1073
pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
1077
pb.hFileInfo.ioDirID = dirID;
1079
error = PBSetCatInfoSync(&pb);
1085
/*****************************************************************************/
1087
pascal OSErr FSpBumpDate(const FSSpec *spec)
1089
return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
1093
/*****************************************************************************/
1095
pascal OSErr OnLine(FSSpecPtr volumes,
1101
OSErr error = noErr;
1102
FSSpec *endVolArray;
1104
if ( *volIndex > 0 )
1107
for ( endVolArray = volumes + reqVolCount;
1108
(volumes < endVolArray) && (error == noErr); ++volumes )
1110
pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
1111
pb.volumeParam.ioVolIndex = *volIndex;
1112
error = PBHGetVInfoSync(&pb);
1113
if ( error == noErr )
1115
volumes->parID = fsRtParID; /* the root directory's
1117
volumes->vRefNum = pb.volumeParam.ioVRefNum;
1132
/*****************************************************************************/
1134
pascal OSErr DTGetComment(short vRefNum,
1136
ConstStr255Param name,
1142
Boolean newDTDatabase;
1144
if (comment != NULL)
1146
comment[0] = 0; /* return nothing by default */
1148
/* attempt to open the desktop database */
1149
error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1150
if ( error == noErr )
1152
/* There was a desktop database and it's now open */
1154
if ( !newDTDatabase )
1156
pb.ioDTRefNum = dtRefNum;
1157
pb.ioNamePtr = (StringPtr)name;
1159
pb.ioDTBuffer = (Ptr)&comment[1];
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.
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.
1175
pb.ioDTReqCount = sizeof(Str255) - 1;
1176
error = PBDTGetCommentSync(&pb);
1179
comment[0] = (unsigned char)pb.ioDTActCount;
1185
/* There is no desktop database - try the Desktop file */
1186
error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
1187
if ( error != noErr )
1189
error = afpItemNotFound; /* return an expected error */
1201
/*****************************************************************************/
1203
pascal OSErr FSpDTGetComment(const FSSpec *spec,
1206
return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
1210
/*****************************************************************************/
1212
pascal OSErr DTSetComment(short vRefNum,
1214
ConstStr255Param name,
1215
ConstStr255Param comment)
1220
Boolean newDTDatabase;
1222
error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
1223
if ( error == noErr )
1225
pb.ioDTRefNum = dtRefNum;
1226
pb.ioNamePtr = (StringPtr)name;
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 )
1233
pb.ioDTReqCount = comment[0];
1237
pb.ioDTReqCount = 200;
1239
error = PBDTSetCommentSync(&pb);
1244
/*****************************************************************************/
1246
pascal OSErr FSpDTSetComment(const FSSpec *spec,
1247
ConstStr255Param comment)
1249
return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
1253
/*****************************************************************************/
1255
pascal OSErr DTOpen(ConstStr255Param volName,
1258
Boolean *newDTDatabase)
1261
GetVolParmsInfoBuffer volParmsInfo;
1265
/* Check for volume Desktop Manager support before calling */
1266
infoSize = sizeof(GetVolParmsInfoBuffer);
1267
error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
1268
if ( error == noErr )
1270
if ( hasDesktopMgr(volParmsInfo) )
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 )
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;
1285
*dtRefNum = pb.ioDTRefNum;
1295
/*****************************************************************************/
1298
** GetCommentFromDesktopFile
1300
** Get a file or directory's Finder comment field (if any) from the
1301
** Desktop file's 'FCMT' resources.
1303
static OSErr GetCommentFromDesktopFile(short vRefNum,
1305
ConstStr255Param name,
1314
StringHandle commentHandle;
1316
/* Get the comment ID number */
1317
error = GetCommentID(vRefNum, dirID, name, &commentID);
1318
if ( error == noErr )
1320
if ( commentID != 0 ) /* commentID == 0 means there's no comment */
1322
error = DetermineVRefNum(name, vRefNum, &realVRefNum);
1323
if ( error == noErr )
1325
error = GetDesktopFileName(realVRefNum, desktopName);
1326
if ( error == noErr )
1328
savedResFile = CurResFile();
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))
1335
dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
1339
if ( dfRefNum != -1)
1341
/* Get the comment resource */
1342
commentHandle = (StringHandle)Get1Resource(kFCMTResType,
1344
if ( commentHandle != NULL )
1346
if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
1348
BlockMoveData(*commentHandle, comment,
1349
*commentHandle[0] + 1);
1352
{ /* no comment available */
1353
error = afpItemNotFound;
1357
{ /* no comment available */
1358
error = afpItemNotFound;
1361
/* restore the resource chain and close
1363
UseResFile(savedResFile);
1364
CloseResFile(dfRefNum);
1368
error = afpItemNotFound;
1373
error = afpItemNotFound;
1379
error = afpItemNotFound; /* no comment available */
1386
/*****************************************************************************/
1388
pascal OSErr HGetVolParms(ConstStr255Param volName,
1390
GetVolParmsInfoBuffer *volParmsInfo,
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 )
1403
*infoSize = pb.ioParam.ioActCount;
1408
/*****************************************************************************/
1412
** Get the comment ID number for the Desktop file's 'FCMT' resource ID from
1413
** the file or folders fdComment (frComment) field.
1415
static OSErr GetCommentID(short vRefNum,
1417
ConstStr255Param name,
1423
error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1424
*commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
1428
/*****************************************************************************/
1431
** GetDesktopFileName
1433
** Get the name of the Desktop file.
1435
static OSErr GetDesktopFileName(short vRefNum,
1443
pb.fileParam.ioNamePtr = desktopName;
1444
pb.fileParam.ioVRefNum = vRefNum;
1445
pb.fileParam.ioFVersNum = 0;
1450
pb.fileParam.ioDirID = fsRtDirID;
1451
pb.fileParam.ioFDirIndex = index;
1452
error = PBHGetFInfoSync(&pb);
1453
if ( error == noErr )
1455
if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
1456
(pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
1462
} while ( (error == noErr) && !found );
1468
/*****************************************************************************/
1470
pascal OSErr XGetVInfo(short volReference,
1473
UnsignedWide *freeBytes,
1474
UnsignedWide *totalBytes)
1480
/* See if large volume support is available */
1481
if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
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 )
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;
1495
/* return the freeBytes and totalBytes */
1496
*totalBytes = pb.ioVTotalBytes;
1497
*freeBytes = pb.ioVFreeBytes;
1502
/* No large volume support */
1504
/* Use HGetVInfo to get the results */
1505
result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
1506
if ( result == noErr )
1508
/* zero the high longs of totalBytes and freeBytes */
1518
/*****************************************************************************/
1520
pascal OSErr HGetVInfo(short volReference,
1523
unsigned long *freeBytes,
1524
unsigned long *totalBytes)
1527
unsigned long allocationBlockSize;
1528
unsigned short numAllocationBlocks;
1529
unsigned short numFreeBlocks;
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);
1540
if ( result == noErr )
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;
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. */
1556
/* Find the volume's VCB */
1558
theVCB = (VCB *)(GetVCBQHdr()->qHead);
1559
while ( (theVCB != NULL) && !vcbFound )
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 )
1565
if ( theVCB->vcbVRefNum == *vRefNum )
1573
theVCB = (VCB *)(theVCB->qLink);
1577
if ( theVCB != NULL )
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;
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;
1592
/* Now, calculate freeBytes and totalBytes using unsigned values */
1593
*freeBytes = numFreeBlocks * allocationBlockSize;
1594
*totalBytes = numAllocationBlocks * allocationBlockSize;
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).
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
1613
#if __WANTPASCALELIMINATION
1618
pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
1622
kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */
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)))
1632
return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
1633
uppFSDispatchProcInfo,
1635
kXGetVolInfoSelector,
1640
#if __WANTPASCALELIMINATION
1644
/*****************************************************************************/
1646
pascal OSErr GetDirName(short vRefNum,
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);
1670
/*****************************************************************************/
1672
pascal OSErr GetVolFileSystemID(ConstStr255Param pathname,
1674
short *fileSystemID)
1679
error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
1680
if ( error == noErr )
1682
*fileSystemID = pb.volumeParam.ioVFSID;
1688
/*****************************************************************************/
1690
pascal OSErr GetDInfo(short vRefNum,
1692
ConstStr255Param name,
1698
error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
1699
if ( error == noErr )
1701
if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
1703
/* it's a directory, return the DInfo */
1704
*fndrInfo = pb.dirInfo.ioDrUsrWds;
1708
/* oops, a file was passed */
1716
/*****************************************************************************/
1718
pascal OSErr FSpGetDInfo(const FSSpec *spec,
1721
return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
1726
const char *BOINC_RCSID_fc2d06db64 = "$Id: macstuff.c 4979 2005-01-02 18:29:53Z ballen $";