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.

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