Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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