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.

534 lines
13 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);
  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. wcscpy( str, denvvalue );
  107. }
  108. // there is a subtle difference between getcurrentdirectory() of DOS and the
  109. // equivalent SheGetDir() of NT. On dos, getcurrentdirectory() accesses the
  110. // floppy drives while in NT SheGetDir() returns the values that are set in
  111. // the environment variables. So we hit the disk on NT too, by calling
  112. // GetFileAttributes. We return SUCCESS or FAILURE based on the return value
  113. // of GetFileAttributes.
  114. if (GetFileAttributesW(strT) == (DWORD)0xffffffff)
  115. return(FAILURE);
  116. else
  117. return(SUCCESS);
  118. }
  119. // Should be BOOL, but possible mips breakage
  120. INT
  121. SheGetDirA(
  122. INT iDrive, // 0 = default, 1=A....
  123. CHAR *szDirA)
  124. {
  125. WCHAR szDirW[MAX_PATH];
  126. BOOL fDefCharUsed;
  127. INT nRet;
  128. if (!szDirA) {
  129. return(FAILURE);
  130. }
  131. nRet = SheGetDirW(iDrive, szDirW);
  132. WideCharToMultiByte(CP_ACP, 0, (LPWSTR)szDirW, -1, (LPSTR)szDirA,
  133. MAX_PATH, NULL, &fDefCharUsed);
  134. return(nRet);
  135. }
  136. INT
  137. SheChangeDirW(
  138. WCHAR *newdir
  139. )
  140. {
  141. WCHAR denvname[ 4 ];
  142. WCHAR newpath[ MAX_PATH ];
  143. WCHAR denvvalue[ MAX_PATH ];
  144. WCHAR c, *s;
  145. DWORD attr;
  146. GetCurrentDirectoryW( MAX_PATH, denvvalue );
  147. c = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)denvvalue[0]);
  148. denvname[0] = WCHAR_EQUAL;
  149. if (IsCharAlphaW(*newdir) && newdir[1] == WCHAR_COLON) {
  150. denvname[1] = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)*newdir);
  151. newdir += 2;
  152. } else {
  153. denvname[ 1 ] = c;
  154. }
  155. denvname[ 2 ] = WCHAR_COLON;
  156. denvname[ 3 ] = WCHAR_NULL;
  157. if ((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH)) {
  158. newpath[ 0 ] = denvname[ 1 ];
  159. newpath[ 1 ] = denvname[ 2 ];
  160. wcscpy( &newpath[ 2 ], newdir );
  161. } else {
  162. if (NULL != (s = SheGetEnvVarW( denvname ))) {
  163. wcscpy( newpath, s );
  164. } else {
  165. newpath[ 0 ] = denvname[ 1 ];
  166. newpath[ 1 ] = denvname[ 2 ];
  167. newpath[ 2 ] = WCHAR_NULL;
  168. }
  169. s = newpath + wcslen( newpath );
  170. *s++ = WCHAR_BSLASH;
  171. wcscpy( s, newdir );
  172. }
  173. if (!GetFullPathNameW(newpath, MAX_PATH, denvvalue, &s )) {
  174. return( ERROR_ACCESS_DENIED );
  175. }
  176. attr = GetFileAttributesW( denvvalue );
  177. if (attr == -1 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  178. return( ERROR_ACCESS_DENIED );
  179. }
  180. if (SheSetEnvVarW(denvname,denvvalue)) {
  181. return( ERROR_NOT_ENOUGH_MEMORY );
  182. }
  183. SetCurrentDirectoryW( denvvalue );
  184. // this seems wrong... SheGetDir(GD_DEFAULT, CurDrvDirW) ;
  185. wcscpy(CurDrvDirW, denvvalue); // this seems right to me.
  186. return(SUCCESS) ;
  187. }
  188. INT
  189. SheChangeDirA(
  190. CHAR *szNewDirA
  191. )
  192. {
  193. WCHAR szNewDirW[MAX_PATH];
  194. if (szNewDirA) {
  195. MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH);
  196. return(SheChangeDirW(szNewDirW));
  197. } else {
  198. return(FAILURE);
  199. }
  200. }
  201. INT
  202. SheChangeDirExW(
  203. WCHAR *newdir)
  204. {
  205. WCHAR wcEnvName[MAX_PATH];
  206. WCHAR wcNewPath[MAX_PATH];
  207. WCHAR wcEnvValue[MAX_PATH];
  208. DWORD cchPathOffset;
  209. WCHAR *s;
  210. DWORD attr;
  211. BOOL bUsedEnv = FALSE;
  212. if (newdir && *newdir &&
  213. ((cchPathOffset = SheGetPathOffsetW((LPWSTR)newdir)) != 0xFFFFFFFF)) {
  214. WCHAR wc = newdir[cchPathOffset];
  215. newdir[cchPathOffset] = WCHAR_NULL;
  216. wcscpy((LPWSTR)&wcEnvName[1], (LPWSTR)newdir);
  217. newdir[cchPathOffset] = wc;
  218. newdir += cchPathOffset;
  219. } else {
  220. GetCurrentDirectoryW(MAX_PATH, wcEnvValue);
  221. wcscpy((LPWSTR)&wcEnvName[1], (LPWSTR)wcEnvValue);
  222. }
  223. wcEnvName[0] = WCHAR_EQUAL;
  224. if ((cchPathOffset = SheGetPathOffsetW((LPWSTR)&wcEnvName[1])) != 0xFFFFFFFF) {
  225. // add one since the first character is "="
  226. wcEnvName[cchPathOffset + 1] = WCHAR_NULL;
  227. }
  228. //
  229. // If return value is 2, then we are a drive letter like A:
  230. // We need to uppercase the drive letter here, since the environ
  231. // vars are usually set as uppercase.
  232. //
  233. if (cchPathOffset == 2) {
  234. wcEnvName[1] = (WCHAR)(DWORD_PTR)CharUpper((LPWSTR)(DWORD_PTR) wcEnvName[1]);
  235. }
  236. if (newdir && *newdir &&
  237. ((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH))) {
  238. wcscpy((LPWSTR)wcNewPath, (LPWSTR)&wcEnvName[1]);
  239. if (lstrlen(wcNewPath) + lstrlen(newdir) < MAX_PATH ) {
  240. lstrcat((LPWSTR)wcNewPath, (LPWSTR)newdir);
  241. }
  242. } else {
  243. LPWSTR lpszEnvName;
  244. if (NULL != (lpszEnvName = (LPWSTR)SheGetEnvVarW(wcEnvName))) {
  245. wcscpy((LPWSTR)wcNewPath, lpszEnvName);
  246. bUsedEnv = TRUE;
  247. } else {
  248. wcscpy((LPWSTR)wcNewPath, (LPWSTR)&wcEnvName[1]);
  249. }
  250. if (newdir && *newdir) {
  251. if (wcNewPath[lstrlen(wcNewPath)-1] != WCHAR_BSLASH) {
  252. lstrcat((LPWSTR)wcNewPath, TEXT("\\"));
  253. }
  254. if (lstrlen(wcNewPath) + lstrlen(newdir) < MAX_PATH ) {
  255. lstrcat((LPWSTR)wcNewPath, (LPWSTR)newdir);
  256. }
  257. }
  258. }
  259. if (!GetFullPathNameW((LPWSTR)wcNewPath, MAX_PATH, wcEnvValue, &s)) {
  260. return( ERROR_ACCESS_DENIED );
  261. }
  262. attr = GetFileAttributesW((LPWSTR)wcEnvValue);
  263. if ((attr == 0xFFFFFFFF ||
  264. ((attr & FILE_ATTRIBUTE_DIRECTORY) &&
  265. !SetCurrentDirectoryW((LPWSTR)wcEnvValue)))
  266. && bUsedEnv ) {
  267. wcscpy((LPWSTR)wcEnvValue, (LPWSTR)&wcEnvName[1]);
  268. lstrcat((LPWSTR)wcEnvValue, TEXT("\\"));
  269. attr = GetFileAttributesW((LPWSTR)wcEnvValue);
  270. }
  271. if (attr == 0xFFFFFFFF || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  272. return(ERROR_ACCESS_DENIED);
  273. }
  274. if (!SetCurrentDirectoryW((LPWSTR)wcEnvValue)) {
  275. return( ERROR_ACCESS_DENIED );
  276. }
  277. // It's ok if this fails
  278. SheSetEnvVarW(wcEnvName, wcEnvValue);
  279. wcscpy(CurDrvDirW, (LPWSTR)wcEnvValue); // this seems right to me.
  280. return(SUCCESS) ;
  281. }
  282. INT
  283. SheChangeDirExA(
  284. CHAR *szNewDirA
  285. )
  286. {
  287. WCHAR szNewDirW[MAX_PATH];
  288. if (szNewDirA) {
  289. MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH);
  290. return(SheChangeDirExW(szNewDirW));
  291. } else {
  292. return(FAILURE);
  293. }
  294. }
  295. INT
  296. SheGetCurDrive()
  297. {
  298. if (!CurDrvDirW[0]) {
  299. SheGetDirW(GD_DEFAULT, CurDrvDirW) ;
  300. }
  301. return(CurDrvDirW[0] - WCHAR_CAP_A);
  302. }
  303. INT
  304. SheSetCurDrive(
  305. INT iDrive
  306. )
  307. {
  308. WCHAR chT[MAX_PATH];
  309. if (CurDrvDirW[0] != (WCHAR)(WCHAR_CAP_A + iDrive)) {
  310. SheGetDirW(iDrive + 1, chT);
  311. return(SheChangeDirW(chT));
  312. }
  313. return(SUCCESS);
  314. }
  315. INT
  316. SheFullPathA(
  317. CHAR *fname,
  318. DWORD sizpath,
  319. CHAR *buf)
  320. {
  321. DWORD rc = SUCCESS; /* prime with good rc */
  322. DWORD buflen; /* buffer length */
  323. CHAR *filepart;
  324. if (*fname == CHAR_NULL) {
  325. SheGetDirA(GD_DEFAULT, buf);
  326. buf += 2; /* Inc past drivespec */
  327. buflen = strlen(buf); /* Is curdir root only? */
  328. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  329. rc = FAILURE;
  330. } else if (buflen != 1) { /* if not root then append */
  331. *(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
  332. *(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
  333. } /* */
  334. } else {
  335. if ((strlen(fname) == 2) &&
  336. (*(fname + 1) == CHAR_COLON)
  337. // && (!is_dbcsleadchar(*fname))
  338. ) {
  339. SheGetDirA((CHAR)(DWORD_PTR)CharUpperA((LPSTR)(DWORD_PTR)*fname) - CHAR_CAP_A, buf); /* Get curdrvdir */
  340. if ((buflen = strlen(buf)) > 3) {
  341. *(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
  342. *(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
  343. }
  344. } else {
  345. if (!GetFullPathNameA( fname, sizpath, buf, &filepart )) {
  346. rc = FAILURE;
  347. }
  348. }
  349. }
  350. return(rc);
  351. }
  352. INT
  353. SheFullPathW(
  354. WCHAR *fname,
  355. DWORD sizpath,
  356. WCHAR *buf)
  357. {
  358. DWORD rc = SUCCESS; /* prime with good rc */
  359. DWORD buflen; /* buffer length */
  360. WCHAR *filepart;
  361. if (*fname == WCHAR_NULL) {
  362. SheGetDirW(GD_DEFAULT, buf);
  363. buf += 2; /* Inc past drivespec */
  364. buflen = wcslen(buf); /* Is curdir root only? */
  365. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  366. rc = FAILURE;
  367. } else if (buflen != 1) { /* if not root then append */
  368. *(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
  369. *(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
  370. } /* */
  371. } else {
  372. if ((wcslen(fname) == 2) &&
  373. (*(fname + 1) == WCHAR_COLON)
  374. // && (!is_dbcsleadchar(*fname))
  375. ) {
  376. SheGetDirW((WCHAR)(DWORD_PTR)CharUpperW((LPWSTR)(DWORD_PTR)*fname) - WCHAR_CAP_A, buf); /* Get curdrvdir */
  377. if ((buflen = wcslen(buf)) > 3) {
  378. *(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
  379. *(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
  380. }
  381. } else {
  382. if (!GetFullPathNameW( fname, sizpath, buf, &filepart )) {
  383. rc = FAILURE;
  384. }
  385. }
  386. }
  387. return(rc);
  388. }
  389. BOOL
  390. SheGetDirExW(
  391. LPWSTR lpszCurDisk,
  392. LPDWORD lpcchCurDir,
  393. LPWSTR lpszCurDir)
  394. {
  395. WCHAR wcEnvName[MAX_PATH];
  396. LPWSTR lpszEnvValue;
  397. INT cchPathOffset;
  398. // if lpszCurDisk NULL, do default
  399. if (!lpszCurDisk) {
  400. DWORD dwRet = GetCurrentDirectoryW(*lpcchCurDir, lpszCurDir);
  401. if (dwRet) {
  402. *lpcchCurDir = dwRet;
  403. return(TRUE);
  404. } else {
  405. return(FALSE);
  406. }
  407. }
  408. cchPathOffset = SheGetPathOffsetW(lpszCurDisk);
  409. if (cchPathOffset != 0xFFFFFFFF) {
  410. WCHAR wc = *(lpszCurDisk + cchPathOffset);
  411. *(lpszCurDisk + cchPathOffset) = WCHAR_NULL;
  412. lstrcpy(&wcEnvName[1], lpszCurDisk);
  413. wcEnvName[0] = WCHAR_EQUAL;
  414. *(lpszCurDisk + cchPathOffset) = wc;
  415. if (NULL != (lpszEnvValue = SheGetEnvVarW(wcEnvName))) {
  416. DWORD cchEnvValue = lstrlen(lpszEnvValue) + 1;
  417. if (cchEnvValue <= *lpcchCurDir) {
  418. wcscpy(lpszCurDir, lpszEnvValue);
  419. return(TRUE);
  420. } else {
  421. *lpcchCurDir = cchEnvValue;
  422. return(FALSE);
  423. }
  424. }
  425. wcscpy(lpszCurDir, lpszCurDisk);
  426. *(lpszCurDir + cchPathOffset) = WCHAR_BSLASH;
  427. *(lpszCurDir + cchPathOffset + 1) = WCHAR_NULL;
  428. return(TRUE);
  429. } else {
  430. // parsing error
  431. return(FALSE);
  432. }
  433. }