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.

818 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998 - 2000.
  5. //
  6. // File: FunyPath.hxx
  7. //
  8. // Contents: Implementation of ``Funny'' Path for long pathnames
  9. //
  10. // Classes: CFunnyPath
  11. // CLowerFunnyPath
  12. // CLowerFunnyStack
  13. //
  14. // Notes: This class takes in a fully qualified path. The path can be in
  15. // two forms - C:\dir\... or \\machine\share\...
  16. // EXCEPTION: To accomodate for scope restrictions, this class
  17. // will also allow paths of \dir... format
  18. // This path is converted to the "funny" form. The normal path
  19. // takes the form of \\?\C:\dir\... and remote path takes the form
  20. // of \\?\UNC\machine\share\... These funny paths can used by in
  21. // functions like CreateFile to open paths > MAX_PATH
  22. //
  23. // History: 08-May-98 vikasman Created
  24. //
  25. //----------------------------------------------------------------------------
  26. #pragma once
  27. #include "lcase.hxx"
  28. const WCHAR _FUNNY_PATH[] = L"\\\\?\\";
  29. const WCHAR _UNC_FUNNY_PATH[] = L"\\\\?\\UN";
  30. const _FUNNY_PATH_LENGTH = ( ( sizeof( _FUNNY_PATH ) / sizeof( WCHAR ) ) - 1 );
  31. const _UNC_FUNNY_PATH_LENGTH = ( ( sizeof( _UNC_FUNNY_PATH ) / sizeof( WCHAR ) ) - 1 );
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Class: CFunnyPath
  35. //
  36. // Purpose: A path name preceeded by "\\?\" to allow file operations
  37. // when the length of the path is > MAX_PATH.
  38. //
  39. // History: 08-May-98 vikasman Created
  40. //
  41. //----------------------------------------------------------------------------
  42. class CFunnyPath
  43. {
  44. public:
  45. // used by SetState function to set the state to funny/actual
  46. enum PathState
  47. {
  48. FUNNY_PATH_STATE,
  49. ACTUAL_PATH_STATE
  50. };
  51. //
  52. // Constructors, Destructors, Operators...
  53. //
  54. CFunnyPath( BOOL fRemote = FALSE ) :
  55. _fRemote( fRemote ),
  56. _ccActualBuf( 0 )
  57. {
  58. if ( _fRemote )
  59. {
  60. _xBuf.SetSize( _UNC_FUNNY_PATH_LENGTH + 1 );
  61. _xBuf[_UNC_FUNNY_PATH_LENGTH] = 0;
  62. }
  63. else
  64. {
  65. _xBuf.SetSize( _FUNNY_PATH_LENGTH + 1 );
  66. _xBuf[_FUNNY_PATH_LENGTH] = 0;
  67. }
  68. }
  69. CFunnyPath( const WCHAR * wcsPath, unsigned cc = 0 ) :
  70. _fRemote( FALSE ),
  71. _ccActualBuf( 0 )
  72. {
  73. SetPath( wcsPath, cc );
  74. }
  75. CFunnyPath( CFunnyPath const & src )
  76. {
  77. *this = src;
  78. }
  79. CFunnyPath & operator =( CFunnyPath const & src )
  80. {
  81. _xBuf = src._xBuf;
  82. _fRemote = src._fRemote;
  83. _ccActualBuf = src._ccActualBuf;
  84. return *this;
  85. }
  86. //
  87. // Sets the path "wcsPath"
  88. //
  89. virtual void SetPath( const WCHAR * wcsPath, unsigned cc = 0 )
  90. {
  91. Win4Assert( wcsPath );
  92. _ccActualBuf = ( 0 == cc ? wcslen( wcsPath ) : cc ) ;
  93. if ( 0 == _ccActualBuf )
  94. {
  95. InitBlank();
  96. return;
  97. }
  98. Win4Assert( _ccActualBuf > 1 ); // at least 2 characters
  99. WCHAR * pwcActualPath;
  100. BOOL fInvalidPath = FALSE;
  101. if ( L'\\' != wcsPath[0] && L':' != wcsPath[1] )
  102. // Looks like we don't have a valid path, but still
  103. // we will continue. It's not CFunnyPath's problem
  104. // We will treat it as a normal path
  105. {
  106. ciDebugOut(( DEB_ITRACE, "CFunnyPath::SetPath - The path (%ws) is not valid.\n", wcsPath ));
  107. fInvalidPath = TRUE;
  108. }
  109. if ( L':' == wcsPath[1] || fInvalidPath )
  110. {
  111. // normal or invalid path
  112. _fRemote = FALSE;
  113. _xBuf.SetSize( _ccActualBuf + _FUNNY_PATH_LENGTH + 1 );
  114. _xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH );
  115. pwcActualPath = &_xBuf[_FUNNY_PATH_LENGTH];
  116. }
  117. else
  118. {
  119. // remote path
  120. _fRemote = TRUE;
  121. _xBuf.SetSize( _ccActualBuf + _UNC_FUNNY_PATH_LENGTH + 1 );
  122. _xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH );
  123. pwcActualPath = &_xBuf[_UNC_FUNNY_PATH_LENGTH];
  124. }
  125. RtlCopyMemory( pwcActualPath, wcsPath, _ccActualBuf * sizeof( WCHAR ) );
  126. pwcActualPath[_ccActualBuf] = 0;
  127. }
  128. //
  129. // Appends the path "wcsPath"
  130. //
  131. virtual void AppendPath( const WCHAR * wcsPath, unsigned cc = 0 )
  132. {
  133. AssertValid();
  134. Win4Assert( wcsPath );
  135. if ( 0 == cc )
  136. {
  137. cc = wcslen( wcsPath );
  138. }
  139. unsigned ccTotalSizeNeeded = cc + _ccActualBuf + 1;
  140. WCHAR * pwcAppendAt;
  141. if ( _fRemote )
  142. {
  143. _xBuf.SetSize( ccTotalSizeNeeded + _UNC_FUNNY_PATH_LENGTH );
  144. pwcAppendAt = &_xBuf[_UNC_FUNNY_PATH_LENGTH + _ccActualBuf];
  145. }
  146. else
  147. {
  148. _xBuf.SetSize( ccTotalSizeNeeded + _FUNNY_PATH_LENGTH );
  149. pwcAppendAt = &_xBuf[_FUNNY_PATH_LENGTH + _ccActualBuf];
  150. }
  151. RtlCopyMemory( pwcAppendAt, wcsPath, cc * sizeof( WCHAR ) );
  152. pwcAppendAt[cc] = 0;
  153. _ccActualBuf += cc;
  154. }
  155. //
  156. // Returns the path either as funny or unc_funny which can be used in
  157. // functions like CreateFile. Do not keep and use the pointer from
  158. // GetPath after calling GetActualPath.
  159. // Reason: Both these functions(even though they are const) may
  160. // modify the internal buffer before returning data
  161. //
  162. const WCHAR * GetPath() const
  163. {
  164. AssertValid();
  165. if ( _fRemote )
  166. {
  167. // need to replace \ with C
  168. ((CFunnyPath*)this)->_xBuf[_UNC_FUNNY_PATH_LENGTH] = L'C';
  169. }
  170. return _xBuf.Get();
  171. }
  172. //
  173. // Returns the "actual path". Do not keep and use the pointer from
  174. // GetActualPath after calling GetPath. Reason: Both these functions
  175. // (even though they are const) may modify the internal buffer before
  176. // returning data
  177. //
  178. const WCHAR * GetActualPath() const
  179. {
  180. return _GetActualPath();
  181. }
  182. //
  183. // Sets the state of the path to actual/funny
  184. //
  185. void SetState( const PathState state )
  186. {
  187. if ( _fRemote )
  188. {
  189. _xBuf[_UNC_FUNNY_PATH_LENGTH] =
  190. ( FUNNY_PATH_STATE == state ? L'C' : L'\\' );
  191. }
  192. }
  193. //
  194. // Returns the actual length of characters
  195. //
  196. unsigned GetActualLength() const
  197. {
  198. return _ccActualBuf;
  199. }
  200. //
  201. // Returns the total length
  202. //
  203. unsigned GetLength() const
  204. {
  205. return ( _ccActualBuf +
  206. (_fRemote ? _UNC_FUNNY_PATH_LENGTH : _FUNNY_PATH_LENGTH) );
  207. }
  208. //
  209. // Appends back slash
  210. //
  211. BOOL AppendBackSlash()
  212. {
  213. WCHAR * pwcsActualPath = _GetActualPath();
  214. if ( 0 == _ccActualBuf || L'\\' == pwcsActualPath[_ccActualBuf - 1] )
  215. {
  216. return FALSE;
  217. }
  218. AppendPath( L"\\", 1 );
  219. return TRUE;
  220. }
  221. //
  222. // Removes back slash
  223. //
  224. BOOL RemoveBackSlash()
  225. {
  226. WCHAR * pwcsActualPath = _GetActualPath();
  227. if ( 0 == _ccActualBuf || L'\\' != pwcsActualPath[_ccActualBuf - 1] )
  228. {
  229. return FALSE;
  230. }
  231. pwcsActualPath[--_ccActualBuf] = 0;
  232. return TRUE;
  233. }
  234. //
  235. // Truncates the buf to ccNewLength (this is the "actual char.", excluding
  236. // funny path prefix, length)
  237. //
  238. void Truncate( unsigned ccNewLength )
  239. {
  240. if ( ccNewLength < _ccActualBuf )
  241. {
  242. WCHAR * pwcActualPath = _GetActualPath();
  243. pwcActualPath[ _ccActualBuf = ccNewLength ] = 0;
  244. }
  245. }
  246. BOOL IsRemote () const
  247. {
  248. return _fRemote;
  249. }
  250. //
  251. // returns TRUE if any component in the path looks like the short version
  252. // of a long file name.
  253. //
  254. BOOL IsShortPath () const;
  255. static BOOL IsShortName( WCHAR const * const pwszName );
  256. //
  257. // Returns the count of all the characters in xBuf
  258. //
  259. unsigned Count() const
  260. {
  261. return _xBuf.Count();
  262. }
  263. //
  264. // Set the size of _xBuf
  265. //
  266. void SetSize( unsigned cc )
  267. {
  268. _xBuf.SetSize( cc );
  269. }
  270. //
  271. // Get the internal buffer
  272. //
  273. const WCHAR * GetBuffer() const
  274. {
  275. return _xBuf.Get();
  276. }
  277. //
  278. // This is a dangerous function as it exposes the internal buffer
  279. //
  280. WCHAR * GetBuffer()
  281. {
  282. return _xBuf.Get();
  283. }
  284. // This path initializes the internal buffer with empty actual path
  285. void InitBlank( BOOL fRemote = FALSE )
  286. {
  287. _fRemote = fRemote;
  288. if ( _fRemote )
  289. {
  290. _xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH + 1 );
  291. }
  292. else
  293. {
  294. _xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH + 1 );
  295. }
  296. _ccActualBuf = 0;
  297. }
  298. #if CIDBG==1
  299. //
  300. // Asserts that we are in good state
  301. //
  302. void AssertValid() const
  303. {
  304. const WCHAR * pwcsFunny = _xBuf.Get();
  305. Win4Assert( pwcsFunny &&
  306. L'\\' == pwcsFunny[0] && L'\\' == pwcsFunny[1] &&
  307. L'?' == pwcsFunny[2] && L'\\' == pwcsFunny[3] );
  308. Win4Assert( L':' == pwcsFunny[5] || L'N' == pwcsFunny[5] ||
  309. L'n' == pwcsFunny[5] );
  310. }
  311. #else
  312. void AssertValid() const {}
  313. #endif
  314. //
  315. // Some static utility functions
  316. //
  317. enum FunnyUNC
  318. {
  319. NOT_FUNNY, // not funny
  320. FUNNY_ONLY, // of type \\?\c:\dir\...
  321. FUNNY_UNC // of type \\?\unc\...
  322. };
  323. static inline BOOL IsFunnyPath( WCHAR const * pwcsPath )
  324. {
  325. return ( pwcsPath &&
  326. L'\\' == pwcsPath[0] &&
  327. L'\\' == pwcsPath[1] &&
  328. L'?' == pwcsPath[2] &&
  329. L'\\' == pwcsPath[3] );
  330. }
  331. static inline FunnyUNC IsFunnyUNCPath( WCHAR const * pwcsPath )
  332. {
  333. // The 6th char here can also be as '\\' (instead of being c/C) as
  334. // this class modifies that charatcter to be a '\\'.
  335. return ( FALSE == IsFunnyPath( pwcsPath ) ?
  336. NOT_FUNNY :
  337. ( ( (L'U' == pwcsPath[4] || L'u' == pwcsPath[4]) &&
  338. (L'N' == pwcsPath[5] || L'n' == pwcsPath[5]) &&
  339. (L'C' == pwcsPath[6] || L'c' == pwcsPath[6] || L'\\' == pwcsPath[6]) &&
  340. (L'\\' == pwcsPath[7] ) ) ?
  341. FUNNY_UNC :
  342. FUNNY_ONLY ) );
  343. }
  344. protected:
  345. WCHAR * _GetActualPath() const
  346. {
  347. WCHAR * pwcsActualPath;
  348. if ( _fRemote )
  349. {
  350. pwcsActualPath = &(((CFunnyPath*)this)->_xBuf[_UNC_FUNNY_PATH_LENGTH]);
  351. // need to replace C with "\"
  352. *pwcsActualPath = L'\\';
  353. }
  354. else
  355. {
  356. pwcsActualPath = &(((CFunnyPath*)this)->_xBuf[_FUNNY_PATH_LENGTH]);
  357. }
  358. return pwcsActualPath;
  359. }
  360. BOOL _fRemote; // Is the path remote ?
  361. unsigned _ccActualBuf; // number of actual characters in _xBuf
  362. // (excluding _FUNNY_PATH/_UNC_FUNNY_PATH)
  363. XGrowable<WCHAR> _xBuf;
  364. };
  365. //+---------------------------------------------------------------------------
  366. //
  367. // Method: CFunnyPath::IsShortName, static public
  368. //
  369. // Arguments: [pwszName] -- name to be checked (only a single path component
  370. // is checked at a time)
  371. //
  372. // Returns: TRUE if file is potentially a short (8.3) name for
  373. // a file with a long name.
  374. //
  375. // History: 01-Sep-1998 AlanW Created
  376. //
  377. //----------------------------------------------------------------------------
  378. inline BOOL CFunnyPath::IsShortName( WCHAR const * const pwszName )
  379. {
  380. //
  381. // First, see if this is possibly a short name (has ~ in file name part).
  382. //
  383. BOOL fTwiddle = FALSE;
  384. unsigned cDot = 0;
  385. for ( unsigned cchFN = 0; cchFN < 13; cchFN++ )
  386. {
  387. if ( pwszName[cchFN] == L'~' && cchFN >= 1 )
  388. fTwiddle = TRUE;
  389. else if ( pwszName[cchFN] == L'.' )
  390. {
  391. if (cchFN == 0 || cchFN > 8)
  392. return FALSE; // short names can't have '.' at beginning
  393. cDot++;
  394. }
  395. else if ( pwszName[cchFN] == L'\0' || pwszName[cchFN] == L'\\' )
  396. break;
  397. cchFN++;
  398. }
  399. if (fTwiddle)
  400. {
  401. // short names can't have more than 1 '.'
  402. // max filename size if no extension is 8
  403. if (cDot >= 2 || cDot == 0 && cchFN > 8)
  404. return FALSE;
  405. // check for min (e.g., EXT~1 for .ext) and max lengths
  406. if (cchFN >= 5 && cchFN <= 12)
  407. return TRUE;
  408. }
  409. return FALSE;
  410. }
  411. //+---------------------------------------------------------------------------
  412. //
  413. // Method: CFunnyPath::IsShortPath, public
  414. //
  415. // Arguments: - none -
  416. //
  417. // Returns: TRUE if the path name potentially contains a short (8.3) name
  418. // for a file with a long name.
  419. //
  420. // History: 15-Sep-1998 AlanW Created
  421. //
  422. //----------------------------------------------------------------------------
  423. inline BOOL CFunnyPath::IsShortPath() const
  424. {
  425. //
  426. // Check to see if the input path name contains an 8.3 short name
  427. //
  428. WCHAR * pwszTilde = wcschr( GetActualPath(), L'~' );
  429. if (pwszTilde)
  430. {
  431. WCHAR * pwszComponent;
  432. for ( pwszComponent = wcschr( GetActualPath(), L'\\' );
  433. pwszComponent;
  434. pwszComponent = wcschr( pwszComponent, L'\\' ) )
  435. {
  436. pwszComponent++;
  437. pwszTilde = wcschr( pwszComponent, L'~' );
  438. if ( 0 == pwszTilde || pwszTilde - pwszComponent > 13)
  439. continue;
  440. if (IsShortName( pwszComponent ))
  441. return TRUE;
  442. }
  443. }
  444. return FALSE;
  445. }
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Class: CFunnyPath
  449. //
  450. // Purpose: A path name preceeded by "\\?\" to allow file operations when
  451. // the length of the path is > MAX_PATH. Keeps the FunnyPath in
  452. // lower case.
  453. //
  454. // History: 08-May-98 vikasman Created
  455. //
  456. //----------------------------------------------------------------------------
  457. class CLowerFunnyPath : public CFunnyPath
  458. {
  459. public:
  460. CLowerFunnyPath( BOOL fRemote = FALSE ) :
  461. CFunnyPath( fRemote )
  462. {
  463. }
  464. CLowerFunnyPath( const CLowerFunnyPath & src )
  465. {
  466. *this = src;
  467. }
  468. CLowerFunnyPath( const WCHAR * wcsPath,
  469. unsigned cc = 0,
  470. BOOL fNoConvert = FALSE ) :
  471. CFunnyPath()
  472. {
  473. SetPath( wcsPath, cc, fNoConvert );
  474. }
  475. CLowerFunnyPath & operator =( CLowerFunnyPath const & src )
  476. {
  477. CFunnyPath::operator=( (CFunnyPath&)src );
  478. return *this;
  479. }
  480. virtual void SetPath( const WCHAR * wcsPath,
  481. unsigned cc = 0,
  482. BOOL fNoConvert = FALSE );
  483. virtual void AppendPath( const WCHAR * wcsPath,
  484. unsigned cc = 0,
  485. BOOL fNoConvert = FALSE );
  486. BOOL ConvertToLongName();
  487. private:
  488. //
  489. // Converts to wcsPath of length cc to lower case and puts it in
  490. // _xBuf starting from ccStart index (actual)
  491. //
  492. void ToLower( const WCHAR * wcsPath, unsigned cc, unsigned ccStart = 0 );
  493. };
  494. inline void CLowerFunnyPath::SetPath(
  495. const WCHAR * wcsPath,
  496. unsigned cc,
  497. BOOL fNoConvert )
  498. {
  499. if ( fNoConvert )
  500. {
  501. // already lower case
  502. CFunnyPath::SetPath( wcsPath, cc );
  503. AssertLowerCase( GetActualPath(), GetActualLength() );
  504. return;
  505. }
  506. Win4Assert( wcsPath );
  507. cc = ( 0 == cc ? wcslen( wcsPath ) : cc ) ;
  508. if ( 0 == cc )
  509. {
  510. InitBlank();
  511. return;
  512. }
  513. BOOL fInvalidPath = FALSE;
  514. if ( L'\\' != wcsPath[0] && L':' != wcsPath[1] )
  515. {
  516. // Looks like we don't have a valid path, but still
  517. // we will continue. It's not CFunnyPath's problem
  518. // We will treat it as a normal path
  519. ciDebugOut(( DEB_ITRACE,
  520. "CLowerFunnyPath::SetPath - path (%ws) is not valid.\n",
  521. wcsPath ));
  522. fInvalidPath = TRUE;
  523. }
  524. if ( L':' == wcsPath[1] || fInvalidPath )
  525. {
  526. // normal or invalid path
  527. _fRemote = FALSE;
  528. _xBuf.SetBuf( _FUNNY_PATH, _FUNNY_PATH_LENGTH + 1 );
  529. }
  530. else
  531. {
  532. // remote path
  533. _fRemote = TRUE;
  534. _xBuf.SetBuf( _UNC_FUNNY_PATH, _UNC_FUNNY_PATH_LENGTH + 1 );
  535. }
  536. ToLower( wcsPath, cc );
  537. }
  538. inline void CLowerFunnyPath::AppendPath(
  539. const WCHAR * wcsPath,
  540. unsigned cc,
  541. BOOL fNoConvert )
  542. {
  543. if ( fNoConvert )
  544. {
  545. // already lower case
  546. CFunnyPath::AppendPath( wcsPath, cc );
  547. AssertLowerCase( GetActualPath(), GetActualLength() );
  548. return;
  549. }
  550. AssertValid();
  551. Win4Assert( wcsPath );
  552. if ( 0 == cc )
  553. {
  554. cc = wcslen( wcsPath );
  555. }
  556. ToLower( wcsPath, cc, _ccActualBuf );
  557. }
  558. inline void CLowerFunnyPath::ToLower(
  559. const WCHAR * wcsPath,
  560. unsigned cc,
  561. unsigned ccStart )
  562. {
  563. WCHAR * pwcDestActualPath;
  564. unsigned ccDestActualCount;
  565. Win4Assert( wcsPath );
  566. if ( !cc )
  567. {
  568. return;
  569. }
  570. #if CIDBG == 1
  571. // Variable to try lowercasing again due to some random
  572. // failures with LCMapStringW
  573. BOOL fTryAgain = TRUE;
  574. #endif
  575. while ( TRUE )
  576. {
  577. if ( _fRemote )
  578. {
  579. pwcDestActualPath = &_xBuf[_UNC_FUNNY_PATH_LENGTH] + ccStart;
  580. ccDestActualCount = _xBuf.Count() - (_UNC_FUNNY_PATH_LENGTH + ccStart);
  581. }
  582. else
  583. {
  584. pwcDestActualPath = &_xBuf[_FUNNY_PATH_LENGTH] + ccStart;
  585. ccDestActualCount = _xBuf.Count() - (_FUNNY_PATH_LENGTH + ccStart);
  586. }
  587. if ( ccDestActualCount < 2 )
  588. {
  589. // Need to allocate more memory
  590. _xBuf.SetSize( _xBuf.Count() * 2 );
  591. continue;
  592. }
  593. unsigned cchLen = LCMapStringW ( LOCALE_NEUTRAL,
  594. LCMAP_LOWERCASE,
  595. wcsPath,
  596. cc,
  597. pwcDestActualPath,
  598. ccDestActualCount - 1 );
  599. if ( 0 == cchLen )
  600. {
  601. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  602. {
  603. _xBuf.SetSize( _xBuf.Count() * 2 );
  604. }
  605. else
  606. {
  607. ciDebugOut(( DEB_ERROR, "Error 0x%x lowercasing path\n", GetLastError() ));
  608. #if CIDBG == 1
  609. if ( fTryAgain )
  610. {
  611. fTryAgain = FALSE;
  612. Win4Assert(( !"neutral lowercase failed. Trying again..." ));
  613. continue;
  614. }
  615. #endif
  616. Win4Assert(( !"neutral lowercase failed" ));
  617. THROW( CException() );
  618. }
  619. }
  620. else
  621. {
  622. Win4Assert( cchLen < ccDestActualCount );
  623. pwcDestActualPath[ cchLen ] = 0;
  624. _ccActualBuf = ccStart + cchLen;
  625. break;
  626. }
  627. }
  628. }
  629. //+---------------------------------------------------------------------------
  630. //
  631. // Member: CLowerFunnyPath::ConvertToLongName, public
  632. //
  633. // Synopsis: Converts file path name components to long names.
  634. //
  635. // Returns: TRUE if conversion was successful.
  636. //
  637. // Notes: GetLongPathNameW will fail with remote funny paths because
  638. // it will try to call FindFirstFileW on the machine name and
  639. // share name.
  640. //
  641. // History: 06-Jan-98 KyleP Created
  642. //
  643. //----------------------------------------------------------------------------
  644. inline BOOL CLowerFunnyPath::ConvertToLongName()
  645. {
  646. XGrowable<WCHAR> wcsTemp;
  647. WCHAR * pwcsShortName;
  648. unsigned ccFunnyChars;
  649. if (IsRemote())
  650. {
  651. pwcsShortName = _GetActualPath();
  652. ccFunnyChars = 0;
  653. }
  654. else
  655. {
  656. pwcsShortName = (WCHAR *)GetPath();
  657. ccFunnyChars = _FUNNY_PATH_LENGTH;
  658. }
  659. DWORD ccOut = GetLongPathNameW( pwcsShortName, // Short name
  660. wcsTemp.Get(), // Long name
  661. wcsTemp.Count() - 1 );
  662. if ( ccOut > wcsTemp.Count() - 1 )
  663. {
  664. // Need to grow the buffer
  665. wcsTemp.SetSize( ccOut + 1 );
  666. ccOut = GetLongPathNameW( pwcsShortName, // Short name
  667. wcsTemp.Get(), // Long name
  668. wcsTemp.Count() - 1 );
  669. Win4Assert( ccOut <= wcsTemp.Count() - 1 );
  670. }
  671. if ( 0 == ccOut )
  672. {
  673. ciDebugOut(( DEB_WARN, "GetLongPathName( %ws ) returned %d\n",
  674. pwcsShortName, GetLastError() ));
  675. return FALSE;
  676. }
  677. SetPath( wcsTemp.Get() + ccFunnyChars, ccOut - ccFunnyChars );
  678. return TRUE;
  679. }
  680. //
  681. // Stack class for FunnyPath
  682. //
  683. DECL_DYNSTACK( _CLowerFunnyStack, CLowerFunnyPath )
  684. class CLowerFunnyStack : protected _CLowerFunnyStack
  685. {
  686. public:
  687. BOOL Pop( XPtr<CLowerFunnyPath> & xLowerFunnyPath )
  688. {
  689. if (Count() == 0)
  690. {
  691. return FALSE;
  692. }
  693. xLowerFunnyPath.Set( _CLowerFunnyStack::Pop() );
  694. return TRUE;
  695. }
  696. void Push( const CLowerFunnyPath & funnyElem )
  697. {
  698. XPtr<CLowerFunnyPath> xLowerFunnyPath( new CLowerFunnyPath(funnyElem) );
  699. _CLowerFunnyStack::Push( xLowerFunnyPath.GetPointer() );
  700. xLowerFunnyPath.Acquire();
  701. }
  702. };