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.

2560 lines
71 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1993 Microsoft Corporation
  6. *
  7. * WKFILEIO.C
  8. * WOW32 KRNL FAST FILEIO ROUTINES
  9. *
  10. * History:
  11. * Routines removed from wkman.c
  12. * Created 1-Jan-1993 by Matt Felton (mattfe)
  13. *
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "dossvc.h"
  18. #include "demexp.h"
  19. #include "nt_vdd.h"
  20. #define DOS_FLAG_EXEC_OPEN 1 // see dos\v86\inc\dossym.inc
  21. MODNAME(wkfileio.c);
  22. extern DOSWOWDATA DosWowData;
  23. // Files which are mapped are kept in a single linked list
  24. // gpCacheHead -> the most recently accessed entry
  25. //
  26. BOOL fCacheInit = TRUE; // Set False When initialized
  27. PHMAPPEDFILEALIAS gpCacheHead = NULL;
  28. HMAPPEDFILEALIAS aMappedFileCache[MAX_MAPPED_FILES] = {0}; // File Handle To MappedFile Array
  29. DWORD dwTotalCacheBytes = 0;
  30. DWORD dwTotalCacheAccess = 0;
  31. #ifdef DEBUG
  32. INT fileiolevel = 12;
  33. INT fileoclevel = 8;
  34. #endif
  35. BOOL FASTCALL IsModuleSymantecInstall(HAND16 hMod16);
  36. //
  37. // named pipe stuff
  38. //
  39. BOOL
  40. LoadVdmRedir(
  41. VOID
  42. );
  43. BOOL
  44. IsVdmRedirLoaded(
  45. VOID
  46. );
  47. BOOL
  48. IsNamedPipeName(
  49. IN LPSTR Name
  50. );
  51. PSTR
  52. TruncatePath83(
  53. IN OUT PSTR,
  54. IN PSTR,
  55. IN int
  56. );
  57. CRITICAL_SECTION VdmLoadCritSec;
  58. //
  59. // invent some typedefs to avoid compiler warnings from GetProcAddress
  60. //
  61. typedef
  62. BOOL
  63. (*VR_READ_NAMED_PIPE_FUNC)(
  64. IN HANDLE Handle,
  65. IN LPBYTE Buffer,
  66. IN DWORD Buflen,
  67. OUT LPDWORD BytesRead,
  68. OUT LPDWORD Error
  69. );
  70. typedef
  71. BOOL
  72. (*VR_WRITE_NAMED_PIPE_FUNC)(
  73. IN HANDLE Handle,
  74. IN LPBYTE Buffer,
  75. IN DWORD Buflen,
  76. OUT LPDWORD BytesRead
  77. );
  78. typedef
  79. BOOL
  80. (*VR_IS_NAMED_PIPE_HANDLE_FUNC)(
  81. IN HANDLE Handle
  82. );
  83. typedef
  84. BOOL
  85. (*VR_ADD_OPEN_NAMED_PIPE_INFO_FUNC)(
  86. IN HANDLE Handle,
  87. IN LPSTR lpFileName
  88. );
  89. typedef
  90. LPSTR
  91. (*VR_CONVERT_LOCAL_NT_PIPE_NAME_FUNC)(
  92. OUT LPSTR Buffer OPTIONAL,
  93. IN LPSTR Name
  94. );
  95. typedef
  96. BOOL
  97. (*VR_REMOVE_OPEN_NAMED_PIPE_INFO_FUNC)(
  98. IN HANDLE Handle
  99. );
  100. typedef
  101. VOID
  102. (*VR_CANCEL_PIPE_IO_FUNC)(
  103. IN DWORD Thread
  104. );
  105. //
  106. // prototypes for functions dynamically loaded from VDMREDIR.DLL
  107. //
  108. BOOL
  109. (*VrReadNamedPipe)(
  110. IN HANDLE Handle,
  111. IN LPBYTE Buffer,
  112. IN DWORD Buflen,
  113. OUT LPDWORD BytesRead,
  114. OUT LPDWORD Error
  115. ) = NULL;
  116. BOOL
  117. (*VrWriteNamedPipe)(
  118. IN HANDLE Handle,
  119. IN LPBYTE Buffer,
  120. IN DWORD Buflen,
  121. OUT LPDWORD BytesWritten
  122. ) = NULL;
  123. BOOL
  124. DefaultIsNamedPipeHandle(
  125. IN HANDLE Handle
  126. );
  127. BOOL
  128. DefaultIsNamedPipeHandle(
  129. IN HANDLE Handle
  130. )
  131. {
  132. return FALSE;
  133. }
  134. BOOL
  135. (*VrIsNamedPipeHandle)(
  136. IN HANDLE Handle
  137. ) = DefaultIsNamedPipeHandle;
  138. BOOL
  139. (*VrAddOpenNamedPipeInfo)(
  140. IN HANDLE Handle,
  141. IN LPSTR lpFileName
  142. ) = NULL;
  143. LPSTR
  144. (*VrConvertLocalNtPipeName)(
  145. OUT LPSTR Buffer OPTIONAL,
  146. IN LPSTR Name
  147. ) = NULL;
  148. BOOL
  149. (*VrRemoveOpenNamedPipeInfo)(
  150. IN HANDLE Handle
  151. ) = NULL;
  152. VOID
  153. DefaultVrCancelPipeIo(
  154. IN DWORD Thread
  155. );
  156. VOID
  157. DefaultVrCancelPipeIo(
  158. IN DWORD Thread
  159. )
  160. {
  161. (void)(Thread);
  162. }
  163. VOID
  164. (*VrCancelPipeIo)(
  165. IN DWORD Thread
  166. ) = DefaultVrCancelPipeIo;
  167. HANDLE hVdmRedir;
  168. BOOL VdmRedirLoaded = FALSE;
  169. BOOL
  170. LoadVdmRedir(
  171. VOID
  172. )
  173. /*++
  174. Routine Description:
  175. Load the VDMREDIR DLL if it is not already loaded. Called from OpenFile
  176. only. Since file operations cannot be performed on a file that has not
  177. been opened, it is safe to only call this function on open
  178. Arguments:
  179. None.
  180. Return Value:
  181. BOOL
  182. TRUE VdmRedir.DLL is loaded
  183. FALSE no it isn't
  184. --*/
  185. {
  186. BOOL currentLoadState;
  187. //
  188. // need critical section - Windows apps end up being multi-threaded in
  189. // 32-bit world - might have simultaneous opens
  190. //
  191. EnterCriticalSection(&VdmLoadCritSec);
  192. if (!VdmRedirLoaded) {
  193. if ((hVdmRedir = SafeLoadLibrary(L"VDMREDIR")) != NULL) {
  194. if ((VrReadNamedPipe = (VR_READ_NAMED_PIPE_FUNC)GetProcAddress(hVdmRedir, "VrReadNamedPipe")) == NULL) {
  195. goto closeAndReturn;
  196. }
  197. if ((VrWriteNamedPipe = (VR_WRITE_NAMED_PIPE_FUNC)GetProcAddress(hVdmRedir, "VrWriteNamedPipe")) == NULL) {
  198. goto closeAndReturn;
  199. }
  200. if ((VrIsNamedPipeHandle = (VR_IS_NAMED_PIPE_HANDLE_FUNC)GetProcAddress(hVdmRedir, "VrIsNamedPipeHandle")) == NULL) {
  201. goto closeAndReturn;
  202. }
  203. if ((VrAddOpenNamedPipeInfo = (VR_ADD_OPEN_NAMED_PIPE_INFO_FUNC)GetProcAddress(hVdmRedir, "VrAddOpenNamedPipeInfo")) == NULL) {
  204. goto closeAndReturn;
  205. }
  206. if ((VrConvertLocalNtPipeName = (VR_CONVERT_LOCAL_NT_PIPE_NAME_FUNC)GetProcAddress(hVdmRedir, "VrConvertLocalNtPipeName")) == NULL) {
  207. goto closeAndReturn;
  208. }
  209. if ((VrRemoveOpenNamedPipeInfo = (VR_REMOVE_OPEN_NAMED_PIPE_INFO_FUNC)GetProcAddress(hVdmRedir, "VrRemoveOpenNamedPipeInfo")) == NULL) {
  210. goto closeAndReturn;
  211. }
  212. if ((VrCancelPipeIo = (VR_CANCEL_PIPE_IO_FUNC)GetProcAddress(hVdmRedir, "VrCancelPipeIo")) == NULL) {
  213. VrCancelPipeIo = DefaultVrCancelPipeIo;
  214. closeAndReturn:
  215. CloseHandle(hVdmRedir);
  216. } else {
  217. VdmRedirLoaded = TRUE;
  218. }
  219. }
  220. }
  221. currentLoadState = VdmRedirLoaded;
  222. LeaveCriticalSection(&VdmLoadCritSec);
  223. return currentLoadState;
  224. }
  225. BOOL
  226. IsVdmRedirLoaded(
  227. VOID
  228. )
  229. /*++
  230. Routine Description:
  231. Checks current load state of VDMREDIR.DLL
  232. Arguments:
  233. None.
  234. Return Value:
  235. BOOL
  236. TRUE VdmRedir.DLL is loaded
  237. FALSE no it isn't
  238. --*/
  239. {
  240. BOOL currentLoadState;
  241. EnterCriticalSection(&VdmLoadCritSec);
  242. currentLoadState = VdmRedirLoaded;
  243. LeaveCriticalSection(&VdmLoadCritSec);
  244. return currentLoadState;
  245. }
  246. BOOL
  247. IsNamedPipeName(
  248. IN LPSTR Name
  249. )
  250. /*++
  251. Routine Description:
  252. Lifted from VDMREDIR.DLL - we don't want to load the entire DLL if we
  253. need to check for a named pipe
  254. Checks if a string designates a named pipe. As criteria for the decision
  255. we use:
  256. \\computername\PIPE\...
  257. DOS (client-side) can only open a named pipe which is created at a server
  258. and must therefore be prefixed by a computername
  259. Arguments:
  260. Name - to check for (Dos) named pipe syntax
  261. Return Value:
  262. BOOL
  263. TRUE - Name refers to (local or remote) named pipe
  264. FALSE - Name doesn't look like name of pipe
  265. --*/
  266. {
  267. int CharCount;
  268. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  269. ++Name;
  270. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  271. ++Name;
  272. CharCount = 0;
  273. while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) {
  274. ++Name;
  275. ++CharCount;
  276. }
  277. if (!CharCount || !*Name) {
  278. //
  279. // Name is \\ or \\\ or just \\name which I don't understand,
  280. // so its not a named pipe - fail it
  281. //
  282. return FALSE;
  283. }
  284. //
  285. // bump name past next path separator. Note that we don't have to
  286. // check CharCount for max. length of a computername, because this
  287. // function is called only after the (presumed) named pipe has been
  288. // successfully opened, therefore we know that the name has been
  289. // validated
  290. //
  291. ++Name;
  292. } else {
  293. return FALSE;
  294. }
  295. //
  296. // We are at <something> (after \ or \\<name>\). Check if <something>
  297. // is [Pp][Ii][Pp][Ee][\\/]
  298. //
  299. if (!WOW32_strnicmp(Name, "PIPE", 4)) {
  300. Name += 4;
  301. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  302. return TRUE;
  303. }
  304. }
  305. }
  306. return FALSE;
  307. }
  308. /* WK32WOWFileRead - Read a file
  309. *
  310. *
  311. * Entry - fh File Handle
  312. * bufsize Count to read
  313. * lpBuf Buffer Address
  314. *
  315. * Exit
  316. * SUCCESS
  317. * Count of bytes read
  318. *
  319. * FAILURE
  320. * system status code
  321. * Concept Borrowed from demFileRead
  322. *
  323. */
  324. ULONG FASTCALL WK32WOWFileRead (PVDMFRAME pFrame)
  325. {
  326. PWOWFILEREAD16 parg16;
  327. LPBYTE pSrc;
  328. LPBYTE pDst;
  329. INT dwBytesRead;
  330. DWORD bufsize, dwError;
  331. LARGE_INTEGER liBytesLeft, liFileSize, liFilePointer;
  332. HANDLE hFile;
  333. PHMAPPEDFILEALIAS pCache = 0;
  334. PDOSSFT pSFT;
  335. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  336. bufsize = FETCHDWORD(parg16->bufsize);
  337. dwBytesRead = bufsize;
  338. hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  339. if (!hFile) {
  340. dwBytesRead = 0xffff0006;
  341. goto Return_dwBytesRead;
  342. }
  343. if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
  344. dwBytesRead = 0xffffffff; // Let DOS handle device handles.
  345. goto Return_dwBytesRead; // kernel QuickRead passes to DOS
  346. } // after any error (dx=ffff)
  347. //
  348. // It is legitimate to ask to read more bytes than are left in the
  349. // selector passed in, if the file is short enough to not actually
  350. // overrun the selector. In this case we don't want limit checking,
  351. // so zero is passed as the required size to GETVDMPTR().
  352. //
  353. GETVDMPTR(parg16->lpBuf, 0, pDst);
  354. // If its the KRNL doing IO then find the File in the Cache
  355. if ( vptopPDB == parg16->lpPDB ) {
  356. if ( !(pCache = FINDMAPFILECACHE(hFile)) ){
  357. // Cache Entry Not Found so Add it
  358. pCache = ALLOCMAPFILECACHE();
  359. pCache->fAccess = W32MapViewOfFile( pCache, hFile);
  360. }
  361. if (pCache->fAccess) {
  362. // Calculate Starting Read Address in File
  363. pSrc = pCache->lpStartingAddressOfView + pCache->lFilePointer;
  364. dwBytesRead = bufsize;
  365. // Adjust Size so as to not read off the End of File
  366. if (pCache->lFilePointer > pCache->dwFileSize) {
  367. dwBytesRead = 0;
  368. } else {
  369. if (pCache->lFilePointer + dwBytesRead > pCache->dwFileSize) {
  370. dwBytesRead-=((pCache->lFilePointer+dwBytesRead)-pCache->dwFileSize);
  371. }
  372. }
  373. LOGDEBUG(fileiolevel, ("MapFileRead fh:%04X fh32:%08X pSrc:%08X Bytes:%08X pDsc %08X\n"
  374. ,FETCHWORD(parg16->fh),hFile, pSrc,dwBytesRead,FETCHDWORD(parg16->lpBuf)));
  375. // Could get PageIO Errors, especially reading over the network
  376. // So do try-except around the mapped read.
  377. try {
  378. RtlCopyMemory(pDst, pSrc, dwBytesRead);
  379. pCache->lFilePointer += dwBytesRead;
  380. dwTotalCacheBytes += dwBytesRead;
  381. dwTotalCacheAccess++;
  382. } except (TRUE) {
  383. DPM_SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
  384. FREEMAPFILECACHE(pCache->hfile32);
  385. pCache->hfile32 = hFile;
  386. pCache->fAccess = FALSE;
  387. pCache = 0;
  388. }
  389. }
  390. }
  391. if ((pCache == 0) || (pCache->fAccess == FALSE)) {
  392. // Do The File Read via the File System
  393. if (IsVdmRedirLoaded() && VrIsNamedPipeHandle(hFile)) {
  394. DWORD error;
  395. if (!VrReadNamedPipe(hFile, pDst, (DWORD)bufsize, &dwBytesRead, &error)) {
  396. dwBytesRead = error | 0xffff0000;
  397. }
  398. } else if (DPM_ReadFile (hFile, pDst, (DWORD)bufsize, &dwBytesRead,
  399. NULL) == FALSE){
  400. //
  401. // In Win3.1 it is not an error to hit EOF during a read with buffer
  402. // smaller than the requested read.
  403. // AmiPro asks for more bytes than they allocated for the buffer.
  404. //
  405. dwError = GetLastError();
  406. if(dwError == ERROR_NOACCESS) {
  407. liFileSize.LowPart = DPM_GetFileSize(hFile, &liFileSize.HighPart);
  408. liFilePointer.HighPart = 0;
  409. liFilePointer.LowPart = DPM_SetFilePointer(hFile,
  410. 0,
  411. &liFilePointer.HighPart,
  412. FILE_CURRENT
  413. );
  414. if (liFileSize.QuadPart <= liFilePointer.QuadPart) {
  415. dwBytesRead = 0;
  416. } else {
  417. // how far to end of file?
  418. liBytesLeft.QuadPart = liFileSize.QuadPart - liFilePointer.QuadPart;
  419. //
  420. // If it should have worked, give up and assert
  421. //
  422. if (liBytesLeft.HighPart || liBytesLeft.LowPart >= bufsize) {
  423. WOW32ASSERTMSGF(
  424. FALSE,
  425. ("WK32WOWFileRead: ReadFile returned ERROR_NOACCESS but there is data to read,\n"
  426. "maybe invalid buffer %x:%4x size 0x%x (would fault on 3.1). Hit 'g' to\n"
  427. "return ERROR_NOT_ENOUGH_MEMORY.\n",
  428. HIWORD(parg16->lpBuf), LOWORD(parg16->lpBuf), bufsize));
  429. dwBytesRead = ERROR_NOT_ENOUGH_MEMORY | 0xffff0000;
  430. }
  431. // else try again with the smaller request
  432. else if (DPM_ReadFile (hFile, pDst, liBytesLeft.LowPart, &dwBytesRead,
  433. NULL) == FALSE){
  434. dwBytesRead = GetLastError() | 0xffff0000;
  435. }
  436. }
  437. } else {
  438. dwBytesRead = dwError | 0xffff0000;
  439. }
  440. }
  441. LOGDEBUG(fileiolevel, ("IOFileRead fh:%X fh32:%X Bytes req:%X read:%X pDsc %08X\n"
  442. ,FETCHWORD(parg16->fh),hFile,bufsize,dwBytesRead, FETCHDWORD(parg16->lpBuf)));
  443. } else {
  444. if ((dwTotalCacheBytes > CACHE_BYTE_THRESHOLD) ||
  445. (dwTotalCacheAccess > CACHE_ACCESS_THRESHOLD) ||
  446. (dwBytesRead > CACHE_READ_THRESHOLD)) {
  447. FlushMapFileCaches();
  448. }
  449. }
  450. //
  451. // If the read was successful, let the emulator know that
  452. // these bytes have changed.
  453. //
  454. // On checked builds perform limit check now that we know the
  455. // actual number of bytes read. We wait until now to allow
  456. // for a requested read size which would overrun the selector,
  457. // but against a file which has few enough bytes remaining
  458. // that the selector isn't actually overrun.
  459. //
  460. if ((dwBytesRead & 0xffff0000) != 0xffff0000) {
  461. FLUSHVDMCODEPTR(parg16->lpBuf, (WORD)dwBytesRead, pDst);
  462. #ifdef DEBUG
  463. FREEVDMPTR(pDst);
  464. GETVDMPTR(parg16->lpBuf, dwBytesRead, pDst);
  465. #endif
  466. }
  467. FREEVDMPTR(pDst);
  468. Return_dwBytesRead:
  469. FREEARGPTR(parg16);
  470. return (dwBytesRead);
  471. }
  472. PHMAPPEDFILEALIAS FindMapFileCache(HANDLE hFile)
  473. {
  474. PHMAPPEDFILEALIAS pCache, prev;
  475. if (fCacheInit) {
  476. InitMapFileCache();
  477. }
  478. pCache = gpCacheHead;
  479. prev = 0;
  480. while ( (pCache->hfile32 != hFile) && (pCache->hpfNext !=0) ) {
  481. prev = pCache;
  482. pCache = pCache->hpfNext;
  483. }
  484. // If we found it, then make sure its at the front of the list
  485. if (pCache->hfile32 == hFile) {
  486. if (prev != 0) {
  487. prev->hpfNext = pCache->hpfNext;
  488. pCache->hpfNext = gpCacheHead;
  489. gpCacheHead = pCache;
  490. }
  491. }else{
  492. // If it was not found return error
  493. pCache = 0;
  494. }
  495. return(pCache);
  496. }
  497. PHMAPPEDFILEALIAS AllocMapFileCache()
  498. {
  499. PHMAPPEDFILEALIAS pCache, prev;
  500. if (fCacheInit) {
  501. InitMapFileCache();
  502. }
  503. pCache = gpCacheHead;
  504. prev = 0;
  505. while ( (pCache->hpfNext != 0) && (pCache->hfile32 != 0) ) {
  506. prev = pCache;
  507. pCache = pCache->hpfNext;
  508. }
  509. if (prev != 0) {
  510. prev->hpfNext = pCache->hpfNext;
  511. pCache->hpfNext = gpCacheHead;
  512. gpCacheHead = pCache;
  513. }
  514. // If The found entry was in use, then Free
  515. if (pCache->hfile32 != 0) {
  516. FREEMAPFILECACHE(pCache->hfile32);
  517. }
  518. return(pCache);
  519. }
  520. VOID FreeMapFileCache(HANDLE hFile)
  521. {
  522. PHMAPPEDFILEALIAS pCache;
  523. if ( pCache = FINDMAPFILECACHE(hFile) ) {
  524. LOGDEBUG(fileiolevel,("FreeMapFileCache: hFile:%08x hMappedFileObject:%08X\n",
  525. hFile,pCache->hMappedFileObject));
  526. if ( pCache->lpStartingAddressOfView != 0 ) {
  527. UnmapViewOfFile( pCache->lpStartingAddressOfView );
  528. }
  529. if ( pCache->hMappedFileObject != 0) {
  530. CloseHandle( pCache->hMappedFileObject );
  531. }
  532. if (pCache->fAccess) {
  533. DPM_SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
  534. }
  535. pCache->hfile32 = 0;
  536. pCache->hMappedFileObject = 0;
  537. pCache->lpStartingAddressOfView = 0;
  538. pCache->lFilePointer = 0;
  539. pCache->dwFileSize = 0;
  540. pCache->fAccess = FALSE;
  541. }
  542. }
  543. VOID InitMapFileCache()
  544. {
  545. PHMAPPEDFILEALIAS pCache;
  546. INT i;
  547. pCache = &aMappedFileCache[0];
  548. gpCacheHead = 0;
  549. for ( i = 1; i <= MAX_MAPPED_FILES-1; i++ ) {
  550. pCache->hfile32 = 0;
  551. pCache->hMappedFileObject = 0;
  552. pCache->lpStartingAddressOfView = 0;
  553. pCache->lFilePointer = 0;
  554. pCache->dwFileSize = 0;
  555. pCache->fAccess = FALSE;
  556. pCache->hpfNext = gpCacheHead;
  557. gpCacheHead = pCache;
  558. pCache = &aMappedFileCache[i];
  559. }
  560. fCacheInit = FALSE;
  561. }
  562. BOOL W32MapViewOfFile( PHMAPPEDFILEALIAS pCache, HANDLE hFile)
  563. {
  564. pCache->fAccess = FALSE;
  565. pCache->hfile32 = hFile;
  566. pCache->lpStartingAddressOfView = 0;
  567. pCache->hMappedFileObject = CreateFileMapping( hFile,
  568. 0,
  569. PAGE_READONLY, 0, 0, 0);
  570. if (pCache->hMappedFileObject != 0) {
  571. pCache->lpStartingAddressOfView = MapViewOfFile( pCache->hMappedFileObject,
  572. FILE_MAP_READ, 0, 0, 0);
  573. if (pCache->lpStartingAddressOfView != 0 ) {
  574. pCache->lFilePointer = DPM_SetFilePointer( hFile, 0, 0, FILE_CURRENT );
  575. pCache->dwFileSize = DPM_GetFileSize(hFile, 0);
  576. pCache->fAccess = TRUE; // Assume Read Access
  577. } else {
  578. CloseHandle(pCache->hMappedFileObject);
  579. pCache->hMappedFileObject = 0; // so FreeMapFileCache doesn't double-close the handle
  580. }
  581. }
  582. return(pCache->fAccess);
  583. }
  584. /* FlushMapFileCaches
  585. *
  586. * Entry - None
  587. *
  588. * Exit - None
  589. *
  590. */
  591. VOID FlushMapFileCaches()
  592. {
  593. PHMAPPEDFILEALIAS pCache;
  594. if (fCacheInit) {
  595. return;
  596. }
  597. WOW32ASSERT(gpCacheHead != NULL);
  598. pCache = gpCacheHead;
  599. dwTotalCacheBytes = dwTotalCacheAccess = 0;
  600. while ( (pCache->hpfNext !=0) ) {
  601. if (pCache->hfile32 != 0) {
  602. FREEMAPFILECACHE(pCache->hfile32);
  603. }
  604. pCache = pCache->hpfNext;
  605. }
  606. }
  607. /* WK32WOWFileWrite - Write to a file
  608. *
  609. *
  610. * Entry - fh File Handle
  611. * bufsize Count to read
  612. * lpBuf Buffer Address
  613. *
  614. * Exit
  615. * SUCCESS
  616. * Count of bytes read
  617. *
  618. * FAILURE
  619. * system status code
  620. * Concept Borrowed from demFileWrite
  621. *
  622. */
  623. ULONG FASTCALL WK32WOWFileWrite (PVDMFRAME pFrame)
  624. {
  625. HANDLE hFile;
  626. DWORD dwBytesWritten;
  627. DWORD bufsize;
  628. PBYTE pb1;
  629. register PWOWFILEWRITE16 parg16;
  630. PHMAPPEDFILEALIAS pCache;
  631. PDOSSFT pSFT;
  632. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  633. bufsize = FETCHDWORD(parg16->bufsize);
  634. if ( HIWORD(parg16->lpBuf) == 0 ) {
  635. pb1 = (PVOID)GetRModeVDMPointer(FETCHDWORD(parg16->lpBuf));
  636. } else {
  637. GETVDMPTR(parg16->lpBuf, bufsize, pb1);
  638. }
  639. hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  640. if (!hFile) {
  641. dwBytesWritten = 0xffff0006; // DOS Invalid Handle Error
  642. goto Cleanup;
  643. }
  644. if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
  645. dwBytesWritten = 0xffffffff; // Let DOS handle device handles.
  646. goto Cleanup; // kernel QuickWrite passes to DOS
  647. } // after any error (dx=ffff)
  648. // We don't Support Writing to Mapped Files
  649. if ( (pCache = FINDMAPFILECACHE(hFile)) && pCache->fAccess ) {
  650. if (pCache->lpStartingAddressOfView) {
  651. DPM_SetFilePointer( hFile, pCache->lFilePointer, NULL, FILE_BEGIN );
  652. FREEMAPFILECACHE(hFile);
  653. }
  654. pCache->fAccess = FALSE;
  655. pCache->hfile32 = hFile;
  656. }
  657. // In DOS CX=0 truncates or extends the file to current file pointer.
  658. if (bufsize == 0){
  659. if (DPM_SetEndOfFile(hFile) == FALSE) {
  660. dwBytesWritten = GetLastError() | 0xffff0000;
  661. LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X SetEndOfFile failed pDsc %08X\n",
  662. FETCHWORD(parg16->fh),hFile,FETCHDWORD(parg16->lpBuf)));
  663. } else {
  664. dwBytesWritten = 0;
  665. LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X truncated at current position pDsc %08X\n",
  666. FETCHWORD(parg16->fh),hFile,FETCHDWORD(parg16->lpBuf)));
  667. }
  668. }
  669. else {
  670. if (IsVdmRedirLoaded() && VrIsNamedPipeHandle(hFile)) {
  671. if (!VrWriteNamedPipe(hFile, pb1, (DWORD)bufsize, &dwBytesWritten)) {
  672. dwBytesWritten = GetLastError() | 0xffff0000;
  673. }
  674. } else {
  675. if (( DPM_WriteFile (hFile,
  676. pb1,
  677. (DWORD)bufsize,
  678. &dwBytesWritten,
  679. NULL)) == FALSE){
  680. dwBytesWritten = GetLastError() | 0xffff0000;
  681. }
  682. }
  683. LOGDEBUG(fileiolevel, ("IOFileWrite fh:%X fh32:%X Bytes req:%X written:%X pDsc %08X\n",
  684. FETCHWORD(parg16->fh),hFile,bufsize,dwBytesWritten,FETCHDWORD(parg16->lpBuf)));
  685. }
  686. Cleanup:
  687. FREEVDMPTR(pb1);
  688. FREEARGPTR(parg16);
  689. return (dwBytesWritten);
  690. }
  691. /* WK32WOWFileLSeek - Change File Pointer
  692. *
  693. *
  694. * Entry - fh File Handle
  695. * fileOffset New Location
  696. * mode Positioning Method
  697. * 0 - File Absolute
  698. * 1 - Relative to Current Position
  699. * 2 - Relative to end of file
  700. *
  701. * Exit
  702. * SUCCESS
  703. * New Location
  704. *
  705. * FAILURE
  706. * system status code
  707. *
  708. */
  709. ULONG FASTCALL WK32WOWFileLSeek (PVDMFRAME pFrame)
  710. {
  711. HANDLE hFile;
  712. ULONG dwLoc;
  713. PHMAPPEDFILEALIAS pCache;
  714. register PWOWFILELSEEK16 parg16;
  715. PDOSSFT pSFT;
  716. #if (FILE_BEGIN != 0 || FILE_CURRENT != 1 || FILE_END !=2)
  717. #error "Win32 values not DOS compatible"
  718. #
  719. #endif
  720. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  721. hFile = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  722. if (!hFile) {
  723. FREEARGPTR(parg16);
  724. return(0xffff0006);
  725. }
  726. if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
  727. FREEARGPTR(parg16); // Let DOS handle device handles.
  728. return(0xffffffff); // kernel QuickLSeek passes to DOS
  729. } // after any error (dx=ffff)
  730. if ( (vptopPDB == parg16->lpPDB) && (pCache = FINDMAPFILECACHE(hFile)) && pCache->fAccess ) {
  731. // File Is in the Cache
  732. // Update our Seek Pointer
  733. LOGDEBUG(fileiolevel, ("CachedSeek fh:%04X Mode %04X pointer %08X\n",FETCHWORD(parg16->fh),FETCHWORD(parg16->mode),FETCHDWORD(parg16->fileOffset)));
  734. switch(FETCHWORD(parg16->mode)) {
  735. case FILE_BEGIN:
  736. pCache->lFilePointer = FETCHDWORD(parg16->fileOffset);
  737. break;
  738. case FILE_CURRENT:
  739. pCache->lFilePointer += (LONG)FETCHDWORD(parg16->fileOffset);
  740. break;
  741. case FILE_END:
  742. pCache->lFilePointer = pCache->dwFileSize +
  743. (LONG)FETCHDWORD(parg16->fileOffset);
  744. break;
  745. }
  746. dwLoc = pCache->lFilePointer;
  747. } else {
  748. DWORD dwLocHi = 0;
  749. // File is NOT in Cache so Just do normal Seek.
  750. if (((dwLoc = DPM_SetFilePointer (hFile,
  751. FETCHDWORD(parg16->fileOffset),
  752. &dwLocHi,
  753. (DWORD)FETCHWORD(parg16->mode))) == -1L) &&
  754. (GetLastError() != NO_ERROR)) {
  755. dwLoc = GetLastError() | 0xffff0000;
  756. return(dwLoc);
  757. }
  758. if (dwLocHi) {
  759. // file pointer has been moved > FFFFFFFF. Truncate it
  760. dwLocHi = 0;
  761. if (((dwLoc = DPM_SetFilePointer (hFile,
  762. dwLoc,
  763. &dwLocHi,
  764. FILE_BEGIN)) == -1L) &&
  765. (GetLastError() != NO_ERROR)) {
  766. dwLoc = GetLastError() | 0xffff0000;
  767. return(dwLoc);
  768. }
  769. }
  770. }
  771. FREEARGPTR(parg16);
  772. return (dwLoc);
  773. }
  774. BOOL IsDevice(PSTR pszFilePath)
  775. {
  776. PSTR pfile, pend;
  777. int length;
  778. UCHAR device_part[9];
  779. PSYSDEV pSys;
  780. PUCHAR p;
  781. // Determine the start of the file part of the path.
  782. if (pfile = WOW32_strrchr(pszFilePath, '\\')) {
  783. pfile++;
  784. } else if (pszFilePath[0] && pszFilePath[1] == ':') {
  785. pfile = pszFilePath + 2;
  786. } else {
  787. pfile = pszFilePath;
  788. }
  789. // Compute length of pre-dot file name part.
  790. for (pend = pfile; *pend; pend++) {
  791. if (*pend == '.') {
  792. break;
  793. }
  794. }
  795. if (pend > pfile && *(pend - 1) == ':') {
  796. pend--;
  797. }
  798. length = (pend - pfile);
  799. if (length > 8) {
  800. return FALSE;
  801. }
  802. RtlFillMemory(device_part + length, 8 - length, ' ');
  803. RtlCopyMemory(device_part, pfile, length);
  804. device_part[8] = 0;
  805. WOW32_strupr(device_part);
  806. // Now go through the device chain comparing each entry with
  807. // the device part extracted from the file path.
  808. pSys = pDeviceChain;
  809. for (;;) {
  810. p = pSys->sdevDevName;
  811. if (RtlEqualMemory(device_part, p, 8)) {
  812. return TRUE;
  813. }
  814. if (LOWORD(pSys->sdevNext) == 0xFFFF) {
  815. break;
  816. }
  817. pSys = (PSYSDEV) GetRModeVDMPointer(pSys->sdevNext);
  818. }
  819. // If it wasn't in the chain then it's not a device.
  820. return FALSE;
  821. }
  822. PSTR NormalizeDosPath(PSTR pszPath, WORD wCurrentDriveNumber, PBOOL ItsANamedPipe)
  823. {
  824. static CHAR NewPath[MAX_PATH];
  825. PSTR p;
  826. DWORD cbFilename;
  827. *ItsANamedPipe = FALSE;
  828. // Special case the NULL path.
  829. if (pszPath[0] == 0) {
  830. return pszPath;
  831. }
  832. // Apps can pass D:\\computer\share to int 21 open
  833. // Win 32 createfile can't cope with the leading drive letter
  834. // so remove it as necessary.
  835. if (WOW32_strncmp(pszPath+1,":\\\\",3) == 0) {
  836. pszPath++;
  837. pszPath++;
  838. }
  839. //
  840. // if the name specifies a named pipe, load VDMREDIR. If this fails return
  841. // an error
  842. //
  843. if (IsNamedPipeName(pszPath)) {
  844. if (!LoadVdmRedir()) {
  845. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  846. return NULL;
  847. }
  848. *ItsANamedPipe = TRUE;
  849. //
  850. // convert \\<this_computer>\PIPE\foo\bar\etc to \\.\PIPE\...
  851. // if we already allocated a buffer for the slash conversion use
  852. // that else this call will allocate another buffer (we don't
  853. // want to write over DOS memory)
  854. //
  855. p = VrConvertLocalNtPipeName(NULL, pszPath);
  856. if (!p) {
  857. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  858. }
  859. return p;
  860. }
  861. // if there is no drive letter at the beginning of the path
  862. // then prepend a drive letter and ':' to the beginning
  863. // of the path.
  864. if (pszPath[1] != ':' &&
  865. !(IS_ASCII_PATH_SEPARATOR(pszPath[0]) &&
  866. IS_ASCII_PATH_SEPARATOR(pszPath[1]))) {
  867. cbFilename = strlen( pszPath ) + 1;
  868. if( cbFilename > MAX_PATH - 2) {
  869. SetLastError(ERROR_PATH_NOT_FOUND);
  870. return NULL;
  871. }
  872. NewPath[0] = wCurrentDriveNumber + 'A';
  873. NewPath[1] = ':';
  874. RtlCopyMemory(NewPath + 2, pszPath, cbFilename);
  875. pszPath = NewPath; //return this value
  876. }
  877. return TruncatePath83(NewPath, pszPath, MAX_PATH);
  878. }
  879. /* TruncatePath83 - Takes as input a path and make sure it has an 8.3 file name
  880. *
  881. * Entry - pstr-> target buffer[MAX_PATH]
  882. * pstr-> string to convert
  883. * It is assumed that the string has at the very least a '?:' as
  884. * its first two characters, where ? is any drive letter.
  885. *
  886. * Exit
  887. * SUCCESS
  888. * return value-> converted string
  889. *
  890. * FAILURE
  891. * return value==NULL
  892. *
  893. */
  894. PSTR TruncatePath83(PSTR NewPath, PSTR pszPath, int cbNewPath)
  895. {
  896. PSTR pPathName, pPathNameSlash, pPathExt;
  897. //
  898. // If the string is not already in the buffer, copy it in
  899. //
  900. if (NewPath != pszPath) {
  901. strncpy (NewPath, pszPath, cbNewPath);
  902. NewPath[cbNewPath-1] = '\0';
  903. }
  904. //
  905. // make sure file name and extension are 8.3
  906. //
  907. pPathName = WOW32_strrchr(NewPath, '\\');
  908. pPathNameSlash = WOW32_strrchr(NewPath, '/');
  909. if ((NULL == pPathName) && (NULL == pPathNameSlash)) {
  910. pPathName = &NewPath[2]; // 1st char after '?:'
  911. } else {
  912. if (pPathNameSlash > pPathName) {
  913. pPathName = pPathNameSlash;
  914. }
  915. pPathName++; // 1st char in name
  916. }
  917. if (NULL != (pPathExt = WOW32_strchr(pPathName, '.'))) { // is there a period?
  918. pPathExt++; // 1st char in ext
  919. if (strlen(pPathExt) > 3) { // extension too big?
  920. pPathExt[3] = 0; // truncate extension
  921. }
  922. pPathExt--; // back to period
  923. if (pPathExt - pPathName > 8) { // is name too big?
  924. strcpy (&pPathName[8], pPathExt); // truncate file name
  925. }
  926. } else {
  927. if (strlen(pPathName) > 8) { // is name too big?
  928. pPathName[8] = 0; // truncate file name
  929. }
  930. }
  931. return(NewPath);
  932. }
  933. /* ExpandDosPath - Expands paths of the form "*.*" to "????????.???"
  934. * and merges in currentdirectory info
  935. *
  936. * N.B. This routine does not handle long file names
  937. *
  938. * Entry - pstr-> string to convert
  939. *
  940. * Exit
  941. * SUCCESS
  942. * return value-> converted string
  943. *
  944. * FAILURE
  945. * return value==NULL
  946. *
  947. */
  948. PSTR ExpandDosPath(PSTR pszPathGiven)
  949. {
  950. static CHAR NewPath[MAX_PATH],TempPath[MAX_PATH]; // this is not reentrant
  951. USHORT usNewPathIndex = 0;
  952. USHORT usFillCount = 8;
  953. UCHAR ucCurrentChar, ucDrive;
  954. PSTR pszPath = TempPath;
  955. char *pFilePart;
  956. if (!pszPathGiven ) {
  957. return NULL;
  958. }
  959. // There is a bug in this routine where it is ignoring /. DOS treats them
  960. // same as \. As matches for \ are spread all over this routine, its
  961. // much safer to take an entry pass over the string and covert / to \.
  962. // sudeepb 29-Jun-1995
  963. while (pszPathGiven[usNewPathIndex]) {
  964. if (pszPathGiven[usNewPathIndex] == '/')
  965. pszPath [usNewPathIndex] = '\\';
  966. else
  967. pszPath [usNewPathIndex] = pszPathGiven[usNewPathIndex];
  968. usNewPathIndex++;
  969. }
  970. pszPath [usNewPathIndex] = '\0';
  971. //
  972. // copy filepath into NewPath, add in current drive, directory
  973. // if relative path name.
  974. //
  975. // Note: should be changed later to use GetFullPathName, since
  976. // it is equivalent, and should have the correct curr dir,
  977. // cur drive. be wary of trailing dots in GetFullPathName
  978. // ie. "*." is not the same as "*"
  979. //
  980. if (WOW32_strncmp(pszPath, "\\\\", 2)) { // should be drive letter
  981. ucDrive = *pszPath++;
  982. if ((*pszPath++ != ':') || (!isalpha(ucDrive))) {
  983. SetLastError(ERROR_PATH_NOT_FOUND);
  984. return NULL;
  985. }
  986. NewPath[0] = ucDrive;
  987. NewPath[1] = ':';
  988. usNewPathIndex = 2;
  989. if (*pszPath != '\\') {
  990. NewPath[usNewPathIndex++] = '\\';
  991. if (DosWowGetCurrentDirectory ((UCHAR) (toupper(ucDrive)-'A'+1),
  992. &NewPath[usNewPathIndex]))
  993. {
  994. return NULL;
  995. }
  996. usNewPathIndex = (USHORT)strlen(NewPath);
  997. if (usNewPathIndex > 3) {
  998. NewPath[usNewPathIndex++] = '\\';
  999. }
  1000. }
  1001. pFilePart = WOW32_strrchr(pszPath, '\\');
  1002. if (pFilePart) {
  1003. pFilePart++;
  1004. } else {
  1005. pFilePart = pszPath;
  1006. }
  1007. } else { // check for UNC name, if not UNC, path not found
  1008. usNewPathIndex = 2;
  1009. NewPath[0] = NewPath[1] = '\\';
  1010. pszPath += 2;
  1011. pFilePart = WOW32_strrchr(pszPath, '\\');
  1012. if (!pFilePart) {
  1013. SetLastError(ERROR_PATH_NOT_FOUND);
  1014. return NULL;
  1015. }
  1016. pFilePart++;
  1017. }
  1018. while (pszPath < pFilePart && usNewPathIndex < MAX_PATH) {
  1019. NewPath[usNewPathIndex++] = *pszPath++;
  1020. }
  1021. ucCurrentChar = *pszPath++;
  1022. while ((usNewPathIndex < MAX_PATH) && (ucCurrentChar)) {
  1023. if (ucCurrentChar == '*') {
  1024. //
  1025. // expand "*"s to "?"
  1026. //
  1027. while ((usFillCount > 0) && (usNewPathIndex < MAX_PATH)) {
  1028. NewPath[usNewPathIndex++] = '?';
  1029. usFillCount--;
  1030. }
  1031. //
  1032. // skip to next valid character after expansion
  1033. //
  1034. while ((ucCurrentChar != 0) &&
  1035. (ucCurrentChar != '.') &&
  1036. (ucCurrentChar != '\\')) {
  1037. ucCurrentChar = *pszPath++;
  1038. }
  1039. } else {
  1040. if (ucCurrentChar == '.') {
  1041. usFillCount = 3; // fill count for .ext
  1042. } else if (ucCurrentChar == '\\') {
  1043. usFillCount = 8; // fill count for fn.
  1044. } else {
  1045. usFillCount--;
  1046. }
  1047. NewPath[usNewPathIndex++] = ucCurrentChar;
  1048. //
  1049. // get next character (except if no more are left)
  1050. //
  1051. if (ucCurrentChar) {
  1052. ucCurrentChar = *pszPath++;
  1053. }
  1054. }
  1055. }
  1056. if (usNewPathIndex >= MAX_PATH) {
  1057. SetLastError(ERROR_PATH_NOT_FOUND);
  1058. return NULL;
  1059. }
  1060. NewPath[usNewPathIndex] = 0; // trailing zero
  1061. return NewPath;
  1062. }
  1063. BOOL IsCdRomFile(PSTR pszPath)
  1064. {
  1065. UCHAR pszRootDir[MAX_PATH];
  1066. UCHAR file_system[MAX_PATH];
  1067. int i, j;
  1068. // The given path is either a network path or has D: at the start.
  1069. if (!pszPath[0]) {
  1070. return FALSE;
  1071. }
  1072. if (pszPath[1] == ':') {
  1073. pszRootDir[0] = pszPath[0];
  1074. pszRootDir[1] = ':';
  1075. pszRootDir[2] = '\\';
  1076. pszRootDir[3] = 0;
  1077. } else if (IS_ASCII_PATH_SEPARATOR(pszPath[0]) &&
  1078. IS_ASCII_PATH_SEPARATOR(pszPath[1])) {
  1079. j = 0;
  1080. for (i = 2; pszPath[i]; i++) {
  1081. if (IS_ASCII_PATH_SEPARATOR(pszPath[i])) {
  1082. if (++j == 2) {
  1083. break;
  1084. }
  1085. }
  1086. }
  1087. i = min(i, MAX_PATH-2);
  1088. memcpy(pszRootDir, pszPath, i);
  1089. pszRootDir[i] = '\\';
  1090. pszRootDir[i+1] = 0;
  1091. } else {
  1092. return FALSE;
  1093. }
  1094. if (GetVolumeInformationOem(pszRootDir, NULL, 0, NULL, NULL, NULL,
  1095. file_system, MAX_PATH) &&
  1096. !WOW32_stricmp(file_system, "CDFS")) {
  1097. return TRUE;
  1098. }
  1099. return FALSE;
  1100. }
  1101. /* WK32WOWFileOpen - Open a file
  1102. *
  1103. *
  1104. * Entry - pszPath Path of file to open
  1105. * wAccess Desired access
  1106. *
  1107. * Exit
  1108. * SUCCESS
  1109. * handle number
  1110. *
  1111. * FAILURE
  1112. * system status code
  1113. * -1 to indicate the the requested open was for device and
  1114. * hence not attempted
  1115. *
  1116. */
  1117. ULONG FASTCALL WK32WOWFileOpen(PVDMFRAME pFrame)
  1118. {
  1119. PWOWFILEOPEN16 parg16;
  1120. HANDLE hFile;
  1121. ULONG ul;
  1122. SHORT iDosHandle;
  1123. PSTR pszPath;
  1124. WORD wAccess;
  1125. DWORD dwWinAccess;
  1126. DWORD dwWinShareMode;
  1127. WORD tmp;
  1128. PBYTE pJFT;
  1129. PDOSSFT pSft;
  1130. PSTR lpFileName;
  1131. BOOL ItsANamedPipe = FALSE;
  1132. PHMAPPEDFILEALIAS pCache;
  1133. PHMAPPEDFILEALIAS pTempCache;
  1134. PTD ptd;
  1135. PWCH pwch;
  1136. BOOL first = TRUE;
  1137. UNICODE_STRING UniFile;
  1138. //
  1139. // Get arguments.
  1140. //
  1141. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  1142. pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  1143. FETCHWORD(parg16->pszPathOffset));
  1144. wAccess = FETCHWORD(parg16->wAccess);
  1145. //
  1146. // If the path requested is a device then just pass it
  1147. // through to DOS.
  1148. //
  1149. if (IsDevice(pszPath)) {
  1150. FREEARGPTR(parg16);
  1151. ul = 0xFFFFFFFF; // magic value to indicate that the open
  1152. goto Done; // was not attempted.
  1153. }
  1154. if ((iDosHandle = VDDAllocateDosHandle(0, (PVOID *)&pSft, &pJFT)) < 0) {
  1155. FREEARGPTR(parg16);
  1156. ul = ERROR_TOO_MANY_OPEN_FILES | 0xFFFF0000;
  1157. goto Done;
  1158. }
  1159. pCache = ALLOCMAPFILECACHE();
  1160. pCache->hfile32 = 0;
  1161. pCache->fAccess = FALSE;
  1162. //
  1163. // Compute dwWinAccess and dwWinShareMode from wAccess.
  1164. //
  1165. tmp = wAccess&0x7;
  1166. if (tmp == 0) {
  1167. pCache->fAccess = TRUE;
  1168. dwWinAccess = GENERIC_READ;
  1169. } else if (tmp == 1) {
  1170. dwWinAccess = GENERIC_WRITE;
  1171. } else if (tmp == 2) {
  1172. dwWinAccess = GENERIC_READ | GENERIC_WRITE;
  1173. } else {
  1174. FREEARGPTR(parg16);
  1175. ul = ERROR_INVALID_ACCESS | 0xFFFF0000;
  1176. goto Done;
  1177. }
  1178. if (Dos_Flag_Addr && (*Dos_Flag_Addr & DOS_FLAG_EXEC_OPEN)) {
  1179. dwWinAccess |= GENERIC_EXECUTE;
  1180. }
  1181. tmp = wAccess&0x70;
  1182. dwWinShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  1183. if (tmp == 0x10) {
  1184. dwWinShareMode = 0;
  1185. } else if (tmp == 0x20) {
  1186. dwWinShareMode = FILE_SHARE_READ;
  1187. } else if (tmp == 0x30) {
  1188. dwWinShareMode = FILE_SHARE_WRITE;
  1189. }
  1190. //
  1191. // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED
  1192. // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe
  1193. // and the only way to accomplish that is to open the named pipe handle in
  1194. // overlapped I/O mode now
  1195. //
  1196. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  1197. lpFileName = NormalizeDosPath(pszPath,
  1198. (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
  1199. &ItsANamedPipe);
  1200. if (lpFileName) {
  1201. //
  1202. // This hack fixes the "Living Books" install program, which opens
  1203. // a file DENY ALL, and then tries to reopen the same file. On DOS,
  1204. // this succeeds if it is done from the same task, but it doesn't work
  1205. // on NT. So here we open it without the sharing restrictions, since it
  1206. // is anyway just a type of .INF file on the CD-ROM.
  1207. // Currently, the test is very specific, but I can't think of a good
  1208. // way to do this generically.
  1209. //
  1210. if ((dwWinShareMode == 0) &&
  1211. ((ptd = CURRENTPTD())->dwWOWCompatFlagsEx & WOWCFEX_SAMETASKFILESHARE) &&
  1212. (IsCdRomFile(lpFileName)) &&
  1213. (!WOW32_stricmp(pszPath, "install.txt"))) {
  1214. dwWinShareMode = FILE_SHARE_READ;
  1215. }
  1216. hFile = CreateFileOem(lpFileName,
  1217. dwWinAccess,
  1218. dwWinShareMode | FILE_SHARE_DELETE,
  1219. NULL,
  1220. OPEN_EXISTING,
  1221. ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0,
  1222. NULL
  1223. );
  1224. // If the open failed, includes a request for WRITE, and was to
  1225. // a CD-ROM then try again without the write request. Since
  1226. // this is how DOS does it.
  1227. if (hFile == INVALID_HANDLE_VALUE) {
  1228. if (dwWinAccess&GENERIC_WRITE &&
  1229. !ItsANamedPipe &&
  1230. IsCdRomFile(lpFileName)) {
  1231. dwWinAccess &= ~GENERIC_WRITE;
  1232. hFile = CreateFileOem(lpFileName,
  1233. dwWinAccess,
  1234. dwWinShareMode | FILE_SHARE_DELETE,
  1235. NULL,
  1236. OPEN_EXISTING,
  1237. ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0,
  1238. NULL
  1239. );
  1240. }
  1241. // See if they are trying to open a .ini file, and if it doesn't exist,
  1242. // copy it to the user's home dir from the system dir
  1243. else if ((gpfnTermsrvCORIniFile != NULL) &&
  1244. WOW32_strstr(lpFileName,".INI")) {
  1245. pwch = malloc_w((MAX_PATH + 1)*sizeof(WCHAR));
  1246. if (pwch) {
  1247. UniFile.Buffer = pwch;
  1248. UniFile.MaximumLength = (MAX_PATH+1)*sizeof(WCHAR);
  1249. RtlMultiByteToUnicodeN(pwch,
  1250. (MAX_PATH+1)*sizeof(WCHAR),
  1251. NULL,
  1252. lpFileName,
  1253. strlen(lpFileName) + 1);
  1254. if (RtlDosPathNameToNtPathName_U(pwch,
  1255. &UniFile,
  1256. NULL,
  1257. NULL)) {
  1258. gpfnTermsrvCORIniFile(&UniFile);
  1259. RtlFreeHeap(RtlProcessHeap(), 0, UniFile.Buffer);
  1260. hFile = CreateFileOem(lpFileName,
  1261. dwWinAccess,
  1262. dwWinShareMode,
  1263. NULL,
  1264. OPEN_EXISTING,
  1265. 0,
  1266. INVALID_HANDLE_VALUE
  1267. );
  1268. }
  1269. free_w(pwch);
  1270. }
  1271. }
  1272. else {
  1273. // If all attempts to open the file failed, it might be one of the
  1274. // 9x special path, so try mapping it to NT special path
  1275. // i.e. c:\winnt\startm~1 becomes c:\docume~1\alluse~1\startm~1
  1276. UCHAR szMappedPath[MAX_PATH];
  1277. if(!ItsANamedPipe && W32Map9xSpecialPath(lpFileName,szMappedPath,sizeof(szMappedPath))){
  1278. lpFileName=&szMappedPath[0];
  1279. hFile = CreateFileOem(lpFileName,
  1280. dwWinAccess,
  1281. dwWinShareMode | FILE_SHARE_DELETE,
  1282. NULL,
  1283. OPEN_EXISTING,
  1284. 0,
  1285. NULL
  1286. );
  1287. }
  1288. }
  1289. }
  1290. } else {
  1291. hFile = INVALID_HANDLE_VALUE;
  1292. if (GetLastError() != ERROR_ACCESS_DENIED) {
  1293. SetLastError(ERROR_FILE_NOT_FOUND);
  1294. }
  1295. SetLastError(ERROR_FILE_NOT_FOUND);
  1296. }
  1297. if (hFile == INVALID_HANDLE_VALUE) {
  1298. ul = GetLastError() | 0xFFFF0000;
  1299. LOGDEBUG(fileoclevel,("WK32WOWFileOpen: %s mode:%02X failed error %d\n",pszPath, wAccess, GetLastError()));
  1300. FREEARGPTR(parg16);
  1301. if (ItsANamedPipe) {
  1302. LocalFree(lpFileName);
  1303. }
  1304. pJFT[iDosHandle] = 0xFF; // undo VDDAllocateDosHandle
  1305. pSft->SFT_Ref_Count--;
  1306. goto Done;
  1307. } else if (ItsANamedPipe) {
  1308. //
  1309. // we have to keep some info around when we open a named pipe
  1310. //
  1311. VrAddOpenNamedPipeInfo(hFile, lpFileName);
  1312. }
  1313. LOGDEBUG(fileoclevel,("WK32WOWFileOpen: %s hFile:%08X fh:%04X mode:%02X\n",pszPath, hFile,(WORD)iDosHandle,wAccess));
  1314. // Be defensive. If the app has managed to close the file via DOSEmulation
  1315. // then we need to make sure we don't have the old file handle in our cache.
  1316. if ( pTempCache = FINDMAPFILECACHE(hFile) ) {
  1317. pTempCache->fAccess = FALSE;
  1318. FREEMAPFILECACHE(hFile);
  1319. }
  1320. pCache->hfile32 = hFile;
  1321. if ((vptopPDB == parg16->lpPDB) && (pCache->fAccess)) {
  1322. W32MapViewOfFile( pCache, hFile);
  1323. } else {
  1324. FREEMAPFILECACHE(hFile);
  1325. }
  1326. //
  1327. // Fill in the SFT.
  1328. //
  1329. VDDAssociateNtHandle(pSft, hFile, wAccess);
  1330. //
  1331. // Set the SFT flags appropriately for an open file
  1332. //
  1333. if (IsCharAlpha(lpFileName[0]) && (':' == lpFileName[1])) {
  1334. UCHAR ch = toupper(lpFileName[0]) - 'A';
  1335. pSft->SFT_Flags = (USHORT)(ch) | (pSft->SFT_Flags & 0xff00);
  1336. }
  1337. FREEARGPTR(parg16);
  1338. if (ItsANamedPipe) {
  1339. LocalFree(lpFileName);
  1340. pSft->SFT_Flags |= SFT_NAMED_PIPE;
  1341. }
  1342. ul = iDosHandle;
  1343. Done:
  1344. return ul;
  1345. }
  1346. /* WK32WOWFileCreate - Create a file
  1347. *
  1348. *
  1349. * Entry - pszPath Path of file to create
  1350. *
  1351. * Exit
  1352. * SUCCESS
  1353. * handle number
  1354. *
  1355. * FAILURE
  1356. * system status code
  1357. * -1 to indicate the the requested open was for device and
  1358. * hence not attempted
  1359. *
  1360. */
  1361. ULONG FASTCALL WK32WOWFileCreate(PVDMFRAME pFrame)
  1362. {
  1363. PWOWFILECREATE16 parg16;
  1364. HANDLE hFile;
  1365. ULONG ul;
  1366. SHORT iDosHandle;
  1367. PSTR pszPath;
  1368. PBYTE pJFT;
  1369. PDOSSFT pSft;
  1370. PSTR lpFileName;
  1371. ULONG attributes;
  1372. BOOL ItsANamedPipe = FALSE;
  1373. PTD ptd;
  1374. BOOL bFirstTry = TRUE;
  1375. //
  1376. // Get arguments.
  1377. //
  1378. GETARGPTR(pFrame, sizeof(WOWFILECREATE16), parg16);
  1379. pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  1380. FETCHWORD(parg16->pszPathOffset));
  1381. if (!(attributes = (DWORD) FETCHWORD(parg16->wAttributes) & 0x27)) {
  1382. attributes = FILE_ATTRIBUTE_NORMAL;
  1383. }
  1384. //
  1385. // If the path requested is a device then just pass it
  1386. // through to DOS.
  1387. //
  1388. if (IsDevice(pszPath)) {
  1389. FREEARGPTR(parg16);
  1390. ul = 0xFFFFFFFF; // magic value to indicate that the open
  1391. goto Done; // was not attempted.
  1392. }
  1393. if ((iDosHandle = VDDAllocateDosHandle(0, (PVOID *)&pSft, &pJFT)) < 0) {
  1394. ul = ERROR_TOO_MANY_OPEN_FILES | 0xFFFF0000;
  1395. goto Done;
  1396. }
  1397. //
  1398. // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED
  1399. // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe
  1400. // and the only way to accomplish that is to open the named pipe handle in
  1401. // overlapped I/O mode now
  1402. //
  1403. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  1404. lpFileName = NormalizeDosPath(pszPath,
  1405. (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
  1406. &ItsANamedPipe);
  1407. if (lpFileName) {
  1408. Try_Create:
  1409. hFile = CreateFileOem(lpFileName,
  1410. GENERIC_READ | GENERIC_WRITE,
  1411. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1412. NULL,
  1413. CREATE_ALWAYS,
  1414. ItsANamedPipe ? attributes | FILE_FLAG_OVERLAPPED : attributes,
  1415. NULL
  1416. );
  1417. if ((hFile == INVALID_HANDLE_VALUE) &&
  1418. (bFirstTry) &&
  1419. (GetLastError() == ERROR_USER_MAPPED_FILE)) {
  1420. // Some Windows Install Programs try to overwrite a .FON font file
  1421. // during installation - without calling RemoveFontResource();
  1422. // If the font is in GDI32's cache the create will fail.
  1423. if (RemoveFontResourceOem(lpFileName)) {
  1424. LOGDEBUG(0,("WK32FileCreate: RemoveFontResource on %s \n", lpFileName));
  1425. SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
  1426. }
  1427. bFirstTry = FALSE;
  1428. goto Try_Create;
  1429. }
  1430. } else {
  1431. hFile = INVALID_HANDLE_VALUE;
  1432. SetLastError(ERROR_FILE_NOT_FOUND);
  1433. }
  1434. if (hFile == INVALID_HANDLE_VALUE) {
  1435. LOGDEBUG(fileoclevel,("WK32WOWFileCreate: %s failed error %d\n",pszPath, GetLastError()));
  1436. if (ItsANamedPipe) {
  1437. LocalFree(lpFileName);
  1438. }
  1439. pJFT[iDosHandle] = 0xFF; // undo VDDAllocateDosHandle
  1440. pSft->SFT_Ref_Count--;
  1441. ul = GetLastError() | 0xFFFF0000;
  1442. goto Done;
  1443. } else {
  1444. if (ItsANamedPipe) {
  1445. //
  1446. // we have to keep some info around when we open a named pipe
  1447. //
  1448. VrAddOpenNamedPipeInfo(hFile, lpFileName);
  1449. }
  1450. //
  1451. // Symantec Install 3.1 shipped with Q&A 4.0 wants to be sure it's the
  1452. // only program running, so instead of nicely asking the user to close
  1453. // other programs, it changes the shell= line in system.ini to its
  1454. // install.exe, then restarts Windows and continues its installation.
  1455. // To reverse this change, they sloppily restore a saved copy of
  1456. // system.ini rather than use the API. Since the shell= line is
  1457. // mapped to the registry, this sloppy method doesn't work. Later
  1458. // when they want to create program groups, they try to start DDE
  1459. // with the shell, and when that fails they read the shell= line
  1460. // and start the specified program. On NT 4.0, that would be the
  1461. // install program and things go poorly. On 3.51 they would eventually
  1462. // give up and launch progman.exe, but since the shell has changed
  1463. // this no longer works.
  1464. //
  1465. // We fix this by detecting their creation (overwriting) of system.ini
  1466. // and at that point repairing the shell= value to Explorer.exe. This
  1467. // operation is done by INSTBIN.EXE, module name INSTBIN, which is a
  1468. // relief because I thought I would have to set WOWCFEX_RESTOREEXPLORER
  1469. // for module name INSTALL (the primary Symantec Install EXE).
  1470. //
  1471. // Thanks to Bob Day for figuring out what the app was doing, I simply
  1472. // came up with a workaround and implemented it.
  1473. //
  1474. // DaveHart 28-Jan-96
  1475. //
  1476. WOW32ASSERTMSG(vptopPDB != parg16->lpPDB,
  1477. "KRNL386 does create files, disable this assertion and add test below.\n");
  1478. if ((ptd = CURRENTPTD())->dwWOWCompatFlagsEx & WOWCFEX_RESTOREEXPLORER) {
  1479. char szLowerPath[MAX_PATH];
  1480. strncpy(szLowerPath, pszPath, MAX_PATH);
  1481. szLowerPath[MAX_PATH-1] = '\0';
  1482. WOW32_strlwr(szLowerPath);
  1483. if (WOW32_strstr(szLowerPath, szSystemDotIni)) {
  1484. if (IsModuleSymantecInstall(ptd->hMod16)) {
  1485. WritePrivateProfileString(szBoot, szShell, szExplorerDotExe, szSystemDotIni);
  1486. LOGDEBUG(LOG_ALWAYS, ("Restored shell=Explorer.exe for Symantec Install hack.\n"));
  1487. }
  1488. }
  1489. }
  1490. }
  1491. FREEARGPTR(parg16);
  1492. LOGDEBUG(fileoclevel,("WK32WOWFileCreate: %s hFile:%08X fh:%04X\n",pszPath, hFile,(WORD)iDosHandle));
  1493. //
  1494. // Fill in the SFT.
  1495. //
  1496. VDDAssociateNtHandle(pSft, hFile, 2);
  1497. //
  1498. // Set the SFT flags appropriately for an open file
  1499. //
  1500. if (IsCharAlpha(lpFileName[0]) && (':' == lpFileName[1])) {
  1501. UCHAR ch = toupper(lpFileName[0]) - 'A';
  1502. pSft->SFT_Flags = (USHORT)(ch) | (pSft->SFT_Flags & 0xff00);
  1503. }
  1504. if (ItsANamedPipe) {
  1505. LocalFree(lpFileName);
  1506. pSft->SFT_Flags |= SFT_NAMED_PIPE;
  1507. }
  1508. ul = iDosHandle;
  1509. Done:
  1510. return ul;
  1511. }
  1512. /* WK32WOWFileClose - Close a file
  1513. *
  1514. *
  1515. * Entry - hFile Handle of file to close
  1516. *
  1517. * Exit
  1518. * SUCCESS
  1519. * 0
  1520. *
  1521. * FAILURE
  1522. * Invalid handle status
  1523. * -1 is returned if this handle is for a device.
  1524. *
  1525. */
  1526. ULONG FASTCALL WK32WOWFileClose(PVDMFRAME pFrame)
  1527. {
  1528. PWOWFILECLOSE16 parg16;
  1529. PBYTE pJFT;
  1530. HANDLE Handle;
  1531. PDOSSFT pSFT;
  1532. ULONG ul;
  1533. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  1534. Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->hFile, (PVOID *)&pSFT, &pJFT);
  1535. if (!Handle || !pSFT->SFT_Ref_Count) {
  1536. ul = ERROR_INVALID_HANDLE | 0xFFFF0000;
  1537. goto Cleanup;
  1538. }
  1539. if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
  1540. ul = 0xFFFFFFFF; // Let DOS handle device handles.
  1541. goto Cleanup;
  1542. }
  1543. // Set the JFT entry to 0xFF to free it up.
  1544. pJFT[FETCHWORD(parg16->hFile)] = 0xFF;
  1545. // Decrement reference count.
  1546. pSFT->SFT_Ref_Count--;
  1547. // Close the handle if the reference count was set to zero.
  1548. if (!pSFT->SFT_Ref_Count) {
  1549. FREEMAPFILECACHE(Handle);
  1550. LOGDEBUG(fileoclevel,("WK32WOWFileClose: Close Handle:%X fh32:%X\n", parg16->hFile, Handle));
  1551. if (!DPM_CloseHandle(Handle)) {
  1552. ul = GetLastError() | 0xFFFF0000;
  1553. goto Cleanup;
  1554. }
  1555. //
  1556. // check if the handle being closed references a named pipe - we have to
  1557. // delete some info that we keep for the open named pipe
  1558. //
  1559. if (!pSFT->SFT_Ref_Count && IsVdmRedirLoaded()) {
  1560. VrRemoveOpenNamedPipeInfo(Handle);
  1561. }
  1562. }
  1563. ul = 0;
  1564. Cleanup:
  1565. FREEARGPTR(parg16);
  1566. return ul;
  1567. }
  1568. /* WK32WOWFileGetAttributes - Get file attributes
  1569. *
  1570. *
  1571. * Entry - pszPath File to get attributes from
  1572. *
  1573. * Exit
  1574. * SUCCESS
  1575. * Attributes for file
  1576. *
  1577. * FAILURE
  1578. * system status code
  1579. *
  1580. */
  1581. ULONG FASTCALL WK32WOWFileGetAttributes(PVDMFRAME pFrame)
  1582. {
  1583. PWOWFILEGETATTRIBUTES16 parg16;
  1584. PSTR pszPath, lpFileName;
  1585. ULONG attributes, l;
  1586. BOOL ItsANamedPipe = FALSE;
  1587. PWCH pwch;
  1588. BOOL first = TRUE;
  1589. UNICODE_STRING UniFile;
  1590. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  1591. pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  1592. FETCHWORD(parg16->pszPathOffset));
  1593. FREEARGPTR(parg16);
  1594. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  1595. if (lpFileName = NormalizeDosPath(pszPath,
  1596. (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
  1597. &ItsANamedPipe)) {
  1598. attributes = GetFileAttributesOemSys(lpFileName, FALSE);
  1599. // See if they are trying to chmod a .ini file, and if so see if we
  1600. // should copy it to the user's home dir
  1601. if ((gpfnTermsrvCORIniFile != NULL) && (attributes == 0xffffffff) && WOW32_strstr(lpFileName,".INI")) {
  1602. pwch = malloc_w((MAX_PATH + 1)*sizeof(WCHAR));
  1603. if (pwch) {
  1604. UniFile.Buffer = pwch;
  1605. UniFile.MaximumLength = (MAX_PATH+1)*sizeof(WCHAR);
  1606. RtlMultiByteToUnicodeN(pwch,
  1607. (MAX_PATH+1)*sizeof(WCHAR),
  1608. NULL,
  1609. lpFileName,
  1610. strlen(lpFileName) + 1);
  1611. if (RtlDosPathNameToNtPathName_U(pwch,
  1612. &UniFile,
  1613. NULL,
  1614. NULL)) {
  1615. gpfnTermsrvCORIniFile(&UniFile);
  1616. RtlFreeHeap(RtlProcessHeap(), 0, UniFile.Buffer);
  1617. attributes = GetFileAttributesOemSys(lpFileName, FALSE);
  1618. }
  1619. free_w(pwch);
  1620. }
  1621. }
  1622. } else {
  1623. attributes = 0xFFFFFFFF;
  1624. }
  1625. if (ItsANamedPipe) {
  1626. LocalFree(lpFileName);
  1627. }
  1628. if (attributes == 0xFFFFFFFF) {
  1629. return (0xFFFF0000 | GetLastError());
  1630. }
  1631. // Success!
  1632. // Check to make sure that we didn't have a trailing backslash
  1633. // on this one. In that case we should fail with PATH_NOT_FOUND.
  1634. l = strlen(pszPath);
  1635. if (l > 0 &&
  1636. IS_ASCII_PATH_SEPARATOR(pszPath[l - 1]) &&
  1637. l != 1 &&
  1638. !(l == 3 && pszPath[1] == ':')) {
  1639. return (0xFFFF0000 | ERROR_PATH_NOT_FOUND);
  1640. }
  1641. if (attributes == FILE_ATTRIBUTE_NORMAL)
  1642. attributes = 0;
  1643. else
  1644. attributes &= DOS_ATTR_MASK;
  1645. // SudeepB - 28-Jul-1997
  1646. //
  1647. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  1648. // for directories while WinNT returns
  1649. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  1650. // Some VB controls that app setups use, depend on getting
  1651. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  1652. // An example of this is Cliffs StudyWare series.
  1653. if (attributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY)) {
  1654. if(IsCdRomFile(lpFileName))
  1655. attributes = FILE_ATTRIBUTE_DIRECTORY;
  1656. }
  1657. return attributes;
  1658. }
  1659. /* WK32WOWFileSetAttributes - Set file attributes
  1660. *
  1661. *
  1662. * Entry - pszPath File to get attributes from
  1663. *
  1664. * Exit
  1665. * SUCCESS
  1666. * Attributes for file
  1667. *
  1668. * FAILURE
  1669. * system status code
  1670. *
  1671. */
  1672. ULONG FASTCALL WK32WOWFileSetAttributes(PVDMFRAME pFrame)
  1673. {
  1674. PWOWFILESETATTRIBUTES16 parg16;
  1675. PSTR pszPath, lpFileName;
  1676. ULONG attributes, l, dwReturn;
  1677. BOOL ItsANamedPipe = FALSE;
  1678. GETARGPTR(pFrame, sizeof(WOWFILESETATTRIBUTES16), parg16);
  1679. pszPath = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  1680. FETCHWORD(parg16->pszPathOffset));
  1681. if (!(attributes = (DWORD) FETCHWORD(parg16->wAttributes))) {
  1682. attributes = FILE_ATTRIBUTE_NORMAL;
  1683. }
  1684. FREEARGPTR(parg16);
  1685. // Check to make sure that we didn't have a trailing backslash
  1686. // on this one. In that case we should fail with PATH_NOT_FOUND.
  1687. l = strlen(pszPath);
  1688. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  1689. if ((l > 0 &&
  1690. IS_ASCII_PATH_SEPARATOR(pszPath[l - 1]) &&
  1691. l != 1 &&
  1692. !(l == 3 && pszPath[1] == ':')) ||
  1693. !(lpFileName = NormalizeDosPath(pszPath,
  1694. (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
  1695. &ItsANamedPipe))) {
  1696. dwReturn = 0xFFFF0000 | ERROR_PATH_NOT_FOUND;
  1697. } else {
  1698. attributes &= DOS_ATTR_MASK;
  1699. if (SetFileAttributesOemSys(lpFileName, attributes, FALSE)) {
  1700. dwReturn = 0;
  1701. } else {
  1702. dwReturn = 0xFFFF0000 | GetLastError();
  1703. }
  1704. }
  1705. if (ItsANamedPipe) {
  1706. LocalFree(lpFileName);
  1707. }
  1708. return (dwReturn);
  1709. }
  1710. /* WK32WOWFileGetDateTime - Get file date and time
  1711. *
  1712. *
  1713. * Entry - fh DOS file handle
  1714. *
  1715. * Exit
  1716. * SUCCESS
  1717. * date and time for file
  1718. *
  1719. * FAILURE
  1720. * 0xFFFF
  1721. *
  1722. */
  1723. // this function lives in ntvdm.exe
  1724. // see demlfn.c for details
  1725. extern ULONG demGetFileTimeByHandle_WOW(HANDLE);
  1726. ULONG FASTCALL WK32WOWFileGetDateTime(PVDMFRAME pFrame)
  1727. {
  1728. PWOWFILEGETDATETIME16 parg16;
  1729. HANDLE Handle;
  1730. PDOSSFT pSFT;
  1731. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  1732. Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  1733. FREEARGPTR(parg16);
  1734. if (!Handle || (pSFT->SFT_Flags & 0x80)) { // Let DOS handle device handles.
  1735. return 0xFFFF;
  1736. }
  1737. return(demGetFileTimeByHandle_WOW(Handle));
  1738. }
  1739. /* WK32WOWFileSetDateTime - Set file date and time
  1740. *
  1741. *
  1742. * Entry - fh DOS file handle
  1743. * date
  1744. * time
  1745. *
  1746. * Exit
  1747. * SUCCESS
  1748. * date and time for file set
  1749. *
  1750. * FAILURE
  1751. * 0xFFFF
  1752. *
  1753. */
  1754. ULONG FASTCALL WK32WOWFileSetDateTime(PVDMFRAME pFrame)
  1755. {
  1756. PWOWFILESETDATETIME16 parg16;
  1757. HANDLE Handle;
  1758. FILETIME LastWriteTime, LocalTime;
  1759. USHORT wDate, wTime;
  1760. PDOSSFT pSFT;
  1761. GETARGPTR(pFrame, sizeof(WOWFILESETDATETIME16), parg16);
  1762. Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  1763. wDate = FETCHWORD(parg16->date);
  1764. wTime = FETCHWORD(parg16->time);
  1765. FREEARGPTR(parg16);
  1766. if (!Handle ||
  1767. (pSFT->SFT_Flags & 0x80) || // Let DOS handle device handles.
  1768. !DosDateTimeToFileTime(wDate, wTime, &LocalTime) ||
  1769. !LocalFileTimeToFileTime(&LocalTime, &LastWriteTime) ||
  1770. !SetFileTime(Handle, NULL, NULL, &LastWriteTime)) {
  1771. return 0xFFFF;
  1772. }
  1773. return (0);
  1774. }
  1775. /* WK32WOWFileLock - Locks or unlocks file data
  1776. *
  1777. *
  1778. * Entry - fh DOS file handle
  1779. * cbRegionOffset Start of file portion to lock or unlock
  1780. * cbRegionLength Length of file portion to lock or unlock
  1781. * al 0 for lock, 1 for unlock
  1782. *
  1783. * Exit
  1784. * SUCCESS
  1785. * 0
  1786. *
  1787. * FAILURE
  1788. * system status code
  1789. *
  1790. */
  1791. ULONG FASTCALL WK32WOWFileLock(PVDMFRAME pFrame)
  1792. {
  1793. PWOWFILELOCK16 parg16;
  1794. HANDLE Handle;
  1795. UCHAR al;
  1796. DWORD cbOffset;
  1797. DWORD cbLength;
  1798. PDOSSFT pSFT;
  1799. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  1800. Handle = VDDRetrieveNtHandle(0, (SHORT) parg16->fh, (PVOID *)&pSFT, NULL);
  1801. if (pSFT->SFT_Flags & 0x80) { // Is this a device handle?
  1802. FREEARGPTR(parg16); // Let DOS handle device handles.
  1803. return 0xffffffff; // kernel QuickLock passes to DOS
  1804. } // after any error except 21 (dx=ffff, ax!=21)
  1805. al = FETCHWORD(parg16->ax) & 0xFF;
  1806. cbOffset = FETCHDWORD(parg16->cbRegionOffset);
  1807. cbLength = FETCHDWORD(parg16->cbRegionLength);
  1808. FREEARGPTR(parg16);
  1809. if (!Handle) {
  1810. return (0xFFFF0000 | ERROR_INVALID_HANDLE);
  1811. }
  1812. if (al == 0) { // lock
  1813. if (!DPM_LockFile(Handle, cbOffset, 0, cbLength, 0)) {
  1814. return (0xFFFF0000 | GetLastError());
  1815. }
  1816. } else if (al == 1) { // unlock
  1817. if (!DPM_UnlockFile(Handle, cbOffset, 0, cbLength, 0)) {
  1818. return (0xFFFF0000 | GetLastError());
  1819. }
  1820. } else { // bad parameter
  1821. return (0xFFFF0000 | ERROR_INVALID_FUNCTION);
  1822. }
  1823. return 0;
  1824. }
  1825. /* WK32WOWFindFirst - Path-Style Find First File
  1826. *
  1827. * Entry - lpDTA pointer to app's DTA
  1828. * lpFile sz to path
  1829. * wAttributes flags for search
  1830. *
  1831. * Exit
  1832. * SUCCESS
  1833. * 0
  1834. *
  1835. * FAILURE
  1836. * system status code
  1837. *
  1838. */
  1839. // this function (sitting in DEMLFN.C) checks to see if the path name
  1840. // passed as a parameter is a SHORT path name, never mind it's existance
  1841. extern BOOL demIsShortPathName(LPSTR, BOOL);
  1842. ULONG FASTCALL WK32WOWFindFirst(PVDMFRAME pFrame)
  1843. {
  1844. PWOWFINDFIRST16 parg16;
  1845. USHORT usSearchAttr;
  1846. PVOID pDTA;
  1847. PSTR ExpandName;
  1848. PSTR pFile;
  1849. BOOL ItsANamedPipe = FALSE;
  1850. DWORD dwRet = 0xFFFF0000 | ERROR_PATH_NOT_FOUND;
  1851. GETARGPTR(pFrame, sizeof(WOWFINDFIRST16), parg16);
  1852. GETVDMPTR(FETCHDWORD(parg16->lpDTA), SIZEOF_DOSSRCHDTA, pDTA);
  1853. pFile = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  1854. FETCHWORD(parg16->pszPathOffset)
  1855. );
  1856. usSearchAttr = FETCHWORD(parg16->wAttributes);
  1857. FREEARGPTR(parg16);
  1858. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  1859. pFile = NormalizeDosPath(pFile,
  1860. (WORD) (*(PUCHAR)DosWowData.lpCurDrv),
  1861. &ItsANamedPipe
  1862. );
  1863. //
  1864. // add in curr directory and expand the "*"s in the path to "?"s
  1865. //
  1866. ExpandName = ExpandDosPath (pFile);
  1867. if (NULL != ExpandName && !demIsShortPathName(ExpandName, TRUE)) {
  1868. ExpandName = NULL;
  1869. SetLastError(ERROR_INVALID_NAME);
  1870. }
  1871. //
  1872. // invoke dem to do the search
  1873. //
  1874. if (ExpandName) {
  1875. // return NO_MORE_FILES for quicktime install etc that barf on
  1876. // big directory or filenames that are longer than 64 bytes
  1877. // the magic number 50 is calculated from 64 - 12 (for 8.3) - 1 (backslash) -1
  1878. // (terminating zero)
  1879. LOGDEBUG(fileoclevel,("WK32WOWFindFirst: StrLen: %X\n", strlen(ExpandName)));
  1880. if ( (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_LIMITFINDFIRSTLEN) &&
  1881. (strlen(ExpandName) > 50)) {
  1882. dwRet = -1;
  1883. SetLastError(ERROR_NO_MORE_FILES);
  1884. }
  1885. else {
  1886. dwRet = demFileFindFirst (pDTA, ExpandName, usSearchAttr);
  1887. }
  1888. } else {
  1889. dwRet = (DWORD)-1;
  1890. }
  1891. if (dwRet == -1) {
  1892. dwRet = 0xFFFF0000 | GetLastError();
  1893. } else if (dwRet) {
  1894. dwRet |= 0xFFFF0000;
  1895. }
  1896. FREEVDMPTR(pDTA);
  1897. if (ItsANamedPipe) {
  1898. LocalFree(pFile);
  1899. }
  1900. return (dwRet);
  1901. }
  1902. /* WK32WOWFindNext - Path-Style Find Next File
  1903. *
  1904. * Entry - lpDTA pointer to app's DTA
  1905. *
  1906. * Exit
  1907. * SUCCESS
  1908. * 0
  1909. *
  1910. * FAILURE
  1911. * system status code
  1912. *
  1913. */
  1914. ULONG FASTCALL WK32WOWFindNext(PVDMFRAME pFrame)
  1915. {
  1916. PWOWFINDNEXT16 parg16;
  1917. PVOID pDTA;
  1918. DWORD dwRet;
  1919. GETARGPTR(pFrame, sizeof(WOWFINDNEXT16), parg16);
  1920. GETVDMPTR(FETCHDWORD(parg16->lpDTA), SIZEOF_DOSSRCHDTA, pDTA);
  1921. FREEARGPTR(parg16);
  1922. if (dwRet = demFileFindNext (pDTA))
  1923. dwRet |= 0xFFFF0000;
  1924. FREEVDMPTR(pDTA);
  1925. return (dwRet);
  1926. }
  1927. BOOL FASTCALL IsModuleSymantecInstall(HAND16 hMod16)
  1928. {
  1929. VPVOID vpFilename = 0;
  1930. PSZ pszFilename;
  1931. CHAR szName[32];
  1932. CHAR szVersion[16];
  1933. BOOL bRet;
  1934. // be sure stackalloc16() size matches stackfree16() size below
  1935. bRet = ((vpFilename = stackalloc16(MAX_PATH)) &&
  1936. GetModuleFileName16(hMod16, vpFilename, MAX_PATH) &&
  1937. (pszFilename = GetPModeVDMPointer(vpFilename, MAX_PATH)) &&
  1938. WowGetProductNameVersion(pszFilename, szName, sizeof szName, szVersion, sizeof szVersion, NULL, NULL, 0) &&
  1939. ! WOW32_stricmp(szName, "Symantec Install for Windows") &&
  1940. RtlEqualMemory(szVersion, "3.1.0.", 6));
  1941. if(vpFilename) {
  1942. stackfree16(vpFilename, MAX_PATH);
  1943. }
  1944. return (bRet);
  1945. }
  1946. //
  1947. // these 3 functions are located in dos/dem/demlfn.c and exported
  1948. // out of ntvdm.exe
  1949. //
  1950. extern ULONG demWOWLFNAllocateSearchHandle(HANDLE hFind);
  1951. extern HANDLE demWOWLFNGetSearchHandle(USHORT DosHandle);
  1952. extern BOOL demWOWLFNCloseSearchHandle(USHORT DosHandle);
  1953. ULONG FASTCALL WK32FindFirstFile(PVDMFRAME pFrame)
  1954. {
  1955. // locate the handle which is a dword and a ptr to win32_find_data
  1956. // which is a dword too. The handle's valid part is a low word
  1957. // To avoid extra calls we check if the hi word of a handle is 0
  1958. // is it is -- then it's 16-bit handle and we retrieve 32-bit handle
  1959. // from DEMLFN
  1960. PFINDFIRSTFILE16 parg16;
  1961. WIN32_FIND_DATA UNALIGNED* pFindData16;
  1962. WIN32_FIND_DATA FindData32;
  1963. HANDLE hFind;
  1964. PSTR pszSearchFile;
  1965. ULONG DosHandle = (ULONG)INVALID_HANDLE_VALUE;
  1966. GETARGPTR(pFrame, sizeof(FINDFIRSTFILE16), parg16);
  1967. GETPSZPTR(parg16->lpszSearchFile, pszSearchFile);
  1968. GETVDMPTR(parg16->lpFindData, sizeof(WIN32_FIND_DATA), pFindData16);
  1969. hFind = DPM_FindFirstFile(pszSearchFile, &FindData32);
  1970. if (INVALID_HANDLE_VALUE != hFind) {
  1971. // copy FindData into 16-bit land. Keep in mind that if we do a copy
  1972. // of sizeof(WIN32_FIND_DATA) we may be writing over user's memory
  1973. // since the size of a structure is not the same in 16-bit code!
  1974. RtlCopyMemory(pFindData16,
  1975. &FindData32,
  1976. sizeof(DWORD)+ // dwFileAttributes
  1977. sizeof(FILETIME)*3 + // FILETIME stuff
  1978. sizeof(DWORD)*3 + // FileSize Low and High
  1979. sizeof(DWORD)*2 + // dwReserved 0/1
  1980. sizeof(FindData32.cFileName) +
  1981. sizeof(FindData32.cAlternateFileName));
  1982. // and now map the handle
  1983. DosHandle = demWOWLFNAllocateSearchHandle(hFind);
  1984. }
  1985. FREEVDMPTR(pFindData16);
  1986. FREEPSZPTR(pszSearchFile);
  1987. FREEARGPTR(parg16);
  1988. return(DosHandle);
  1989. }
  1990. ULONG FASTCALL WK32FindNextFile(PVDMFRAME pFrame)
  1991. {
  1992. PFINDNEXTFILE16 parg16;
  1993. WIN32_FIND_DATA UNALIGNED* pFindData16;
  1994. WIN32_FIND_DATA FindData32;
  1995. HANDLE hFindFile;
  1996. ULONG DosHandle;
  1997. BOOL bSuccess;
  1998. GETARGPTR(pFrame, sizeof(FINDNEXTFILE16), parg16);
  1999. DosHandle = FETCHDWORD(parg16->hFindFile);
  2000. GETVDMPTR(parg16->lpFindData, sizeof(WIN32_FIND_DATA), pFindData16);
  2001. hFindFile = demWOWLFNGetSearchHandle((USHORT)DosHandle);
  2002. bSuccess = DPM_FindNextFile(hFindFile, &FindData32);
  2003. if (bSuccess) {
  2004. RtlCopyMemory(pFindData16,
  2005. &FindData32,
  2006. sizeof(DWORD)+ // dwFileAttributes
  2007. sizeof(FILETIME)*3 + // FILETIME stuff
  2008. sizeof(DWORD)*3 + // FileSize Low and High
  2009. sizeof(DWORD)*2 + // dwReserved 0/1
  2010. sizeof(FindData32.cFileName) +
  2011. sizeof(FindData32.cAlternateFileName));
  2012. }
  2013. FREEVDMPTR(pFindData16);
  2014. FREEARGPTR(parg16);
  2015. return((ULONG)bSuccess);
  2016. }
  2017. ULONG FASTCALL WK32FindClose(PVDMFRAME pFrame)
  2018. {
  2019. PFINDCLOSE16 parg16;
  2020. ULONG DosHandle;
  2021. GETARGPTR(pFrame, sizeof(FINDCLOSE16), parg16);
  2022. DosHandle = FETCHDWORD(parg16->hFindFile);
  2023. FREEARGPTR(parg16);
  2024. // this also closes the real search handle via FindClose
  2025. return ((ULONG)demWOWLFNCloseSearchHandle((USHORT)DosHandle));
  2026. }