Leaked source code of windows server 2003
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.

693 lines
17 KiB

  1. /* vdir.h
  2. *
  3. * (c) 1999 Microsoft Corporation. All rights reserved.
  4. * Portions (c) 1999 ActiveState Tool Corp, http://www.ActiveState.com/
  5. *
  6. * You may distribute under the terms of either the GNU General Public
  7. * License or the Artistic License, as specified in the README file.
  8. */
  9. #ifndef ___VDir_H___
  10. #define ___VDir_H___
  11. /*
  12. * Allow one slot for each possible drive letter
  13. * and one additional slot for a UNC name
  14. */
  15. const int driveCount = ('Z'-'A')+1+1;
  16. class VDir
  17. {
  18. public:
  19. VDir(int bManageDir = 1);
  20. ~VDir() {};
  21. void Init(VDir* pDir, VMem *pMem);
  22. void SetDefaultA(char const *pDefault);
  23. void SetDefaultW(WCHAR const *pDefault);
  24. char* MapPathA(const char *pInName);
  25. WCHAR* MapPathW(const WCHAR *pInName);
  26. int SetCurrentDirectoryA(char *lpBuffer);
  27. int SetCurrentDirectoryW(WCHAR *lpBuffer);
  28. inline int GetDefault(void) { return nDefault; };
  29. inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer)
  30. {
  31. char* ptr = dirTableA[nDefault];
  32. while (dwBufSize--)
  33. {
  34. if ((*lpBuffer++ = *ptr++) == '\0')
  35. break;
  36. }
  37. return lpBuffer;
  38. };
  39. inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer)
  40. {
  41. WCHAR* ptr = dirTableW[nDefault];
  42. while (dwBufSize--)
  43. {
  44. if ((*lpBuffer++ = *ptr++) == '\0')
  45. break;
  46. }
  47. return lpBuffer;
  48. };
  49. DWORD CalculateEnvironmentSpace(void);
  50. LPSTR BuildEnvironmentSpace(LPSTR lpStr);
  51. protected:
  52. int SetDirA(char const *pPath, int index);
  53. void FromEnvA(char *pEnv, int index);
  54. inline const char *GetDefaultDirA(void)
  55. {
  56. return dirTableA[nDefault];
  57. };
  58. inline void SetDefaultDirA(char const *pPath, int index)
  59. {
  60. SetDirA(pPath, index);
  61. nDefault = index;
  62. };
  63. int SetDirW(WCHAR const *pPath, int index);
  64. inline const WCHAR *GetDefaultDirW(void)
  65. {
  66. return dirTableW[nDefault];
  67. };
  68. inline void SetDefaultDirW(WCHAR const *pPath, int index)
  69. {
  70. SetDirW(pPath, index);
  71. nDefault = index;
  72. };
  73. inline const char *GetDirA(int index)
  74. {
  75. char *ptr = dirTableA[index];
  76. if (!ptr) {
  77. /* simulate the existance of this drive */
  78. ptr = szLocalBufferA;
  79. ptr[0] = 'A' + index;
  80. ptr[1] = ':';
  81. ptr[2] = '\\';
  82. ptr[3] = 0;
  83. }
  84. return ptr;
  85. };
  86. inline const WCHAR *GetDirW(int index)
  87. {
  88. WCHAR *ptr = dirTableW[index];
  89. if (!ptr) {
  90. /* simulate the existance of this drive */
  91. ptr = szLocalBufferW;
  92. ptr[0] = 'A' + index;
  93. ptr[1] = ':';
  94. ptr[2] = '\\';
  95. ptr[3] = 0;
  96. }
  97. return ptr;
  98. };
  99. inline int DriveIndex(char chr)
  100. {
  101. if (chr == '\\' || chr == '/')
  102. return ('Z'-'A')+1;
  103. return (chr | 0x20)-'a';
  104. };
  105. VMem *pMem;
  106. int nDefault, bManageDirectory;
  107. char *dirTableA[driveCount];
  108. char szLocalBufferA[MAX_PATH+1];
  109. WCHAR *dirTableW[driveCount];
  110. WCHAR szLocalBufferW[MAX_PATH+1];
  111. };
  112. VDir::VDir(int bManageDir /* = 1 */)
  113. {
  114. nDefault = 0;
  115. bManageDirectory = bManageDir;
  116. memset(dirTableA, 0, sizeof(dirTableA));
  117. memset(dirTableW, 0, sizeof(dirTableW));
  118. }
  119. void VDir::Init(VDir* pDir, VMem *p)
  120. {
  121. int index;
  122. DWORD driveBits;
  123. int nSave;
  124. char szBuffer[MAX_PATH*driveCount];
  125. pMem = p;
  126. if (pDir) {
  127. for (index = 0; index < driveCount; ++index) {
  128. SetDirW(pDir->GetDirW(index), index);
  129. }
  130. nDefault = pDir->GetDefault();
  131. }
  132. else {
  133. nSave = bManageDirectory;
  134. bManageDirectory = 0;
  135. driveBits = GetLogicalDrives();
  136. if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) {
  137. char* pEnv = GetEnvironmentStrings();
  138. char* ptr = szBuffer;
  139. for (index = 0; index < driveCount; ++index) {
  140. if (driveBits & (1<<index)) {
  141. ptr += SetDirA(ptr, index) + 1;
  142. FromEnvA(pEnv, index);
  143. }
  144. }
  145. FreeEnvironmentStrings(pEnv);
  146. }
  147. SetDefaultA(".");
  148. bManageDirectory = nSave;
  149. }
  150. }
  151. int VDir::SetDirA(char const *pPath, int index)
  152. {
  153. char chr, *ptr;
  154. int length = 0;
  155. WCHAR wBuffer[MAX_PATH+1];
  156. if (index < driveCount && pPath != NULL) {
  157. length = strlen(pPath);
  158. pMem->Free(dirTableA[index]);
  159. ptr = dirTableA[index] = (char*)pMem->Malloc(length+2);
  160. if (ptr != NULL) {
  161. strcpy(ptr, pPath);
  162. ptr += length-1;
  163. chr = *ptr++;
  164. if (chr != '\\' && chr != '/') {
  165. *ptr++ = '\\';
  166. *ptr = '\0';
  167. }
  168. MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1,
  169. wBuffer, (sizeof(wBuffer)/sizeof(WCHAR)));
  170. length = wcslen(wBuffer);
  171. pMem->Free(dirTableW[index]);
  172. dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2);
  173. if (dirTableW[index] != NULL) {
  174. wcscpy(dirTableW[index], wBuffer);
  175. }
  176. }
  177. }
  178. if(bManageDirectory)
  179. ::SetCurrentDirectoryA(pPath);
  180. return length;
  181. }
  182. void VDir::FromEnvA(char *pEnv, int index)
  183. { /* gets the directory for index from the environment variable. */
  184. while (*pEnv != '\0') {
  185. if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) {
  186. SetDirA(&pEnv[4], index);
  187. break;
  188. }
  189. else
  190. pEnv += strlen(pEnv)+1;
  191. }
  192. }
  193. void VDir::SetDefaultA(char const *pDefault)
  194. {
  195. char szBuffer[MAX_PATH+1];
  196. char *pPtr;
  197. if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) {
  198. if (*pDefault != '.' && pPtr != NULL)
  199. *pPtr = '\0';
  200. SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
  201. }
  202. }
  203. int VDir::SetDirW(WCHAR const *pPath, int index)
  204. {
  205. WCHAR chr, *ptr;
  206. char szBuffer[MAX_PATH+1];
  207. int length = 0;
  208. if (index < driveCount && pPath != NULL) {
  209. length = wcslen(pPath);
  210. pMem->Free(dirTableW[index]);
  211. ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2);
  212. if (ptr != NULL) {
  213. wcscpy(ptr, pPath);
  214. ptr += length-1;
  215. chr = *ptr++;
  216. if (chr != '\\' && chr != '/') {
  217. *ptr++ = '\\';
  218. *ptr = '\0';
  219. }
  220. WideCharToMultiByte(CP_ACP, 0, dirTableW[index], -1, szBuffer, sizeof(szBuffer), NULL, NULL);
  221. length = strlen(szBuffer);
  222. pMem->Free(dirTableA[index]);
  223. dirTableA[index] = (char*)pMem->Malloc(length+1);
  224. if (dirTableA[index] != NULL) {
  225. strcpy(dirTableA[index], szBuffer);
  226. }
  227. }
  228. }
  229. if(bManageDirectory)
  230. ::SetCurrentDirectoryW(pPath);
  231. return length;
  232. }
  233. void VDir::SetDefaultW(WCHAR const *pDefault)
  234. {
  235. WCHAR szBuffer[MAX_PATH+1];
  236. WCHAR *pPtr;
  237. if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) {
  238. if (*pDefault != '.' && pPtr != NULL)
  239. *pPtr = '\0';
  240. SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
  241. }
  242. }
  243. inline BOOL IsPathSep(char ch)
  244. {
  245. return (ch == '\\' || ch == '/');
  246. }
  247. inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest)
  248. {
  249. char *pPtr;
  250. /*
  251. * On WinNT GetFullPathName does not fail, (or at least always
  252. * succeeds when the drive is valid) WinNT does set *Dest to Nullch
  253. * On Win98 GetFullPathName will set last error if it fails, but
  254. * does not touch *Dest
  255. */
  256. *Dest = '\0';
  257. GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr);
  258. }
  259. inline bool IsSpecialFileName(const char* pName)
  260. {
  261. /* specical file names are devices that the system can open
  262. * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
  263. * (x is a single digit, and names are case-insensitive)
  264. */
  265. char ch = (pName[0] & ~0x20);
  266. switch (ch)
  267. {
  268. case 'A': /* AUX */
  269. if (((pName[1] & ~0x20) == 'U')
  270. && ((pName[2] & ~0x20) == 'X')
  271. && !pName[3])
  272. return true;
  273. break;
  274. case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */
  275. ch = (pName[1] & ~0x20);
  276. switch (ch)
  277. {
  278. case 'L': /* CLOCK$ */
  279. if (((pName[2] & ~0x20) == 'O')
  280. && ((pName[3] & ~0x20) == 'C')
  281. && ((pName[4] & ~0x20) == 'K')
  282. && (pName[5] == '$')
  283. && !pName[6])
  284. return true;
  285. break;
  286. case 'O': /* COMx, CON, CONIN$ CONOUT$ */
  287. if ((pName[2] & ~0x20) == 'M') {
  288. if ((pName[3] >= '1') && (pName[3] <= '9')
  289. && !pName[4])
  290. return true;
  291. }
  292. else if ((pName[2] & ~0x20) == 'N') {
  293. if (!pName[3])
  294. return true;
  295. else if ((pName[3] & ~0x20) == 'I') {
  296. if (((pName[4] & ~0x20) == 'N')
  297. && (pName[5] == '$')
  298. && !pName[6])
  299. return true;
  300. }
  301. else if ((pName[3] & ~0x20) == 'O') {
  302. if (((pName[4] & ~0x20) == 'U')
  303. && ((pName[5] & ~0x20) == 'T')
  304. && (pName[6] == '$')
  305. && !pName[7])
  306. return true;
  307. }
  308. }
  309. break;
  310. }
  311. break;
  312. case 'L': /* LPTx */
  313. if (((pName[1] & ~0x20) == 'U')
  314. && ((pName[2] & ~0x20) == 'X')
  315. && (pName[3] >= '1') && (pName[3] <= '9')
  316. && !pName[4])
  317. return true;
  318. break;
  319. case 'N': /* NUL */
  320. if (((pName[1] & ~0x20) == 'U')
  321. && ((pName[2] & ~0x20) == 'L')
  322. && !pName[3])
  323. return true;
  324. break;
  325. case 'P': /* PRN */
  326. if (((pName[1] & ~0x20) == 'R')
  327. && ((pName[2] & ~0x20) == 'N')
  328. && !pName[3])
  329. return true;
  330. break;
  331. }
  332. return false;
  333. }
  334. char *VDir::MapPathA(const char *pInName)
  335. { /*
  336. * possiblities -- relative path or absolute path with or without drive letter
  337. * OR UNC name
  338. */
  339. char szBuffer[(MAX_PATH+1)*2];
  340. char szlBuf[MAX_PATH+1];
  341. int length = strlen(pInName);
  342. if (!length)
  343. return (char*)pInName;
  344. if (length > MAX_PATH) {
  345. strncpy(szlBuf, pInName, MAX_PATH);
  346. if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
  347. /* absolute path - reduce length by 2 for drive specifier */
  348. szlBuf[MAX_PATH-2] = '\0';
  349. }
  350. else
  351. szlBuf[MAX_PATH] = '\0';
  352. pInName = szlBuf;
  353. }
  354. /* strlen(pInName) is now <= MAX_PATH */
  355. if (pInName[1] == ':') {
  356. /* has drive letter */
  357. if (IsPathSep(pInName[2])) {
  358. /* absolute with drive letter */
  359. strcpy(szLocalBufferA, pInName);
  360. }
  361. else {
  362. /* relative path with drive letter */
  363. strcpy(szBuffer, GetDirA(DriveIndex(*pInName)));
  364. strcat(szBuffer, &pInName[2]);
  365. if(strlen(szBuffer) > MAX_PATH)
  366. szBuffer[MAX_PATH] = '\0';
  367. DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
  368. }
  369. }
  370. else {
  371. /* no drive letter */
  372. if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
  373. /* UNC name */
  374. strcpy(szLocalBufferA, pInName);
  375. }
  376. else {
  377. strcpy(szBuffer, GetDefaultDirA());
  378. if (IsPathSep(pInName[0])) {
  379. /* absolute path */
  380. szLocalBufferA[0] = szBuffer[0];
  381. szLocalBufferA[1] = szBuffer[1];
  382. strcpy(&szLocalBufferA[2], pInName);
  383. }
  384. else {
  385. /* relative path */
  386. if (IsSpecialFileName(pInName)) {
  387. return (char*)pInName;
  388. }
  389. else {
  390. strcat(szBuffer, pInName);
  391. if (strlen(szBuffer) > MAX_PATH)
  392. szBuffer[MAX_PATH] = '\0';
  393. DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
  394. }
  395. }
  396. }
  397. }
  398. return szLocalBufferA;
  399. }
  400. int VDir::SetCurrentDirectoryA(char *lpBuffer)
  401. {
  402. char *pPtr;
  403. int length, nRet = -1;
  404. pPtr = MapPathA(lpBuffer);
  405. length = strlen(pPtr);
  406. if(length > 3 && IsPathSep(pPtr[length-1])) {
  407. /* don't remove the trailing slash from 'x:\' */
  408. pPtr[length-1] = '\0';
  409. }
  410. DWORD r = GetFileAttributesA(pPtr);
  411. if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
  412. {
  413. char szBuffer[(MAX_PATH+1)*2];
  414. DoGetFullPathNameA(pPtr, sizeof(szBuffer), szBuffer);
  415. SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
  416. nRet = 0;
  417. }
  418. return nRet;
  419. }
  420. DWORD VDir::CalculateEnvironmentSpace(void)
  421. { /* the current directory environment strings are stored as '=D:=d:\path' */
  422. int index;
  423. DWORD dwSize = 0;
  424. for (index = 0; index < driveCount; ++index) {
  425. if (dirTableA[index] != NULL) {
  426. dwSize += strlen(dirTableA[index]) + 5; /* add 1 for trailing NULL and 4 for '=D:=' */
  427. }
  428. }
  429. return dwSize;
  430. }
  431. LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr)
  432. { /* store the current directory environment strings as '=D:=d:\path' */
  433. int index, length;
  434. LPSTR lpDirStr;
  435. for (index = 0; index < driveCount; ++index) {
  436. lpDirStr = dirTableA[index];
  437. if (lpDirStr != NULL) {
  438. lpStr[0] = '=';
  439. lpStr[1] = lpDirStr[0];
  440. lpStr[2] = '\0';
  441. CharUpper(&lpStr[1]);
  442. lpStr[2] = ':';
  443. lpStr[3] = '=';
  444. strcpy(&lpStr[4], lpDirStr);
  445. length = strlen(lpDirStr);
  446. lpStr += length + 5; /* add 1 for trailing NULL and 4 for '=D:=' */
  447. if (length > 3 && IsPathSep(lpStr[-2])) {
  448. lpStr[-2] = '\0'; /* remove the trailing path separator */
  449. --lpStr;
  450. }
  451. }
  452. }
  453. return lpStr;
  454. }
  455. inline BOOL IsPathSep(WCHAR ch)
  456. {
  457. return (ch == '\\' || ch == '/');
  458. }
  459. inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest)
  460. {
  461. WCHAR *pPtr;
  462. /*
  463. * On WinNT GetFullPathName does not fail, (or at least always
  464. * succeeds when the drive is valid) WinNT does set *Dest to Nullch
  465. * On Win98 GetFullPathName will set last error if it fails, but
  466. * does not touch *Dest
  467. */
  468. *Dest = '\0';
  469. GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr);
  470. }
  471. inline bool IsSpecialFileName(const WCHAR* pName)
  472. {
  473. /* specical file names are devices that the system can open
  474. * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
  475. * (x is a single digit, and names are case-insensitive)
  476. */
  477. WCHAR ch = (pName[0] & ~0x20);
  478. switch (ch)
  479. {
  480. case 'A': /* AUX */
  481. if (((pName[1] & ~0x20) == 'U')
  482. && ((pName[2] & ~0x20) == 'X')
  483. && !pName[3])
  484. return true;
  485. break;
  486. case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */
  487. ch = (pName[1] & ~0x20);
  488. switch (ch)
  489. {
  490. case 'L': /* CLOCK$ */
  491. if (((pName[2] & ~0x20) == 'O')
  492. && ((pName[3] & ~0x20) == 'C')
  493. && ((pName[4] & ~0x20) == 'K')
  494. && (pName[5] == '$')
  495. && !pName[6])
  496. return true;
  497. break;
  498. case 'O': /* COMx, CON, CONIN$ CONOUT$ */
  499. if ((pName[2] & ~0x20) == 'M') {
  500. if ((pName[3] >= '1') && (pName[3] <= '9')
  501. && !pName[4])
  502. return true;
  503. }
  504. else if ((pName[2] & ~0x20) == 'N') {
  505. if (!pName[3])
  506. return true;
  507. else if ((pName[3] & ~0x20) == 'I') {
  508. if (((pName[4] & ~0x20) == 'N')
  509. && (pName[5] == '$')
  510. && !pName[6])
  511. return true;
  512. }
  513. else if ((pName[3] & ~0x20) == 'O') {
  514. if (((pName[4] & ~0x20) == 'U')
  515. && ((pName[5] & ~0x20) == 'T')
  516. && (pName[6] == '$')
  517. && !pName[7])
  518. return true;
  519. }
  520. }
  521. break;
  522. }
  523. break;
  524. case 'L': /* LPTx */
  525. if (((pName[1] & ~0x20) == 'U')
  526. && ((pName[2] & ~0x20) == 'X')
  527. && (pName[3] >= '1') && (pName[3] <= '9')
  528. && !pName[4])
  529. return true;
  530. break;
  531. case 'N': /* NUL */
  532. if (((pName[1] & ~0x20) == 'U')
  533. && ((pName[2] & ~0x20) == 'L')
  534. && !pName[3])
  535. return true;
  536. break;
  537. case 'P': /* PRN */
  538. if (((pName[1] & ~0x20) == 'R')
  539. && ((pName[2] & ~0x20) == 'N')
  540. && !pName[3])
  541. return true;
  542. break;
  543. }
  544. return false;
  545. }
  546. WCHAR* VDir::MapPathW(const WCHAR *pInName)
  547. { /*
  548. * possiblities -- relative path or absolute path with or without drive letter
  549. * OR UNC name
  550. */
  551. WCHAR szBuffer[(MAX_PATH+1)*2];
  552. WCHAR szlBuf[MAX_PATH+1];
  553. int length = wcslen(pInName);
  554. if (!length)
  555. return (WCHAR*)pInName;
  556. if (length > MAX_PATH) {
  557. wcsncpy(szlBuf, pInName, MAX_PATH);
  558. if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
  559. /* absolute path - reduce length by 2 for drive specifier */
  560. szlBuf[MAX_PATH-2] = '\0';
  561. }
  562. else
  563. szlBuf[MAX_PATH] = '\0';
  564. pInName = szlBuf;
  565. }
  566. /* strlen(pInName) is now <= MAX_PATH */
  567. if (pInName[1] == ':') {
  568. /* has drive letter */
  569. if (IsPathSep(pInName[2])) {
  570. /* absolute with drive letter */
  571. wcscpy(szLocalBufferW, pInName);
  572. }
  573. else {
  574. /* relative path with drive letter */
  575. wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName)));
  576. wcscat(szBuffer, &pInName[2]);
  577. if(wcslen(szBuffer) > MAX_PATH)
  578. szBuffer[MAX_PATH] = '\0';
  579. DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
  580. }
  581. }
  582. else {
  583. /* no drive letter */
  584. if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
  585. /* UNC name */
  586. wcscpy(szLocalBufferW, pInName);
  587. }
  588. else {
  589. wcscpy(szBuffer, GetDefaultDirW());
  590. if (IsPathSep(pInName[0])) {
  591. /* absolute path */
  592. szLocalBufferW[0] = szBuffer[0];
  593. szLocalBufferW[1] = szBuffer[1];
  594. wcscpy(&szLocalBufferW[2], pInName);
  595. }
  596. else {
  597. /* relative path */
  598. if (IsSpecialFileName(pInName)) {
  599. return (WCHAR*)pInName;
  600. }
  601. else {
  602. wcscat(szBuffer, pInName);
  603. if (wcslen(szBuffer) > MAX_PATH)
  604. szBuffer[MAX_PATH] = '\0';
  605. DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
  606. }
  607. }
  608. }
  609. }
  610. return szLocalBufferW;
  611. }
  612. int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer)
  613. {
  614. WCHAR *pPtr;
  615. int length, nRet = -1;
  616. pPtr = MapPathW(lpBuffer);
  617. length = wcslen(pPtr);
  618. if(length > 3 && IsPathSep(pPtr[length-1])) {
  619. /* don't remove the trailing slash from 'x:\' */
  620. pPtr[length-1] = '\0';
  621. }
  622. DWORD r = GetFileAttributesW(pPtr);
  623. if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
  624. {
  625. WCHAR wBuffer[(MAX_PATH+1)*2];
  626. DoGetFullPathNameW(pPtr, (sizeof(wBuffer)/sizeof(WCHAR)), wBuffer);
  627. SetDefaultDirW(wBuffer, DriveIndex((char)wBuffer[0]));
  628. nRet = 0;
  629. }
  630. return nRet;
  631. }
  632. #endif /* ___VDir_H___ */