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.

3433 lines
102 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1992.
  5. //
  6. // File: filest32.cxx
  7. //
  8. // Contents: Win32 LStream implementation
  9. //
  10. // History: 12-May-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include <exphead.cxx>
  14. #pragma hdrstop
  15. #include <time.h>
  16. #include <marshl.hxx>
  17. #include <df32.hxx>
  18. #include <logfile.hxx>
  19. #include <dfdeb.hxx>
  20. #include <lock.hxx>
  21. #if WIN32 != 200
  22. #define USE_OVERLAPPED
  23. #endif
  24. DECLARE_INFOLEVEL(filest);
  25. HRESULT GetNtHandleSectorSize (HANDLE Handle, ULONG * pulSectorSize);
  26. HRESULT NtStatusToScode(NTSTATUS nts);
  27. #if DBG == 1
  28. //+--------------------------------------------------------------
  29. //
  30. // Member: CFileStream::PossibleDiskFull, private
  31. //
  32. // Synopsis: In debug builds it can simulate a disk full error
  33. //
  34. // Returns: STG_E_MEDIUMFULL when it wants to simulate an error.
  35. //
  36. // History: 25-Nov-96 BChapman Created
  37. //
  38. //---------------------------------------------------------------
  39. #ifdef LARGE_DOCFILE
  40. SCODE CFileStream::PossibleDiskFull(ULONGLONG ulOffset)
  41. #else
  42. SCODE CFileStream::PossibleDiskFull(ULONG iOffset)
  43. #endif
  44. {
  45. #ifdef LARGE_DOCFILE
  46. ULARGE_INTEGER ulCurrentSize;
  47. ulCurrentSize.LowPart = GetFileSize(_hFile, &ulCurrentSize.HighPart);
  48. if (ulOffset > ulCurrentSize.QuadPart)
  49. #else
  50. ULONG ulCurrentSize;
  51. ulCurrentSize = GetFileSize(_hFile, NULL);
  52. if ((iOffset) > ulCurrentSize)
  53. #endif
  54. {
  55. if (SimulateFailure(DBF_DISKFULL))
  56. {
  57. return STG_E_MEDIUMFULL;
  58. }
  59. }
  60. return S_OK;
  61. }
  62. void CFileStream::CheckSeekPointer(void)
  63. {
  64. #ifdef LARGE_DOCFILE
  65. LARGE_INTEGER ulChk;
  66. ulChk.QuadPart = 0;
  67. #else
  68. LONG lHighChk;
  69. ULONG ulLowChk;
  70. lHighChk = 0;
  71. #endif
  72. if (_hFile != INVALID_FH)
  73. {
  74. #ifdef LARGE_DOCFILE
  75. ulChk.LowPart = SetFilePointer(_hFile, 0, &ulChk.HighPart,FILE_CURRENT);
  76. if (ulChk.LowPart == MAX_ULONG && GetLastError() != NOERROR)
  77. #else
  78. ulLowChk = SetFilePointer(_hFile, 0, &lHighChk, FILE_CURRENT);
  79. if (ulLowChk == 0xFFFFFFFF)
  80. #endif
  81. {
  82. //An error of some sort occurred.
  83. filestDebug((DEB_ERROR, "SetFilePointer call failed with %x\n",
  84. GetLastError()));
  85. return;
  86. }
  87. if (_pgfst != NULL)
  88. {
  89. #ifdef LARGE_DOCFILE
  90. _pgfst->CheckSeekPointer(ulChk.QuadPart);
  91. #else
  92. _pgfst->CheckSeekPointer(ulLowChk);
  93. #endif
  94. }
  95. }
  96. }
  97. #endif // DBG == 1
  98. #if DBG == 1
  99. #ifdef LARGE_DOCFILE
  100. inline void CGlobalFileStream::CheckSeekPointer(ULONGLONG ulChk)
  101. {
  102. if(ulChk != _ulPos && MAX_ULONGLONG != _ulPos)
  103. {
  104. filestDebug((DEB_ERROR,"Seek pointer mismatch."
  105. " Cached = 0x%Lx, Real = 0x%Lx, Last Checked = 0x%Lx"
  106. " %ws\n",
  107. _ulPos,
  108. ulChk,
  109. _ulLastFilePos,
  110. GetName()));
  111. fsAssert(aMsg("Cached FilePointer incorrect!!\n"));
  112. }
  113. _ulLastFilePos = ulChk;
  114. }
  115. #else
  116. inline void CGlobalFileStream::CheckSeekPointer(DWORD ulLowChk)
  117. {
  118. if(ulLowChk != _ulLowPos && 0xFFFFFFFF != _ulLowPos)
  119. {
  120. filestDebug((DEB_ERROR,"Seek pointer mismatch."
  121. " Cached = 0x%06x, Real = 0x%06x, Last Checked = 0x%06x"
  122. " %ws\n",
  123. _ulLowPos,
  124. ulLowChk,
  125. _ulLastFilePos,
  126. GetName()));
  127. fsAssert(aMsg("Cached FilePointer incorrect!!\n"));
  128. }
  129. _ulLastFilePos = ulLowChk;
  130. }
  131. #endif // LARGE_DOCFILE
  132. #endif
  133. //+--------------------------------------------------------------
  134. //
  135. // Member: CFileStream::InitWorker, private
  136. //
  137. // Synopsis: Constructor
  138. //
  139. // Arguments: [pwcsPath] -- Path
  140. // [dwFSInit] -- Reason why we are initing.
  141. //
  142. // Returns: Appropriate status code
  143. //
  144. // History: 20-Feb-92 DrewB Created
  145. // 20-Feb-97 BChapman Rewrote.
  146. //
  147. // Notes: [pwcsPath] may be unsafe memory so we must be careful
  148. // not to propagate faults
  149. // The PathName will always be OLECHAR (WIDECHAR) so most of the
  150. // code is Unicode using WideWrap to talk to Win95. Except
  151. // when creating a TempFile name. To avoid lots of unnecessary
  152. // converting we work in TCHAR, and convert only the result.
  153. //---------------------------------------------------------------
  154. SCODE CFileStream::InitWorker(WCHAR const *pwcsPath, DWORD dwFSInit)
  155. {
  156. WCHAR awcPath[_MAX_PATH+1];
  157. TCHAR atcPath[_MAX_PATH+1];
  158. TCHAR atcTempDirPath[_MAX_PATH+1];
  159. SCODE sc;
  160. DWORD DFlags = _pgfst->GetDFlags();
  161. filestDebug((DEB_ITRACE, "IN CFileStream::InitWorker(%ws, 0x%x)\n",
  162. pwcsPath, dwFSInit));
  163. // If we've already been constructed, leave
  164. if (INVALID_FH != _hFile)
  165. {
  166. filestDebug((DEB_ITRACE, "OUT CFileStream::Init returning %x\n", S_OK));
  167. return S_OK;
  168. }
  169. // Get file name from:
  170. // 1) the global object on Unmarshals (stored in Unicode).
  171. // 2) the passed parameter on Opens (OLE standard Unicode).
  172. // 3) MakeTmpName() when making Scratch or SnapShot files.
  173. //
  174. if (!_pgfst->HasName())
  175. {
  176. //
  177. // The Global object does not have a name so this CAN'T be an
  178. // unmarshal. It is possible for scratch files to be marshaled
  179. // with no name because they have not yet been "demanded" but
  180. // Unmarshal() doesn't calls us if there is no name.
  181. //
  182. // fsAssert(!(dwFSInit & FSINIT_UNMARSHAL));
  183. // If we were passed a name, copy it.
  184. // Watch out for a possible bad pointer from the user.
  185. if (pwcsPath != NULL)
  186. {
  187. if (FAILED(StringCbCopyW (awcPath, sizeof(awcPath), pwcsPath)))
  188. fsErr(EH_Err, STG_E_INVALIDPOINTER);
  189. }
  190. else // If we weren't given a name then make one up.
  191. {
  192. // We use native "TCHAR" when finding a temp name.
  193. //
  194. fsChk(Init_GetTempName(atcPath, atcTempDirPath));
  195. dwFSInit |= FSINIT_MADEUPNAME;
  196. if (FAILED(StringCbCopyW (awcPath, sizeof(awcPath), atcPath)))
  197. fsErr(EH_Err, STG_E_INVALIDPOINTER);
  198. }
  199. fsChk(Init_OpenOrCreate(awcPath, // filename: given or created
  200. atcTempDirPath, // path to temp directory
  201. dwFSInit)); // various state information
  202. }
  203. else
  204. { // Name is in the global file object. This is unmarshaling.
  205. // Or we could be in the 2nd init of a scratch file that was
  206. // "demanded" after it was marshaled.
  207. fsAssert( (dwFSInit & FSINIT_UNMARSHAL)
  208. || (GetStartFlags() & RSF_SCRATCH) );
  209. fsChk(Init_DupFileHandle(dwFSInit));
  210. }
  211. //
  212. // If this is the first open of the file then we need to store
  213. // the name into the global object.
  214. // Set name to fully qualified path to avoid current-directory
  215. // dependencies.
  216. // Always store the path as Unicode. We are using "WideWrap" here.
  217. //
  218. if (!_pgfst->HasName())
  219. {
  220. WCHAR awcFullPath[_MAX_PATH+1];
  221. WCHAR *pwcBaseName;
  222. if(0 == GetFullPathName(awcPath, _MAX_PATH, awcFullPath, &pwcBaseName))
  223. {
  224. fsErr(EH_File, LAST_STG_SCODE);
  225. }
  226. _pgfst->SetName(awcFullPath);
  227. //
  228. // If this is the first open of a SCRATCH then dup the file handle
  229. // to any other marshaled instances. This covers the case of a
  230. // late "demand" scratch.
  231. //
  232. if(GetStartFlags() & RSF_SCRATCH)
  233. DupFileHandleToOthers();
  234. }
  235. CheckSeekPointer();
  236. filestDebug((DEB_INFO,
  237. "File=%2x Initialize this=%p thread %lX path %ws\n",
  238. _hFile, this, GetCurrentThreadId(), _pgfst->GetName()));
  239. //
  240. // When a file is mapped we can't shorten the real filesize except by
  241. // truncating when we close.
  242. //
  243. // If More than one context has the file mapped we can't truncate the
  244. // file when we close.
  245. //
  246. // If multiple writers having a file mapped data can be destroyed when
  247. // they close and truncate a file that the other guy may have written.
  248. // There is also a problem with readers holding the file mapped that
  249. // prevents the writer from truncating the file when he closes.
  250. //
  251. // So... the cases Where we want to allow mapping:
  252. // - Direct, Read
  253. // - Transacted, Read w/ Deny-Write
  254. // - AnyMode, Write w/ Deny-Write
  255. // - Tempfiles (scratch and snapshot)
  256. //
  257. if( (P_DIRECT(DFlags) && P_READ(DFlags))
  258. || (P_TRANSACTED(DFlags) && P_READ(DFlags) && P_DENYWRITE(DFlags))
  259. || (P_WRITE(DFlags) && P_DENYWRITE(DFlags))
  260. || (RSF_TEMPFILE & GetStartFlags()) )
  261. {
  262. Init_MemoryMap(dwFSInit);
  263. }
  264. else
  265. {
  266. filestDebug((DEB_MAP, "File=%2x Not creating a memory map for %ws.\n",
  267. _hFile, _pgfst->GetName()));
  268. }
  269. filestDebug((DEB_ITRACE, "OUT CFileStream::Init returning %x\n", S_OK));
  270. return S_OK;
  271. EH_File:
  272. fsVerify(CloseHandle(_hFile));
  273. _hFile = INVALID_FH;
  274. if(RSF_CREATE & _pgfst->GetStartFlags())
  275. DeleteTheFile(awcPath);
  276. EH_Err:
  277. filestDebug((DEB_ITRACE, "OUT CFileStream::Init returning %x\n", sc));
  278. return sc;
  279. }
  280. //+--------------------------------------------------------------
  281. //
  282. // Member: CFileStream::Init_GetTempName, private
  283. //
  284. // Synopsis: Make up a temp filename.
  285. //
  286. // Arguments: [ptcPath] -- [out] Tmp filename path
  287. // [ptcTmpPath] -- [out] Tmp directory path
  288. //
  289. // Returns: S_OK
  290. //
  291. // History: 13-Jan-97 BChapman Clean up InitWorker.
  292. //
  293. // Note: TCHAR issue. We do as much as we can "native" and the
  294. // caller converts the result. (If necessary)
  295. //
  296. //---------------------------------------------------------------
  297. SCODE CFileStream::Init_GetTempName(TCHAR *ptcPath, TCHAR *ptcTmpPath)
  298. {
  299. SCODE sc;
  300. LUID luid;
  301. DWORD cch;
  302. // Can't truncate since for temporary files we will
  303. // always be creating
  304. fsAssert(0 == (_pgfst->GetStartFlags() & RSF_TRUNCATE));
  305. // Create the Temp Name with native TCHAR.
  306. //
  307. cch = GetTempPath(_MAX_PATH, ptcTmpPath);
  308. if (0 == cch)
  309. {
  310. fsErr(EH_Err, LAST_STG_SCODE);
  311. }
  312. else if (cch > _MAX_PATH)
  313. {
  314. fsErr(EH_Err, STG_E_PATHNOTFOUND);
  315. }
  316. if (AllocateLocallyUniqueId (&luid) == FALSE)
  317. fsErr (EH_Err, LAST_STG_SCODE);
  318. if(0 == GetTempFileName(ptcTmpPath, TEMPFILE_PREFIX, luid.LowPart, ptcPath))
  319. {
  320. fsErr(EH_Err, LAST_STG_SCODE);
  321. }
  322. return S_OK;
  323. EH_Err:
  324. return sc;
  325. }
  326. //+--------------------------------------------------------------
  327. //
  328. // Member: CFileStream::Init_GetNtOpenFlags, private
  329. //
  330. // Synopsis: Convert Docfile flags into NT Open flags.
  331. //
  332. // Arguments: [pdwAccess] -- [out] NT flags
  333. // [pdwShare] -- [out] NT flags
  334. // [pdwCreation] -- [out] NT Flags
  335. // [pdwFlagAttr] -- [out] NT Flags
  336. //
  337. // Returns: S_OK
  338. //
  339. // Notes: Uses _pgfst->GetDFlags() and _pgfst->GetStartFlags().
  340. //
  341. // History: 6-Nov-96 BChapman Clean up InitWorker.
  342. //
  343. //---------------------------------------------------------------
  344. SCODE CFileStream::Init_GetNtOpenFlags(
  345. LPDWORD pdwAccess,
  346. LPDWORD pdwShare,
  347. LPDWORD pdwCreation,
  348. LPDWORD pdwFlagAttr)
  349. {
  350. DWORD dwStartFlags = _pgfst->GetStartFlags();
  351. *pdwAccess = 0;
  352. *pdwShare = 0;
  353. *pdwCreation = 0;
  354. *pdwFlagAttr = 0;
  355. if (_pgfst->HasName())
  356. {
  357. dwStartFlags &= ~RSF_CREATEFLAGS;
  358. dwStartFlags |= RSF_OPEN;
  359. }
  360. if (dwStartFlags & RSF_OPENCREATE)
  361. {
  362. // This is used for our internal logging
  363. *pdwCreation = OPEN_ALWAYS;
  364. }
  365. else if (dwStartFlags & RSF_CREATE)
  366. {
  367. if (dwStartFlags & RSF_TRUNCATE)
  368. *pdwCreation = CREATE_ALWAYS;
  369. else
  370. *pdwCreation = CREATE_NEW;
  371. }
  372. else
  373. {
  374. if (dwStartFlags & RSF_TRUNCATE)
  375. *pdwCreation = TRUNCATE_EXISTING;
  376. else
  377. *pdwCreation = OPEN_EXISTING;
  378. }
  379. DWORD dwDFlags = _pgfst->GetDFlags();
  380. if (!P_WRITE(dwDFlags))
  381. *pdwAccess = GENERIC_READ;
  382. else
  383. *pdwAccess = GENERIC_READ | GENERIC_WRITE;
  384. if (P_DENYWRITE(dwDFlags) && !P_WRITE(dwDFlags))
  385. *pdwShare = FILE_SHARE_READ;
  386. else
  387. *pdwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  388. #if WIN32 == 300
  389. if (dwDFlags & DF_ACCESSCONTROL)
  390. *pdwAccess |= WRITE_DAC | READ_CONTROL;
  391. #endif
  392. // Make sure we're not attempting to create/truncate a read-only thing
  393. fsAssert(*pdwAccess != GENERIC_READ ||
  394. !(dwStartFlags & (RSF_CREATE | RSF_TRUNCATE)));
  395. switch(RSF_TEMPFILE & dwStartFlags)
  396. {
  397. case RSF_SCRATCH:
  398. *pdwFlagAttr = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS;
  399. break;
  400. case RSF_SNAPSHOT:
  401. *pdwFlagAttr = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
  402. break;
  403. case 0: // Normal "original" file
  404. *pdwFlagAttr = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
  405. break;
  406. default:
  407. // if we get here something is rotten in the header files
  408. fsAssert(RSF_TEMPFILE == (RSF_SCRATCH | RSF_SNAPSHOT));
  409. break;
  410. }
  411. if(RSF_DELETEONRELEASE & dwStartFlags && RSF_TEMPFILE & dwStartFlags)
  412. {
  413. *pdwFlagAttr |= FILE_FLAG_DELETE_ON_CLOSE;
  414. *pdwShare |= FILE_SHARE_DELETE;
  415. }
  416. if (RSF_NO_BUFFERING & dwStartFlags)
  417. {
  418. *pdwFlagAttr |= FILE_FLAG_NO_BUFFERING;
  419. }
  420. if (RSF_ENCRYPTED & dwStartFlags)
  421. {
  422. *pdwFlagAttr |= FILE_ATTRIBUTE_ENCRYPTED;
  423. }
  424. return S_OK;
  425. }
  426. //+--------------------------------------------------------------
  427. //
  428. // Member: CFileStream::Init_OpenOrCreate, private
  429. //
  430. // Synopsis: Actually Open the NT file.
  431. //
  432. // Arguments: [pwcPath] -- Name of File to open. OLECHAR
  433. // [ptcTmpPath] -- Path to the Temp Directory. TCHAR
  434. // [dwFSInit] -- Flags.
  435. //
  436. // Returns: S_OK
  437. //
  438. // History: 6-Nov-96 BChapman InitWorker was too big.
  439. //
  440. // Notes: We pass the Temp directory path as a TCHAR because if we
  441. // need to construct a new temp file name we want to work
  442. // "native" as much as possible.
  443. //
  444. //---------------------------------------------------------------
  445. SCODE CFileStream::Init_OpenOrCreate(
  446. WCHAR *pwcPath,
  447. TCHAR *ptcTmpPath,
  448. DWORD dwFSInit)
  449. {
  450. SCODE sc;
  451. TCHAR atcPath[_MAX_PATH+1];
  452. DWORD dwAccess, dwShare, dwCreation, dwFlagAttr;
  453. DWORD dwDFlags = _pgfst->GetDFlags();
  454. Init_GetNtOpenFlags(&dwAccess, &dwShare, &dwCreation, &dwFlagAttr);
  455. //If we're opening with deny-read, we need to let the
  456. // file system tell us if there are any other readers, to
  457. // avoid our no-lock trick for the read-only deny-write case.
  458. //Yes, this is ugly.
  459. //Yes, it also has a race condition in which two people can
  460. // get read access while specifying SHARE_DENY_READ.
  461. //
  462. if (!(dwFSInit & FSINIT_UNMARSHAL) &&
  463. !P_WRITE(dwDFlags) && P_DENYREAD(dwDFlags))
  464. {
  465. // We open read-only, share exclusive(ie == 0). If this
  466. // fails, there is already another accessor, so we bail.
  467. //
  468. // If we are unmarshalling, we don't do this check because we
  469. // know there is already another reader, i.e. the original open.
  470. //
  471. // Using WideWrap to handle the !UNICODE case.
  472. //
  473. _hFile = CreateFile(pwcPath, GENERIC_READ, 0, NULL,
  474. dwCreation, dwFlagAttr, NULL);
  475. if (INVALID_FH == _hFile)
  476. {
  477. filestDebug((DEB_INFO, "Can open file %ws in the test open "
  478. "read-only deny read case\n", pwcPath));
  479. if (GetLastError() == ERROR_ALREADY_EXISTS)
  480. fsErr(EH_Err, STG_E_FILEALREADYEXISTS)
  481. else
  482. fsErr(EH_Err, LAST_STG_SCODE);
  483. }
  484. CloseHandle(_hFile);
  485. }
  486. //
  487. // Open the File. We use OLE WideWrap to handle !UNICODE
  488. //
  489. _hFile = CreateFile(pwcPath, dwAccess, dwShare, NULL,
  490. dwCreation, dwFlagAttr, NULL);
  491. //
  492. // If the Open failed w/ error = FILE_EXISTS and this is a temp file
  493. // then make up a new temp file name and keep tring until we succeed
  494. // or fail with a different error.
  495. //
  496. if (INVALID_FH == _hFile)
  497. {
  498. DWORD dwLastError = GetLastError();
  499. if (dwLastError != ERROR_ALREADY_EXISTS &&
  500. dwLastError != ERROR_FILE_EXISTS)
  501. {
  502. filestDebug((DEB_INFO, "File %ws Open Failed. err=%x\n",
  503. pwcPath, dwLastError));
  504. fsErr(EH_Err, STG_SCODE(dwLastError));
  505. }
  506. //
  507. // If we didn't make this name (ie. tempfile) then it is
  508. // time to error out. Otherwise if we did make this name then
  509. // we can continue to try other names.
  510. //
  511. if(!(FSINIT_MADEUPNAME & dwFSInit))
  512. {
  513. filestDebug((DEB_INFO, "File Open Failed. File %ws Exists\n",
  514. pwcPath));
  515. fsErr(EH_Err, STG_E_FILEALREADYEXISTS);
  516. }
  517. LUID luid;
  518. CGlobalSecurity gs; // put an secure ACL on the temp files
  519. fsChk (gs.Init(TRUE));
  520. while (1)
  521. {
  522. if (AllocateLocallyUniqueId (&luid) == FALSE)
  523. fsErr (EH_Err, LAST_STG_SCODE);
  524. filestDebug((DEB_INFO,
  525. "CreateFile failed %x tring a new tempfile name.\n",
  526. dwLastError));
  527. if (GetTempFileName(ptcTmpPath, TEMPFILE_PREFIX,
  528. luid.LowPart, atcPath) == 0)
  529. {
  530. fsErr(EH_Err, LAST_STG_SCODE);
  531. }
  532. StringCchCopyW (pwcPath, MAX_PATH+1, atcPath);
  533. filestDebug((DEB_INFO,
  534. "Tempfile CreateFile(%ws, %x, %x, NULL, %x, NORMAL|RANDOM, NULL)\n",
  535. pwcPath, dwAccess, dwShare, dwCreation));
  536. //
  537. // Using WideWrap to handle the !UNICODE case
  538. //
  539. _hFile = CreateFile(
  540. pwcPath,
  541. dwAccess,
  542. dwShare,
  543. (SECURITY_ATTRIBUTES *) gs,
  544. dwCreation,
  545. dwFlagAttr,
  546. NULL);
  547. if (INVALID_FH != _hFile)
  548. break;
  549. dwLastError = GetLastError();
  550. if (dwLastError != ERROR_ALREADY_EXISTS &&
  551. dwLastError != ERROR_FILE_EXISTS)
  552. {
  553. fsErr(EH_Err, STG_SCODE(dwLastError));
  554. }
  555. }
  556. }
  557. #if WIN32 == 100
  558. if (_pgfst->GetStartFlags() & RSF_NO_BUFFERING)
  559. {
  560. ULONG cbSector;
  561. fsChk (GetNtHandleSectorSize (_hFile, &cbSector));
  562. if ((cbSector % HEADERSIZE) == 0) // only support sector sizes n*512
  563. _pgfst->SetSectorSize(cbSector);
  564. }
  565. #endif
  566. filestDebug((DEB_INFO,
  567. "File=%2x CreateFile(%ws, %x, %x, NULL, %x, %x, NULL)\n",
  568. _hFile, pwcPath, dwAccess, dwShare,
  569. dwCreation, dwFlagAttr));
  570. //At this point the file handle is valid, so let's look at the
  571. //seek pointer and see what it is.
  572. CheckSeekPointer();
  573. return S_OK;
  574. EH_Err:
  575. return sc;
  576. }
  577. //+--------------------------------------------------------------
  578. //
  579. // Member: CFileStream::Init_DupFileHandle, private
  580. //
  581. // Synopsis: Dup any existing File Handle into _hFile.
  582. //
  583. // Returns: S_OK, System Error
  584. // or STG_E_INVALIDHANDLE if it can't file a file to Dup.
  585. //
  586. // History: 15-Apr-96 BChapman Created
  587. //
  588. // Notes: This is called from unmarshal. So we can assert that there
  589. // MUST be another instance of an open handle in the list.
  590. //
  591. //---------------------------------------------------------------
  592. SCODE CFileStream::Init_DupFileHandle(DWORD dwFSINIT)
  593. {
  594. CFileStream *pfst;
  595. SCODE sc=E_FAIL;
  596. HANDLE hprocSrc = NULL;
  597. HANDLE hFileSrc;
  598. fsAssert(INVALID_FH == _hFile);
  599. //
  600. // Another context may have already Dup'ed the File Handle
  601. // to us. (This is only in the marshaled-undemanded-scratch case)
  602. //
  603. if(INVALID_FH != _hPreDuped)
  604. {
  605. _hFile = _hPreDuped;
  606. _hPreDuped = INVALID_FH;
  607. return S_OK;
  608. }
  609. //
  610. // Search the list of contexts for someone we can Dup from.
  611. //
  612. pfst = _pgfst->GetFirstContext();
  613. fsAssert(NULL != pfst);
  614. while (pfst != NULL)
  615. {
  616. if (INVALID_FH == pfst->_hFile && INVALID_FH == pfst->_hPreDuped)
  617. {
  618. pfst = pfst->GetNext();
  619. continue;
  620. }
  621. //
  622. // Found someone with the file open. Now Dup it.
  623. //
  624. hFileSrc = (INVALID_FH == pfst->_hFile) ?
  625. pfst->_hPreDuped :
  626. pfst->_hFile;
  627. hprocSrc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pfst->GetContext());
  628. if(NULL == hprocSrc)
  629. {
  630. sc = LAST_STG_SCODE;
  631. pfst = pfst->GetNext();
  632. continue;
  633. }
  634. if(DuplicateHandle(hprocSrc, // Src Process
  635. hFileSrc, // Src Handle
  636. GetCurrentProcess(), // Dest Process
  637. &_hFile, // Dest Handle
  638. 0, FALSE,
  639. DUPLICATE_SAME_ACCESS))
  640. {
  641. sc = S_OK;
  642. break;
  643. }
  644. sc = LAST_STG_SCODE;
  645. CloseHandle(hprocSrc);
  646. pfst = pfst->GetNext();
  647. }
  648. if (NULL == pfst)
  649. fsErr(EH_Err, STG_E_INVALIDHANDLE);
  650. if (hprocSrc)
  651. CloseHandle(hprocSrc);
  652. return S_OK;
  653. EH_Err:
  654. return sc;
  655. }
  656. //+--------------------------------------------------------------
  657. //
  658. // Member: CFileStream::DupFileHandleToOthers, private
  659. //
  660. // Synopsis: Dup your file handle into everyone else.
  661. //
  662. // Returns: S_OK, or system faliure code.
  663. //
  664. // History: 17-Apr-96 BChapman Created
  665. //
  666. // Notes: This is used when demanding a marshaled undemanded scratch.
  667. // We put the Dup'ed handle in "_hPreDuped". The "Init_DupHandle()"
  668. // routine will find it an move it into _hFile.
  669. //---------------------------------------------------------------
  670. SCODE CFileStream::DupFileHandleToOthers()
  671. {
  672. SCODE scAny = S_OK;
  673. CFileStream *pfst;
  674. HANDLE hprocDest;
  675. pfst = _pgfst->GetFirstContext();
  676. fsAssert(NULL != pfst);
  677. //
  678. // Walk the list of contexts and Dup the file handle into all
  679. // contexts that don't already have it open. If any of them fail,
  680. // keep going. Hold onto the last error code and return it.
  681. //
  682. while(NULL != pfst)
  683. {
  684. if(INVALID_FH == pfst->_hFile && INVALID_FH == pfst->_hPreDuped)
  685. {
  686. //
  687. // Found someone that needs the file handle.
  688. //
  689. hprocDest = OpenProcess(PROCESS_DUP_HANDLE,
  690. FALSE,
  691. pfst->GetContext());
  692. if(NULL == hprocDest)
  693. {
  694. scAny = LAST_STG_SCODE;
  695. }
  696. else
  697. {
  698. if(!DuplicateHandle(GetCurrentProcess(), // Src Process
  699. _hFile, // Src Handle
  700. hprocDest, // Dest Process
  701. &pfst->_hPreDuped, // Dest Handle
  702. 0, FALSE,
  703. DUPLICATE_SAME_ACCESS))
  704. {
  705. scAny = LAST_STG_SCODE;
  706. }
  707. CloseHandle(hprocDest);
  708. }
  709. }
  710. pfst = pfst->GetNext();
  711. }
  712. return scAny;
  713. }
  714. #ifdef USE_FILEMAPPING
  715. //+--------------------------------------------------------
  716. // The following are Memory mapped file support for NT
  717. // Init_MemoryMap
  718. // TurnOffMapping
  719. // MakeFileMapAddressValid
  720. //+--------------------------------------------------------
  721. //
  722. // This size will need to be revisited in the future. Right now this is
  723. // a balance between not consuming too much of a 32 address space, and big
  724. // enough for most files without need to grow.
  725. // In Nov 1996 (at the time of this writing) most documents are between
  726. // 80-800K. Some huge spreadsheets like the perf group reportare 18-20Mb.
  727. //
  728. #define MINIMUM_MAPPING_SIZE (512*1024)
  729. BOOL DfIsRemoteFile (HANDLE hFile)
  730. {
  731. NTSTATUS Status;
  732. IO_STATUS_BLOCK IoStatus;
  733. FILE_FS_DEVICE_INFORMATION DeviceInformation;
  734. DeviceInformation.Characteristics = 0;
  735. Status = NtQueryVolumeInformationFile(
  736. hFile,
  737. &IoStatus,
  738. &DeviceInformation,
  739. sizeof(DeviceInformation),
  740. FileFsDeviceInformation
  741. );
  742. if ( NT_SUCCESS(Status) &&
  743. (DeviceInformation.Characteristics & FILE_REMOTE_DEVICE) ) {
  744. return TRUE;
  745. }
  746. return FALSE;
  747. }
  748. //+---------------------------------------------------------------------------
  749. //
  750. // Member: CFileStream::IsEncryptedFile, private
  751. //
  752. // Synopsis: queries the file handle to see if it's encrypted
  753. //
  754. // Arguments: [dwFSInit] -- Flags. Possible values:
  755. // FSINIT_UNMARSHAL - This is an unmarshal.
  756. //
  757. // Returns: TRUE - if the file is encrypted on NTFS
  758. // FALSE - if we can't tell
  759. //
  760. // History: 05-Apr-2000 HenryLee Created
  761. //
  762. //----------------------------------------------------------------------------
  763. BOOL CFileStream::IsEncryptedFile ()
  764. {
  765. NTSTATUS Status;
  766. IO_STATUS_BLOCK IoStatus;
  767. FILE_BASIC_INFORMATION BasicInformation;
  768. Status = NtQueryInformationFile(
  769. _hFile,
  770. &IoStatus,
  771. &BasicInformation,
  772. sizeof(BasicInformation),
  773. FileBasicInformation
  774. );
  775. if ( NT_SUCCESS(Status) &&
  776. (BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) )
  777. return TRUE;
  778. return FALSE;
  779. }
  780. //+---------------------------------------------------------------------------
  781. //
  782. // Member: CFileStream::Init_MemoryMap, private
  783. //
  784. // Synopsis: Creates and Views a memory map for the current file.
  785. // Used by First open and Unmarshal.
  786. //
  787. // Arguments: [dwFSInit] -- Flags. Possible values:
  788. // FSINIT_UNMARSHAL - This is an unmarshal.
  789. //
  790. // Returns: S_OK - When the mapping is added to the address space.
  791. // E_FAIL - When the global object says not to map the file.
  792. // E_OUTOFMEMORY - When the attempt to map the file failed.
  793. //
  794. // Private Effect: Sets _hMapObject
  795. // Sets _pbBaseAddr
  796. //
  797. // Note: The field _pbBaseAddr is check before each use of the memory map.
  798. //
  799. // History: 19-Oct-96 BChapman Created
  800. //
  801. //----------------------------------------------------------------------------
  802. SCODE CFileStream::Init_MemoryMap(DWORD dwFSInit)
  803. {
  804. LUID luid;
  805. WCHAR pwcMapName[MAPNAME_MAXLEN];
  806. DWORD dwPageFlags, dwMapFlags;
  807. ULONG cbFileSize;
  808. ULONG cbFileSizeHigh;
  809. ULONG cbViewSize;
  810. ULONG cbCommitedSize;
  811. SCODE sc;
  812. BOOL fMakeStub = FALSE;
  813. filestDebug((DEB_ITRACE, "In Init_MemoryMap(0x%x)\n", dwFSInit));
  814. if (_pgfst->GetStartFlags() & RSF_NO_BUFFERING)
  815. fsErr (EH_Err, STG_E_INVALIDFUNCTION);
  816. cbFileSize = GetFileSize(_hFile, &cbFileSizeHigh);
  817. if (cbFileSize == MAX_ULONG && NO_ERROR != GetLastError())
  818. fsErr(EH_Err, LAST_STG_SCODE)
  819. if (cbFileSizeHigh > 0)
  820. fsErr (EH_Err, STG_E_DOCFILETOOLARGE);
  821. // disallow remote opens except for read, deny-write for NT4 compatiblity
  822. if ((P_WRITE(_pgfst->GetDFlags()) || !P_DENYWRITE(_pgfst->GetDFlags())) &&
  823. DfIsRemoteFile (_hFile))
  824. fsErr (EH_Err, STG_E_INVALIDFUNCTION);
  825. filestDebug((DEB_MAP, "File=%2x Init_MemoryMap filesize = %x\n",
  826. _hFile, cbFileSize));
  827. #if DBG==1
  828. //
  829. // DEBUG ASSERT
  830. // If the file is a temp file it must be delete on release.
  831. // The performance of mapped temp files that are not DELETE_ON_CLOSE
  832. // is very slow on FAT.
  833. //
  834. if(RSF_TEMPFILE & GetStartFlags())
  835. fsAssert(RSF_DELETEONRELEASE & GetStartFlags());
  836. #endif
  837. //
  838. // This routine makes two kinds of mapping.
  839. // 1) Writeable mappings over filesystem files that grow.
  840. // 2) Readonly mappings over filesystem files that are fixed size.
  841. //
  842. //
  843. // If we are opening for writing then grow the mapping upto
  844. // some limit so there is room for writes to extend the file.
  845. // If we are opening for reading then the mapping is the same
  846. // size as the original file.
  847. //
  848. if(_pgfst->GetDFlags() & DF_WRITE)
  849. {
  850. dwPageFlags = PAGE_READWRITE;
  851. dwMapFlags = FILE_MAP_WRITE;
  852. //
  853. // Nt can't Memory map a zero length file, so if the file is
  854. // zero length and we are open for writing then grow the file
  855. // to one sector before we create the memory map. But don't set
  856. // the MappedFileSize or MappedCommitSize because the docfile
  857. // code uses filesize==0 to determine if this is a create or an
  858. // open. So it is important to not expose the fact that we grew
  859. // the file.
  860. //
  861. if (0 == cbFileSize)
  862. {
  863. //Grow the file to 512 bytes in the create path - in the
  864. //open path we don't want to change the file size.
  865. //For the open path, don't map it - we'll fail later with
  866. //STG_E_INVALIDHEADER.
  867. if ((GetStartFlags() & RSF_CREATE) ||
  868. (GetStartFlags() & RSF_TEMPFILE))
  869. {
  870. if (SUCCEEDED(MakeFileStub()))
  871. fMakeStub = TRUE;
  872. }
  873. else
  874. fsErr(EH_Err, E_OUTOFMEMORY);
  875. }
  876. if(cbFileSize < MINIMUM_MAPPING_SIZE/2)
  877. cbViewSize = MINIMUM_MAPPING_SIZE;
  878. else
  879. cbViewSize = cbFileSize * 2;
  880. }
  881. else
  882. {
  883. dwPageFlags = PAGE_READONLY;
  884. dwMapFlags = FILE_MAP_READ;
  885. cbViewSize = cbFileSize;
  886. }
  887. //
  888. // Get the mapping object. Either open the existing one for this
  889. // file. Or if this is the first open for this "DF context" then
  890. // create a new one.
  891. //
  892. if(NULL == _pgfst->GetMappingName())
  893. {
  894. //
  895. // If this is a first open for this "context" then we won't have
  896. // a name and the Unmarshaling flag should be FALSE.
  897. //
  898. //fsAssert(!(dwFSInit & FSINIT_UNMARSHAL));
  899. //
  900. // Create a new unique name for the Mapping.
  901. //
  902. AllocateLocallyUniqueId(&luid);
  903. StringCbPrintfW (pwcMapName, sizeof(pwcMapName),
  904. MAPNAME_FORMAT, luid.HighPart, luid.LowPart);
  905. _pgfst->SetMappingName(pwcMapName);
  906. //
  907. // Do not map very large files since they can consume
  908. // too much virtual memory
  909. //
  910. MEMORYSTATUS memstatus;
  911. GlobalMemoryStatus (&memstatus);
  912. if (cbFileSize > memstatus.dwTotalPhys / 2 ||
  913. memstatus.dwAvailVirtual < DOCFILE_SM_LIMIT / 2)
  914. fsErr(EH_Err, E_OUTOFMEMORY);
  915. filestDebug((DEB_MAP,
  916. "File=%2x New MappingName='%ws' FileName='%ws'\n",
  917. _hFile, pwcMapName, _pgfst->GetName() ));
  918. //
  919. // Create the Mapping. This only covers the orignal file size.
  920. // RESERVED uncommitted extensions are done in MapView.
  921. //
  922. _hMapObject = CreateFileMappingW(_hFile,
  923. NULL, // default Security Descriptor.
  924. dwPageFlags,
  925. 0, 0, // Creation size of 0 means The Entire File.
  926. _pgfst->GetMappingName()
  927. );
  928. //
  929. // This mapping is new and did not exist previously.
  930. //
  931. fsAssert(ERROR_ALREADY_EXISTS != GetLastError());
  932. //
  933. // Record the size of the file (also the commited region of the map)
  934. // We waited to record the size until after the mapping is created.
  935. // A seperate open could have shortened the file in the time between
  936. // the top of this routine and here. But SetEndOfFile is disallowed
  937. // once a file mapping is active.
  938. // Note: Watch out for the case where the file is logically zero size
  939. // but we grew it a little so we could memory map it.
  940. //
  941. if(0 != cbFileSize)
  942. {
  943. cbFileSize = GetFileSize(_hFile, &cbFileSizeHigh);
  944. if (cbFileSize == MAX_ULONG && NO_ERROR != GetLastError())
  945. {
  946. sc = LAST_STG_SCODE;
  947. if (_hMapObject != NULL)
  948. {
  949. CloseHandle (_hMapObject);
  950. _hMapObject = NULL;
  951. }
  952. fsErr(EH_Err, sc)
  953. }
  954. fsAssert (cbFileSizeHigh == 0);
  955. _pgfst->SetMappedFileSize(cbFileSize);
  956. _pgfst->SetMappedCommitSize(cbFileSize);
  957. }
  958. }
  959. else
  960. {
  961. //
  962. // If the global object already has a mapping name then this must
  963. // be an unmarshal. Or we could be in the 2nd init of a scratch
  964. // file that is "demanded" after it was first marshaled.
  965. //
  966. fsAssert( (dwFSInit & FSINIT_UNMARSHAL)
  967. || (GetStartFlags() & RSF_SCRATCH) );
  968. filestDebug((DEB_MAP,
  969. "File=%2x UnMarshal MappingName='%ws' FileName='%ws'\n",
  970. _hFile, _pgfst->GetMappingName(),
  971. _pgfst->GetName() ));
  972. // If the global object says the mapping is off,
  973. // then some other instance of this FileStream has declared
  974. // the mapping unuseable and no other instance should map it either.
  975. //
  976. if( ! _pgfst->TestMapState(FSTSTATE_MAPPED))
  977. {
  978. filestDebug((DEB_MAP, "Global Flag says Don't Map.\n"));
  979. filestDebug((DEB_ITRACE, "Out Init_MemoryMap() => %lx\n", E_FAIL));
  980. return E_FAIL;
  981. }
  982. _hMapObject = OpenFileMapping(dwMapFlags,
  983. FALSE, // Don't Inherit
  984. _pgfst->GetMappingName()
  985. );
  986. }
  987. if (NULL == _hMapObject)
  988. {
  989. filestDebug((DEB_IWARN|DEB_MAP,
  990. "File=%2x Create FileMapping '%ws' for "
  991. "filename '%ws' failed, error=0x%x\n",
  992. _hFile,
  993. _pgfst->GetMappingName(),
  994. _pgfst->GetName(),
  995. GetLastError()));
  996. fsErr(EH_Err, E_OUTOFMEMORY);
  997. }
  998. filestDebug((DEB_MAP,
  999. "File=%2x Map=%2x filesize=0x%06x, commitsize=0x%06x\n",
  1000. _hFile, _hMapObject,
  1001. _pgfst->GetMappedFileSize(),
  1002. _pgfst->GetMappedCommitSize()));
  1003. //
  1004. // Add the file map to the process' address space.
  1005. //
  1006. if(FAILED(MapView(cbViewSize, dwPageFlags, dwFSInit)))
  1007. {
  1008. TurnOffAllMappings();
  1009. fsErr(EH_Err, E_OUTOFMEMORY);
  1010. }
  1011. return S_OK;
  1012. EH_Err:
  1013. //
  1014. // If we can't get a mapping then set a flag so no other marshal's
  1015. // of this context should try either.
  1016. //
  1017. _pgfst->ResetMapState(FSTSTATE_MAPPED);
  1018. if (fMakeStub) // try to reset the filesize back to 0
  1019. {
  1020. SetFilePointer(_hFile, 0, NULL, FILE_BEGIN);
  1021. SetEndOfFile(_hFile);
  1022. }
  1023. filestDebug((DEB_ITRACE, "Out Init_MemoryMap() => %lx\n", sc));
  1024. return sc;
  1025. }
  1026. //+--------------------------------------------------------------
  1027. //
  1028. // Member: CFileStream::MakeFileStub, private
  1029. //
  1030. // Synopsis: Takes a zero length file and makes it 512 bytes. This is
  1031. // needed to support NT file mapping. The important effects
  1032. // are that it does NOT set the saved file size.
  1033. //
  1034. // History: 09-Mar-96 Bchapman Created
  1035. //
  1036. //---------------------------------------------------------------
  1037. HRESULT CFileStream::MakeFileStub()
  1038. {
  1039. SCODE sc=S_OK;
  1040. #if DBG == 1
  1041. ULONG cbFileSizeHigh;
  1042. #endif
  1043. fsAssert(0 == GetFilePointer());
  1044. #if DBG == 1
  1045. fsAssert(0 == GetFileSize(_hFile, &cbFileSizeHigh));
  1046. fsAssert(0 == cbFileSizeHigh);
  1047. #endif
  1048. SetFilePointer(_hFile, 512, NULL, FILE_BEGIN);
  1049. if(FALSE == SetEndOfFile(_hFile))
  1050. sc = LAST_STG_SCODE;
  1051. SetFilePointer(_hFile, 0, NULL, FILE_BEGIN);
  1052. return sc;
  1053. }
  1054. //+--------------------------------------------------------------
  1055. //
  1056. // Member: CFileStream::MapView, private
  1057. //
  1058. // Synopsis: Maps a view of an existing File Mapping.
  1059. //
  1060. // Arguments: Size of the mapping, including extra space for RESERVED
  1061. // pages that can be added with VIrtualAlloc.
  1062. //
  1063. // Returns: S_OK - When the mapping is added to the address space.
  1064. // E_OUTOFMEMORY - When the attempt to map the file failed.
  1065. //
  1066. // Private Effect: Sets _pbBaseAddr
  1067. // Sets _cbViewSize
  1068. //
  1069. // Note:
  1070. //
  1071. // History: 25-Nov-96 Bchapman Created
  1072. //
  1073. //---------------------------------------------------------------
  1074. HRESULT CFileStream::MapView(
  1075. SIZE_T cbViewSize,
  1076. DWORD dwPageFlags,
  1077. DWORD dwFSInit)
  1078. {
  1079. filestDebug((DEB_ITRACE, "In MapView(0x%06x, 0x%x)\n",
  1080. cbViewSize, dwPageFlags));
  1081. PVOID pvBase=NULL;
  1082. LARGE_INTEGER SectionOffset;
  1083. NTSTATUS Status;
  1084. DWORD dwAllocationType = 0;
  1085. LISet32(SectionOffset, 0);
  1086. // confirm that we are mapping the whole file.
  1087. fsAssert(cbViewSize >= _pgfst->GetMappedFileSize());
  1088. if((PAGE_READWRITE & dwPageFlags))
  1089. dwAllocationType = MEM_RESERVE; // RESERVE uncommited pages.
  1090. Status = NtMapViewOfSection(
  1091. _hMapObject,
  1092. GetCurrentProcess(),
  1093. &pvBase, // returned pointer to base of map. If the
  1094. // initial value is non-Zero it is a "Hint".
  1095. 0L, // ZeroBits: see ntos\mm\mapview.c
  1096. 0L, // Commit: amount to initially Commit.
  1097. &SectionOffset, // Offset in file for base of Map.
  1098. &cbViewSize, // Size of VirtAddr chunk to reserve.
  1099. ViewShare,
  1100. dwAllocationType,
  1101. dwPageFlags);
  1102. if(NT_ERROR(Status))
  1103. {
  1104. filestDebug((DEB_WARN|DEB_MAP,
  1105. "File=%2x NtMapViewOfSection Failed, viewsize=0x%06x, "
  1106. "dwPageFlags=%x, status=0x%x\n",
  1107. _hFile, _cbViewSize, dwPageFlags, Status));
  1108. return E_OUTOFMEMORY;
  1109. }
  1110. _pgfst->SetMapState(FSTSTATE_MAPPED);
  1111. _pbBaseAddr = (LPBYTE)pvBase;
  1112. _cbViewSize = (ULONG)cbViewSize;
  1113. filestDebug((DEB_MAP,
  1114. "File=%2x Attaching Map: address=0x%07x, viewsz=0x%06x, "
  1115. "commitsz=0x%06x\n",
  1116. _hFile, _pbBaseAddr, _cbViewSize,
  1117. _pgfst->GetMappedCommitSize()));
  1118. filestDebug((DEB_ITRACE, "Out MapView => %lx\n", S_OK));
  1119. return S_OK;
  1120. }
  1121. //+--------------------------------------------------------------
  1122. //
  1123. // Member: CFileStream::TurnOffMapping, private
  1124. //
  1125. // Synopsis: Turns off the use of file mapping
  1126. //
  1127. // Private Effect: Clears _pbBaseAddr
  1128. // Clears _hMapObject
  1129. //
  1130. // History: 31-Aug-96 DrewB Created
  1131. // 22-Oct-96 BChapman Trim the End of File.
  1132. // Nov-96 BChapman Rewrote
  1133. //
  1134. //---------------------------------------------------------------
  1135. SCODE CFileStream::TurnOffMapping(BOOL fFlush)
  1136. {
  1137. filestDebug((DEB_ITRACE, "In TurnOffMapping(%d)\n", fFlush));
  1138. //
  1139. // We want to be make sure the file mapping was in use. Otherwise
  1140. // the "MappedFileSize" may not be valid when we truncate the file
  1141. // below. Which destroys data.
  1142. //
  1143. // Checking for the map object is better than checking the base pointer
  1144. // because this routine can be called when remapping the view.
  1145. // Then the base pointer will be NULL but we still have a map object.
  1146. //
  1147. if(NULL == _hMapObject)
  1148. return S_OK;
  1149. //
  1150. // Release the view of the map. And release the Map Object.
  1151. // Don't exit on errors. Do as much as we can.
  1152. //
  1153. if(NULL != _pbBaseAddr)
  1154. {
  1155. filestDebug((DEB_MAP, "File=%2x Detaching Map 0x%07x\n",
  1156. _hFile, _pbBaseAddr));
  1157. // the redirector cannot handle a dirty file mapping followed by
  1158. // ReadFile calls; local filesystems have a single coherent cache
  1159. // fortunately, we no longer map docfiles over the redirector
  1160. if (fFlush)
  1161. fsVerify(FlushViewOfFile(_pbBaseAddr, 0));
  1162. fsVerify(UnmapViewOfFile(_pbBaseAddr));
  1163. _pbBaseAddr = NULL;
  1164. }
  1165. if(NULL != _hMapObject)
  1166. {
  1167. fsVerify(CloseHandle(_hMapObject));
  1168. _hMapObject = NULL;
  1169. }
  1170. filestDebug((DEB_MAP, "File=%2x TurnOffMapping RefCount=%x\n",
  1171. _hFile, _pgfst->CountContexts()));
  1172. //
  1173. // If file was open for writing, and this is the last/only instance
  1174. // of this "DF context" then truncate the file to the proper size.
  1175. // We do this when the file may have grown by commiting pages on
  1176. // the end of the memory map, the system will grow the file in
  1177. // whole MMU page units, so we may need to trim the extra off.
  1178. //
  1179. // Don't do this in the case of multiple 'seperate' writers. Last
  1180. // close wins on the file size and that is not good.
  1181. //
  1182. // Don't fail on errors. We are only trimming the EOF.
  1183. //
  1184. // Bugfix Feb '98 BChapman
  1185. // Don't Set EOF unless the map was written to or SetSize was called.
  1186. // Many people were opening READ/WRITE, not writing, and expecting the
  1187. // Mod. time to remain unchanged.
  1188. //
  1189. if( (_pgfst->CountContexts() == 1)
  1190. && (_pgfst->GetDFlags() & DF_WRITE)
  1191. && (_pgfst->TestMapState(FSTSTATE_DIRTY) ) )
  1192. {
  1193. #ifdef LARGE_DOCFILE
  1194. ULONGLONG ret;
  1195. #else
  1196. ULONG ret;
  1197. #endif
  1198. ULONG cbFileSize = _pgfst->GetMappedFileSize();
  1199. ret = SeekTo( cbFileSize );
  1200. #ifdef LARGE_DOCFILE
  1201. if (ret == MAX_ULONGLONG) // 0xFFFFFFFFFFFFFFFF
  1202. #else
  1203. if (ret == 0xFFFFFFFF)
  1204. #endif
  1205. {
  1206. filestDebug((DEB_ERROR,
  1207. "File Seek in TurnOffMapping failed err=0x%x\n",
  1208. GetLastError()));
  1209. return S_OK;
  1210. }
  1211. filestDebug((DEB_MAP,
  1212. "File=%2x TurnOffMapping->SetEndOfFile 0x%06x\n",
  1213. _hFile, cbFileSize));
  1214. if(FALSE == SetEndOfFile(_hFile))
  1215. {
  1216. filestDebug((DEB_WARN,
  1217. "File=%2x SetEndOfFile in TurnOffMapping Failed. "
  1218. "file may still be open 'seperately'\n",
  1219. _hFile));
  1220. }
  1221. }
  1222. filestDebug((DEB_ITRACE, "Out TurnOffMapping => S_OK\n"));
  1223. return S_OK;
  1224. }
  1225. //+--------------------------------------------------------------
  1226. //
  1227. // Member: CFileStream::ExtendMapView, private
  1228. //
  1229. // Synopsis: Unmaps the Map object and creates a bigger View based
  1230. // on the new request size. The cbRequest is the requested
  1231. // real size. So we make a view larger than that to leave room.
  1232. //
  1233. // Returns: S_OK - When the mapping is added to the address space.
  1234. // E_OUTOFMEMORY - When the attempt to map the file failed.
  1235. //
  1236. // History: 20-Feb-97 BChapman Created.
  1237. //
  1238. //---------------------------------------------------------------
  1239. #define MAX_MAPVIEW_GROWTH (5*1024*1024)
  1240. SCODE CFileStream::ExtendMapView(ULONG cbRequest)
  1241. {
  1242. ULONG dwPageFlag;
  1243. ULONG cbNewView;
  1244. //
  1245. // Confirm that we were not needlessly called.
  1246. //
  1247. fsAssert(cbRequest > _cbViewSize);
  1248. //
  1249. // If the mapping is small, then grow it by doubling.
  1250. // If the mapping is big add a fixed amount.
  1251. //
  1252. if(cbRequest < MAX_MAPVIEW_GROWTH)
  1253. cbNewView = cbRequest * 2;
  1254. else
  1255. cbNewView = cbRequest + MAX_MAPVIEW_GROWTH;
  1256. //
  1257. // Someone else may have grown the mapping a huge amount.
  1258. // If that is the case then increase the New View to include the
  1259. // entire existing file.
  1260. //
  1261. if(cbNewView < _pgfst->GetMappedFileSize())
  1262. cbNewView = _pgfst->GetMappedFileSize();
  1263. filestDebug((DEB_MAP,
  1264. "File=%2x Mapping view is being grown from 0x%06x to 0x%06x\n",
  1265. _hFile, _cbViewSize, cbNewView));
  1266. //
  1267. // Unmap the View and re-map it at more than the currenly needed size.
  1268. //
  1269. filestDebug((DEB_MAP, "File=%2x Detaching Map 0x%07x to grow it.\n",
  1270. _hFile, _pbBaseAddr));
  1271. fsVerify(UnmapViewOfFile(_pbBaseAddr));
  1272. _pbBaseAddr = NULL;
  1273. //
  1274. // We know the mode must be read/write because we are growing.
  1275. //
  1276. if(FAILED(MapView(cbNewView, PAGE_READWRITE, 0)))
  1277. {
  1278. TurnOffAllMappings();
  1279. return E_OUTOFMEMORY;
  1280. }
  1281. return S_OK;
  1282. }
  1283. //+--------------------------------------------------------------
  1284. // Helper routine to round up memory request in a consistant manner.
  1285. //+--------------------------------------------------------------
  1286. ULONG BlockUpCommit(ULONG x) {
  1287. return((x+COMMIT_BLOCK-1) & (~(COMMIT_BLOCK-1)));
  1288. }
  1289. //+--------------------------------------------------------------
  1290. //
  1291. // Member: CFileStream::MakeFileMapAddressValidWorker, private
  1292. //
  1293. // Synopsis: Commits reserved pages that extend a writable
  1294. // Memory Mapped file. Used by WriteAt and SetSize.
  1295. //
  1296. // Returns: S_OK - When the mapping is added to the address space.
  1297. // E_OUTOFMEMORY - When the attempt to map the file failed.
  1298. //
  1299. // History: 31-Oct-96 BChapman Created.
  1300. //
  1301. //---------------------------------------------------------------
  1302. SCODE CFileStream::MakeFileMapAddressValidWorker(
  1303. ULONG cbRequested,
  1304. ULONG cbCommitedSize)
  1305. {
  1306. ULONG cbNeeded;
  1307. ULONG iStart, cbGrown;
  1308. SCODE sc;
  1309. filestDebug((DEB_ITRACE|DEB_MAP,
  1310. "File=%2x MakeFileMappingAddressValidWorker(0x%06x)\n",
  1311. _hFile, cbRequested));
  1312. // Assert we are not completely confused.
  1313. fsAssert(IsFileMapped());
  1314. fsAssert(cbCommitedSize >= _pgfst->GetMappedFileSize());
  1315. // Assert we were called correctly.
  1316. fsAssert(cbCommitedSize == _pgfst->GetMappedCommitSize());
  1317. fsAssert(cbRequested > cbCommitedSize);
  1318. //
  1319. // We allocate pages in clumps to cut down on little VirtualAlloc calls.
  1320. //
  1321. cbNeeded = BlockUpCommit(cbRequested);
  1322. //
  1323. // If the needed commit size is bigger than the view window, then
  1324. // make the view size bigger first.
  1325. //
  1326. if(FAILED(CheckMapView(cbNeeded)))
  1327. return E_OUTOFMEMORY;
  1328. //
  1329. // Now commit the new pages.
  1330. //
  1331. iStart = cbCommitedSize;
  1332. cbGrown = cbNeeded - cbCommitedSize;
  1333. filestDebug((DEB_MAP,
  1334. "File=%2x VirtualAlloc map=0x%07x[0x%06x] + 0x%06x(0x%06x)\n",
  1335. _hFile, _pbBaseAddr,
  1336. iStart, cbGrown, cbNeeded));
  1337. if(NULL==VirtualAlloc(
  1338. (void*)&_pbBaseAddr[iStart],
  1339. cbGrown,
  1340. MEM_COMMIT,
  1341. PAGE_READWRITE))
  1342. {
  1343. // Ran out of Virtual Memory or Filesystem disk space.
  1344. filestDebug((DEB_ERROR|DEB_MAP,
  1345. "File=%2x VirtualAlloc(%x + %x) 1st Failure=%x.\n",
  1346. _hFile,
  1347. &_pbBaseAddr[iStart],
  1348. cbGrown,
  1349. GetLastError()));
  1350. //
  1351. // If the VirutalAlloc failed we try again. The original
  1352. // request was rounded up to some large block size so there
  1353. // is a slim hope that we might get just what we need.
  1354. //
  1355. cbNeeded = cbRequested;
  1356. cbGrown = cbNeeded - cbCommitedSize;
  1357. filestDebug((DEB_MAP,
  1358. "File=%2x Retry VirtualAlloc map=0x%07x[0x%06x] + 0x%06x(0x%06x)\n",
  1359. _hFile, _pbBaseAddr,
  1360. iStart, cbGrown, cbNeeded));
  1361. if(NULL==VirtualAlloc(
  1362. (void*)&_pbBaseAddr[iStart],
  1363. cbGrown,
  1364. MEM_COMMIT,
  1365. PAGE_READWRITE))
  1366. {
  1367. // Ran out of Virtual Memory or Filesystem disk space.
  1368. filestDebug((DEB_ERROR|DEB_MAP,
  1369. "File=%2x VirtualAlloc(%x + %x) 2nd Failure=%x.\n",
  1370. _hFile,
  1371. &_pbBaseAddr[iStart],
  1372. cbGrown,
  1373. GetLastError()));
  1374. TurnOffMapping(TRUE);
  1375. if (_pgfst != NULL)
  1376. _pgfst->ResetMapState(FSTSTATE_MAPPED);
  1377. return E_OUTOFMEMORY;
  1378. }
  1379. }
  1380. _pgfst->SetMappedCommitSize(cbNeeded);
  1381. return S_OK;
  1382. }
  1383. #endif // Memory Mapped File Support
  1384. //+---------------------------------------------------------------------------
  1385. //
  1386. // Member: CFileStream::InitFromHandle, public
  1387. //
  1388. // Synopsis: Creates a filestream by duping an existing handle
  1389. //
  1390. // Arguments: [h] - Handle
  1391. //
  1392. // Returns: Appropriate status code
  1393. //
  1394. // History: 09-Feb-94 DrewB Created
  1395. //
  1396. // Notes: Intended only for creating a temporary ILockBytes on a file;
  1397. // does not create a true CFileStream; there is no
  1398. // global filestream, no access flags, etc.
  1399. //
  1400. //----------------------------------------------------------------------------
  1401. SCODE CFileStream::InitFromHandle(HANDLE h)
  1402. {
  1403. SCODE sc;
  1404. filestDebug((DEB_ITRACE, "In CFileStream::InitFromHandle:%p(%p)\n",
  1405. this, h));
  1406. if (!DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), &_hFile,
  1407. 0, FALSE, DUPLICATE_SAME_ACCESS))
  1408. {
  1409. sc = LAST_STG_SCODE;
  1410. }
  1411. else
  1412. {
  1413. sc = S_OK;
  1414. }
  1415. filestDebug((DEB_ITRACE, "Out CFileStream::InitFromHandle\n"));
  1416. return sc;
  1417. }
  1418. //+--------------------------------------------------------------
  1419. //
  1420. // Member: CFileStream::~CFileStream, public
  1421. //
  1422. // Synopsis: Destructor
  1423. //
  1424. // History: 20-Feb-92 DrewB Created
  1425. //
  1426. //---------------------------------------------------------------
  1427. CFileStream::~CFileStream(void)
  1428. {
  1429. filestDebug((DEB_ITRACE, "In CFileStream::~CFileStream()\n"));
  1430. fsAssert(_cReferences == 0);
  1431. _sig = CFILESTREAM_SIGDEL;
  1432. CheckSeekPointer();
  1433. if (INVALID_FH != _hPreDuped)
  1434. fsVerify(CloseHandle(_hPreDuped));
  1435. if (INVALID_FH != _hFile)
  1436. {
  1437. filestDebug((DEB_INFO, "~CFileStream %p handle %p thread %lX\n",
  1438. this, _hFile, GetCurrentThreadId()));
  1439. //
  1440. // A CFileStream normally _always_ had a global object connected
  1441. // to it. But due to the abuses of the Debug Logger we need to
  1442. // check this here. Also see "CFileStream::InitFromHandle"
  1443. //
  1444. if(_pgfst)
  1445. TurnOffMapping(FALSE);
  1446. fsVerify(CloseHandle(_hFile));
  1447. #ifdef ASYNC
  1448. if ((_pgfst) &&
  1449. (_pgfst->GetTerminationStatus() == TERMINATED_ABNORMAL))
  1450. {
  1451. WCHAR *pwcsName;
  1452. SCODE sc = GetName(&pwcsName);
  1453. if (SUCCEEDED(sc))
  1454. {
  1455. DeleteTheFile(pwcsName);
  1456. TaskMemFree(pwcsName);
  1457. }
  1458. }
  1459. #endif //ASYNC
  1460. }
  1461. if (_hReserved != INVALID_FH)
  1462. {
  1463. filestDebug((DEB_INFO, "~CFileStream reserved %p "
  1464. "handle %p thread %lX\n",
  1465. this, _hReserved, GetCurrentThreadId()));
  1466. fsVerify(CloseHandle(_hReserved));
  1467. _hReserved = INVALID_FH;
  1468. }
  1469. if (_pgfst)
  1470. {
  1471. _pgfst->Remove(this);
  1472. if (_pgfst->HasName())
  1473. {
  1474. if (0 == _pgfst->CountContexts())
  1475. {
  1476. // Delete zero length files also. A zero length file
  1477. // is not a valid docfile so don't leave them around
  1478. if (_pgfst->GetStartFlags() & RSF_DELETEONRELEASE)
  1479. {
  1480. // This is allowed to fail if somebody
  1481. // else has the file open
  1482. DeleteTheFile(_pgfst->GetName());
  1483. }
  1484. }
  1485. }
  1486. _pgfst->Release();
  1487. }
  1488. filestDebug((DEB_ITRACE, "Out CFileStream::~CFileStream\n"));
  1489. }
  1490. //+--------------------------------------------------------------
  1491. //
  1492. // Member: CFileStream::ReadAt, public
  1493. //
  1494. // Synopsis: Reads bytes at a specific point in a stream
  1495. //
  1496. // Arguments: [ulPosition] - Offset in file to read at
  1497. // [pb] - Buffer
  1498. // [cb] - Count of bytes to read
  1499. // [pcbRead] - Return of bytes read
  1500. //
  1501. // Returns: Appropriate status code
  1502. //
  1503. // Modifies: [pcbRead]
  1504. //
  1505. // History: 20-Feb-92 DrewB Created
  1506. //
  1507. //---------------------------------------------------------------
  1508. STDMETHODIMP CFileStream::ReadAt(ULARGE_INTEGER ulPosition,
  1509. VOID *pb,
  1510. ULONG cb,
  1511. ULONG *pcbRead)
  1512. {
  1513. SCODE sc;
  1514. LONG lHigh = ULIGetHigh(ulPosition);
  1515. ULONG uLow = ULIGetLow(ulPosition);
  1516. #ifdef ASYNC
  1517. fsAssert((_ppc == NULL) || (_ppc->HaveMutex()));
  1518. #endif
  1519. fsAssert((!IsFileMapped() || lHigh == 0) &&
  1520. aMsg("High dword other than zero passed to filestream."));
  1521. filestDebug((DEB_ITRACE, "In CFileStream::ReadAt("
  1522. "%x:%x, %p, %x, %p)\n", ULIGetHigh(ulPosition),
  1523. ULIGetLow(ulPosition), pb, cb, pcbRead));
  1524. CheckSeekPointer();
  1525. fsAssert(_hFile != INVALID_FH);
  1526. *pcbRead = 0;
  1527. #ifdef ASYNC
  1528. DWORD dwTerminate;
  1529. dwTerminate = _pgfst->GetTerminationStatus();
  1530. if (dwTerminate == TERMINATED_ABNORMAL)
  1531. {
  1532. sc = STG_E_INCOMPLETE;
  1533. }
  1534. else if ((dwTerminate != TERMINATED_NORMAL) &&
  1535. #ifdef LARGE_DOCFILE
  1536. (ulPosition.QuadPart + cb > _pgfst->GetHighWaterMark()))
  1537. #else
  1538. (uLow + cb > _pgfst->GetHighWaterMark()))
  1539. #endif
  1540. {
  1541. *pcbRead = 0;
  1542. #ifdef LARGE_DOCFILE
  1543. _pgfst->SetFailurePoint(cb + ulPosition.QuadPart);
  1544. #else
  1545. _pgfst->SetFailurePoint(cb + uLow);
  1546. #endif
  1547. sc = E_PENDING;
  1548. }
  1549. else
  1550. {
  1551. #endif
  1552. if(!IsFileMapped())
  1553. { // Read w/ ReadFile()
  1554. #ifdef LARGE_DOCFILE
  1555. sc = ReadAt_FromFile(ulPosition.QuadPart, pb, cb, pcbRead);
  1556. #else
  1557. sc = ReadAt_FromFile(uLow, pb, cb, pcbRead);
  1558. #endif
  1559. }
  1560. else
  1561. { // Read from Map
  1562. sc = ReadAt_FromMap(uLow, pb, cb, pcbRead);
  1563. if (!SUCCEEDED(sc))
  1564. #ifdef LARGE_DOCFILE
  1565. sc = ReadAt_FromFile(ulPosition.QuadPart, pb, cb, pcbRead);
  1566. #else
  1567. sc = ReadAt_FromFile(uLow, pb, cb, pcbRead);
  1568. #endif
  1569. }
  1570. #ifdef ASYNC
  1571. }
  1572. #endif
  1573. olLowLog(("STGIO - Read : %8x at %8x, %8d, %8d <--\n", _hFile, uLow, cb, *pcbRead));
  1574. filestDebug((DEB_ITRACE, "Out CFileStream::ReadAt => %x\n", sc));
  1575. CheckSeekPointer();
  1576. return sc;
  1577. }
  1578. #ifdef USE_FILEMAPPING
  1579. //+--------------------------------------------------------------
  1580. //
  1581. // Member: CFileStream::ReadAt_FromMap, private
  1582. //
  1583. // Synopsis: Reads bytes at a specific point from the file mapping
  1584. //
  1585. // Arguments: [iPosition] - Offset in file
  1586. // [pb] - Buffer
  1587. // [cb] - Count of bytes to read
  1588. // [pcbRead] - Return of bytes read
  1589. //
  1590. // Returns: Appropriate status code
  1591. //
  1592. // Modifies: [pcbRead]
  1593. //
  1594. // History: 16-Jan-97 BChapman Created
  1595. //
  1596. //---------------------------------------------------------------
  1597. SCODE CFileStream::ReadAt_FromMap(
  1598. ULONG iPosition,
  1599. VOID *pb,
  1600. ULONG cb,
  1601. ULONG *pcbRead)
  1602. {
  1603. SCODE sc = S_OK;
  1604. ULONG cbRead=0;
  1605. ULONG cbFileSize = _pgfst->GetMappedFileSize();
  1606. //
  1607. // If any of the read is before the End of File then
  1608. // we can read something. Reads at EOF
  1609. //
  1610. *pcbRead = 0;
  1611. if (iPosition < cbFileSize)
  1612. {
  1613. ULONG cbTail;
  1614. filestDebug((DEB_MAPIO,
  1615. "File=%2x Read MapFile @ 0x%06x, 0x%04x, bytes\n",
  1616. _hFile, iPosition, cb));
  1617. //
  1618. // Possibly shorted the read request to fit inside
  1619. // the logical End of File.
  1620. //
  1621. cbTail = cbFileSize - iPosition;
  1622. if (cb < cbTail)
  1623. cbRead = cb;
  1624. else
  1625. cbRead = cbTail;
  1626. if(cb != cbRead)
  1627. {
  1628. filestDebug((DEB_MAPIO,
  1629. "File=%2x\t\t(Short Read 0x%04x bytes)\n",
  1630. _hFile, cbRead));
  1631. }
  1632. sc = CheckMapView(iPosition+cbRead);
  1633. if (SUCCEEDED(sc))
  1634. {
  1635. __try
  1636. {
  1637. memcpy (pb, _pbBaseAddr+iPosition, cbRead);
  1638. *pcbRead = cbRead;
  1639. }
  1640. __except (EXCEPTION_EXECUTE_HANDLER)
  1641. {
  1642. filestDebug((DEB_WARN|DEB_MAP,
  1643. "File=%2x Mapfile READFAULT Xfer 0x%x bytes @ 0x%x %x\n",
  1644. _hFile, cbRead, iPosition, GetExceptionCode()));
  1645. sc = STG_E_READFAULT;
  1646. }
  1647. }
  1648. else // lost the file mapping
  1649. sc = ReadAt_FromFile(iPosition, pb, cb, pcbRead);
  1650. }
  1651. else
  1652. {
  1653. if(cbFileSize < iPosition)
  1654. {
  1655. filestDebug((DEB_WARN|DEB_MAP,
  1656. "File=%2x Read MapFile @ 0x%x, 0x%x bytes is entirely "
  1657. "off the end @ 0x%x\n",
  1658. _hFile, iPosition, cb, cbFileSize));
  1659. fsAssert(cbFileSize > iPosition);
  1660. }
  1661. }
  1662. filestDebug((DEB_ITRACE, "Out CFileStream::ReadAt => %x\n", sc));
  1663. return sc;
  1664. }
  1665. #endif // USE_FILEMAPPING
  1666. //+--------------------------------------------------------------
  1667. //
  1668. // Member: CFileStream::ReadAt_FromFile, private
  1669. //
  1670. // Synopsis: Reads bytes at a specific point from the file mapping
  1671. //
  1672. // Arguments: [iPosition] - Offset in file
  1673. // [pb] - Buffer
  1674. // [cb] - Count of bytes to read
  1675. // [pcbRead] - Return of bytes read
  1676. //
  1677. // Returns: Appropriate status code
  1678. //
  1679. // Modifies: [pcbRead]
  1680. //
  1681. // History: 16-Jan-97 BChapman Created
  1682. //
  1683. //---------------------------------------------------------------
  1684. SCODE CFileStream::ReadAt_FromFile(
  1685. #ifdef LARGE_DOCFILE
  1686. ULONGLONG iPosition,
  1687. #else
  1688. ULONG iPosition,
  1689. #endif
  1690. VOID *pb,
  1691. ULONG cb,
  1692. ULONG *pcbRead)
  1693. {
  1694. SCODE sc = S_OK;
  1695. if(0 == cb)
  1696. {
  1697. *pcbRead = 0;
  1698. return S_OK;
  1699. }
  1700. #ifndef USE_OVERLAPPED
  1701. negChk(SeekTo(iPosition));
  1702. filestDebug((DEB_FILEIO,
  1703. "File=%2x ReadFile (old code) @ 0x%06x, 0x%04x bytes\n",
  1704. _hFile, iPosition, cb));
  1705. boolChk(ReadFile(_hFile, pb, cb, pcbRead, NULL));
  1706. if(cb != *pcbRead)
  1707. {
  1708. filestDebug((DEB_FILEIO,
  1709. "File=%2x\t\t(Short read 0x%x bytes)\n",
  1710. _hFile, *pcbRead));
  1711. }
  1712. #else // ifndef USE_OVERLAPPED
  1713. if (!FilePointerEqual(iPosition))
  1714. {
  1715. OVERLAPPED Overlapped;
  1716. #ifdef LARGE_DOCFILE
  1717. LARGE_INTEGER ulPosition;
  1718. ulPosition.QuadPart = iPosition;
  1719. Overlapped.Offset = ulPosition.LowPart;
  1720. Overlapped.OffsetHigh = ulPosition.HighPart;
  1721. #else
  1722. Overlapped.Offset = iPosition;
  1723. Overlapped.OffsetHigh = 0;
  1724. #endif
  1725. Overlapped.hEvent = NULL;
  1726. filestDebug((DEB_FILEIO,
  1727. "File=%2x ReadFile (w/seek) @ 0x%06x, 0x%04x bytes\n",
  1728. _hFile, (ULONG)iPosition, cb));
  1729. if (!ReadFile(_hFile, pb, cb, pcbRead, &Overlapped))
  1730. {
  1731. if (GetLastError() != ERROR_HANDLE_EOF)
  1732. fsErr(EH_Err, LAST_STG_SCODE);
  1733. }
  1734. }
  1735. else
  1736. {
  1737. filestDebug((DEB_FILEIO,
  1738. "File=%2x ReadFile @ 0x%Lx, 0x%04x bytes\n",
  1739. _hFile, iPosition, cb));
  1740. boolChk(ReadFile(_hFile, pb, cb, pcbRead, NULL));
  1741. }
  1742. if(cb != *pcbRead)
  1743. {
  1744. filestDebug((DEB_FILEIO,
  1745. "File=%2x\t\t(Short read 0x%04x bytes)\n",
  1746. _hFile, *pcbRead));
  1747. }
  1748. #endif // USE_OVERLAPPED
  1749. // if 0 bytes were read, the seek pointer has not changed
  1750. if (*pcbRead > 0)
  1751. SetCachedFilePointer(iPosition + *pcbRead);
  1752. return S_OK;
  1753. EH_Err:
  1754. filestDebug((DEB_ERROR|DEB_FILEIO, "ReadAt_FromFile Error = %x\n", sc));
  1755. return sc;
  1756. }
  1757. //+--------------------------------------------------------------
  1758. //
  1759. // Member: CFileStream::WriteAt, public
  1760. //
  1761. // Synopsis: Writes bytes at a specific point in a stream
  1762. //
  1763. // Arguments: [ulPosition] - Offset in file
  1764. // [pb] - Buffer
  1765. // [cb] - Count of bytes to write
  1766. // [pcbWritten] - Return of bytes written
  1767. //
  1768. // Returns: Appropriate status code
  1769. //
  1770. // Modifies: [pcbWritten]
  1771. //
  1772. // History: 20-Feb-92 DrewB Created
  1773. //
  1774. //---------------------------------------------------------------
  1775. STDMETHODIMP CFileStream::WriteAt(ULARGE_INTEGER ulPosition,
  1776. VOID const *pb,
  1777. ULONG cb,
  1778. ULONG *pcbWritten)
  1779. {
  1780. SCODE sc;
  1781. LONG lHigh = ULIGetHigh(ulPosition);
  1782. ULONG uLow = ULIGetLow(ulPosition);
  1783. #ifdef ASYNC
  1784. fsAssert((_ppc == NULL) || (_ppc->HaveMutex()));
  1785. #endif
  1786. #ifndef LARGE_DOCFILE
  1787. fsAssert(lHigh == 0 &&
  1788. aMsg("High dword other than zero passed to filestream."));
  1789. #endif
  1790. filestDebug((DEB_ITRACE, "In CFileStream::WriteAt:%p("
  1791. "%x:%x, %p, %x, %p)\n", this, ULIGetHigh(ulPosition),
  1792. ULIGetLow(ulPosition), pb, cb, pcbWritten));
  1793. #ifdef ASYNC
  1794. DWORD dwTerminate;
  1795. dwTerminate = _pgfst->GetTerminationStatus();
  1796. if (dwTerminate == TERMINATED_ABNORMAL)
  1797. {
  1798. sc = STG_E_INCOMPLETE;
  1799. }
  1800. else if ((dwTerminate == TERMINATED_NORMAL) ||
  1801. (uLow + cb <= _pgfst->GetHighWaterMark()))
  1802. {
  1803. #endif
  1804. #ifdef LARGE_DOCFILE
  1805. sc = WriteAtWorker(ulPosition, pb, cb, pcbWritten);
  1806. #else
  1807. sc = WriteAtWorker(uLow, pb, cb, pcbWritten);
  1808. #endif
  1809. #ifdef ASYNC
  1810. }
  1811. else
  1812. {
  1813. *pcbWritten = 0;
  1814. #ifdef LARGE_DOCFILE
  1815. _pgfst->SetFailurePoint(cb + ulPosition.QuadPart);
  1816. #else
  1817. _pgfst->SetFailurePoint(cb + uLow);
  1818. #endif
  1819. sc = E_PENDING;
  1820. }
  1821. #endif
  1822. filestDebug((DEB_ITRACE, "Out CFileStream::WriteAt => %x\n", sc));
  1823. return sc;
  1824. }
  1825. #ifdef LARGE_DOCFILE
  1826. SCODE CFileStream::WriteAtWorker(ULARGE_INTEGER ulPosition,
  1827. #else
  1828. SCODE CFileStream::WriteAtWorker(ULONG uLow,
  1829. #endif
  1830. VOID const *pb,
  1831. ULONG cb,
  1832. ULONG *pcbWritten)
  1833. {
  1834. SCODE sc;
  1835. #ifdef LARGE_DOCFILE
  1836. ULONG uLow = ulPosition.LowPart;
  1837. #endif
  1838. CheckSeekPointer();
  1839. fsAssert(_hFile != INVALID_FH);
  1840. *pcbWritten = 0;
  1841. #ifdef LARGE_DOCFILE
  1842. fsChk(PossibleDiskFull(ulPosition.QuadPart + cb));
  1843. #else
  1844. fsChk(PossibleDiskFull(uLow + cb));
  1845. #endif
  1846. #ifdef USE_FILEMAPPING
  1847. #ifdef LARGE_DOCFILE
  1848. if (ulPosition.QuadPart + cb < MAX_ULONG/2)
  1849. MakeFileMapAddressValid(uLow + cb);
  1850. else
  1851. TurnOffMapping(TRUE);
  1852. #else
  1853. MakeFileMapAddressValid(uLow + cb);
  1854. #endif
  1855. if (IsFileMapped())
  1856. {
  1857. filestDebug((DEB_MAPIO,
  1858. "File=%2x Write Mapfile @ 0x%06x, 0x%04x bytes\n",
  1859. _hFile, uLow, cb));
  1860. __try
  1861. {
  1862. memcpy (_pbBaseAddr+uLow, pb, cb);
  1863. }
  1864. __except (EXCEPTION_EXECUTE_HANDLER)
  1865. {
  1866. filestDebug((DEB_WARN|DEB_MAP,
  1867. "File=%2x Mapfile WRITEFAULT Xfer 0x%x bytes @ 0x%x %x\n",
  1868. _hFile, cb, uLow, GetExceptionCode()));
  1869. return STG_E_WRITEFAULT;
  1870. }
  1871. *pcbWritten = cb;
  1872. _pgfst->SetMapState(FSTSTATE_DIRTY);
  1873. if(_pgfst->GetMappedFileSize() < uLow + cb)
  1874. _pgfst->SetMappedFileSize(uLow + cb);
  1875. return S_OK;
  1876. }
  1877. #endif
  1878. #ifndef USE_OVERLAPPED
  1879. #ifdef LARGE_DOCFILE
  1880. negChk(SeekTo(ulPosition.QuadPart));
  1881. #else
  1882. negChk(SeekTo(uLow));
  1883. #endif
  1884. filestDebug((DEB_FILEIO,
  1885. "File=%2x WriteFile (old code) @ 0x%06x, 0x%04x bytes\n",
  1886. _hFile, uLow, cb));
  1887. boolChk(WriteFile(_hFile, pb, cb, pcbWritten, NULL));
  1888. #else // ifndef USE_OVERLAPPED
  1889. #ifdef LARGE_DOCFILE
  1890. if (!FilePointerEqual(ulPosition.QuadPart))
  1891. #else
  1892. if (!FilePointerEqual(uLow))
  1893. #endif
  1894. {
  1895. OVERLAPPED Overlapped;
  1896. #ifdef LARGE_DOCFILE
  1897. Overlapped.Offset = ulPosition.LowPart;
  1898. Overlapped.OffsetHigh = ulPosition.HighPart;
  1899. #else
  1900. Overlapped.Offset = uLow;
  1901. Overlapped.OffsetHigh = 0;
  1902. #endif
  1903. Overlapped.hEvent = NULL;
  1904. filestDebug((DEB_FILEIO,
  1905. "File=%2x WriteFile (w/seek) @ 0x%06x, 0x%04x bytes\n",
  1906. _hFile, uLow, cb));
  1907. boolChk(WriteFile(_hFile, pb, cb, pcbWritten,&Overlapped));
  1908. }
  1909. else
  1910. {
  1911. filestDebug((DEB_FILEIO,
  1912. "File=%2x WriteFile @ 0x%06x, 0x%04x bytes\n",
  1913. _hFile, uLow, cb));
  1914. boolChk(WriteFile(_hFile, pb, cb, pcbWritten, NULL));
  1915. }
  1916. #endif
  1917. #ifdef LARGE_DOCFILE
  1918. SetCachedFilePointer(ulPosition.QuadPart + *pcbWritten);
  1919. #else
  1920. SetCachedFilePointer(uLow + *pcbWritten);
  1921. #endif
  1922. if(_pgfst->GetMappedFileSize() < uLow + cb)
  1923. _pgfst->SetMappedFileSize(uLow + cb);
  1924. olLowLog(("STGIO - Write: %8x at %8x, %8d, %8d -->\n", _hFile, uLow, cb, *pcbWritten));
  1925. sc = S_OK;
  1926. EH_Err:
  1927. CheckSeekPointer();
  1928. return ResultFromScode(sc);
  1929. }
  1930. //+--------------------------------------------------------------
  1931. //
  1932. // Member: CFileStream::Flush, public
  1933. //
  1934. // Synopsis: Flushes buffers
  1935. //
  1936. // Returns: Appropriate status code
  1937. //
  1938. // History: 24-Mar-92 DrewB Created
  1939. //
  1940. //---------------------------------------------------------------
  1941. STDMETHODIMP CFileStream::Flush(void)
  1942. {
  1943. CheckSeekPointer();
  1944. #if WIN32 == 200
  1945. SCODE sc = S_OK;
  1946. if (_hReserved == INVALID_FH)
  1947. {
  1948. if (!DuplicateHandle(GetCurrentProcess(), _hFile, GetCurrentProcess(),
  1949. &_hReserved, 0, FALSE, DUPLICATE_SAME_ACCESS))
  1950. {
  1951. //We couldn't get a handle, so flush everything just to be
  1952. //safe.
  1953. sc = FlushCache();
  1954. }
  1955. else
  1956. {
  1957. fsAssert(_hReserved != INVALID_FH);
  1958. fsVerify(CloseHandle(_hReserved));
  1959. _hReserved = INVALID_FH;
  1960. }
  1961. }
  1962. else
  1963. {
  1964. //In this case, we already have a duplicate of the file handle
  1965. // reserved, so close it, then reopen it again.
  1966. fsVerify(CloseHandle(_hReserved));
  1967. _hReserved = INVALID_FH;
  1968. }
  1969. if ((_hReserved == INVALID_FH) && (_grfLocal & LFF_RESERVE_HANDLE))
  1970. {
  1971. //Reacquire reserved handle.
  1972. //If this fails there isn't anything we can do about it. We'll
  1973. // try to reacquire the handle later when we really need it.
  1974. DuplicateHandle(GetCurrentProcess(), _hFile, GetCurrentProcess(),
  1975. &_hReserved, 0, FALSE, DUPLICATE_SAME_ACCESS);
  1976. }
  1977. return ResultFromScode(sc);
  1978. #else
  1979. // Otherwise on NT, the file system does the right thing, we think.
  1980. return S_OK;
  1981. #endif
  1982. }
  1983. //+--------------------------------------------------------------
  1984. //
  1985. // Member: CFileStream::FlushCache, public
  1986. //
  1987. // Synopsis: Flushes buffers
  1988. //
  1989. // Returns: Appropriate status code
  1990. //
  1991. // History: 12-Feb-93 AlexT Created
  1992. //
  1993. // Notes:
  1994. //
  1995. //---------------------------------------------------------------
  1996. STDMETHODIMP CFileStream::FlushCache(void)
  1997. {
  1998. SCODE sc;
  1999. filestDebug((DEB_ITRACE, "In CFileStream::Flush()\n"));
  2000. CheckSeekPointer();
  2001. fsAssert(_hFile != INVALID_FH);
  2002. boolChk(FlushFileBuffers(_hFile));
  2003. if (IsFileMapped())
  2004. boolChk(FlushViewOfFile(_pbBaseAddr, 0));
  2005. sc = S_OK;
  2006. filestDebug((DEB_ITRACE, "Out CFileStream::Flush\n"));
  2007. EH_Err:
  2008. CheckSeekPointer();
  2009. return ResultFromScode(sc);
  2010. }
  2011. //+--------------------------------------------------------------
  2012. //
  2013. // Member: CFileStream::SetSize, public
  2014. //
  2015. // Synopsis: Sets the size of the LStream
  2016. //
  2017. // Arguments: [ulSize] - New size
  2018. //
  2019. // Returns: Appropriate status code
  2020. //
  2021. // History: 20-Feb-92 DrewB Created
  2022. //
  2023. //---------------------------------------------------------------
  2024. STDMETHODIMP CFileStream::SetSize(ULARGE_INTEGER ulSize)
  2025. {
  2026. SCODE sc;
  2027. #ifdef ASYNC
  2028. fsAssert((_ppc == NULL) || (_ppc->HaveMutex()));
  2029. #endif
  2030. #ifndef LARGE_DOCFILE
  2031. ULONG uLow = ULIGetLow(ulSize);
  2032. LONG lHigh = ULIGetHigh(ulSize);
  2033. fsAssert(lHigh == 0 &&
  2034. aMsg("High dword other than zero passed to filestream."));
  2035. #endif
  2036. filestDebug((DEB_ITRACE, "In CFileStream::SetSize:%p(%Lx)\n",
  2037. this, ulSize.QuadPart));
  2038. #ifdef ASYNC
  2039. DWORD dwTerminate;
  2040. dwTerminate = _pgfst->GetTerminationStatus();
  2041. if (dwTerminate == TERMINATED_ABNORMAL)
  2042. {
  2043. sc = STG_E_INCOMPLETE;
  2044. }
  2045. else if ((dwTerminate == TERMINATED_NORMAL) ||
  2046. #ifdef LARGE_DOCFILE
  2047. (ulSize.QuadPart <= _pgfst->GetHighWaterMark()))
  2048. #else
  2049. (uLow <= _pgfst->GetHighWaterMark()))
  2050. #endif
  2051. {
  2052. #endif
  2053. #ifdef LARGE_DOCFILE
  2054. sc = SetSizeWorker(ulSize.QuadPart);
  2055. #else
  2056. sc = SetSizeWorker(uLow);
  2057. #endif
  2058. #ifdef ASYNC
  2059. }
  2060. else
  2061. {
  2062. #ifdef LARGE_DOCFILE
  2063. _pgfst->SetFailurePoint(ulSize.QuadPart);
  2064. #else
  2065. _pgfst->SetFailurePoint(uLow);
  2066. #endif
  2067. sc = E_PENDING;
  2068. }
  2069. #endif
  2070. return sc;
  2071. }
  2072. //+--------------------------------------------------------------
  2073. //
  2074. // Member: CFileStream::SetSizeWorker, Private
  2075. //
  2076. // Synopsis: Sets the size of the File
  2077. //
  2078. // Arguments: [ulSize] - New size
  2079. //
  2080. // Returns: Appropriate status code
  2081. //
  2082. // History: 20-Feb-92 DrewB Created
  2083. // 16-Jan-97 BChapman Added Support for File Mapping
  2084. // 08-Mar-97 BChapman Fixes for File Mapping
  2085. //
  2086. // Note: If the file is mapped then we grow the file with VirtualAlloc
  2087. // and shrink it at unmap time with SetEndOfFile() and the intended
  2088. // size recorded in the _pgfst.
  2089. // If we are NOT mapped then we use normal File I/O. But things can
  2090. // get tricky if we are switching from mapped to unmapped and all the
  2091. // other marshalled opens have not yet unmapped. If anyone has the
  2092. // file mapped then SetEndOfFile doesn't work.
  2093. // To avoid this we grow with WriteFile() and we try to shrink with
  2094. // SetEndOfFile(). But we also always put the intended size in _pgfst,
  2095. // so if the other guy has the file mapped he will shrink the file
  2096. // when he unmaps.
  2097. //---------------------------------------------------------------
  2098. #ifdef LARGE_DOCFILE
  2099. SCODE CFileStream::SetSizeWorker(ULONGLONG ulSize)
  2100. #else
  2101. SCODE CFileStream::SetSizeWorker(ULONG uLow)
  2102. #endif
  2103. {
  2104. SCODE sc;
  2105. CheckSeekPointer();
  2106. fsAssert(_hFile != INVALID_FH);
  2107. #ifdef LARGE_DOCFILE
  2108. fsChk(PossibleDiskFull(ulSize));
  2109. if (ulSize < MAX_ULONG/2)
  2110. MakeFileMapAddressValid((ULONG)ulSize);
  2111. else
  2112. TurnOffMapping(TRUE);
  2113. #else
  2114. fsChk(PossibleDiskFull(uLow));
  2115. MakeFileMapAddressValid(uLow);
  2116. #endif
  2117. // Always record the intended size, because the mapped size is stored
  2118. // globaly. You might not be mapped but other marshalled opens could
  2119. // be (they will fall back as soon as they run).
  2120. #ifdef USE_FILEMAPPING
  2121. #ifdef LARGE_DOCFILE
  2122. // A memory mapped file can never be greater than 2G, even for 64-bit
  2123. // platforms, because of the range locks at offset 2G in the file.
  2124. _pgfst->SetMappedFileSize(ulSize > MAX_ULONG ? MAX_ULONG : (ULONG) ulSize);
  2125. #else
  2126. _pgfst->SetMappedFileSize(uLow);
  2127. #endif
  2128. _pgfst->SetMapState(FSTSTATE_DIRTY);
  2129. #endif // USE_FILEMAPPING
  2130. if(!IsFileMapped())
  2131. {
  2132. ULARGE_INTEGER uliFileSize;
  2133. ULONG ulZero=0;
  2134. DWORD cbWritten;
  2135. fsChk(GetSize(&uliFileSize));
  2136. #ifdef LARGE_DOCFILE
  2137. if(uliFileSize.QuadPart == ulSize)
  2138. #else
  2139. Assert (0 == uliFileSize.HighPart);
  2140. if(uliFileSize.LowPart == uLow)
  2141. #endif
  2142. {
  2143. #ifdef LARGE_DOCFILE
  2144. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%Lx)"
  2145. " size didn't change\n",
  2146. _hFile, ulSize));
  2147. #else
  2148. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%06x)"
  2149. " size didn't change\n",
  2150. _hFile, uLow));
  2151. #endif
  2152. return S_OK;
  2153. }
  2154. // Grow the file.
  2155. //
  2156. #ifdef LARGE_DOCFILE
  2157. if(uliFileSize.QuadPart < ulSize &&
  2158. !(_pgfst->GetDFlags() & DF_LARGE))
  2159. {
  2160. ULARGE_INTEGER uli;
  2161. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%Lx)"
  2162. " increasing from 0x%Lx\n",
  2163. _hFile, ulSize, uliFileSize));
  2164. uli.QuadPart = ulSize - 1;
  2165. fsChk(WriteAtWorker(uli, (LPCVOID)&ulZero, 1, &cbWritten));
  2166. }
  2167. #else
  2168. if(uliFileSize.LowPart < uLow)
  2169. {
  2170. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%06x)"
  2171. " increasing from 0x%06x\n",
  2172. _hFile, uLow, uliFileSize.LowPart));
  2173. fsChk(WriteAtWorker(uLow-1, (LPCVOID)&ulZero, 1, &cbWritten));
  2174. }
  2175. #endif
  2176. // Shrink the file or large sector docfile
  2177. //
  2178. else
  2179. {
  2180. #ifdef LARGE_DOCFILE
  2181. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%Lx)"
  2182. " reducing from 0x%Lx\n",
  2183. _hFile, ulSize, uliFileSize));
  2184. negChk(SeekTo(ulSize));
  2185. #else
  2186. filestDebug((DEB_FILEIO, "File=%2x SetSizeWorker(0x%06x)"
  2187. " reducing from 0x%06x\n",
  2188. _hFile, uLow, uliFileSize.LowPart));
  2189. negChk(SeekTo(uLow));
  2190. #endif
  2191. if(FALSE == SetEndOfFile(_hFile))
  2192. {
  2193. sc = LAST_STG_SCODE;
  2194. // If a seperate marshaling still has the file mapped then
  2195. // this will fail. But this particular error is OK.
  2196. //
  2197. if(WIN32_SCODE(ERROR_USER_MAPPED_FILE) == sc)
  2198. {
  2199. sc = S_OK;
  2200. }
  2201. fsChk (sc);
  2202. }
  2203. }
  2204. }
  2205. sc = S_OK;
  2206. filestDebug((DEB_ITRACE, "Out CFileStream::SetSize\n"));
  2207. EH_Err:
  2208. CheckSeekPointer();
  2209. return ResultFromScode(sc);
  2210. }
  2211. //+---------------------------------------------------------------------------
  2212. //
  2213. // Member: CFileStream::SeekTo, private
  2214. // CFileStream::GetFilePointer, private
  2215. //
  2216. // Synopsis: Wrap calls to SetFilePointer to make the usage more clear.
  2217. // Esp. in the GetFilePointer case.
  2218. //
  2219. // History: 07-Nov-96 BChapman Created
  2220. //
  2221. //----------------------------------------------------------------------------
  2222. #ifdef LARGE_DOCFILE
  2223. ULONGLONG CFileStream::SeekTo(ULONGLONG ulPos)
  2224. {
  2225. LARGE_INTEGER uliPos;
  2226. if(FilePointerEqual(ulPos))
  2227. {
  2228. filestDebug((DEB_SEEK, "File=%2x SeekTo(0x%Lx) (cache hit)\n",
  2229. _hFile, ulPos));
  2230. return ulPos;
  2231. }
  2232. uliPos.QuadPart = ulPos;
  2233. uliPos.LowPart =
  2234. SetFilePointer(_hFile, uliPos.LowPart, &uliPos.HighPart, FILE_BEGIN);
  2235. if (uliPos.LowPart == MAX_ULONG && GetLastError() != NO_ERROR)
  2236. return MAX_ULONGLONG; // 0xFFFFFFFFFFFFFFFF
  2237. SetCachedFilePointer(uliPos.QuadPart);
  2238. filestDebug((DEB_SEEK, "File=%2x SeekTo(0x%Lx)\n", _hFile, ulPos));
  2239. olLowLog(("STGIO - Seek : %8x at %Lx\n", _hFile, ulPos));
  2240. return uliPos.QuadPart;
  2241. }
  2242. ULONGLONG CFileStream::GetFilePointer()
  2243. {
  2244. LARGE_INTEGER ulPos = {0,0};
  2245. ulPos.LowPart = SetFilePointer(_hFile, 0, &ulPos.HighPart, FILE_CURRENT);
  2246. filestDebug((DEB_SEEK, "File=%2x GetFilePointer() => 0x%Lx\n",
  2247. _hFile, ulPos));
  2248. return ulPos.QuadPart;
  2249. }
  2250. #else
  2251. DWORD CFileStream::SeekTo(ULONG Low)
  2252. {
  2253. DWORD dwPos;
  2254. if(FilePointerEqual(Low))
  2255. {
  2256. filestDebug((DEB_SEEK, "File=%2x SeekTo(0x%06x) (cache hit)\n",
  2257. _hFile, Low));
  2258. return Low;
  2259. }
  2260. if(0xFFFFFFFF == (dwPos = SetFilePointer(_hFile, Low, NULL, FILE_BEGIN)))
  2261. return dwPos;
  2262. SetCachedFilePointer(dwPos);
  2263. filestDebug((DEB_SEEK, "File=%2x SeekTo(0x%06x)\n", _hFile, Low));
  2264. olLowLog(("STGIO - Seek : %8x at %8x\n", _hFile, Low));
  2265. return dwPos;
  2266. }
  2267. DWORD CFileStream::GetFilePointer()
  2268. {
  2269. DWORD dwPos = SetFilePointer(_hFile, 0, NULL, FILE_CURRENT);
  2270. filestDebug((DEB_SEEK, "File=%2x GetFilePointer() => 0x%06x\n",
  2271. _hFile, dwPos));
  2272. return dwPos;
  2273. }
  2274. #endif
  2275. //+--------------------------------------------------------------
  2276. //
  2277. // Member: CFileStream::LockRegion, public
  2278. //
  2279. // Synopsis: Gets a lock on a portion of the LStream
  2280. //
  2281. // Arguments: [ulStartOffset] - Lock start
  2282. // [cbLockLength] - Length
  2283. // [dwLockType] - Exclusive/Read only
  2284. //
  2285. // Returns: Appropriate status code
  2286. //
  2287. // History: 20-Feb-92 DrewB Created
  2288. //
  2289. //---------------------------------------------------------------
  2290. STDMETHODIMP CFileStream::LockRegion(ULARGE_INTEGER ulStartOffset,
  2291. ULARGE_INTEGER cbLockLength,
  2292. DWORD dwLockType)
  2293. {
  2294. SCODE sc;
  2295. filestDebug((DEB_ITRACE, "In CFileStream::LockRegion("
  2296. "%x:%x, %x:%x, %x)\n", ULIGetHigh(ulStartOffset),
  2297. ULIGetLow(ulStartOffset), ULIGetHigh(cbLockLength),
  2298. ULIGetLow(cbLockLength), dwLockType));
  2299. CheckSeekPointer();
  2300. fsAssert(_hFile != INVALID_FH);
  2301. filestDebug((DEB_LOCK, "File=%2x LockRegion %1x:%x bytes @ %1x:%x\n",
  2302. ULIGetLow(cbLockLength), ULIGetHigh(cbLockLength),
  2303. ULIGetLow(ulStartOffset), ULIGetHigh(ulStartOffset)));
  2304. boolChk(LockFile(_hFile, ULIGetLow(ulStartOffset),
  2305. ULIGetHigh(ulStartOffset), ULIGetLow(cbLockLength),
  2306. ULIGetHigh(cbLockLength)));
  2307. sc = S_OK;
  2308. filestDebug((DEB_ITRACE, "Out CFileStream::LockRegion\n"));
  2309. EH_Err:
  2310. CheckSeekPointer();
  2311. return ResultFromScode(sc);
  2312. }
  2313. //+--------------------------------------------------------------
  2314. //
  2315. // Member: CFileStream::UnlockRegion, public
  2316. //
  2317. // Synopsis: Releases an existing lock
  2318. //
  2319. // Arguments: [ulStartOffset] - Lock start
  2320. // [cbLockLength] - Length
  2321. // [dwLockType] - Lock type
  2322. //
  2323. // Returns: Appropriate status code
  2324. //
  2325. // History: 20-Feb-92 DrewB Created
  2326. //
  2327. // Notes: Must match an existing lock exactly
  2328. //
  2329. //---------------------------------------------------------------
  2330. STDMETHODIMP CFileStream::UnlockRegion(ULARGE_INTEGER ulStartOffset,
  2331. ULARGE_INTEGER cbLockLength,
  2332. DWORD dwLockType)
  2333. {
  2334. SCODE sc;
  2335. filestDebug((DEB_ITRACE, "In CFileStream::UnlockRegion("
  2336. "%x:%x, %x:%x, %x)\n", ULIGetHigh(ulStartOffset),
  2337. ULIGetLow(ulStartOffset), ULIGetHigh(cbLockLength),
  2338. ULIGetLow(cbLockLength), dwLockType));
  2339. CheckSeekPointer();
  2340. fsAssert(_hFile != INVALID_FH);
  2341. filestDebug((DEB_LOCK, "File=%2x UnlockRegion %1x:%x bytes @ %1x:%x\n",
  2342. ULIGetLow(cbLockLength), ULIGetHigh(cbLockLength),
  2343. ULIGetLow(ulStartOffset), ULIGetHigh(ulStartOffset)));
  2344. boolChk(UnlockFile(_hFile, ULIGetLow(ulStartOffset),
  2345. ULIGetHigh(ulStartOffset),
  2346. ULIGetLow(cbLockLength),
  2347. ULIGetHigh(cbLockLength)));
  2348. sc = S_OK;
  2349. filestDebug((DEB_ITRACE, "Out CFileStream::UnlockRegion\n"));
  2350. EH_Err:
  2351. CheckSeekPointer();
  2352. return ResultFromScode(sc);
  2353. }
  2354. //+--------------------------------------------------------------
  2355. //
  2356. // Function: FileTimeToTimeT, private
  2357. //
  2358. // Synopsis: Converts a FILETIME to a TIME_T
  2359. //
  2360. // Arguments: [pft] - FILETIME
  2361. //
  2362. // Returns: TIME_T
  2363. //
  2364. // History: 12-May-92 DrewB Created
  2365. //
  2366. //+--------------------------------------------------------------
  2367. #ifdef NOFILETIME
  2368. TIME_T FileTimeToTimeT(LPFILETIME pft)
  2369. {
  2370. WORD dt, tm;
  2371. struct tm tmFile;
  2372. fsVerify(FileTimeToDosDateTime(pft, &dt, &tm));
  2373. tmFile.tm_sec = (tm&31)*2;
  2374. tmFile.tm_min = (tm>>5)&63;
  2375. tmFile.tm_hour = (tm>>11)&31;
  2376. tmFile.tm_mday = dt&31;
  2377. tmFile.tm_mon = ((dt>>5)&15)-1;
  2378. tmFile.tm_year = (dt>>9)+80;
  2379. return (TIME_T)mktime(&tmFile);
  2380. }
  2381. #endif
  2382. //+--------------------------------------------------------------
  2383. //
  2384. // Member: CFileStream::Stat, public
  2385. //
  2386. // Synopsis: Fills in a stat buffer for this object
  2387. //
  2388. // Arguments: [pstatstg] - Buffer
  2389. //
  2390. // Returns: Appropriate status code
  2391. //
  2392. // Modifies: [pstatstg]
  2393. //
  2394. // History: 25-Mar-92 DrewB Created
  2395. //
  2396. //---------------------------------------------------------------
  2397. _OLESTDMETHODIMP CFileStream::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
  2398. {
  2399. SCODE sc;
  2400. filestDebug((DEB_ITRACE, "In CFileStream::Stat(%p)\n", pstatstg));
  2401. CheckSeekPointer();
  2402. fsAssert(_hFile != INVALID_FH);
  2403. fsChk(GetSize(&pstatstg->cbSize));
  2404. #ifdef NOFILETIME
  2405. FILETIME ftCreation, ftAccess, ftWrite;
  2406. boolChk(GetFileTime(_hFile, &ftCreation, &ftAccess, &ftWrite));
  2407. if (ftCreation.dwLowDateTime == 0 && ftCreation.dwHighDateTime == 0)
  2408. ftCreation = ftWrite;
  2409. if (ftAccess.dwLowDateTime == 0 && ftAccess.dwHighDateTime == 0)
  2410. ftAccess = ftWrite;
  2411. pstatstg->ctime = FileTimeToTimeT(&ftCreation);
  2412. pstatstg->atime = FileTimeToTimeT(&ftAccess);
  2413. pstatstg->mtime = FileTimeToTimeT(&ftWrite);
  2414. #else
  2415. boolChk(GetFileTime(_hFile, &pstatstg->ctime, &pstatstg->atime,
  2416. &pstatstg->mtime));
  2417. #endif
  2418. fsHVerSucc(GetLocksSupported(&pstatstg->grfLocksSupported));
  2419. pstatstg->type = STGTY_LOCKBYTES;
  2420. pstatstg->grfMode = DFlagsToMode(_pgfst->GetDFlags());
  2421. pstatstg->pwcsName = NULL;
  2422. if ((grfStatFlag & STATFLAG_NONAME) == 0)
  2423. {
  2424. fsChk(GetName(&pstatstg->pwcsName));
  2425. }
  2426. sc = S_OK;
  2427. CheckSeekPointer();
  2428. filestDebug((DEB_ITRACE, "Out CFileStream::Stat\n"));
  2429. return NOERROR;
  2430. EH_Err:
  2431. CheckSeekPointer();
  2432. return ResultFromScode(sc);
  2433. }
  2434. //+---------------------------------------------------------------------------
  2435. //
  2436. // Member: CFileStream::SwitchToFile, public
  2437. //
  2438. // Synopsis: Changes the file this filestream uses
  2439. //
  2440. // Arguments: [ptcsFile] - File name
  2441. // [ulCommitSize] -- Size needed to do overwrite commit
  2442. // [cbBuffer] - Buffer size
  2443. // [pvBuffer] - Buffer for file copying
  2444. //
  2445. // Returns: Appropriate status code
  2446. //
  2447. // History: 08-Jan-93 DrewB Created
  2448. //
  2449. //----------------------------------------------------------------------------
  2450. STDMETHODIMP CFileStream::SwitchToFile(OLECHAR const *ptcsFile,
  2451. #ifdef LARGE_DOCFILE
  2452. ULONGLONG ulCommitSize,
  2453. #else
  2454. ULONG ulCommitSize,
  2455. #endif
  2456. ULONG cbBuffer,
  2457. void *pvBuffer)
  2458. {
  2459. SCODE sc;
  2460. DWORD cbRead, cbWritten = 0;
  2461. FILEH hOldFile;
  2462. WCHAR awcOldName[_MAX_PATH+1];
  2463. WCHAR wcsFile[_MAX_PATH+1];
  2464. DWORD dwOldStartFlags;
  2465. ULARGE_INTEGER ulPos;
  2466. ULONG cbBufferSave = 0;
  2467. #ifdef ASYNC
  2468. fsAssert((_ppc == NULL) || (_ppc->HaveMutex()));
  2469. #endif
  2470. filestDebug((DEB_ITRACE, "In CFileStream::SwitchToFile:%p(%s, %x, %p)\n",
  2471. this, ptcsFile, cbBuffer, pvBuffer));
  2472. // Check for marshals
  2473. // This must be the only instance of this "context". Other
  2474. // seperate opens are possible though.
  2475. //
  2476. if (_pgfst->CountContexts() != 1)
  2477. fsErr(EH_Err, STG_E_EXTANTMARSHALLINGS);
  2478. CheckSeekPointer();
  2479. //
  2480. // We are about to switch physical files for this CFileStream. So
  2481. // turn off the mapping so we can switch to the new file.
  2482. //
  2483. fsChk(TurnOffMapping(TRUE));
  2484. // Seek to beginning
  2485. negChk(SeekTo(0));
  2486. // Preserve old file information
  2487. StringCbCopyW (awcOldName, sizeof(awcOldName), _pgfst->GetName());
  2488. hOldFile = _hFile;
  2489. dwOldStartFlags = _pgfst->GetStartFlags();
  2490. // Set file information to prepare for new Init
  2491. _pgfst->SetName(NULL);
  2492. _pgfst->SetMappingName(NULL);
  2493. _pgfst->SetMappedFileSize(0);
  2494. _pgfst->SetMappedCommitSize(0);
  2495. _pgfst->ResetMapState(~0UL); // Clear All State Flags.
  2496. _hFile = INVALID_FH;
  2497. _pgfst->SetStartFlags((dwOldStartFlags & ~(RSF_CREATEFLAGS |
  2498. RSF_CONVERT |
  2499. RSF_DELETEONRELEASE |
  2500. RSF_OPEN)) |
  2501. RSF_CREATE);
  2502. // Release reserved file handle so it can be consumed
  2503. if (_hReserved != INVALID_FH)
  2504. {
  2505. fsVerify(CloseHandle(_hReserved));
  2506. _hReserved = INVALID_FH;
  2507. }
  2508. if (FAILED(StringCbCopy(wcsFile, sizeof(wcsFile), ptcsFile)))
  2509. fsErr(EH_ReplaceOld, STG_E_INVALIDPOINTER);
  2510. // Attempt to create new file
  2511. fsChkTo(EH_ReplaceOld, InitFile(wcsFile));
  2512. ULARGE_INTEGER ulNewSize;
  2513. ulNewSize.QuadPart = ulCommitSize;
  2514. // SetSize to minimum commit size
  2515. fsHChkTo(EH_NewFile, SetSize(ulNewSize));
  2516. // SetSize changes the file pointer, so move it back to the beginning
  2517. negChkTo(EH_NewFile, SeekTo(0));
  2518. // Copy file contents
  2519. ulPos.QuadPart = 0;
  2520. for (;;)
  2521. {
  2522. BOOL fRangeLocks = IsInRangeLocks (ulPos.QuadPart, cbBuffer);
  2523. if (fRangeLocks)
  2524. {
  2525. ULONG ulRangeLocksBegin = OLOCKREGIONEND_SECTORALIGNED;
  2526. // The end of the range locks is within this cbBuffer block
  2527. // For unbuffered I/O, make sure we skip a whole sector
  2528. cbBufferSave = cbBuffer;
  2529. ulRangeLocksBegin -= (_pgfst->GetDFlags() & DF_LARGE) ? 4096 : 512;
  2530. cbBuffer = ulRangeLocksBegin - ulPos.LowPart;
  2531. }
  2532. if (cbBuffer > 0)
  2533. {
  2534. boolChkTo(EH_NewFile,
  2535. ReadFile(hOldFile, pvBuffer, (UINT)cbBuffer, &cbRead, NULL));
  2536. if (cbRead == 0)
  2537. break; // EOF
  2538. fsChkTo(EH_NewFile, WriteAt(ulPos, pvBuffer, cbRead, &cbWritten));
  2539. if (cbWritten != cbRead)
  2540. fsErr(EH_NewFile, STG_E_WRITEFAULT);
  2541. }
  2542. if (fRangeLocks)
  2543. {
  2544. cbBuffer = cbBufferSave;
  2545. cbWritten = cbBuffer;
  2546. }
  2547. ulPos.QuadPart += cbWritten;
  2548. if (fRangeLocks)
  2549. {
  2550. // If we've skipped the range locks, move past them
  2551. if (SetFilePointer(hOldFile, ulPos.LowPart, (LONG*)&ulPos.HighPart,
  2552. FILE_BEGIN) == MAX_ULONG)
  2553. fsChkTo(EH_NewFile, STG_SCODE(GetLastError()));
  2554. }
  2555. }
  2556. fsVerify(CloseHandle(hOldFile));
  2557. if (dwOldStartFlags & RSF_DELETEONRELEASE)
  2558. {
  2559. // This is allowed to fail if somebody else has
  2560. // the file open
  2561. DeleteTheFile(awcOldName);
  2562. }
  2563. filestDebug((DEB_ITRACE, "Out CFileStream::SwitchToFile\n"));
  2564. SetCachedFilePointer(GetFilePointer());
  2565. return S_OK;
  2566. EH_NewFile:
  2567. TurnOffMapping(FALSE);
  2568. fsVerify(CloseHandle(_hFile));
  2569. fsVerify(DeleteTheFile(_pgfst->GetName()));
  2570. EH_ReplaceOld:
  2571. _hFile = hOldFile;
  2572. if (_pgfst != NULL)
  2573. {
  2574. _pgfst->SetName(awcOldName);
  2575. _pgfst->SetStartFlags(dwOldStartFlags);
  2576. }
  2577. EH_Err:
  2578. SetCachedFilePointer(GetFilePointer());
  2579. return ResultFromScode(sc);
  2580. }
  2581. //+---------------------------------------------------------------------------
  2582. //
  2583. // Member: CFileStream::Delete, public
  2584. //
  2585. // Synopsis: Closes and deletes the file, errors ignored
  2586. //
  2587. // Returns: Appropriate status code
  2588. //
  2589. // History: 09-Feb-93 DrewB Created
  2590. //
  2591. //----------------------------------------------------------------------------
  2592. void CFileStream::Delete(void)
  2593. {
  2594. filestDebug((DEB_ITRACE, "In CFileStream::Delete:%p()\n", this));
  2595. TurnOffAllMappings();
  2596. if (_hFile != INVALID_FH)
  2597. CloseHandle(_hFile);
  2598. _hFile = INVALID_FH;
  2599. if (_hReserved != INVALID_FH)
  2600. CloseHandle(_hReserved);
  2601. _hReserved = INVALID_FH;
  2602. DeleteTheFile(_pgfst->GetName());
  2603. filestDebug((DEB_ITRACE, "Out CFileStream::Delete\n"));
  2604. }
  2605. //+--------------------------------------------------------------
  2606. //
  2607. // Member: CFileStream::DeleteTheFile, public
  2608. //
  2609. // Synopsis: Delete the file (using WideWrap DeleteFile), but don't
  2610. // if we don't think the system as already done so.
  2611. //
  2612. // History: 21-Jan-97 BChapman Created
  2613. //
  2614. //---------------------------------------------------------------
  2615. BOOL CFileStream::DeleteTheFile(const WCHAR *pwcName)
  2616. {
  2617. #ifndef MAC
  2618. //
  2619. // If the file is a "TEMPFILE" then it is DELETE_ON_CLOSE
  2620. // and the system already deleted it.
  2621. //
  2622. if(RSF_TEMPFILE & GetStartFlags())
  2623. return TRUE;
  2624. #endif
  2625. return DeleteFile(_pgfst->GetName());
  2626. }
  2627. //+---------------------------------------------------------------------------
  2628. //
  2629. // Member: CFileStream::ReserveHandle, public
  2630. //
  2631. // Synopsis: Reserves a backup file handle for handle-required operations
  2632. //
  2633. // Returns: Appropriate status code
  2634. //
  2635. // History: 01-Jul-93 DrewB Created
  2636. //
  2637. // Notes: May be called with a handle already reserved
  2638. //
  2639. //----------------------------------------------------------------------------
  2640. STDMETHODIMP CFileStream::ReserveHandle(void)
  2641. {
  2642. SCODE sc;
  2643. filestDebug((DEB_ITRACE, "In CFileStream::ReserveHandle:%p()\n", this));
  2644. if (_hReserved == INVALID_FH &&
  2645. !DuplicateHandle(GetCurrentProcess(), _hFile, GetCurrentProcess(),
  2646. &_hReserved, 0, FALSE, DUPLICATE_SAME_ACCESS))
  2647. {
  2648. sc = LAST_STG_SCODE;
  2649. }
  2650. else
  2651. {
  2652. filestDebug((DEB_INFO, "CFileStream reserved %p "
  2653. "handle %p thread %lX\n",
  2654. this, _hReserved, GetCurrentThreadId()));
  2655. sc = S_OK;
  2656. _grfLocal |= LFF_RESERVE_HANDLE;
  2657. }
  2658. filestDebug((DEB_ITRACE, "Out CFileStream::ReserveHandle => %lX\n", sc));
  2659. return ResultFromScode(sc);
  2660. }
  2661. //+---------------------------------------------------------------------------
  2662. //
  2663. // Member: CFileStream::GetSize, public
  2664. //
  2665. // Synopsis: Return the size of the stream
  2666. //
  2667. // Returns: Appropriate status code
  2668. //
  2669. // History: 12-Jul-93 AlexT Created
  2670. //
  2671. // Notes: This is a separate method from Stat as an optimization
  2672. //
  2673. //----------------------------------------------------------------------------
  2674. STDMETHODIMP CFileStream::GetSize(ULARGE_INTEGER *puliSize)
  2675. {
  2676. SCODE sc = S_OK;
  2677. CheckSeekPointer();
  2678. if(IsFileMapped())
  2679. {
  2680. puliSize->LowPart = _pgfst->GetMappedFileSize();
  2681. puliSize->HighPart = 0;
  2682. }
  2683. else
  2684. #ifdef LARGE_DOCFILE
  2685. {
  2686. puliSize->LowPart = GetFileSize(_hFile, &puliSize->HighPart);
  2687. if (puliSize->LowPart == MAX_ULONG && NO_ERROR != GetLastError())
  2688. fsErr(EH_Err, LAST_STG_SCODE)
  2689. }
  2690. #else
  2691. negChk(puliSize->LowPart = GetFileSize(_hFile, &puliSize->HighPart));
  2692. #endif
  2693. EH_Err:
  2694. CheckSeekPointer();
  2695. return(ResultFromScode(sc));
  2696. }
  2697. //+---------------------------------------------------------------------------
  2698. //
  2699. // Member: CFileStream::SetTime, public
  2700. //
  2701. // Synopsis: Set the times on the ILockbytes
  2702. //
  2703. // Arguments: [tt] -- Which time to set
  2704. // [nt] -- New time stamp
  2705. //
  2706. // Returns: Appropriate status code
  2707. //
  2708. // History: 24-Mar-95 PhilipLa Created
  2709. //
  2710. //----------------------------------------------------------------------------
  2711. SCODE CFileStream::SetTime(WHICHTIME tt,
  2712. TIME_T nt)
  2713. {
  2714. filestDebug((DEB_ITRACE, "In CFileStream::SetTime()\n"));
  2715. SCODE sc = S_OK;
  2716. FILETIME *pctime = NULL, *patime = NULL, *pmtime = NULL;
  2717. CheckSeekPointer();
  2718. if (tt == WT_CREATION)
  2719. {
  2720. pctime = &nt;
  2721. }
  2722. else if (tt == WT_MODIFICATION)
  2723. {
  2724. pmtime = &nt;
  2725. }
  2726. else
  2727. {
  2728. patime = &nt;
  2729. }
  2730. boolChk(SetFileTime(_hFile,
  2731. pctime,
  2732. patime,
  2733. pmtime));
  2734. EH_Err:
  2735. filestDebug((DEB_ITRACE, "Out CFileStream::SetTime() => %lx\n", sc));
  2736. CheckSeekPointer();
  2737. return sc;
  2738. }
  2739. //+---------------------------------------------------------------------------
  2740. //
  2741. // Member: CFileStream::SetAllTimes, public
  2742. //
  2743. // Synopsis: Set the times on the ILockbytes
  2744. //
  2745. // Arguments: [atm] Access time
  2746. // [mtm] Modification time
  2747. // [ctm] Creation time
  2748. //
  2749. // Returns: Appropriate status code
  2750. //
  2751. // History: 24-Nov-95 SusiA Created
  2752. //
  2753. //----------------------------------------------------------------------------
  2754. SCODE CFileStream::SetAllTimes( TIME_T atm,
  2755. TIME_T mtm,
  2756. TIME_T ctm)
  2757. {
  2758. filestDebug((DEB_ITRACE, "In CFileStream::SetAllTimes()\n"));
  2759. SCODE sc = S_OK;
  2760. CheckSeekPointer();
  2761. boolChk(SetFileTime(_hFile, &ctm, &atm, &mtm));
  2762. EH_Err:
  2763. filestDebug((DEB_ITRACE, "Out CFileStream::SetAllTimes() => %lx\n", sc));
  2764. CheckSeekPointer();
  2765. return sc;
  2766. }
  2767. #ifdef ASYNC
  2768. //+---------------------------------------------------------------------------
  2769. //
  2770. // Member: CFileStream::FillAppend, public
  2771. //
  2772. // Synopsis:
  2773. //
  2774. // Arguments:
  2775. //
  2776. // Returns: Appropriate status code
  2777. //
  2778. // Modifies:
  2779. //
  2780. // History: 28-Dec-95 PhilipLa Created
  2781. //
  2782. // Notes:
  2783. //
  2784. //----------------------------------------------------------------------------
  2785. STDMETHODIMP CFileStream::FillAppend(void const *pv,
  2786. ULONG cb,
  2787. ULONG *pcbWritten)
  2788. {
  2789. SCODE sc;
  2790. SAFE_SEM;
  2791. HANDLE hEvent;
  2792. filestDebug((DEB_ITRACE, "In CFileStream::FillAppend:%p()\n", this));
  2793. fsChk(TakeSafeSem());
  2794. if (_pgfst->GetTerminationStatus() != UNTERMINATED)
  2795. {
  2796. sc = STG_E_TERMINATED;
  2797. }
  2798. else
  2799. {
  2800. ULONG cbWritten;
  2801. #ifdef LARGE_DOCFILE
  2802. ULARGE_INTEGER ulHighWater;
  2803. ulHighWater.QuadPart = _pgfst->GetHighWaterMark();
  2804. #else
  2805. ULONG ulHighWater = _pgfst->GetHighWaterMark();
  2806. #endif
  2807. sc = CFileStream::WriteAtWorker(ulHighWater, pv, cb, &cbWritten);
  2808. #ifdef LARGE_DOCFILE
  2809. _pgfst->SetHighWaterMark(ulHighWater.QuadPart + cbWritten);
  2810. #else
  2811. _pgfst->SetHighWaterMark(ulHighWater + cbWritten);
  2812. #endif
  2813. if (pcbWritten != NULL)
  2814. {
  2815. *pcbWritten = cbWritten;
  2816. }
  2817. hEvent = _ppc->GetNotificationEvent();
  2818. if (!PulseEvent(hEvent))
  2819. {
  2820. sc = Win32ErrorToScode(GetLastError());
  2821. }
  2822. }
  2823. filestDebug((DEB_ITRACE, "Out CFileStream::FillAppend\n"));
  2824. EH_Err:
  2825. return sc;
  2826. }
  2827. //+---------------------------------------------------------------------------
  2828. //
  2829. // Member: CFileStream::FillAt, public
  2830. //
  2831. // Synopsis:
  2832. //
  2833. // Arguments:
  2834. //
  2835. // Returns: Appropriate status code
  2836. //
  2837. // Modifies:
  2838. //
  2839. // History: 28-Dec-95 PhilipLa Created
  2840. //
  2841. // Notes:
  2842. //
  2843. //----------------------------------------------------------------------------
  2844. STDMETHODIMP CFileStream::FillAt(ULARGE_INTEGER ulOffset,
  2845. void const *pv,
  2846. ULONG cb,
  2847. ULONG *pcbWritten)
  2848. {
  2849. filestDebug((DEB_ITRACE, "In CFileStream::FillAt:%p()\n", this));
  2850. filestDebug((DEB_ITRACE, "Out CFileStream::FillAt\n"));
  2851. return STG_E_UNIMPLEMENTEDFUNCTION;
  2852. }
  2853. //+---------------------------------------------------------------------------
  2854. //
  2855. // Member: CFileStream::SetFillSize, public
  2856. //
  2857. // Synopsis:
  2858. //
  2859. // Arguments:
  2860. //
  2861. // Returns: Appropriate status code
  2862. //
  2863. // Modifies:
  2864. //
  2865. // History: 28-Dec-95 PhilipLa Created
  2866. //
  2867. // Notes:
  2868. //
  2869. //----------------------------------------------------------------------------
  2870. STDMETHODIMP CFileStream::SetFillSize(ULARGE_INTEGER ulSize)
  2871. {
  2872. SCODE sc;
  2873. SAFE_SEM;
  2874. filestDebug((DEB_ITRACE,
  2875. "In CFileStream::SetFillSize:%p()\n", this));
  2876. fsChk(TakeSafeSem());
  2877. if (_pgfst->GetTerminationStatus() == TERMINATED_ABNORMAL)
  2878. {
  2879. sc = STG_E_INCOMPLETE;
  2880. }
  2881. else
  2882. {
  2883. #ifndef LARGE_DOCFILE
  2884. ULONG uLow = ULIGetLow(ulSize);
  2885. LONG lHigh = ULIGetHigh(ulSize);
  2886. fsAssert(lHigh == 0 &&
  2887. aMsg("High dword other than zero passed to filestream."));
  2888. #endif
  2889. #ifdef LARGE_DOCFILE
  2890. sc = SetSizeWorker(ulSize.QuadPart);
  2891. #else
  2892. sc = SetSizeWorker(uLow);
  2893. #endif
  2894. }
  2895. filestDebug((DEB_ITRACE, "Out CFileStream::SetFillSize\n"));
  2896. EH_Err:
  2897. return sc;
  2898. }
  2899. //+---------------------------------------------------------------------------
  2900. //
  2901. // Member: CFileStream::Terminate, public
  2902. //
  2903. // Synopsis:
  2904. //
  2905. // Arguments:
  2906. //
  2907. // Returns: Appropriate status code
  2908. //
  2909. // Modifies:
  2910. //
  2911. // History: 28-Dec-95 PhilipLa Created
  2912. //
  2913. // Notes:
  2914. //
  2915. //----------------------------------------------------------------------------
  2916. STDMETHODIMP CFileStream::Terminate(BOOL bCanceled)
  2917. {
  2918. SCODE sc;
  2919. SAFE_SEM;
  2920. HANDLE hEvent;
  2921. filestDebug((DEB_ITRACE, "In CFileStream::Terminate:%p()\n", this));
  2922. fsChk(TakeSafeSem());
  2923. _pgfst->SetTerminationStatus((bCanceled) ?
  2924. TERMINATED_ABNORMAL :
  2925. TERMINATED_NORMAL);
  2926. hEvent = _ppc->GetNotificationEvent();
  2927. if ((hEvent != INVALID_HANDLE_VALUE) && (!SetEvent(hEvent)))
  2928. {
  2929. return Win32ErrorToScode(GetLastError());
  2930. }
  2931. filestDebug((DEB_ITRACE, "Out CFileStream::Terminate\n"));
  2932. EH_Err:
  2933. return sc;
  2934. }
  2935. void CFileStream::StartAsyncMode(void)
  2936. {
  2937. //Note: No semaphore here - this must be called before the ILockBytes
  2938. // is returned to an app.
  2939. _pgfst->SetTerminationStatus(UNTERMINATED);
  2940. }
  2941. STDMETHODIMP CFileStream::GetFailureInfo(ULONG *pulWaterMark,
  2942. ULONG *pulFailurePoint)
  2943. {
  2944. //We don't take a semaphore here because we don't need it. This call
  2945. // is either made when we're already holding the semaphore, or is made
  2946. // when we don't care about the absolute accuracy of the results.
  2947. //However, we do need a shared heap to access _pgfst
  2948. CSafeMultiHeap smh(_ppc);
  2949. #ifdef LARGE_DOCFILE
  2950. // This method, used by IProgressNotify, cannot handle large integers
  2951. // If the high water mark is too big to fit, return an error
  2952. ULONGLONG ulWaterMark = _pgfst->GetHighWaterMark();
  2953. if (ulWaterMark < MAX_ULONG)
  2954. {
  2955. *pulWaterMark = (ULONG) ulWaterMark;
  2956. *pulFailurePoint = (ULONG) _pgfst->GetFailurePoint();
  2957. return S_OK;
  2958. }
  2959. else return STG_E_INVALIDFUNCTION; // file is too big
  2960. #else
  2961. *pulWaterMark = _pgfst->GetHighWaterMark();
  2962. *pulFailurePoint = _pgfst->GetFailurePoint();
  2963. return S_OK;
  2964. #endif
  2965. }
  2966. STDMETHODIMP CFileStream::GetTerminationStatus(DWORD *pdwFlags)
  2967. {
  2968. SAFE_SEM;
  2969. TakeSafeSem();
  2970. *pdwFlags = _pgfst->GetTerminationStatus();
  2971. return S_OK;
  2972. }
  2973. #endif //ASYNC
  2974. //+---------------------------------------------------------------------------
  2975. //
  2976. // Function: GetNtHandleSectorSize
  2977. //
  2978. // Synopsis: Find a volume's physical sector size
  2979. //
  2980. // Arguments: [Handle] -- file handle
  2981. // [pulSectorSize] -- number of bytes per physical sector
  2982. //
  2983. // Returns: Appropriate status code
  2984. //
  2985. //----------------------------------------------------------------------------
  2986. HRESULT GetNtHandleSectorSize (HANDLE Handle, ULONG * pulSectorSize)
  2987. {
  2988. FILE_FS_SIZE_INFORMATION SizeInfo;
  2989. IO_STATUS_BLOCK iosb;
  2990. NTSTATUS nts = NtQueryVolumeInformationFile( Handle, &iosb,
  2991. &SizeInfo, sizeof(SizeInfo), FileFsSizeInformation );
  2992. if (NT_SUCCESS(nts))
  2993. {
  2994. *pulSectorSize = SizeInfo.BytesPerSector;
  2995. return S_OK;
  2996. }
  2997. return NtStatusToScode(nts);
  2998. }