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.

610 lines
17 KiB

  1. // PSeuDO CURrentDirectory module (psdocurd.c)
  2. //
  3. // This was swiped from cmd.exe sources to use the environment to emulate
  4. // per process per drive current directory stuff.
  5. //
  6. // This uses the special '=A:=' environment strings to remember the
  7. // current directories.
  8. //
  9. // Since the library is a DLL, all globals are process based.
  10. //
  11. #define UNICODE 1
  12. #include "shellprv.h"
  13. #pragma hdrstop
  14. #define SUCCESS FALSE
  15. #define FAILURE TRUE
  16. #define GD_DEFAULT 0
  17. WCHAR CurDrvDirW[MAX_PATH] = L"";
  18. #define DBL_BSLASH(sz) \
  19. (*(WCHAR *)(sz) == CHAR_BSLASH) && \
  20. (*(WCHAR *)((sz)+1) == CHAR_BSLASH)
  21. INT
  22. SheSetEnvVarW(
  23. WCHAR *varname,
  24. WCHAR *varvalue
  25. )
  26. {
  27. if (!wcslen(varvalue)) {
  28. varvalue = NULL; // null to remove from env
  29. }
  30. return (!SetEnvironmentVariable(varname, varvalue));
  31. }
  32. WCHAR *
  33. SheGetEnvVarW(
  34. WCHAR *varname)
  35. {
  36. static WCHAR GetEnvVarBuffer[ 1024 ];
  37. if (GetEnvironmentVariableW(varname, GetEnvVarBuffer, 1024)) {
  38. return(GetEnvVarBuffer);
  39. } else {
  40. return(NULL);
  41. }
  42. }
  43. INT
  44. SheGetPathOffsetW(
  45. LPWSTR lpszDir)
  46. {
  47. // sanity
  48. if (!lpszDir || !*lpszDir) {
  49. return(-1);
  50. }
  51. if ((*(lpszDir+1) == WCHAR_COLON) &&
  52. ((*(lpszDir+2) == WCHAR_BSLASH) ||
  53. (*(lpszDir+2) == WCHAR_SLASH) ||
  54. (*(lpszDir+2) == WCHAR_NULL)) ) {
  55. return(2);
  56. } else if (DBL_BSLASH(lpszDir)) {
  57. // Deviceless, assume LanMan Provided UNC names (i.e. DBL_BSLASH above)
  58. INT cchServerShareLen = -1;
  59. DWORD dwSlashesSeen = 0;
  60. // There are exactly 4 b-slashes from here
  61. while (dwSlashesSeen != 4) {
  62. cchServerShareLen++;
  63. if (!*lpszDir) {
  64. if (dwSlashesSeen == 3) {
  65. return(cchServerShareLen);
  66. } else {
  67. return(-1);
  68. }
  69. }
  70. if ((*lpszDir == CHAR_BSLASH) || (*lpszDir == CHAR_SLASH)) {
  71. dwSlashesSeen++;
  72. }
  73. lpszDir++;
  74. }
  75. return(cchServerShareLen);
  76. } else {
  77. // unrecognized format
  78. return(-1);
  79. }
  80. }
  81. INT
  82. SheGetDirW(
  83. INT iDrive, // 0 = default, 1=A....
  84. WCHAR *str
  85. )
  86. {
  87. WCHAR denvname[ 4 ];
  88. WCHAR *denvvalue;
  89. WCHAR *strT = str;
  90. if (iDrive-- == GD_DEFAULT) {
  91. GetCurrentDirectoryW(MAX_PATH, str); // pray that str is at least MAX_PATH
  92. return(SUCCESS);
  93. }
  94. denvname[ 0 ] = WCHAR_EQUAL;
  95. denvname[ 1 ] = (WCHAR)(WCHAR_CAP_A + (WCHAR)iDrive);
  96. denvname[ 2 ] = WCHAR_COLON;
  97. denvname[ 3 ] = WCHAR_NULL;
  98. denvvalue = SheGetEnvVarW( denvname );
  99. if (!denvvalue) {
  100. *str++ = (WCHAR)(WCHAR_CAP_A + (WCHAR)iDrive);
  101. *str++ = WCHAR_COLON;
  102. *str++ = WCHAR_BSLASH;
  103. *str = WCHAR_NULL;
  104. }
  105. else {
  106. if (FAILED(StringCchCopy(str, MAX_PATH, denvvalue)))
  107. {
  108. return FAILURE;
  109. }
  110. }
  111. // there is a subtle difference between getcurrentdirectory() of DOS and the
  112. // equivalent SheGetDir() of NT. On dos, getcurrentdirectory() accesses the
  113. // floppy drives while in NT SheGetDir() returns the values that are set in
  114. // the environment variables. So we hit the disk on NT too, by calling
  115. // GetFileAttributes. We return SUCCESS or FAILURE based on the return value
  116. // of GetFileAttributes.
  117. if (GetFileAttributesW(strT) == (DWORD)0xffffffff)
  118. return(FAILURE);
  119. else
  120. return(SUCCESS);
  121. }
  122. // Should be BOOL, but possible mips breakage
  123. INT
  124. SheGetDirA(
  125. INT iDrive, // 0 = default, 1=A....
  126. CHAR *szDirA)
  127. {
  128. WCHAR szDirW[MAX_PATH];
  129. BOOL fDefCharUsed;
  130. INT nRet;
  131. if (!szDirA) {
  132. return(FAILURE);
  133. }
  134. nRet = SheGetDirW(iDrive, szDirW);
  135. if (SUCCESS == nRet)
  136. {
  137. WideCharToMultiByte(CP_ACP, 0, szDirW, -1, (LPSTR)szDirA,
  138. MAX_PATH, NULL, &fDefCharUsed);
  139. }
  140. return(nRet);
  141. }
  142. INT
  143. SheChangeDirW(
  144. WCHAR *newdir
  145. )
  146. {
  147. WCHAR denvname[ 4 ];
  148. WCHAR newpath[ MAX_PATH ];
  149. WCHAR denvvalue[ MAX_PATH ];
  150. WCHAR c, *s;
  151. DWORD attr;
  152. GetCurrentDirectoryW( MAX_PATH, denvvalue );
  153. c = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)denvvalue[0]);
  154. denvname[0] = WCHAR_EQUAL;
  155. if (IsCharAlphaW(*newdir) && newdir[1] == WCHAR_COLON) {
  156. denvname[1] = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)*newdir);
  157. newdir += 2;
  158. } else {
  159. denvname[ 1 ] = c;
  160. }
  161. denvname[ 2 ] = WCHAR_COLON;
  162. denvname[ 3 ] = WCHAR_NULL;
  163. if ((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH)) {
  164. newpath[ 0 ] = denvname[ 1 ];
  165. newpath[ 1 ] = denvname[ 2 ];
  166. if (FAILED(StringCchCopy( &newpath[ 2 ], ARRAYSIZE(newpath) - 2, newdir)))
  167. {
  168. return ERROR_BUFFER_OVERFLOW;
  169. }
  170. } else {
  171. if (NULL != (s = SheGetEnvVarW( denvname )))
  172. {
  173. if (FAILED(StringCchCopy(newpath, ARRAYSIZE(newpath), s)))
  174. {
  175. return ERROR_BUFFER_OVERFLOW;
  176. }
  177. }
  178. else
  179. {
  180. newpath[ 0 ] = denvname[ 1 ];
  181. newpath[ 1 ] = denvname[ 2 ];
  182. newpath[ 2 ] = WCHAR_NULL;
  183. }
  184. s = newpath + wcslen( newpath );
  185. *s++ = WCHAR_BSLASH;
  186. if (FAILED(StringCchCopy(s, ARRAYSIZE(newpath) - (s - newpath), newdir)))
  187. {
  188. return ERROR_BUFFER_OVERFLOW;
  189. }
  190. }
  191. if (!GetFullPathNameW(newpath, MAX_PATH, denvvalue, &s )) {
  192. return( ERROR_ACCESS_DENIED );
  193. }
  194. attr = GetFileAttributesW( denvvalue );
  195. if (attr == -1 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  196. return( ERROR_ACCESS_DENIED );
  197. }
  198. if (SheSetEnvVarW(denvname,denvvalue)) {
  199. return( ERROR_NOT_ENOUGH_MEMORY );
  200. }
  201. SetCurrentDirectoryW( denvvalue );
  202. // this seems wrong... SheGetDir(GD_DEFAULT, CurDrvDirW) ;
  203. if (FAILED(StringCchCopy(CurDrvDirW, ARRAYSIZE(CurDrvDirW), denvvalue))) // this seems right to me.
  204. {
  205. return (ERROR_BUFFER_OVERFLOW);
  206. }
  207. return(SUCCESS) ;
  208. }
  209. INT
  210. SheChangeDirA(
  211. CHAR *szNewDirA
  212. )
  213. {
  214. INT iRet;
  215. WCHAR szNewDirW[MAX_PATH];
  216. if (szNewDirA &&
  217. MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH))
  218. {
  219. iRet = SheChangeDirW(szNewDirW);
  220. }
  221. else
  222. {
  223. iRet = FAILURE;
  224. }
  225. return iRet;
  226. }
  227. INT
  228. SheChangeDirExW(
  229. WCHAR *newdir)
  230. {
  231. WCHAR wcEnvName[MAX_PATH];
  232. WCHAR wcNewPath[MAX_PATH];
  233. WCHAR wcEnvValue[MAX_PATH];
  234. DWORD cchPathOffset;
  235. WCHAR *s;
  236. DWORD attr;
  237. BOOL bUsedEnv = FALSE;
  238. if (newdir && *newdir &&
  239. ((cchPathOffset = SheGetPathOffsetW(newdir)) != 0xFFFFFFFF)) {
  240. WCHAR wc = newdir[cchPathOffset];
  241. newdir[cchPathOffset] = WCHAR_NULL;
  242. if (FAILED(StringCchCopy(&wcEnvName[1],
  243. ARRAYSIZE(wcEnvName) - 1,
  244. newdir)))
  245. {
  246. return ERROR_BUFFER_OVERFLOW;
  247. }
  248. newdir[cchPathOffset] = wc;
  249. newdir += cchPathOffset;
  250. } else {
  251. GetCurrentDirectoryW(MAX_PATH, wcEnvValue);
  252. if (FAILED(StringCchCopy(&wcEnvName[1],
  253. ARRAYSIZE(wcEnvName) - 1,
  254. wcEnvValue)))
  255. {
  256. return ERROR_BUFFER_OVERFLOW;
  257. }
  258. }
  259. wcEnvName[0] = WCHAR_EQUAL;
  260. if ((cchPathOffset = SheGetPathOffsetW(&wcEnvName[1])) != 0xFFFFFFFF) {
  261. // add one since the first character is "="
  262. wcEnvName[cchPathOffset + 1] = WCHAR_NULL;
  263. }
  264. //
  265. // If return value is 2, then we are a drive letter like A:
  266. // We need to uppercase the drive letter here, since the environ
  267. // vars are usually set as uppercase.
  268. //
  269. if (cchPathOffset == 2) {
  270. wcEnvName[1] = (WCHAR)(DWORD_PTR)CharUpper((LPWSTR)(DWORD_PTR) wcEnvName[1]);
  271. }
  272. if (newdir && *newdir &&
  273. ((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH))) {
  274. if (FAILED(StringCchCopy(wcNewPath,
  275. ARRAYSIZE(wcNewPath),
  276. &wcEnvName[1])))
  277. {
  278. return ERROR_BUFFER_OVERFLOW;
  279. }
  280. if (FAILED(StringCchCat(wcNewPath,
  281. ARRAYSIZE(wcNewPath),
  282. newdir)))
  283. {
  284. return ERROR_BUFFER_OVERFLOW;
  285. }
  286. } else {
  287. LPWSTR lpszEnvName;
  288. if (NULL != (lpszEnvName = SheGetEnvVarW(wcEnvName))) {
  289. if (FAILED(StringCchCopy(wcNewPath,
  290. ARRAYSIZE(wcNewPath),
  291. lpszEnvName)))
  292. {
  293. return ERROR_BUFFER_OVERFLOW;
  294. }
  295. bUsedEnv = TRUE;
  296. } else {
  297. if (FAILED(StringCchCopy(wcNewPath,
  298. ARRAYSIZE(wcNewPath),
  299. &wcEnvName[1])))
  300. {
  301. return ERROR_BUFFER_OVERFLOW;
  302. }
  303. }
  304. if (newdir && *newdir)
  305. {
  306. if (!PathAppend(wcNewPath, newdir))
  307. {
  308. return ERROR_BUFFER_OVERFLOW;
  309. }
  310. }
  311. }
  312. if (!GetFullPathNameW(wcNewPath, MAX_PATH, wcEnvValue, &s)) {
  313. return( ERROR_ACCESS_DENIED );
  314. }
  315. attr = GetFileAttributesW(wcEnvValue);
  316. if ((attr == 0xFFFFFFFF ||
  317. ((attr & FILE_ATTRIBUTE_DIRECTORY) &&
  318. !SetCurrentDirectoryW(wcEnvValue)))
  319. && bUsedEnv )
  320. {
  321. if (FAILED(StringCchCopy(wcEnvValue, ARRAYSIZE(wcEnvValue), &wcEnvName[1])) ||
  322. FAILED(StringCchCat(wcEnvValue, ARRAYSIZE(wcEnvValue), TEXT("\\"))))
  323. {
  324. return ERROR_BUFFER_OVERFLOW;
  325. }
  326. attr = GetFileAttributesW(wcEnvValue);
  327. }
  328. if (attr == 0xFFFFFFFF || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  329. return(ERROR_ACCESS_DENIED);
  330. }
  331. if (!SetCurrentDirectoryW(wcEnvValue)) {
  332. return( ERROR_ACCESS_DENIED );
  333. }
  334. // It's ok if this fails
  335. SheSetEnvVarW(wcEnvName, wcEnvValue);
  336. // this seems right to me.
  337. if (FAILED(StringCchCopy(CurDrvDirW, ARRAYSIZE(CurDrvDirW), wcEnvValue)))
  338. {
  339. return ERROR_BUFFER_OVERFLOW;
  340. }
  341. return(SUCCESS) ;
  342. }
  343. INT
  344. SheChangeDirExA(
  345. CHAR *szNewDirA
  346. )
  347. {
  348. INT iRet;
  349. WCHAR szNewDirW[MAX_PATH];
  350. if (szNewDirA &&
  351. MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH))
  352. {
  353. iRet = SheChangeDirExW(szNewDirW);
  354. }
  355. else
  356. {
  357. iRet = FAILURE;
  358. }
  359. return iRet;
  360. }
  361. INT
  362. SheGetCurDrive()
  363. {
  364. if (!CurDrvDirW[0]) {
  365. SheGetDirW(GD_DEFAULT, CurDrvDirW) ;
  366. }
  367. return(CurDrvDirW[0] - WCHAR_CAP_A);
  368. }
  369. INT
  370. SheSetCurDrive(
  371. INT iDrive
  372. )
  373. {
  374. WCHAR chT[MAX_PATH];
  375. if (CurDrvDirW[0] != (WCHAR)(WCHAR_CAP_A + iDrive)) {
  376. SheGetDirW(iDrive + 1, chT);
  377. return(SheChangeDirW(chT));
  378. }
  379. return(SUCCESS);
  380. }
  381. INT
  382. SheFullPathA(
  383. CHAR *fname,
  384. DWORD sizpath,
  385. CHAR *buf)
  386. {
  387. DWORD rc = SUCCESS; /* prime with good rc */
  388. DWORD buflen; /* buffer length */
  389. CHAR *filepart;
  390. if (*fname == CHAR_NULL) {
  391. SheGetDirA(GD_DEFAULT, buf);
  392. buf += 2; /* Inc past drivespec */
  393. buflen = strlen(buf); /* Is curdir root only? */
  394. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  395. rc = FAILURE;
  396. } else if (buflen != 1) { /* if not root then append */
  397. *(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
  398. *(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
  399. } /* */
  400. } else {
  401. if ((strlen(fname) == 2) &&
  402. (*(fname + 1) == CHAR_COLON)
  403. // && (!is_dbcsleadchar(*fname))
  404. ) {
  405. SheGetDirA((CHAR)(DWORD_PTR)CharUpperA((LPSTR)(DWORD_PTR)*fname) - CHAR_CAP_A, buf); /* Get curdrvdir */
  406. if ((buflen = strlen(buf)) > 3) {
  407. *(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
  408. *(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
  409. }
  410. } else {
  411. if (!GetFullPathNameA( fname, sizpath, buf, &filepart )) {
  412. rc = FAILURE;
  413. }
  414. }
  415. }
  416. return(rc);
  417. }
  418. INT
  419. SheFullPathW(
  420. WCHAR *fname,
  421. DWORD sizpath,
  422. WCHAR *buf)
  423. {
  424. DWORD rc = SUCCESS; /* prime with good rc */
  425. DWORD buflen; /* buffer length */
  426. WCHAR *filepart;
  427. if (*fname == WCHAR_NULL) {
  428. SheGetDirW(GD_DEFAULT, buf);
  429. buf += 2; /* Inc past drivespec */
  430. buflen = wcslen(buf); /* Is curdir root only? */
  431. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  432. rc = FAILURE;
  433. } else if (buflen != 1) { /* if not root then append */
  434. *(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
  435. *(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
  436. } /* */
  437. } else {
  438. if ((wcslen(fname) == 2) &&
  439. (*(fname + 1) == WCHAR_COLON)
  440. // && (!is_dbcsleadchar(*fname))
  441. ) {
  442. SheGetDirW((WCHAR)(DWORD_PTR)CharUpperW((LPWSTR)(DWORD_PTR)*fname) - WCHAR_CAP_A, buf); /* Get curdrvdir */
  443. if ((buflen = wcslen(buf)) > 3) {
  444. *(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
  445. *(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
  446. }
  447. } else {
  448. if (!GetFullPathNameW( fname, sizpath, buf, &filepart )) {
  449. rc = FAILURE;
  450. }
  451. }
  452. }
  453. return(rc);
  454. }
  455. BOOL
  456. SheGetDirExW(
  457. LPWSTR lpszCurDisk,
  458. LPDWORD lpcchCurDir,
  459. LPWSTR lpszCurDir)
  460. {
  461. WCHAR wcEnvName[MAX_PATH];
  462. LPWSTR lpszEnvValue;
  463. INT cchPathOffset;
  464. // if lpszCurDisk NULL, do default
  465. if (!lpszCurDisk) {
  466. DWORD dwRet = GetCurrentDirectoryW(*lpcchCurDir, lpszCurDir);
  467. if (dwRet) {
  468. *lpcchCurDir = dwRet;
  469. return(TRUE);
  470. } else {
  471. return(FALSE);
  472. }
  473. }
  474. cchPathOffset = SheGetPathOffsetW(lpszCurDisk);
  475. if (cchPathOffset != 0xFFFFFFFF) {
  476. WCHAR wc = *(lpszCurDisk + cchPathOffset);
  477. *(lpszCurDisk + cchPathOffset) = WCHAR_NULL;
  478. if (FAILED(StringCchCopy(&wcEnvName[1], ARRAYSIZE(wcEnvName) - 1, lpszCurDisk)))
  479. {
  480. return FALSE;
  481. }
  482. wcEnvName[0] = WCHAR_EQUAL;
  483. *(lpszCurDisk + cchPathOffset) = wc;
  484. if (NULL != (lpszEnvValue = SheGetEnvVarW(wcEnvName)))
  485. {
  486. if (FAILED(StringCchCopy(lpszCurDir, *lpcchCurDir, lpszEnvValue)))
  487. {
  488. *lpcchCurDir = lstrlen(lpszEnvValue) + 1;
  489. return FALSE;
  490. }
  491. else
  492. {
  493. return TRUE;
  494. }
  495. }
  496. if (FAILED(StringCchCopy(lpszCurDir, *lpcchCurDir, lpszCurDisk)))
  497. {
  498. return FALSE;
  499. }
  500. *(lpszCurDir + cchPathOffset) = WCHAR_BSLASH;
  501. *(lpszCurDir + cchPathOffset + 1) = WCHAR_NULL;
  502. return(TRUE);
  503. } else {
  504. // parsing error
  505. return(FALSE);
  506. }
  507. }