macstuff.c 52 KB

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