Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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