Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

984 lines
26 KiB

  1. /*****************************************************************************
  2. * *
  3. * FM.c *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990 - 1994. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * Routines for manipulating FMs (File Monikers, equivalent to file names). *
  13. * WINDOWS LAYER
  14. * *
  15. ******************************************************************************
  16. * *
  17. * Current Owner: davej *
  18. * *
  19. *****************************************************************************/
  20. /*****************************************************************************
  21. *
  22. * Revision History:
  23. * -- Mar 92 adapted from WinHelps FM.C
  24. * 26-Jun-1992 RussPJ #293 - Now using OpenFile(OF_EXIST) instead of
  25. * access().
  26. * 29-Jun-1992 RussPJ #723 - Using OF_SHARE_DENY_NONE for OpenFile() call.
  27. * 18/10/94 a-kevct Fixed FmNewTemp to use "higher temperature" filenames
  28. * so that problems with calling it twice in rapid succession
  29. * are avoided.
  30. * 7/28/95 FM changed to just an LPSTR !!! - davej
  31. * 3/05/97 erinfox Change errors to HRESULTS
  32. *
  33. *****************************************************************************/
  34. #include <mvopsys.h>
  35. #include <stdlib.h> /* for _MAX_ constants & min and max macros*/
  36. #include <dos.h> /* for FP_OFF macros and file attribute constants */
  37. #include <io.h> /* for tell() and eof() */
  38. #include <direct.h> /* for getcwd */
  39. #include <string.h>
  40. #include <misc.h>
  41. #include <iterror.h>
  42. #include <wrapstor.h>
  43. #include <orkin.h>
  44. #ifndef _NT
  45. #include <errno.h>
  46. #endif
  47. #include <_mvutil.h>
  48. static char s_aszModule[] = __FILE__; /* For error report */
  49. /*****************************************************************************
  50. * *
  51. * Defines *
  52. * *
  53. *****************************************************************************/
  54. #define cbPathName _MAX_PATH
  55. #define cbMessage 50
  56. /*****************************************************************************
  57. * *
  58. * Variables *
  59. * *
  60. *****************************************************************************/
  61. void InitRandomPrefix(char *sz, int cb);
  62. PRIVATE BOOL PASCAL NEAR fIsTrailByte(SZ psz,SZ pch);
  63. // InitRandomPrefix
  64. //
  65. // Given a buffer at least cb + 1 chars long,
  66. // fills sz[0] through sz[ch-1] with random alphabetic chars
  67. // and null terminates at sz[cb].
  68. //
  69. //
  70. #ifdef _IT_FULL_CRT
  71. void InitRandomPrefix(char *sz, int cb)
  72. {
  73. while (--cb >= 0)
  74. *sz++ = 'A' + rand() % 26;
  75. *sz = '\0';
  76. }
  77. #endif
  78. /***************************************************************************
  79. *
  80. - Name: SnoopPath()
  81. -
  82. * Purpose:
  83. * Looks through a string for the various components of a file name and
  84. * returns the offsets into the string where each part starts.
  85. *
  86. * Arguments:
  87. * sz - string to snoop
  88. * *iDrive - offset for the drive specification if present
  89. * *iDir - offset for the directory path if present
  90. * *iBase - offset to the filename if present
  91. * *iExt - offset to the extension (including dot) if present
  92. *
  93. * Returns:
  94. * sets the index parameters for each respective part. the index is set
  95. * to point to the end of the string if the part is not present (thus
  96. * making it point to a null string).
  97. *
  98. *
  99. * +++
  100. *
  101. * Notes:
  102. *
  103. ***************************************************************************/
  104. void FAR PASCAL SnoopPath (LPSTR sz, int far * iDrive, int far *iDir,
  105. int far *iBase, int far *iExt)
  106. {
  107. short i = 0;
  108. short cb = (short) STRLEN(sz);
  109. BOOL fDir = FALSE;
  110. *iDrive = *iExt = cb;
  111. *iDir = *iBase = 0;
  112. while (*(sz + i))
  113. {
  114. switch (*(sz + i))
  115. {
  116. case ':':
  117. *iDrive = 0;
  118. *iDir = i + 1;
  119. *iBase = i + 1;
  120. break;
  121. case '/':
  122. case '\\':
  123. // make sure we are not looking at a trail byte
  124. if(fIsTrailByte(sz,sz+i))
  125. break;
  126. fDir = TRUE;
  127. *iBase = i + 1;
  128. *iExt = cb;
  129. break;
  130. case '.':
  131. *iExt = i;
  132. break;
  133. default:
  134. break;
  135. }
  136. i++;
  137. }
  138. if (!fDir)
  139. *iDir = i;
  140. else if (*iBase == '.')
  141. *iExt = cb;
  142. }
  143. /***************************************************************************\
  144. *
  145. - Function: fIsTrailByte(psz, pch)
  146. -
  147. * Purpose: Determine if pch is the trail byte of a DBC.
  148. *
  149. * ASSUMES
  150. *
  151. * args IN: psz - the beginning of the string
  152. * pch - the character to test
  153. *
  154. * Notes: This function is necessary because the Shift-JIS trail byte
  155. * ranges include the value 0x5C (backslash) and we need to
  156. * know the difference between a real backslash and a DBC that
  157. * has this trail byte value.
  158. *
  159. \***************************************************************************/
  160. PRIVATE BOOL PASCAL NEAR fIsTrailByte(SZ psz,SZ pch)
  161. {
  162. #if JRUSH
  163. return (IsDBCSLeadByte (*(pch - 1)));
  164. #else
  165. SZ pchTemp = psz;
  166. if(pch==psz || pch<psz)
  167. return FALSE;
  168. while(1)
  169. {
  170. pchTemp = CharNext(pchTemp);
  171. if(pchTemp==pch)
  172. return FALSE; // it's a lead byte
  173. if(pchTemp>pch)
  174. return TRUE; // we stepped past it - must have been a trail byte
  175. }
  176. #endif
  177. }
  178. /***************************************************************************
  179. *
  180. - Name: SzGetDir
  181. -
  182. * Purpose: returns the rooted path of a DIR
  183. *
  184. * Arguments: dir - DIR (must be one field only, and must be an actual dir -
  185. * not dirPath)
  186. * sz - buffer for storage (should be at least cchMaxPath)
  187. *
  188. * Returns: sz - fine
  189. * NULL - OS Error (check rcIOError)
  190. *
  191. * Globals Used: rcIOError
  192. *
  193. * +++
  194. *
  195. *
  196. ***************************************************************************/
  197. // Hey! what about dirTemp? This wasn't handled before so I'm not going
  198. // to add it. But someday the case should be handled.
  199. PRIVATE SZ PASCAL NEAR SzGetDir(DIR dir, SZ sz, PHRESULT phr)
  200. {
  201. int i=0;
  202. QCH qch;
  203. char LocalBuffer1[_MAX_PATH];
  204. if (sz == NULL)
  205. {
  206. SetErrCode (phr, E_INVALIDARG);
  207. return(NULL);
  208. };
  209. switch (dir)
  210. {
  211. case dirCurrent:
  212. if (GETCWD(LocalBuffer1, cchMaxPath) == NULL)
  213. {
  214. SetErrCode (phr, RcGetDOSError());
  215. sz = NULL;
  216. }
  217. else
  218. {
  219. STRCPY (sz, LocalBuffer1);
  220. }
  221. break;
  222. case dirHelp:
  223. #ifdef _WIN64
  224. GetModuleFileName((HINSTANCE)GetWindowLongPtr(GetActiveWindow(),
  225. GWLP_HINSTANCE),
  226. #elif _32BIT
  227. GetModuleFileName((HINSTANCE)GetWindowLong(GetActiveWindow(),
  228. GWL_HINSTANCE),
  229. #else
  230. GetModuleFileName((HINSTANCE)GetWindowWord(GetActiveWindow(),
  231. GWW_HINSTANCE),
  232. #endif
  233. sz, cchMaxPath);
  234. qch = sz + STRLEN(sz);
  235. while ((*qch != '\\' && !fIsTrailByte(sz,qch)) && *qch != '/')
  236. --qch;
  237. *qch = '\0';
  238. break; /* dirHelp */
  239. case dirSystem:
  240. i = GetWindowsDirectory((LPSTR)sz, cchMaxPath);
  241. if (i > cchMaxPath || i == 0)
  242. {
  243. SetErrCode (phr, E_FAIL);
  244. sz = NULL;
  245. }
  246. break; /* dirSystem */
  247. default:
  248. SetErrCode (phr, E_INVALIDARG);
  249. sz = NULL;
  250. break;
  251. }
  252. if (sz != NULL)
  253. {
  254. qch = sz+STRLEN(sz);
  255. /*------------------------------------------------------------*
  256. | Make sure that the string ends with a slash.
  257. *------------------------------------------------------------*/
  258. if ((*(qch-1) != '\\' && *(qch-1) != '/') || fIsTrailByte(sz,qch-1))
  259. {
  260. *qch++='\\';
  261. *qch='\0';
  262. }
  263. assert(qch < sz+_MAX_PATH && *qch=='\0');
  264. }
  265. return sz;
  266. }
  267. /***************************************************************************
  268. *
  269. - Name: FmNew
  270. -
  271. * Purpose: Allocate and initialize a new FM
  272. *
  273. * Arguments: sz - filename string
  274. *
  275. * Returns: FM (handle to fully canonicalized filename)
  276. *
  277. * Globals Used: rcIOError
  278. *
  279. * +++
  280. *
  281. * Notes:
  282. *
  283. ***************************************************************************/
  284. FM EXPORT_API PASCAL FAR FmNew(LPSTR sz, PHRESULT phr)
  285. {
  286. QAFM qafm;
  287. FM fm = fmNil;
  288. char LocalBuffer1[_MAX_PATH];
  289. char LocalBuffer2[_MAX_PATH];
  290. #ifndef _IT_FULL_CRT
  291. LPSTR lpAddr;
  292. #endif
  293. STRCPY(LocalBuffer2, sz);
  294. #ifdef _IT_FULL_CRT
  295. if (_fullpath(LocalBuffer1, LocalBuffer2, _MAX_PATH) == NULL)
  296. #else
  297. if (0 == GetFullPathName(LocalBuffer2, _MAX_PATH, LocalBuffer1, &lpAddr))
  298. #endif
  299. {
  300. SetErrCode (phr, E_FAIL);
  301. return(NULL);
  302. }
  303. else
  304. {
  305. fm = (FM) NewMemory( (WORD)(lstrlen(LocalBuffer1)+1) );
  306. //fm = (FM) _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE|GMEM_MOVEABLE,
  307. // (LONG)lstrlen(LocalBuffer1)+1);
  308. if (fm == fmNil)
  309. {
  310. SetErrCode (phr, E_OUTOFMEMORY);
  311. return fm;
  312. }
  313. qafm = (QAFM)fm;
  314. //qafm = (QAFM) _GLOBALLOCK(fm);
  315. STRCPY(qafm->rgch, LocalBuffer1);
  316. // Convert to upper case to make it less likely that two
  317. // FMs will contain different strings yet refer to the
  318. // same file.
  319. AnsiUpper(qafm->rgch);
  320. //_GLOBALUNLOCK((HANDLE)fm);
  321. }
  322. return fm;
  323. }
  324. /***************************************************************************
  325. *
  326. - Name: FmNewSzDir
  327. -
  328. * Purpose: Create an FM describing the file "sz" in the directory "dir"
  329. * If sz is a simple filename the FM locates the file in the
  330. * directory specified. If there is a drive or a rooted path
  331. * in the filename the directory parameter is ignored.
  332. * Relative paths are allowed and will reference off the dir
  333. * parameter or the default (current) directory as appropriate.
  334. *
  335. * This does not create a file or expect one to exist at the
  336. * final destination (that's what FmNewExistSzDir is for), all
  337. * wind up with is a cookie to a fully qualified path name.
  338. *
  339. * Arguments: sz - filename ("File.ext"),
  340. * or partial pathname ("Dir\File.ext"),
  341. * or current directory ("c:File.ext"),
  342. * or full pathname ("C:\Dir\Dir\File.ext")
  343. * dir - dirCurrent et al.
  344. *
  345. * Returns: the new FM, or fmNil if error
  346. * sz is unchanged
  347. *
  348. * Globals Used:
  349. *
  350. * +++
  351. *
  352. * Notes:
  353. *
  354. ***************************************************************************/
  355. PUBLIC FM PASCAL FAR FmNewSzDir(LPSTR sz, DIR dir, PHRESULT phr)
  356. {
  357. char nsz[_MAX_PATH];
  358. int iDrive, iDir, iBase, iExt;
  359. int cb;
  360. if (sz == NULL || *sz == '\0')
  361. {
  362. SetErrCode (phr, E_INVALIDARG);
  363. return NULL;
  364. }
  365. cb = (int) STRLEN(sz);
  366. SnoopPath(sz, &iDrive, &iDir, &iBase, &iExt);
  367. if (*(sz + iBase) == '\0') /* no name */
  368. {
  369. *nsz = '\0'; /* force error */
  370. }
  371. else if (*(sz + iDrive) || (*(sz + iDir) == '\\' &&
  372. !fIsTrailByte(sz,sz+iDir)) || *(sz + iDir) == '/')
  373. {
  374. /* there's a drive or root slash so we have an implicit directory spec */
  375. /* and we can ignore the directory parameter and use what was passed. */
  376. STRCPY(nsz, sz);
  377. }
  378. else
  379. {
  380. /* dir & (dir-1) checks to make sure there is only one bit set which is */
  381. /* followed by a check to make sure that it is also a permitted bit */
  382. assert(((dir & (dir-1)) == (WORD)0)
  383. && (dir & (dirCurrent|dirTemp|dirHelp|dirSystem|dirPath)));
  384. if (SzGetDir(dir, nsz, phr) == NULL)
  385. return NULL;
  386. SzNzCat(nsz, sz + iDir, (WORD)max(1, iBase - iDir));
  387. SzNzCat(nsz, sz + iBase, (WORD)max(1, iExt - iBase));
  388. STRCAT(nsz, sz + iExt);
  389. }
  390. /* We've got all the parameters, now make the FM */
  391. return FmNew(nsz, phr);
  392. }
  393. FM PASCAL FmNewExistSzDir(LPSTR sz, DIR dir, PHRESULT phr)
  394. {
  395. char nsz[_MAX_PATH];
  396. FM fm = fmNil;
  397. OFSTRUCT of;
  398. char szANSI[_MAX_PATH];
  399. int iDrive, iDir, iBase, iExt;
  400. int cb;
  401. DIR idir, xdir;
  402. if (sz == NULL || *sz == '\0')
  403. {
  404. SetErrCode (phr, E_INVALIDARG);
  405. return NULL;
  406. }
  407. cb = (int) STRLEN(sz);
  408. SnoopPath(sz, &iDrive, &iDir, &iBase, &iExt);
  409. if (*(sz + iBase) == '\0') /* no name */
  410. {
  411. SetErrCode (phr, E_INVALIDARG);
  412. return NULL;
  413. }
  414. if (*(sz + iDrive) || (*(sz + iDir) == '\\' && !fIsTrailByte(sz,sz+iDir)) || *(sz + iDir) == '/')
  415. { /* was given a drive or rooted path, so ignore dir parameter */
  416. fm = FmNew(sz, phr);
  417. if (!FExistFm(fm))
  418. {
  419. DisposeFm(fm);
  420. SetErrCode (phr, E_NOTEXIST);
  421. fm = fmNil;
  422. }
  423. return fm;
  424. }
  425. for (idir = dirFirst, fm = fmNil; idir <= dirLast && fm==fmNil;
  426. idir <<= 1)
  427. {
  428. xdir = dir & idir;
  429. if (xdir == dirPath)
  430. {
  431. /* search $PATH using the full string which will catch
  432. the case of a relative path and also do the right thing
  433. searching $PATH */
  434. if (OpenFile(sz, (LPOFSTRUCT)&of,
  435. OF_EXIST | OF_SHARE_DENY_NONE) != (HFILE)-1)
  436. {
  437. OemToAnsi(of.szPathName, szANSI);
  438. fm = FmNew(szANSI, phr);
  439. }
  440. }
  441. else if (xdir)
  442. {
  443. if (SzGetDir(xdir, nsz, phr) != NULL)
  444. {
  445. SzNzCat(nsz, sz + iDir, (WORD)max(1, iBase - iDir));
  446. SzNzCat(nsz, sz + iBase, (WORD)max(1, iExt - iBase));
  447. STRCAT(nsz, sz + iExt);
  448. fm = FmNew(nsz, phr);
  449. if (!FValidFm(fm))
  450. {
  451. SetErrCode (phr, E_FAIL);
  452. }
  453. else if (!FExistFm(fm))
  454. {
  455. DisposeFm(fm);
  456. fm=fmNil;
  457. }
  458. }
  459. }
  460. } /* for */
  461. if ((!FValidFm(fm)))
  462. SetErrCode (phr, E_NOTEXIST);
  463. return fm;
  464. }
  465. /***************************************************************************
  466. *
  467. - Name: FmNewTemp
  468. -
  469. *
  470. * Purpose: Create a unique FM for a temporary file
  471. *
  472. * Arguments: LPSTR Filename: filename's template
  473. *
  474. * Returns: the new FM, or fmNil if failure
  475. *
  476. * Globals Used: rcIOError
  477. *
  478. * +++
  479. *
  480. * Notes:
  481. *
  482. ***************************************************************************/
  483. FM PASCAL FmNewTemp(LPSTR filename, PHRESULT phr)
  484. {
  485. char nsz[_MAX_PATH];
  486. FM fm = fmNil;
  487. char template[5];
  488. int i;
  489. if (filename == NULL || *filename == 0)
  490. {
  491. // WARNING: we MUST generate our own random
  492. // prefix here since GetTempFileName does NOT
  493. // always return a unique name when called twice
  494. // in very rapid succession.
  495. #ifndef _IT_FULL_CRT
  496. /* InitRandomPrefix calls rand, which pulls in the c run-time
  497. * startup code. Since this is never called we remove the
  498. * functionality */
  499. if(phr)
  500. {
  501. ITASSERT(FALSE);
  502. SetErrCode(phr, E_NOTSUPPORTED);
  503. }
  504. return fmNil;
  505. #else
  506. char szPrefix[4];
  507. InitRandomPrefix(szPrefix, 3);
  508. GETTEMPFILENAME(0, szPrefix, 0, nsz);
  509. #endif
  510. }
  511. else
  512. {
  513. for (i = 0; *filename && i < 5; filename++)
  514. {
  515. if ((*filename | 0x20) >= 'a' && (*filename | 0x20) <= 'z')
  516. {
  517. template[i] = *filename;
  518. i++;
  519. }
  520. }
  521. template[i] = 0;
  522. GETTEMPFILENAME(0, template, 0, nsz);
  523. }
  524. fm = FmNew(nsz, phr);
  525. if (fm && RcUnlinkFm(fm) != S_OK)
  526. {
  527. DisposeFm(fm);
  528. SetErrCode (phr, E_FAIL);
  529. return fmNil;
  530. }
  531. return fm;
  532. }
  533. /***************************************************************************
  534. *
  535. - Name: FmNewSameDirFmSz
  536. -
  537. * Purpose: Makes a new FM to a file called sz in the same directory
  538. * as the file described by fm.
  539. *
  540. * Arguments: fm - original fm
  541. * sz - new file name (including extention, if desired)
  542. *
  543. * Returns: new FM or fmNil and sets the rc global on failure
  544. *
  545. * Globals Used:
  546. * rcIOError
  547. *
  548. * +++
  549. *
  550. * Notes:
  551. * This will ignore the passed FM if the filename is fully qualified.
  552. * This is in keeping consistent with the other functions above that
  553. * ignore the directory parameter in such a case. It will fail if it
  554. * is given a drive with anything but a rooted path.
  555. *
  556. ***************************************************************************/
  557. FM PASCAL FmNewSameDirFmSz(FM fm, LPSTR szName, PHRESULT phr)
  558. {
  559. char nszNew[_MAX_PATH];
  560. QAFM qafm;
  561. FM fmNew = fmNil;
  562. int iDrive, iDir, iBase, iExt;
  563. if (!FValidFm(fm) || szName == NULL || *szName == '\0')
  564. {
  565. SetErrCode (phr, E_INVALIDARG);
  566. return fmNil;
  567. }
  568. qafm = (QAFM)_GLOBALLOCK((HANDLE)fm);
  569. /* check for a drive or rooted file name and just return it if it is so */
  570. SnoopPath(szName, &iDrive, &iDir, &iBase, &iExt);
  571. if (*(szName + iDrive) || (*(szName + iDir) == '\\' && !fIsTrailByte(szName,szName+iDir)) || *(szName +iDir) == '/')
  572. STRCPY(nszNew, szName);
  573. else
  574. {
  575. if (*(szName + iDrive) != '\0')
  576. {
  577. fmNew = fmNil;
  578. goto bail_out;
  579. }
  580. else
  581. {
  582. SnoopPath(qafm->rgch, &iDrive, &iDir, &iBase, &iExt);
  583. STRNCPY(nszNew, qafm->rgch, iBase);
  584. *(nszNew + iBase) = '\0';
  585. STRCAT(nszNew, szName);
  586. }
  587. }
  588. fmNew = FmNew((SZ)nszNew, phr);
  589. bail_out:
  590. _GLOBALUNLOCK((HANDLE)fm);
  591. return fmNew;
  592. }
  593. /***************************************************************************
  594. *
  595. - DisposeFm
  596. -
  597. * Purpose
  598. * You must call this routine to free the memory used by an FM, which
  599. * was created by one of the FmNew* routines
  600. *
  601. * Arguments
  602. * fm - original FM
  603. *
  604. * Returns
  605. * nothing
  606. *
  607. * Globals Used:
  608. *
  609. * +++
  610. *
  611. * Notes:
  612. *
  613. ***************************************************************************/
  614. VOID PASCAL DisposeFm (FM fm)
  615. {
  616. if (FValidFm(fm))
  617. DisposeMemory(fm);
  618. //_GLOBALFREE ((HANDLE)fm);
  619. }
  620. /***************************************************************************
  621. *
  622. - Name: FmCopyFm
  623. -
  624. * Purpose: return an FM to the same file as the passed one
  625. *
  626. * Arguments: fm
  627. *
  628. * Returns: FM - for now, it's a real copy. Later, we may implement caching
  629. * and counts.
  630. * If fmNil, either it's an error (check WGetIOError()) or the
  631. * original fm was nil too
  632. *
  633. * Globals Used: rcIOError (indirectly)
  634. *
  635. * +++
  636. *
  637. * Notes:
  638. *
  639. ***************************************************************************/
  640. FM PASCAL FmCopyFm(FM fmSrc, PHRESULT phr)
  641. {
  642. FM fmDest = fmNil;
  643. QAFM qafmSrc, qafmDest;
  644. if (!FValidFm(fmSrc))
  645. {
  646. SetErrCode (phr, E_INVALIDARG);
  647. return fmNil;
  648. }
  649. qafmSrc = (QAFM)fmSrc;
  650. //qafmSrc = (QAFM)_GLOBALLOCK((HANDLE)fmSrc);
  651. fmDest = (FM) NewMemory((WORD)(lstrlen(qafmSrc->rgch) + 1));
  652. //fmDest = (FM) _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE|GMEM_MOVEABLE,
  653. // (size_t)lstrlen(qafmSrc->rgch) + 1);
  654. if (fmDest == fmNil)
  655. {
  656. SetErrCode(phr, E_OUTOFMEMORY);
  657. //_GLOBALUNLOCK((HANDLE)fmSrc);
  658. return fmNil;
  659. }
  660. qafmDest = (QAFM)fmDest;
  661. //qafmDest = (QAFM)_GLOBALLOCK((HANDLE)fmDest);
  662. STRCPY(qafmDest->rgch, qafmSrc->rgch);
  663. //_GLOBALUNLOCK((HANDLE)fmSrc);
  664. //_GLOBALUNLOCK((HANDLE)fmDest);
  665. return fmDest;
  666. }
  667. /***************************************************************************
  668. *
  669. - Name: FExistFm
  670. -
  671. * Purpose: Does the file exist?
  672. *
  673. * Arguments: FM
  674. *
  675. * Returns: TRUE if it does
  676. * FALSE if it doesn't, or if there's an error
  677. * (call _ to find out what error it was)
  678. *
  679. * Globals Used: rcIOError
  680. *
  681. * +++
  682. *
  683. * Notes:
  684. *
  685. ***************************************************************************/
  686. BOOL PASCAL FExistFm(FM fm)
  687. {
  688. QAFM qafm;
  689. BOOL fExist;
  690. OFSTRUCT ofs;
  691. HRESULT rc;
  692. char LocalBuffer1[_MAX_PATH];
  693. HRESULT errb;
  694. if (!FValidFm(fm))
  695. {
  696. SetErrCode(&errb, E_INVALIDARG);
  697. return FALSE;
  698. }
  699. qafm = (QAFM)fm;
  700. //qafm = _GLOBALLOCK((HANDLE)fm);
  701. STRCPY(LocalBuffer1, qafm->rgch); /* bring the filename into near space */
  702. //_GLOBALUNLOCK((HANDLE)fm);
  703. // try in both modes!
  704. fExist = (OpenFile(LocalBuffer1, &ofs,
  705. OF_EXIST | OF_SHARE_DENY_NONE) != (HFILE)-1)
  706. || (OpenFile(LocalBuffer1, &ofs, OF_EXIST) != (HFILE)-1);
  707. rc = S_OK;
  708. if (!fExist)
  709. {
  710. #ifdef _NT
  711. if( GetLastError() != ERROR_FILE_NOT_FOUND )
  712. #else
  713. if( errno != ENOENT )
  714. #endif // _NT
  715. rc = RcGetDOSError();
  716. }
  717. SetErrCode(&errb, rc);
  718. return fExist;
  719. }
  720. /***************************************************************************
  721. *
  722. - CbPartsFm
  723. -
  724. * Purpose:
  725. * Before calling szPartsFm, call this routine to find out how much
  726. * space to allocate for the string.
  727. *
  728. * Arguments:
  729. * FM - the File Moniker you'll be extracting the string from
  730. * INT iPart - the parts of the full pathname you want
  731. *
  732. * Returns:
  733. * The length in bytes, INCLUDING the terminating null, of the string
  734. * specified by iPart of the filename of FM, or -1 if error
  735. *
  736. * Globals Used:
  737. *
  738. * +++
  739. *
  740. * Notes:
  741. *
  742. ***************************************************************************/
  743. int PASCAL FAR EXPORT_API CbPartsFm(FM fm, int grfPart)
  744. {
  745. char rgch[_MAX_PATH];
  746. if (!FValidFm(fm))
  747. return -1;
  748. (void)SzPartsFm(fm, rgch, _MAX_PATH, grfPart);
  749. return ((int) STRLEN(rgch) + 1); /* add space for the null */
  750. }
  751. /***************************************************************************
  752. *
  753. - SzPartsFm
  754. -
  755. * Purpose:
  756. * Extract a string from an FM
  757. *
  758. * Arguments:
  759. * FM - the File Moniker you'll be extracting the string from
  760. * SZ szDest - destination string
  761. * INT cbDest - bytes allocated for the string
  762. * INT iPart - the parts of the full pathname you want
  763. *
  764. * Returns:
  765. * szDest, or NULL if error (?)
  766. *
  767. * Globals Used:
  768. *
  769. * +++
  770. *
  771. * Notes:
  772. *
  773. ***************************************************************************/
  774. LPSTR PASCAL SzPartsFm(FM fm, LPSTR szDest, int cbDest,
  775. int iPart)
  776. {
  777. QAFM qafm;
  778. int iDrive, iDir, iBase, iExt;
  779. int cb;
  780. HRESULT errb;
  781. if (!FValidFm(fm) || szDest == NULL || cbDest < 1)
  782. {
  783. SetErrCode (&errb, E_INVALIDARG);
  784. return NULL;
  785. }
  786. qafm = (QAFM) fm;
  787. //qafm = (QAFM) _GLOBALLOCK(fm);
  788. /* special case so we don't waste effort */
  789. if (iPart == partAll)
  790. {
  791. STRNCPY(szDest, qafm->rgch, cbDest);
  792. *(szDest + cbDest - 1) = '\0';
  793. //_GLOBALUNLOCK((HANDLE)fm);
  794. return szDest;
  795. }
  796. SnoopPath(qafm->rgch, &iDrive, &iDir, &iBase, &iExt);
  797. *szDest = '\0';
  798. if (iPart & partDrive)
  799. {
  800. cb = max(0, iDir - iDrive);
  801. SzNzCat(szDest, qafm->rgch + iDrive, (WORD)(min(cb + 1, cbDest) - 1));
  802. cbDest -= cb;
  803. }
  804. if (iPart & partDir)
  805. {
  806. cb = max(0, iBase - iDir);
  807. SzNzCat(szDest, qafm->rgch + iDir, (WORD)(min(cb + 1, cbDest) - 1));
  808. cbDest -= cb;
  809. }
  810. if (iPart & partBase)
  811. {
  812. cb = max(0, iExt - iBase);
  813. SzNzCat(szDest, qafm->rgch + iBase, (WORD)(min(cb + 1, cbDest) - 1));
  814. cbDest -= cb;
  815. }
  816. if (iPart & partExt)
  817. {
  818. SzNzCat(szDest, qafm->rgch + iExt, (WORD)(cbDest - 1));
  819. }
  820. //_GLOBALUNLOCK((HANDLE)fm);
  821. return szDest;
  822. }
  823. /***************************************************************************
  824. *
  825. - Name: FSameFmFm
  826. -
  827. * Purpose: Compare two FM's
  828. *
  829. * Arguments: fm1, fm2
  830. *
  831. * Returns: TRUE or FALSE
  832. *
  833. * Globals Used:
  834. *
  835. * +++
  836. *
  837. * Notes: case insensitive compare is used because strings are
  838. * upper cased at FM creation time
  839. *
  840. ***************************************************************************/
  841. BOOL PASCAL FSameFmFm(FM fm1, FM fm2)
  842. {
  843. QAFM qafm1;
  844. QAFM qafm2;
  845. BOOL fSame;
  846. if (fm1 == fm2)
  847. return TRUE;
  848. if (!FValidFm(fm1) || !FValidFm(fm2))
  849. return FALSE;
  850. qafm1 = (QAFM)fm1;
  851. qafm2 = (QAFM)fm2;
  852. //qafm1 = _GLOBALLOCK(fm1);
  853. //qafm2 = _GLOBALLOCK(fm2);
  854. fSame = STRCMP(qafm1->rgch, qafm2->rgch) == 0;
  855. //_GLOBALUNLOCK(fm1);
  856. //_GLOBALUNLOCK(fm2);
  857. return fSame;
  858. }