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.

1333 lines
35 KiB

  1. /* demfile.c - SVC handlers for calls where file name is specified.
  2. *
  3. * demOpen
  4. * demCreate
  5. * demUnlink
  6. * demChMod
  7. * demRename
  8. *
  9. * Modification History:
  10. *
  11. * Sudeepb 02-Apr-1991 Created
  12. *
  13. */
  14. #include "dem.h"
  15. #include "demmsg.h"
  16. #include <softpc.h>
  17. #include <winbase.h>
  18. #include <vrnmpipe.h>
  19. #include <nt_vdd.h>
  20. extern PDOSSF pSFTHead;
  21. BOOL (*VrInitialized)(VOID); // POINTER TO FUNCTION
  22. extern BOOL LoadVdmRedir(VOID);
  23. extern BOOL IsVdmRedirLoaded(VOID);
  24. BOOL
  25. IsNamedPipeName(
  26. IN LPSTR Name
  27. );
  28. BOOL
  29. IsNamedPipeName(
  30. IN LPSTR Name
  31. )
  32. /*++
  33. Routine Description:
  34. Lifted from VDMREDIR.DLL - we don't want to load the entire DLL if we
  35. need to check for a named pipe
  36. Checks if a string designates a named pipe. As criteria for the decision
  37. we use:
  38. \\computername\PIPE\...
  39. DOS (client-side) can only open a named pipe which is created at a server
  40. and must therefore be prefixed by a computername
  41. Arguments:
  42. Name - to check for (Dos) named pipe syntax
  43. Return Value:
  44. BOOL
  45. TRUE - Name refers to (local or remote) named pipe
  46. FALSE - Name doesn't look like name of pipe
  47. --*/
  48. {
  49. int CharCount;
  50. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  51. ++Name;
  52. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  53. ++Name;
  54. CharCount = 0;
  55. while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) {
  56. ++Name;
  57. ++CharCount;
  58. }
  59. if (!CharCount || !*Name) {
  60. //
  61. // Name is \\ or \\\ or just \\name which I don't understand,
  62. // so its not a named pipe - fail it
  63. //
  64. return FALSE;
  65. }
  66. //
  67. // bump name past next path separator. Note that we don't have to
  68. // check CharCount for max. length of a computername, because this
  69. // function is called only after the (presumed) named pipe has been
  70. // successfully opened, therefore we know that the name has been
  71. // validated
  72. //
  73. ++Name;
  74. } else {
  75. return FALSE;
  76. }
  77. //
  78. // We are at <something> (after \ or \\<name>\). Check if <something>
  79. // is [Pp][Ii][Pp][Ee][\\/]
  80. //
  81. if (!_strnicmp(Name, "PIPE", 4)) {
  82. Name += 4;
  83. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  84. return TRUE;
  85. }
  86. }
  87. }
  88. return FALSE;
  89. }
  90. /* demOpen - Open a file
  91. *
  92. *
  93. * Entry - Client (DS:SI) Full path of File
  94. * Client (BL) Open Mode
  95. * Client (ES:DI) Address of extended attributes buffer
  96. * Client (AL) 0 - No EA's ; 1 - EA's specified
  97. *
  98. * Exit
  99. * SUCCESS
  100. * Client (CY) = 0
  101. * Client (AX) = Assigned Open Handle (high word)
  102. * Client (BP) = Assigned Open Handle (low word)
  103. * Client (DX) = 1 if pipe was opened
  104. * Client (BX) = High word of the file size
  105. * Client (CX) = low word of the file size
  106. *
  107. *
  108. * FAILURE
  109. * CY = 1
  110. * AX = system status code
  111. * HARD ERROR
  112. * CY = 1
  113. * AX = 0FFFFh
  114. *
  115. *
  116. * Notes : Extended Attributes is not yet taken care of.
  117. */
  118. VOID demOpen (VOID)
  119. {
  120. HANDLE hFile;
  121. LPSTR lpFileName;
  122. UCHAR uchMode,uchAccess;
  123. DWORD dwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
  124. DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  125. BOOL ItsANamedPipe = FALSE;
  126. BOOL IsFirst;
  127. LPSTR dupFileName;
  128. DWORD dwFileSize,dwSizeHigh;
  129. SECURITY_ATTRIBUTES sa;
  130. if (getAL()){
  131. demPrintMsg (MSG_EAS);
  132. return;
  133. }
  134. lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI());
  135. #if DBG
  136. if(fShowSVCMsg & DEMFILIO){
  137. sprintf(demDebugBuffer,"demfile: Opening File <%s>\n",lpFileName);
  138. OutputDebugStringOem(demDebugBuffer);
  139. }
  140. #endif
  141. //
  142. // the DOS filename must be 'canonicalized': forward slashes (/) must be
  143. // converted to back slashes (\) and the filename should be upper-cased
  144. // using the current code page info
  145. //
  146. //
  147. // BUBUG: Kanji? (/other DBCS)
  148. //
  149. if (strchr(lpFileName, '/')) {
  150. char ch= *lpFileName;
  151. lpFileName = _strdup(lpFileName);
  152. if (lpFileName == NULL) {
  153. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  154. demClientError(INVALID_HANDLE_VALUE, ch);
  155. return;
  156. }
  157. for (dupFileName = lpFileName; *dupFileName; ++dupFileName) {
  158. if (*dupFileName == '/') {
  159. *dupFileName = '\\';
  160. }
  161. }
  162. dupFileName = lpFileName;
  163. } else {
  164. dupFileName = NULL;
  165. }
  166. uchMode = getBL();
  167. uchAccess = uchMode & (UCHAR)ACCESS_MASK;
  168. if (uchAccess == OPEN_FOR_READ)
  169. dwDesiredAccess = GENERIC_READ;
  170. else if (uchAccess == OPEN_FOR_WRITE)
  171. dwDesiredAccess = GENERIC_WRITE;
  172. uchMode = uchMode & (UCHAR)SHARING_MASK;
  173. switch (uchMode) {
  174. case SHARING_DENY_BOTH:
  175. dwShareMode = 0;
  176. break;
  177. case SHARING_DENY_WRITE:
  178. dwShareMode = FILE_SHARE_READ;
  179. break;
  180. case SHARING_DENY_READ:
  181. dwShareMode = FILE_SHARE_WRITE;
  182. break;
  183. }
  184. //
  185. // slightly new scheme - the redir isn't automatically loaded anymore. We
  186. // may perform a named pipe operation before VDMREDIR is loaded. So now we
  187. // load VDMREDIR.DLL if the filespec designates a named pipe
  188. //
  189. if (IsNamedPipeName(lpFileName)) {
  190. if (!LoadVdmRedir()) {
  191. goto errorReturn;
  192. }
  193. ItsANamedPipe = TRUE;
  194. //
  195. // convert \\<this_computer>\PIPE\foo\bar\etc to \\.\PIPE\...
  196. // if we already allocated a buffer for the slash conversion use
  197. // that else this call will allocate another buffer (we don't
  198. // want to write over DOS memory)
  199. //
  200. lpFileName = VrConvertLocalNtPipeName(dupFileName, lpFileName);
  201. if (!lpFileName) {
  202. goto errorReturn;
  203. }
  204. }
  205. //
  206. // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED
  207. // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe
  208. // and the only way to accomplish that is to open the named pipe handle in
  209. // overlapped I/O mode now
  210. //
  211. // sudeepb 26-Apr-1993 We are retrying opening the file in case
  212. // of failure without GENERIC_WRITE because of the incompatibility
  213. // of DOS and NT CD ROM driver. DOS CDROM driver ignores the write
  214. // bit which we have to fakeout in this way.
  215. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  216. sa.lpSecurityDescriptor = NULL;
  217. sa.bInheritHandle = TRUE;
  218. IsFirst = TRUE;
  219. while (TRUE) {
  220. if ((hFile = CreateFileOem(lpFileName,
  221. dwDesiredAccess,
  222. dwShareMode | FILE_SHARE_DELETE,
  223. &sa,
  224. OPEN_EXISTING,
  225. ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0,
  226. NULL)) == (HANDLE)-1){
  227. if (IsFirst && dwDesiredAccess & GENERIC_WRITE &&
  228. IsCdRomFile(lpFileName)) {
  229. dwDesiredAccess &= ~GENERIC_WRITE;
  230. IsFirst = FALSE;
  231. continue;
  232. }
  233. errorReturn:
  234. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  235. if (dupFileName) {
  236. free(dupFileName);
  237. } else if (ItsANamedPipe && lpFileName) {
  238. LocalFree(lpFileName);
  239. }
  240. return;
  241. }
  242. else
  243. break;
  244. }
  245. //
  246. // we have to keep some info around when we open a named pipe
  247. //
  248. if (ItsANamedPipe) {
  249. VrAddOpenNamedPipeInfo(hFile, lpFileName);
  250. setDX(1);
  251. }
  252. else {
  253. if(((dwFileSize=GetFileSize(hFile,&dwSizeHigh)) == (DWORD)-1) ||
  254. dwSizeHigh) {
  255. CloseHandle (hFile);
  256. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  257. return;
  258. }
  259. setCX ((USHORT)dwFileSize);
  260. setBX ((USHORT)(dwFileSize >> 16 ));
  261. setDX(0);
  262. }
  263. setBP((USHORT)hFile);
  264. setAX((USHORT)((ULONG)hFile >> 16));
  265. setCF(0);
  266. if (dupFileName) {
  267. free(dupFileName);
  268. } else if (ItsANamedPipe) {
  269. LocalFree(lpFileName);
  270. }
  271. return;
  272. }
  273. #define DEM_CREATE 0
  274. #define DEM_CREATE_NEW 1
  275. /* demCreate - Create a file
  276. *
  277. *
  278. * Entry - Client (DS:SI) Full path of File
  279. * Client (CX) Attributes
  280. * 00 - Normal File
  281. * 01 - Read-only file
  282. * 02 - Hidden File
  283. * 04 - System file
  284. *
  285. * Exit
  286. * SUCCESS
  287. * Client (CY) = 0
  288. * Client (AX) = Assigned Open Handle (high word)
  289. * VSF(BP) = Assigned Open Handle (low word)
  290. *
  291. * FAILURE
  292. * CY = 1
  293. * AX = error code
  294. * HARD ERROR
  295. * CY = 1
  296. * AX = 0FFFFh
  297. *
  298. */
  299. VOID demCreate (VOID)
  300. {
  301. demCreateCommon (DEM_CREATE);
  302. return;
  303. }
  304. /* demCreateNew - Create a New file
  305. *
  306. *
  307. * Entry - Client (DS:SI) Full path of File
  308. * Client (CX) Attributes
  309. * 00 - Normal File
  310. * 01 - Read-only file
  311. * 02 - Hidden File
  312. * 04 - System file
  313. *
  314. * Exit
  315. * SUCCESS
  316. * Client (CY) = 0
  317. * Client (AX) = Assigned Open Handle (high word)
  318. * VSF(BP) = Assigned Open Handle (low word)
  319. *
  320. * FAILURE
  321. * CY = 1
  322. * AX = error code
  323. * HARD ERROR
  324. * CY = 1
  325. * AX = 0FFFFh
  326. *
  327. */
  328. VOID demCreateNew (VOID)
  329. {
  330. demCreateCommon (DEM_CREATE_NEW);
  331. return;
  332. }
  333. /* demFileDelete
  334. *
  335. * EXPORTED FUNCTION
  336. *
  337. * ENTRY:
  338. * lpFile -> OEM file name to be deleted
  339. *
  340. * EXIT:
  341. * returns 0 on success, DOS error code on failure
  342. *
  343. * NOTES:
  344. * Some apps keep a file open and delete it. Then rename another file to
  345. * the old name. On NT since the orignal object is still open the second
  346. * rename fails.
  347. * To get around this problem we rename the file before deleteing it
  348. * this allows the second rename to work
  349. *
  350. * But since renaming the file is known to be expensive over the net, we try
  351. * first to open the file exclusively to see if there is really any reason to
  352. * rename it. If we can get a handle to it, then we should be able to skip the
  353. * rename and just delete it. If we can't get a handle to it, then we try
  354. * the rename trick. This should cut down our overhead for the normal case.
  355. */
  356. DWORD demFileDelete (LPSTR lpFile)
  357. {
  358. CHAR vdmtemp[MAX_PATH];
  359. CHAR tmpfile[MAX_PATH];
  360. PSZ pFileName;
  361. HANDLE hFile;
  362. //
  363. // First, try to access the file exclusively
  364. //
  365. hFile = CreateFileOem(lpFile,
  366. DELETE,
  367. 0,
  368. NULL,
  369. OPEN_EXISTING,
  370. FILE_ATTRIBUTE_NORMAL,
  371. NULL);
  372. if (hFile != INVALID_HANDLE_VALUE) {
  373. NTSTATUS status;
  374. IO_STATUS_BLOCK ioStatusBlock;
  375. FILE_DISPOSITION_INFORMATION fileDispositionInformation;
  376. // Member name "DeleteFile" conflicts with win32 definition (it
  377. // becomes "DeleteFileA".
  378. #undef DeleteFile
  379. fileDispositionInformation.DeleteFile = TRUE;
  380. //
  381. // We got a handle to it, so there can't be any open
  382. // handles to it. Set the disposition to DELETE.
  383. //
  384. status = NtSetInformationFile(hFile,
  385. &ioStatusBlock,
  386. &fileDispositionInformation,
  387. sizeof(FILE_DISPOSITION_INFORMATION),
  388. FileDispositionInformation);
  389. CloseHandle(hFile);
  390. if NT_SUCCESS(status) {
  391. SetLastError(NO_ERROR);
  392. } else {
  393. SetLastError(ERROR_ACCESS_DENIED);
  394. }
  395. }
  396. //
  397. // Check to see if the delete went OK. If not, try renaming
  398. // the file.
  399. //
  400. switch (GetLastError()) {
  401. case NO_ERROR:
  402. case ERROR_FILE_NOT_FOUND:
  403. case ERROR_PATH_NOT_FOUND:
  404. // Can't find it, forget about it
  405. break;
  406. case ERROR_SHARING_VIOLATION:
  407. case ERROR_ACCESS_DENIED:
  408. //
  409. // The file didn't really go away because there appears to
  410. // be an open handle to the file.
  411. //
  412. if (GetFullPathNameOem(lpFile,MAX_PATH,vdmtemp,&pFileName)) {
  413. if ( pFileName )
  414. *(pFileName) = 0;
  415. if (GetTempFileNameOem(vdmtemp,"VDM",0,tmpfile)) {
  416. if (MoveFileExOem(lpFile,tmpfile, MOVEFILE_REPLACE_EXISTING)) {
  417. if(DeleteFileOem(tmpfile)) {
  418. SetLastError(NO_ERROR);
  419. } else {
  420. MoveFileOem(tmpfile,lpFile);
  421. SetLastError(ERROR_ACCESS_DENIED);
  422. }
  423. }
  424. }
  425. }
  426. break;
  427. default:
  428. //
  429. // We couldn't open or delete the file, and it's not because of a
  430. // sharing violation. Just try a last ditch effort of a
  431. // plain old delete, and see if it works.
  432. //
  433. if(DeleteFileOem(lpFile)) {
  434. SetLastError(NO_ERROR);
  435. }
  436. }
  437. //
  438. // Map win32 error code to DOS
  439. //
  440. switch(GetLastError()) {
  441. case NO_ERROR:
  442. case ERROR_FILE_NOT_FOUND:
  443. case ERROR_PATH_NOT_FOUND:
  444. case ERROR_ACCESS_DENIED:
  445. break;
  446. default:
  447. // make sure demClientError can see retval
  448. SetLastError(ERROR_ACCESS_DENIED);
  449. }
  450. return GetLastError();
  451. }
  452. /* demDelete - Delete a file
  453. *
  454. *
  455. * Entry - Client (DS:DX) Full path of File
  456. *
  457. * Exit
  458. * SUCCESS
  459. * Client (CY) = 0
  460. *
  461. * FAILURE
  462. * CY = 1
  463. * AX = system status code
  464. * HARD ERROR
  465. * CY = 1
  466. * AX = 0FFFFh
  467. *
  468. */
  469. VOID demDelete (VOID)
  470. {
  471. LPSTR lpFileName;
  472. DWORD retval;
  473. lpFileName = (LPSTR) GetVDMAddr (getDS(),getDX());
  474. #if DBG
  475. if(fShowSVCMsg & DEMFILIO){
  476. sprintf(demDebugBuffer,"demfile: Deleting File<%s>\n",lpFileName);
  477. OutputDebugStringOem(demDebugBuffer);
  478. }
  479. #endif
  480. if (retval = demFileDelete(lpFileName)){
  481. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  482. return;
  483. }
  484. setCF(0);
  485. return;
  486. }
  487. /* demChMod - Change the file modes
  488. *
  489. * Entry - Client (DS:DX) Full path of File
  490. * Client (AL) = 0 Get File Modes 1 Set File Modes
  491. * Client (CL) new modes
  492. *
  493. * Exit
  494. * SUCCESS
  495. * Client (CY) = 0
  496. * Client (CL) = file attributes in get case.
  497. *
  498. * FAILURE
  499. * Client (CY) = 1
  500. * Client (AX) = Error Code
  501. * HARD ERROR
  502. * CY = 1
  503. * AX = 0FFFFh
  504. *
  505. * Compatibility Notes:
  506. *
  507. * ATTR_VOLUME_ID,ATTR_DEVICE and ATTR_DIRECTORY are not supported
  508. * by WIN32 call. Although these are unpublished for DOS world also
  509. * but still a compatibility requirement.
  510. */
  511. VOID demChMod (VOID)
  512. {
  513. LPSTR lpFileName;
  514. DWORD dwAttr;
  515. lpFileName = (LPSTR) GetVDMAddr (getDS(),getDX());
  516. #if DBG
  517. if(fShowSVCMsg & DEMFILIO){
  518. sprintf(demDebugBuffer,"demfile: ChMod File <%s>\n",lpFileName);
  519. OutputDebugStringOem(demDebugBuffer);
  520. }
  521. #endif
  522. if(getAL() == 0){
  523. if ((dwAttr = GetFileAttributesOem(lpFileName)) == -1)
  524. goto dcerr;
  525. if (dwAttr == FILE_ATTRIBUTE_NORMAL) {
  526. dwAttr = 0;
  527. }
  528. else {
  529. dwAttr &= DOS_ATTR_MASK;
  530. }
  531. // SudeepB - 28-Jul-1997
  532. //
  533. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  534. // for directories while WinNT returns
  535. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  536. // Some VB controls that app setups use, depend on getting
  537. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  538. // An example of this is Cliffs StudyWare series.
  539. if (dwAttr == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY)) {
  540. if(IsCdRomFile(lpFileName))
  541. dwAttr = FILE_ATTRIBUTE_DIRECTORY;
  542. }
  543. setCX((USHORT)dwAttr);
  544. setCF(0);
  545. return;
  546. }
  547. if((dwAttr = getCX()) == 0)
  548. dwAttr = FILE_ATTRIBUTE_NORMAL;
  549. dwAttr &= DOS_ATTR_MASK;
  550. if (!SetFileAttributesOem(lpFileName,dwAttr))
  551. goto dcerr;
  552. setCF(0);
  553. return;
  554. dcerr:
  555. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  556. return;
  557. }
  558. /* demRename - Rename a file
  559. *
  560. * Entry - Client (DS:DX) Source File
  561. * Client (ES:DI) Destination File
  562. *
  563. * Exit
  564. * SUCCESS
  565. * Client (CY) = 0
  566. *
  567. * FAILURE
  568. * Client (CY) = 1
  569. * Client (AX) = Error Code
  570. *
  571. */
  572. VOID demRename (VOID)
  573. {
  574. LPSTR lpSrc,lpDst;
  575. lpSrc = (LPSTR) GetVDMAddr (getDS(),getDX());
  576. lpDst = (LPSTR) GetVDMAddr (getES(),getDI());
  577. #if DBG
  578. if(fShowSVCMsg & DEMFILIO){
  579. sprintf(demDebugBuffer,"demfile: Rename File <%s> to <%s>\n",lpSrc,lpDst);
  580. OutputDebugStringOem(demDebugBuffer);
  581. }
  582. #endif
  583. // DOS rename fails accross drives with 11h error code
  584. // This following check is OK even for UNC names and SUBST drives.
  585. // SUBST drives come to NTVDM as env variables for current directory
  586. // and we will treet them just like a network drive and full qualified
  587. // path will be sent from NTDOS.
  588. if(toupper(lpSrc[0]) != toupper(lpDst[0])) {
  589. setCF(1);
  590. setAX(0x11);
  591. return;
  592. }
  593. // Now check that SRC and DEST are not pointing to the same file.
  594. // if they do return error 5.
  595. if (!_stricmp (lpSrc, lpDst)) {
  596. setCF(1);
  597. setAX(0x5);
  598. return;
  599. }
  600. if(MoveFileOem(lpSrc,lpDst) == FALSE){
  601. demClientError(INVALID_HANDLE_VALUE, *lpSrc);
  602. return;
  603. }
  604. setCF(0);
  605. return;
  606. }
  607. /* demCreateCommon - Create a file or Craete a new file
  608. *
  609. *
  610. * Entry - flCreateType - DEM_CREATE_NEW create new
  611. * DEM_CREATE create
  612. *
  613. * Exit
  614. * SUCCESS
  615. * Client (CY) = 0
  616. * Client (AX) = Assigned Open Handle (high word)
  617. * Client (BP) = Assigned Open Handle (low word)
  618. *
  619. * FAILURE
  620. * CY = 1
  621. * AX = error code
  622. * HARD ERROR
  623. * CY = 1
  624. * AX = 0FFFFh
  625. *
  626. */
  627. VOID demCreateCommon (flCreateType)
  628. ULONG flCreateType;
  629. {
  630. HANDLE hFile;
  631. LPSTR lpFileName;
  632. LPSTR lpDot;
  633. DWORD dwAttr;
  634. DWORD dwFileSize,dwSizeHigh;
  635. USHORT uErr;
  636. DWORD dwDesiredAccess;
  637. SECURITY_ATTRIBUTES sa;
  638. CHAR cFOTName[MAX_PATH];
  639. BOOL ttfOnce,IsFirst;
  640. DWORD dwLastError;
  641. lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI());
  642. dwAttr = (DWORD)getCX();
  643. // Here is some code stolen from DOS_Create (create.asm) for handling the
  644. // attributes
  645. if (flCreateType == DEM_CREATE || flCreateType == DEM_CREATE_NEW)
  646. dwAttr &= 0xff;
  647. if (dwAttr & ~(ATTR_ALL | ATTR_IGNORE | ATTR_VOLUME_ID)) {
  648. setCF(1);
  649. setAX(5); //Attribute problem
  650. return;
  651. }
  652. /* Special case for set volume label (INT 21 Func 3CH, Attr = 8H */
  653. if((flCreateType == DEM_CREATE || flCreateType == DEM_CREATE_NEW) && (dwAttr == ATTR_VOLUME_ID)) {
  654. if((uErr = demCreateLabel(lpFileName[DRIVEBYTE],
  655. lpFileName+LABELOFF))) {
  656. setCF(1);
  657. setAX(uErr);
  658. return;
  659. }
  660. setAX(0);
  661. setBP(0); // in this case handle = 0 and if we will
  662. setCF(0); // close this handle CF will be 0(!)
  663. return;
  664. }
  665. if ((dwAttr & 0xff) == 0) {
  666. dwAttr = FILE_ATTRIBUTE_NORMAL;
  667. } else {
  668. dwAttr &= DOS_ATTR_MASK;
  669. }
  670. #if DBG
  671. if(fShowSVCMsg & DEMFILIO){
  672. sprintf(demDebugBuffer,"demfile: Creating File <%s>\n",lpFileName);
  673. OutputDebugStringOem(demDebugBuffer);
  674. }
  675. #endif
  676. dwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
  677. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  678. sa.lpSecurityDescriptor = NULL;
  679. sa.bInheritHandle = TRUE;
  680. ttfOnce = TRUE;
  681. IsFirst = TRUE;
  682. while (TRUE) {
  683. if ((hFile = CreateFileOem(lpFileName,
  684. // create file with delete access and sharing mode
  685. // so that anybody can delete it without closing
  686. // the file handle returned from create file
  687. dwDesiredAccess,
  688. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  689. &sa,
  690. flCreateType == DEM_CREATE ? CREATE_ALWAYS : CREATE_NEW,
  691. dwAttr,
  692. NULL)) == (HANDLE)-1){
  693. if (IsFirst && dwDesiredAccess & GENERIC_WRITE &&
  694. IsCdRomFile(lpFileName)) {
  695. dwDesiredAccess &= ~GENERIC_WRITE;
  696. IsFirst = FALSE;
  697. continue;
  698. }
  699. // APP COMPATABILITY
  700. // Some WOW apps installing .TTF or .FON or Fonts fail to create
  701. // The file because the font is already open by GDI32 server.
  702. // The install/setup programs don't gracefully handle
  703. // this error, they bomb out of the install with retry or cancel
  704. // without offering the user a way to ignore the error (which
  705. // would be the right thing since the font already exists.
  706. // To work around this problem we do a RemoveFontResource here
  707. // which causes GDI32 to unmap the file, we then retry
  708. // the create. - mattfe june 93
  709. // If it is a TTF file then we need to remove the font resource
  710. // for the .FOT file of the same name
  711. if (ttfOnce) {
  712. // Look for the file extension
  713. lpDot = strrchr(lpFileName,'.');
  714. if (lpDot) {
  715. if ( (!_strcmpi(lpDot,".TTF")) ||
  716. (!_strcmpi(lpDot,".FON")) ||
  717. (!_strcmpi(lpDot,".FOT")) ) {
  718. if ( RemoveFontResourceOem(lpFileName) ) {
  719. PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
  720. ttfOnce = FALSE;
  721. continue;
  722. }
  723. // We failed to remove the .TTF file probably because
  724. // the .FOT file was loaded, so try to remove it
  725. if (!_strcmpi(lpDot,".TTF")) {
  726. RtlZeroMemory(cFOTName,sizeof(cFOTName));
  727. RtlCopyMemory(cFOTName,lpFileName,(ULONG)lpDot-(ULONG)lpFileName);
  728. strcat(cFOTName,".FOT");
  729. if ( RemoveFontResourceOem(cFOTName) ) {
  730. PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
  731. ttfOnce = FALSE;
  732. continue;
  733. }
  734. }
  735. }
  736. }
  737. }
  738. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  739. return;
  740. }
  741. else
  742. break;
  743. }
  744. if((dwFileSize=GetFileSize(hFile,&dwSizeHigh) == -1) || dwSizeHigh) {
  745. CloseHandle (hFile);
  746. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  747. return;
  748. }
  749. setCX ((USHORT)dwFileSize);
  750. setBX ((USHORT)(dwFileSize >> 16 ));
  751. setBP((USHORT)hFile);
  752. setAX((USHORT)((ULONG)hFile >> 16));
  753. setCF(0);
  754. return;
  755. }
  756. BOOL IsCdRomFile (PSTR pszPath)
  757. {
  758. UCHAR pszRootDir[MAX_PATH];
  759. UCHAR file_system[MAX_PATH];
  760. int i, j;
  761. // The given path is either a network path or has D: at the start.
  762. if (!pszPath[0]) {
  763. return FALSE;
  764. }
  765. if (pszPath[1] == ':') {
  766. pszRootDir[0] = pszPath[0];
  767. pszRootDir[1] = ':';
  768. pszRootDir[2] = '\\';
  769. pszRootDir[3] = 0;
  770. } else if (IS_ASCII_PATH_SEPARATOR(pszPath[0]) &&
  771. IS_ASCII_PATH_SEPARATOR(pszPath[1])) {
  772. j = 0;
  773. for (i = 2; pszPath[i]; i++) {
  774. if (IS_ASCII_PATH_SEPARATOR(pszPath[i])) {
  775. if (++j == 2) {
  776. break;
  777. }
  778. }
  779. }
  780. memcpy(pszRootDir, pszPath, i);
  781. pszRootDir[i] = '\\';
  782. pszRootDir[i+1] = 0;
  783. } else {
  784. return FALSE;
  785. }
  786. if (GetVolumeInformationOem(pszRootDir, NULL, 0, NULL, NULL, NULL,
  787. file_system, MAX_PATH) &&
  788. !_stricmp(file_system, "CDFS")) {
  789. return TRUE;
  790. }
  791. return FALSE;
  792. }
  793. /* demCheckPath - Check path (for device only)
  794. *
  795. *
  796. * Entry - Client (DS:SI) Full path (with last '\')
  797. *
  798. * Exit
  799. * SUCCESS
  800. * Client (CF) = 0
  801. *
  802. * FAILURE
  803. * CF = 1
  804. */
  805. VOID demCheckPath (VOID)
  806. {
  807. HANDLE hFile;
  808. LPSTR lpFileName;
  809. CHAR cDRV;
  810. CHAR szFileName[MAX_PATH];
  811. lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI());
  812. cDRV = getDL()+'A'-1;
  813. setDX(0);
  814. // If we have \dev dir then return OK, DOS always has this directory for
  815. // devices.
  816. if(!lstrcmpi(lpFileName, "\\DEV\\")) {
  817. setCF(0);
  818. return;
  819. }
  820. sprintf(szFileName, "%c:%sNUL", cDRV, lpFileName);
  821. #if DBG
  822. if(fShowSVCMsg & DEMFILIO){
  823. sprintf(demDebugBuffer,"demfile: Check Pathe <%s>\n",lpFileName);
  824. OutputDebugStringOem(demDebugBuffer);
  825. }
  826. #endif
  827. // If path exists then we always can open NUL file in this directory,
  828. // if path doesn't exists then CreateFile returns INVALID_HANDLE_VALUE
  829. //
  830. if ((hFile = CreateFileOem((LPSTR) szFileName,
  831. GENERIC_WRITE,
  832. FILE_SHARE_READ | FILE_SHARE_WRITE,
  833. NULL,
  834. CREATE_ALWAYS,
  835. FILE_ATTRIBUTE_NORMAL,
  836. NULL)) == INVALID_HANDLE_VALUE) {
  837. demClientError(INVALID_HANDLE_VALUE, *lpFileName);
  838. setCF(1);
  839. return;
  840. }
  841. CloseHandle (hFile);
  842. setCF(0);
  843. return;
  844. }
  845. PDOSSFT GetFreeSftEntry(PDOSSF pSfHead, PWORD usSFN)
  846. {
  847. WORD i;
  848. PDOSSFT pSft;
  849. DWORD ulSFLink;
  850. *usSFN = 0;
  851. for (;;) {
  852. pSft = (PDOSSFT) &(pSfHead->SFTable);
  853. for (i = 0; i < pSfHead->SFCount; i++) {
  854. if (pSft[i].SFT_Ref_Count == 0) {
  855. *usSFN += i;
  856. return (pSft + i);
  857. }
  858. }
  859. *usSFN += pSfHead->SFCount;
  860. ulSFLink = pSfHead->SFLink;
  861. if (LOWORD(ulSFLink) == 0xFFFF) {
  862. break;
  863. }
  864. pSfHead = (PDOSSF) Sim32GetVDMPointer (ulSFLink, 0, 0);
  865. }
  866. return NULL;
  867. }
  868. /** VDDAllocateDosHandle - Allocates an unused DOS file handle.
  869. *
  870. * ENTRY -
  871. * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task
  872. * OUT ppSFT - OPTIONAL: Returns a 32-bit flat pointer to the SFT
  873. * associated with the allocated file handle.
  874. * OUT ppJFT - OPTIONAL: Returns a 32-bit flat pointer to the JFT
  875. * associated with the given PDB.
  876. *
  877. *
  878. * EXIT
  879. * SUCCESS - Returns the value of the DOS file handle and associated
  880. * pointers.
  881. * FAILURE - Returns a negative value. The absolute value of this number
  882. * is the DOS error code.
  883. *
  884. * Comments:
  885. * This routine searches for an unused DOS file handle and SFT and "opens"
  886. * a file. After the successful completion of this call, the returned file
  887. * handle and the corresponding SFT will be reserved for the caller's use, and
  888. * will be unavailable to other callers trying to issue DOS Open or Create api
  889. * calls. It is the caller's responsibility to release this file handle (with
  890. * a call to VDDReleaseDosHandle).
  891. *
  892. * If the pPDB pointer is not supplied (e.g., is NULL), then the current
  893. * PDB as reported by DOS will be used.
  894. *
  895. * Although the ppSFT parameter is technically optional, it is a required
  896. * parameter of the VDDAssociateNtHandle call. This was done to avoid a
  897. * second handle lookup in the Associate call.
  898. *
  899. */
  900. SHORT VDDAllocateDosHandle (pPDB,ppSFT,ppJFT)
  901. ULONG pPDB;
  902. PDOSSFT* ppSFT;
  903. PBYTE* ppJFT;
  904. {
  905. PDOSPDB pPDBFlat;
  906. PBYTE pJFT;
  907. PDOSSFT pSFT;
  908. USHORT usSFN;
  909. WORD JFTLength;
  910. SHORT hDosHandle;
  911. if (!pPDB) {
  912. pPDB = (ULONG) (*pusCurrentPDB) << 16;
  913. }
  914. //
  915. // Get the JFT.
  916. //
  917. pPDBFlat = (PDOSPDB) Sim32GetVDMPointer (pPDB, 0, 0);
  918. if ( NULL == pPDBFlat ) {
  919. return (- ERROR_INVALID_HANDLE);
  920. }
  921. pJFT = (PBYTE) Sim32GetVDMPointer (pPDBFlat->PDB_JFN_Pointer, 0, 0);
  922. if ( NULL == pJFT ) {
  923. return (- ERROR_INVALID_HANDLE);
  924. }
  925. //
  926. // Check to see if there's a free entry in the JFT.
  927. //
  928. JFTLength = pPDBFlat->PDB_JFN_Length;
  929. for (hDosHandle = 0; hDosHandle < JFTLength; hDosHandle++) {
  930. if (pJFT[hDosHandle] == 0xFF) {
  931. break;
  932. }
  933. }
  934. // If no room in the JFT then return ERROR_TOO_MANY_OPEN_FILES
  935. if (hDosHandle == JFTLength) {
  936. return (- ERROR_TOO_MANY_OPEN_FILES);
  937. }
  938. //
  939. // Check the SF for a free SFT.
  940. //
  941. if (!(pSFT = GetFreeSftEntry(pSFTHead, &usSFN))) {
  942. return (- ERROR_TOO_MANY_OPEN_FILES);
  943. }
  944. pJFT[hDosHandle] = (BYTE)usSFN;
  945. RtlZeroMemory((PVOID)pSFT, sizeof(DOSSFT));
  946. pSFT->SFT_Ref_Count = 1;
  947. if (ppSFT) {
  948. *ppSFT = (pSFT);
  949. }
  950. if (ppJFT) {
  951. *ppJFT = pJFT;
  952. }
  953. return(hDosHandle);
  954. }
  955. /** VDDAssociateNtHandle - Associates the passed NT handle and access flags
  956. * the given DOS handle.
  957. *
  958. * ENTRY -
  959. * IN pSFT - flat address of the SFT to be updated
  960. * IN hFile32 - NT handle to be stored
  961. * IN wAccess - access flags to set in the SFT
  962. *
  963. * EXIT -
  964. * This routine has no return value.
  965. *
  966. * Comments:
  967. * This routine takes the passed NT handle value and stores it in a DOS SFT
  968. * so that it can later be retrieved by the VDDRetrieveNtHandle api. The
  969. * pointer to the SFT is returned by the VDDAllocateDosHandle api.
  970. *
  971. * The format of the third parameter is the same as the file access flags
  972. * defined for DOS Open File with Handle call (Int 21h, func 3dh), documented
  973. * in Microsoft MS-DOS Programmer's Reference. Only the low order byte of
  974. * this parameter is used, the upper byte is reserved and must be zero.
  975. * The value of this parameter is placed into the passed SFT. This is provided
  976. * to allow the caller to define the access rights for the corresponding
  977. * DOS file handle.
  978. *
  979. */
  980. VOID VDDAssociateNtHandle (pSFT,hFile,wAccess)
  981. PDOSSFT pSFT;
  982. HANDLE hFile;
  983. WORD wAccess;
  984. {
  985. pSFT->SFT_Mode = wAccess&0x7f; // take out no_inherit bit
  986. pSFT->SFT_Attr = 0; // Not used.
  987. pSFT->SFT_Flags = (wAccess&0x80) ? 0x1000 : 0; // copy no_inherit bit.
  988. pSFT->SFT_Devptr = (ULONG) -1;
  989. pSFT->SFT_NTHandle = (ULONG) hFile;
  990. }
  991. /** VDDReleaseDosHandle - Release the given DOS file handle.
  992. *
  993. * ENTRY -
  994. * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task
  995. * IN hFile - DOS handle (in low byte)
  996. *
  997. * EXIT -
  998. * TRUE - the file handle was released
  999. * FALSE - The file handle was not valid or open
  1000. *
  1001. * Comments:
  1002. * This routine updates the DOS file system data areas to free the passed
  1003. * file handle. No effort is made to determine if this handle was previously
  1004. * opened by the VDDAllocateDosHandle call. It is the responsibility of the
  1005. * caller to insure that the given file handle in the specified PDB should
  1006. * be closed.
  1007. *
  1008. * If the pPDB pointer is not supplied (e.g., is NULL), then the current
  1009. * PDB as reported by DOS will be used.
  1010. *
  1011. */
  1012. BOOL VDDReleaseDosHandle (pPDB,hFile)
  1013. ULONG pPDB;
  1014. SHORT hFile;
  1015. {
  1016. PBYTE pJFT;
  1017. PDOSSFT pSFT;
  1018. HANDLE ntHandle;
  1019. if (!pPDB) {
  1020. pPDB = (ULONG) (*pusCurrentPDB) << 16;
  1021. }
  1022. ntHandle = VDDRetrieveNtHandle(pPDB,hFile,(PVOID *)&pSFT,&pJFT);
  1023. if (!ntHandle) {
  1024. return(FALSE);
  1025. }
  1026. pJFT[hFile] = 0xFF;
  1027. // Decrement reference count.
  1028. pSFT->SFT_Ref_Count--;
  1029. return(TRUE);
  1030. }
  1031. /** VDDRetrieveNtHandle - Given a DOS file handle get the associated
  1032. * NT handle.
  1033. *
  1034. * ENTRY -
  1035. * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task
  1036. * IN hFile - DOS handle (in low byte)
  1037. * OUT ppSFT - OPTIONAL: Returns a 32-bit flat pointer to the SFT
  1038. * associated with the given file.
  1039. * OUT ppJFT - OPTIONAL: Returns a 32-bit flat pointer to the JFT
  1040. * associated with the given PDB.
  1041. *
  1042. *
  1043. * EXIT -
  1044. * SUCCESS - returns 4byte NT handle
  1045. * FAILURE - returns 0
  1046. *
  1047. * Comments:
  1048. * The value returned by this function will be the NT handle passed in a
  1049. * previous VDDAssociateNtHandle call. If no previous call is made to the
  1050. * the Associate api, then the value returned by this function is undefined.
  1051. *
  1052. * If the pPDB pointer is not supplied (e.g., is NULL), then the current
  1053. * PDB as reported by DOS will be used.
  1054. *
  1055. * Although the ppSFT parameter is technically optional, it is a required
  1056. * parameter of the VDDAssociateNtHandle call. This was done to avoid a
  1057. * second handle lookup in the Associate call.
  1058. *
  1059. * The third and fourth parameters are provided to provide the caller the
  1060. * ability to update the DOS system data areas directly. This may be useful
  1061. * for performance reasons, or necessary depending on the application. In
  1062. * general, care must be taken when using these pointers to avoid causing
  1063. * system integrity problems.
  1064. *
  1065. */
  1066. HANDLE VDDRetrieveNtHandle (pPDB,hFile,ppSFT,ppJFT)
  1067. ULONG pPDB;
  1068. SHORT hFile;
  1069. PDOSSFT* ppSFT;
  1070. PBYTE* ppJFT;
  1071. {
  1072. PDOSPDB pPDBFlat;
  1073. PDOSSF pSfFlat;
  1074. PDOSSFT pSftFlat;
  1075. PBYTE pJFT;
  1076. USHORT usSFN;
  1077. USHORT usSFTCount;
  1078. ULONG ulSFLink;
  1079. if (!pPDB) {
  1080. pPDB = (ULONG) (*pusCurrentPDB) << 16;
  1081. }
  1082. // Get flat pointer to PDB
  1083. pPDBFlat = (PDOSPDB) Sim32GetVDMPointer(pPDB, 0, 0);
  1084. // Check that handle is within JFT
  1085. if (hFile >= pPDBFlat->PDB_JFN_Length) {
  1086. return 0;
  1087. }
  1088. // Get the pointer to JFT
  1089. pJFT = (PBYTE) Sim32GetVDMPointer (pPDBFlat->PDB_JFN_Pointer, 0, 0);
  1090. // Get the SFN, remember -1 indicates unused JFT
  1091. usSFN = (USHORT) pJFT[hFile];
  1092. if (usSFN == 0xff) {
  1093. return 0;
  1094. }
  1095. // Get flat pointer to SF
  1096. pSfFlat = pSFTHead;
  1097. // Find the right SFT group
  1098. while (usSFN >= (usSFTCount = pSfFlat->SFCount)){
  1099. usSFN = usSFN - usSFTCount;
  1100. ulSFLink = pSfFlat->SFLink;
  1101. if (LOWORD(ulSFLink) == 0xffff)
  1102. return 0;
  1103. pSfFlat = (PDOSSF) Sim32GetVDMPointer (ulSFLink, 0, 0);
  1104. }
  1105. // Get the begining of SFT
  1106. pSftFlat = (PDOSSFT)&(pSfFlat->SFTable);
  1107. // Get the SFN, Finally
  1108. if(pSftFlat[usSFN].SFT_Ref_Count == 0) {
  1109. return 0;
  1110. }
  1111. if (ppSFT) {
  1112. *ppSFT = (pSftFlat + usSFN);
  1113. }
  1114. if (ppJFT) {
  1115. *ppJFT = pJFT;
  1116. }
  1117. return (HANDLE) pSftFlat[usSFN].SFT_NTHandle;
  1118. }