filespecutils.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:32k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: filespecutils.cpp,v 1.1.1.1.50.3 2004/07/09 01:44:13 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "filespec.h"
  50. #include "filespecutils.h"
  51. #include "hxstring.h"
  52. #include "hxtick.h"
  53. #include "hxrand.h"
  54. #include "carray.h"
  55. #ifndef _CARBON
  56. #include "morefilesextras.h"
  57. #else
  58. #include "MoreFilesX.h"
  59. #endif
  60. // ------------------------------------------------------------------------------------
  61. //
  62. // GetFreeSpaceOnDisk
  63. //
  64. // ------------------------------------------------------------------------------------
  65. HX_RESULT CHXFileSpecUtils::GetFreeSpaceOnDisk(const CHXDirSpecifier& volSpec, INT64& freeSpace)
  66. {
  67. HX_RESULT err;
  68. FSSpec targetSpec;
  69. #ifdef _CARBON
  70. UInt64 freeBytes;
  71. UInt64 totalBytes;
  72. #else
  73. short foundVRefNum;
  74. UnsignedWide freeBytes;
  75. UnsignedWide totalBytes;
  76. #endif
  77. require_return(volSpec.IsSet(), HXR_INVALID_PARAMETER);
  78. targetSpec = volSpec;
  79. const StringPtr kDontCareVolName = NULL;
  80. #ifndef _CARBON
  81. err = XGetVInfo(targetSpec.vRefNum, kDontCareVolName, &foundVRefNum, &freeBytes, &totalBytes);
  82. #else
  83. err = FSGetVInfo(targetSpec.vRefNum, (HFSUniStr255*) kDontCareVolName, &freeBytes, &totalBytes);
  84. #endif
  85. if (err == noErr)
  86. {
  87. freeSpace = *(long long *) &freeBytes;
  88. }
  89. return err;
  90. }
  91. // ------------------------------------------------------------------------------------
  92. //
  93. // GetTotalSpaceOnDisk
  94. //
  95. // ------------------------------------------------------------------------------------
  96. HX_RESULT CHXFileSpecUtils::GetTotalSpaceOnDisk(const CHXDirSpecifier& volSpec, INT64& totalSpace)
  97. {
  98. HX_RESULT err;
  99. FSSpec targetSpec;
  100. #ifdef _CARBON
  101. UInt64 freeBytes;
  102. UInt64 totalBytes;
  103. #else
  104. UnsignedWide freeBytes;
  105. UnsignedWide totalBytes;
  106. short foundVRefNum;
  107. #endif
  108. require_return(volSpec.IsSet(), HXR_INVALID_PARAMETER);
  109. targetSpec = volSpec;
  110. const StringPtr kDontCareVolName = NULL;
  111. #ifndef _CARBON
  112. err = XGetVInfo(targetSpec.vRefNum, kDontCareVolName, &foundVRefNum, &freeBytes, &totalBytes);
  113. #else
  114. err = FSGetVInfo(targetSpec.vRefNum, (HFSUniStr255*) kDontCareVolName, &freeBytes, &totalBytes);
  115. #endif
  116. if (err == noErr)
  117. {
  118. totalSpace = *(long long *) &totalBytes;
  119. }
  120. return err;
  121. }
  122. // ------------------------------------------------------------------------------------
  123. //
  124. // IsFileLocal
  125. // IsDirectoryLocal
  126. //
  127. // ------------------------------------------------------------------------------------
  128. BOOL CHXFileSpecUtils::IsDiskLocal(const CHXDirSpecifier& volSpec)
  129. {
  130. HParamBlockRec pb;
  131. HX_RESULT err;
  132. FSSpec targetSpec;
  133. GetVolParmsInfoBuffer buff;
  134. BOOL bLocalVol;
  135. require_return(volSpec.IsSet(), FALSE);
  136. targetSpec = volSpec;
  137. ZeroInit(&pb);
  138. pb.ioParam.ioVRefNum = targetSpec.vRefNum;
  139. pb.ioParam.ioBuffer = (Ptr) &buff;
  140. pb.ioParam.ioReqCount = sizeof(buff);
  141. err = PBHGetVolParmsSync(&pb);
  142. check_noerr(err);
  143. if (err == noErr)
  144. {
  145. bLocalVol = (buff.vMServerAdr == 0);
  146. }
  147. else
  148. {
  149. // error occurred, default to true
  150. bLocalVol = TRUE;
  151. }
  152. return bLocalVol;
  153. }
  154. // ------------------------------------------------------------------------------------
  155. //
  156. // IsDiskEjectable
  157. //
  158. // ------------------------------------------------------------------------------------
  159. BOOL CHXFileSpecUtils::IsDiskEjectable(const CHXDirSpecifier& volSpec)
  160. {
  161. #ifdef _CARBON
  162. OSErr err;
  163. FSSpec targetSpec;
  164. GetVolParmsInfoBuffer  volParmsInfo;
  165. HParamBlockRec pb;
  166. require_return(volSpec.IsSet(), FALSE);
  167. targetSpec = volSpec;
  168. ZeroInit(&volParmsInfo);
  169. ZeroInit(&pb);
  170. pb.ioParam.ioVRefNum = targetSpec.vRefNum;
  171. pb.ioParam.ioBuffer = (Ptr) &volParmsInfo;
  172. pb.ioParam.ioReqCount = sizeof(volParmsInfo);
  173. err = PBHGetVolParmsSync(&pb);
  174. if (err == noErr)
  175. {
  176. // we require version 3 of the info buffer to rely on the vMExtendedAttributes
  177. if (volParmsInfo.vMVersion >= 3)
  178. {
  179. if (volParmsInfo.vMExtendedAttributes & (1L << bIsEjectable))
  180. {
  181. return TRUE;
  182. }
  183. }
  184. }
  185. return FALSE;
  186. #else
  187. HX_RESULT err;
  188. FSSpec targetSpec;
  189. Boolean driverWantsEject, driveEjectable, volumeEjected, volumeOnline;
  190. require_return(volSpec.IsSet(), FALSE);
  191. targetSpec = volSpec;
  192. const StringPtr kDontCareVolName = NULL;
  193. err = GetVolState(kDontCareVolName, targetSpec.vRefNum, &volumeOnline, &volumeEjected,
  194. &driveEjectable, &driverWantsEject);
  195. check_noerr(err);
  196. if (err == noErr)
  197. {
  198. return driveEjectable;
  199. }
  200. else
  201. {
  202. return FALSE;
  203. }
  204. #endif
  205. }
  206. // ------------------------------------------------------------------------------------
  207. //
  208. // IsDiskWritable
  209. //
  210. // ------------------------------------------------------------------------------------
  211. BOOL CHXFileSpecUtils::IsDiskWritable(const CHXDirSpecifier& volSpec)
  212. {
  213. OSErr err;
  214. FSSpec targetSpec;
  215. require_return(volSpec.IsSet(), FALSE);
  216. targetSpec = volSpec;
  217. HParamBlockRec hpb;
  218. ZeroInit(&hpb);
  219. hpb.volumeParam.ioVolIndex = 0;
  220. hpb.volumeParam.ioVRefNum = targetSpec.vRefNum;
  221. err = PBHGetVInfoSync(&hpb);
  222. check_noerr(err);
  223. if (err == noErr)
  224. {
  225. if ((hpb.volumeParam.ioVAtrb & 0x8080) != 0) // locked, software or hardware, per tech note FL 530
  226. {
  227. return FALSE; // not writable
  228. }
  229. }
  230. return TRUE;
  231. }
  232. // ------------------------------------------------------------------------------------
  233. //
  234. // GetFileSize
  235. //
  236. // ------------------------------------------------------------------------------------
  237. HX_RESULT CHXFileSpecUtils::GetFileSize(const CHXFileSpecifier& fileSpec, INT64& fSize)
  238. {
  239. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  240. #ifdef USE_FSREFS
  241. HX_RESULT err;
  242. FSRef targetRef;
  243. UInt64 logicalSize, physicalSize;
  244. ItemCount numForks;
  245. targetRef = fileSpec;
  246. err = FSGetTotalForkSizes(&targetRef, &logicalSize, &physicalSize, &numForks);
  247. if (err == noErr)
  248. {
  249. fSize = (INT64) logicalSize;
  250. }
  251. return err;
  252. #else
  253. HX_RESULT err;
  254. FSSpec targetSpec;
  255. targetSpec = fileSpec;
  256. HParamBlockRec pb;
  257. ZeroInit(&pb);
  258. pb.fileParam.ioVRefNum = targetSpec.vRefNum;
  259. pb.fileParam.ioDirID = targetSpec.parID;
  260. pb.fileParam.ioNamePtr = targetSpec.name;
  261. pb.fileParam.ioFDirIndex = 0;
  262. err = PBHGetFInfoSync(&pb);
  263. check_noerr(err);
  264. if ( err == noErr )
  265. {
  266. fSize = (INT64) pb.fileParam.ioFlLgLen;
  267. fSize += (INT64) pb.fileParam.ioFlRLgLen;
  268. }
  269. return err;
  270. #endif
  271. }
  272. // ------------------------------------------------------------------------------------
  273. //
  274. // GetDirectorySize
  275. //
  276. // ------------------------------------------------------------------------------------
  277. HX_RESULT CHXFileSpecUtils::GetDirectorySize(const CHXDirSpecifier& dirSpec, BOOL shouldDescend, INT64& fSize)
  278. {
  279. // rather than literally recurse through the directory tree, this routine
  280. // will keep an array of directories yet to be added to the total size
  281. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  282. CHXPtrArray specArray;
  283. CHXDirSpecifier *pCurrDirSpec;
  284. INT64 totalSize;
  285. // push a copy of the initial directory spec into the array; 
  286. // it will be deleted when it is popped off
  287. pCurrDirSpec = new CHXDirSpecifier(dirSpec);
  288. require_nonnull_return(pCurrDirSpec, HXR_OUTOFMEMORY);
  289. specArray.Add(pCurrDirSpec);
  290. totalSize = 0;
  291. while (!specArray.IsEmpty())
  292. {
  293. FSSpec targetFSSpec;
  294. OSErr err;
  295. CInfoPBRec pb;
  296. short vRefNum;
  297. long currentDirID, index;
  298. Str63 fileName;
  299. Boolean bDoneWithThisDirectory;
  300. // grab a dirSpec from the array, delete the object, 
  301. // and step through all items in the directory
  302. pCurrDirSpec = (CHXDirSpecifier *) specArray.ElementAt(0);
  303. check_nonnull(pCurrDirSpec);
  304. if (pCurrDirSpec)
  305. {
  306. targetFSSpec = *pCurrDirSpec;
  307. currentDirID = pCurrDirSpec->GetDirID();
  308. vRefNum = targetFSSpec.vRefNum;
  309. // remove this dirSpec from our array and delete the object
  310. specArray.RemoveAt(0);
  311. HX_DELETE(pCurrDirSpec);
  312. check(vRefNum != 0 && currentDirID != 0);
  313. if (vRefNum != 0 && currentDirID != 0)
  314. {
  315. // step through all items in this directory
  316. index = 0;
  317. bDoneWithThisDirectory = false;
  318. while (!bDoneWithThisDirectory)
  319. {
  320. index++;
  321. ZeroInit(&pb);
  322. fileName[0] = 0;
  323. pb.hFileInfo.ioVRefNum = vRefNum;
  324. pb.hFileInfo.ioDirID = currentDirID;
  325. pb.hFileInfo.ioNamePtr = fileName;
  326. pb.hFileInfo.ioFDirIndex = index;
  327. err = PBGetCatInfoSync(&pb);
  328. if (err != noErr)
  329. {
  330. // no more items in this directory
  331. bDoneWithThisDirectory = true;
  332. }
  333. else
  334. {
  335. if ((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0)
  336. {
  337. // it's a file; add its size
  338. totalSize += (INT64) pb.hFileInfo.ioFlLgLen; // data fork
  339. totalSize += (INT64) pb.hFileInfo.ioFlRLgLen; // resource fork
  340. }
  341. else
  342. {
  343. // it's a directory; add a dirSpec for it to the array
  344. if (shouldDescend)
  345. {
  346. CHXDirSpecifier *pNewDirSpec;
  347. err = FSMakeFSSpec(vRefNum, currentDirID, fileName, &targetFSSpec);
  348. check_noerr(err);
  349. pNewDirSpec = new CHXDirSpecifier(targetFSSpec);
  350. check_nonnull(pNewDirSpec);
  351. if (pNewDirSpec)
  352. {
  353. specArray.Add(pNewDirSpec);
  354. }
  355. }
  356. }
  357. }
  358. } // while (!bDoneWithThisDirectory)
  359. }
  360. }
  361. } // while(!specArray.IsEmpty())
  362. fSize = totalSize;
  363. return HXR_OK;
  364. }
  365. // ------------------------------------------------------------------------------------
  366. //
  367. // GetCurrentApplication
  368. // GetCurrentApplicationDir
  369. //
  370. // ------------------------------------------------------------------------------------
  371. CHXFileSpecifier CHXFileSpecUtils::GetCurrentApplication()
  372. {
  373. OSErr err;
  374. FSSpec  appFSSpec;
  375. ProcessSerialNumber  appPSN = { 0, kCurrentProcess };
  376. ProcessInfoRec  appPIR;
  377. CHXFileSpecifier  appSpec;
  378. appPIR.processInfoLength = sizeof(ProcessInfoRec);
  379. appPIR.processAppSpec = &appFSSpec;
  380. appPIR.processName = NULL;
  381. err = GetProcessInformation(&appPSN, &appPIR);
  382. check_noerr(err);
  383. if (err == noErr)
  384. {
  385. appSpec = appFSSpec;
  386. }
  387. return appSpec;
  388. }
  389. CHXDirSpecifier CHXFileSpecUtils::GetCurrentApplicationDir()
  390. {
  391. CHXFileSpecifier  appSpec;
  392. CHXDirSpecifier  dirSpec;
  393. appSpec = GetCurrentApplication();
  394. if (appSpec.IsSet())
  395. {
  396. dirSpec = appSpec.GetParentDirectory();
  397. }
  398. return dirSpec;
  399. }
  400. // ------------------------------------------------------------------------------------
  401. //
  402. // FileExists
  403. // DirectoryExists
  404. //
  405. // ------------------------------------------------------------------------------------
  406. #ifndef USE_FSREFS
  407. static BOOL FSSpecExists(FSSpecPtr itemSpec, BOOL *isDirectory); // Forward declaration
  408. BOOL CHXFileSpecUtils::FileExists(const CHXFileSpecifier& fileSpec)
  409. {
  410. FSSpec  fileFSSpec;
  411. BOOL isDirectory;
  412. require_return(fileSpec.IsSet(), FALSE);
  413. fileFSSpec = fileSpec;
  414. return FSSpecExists(&fileFSSpec, &isDirectory) && !isDirectory;
  415. }
  416. BOOL CHXFileSpecUtils::DirectoryExists(const CHXDirSpecifier& dirSpec)
  417. {
  418. FSSpec  dirFSSpec;
  419. BOOL isDirectory;
  420. require_return(dirSpec.IsSet(), FALSE);
  421. dirFSSpec = dirSpec;
  422. return FSSpecExists(&dirFSSpec, &isDirectory) && isDirectory;
  423. }
  424. static BOOL FSSpecExists(FSSpecPtr itemSpec, BOOL *isDirectory)
  425. {
  426. OSErr err;
  427. CInfoPBRec cInfo;
  428. FSSpec tempSpec;
  429. BOOL bExists;
  430. bExists = FALSE;
  431. // copy the provided file spec so PBGetCatInfo doesn't change the name
  432. tempSpec = *itemSpec;
  433. cInfo.dirInfo.ioVRefNum = tempSpec.vRefNum;
  434. cInfo.dirInfo.ioDrDirID = tempSpec.parID;
  435. cInfo.dirInfo.ioNamePtr = tempSpec.name;
  436. cInfo.dirInfo.ioFDirIndex = 0; // use name, vRefNum, and dirID
  437. err = PBGetCatInfoSync(&cInfo);
  438. if (err == noErr)
  439. {
  440. bExists = TRUE;
  441. if (isDirectory)
  442. {
  443. if ((cInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0)
  444. {
  445. *isDirectory = TRUE;
  446. }
  447. else
  448. {
  449. *isDirectory = FALSE;
  450. }
  451. }
  452. }
  453. return bExists;
  454. }
  455. #else // defined USE_FSREFS
  456. static BOOL FSRefExists(const FSRef * itemSpec, BOOL *isDirectory); // Forward declaration
  457. BOOL CHXFileSpecUtils::FileExists(const CHXFileSpecifier& fileSpec)
  458. {
  459. FSRef  fileRef;
  460. BOOL isDirectory;
  461. require_return(fileSpec.IsSet(), FALSE);
  462. fileRef = fileSpec;
  463.   return FSRefExists(&fileRef, &isDirectory) && !isDirectory;
  464. }
  465. BOOL CHXFileSpecUtils::DirectoryExists(const CHXDirSpecifier& dirSpec)
  466. {
  467. FSRef  dirRef;
  468. BOOL isDirectory;
  469. require_return(dirSpec.IsSet(), FALSE);
  470. dirRef = dirSpec;
  471. return FSRefExists(&dirRef, &isDirectory) && isDirectory;
  472. }
  473. static BOOL FSRefExists(const FSRef *itemRef, BOOL *isDirectory)
  474. {
  475. OSErr err;
  476. BOOL bExists;
  477. FSCatalogInfo  catInfo;
  478. const FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeID | kFSCatInfoNodeFlags;
  479. HFSUniStr255 * kDontWantName = NULL;
  480. FSSpec * kDontWantFSSpec = NULL;
  481. FSRef * kDontWantParentRef = NULL;
  482. bExists = FALSE;
  483. err = ::FSGetCatalogInfo(itemRef, whichInfo, &catInfo,
  484. kDontWantName, kDontWantFSSpec, kDontWantParentRef);
  485. if (err == noErr)
  486. {
  487. bExists = TRUE;
  488. if (isDirectory)
  489. {
  490. if ((catInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0)
  491. {
  492. *isDirectory = TRUE;
  493. }
  494. else
  495. {
  496. *isDirectory = FALSE;
  497. }
  498. }
  499. }
  500. return bExists;
  501. }
  502. #endif // defined USE_FSREFS
  503. // ------------------------------------------------------------------------------------
  504. //
  505. // CreateDirectory
  506. //
  507. // ------------------------------------------------------------------------------------
  508. HX_RESULT CHXFileSpecUtils::CreateDir(const CHXDirSpecifier& dirSpec)
  509. {
  510. FSSpec  dirFSSpec;
  511. long dirID;
  512. OSErr err;
  513. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  514. dirFSSpec = dirSpec;
  515. err = FSpDirCreate(&dirFSSpec, smSystemScript, &dirID);
  516. return err;
  517. }
  518. // ------------------------------------------------------------------------------------
  519. //
  520. // RemoveDir - deletes an empty directory
  521. //
  522. // ------------------------------------------------------------------------------------
  523. HX_RESULT CHXFileSpecUtils::RemoveDir(const CHXDirSpecifier& dirSpec)
  524. {
  525. FSSpec  dirFSSpec;
  526. OSErr err;
  527. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  528. dirFSSpec = dirSpec;
  529. err = FSpDelete(&dirFSSpec);
  530. return err;
  531. }
  532. // ------------------------------------------------------------------------------------
  533. //
  534. // RemoveFile
  535. //
  536. // ------------------------------------------------------------------------------------
  537. HX_RESULT CHXFileSpecUtils::RemoveFile(const CHXFileSpecifier& fileSpec)
  538. {
  539. FSSpec  fileFSSpec;
  540. OSErr err;
  541. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  542. fileFSSpec = fileSpec;
  543. err = FSpDelete(&fileFSSpec);
  544. return err;
  545. }
  546. // ------------------------------------------------------------------------------------
  547. //
  548. // GetFileType
  549. //
  550. // ------------------------------------------------------------------------------------
  551. FOURCC CHXFileSpecUtils::GetFileType(const CHXFileSpecifier& fileSpec)
  552. {
  553. FOURCC fileType;
  554. OSErr err;
  555. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  556. fileType = 0;
  557. if (fileSpec.IsSet())
  558. {
  559. #ifdef USE_FSREFS
  560. FSRef fileRef;
  561. FinderInfo fndrInfo;
  562. Boolean isDir;
  563. ExtendedFinderInfo * kDontWantExtendedInfo = NULL;
  564. fileRef = fileSpec;
  565. err = FSGetFinderInfo(&fileRef, &fndrInfo, kDontWantExtendedInfo, &isDir);
  566. if ((err == noErr) && !isDir)
  567. {
  568. fileType = fndrInfo.file.fileType;
  569. }
  570. #else
  571. FSSpec fileFSSpec;
  572. FInfo fndrInfo;
  573. fileFSSpec = fileSpec;
  574. err = FSpGetFInfo(&fileFSSpec, &fndrInfo);
  575. check_noerr(err);
  576. if (err == noErr)
  577. {
  578. fileType = fndrInfo.fdType;
  579. }
  580. #endif
  581. }
  582. return fileType;
  583. }
  584. // ------------------------------------------------------------------------------------
  585. //
  586. // MakeNameLegal
  587. //
  588. // returns TRUE if the name was changed
  589. //
  590. // ------------------------------------------------------------------------------------
  591. BOOL CHXFileSpecUtils::MakeNameLegal(char *pszName)
  592. {
  593. const char *badChars = ":";
  594. const char replacementChar = '-';
  595. const long maxNameLength = 31;
  596. long len, idx;
  597. BOOL bChanged;
  598. require_nonnull_return(pszName, FALSE);
  599. bChanged = FALSE;
  600. len = strlen(pszName);
  601. // replace any illegal characters
  602. for (idx = 0; idx < len; idx++)
  603. {
  604. if (strchr(badChars, pszName[idx]))
  605. {
  606. pszName[idx] = replacementChar;
  607. bChanged = TRUE;
  608. }
  609. }
  610. // be sure the name isn't too long
  611. if (len > maxNameLength)
  612. {
  613. pszName[maxNameLength] = 0;
  614. bChanged = TRUE;
  615. }
  616. return bChanged;
  617. }
  618. // ------------------------------------------------------------------------------------
  619. //
  620. // FindFolder
  621. //
  622. // ------------------------------------------------------------------------------------
  623. CHXDirSpecifier CHXFileSpecUtils::MacFindFolder(short vRefNum, FolderType foldType)
  624. {
  625. short  foundVRefNum;
  626. long  foundDirID;
  627. FSSpec targetSpec;
  628. CHXDirSpecifier foundDirSpec;
  629. OSErr err;
  630. err = ::FindFolder(vRefNum, foldType, kCreateFolder, &foundVRefNum, &foundDirID);
  631. if (err == noErr)
  632. {
  633. err = FSMakeFSSpec(foundVRefNum, foundDirID, "p", &targetSpec);
  634. check_noerr(err);
  635. if (err == noErr)
  636. {
  637. foundDirSpec = targetSpec;
  638. }
  639. }
  640. return foundDirSpec;
  641. }
  642. CHXFileSpecifier CHXFileSpecUtils::SpecifyFileWithMacFindFolder(short vRefNum, FolderType foldType, const char *pszChildFile)
  643. {
  644. CHXDirSpecifier parentDir;
  645. CHXFileSpecifier targetFile;
  646. parentDir = CHXFileSpecUtils::MacFindFolder(vRefNum, foldType);
  647. check(parentDir.IsSet());
  648. if (CHXFileSpecUtils::DirectoryExists(parentDir))
  649. {
  650. targetFile = parentDir.SpecifyChildFile(pszChildFile);
  651. }
  652. return targetFile;
  653. }
  654. CHXDirSpecifier CHXFileSpecUtils::SpecifyFolderWithMacFindFolder(short vRefNum, FolderType foldType, const char *pszChildFolder)
  655. {
  656. CHXDirSpecifier parentDir;
  657. CHXDirSpecifier targetDir;
  658. parentDir = CHXFileSpecUtils::MacFindFolder(vRefNum, foldType);
  659. check(parentDir.IsSet());
  660. if (CHXFileSpecUtils::DirectoryExists(parentDir))
  661. {
  662. targetDir = parentDir.SpecifyChildDirectory(pszChildFolder);
  663. }
  664. return targetDir;
  665. }
  666. // ------------------------------------------------------------------------------------
  667. //
  668. // ResolveFileSpecifierAlias
  669. // ResolveDirSpecifierAlias
  670. //
  671. // These resolve a file spec to an alias file in place
  672. //
  673. // ------------------------------------------------------------------------------------
  674. HX_RESULT CHXFileSpecUtils::ResolveFileSpecifierAlias(CHXFileSpecifier& fileSpec)
  675. {
  676. HX_RESULT res;
  677. res = HXR_FAIL;
  678. if (fileSpec.IsSet())
  679. {
  680. FSSpec fileFSSpec;
  681. OSErr err;
  682. Boolean bIsFolder;
  683. Boolean bWasAliased;
  684. const Boolean kShouldResolveChains = true;
  685. fileFSSpec = fileSpec;
  686. err = ResolveAliasFileWithMountFlags(&fileFSSpec, kShouldResolveChains,
  687. &bIsFolder, &bWasAliased, kResolveAliasFileNoUI);
  688. check(err == noErr);
  689. if ((err == noErr) && !bIsFolder)
  690. {
  691. res = HXR_OK;
  692. if (bWasAliased)
  693. {
  694. fileSpec = fileFSSpec;
  695. }
  696. }
  697. else
  698. {
  699. // error occurred
  700. }
  701. }
  702. return res;
  703. }
  704. HX_RESULT CHXFileSpecUtils::ResolveDirSpecifierAlias(CHXDirSpecifier& dirSpec)
  705. {
  706. HX_RESULT res;
  707. res = HXR_FAIL;
  708. if (dirSpec.IsSet())
  709. {
  710. FSSpec dirFSSpec;
  711. OSErr err;
  712. Boolean bIsFolder;
  713. Boolean bWasAliased;
  714. const Boolean kShouldResolveChains = true;
  715. dirFSSpec = dirSpec;
  716. err = ResolveAliasFileWithMountFlags(&dirFSSpec, kShouldResolveChains,
  717. &bIsFolder, &bWasAliased, kResolveAliasFileNoUI);
  718. if ((err == noErr) && bIsFolder)
  719. {
  720. res = HXR_OK;
  721. if (bWasAliased)
  722. {
  723. dirSpec = dirFSSpec;
  724. }
  725. }
  726. else
  727. {
  728. // error occurred
  729. }
  730. }
  731. return res;
  732. }
  733. // ------------------------------------------------------------------------------------
  734. //
  735. // MoveFileToTrash
  736. // MoveFolderToTrash
  737. // MoveFileToFolderWithRenaming
  738. // MoveFolderToFolderWithRenaming
  739. //
  740. // ------------------------------------------------------------------------------------
  741. static HX_RESULT MoveToFolderWithRenamingInternal(const FSSpec* itemFSSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove);
  742. HX_RESULT CHXFileSpecUtils::MoveFileToTrash(const CHXFileSpecifier& fileSpec) 
  743. {
  744. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  745. CHXDirSpecifier trashSpec;
  746. FSSpec itemFSSpec;
  747. itemFSSpec = fileSpec;
  748. trashSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kTrashFolderType);
  749. return MoveToFolderWithRenamingInternal(&itemFSSpec, trashSpec, TRUE);
  750. }
  751. HX_RESULT CHXFileSpecUtils::MoveFolderToTrash(const CHXDirSpecifier& dirSpec) 
  752. {
  753. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  754. CHXDirSpecifier trashSpec;
  755. FSSpec itemFSSpec;
  756. itemFSSpec = dirSpec;
  757. trashSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kTrashFolderType);
  758. return MoveToFolderWithRenamingInternal(&itemFSSpec, trashSpec, TRUE);
  759. }
  760. HX_RESULT CHXFileSpecUtils::MoveFileToCleanupAtStartup(const CHXFileSpecifier& fileSpec, BOOL bDeleteIfCantMove) 
  761. {
  762. CHXFileSpecifier nonConstFileSpec(fileSpec);
  763. return MoveFileToCleanupAtStartup(nonConstFileSpec, bDeleteIfCantMove);
  764. }
  765. HX_RESULT CHXFileSpecUtils::MoveFileToCleanupAtStartup(CHXFileSpecifier& fileSpec, BOOL bDeleteIfCantMove) 
  766. {
  767. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  768. CHXDirSpecifier cleanupSpec;
  769. FSSpec itemFSSpec;
  770. itemFSSpec = fileSpec;
  771. cleanupSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kChewableItemsFolderType);
  772. return MoveToFolderWithRenamingInternal(&itemFSSpec, cleanupSpec, TRUE);
  773. }
  774. HX_RESULT CHXFileSpecUtils::MoveFolderToCleanupAtStartup(const CHXDirSpecifier& dirSpec, BOOL bDeleteIfCantMove) 
  775. {
  776. CHXDirSpecifier nonConstDirSpec(dirSpec);
  777. return MoveFolderToCleanupAtStartup(nonConstDirSpec, bDeleteIfCantMove);
  778. }
  779. HX_RESULT CHXFileSpecUtils::MoveFolderToCleanupAtStartup(CHXDirSpecifier& dirSpec, BOOL bDeleteIfCantMove) 
  780. {
  781. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  782. CHXDirSpecifier cleanupSpec;
  783. FSSpec itemFSSpec;
  784. itemFSSpec = dirSpec;
  785. cleanupSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kChewableItemsFolderType);
  786. return MoveToFolderWithRenamingInternal(&itemFSSpec, cleanupSpec, TRUE);
  787. }
  788. HX_RESULT CHXFileSpecUtils::MoveFileToFolderWithRenaming(CHXFileSpecifier& fileSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  789. {
  790. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  791. if (!CHXFileSpecUtils::DirectoryExists(targetSpec)) return HXR_INVALID_PARAMETER;
  792. FSSpec fsSpec;
  793. fsSpec = fileSpec;
  794. return MoveToFolderWithRenamingInternal(&fsSpec, targetSpec, bDeleteIfCantMove);
  795. }
  796. HX_RESULT CHXFileSpecUtils::MoveFolderToFolderWithRenaming(CHXDirSpecifier& dirSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  797. {
  798. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  799. if (!CHXFileSpecUtils::DirectoryExists(targetSpec)) return HXR_INVALID_PARAMETER;
  800. FSSpec fsSpec;
  801. fsSpec = dirSpec;
  802. return MoveToFolderWithRenamingInternal(&fsSpec, targetSpec, bDeleteIfCantMove);
  803. }
  804. static HX_RESULT MoveToFolderWithRenamingInternal(const FSSpec* itemFSSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  805. {
  806. check_nonnull(itemFSSpec);
  807. HX_RESULT pnres;
  808. OSErr err;
  809. FSSpec targetFSSpec;
  810. pnres = HXR_FAILED;
  811. // find the trash for the disk containing the file
  812. if (!targetSpec.IsSet())
  813. {
  814. // targetSpec wasn't set, nowhere to move to
  815. if (bDeleteIfCantMove)
  816. {
  817. err = FSpDelete(itemFSSpec);
  818. if (err == noErr)
  819. {
  820. pnres = HXR_OK;
  821. }
  822. }
  823. }
  824. else
  825. {
  826. // targetSpec is set
  827. //
  828. // try to move the file to the target
  829. targetFSSpec = targetSpec;
  830. err = CatMove(itemFSSpec->vRefNum, itemFSSpec->parID, itemFSSpec->name, targetFSSpec.parID, targetFSSpec.name);
  831. if (err == noErr)
  832. {
  833. pnres = HXR_OK;
  834. }
  835. else if (err == dupFNErr)
  836. {
  837. // there's a name conflict; find a unique name for the file we're moving in the
  838. // target folder, rename it, and then move it again
  839. CHXString strName, strTemplate;
  840. CHXFileSpecifier specNewNamedFile;
  841. strName.SetFromStr255(itemFSSpec->name); // make a template like "filename_N"
  842. strTemplate = strName + "_%-%-%";
  843. specNewNamedFile = CHXFileSpecUtils::GetUniqueFileSpec(targetSpec, strName, strTemplate, "%-%-%");
  844. err = FSpRename(itemFSSpec, (ConstStr255Param) specNewNamedFile.GetName());
  845. if (err == noErr)
  846. {
  847. err = CatMove(itemFSSpec->vRefNum, itemFSSpec->parID, (ConstStr255Param) specNewNamedFile.GetName(), 
  848. targetFSSpec.parID, targetFSSpec.name);
  849. if (err == noErr)
  850. {
  851. pnres = HXR_OK;
  852. }
  853. else if (err != noErr && bDeleteIfCantMove)
  854. {
  855. // couldn't move it; delete the renamed file
  856. err = HDelete(itemFSSpec->vRefNum, itemFSSpec->parID, (ConstStr255Param) specNewNamedFile.GetName());
  857. if (err == noErr)
  858. {
  859. pnres = HXR_OK;
  860. }
  861. }
  862. else
  863. {
  864. // couldn't move it; change the name back
  865. err = FSpRename((FSSpec *) specNewNamedFile, itemFSSpec->name);
  866. }
  867. }
  868. else
  869. {
  870. // rename failed for some reason
  871. if (bDeleteIfCantMove)
  872. {
  873. err = FSpDelete(itemFSSpec);
  874. if (err == noErr)
  875. {
  876. pnres = HXR_OK;
  877. }
  878. }
  879. }
  880. else
  881. {
  882. // catmove failed for some unknown reason, not a name conflict
  883. if (bDeleteIfCantMove)
  884. {
  885. err = FSpDelete(itemFSSpec);
  886. if (err == noErr)
  887. {
  888. pnres = HXR_OK;
  889. }
  890. }
  891. }
  892. }
  893. return pnres;
  894. }
  895. // ------------------------------------------------------------------------------------
  896. //
  897. // GetSystemTempDirectory
  898. //
  899. // ------------------------------------------------------------------------------------
  900. CHXDirSpecifier CHXFileSpecUtils::GetSystemTempDirectory()
  901. {
  902. return CHXFileSpecUtils::MacFindFolder(kOnSystemDisk, kChewableItemsFolderType);
  903. }
  904. // ------------------------------------------------------------------------------------
  905. //
  906. // GetUniqueFileSpec
  907. // GetUniqueTempFileSpec
  908. //
  909. // ------------------------------------------------------------------------------------
  910. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  911. const char *pszNameFirst, const char *pszTemplate, 
  912. const char *pszWildcard, UINT32 nStartNum);
  913. const UINT32 kNumWrapValue = 9999+1; // limit insertions to 4-digit numbers
  914. CHXFileSpecifier CHXFileSpecUtils::GetUniqueFileSpec(const CHXDirSpecifier& locationSpec, 
  915. const char *pszNameFirst, const char *pszTemplate, 
  916. const char *pszWildcard)
  917. {
  918. return GetUniqueFileSpecInternal(locationSpec, pszNameFirst, pszTemplate, pszWildcard, 0);
  919. }
  920. CHXFileSpecifier CHXFileSpecUtils::GetUniqueTempFileSpec(const CHXDirSpecifier& locationSpec, 
  921. const char *pszTemplate, const char *pszWildcard)
  922. {
  923. CMultiplePrimeRandom  rand(HX_GET_TICKCOUNT());
  924. UINT32 num;
  925. num = rand.GetRandomNumber();
  926. num %= kNumWrapValue;
  927. // skip 0, which means "don't substitute for the wildcard", and 1
  928. if (num == 0 || num == 1) num = 2;
  929. return GetUniqueFileSpecInternal(locationSpec, NULL, pszTemplate, pszWildcard, num);
  930. }
  931. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  932. const char *pszNameFirst, const char *pszTemplate, 
  933. const char *pszWildcard, UINT32 nStartNum)
  934. {
  935. CHXFileSpecifier  resultFileSpec;
  936. require_return(locationSpec.IsSet(), resultFileSpec);
  937. require_return(pszTemplate != NULL && pszWildcard != NULL, resultFileSpec);
  938. require_return(pszNameFirst != NULL || nStartNum != 0, resultFileSpec);
  939. CHXFileSpecifier  testFileSpec;
  940. CHXDirSpecifier  testDirSpec;
  941. CHXString strNumber;
  942. CHXString strName;
  943. UINT32 nCurrentNum;
  944. nCurrentNum = nStartNum;
  945. while (1) 
  946. {
  947. // if the number is non-zero, make a string from the template;
  948. // if the number is zero, user the initial name string
  949. if (nCurrentNum == 0)
  950. {
  951. // replace the wildcard in the template with the number string
  952. strName = pszNameFirst;
  953. }
  954. else
  955. {
  956. // replace the wildcard in the template with the number string
  957. strNumber.Empty();
  958. strNumber.AppendULONG(nCurrentNum);
  959. strName = pszTemplate;
  960. strName.FindAndReplace(pszWildcard, strNumber); // replace first wildcard with number string
  961. }
  962. // test if a file or directory exists with that name
  963. testFileSpec = locationSpec.SpecifyChildFile(strName);
  964. testDirSpec = locationSpec.SpecifyChildDirectory(strName);
  965. if (CHXFileSpecUtils::FileExists(testFileSpec)
  966. || CHXFileSpecUtils::DirectoryExists(testDirSpec))
  967. {
  968. // an item already has that name, so increment & wrap the number
  969. nCurrentNum++;
  970. nCurrentNum %= kNumWrapValue;
  971. // don't use 0 again, and skip 1 since "MyFile2.txt" logically follows "MyFile.txt"
  972. if (nCurrentNum == 0 || nCurrentNum == 1) 
  973. {
  974. nCurrentNum = 2; 
  975. }
  976. // a quick sanity check
  977. if (nCurrentNum == nStartNum)
  978. {
  979. check(!"GetUniqueFileSpecInternal number wrapped");
  980. break;
  981. }
  982. }
  983. else
  984. {
  985. // the name is unique
  986. resultFileSpec = testFileSpec;
  987. break;
  988. }
  989. } // while
  990. return resultFileSpec;
  991. }
  992. CHXDirSpecifier 
  993. CHXFileSpecUtils::GetAppDataDir(const char* szAppName)
  994. {
  995. // XXXSEH: Placeholder.
  996. check(!"GetAppDataDir doesn't find anyplace useful on the Mac");
  997. // GR 3/19/02  What is supposed to go in the "app data dir"?
  998. //
  999. // We could make an appName folder in the users documents directory 
  1000. // with MacFindFolder(kUserDomain, kDocumentsFolderType), 
  1001. // but it's not normal for applications to hardcode that location for anything.
  1002. //
  1003. // The windows implementation finds someplace in the user directories, but this implementation doesn't.
  1004. return GetCurrentApplicationDir();
  1005. }
  1006. #ifdef _DEBUG
  1007. void CHXFileSpecUtils::TestMacFileSpecUtils()
  1008. {
  1009. }
  1010. #endif