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.

402 lines
9.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. filestm.c
  5. Abstract:
  6. This modules implements IStream over a file.
  7. Author:
  8. Jay Krell (a-JayK) June 2000
  9. Revision History:
  10. --*/
  11. #define RTL_DECLARE_STREAMS 1
  12. #define RTL_DECLARE_FILE_STREAM 1
  13. #include "ntos.h"
  14. #include "nt.h"
  15. #include "ntrtl.h"
  16. #include "nturtl.h"
  17. #include "objidl.h"
  18. #define RTLP_FILE_STREAM_NOT_IMPL(x) \
  19. KdPrintEx((DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "RTLSXS: %s() E_NOTIMPL", __FUNCTION__)); \
  20. return E_NOTIMPL;
  21. #if !defined(RTLP_FILE_STREAM_HRESULT_FROM_STATUS)
  22. #if defined(RTLP_HRESULT_FROM_STATUS)
  23. #define RTLP_FILE_STREAM_HRESULT_FROM_STATUS(x) RTLP_HRESULT_FROM_STATUS(x)
  24. #else
  25. #define RTLP_FILE_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosErrorNoTeb(x))
  26. //#define RTLP_FILE_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x))
  27. //#define RTLP_FILE_STREAM_HRESULT_FROM_STATUS(x) HRESULT_FROM_NT(x)
  28. #endif
  29. #endif
  30. HRESULT
  31. STDMETHODCALLTYPE
  32. RtlInitFileStream(
  33. PRTL_FILE_STREAM FileStream
  34. )
  35. {
  36. RtlZeroMemory(FileStream, sizeof(*FileStream));
  37. return NOERROR;
  38. }
  39. HRESULT
  40. STDMETHODCALLTYPE
  41. RtlCloseFileStream(
  42. PRTL_FILE_STREAM FileStream
  43. )
  44. {
  45. const HANDLE FileHandle = FileStream->FileHandle;
  46. NTSTATUS Status = STATUS_SUCCESS;
  47. HRESULT Hr = NOERROR;
  48. if (FileHandle != NULL) {
  49. FileStream->FileHandle = NULL;
  50. Status = NtClose(FileHandle);
  51. if (!NT_SUCCESS(Status)) {
  52. Hr = RTLP_FILE_STREAM_HRESULT_FROM_STATUS(Status);
  53. }
  54. }
  55. return Hr;
  56. }
  57. ULONG
  58. STDMETHODCALLTYPE
  59. RtlAddRefFileStream(
  60. PRTL_FILE_STREAM FileStream
  61. )
  62. {
  63. LONG ReferenceCount = InterlockedIncrement(&FileStream->ReferenceCount);
  64. return ReferenceCount;
  65. }
  66. ULONG
  67. STDMETHODCALLTYPE
  68. RtlReleaseFileStream(
  69. PRTL_FILE_STREAM FileStream
  70. )
  71. {
  72. LONG ReferenceCount = InterlockedDecrement(&FileStream->ReferenceCount);
  73. if (ReferenceCount == 0 && FileStream->FinalRelease != NULL) {
  74. FileStream->FinalRelease(FileStream);
  75. }
  76. return ReferenceCount;
  77. }
  78. HRESULT
  79. STDMETHODCALLTYPE
  80. RtlQueryInterfaceFileStream(
  81. IStream* Functions,
  82. PRTL_FILE_STREAM Data,
  83. const IID* Interface,
  84. PVOID* Object
  85. )
  86. {
  87. if (IsEqualGUID(Interface, &IID_IUnknown)
  88. || IsEqualGUID(Interface, &IID_IStream)
  89. || IsEqualGUID(Interface, &IID_ISequentialStream)
  90. )
  91. {
  92. InterlockedIncrement(&Data->ReferenceCount);
  93. *Object = Functions;
  94. return NOERROR;
  95. }
  96. return E_NOINTERFACE;
  97. }
  98. HRESULT
  99. STDMETHODCALLTYPE
  100. RtlReadFileStream(
  101. PRTL_FILE_STREAM FileStream,
  102. PVOID Buffer,
  103. ULONG BytesToRead,
  104. ULONG* BytesRead
  105. )
  106. {
  107. //
  108. // based on Win32 ReadFile
  109. // we should allow asynchronous i/o here.. put the IO_STATUS_BLOCK
  110. // in the RTL_FILE_STREAM..
  111. //
  112. IO_STATUS_BLOCK IoStatusBlock;
  113. const HANDLE FileHandle = FileStream->FileHandle;
  114. NTSTATUS Status = STATUS_SUCCESS;
  115. HRESULT Hr = NOERROR;
  116. Status = NtReadFile(
  117. FileHandle,
  118. NULL, // optional event
  119. NULL, // optional apc routine
  120. NULL, // optional apc context
  121. &IoStatusBlock,
  122. Buffer,
  123. BytesToRead,
  124. NULL, // optional offset
  125. NULL // optional "key"
  126. );
  127. if ( Status == STATUS_PENDING) {
  128. // Operation must complete before return & IoStatusBlock destroyed
  129. Status = NtWaitForSingleObject(FileHandle, FALSE, NULL);
  130. if (NT_SUCCESS(Status)) {
  131. Status = IoStatusBlock.Status;
  132. }
  133. }
  134. if (NT_SUCCESS(Status)) {
  135. *BytesRead = (ULONG)IoStatusBlock.Information; // cast from ULONG_PTR
  136. Hr = NOERROR;
  137. } else if (Status == STATUS_END_OF_FILE) {
  138. *BytesRead = 0;
  139. Hr = NOERROR;
  140. } else {
  141. if (NT_WARNING(Status)) {
  142. *BytesRead = (ULONG)IoStatusBlock.Information; // cast from ULONG_PTR
  143. }
  144. Hr = RTLP_FILE_STREAM_HRESULT_FROM_STATUS(Status);
  145. }
  146. return Hr;
  147. }
  148. HRESULT
  149. STDMETHODCALLTYPE
  150. RtlWriteFileStream(
  151. PRTL_FILE_STREAM FileStream,
  152. const VOID* Buffer,
  153. ULONG BytesToWrite,
  154. ULONG* BytesWritten
  155. )
  156. {
  157. RTLP_FILE_STREAM_NOT_IMPL(Write);
  158. }
  159. HRESULT
  160. STDMETHODCALLTYPE
  161. RtlSeekFileStream(
  162. PRTL_FILE_STREAM FileStream,
  163. LARGE_INTEGER Distance,
  164. DWORD Origin,
  165. ULARGE_INTEGER* NewPosition
  166. )
  167. {
  168. //
  169. // based closely on Win32 SetFilePointer
  170. //
  171. HRESULT Hr = NOERROR;
  172. NTSTATUS Status = STATUS_SUCCESS;
  173. IO_STATUS_BLOCK IoStatusBlock;
  174. FILE_POSITION_INFORMATION CurrentPosition;
  175. const HANDLE FileHandle = FileStream->FileHandle;
  176. switch (Origin) {
  177. case STREAM_SEEK_SET:
  178. CurrentPosition.CurrentByteOffset = Distance;
  179. break;
  180. case STREAM_SEEK_CUR:
  181. Status = NtQueryInformationFile(
  182. FileHandle,
  183. &IoStatusBlock,
  184. &CurrentPosition,
  185. sizeof(CurrentPosition),
  186. FilePositionInformation
  187. );
  188. if (!NT_SUCCESS(Status)) {
  189. Hr = RTLP_FILE_STREAM_HRESULT_FROM_STATUS(Status);
  190. goto Exit;
  191. }
  192. CurrentPosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
  193. break;
  194. case STREAM_SEEK_END: {
  195. FILE_STANDARD_INFORMATION StandardInfo;
  196. Status = NtQueryInformationFile(
  197. FileHandle,
  198. &IoStatusBlock,
  199. &StandardInfo,
  200. sizeof(StandardInfo),
  201. FileStandardInformation
  202. );
  203. if (!NT_SUCCESS(Status)) {
  204. Hr = RTLP_FILE_STREAM_HRESULT_FROM_STATUS(Status);
  205. goto Exit;
  206. }
  207. // SetFilePointer uses + here. Which is correct?
  208. // Descriptions of how Seek work are always unclear on this point..
  209. CurrentPosition.CurrentByteOffset.QuadPart =
  210. StandardInfo.EndOfFile.QuadPart - Distance.QuadPart;
  211. }
  212. break;
  213. default:
  214. // You would expect this to be E_INVALIDARG, but since
  215. // the IStream
  216. // but IStream docs weakly suggest STG_E_INVALIDPOINTER.
  217. Hr = STG_E_INVALIDFUNCTION; // E_INVALIDARG?
  218. goto Exit;
  219. }
  220. if (CurrentPosition.CurrentByteOffset.QuadPart < 0) {
  221. // You would expect this to be E_INVALIDARG,
  222. // but IStream docs say to return STG_E_INVALIDPOINTER.
  223. Hr = STG_E_INVALIDPOINTER;
  224. goto Exit;
  225. }
  226. //
  227. // Set the current file position
  228. //
  229. Status = NtSetInformationFile(
  230. FileHandle,
  231. &IoStatusBlock,
  232. &CurrentPosition,
  233. sizeof(CurrentPosition),
  234. FilePositionInformation
  235. );
  236. NewPosition->QuadPart = CurrentPosition.CurrentByteOffset.QuadPart;
  237. Hr = NOERROR;
  238. Exit:
  239. return Hr;
  240. }
  241. HRESULT
  242. STDMETHODCALLTYPE
  243. RtlSetFileStreamSize(
  244. PRTL_FILE_STREAM FileStream,
  245. ULARGE_INTEGER NewSize
  246. )
  247. {
  248. //
  249. // based on Win32 SetEndOfFile, but is independent of current seek pointer
  250. //
  251. NTSTATUS Status = STATUS_SUCCESS;
  252. IO_STATUS_BLOCK IoStatusBlock;
  253. FILE_END_OF_FILE_INFORMATION EndOfFile;
  254. FILE_ALLOCATION_INFORMATION Allocation;
  255. const HANDLE FileHandle = FileStream->FileHandle;
  256. EndOfFile.EndOfFile.QuadPart = NewSize.QuadPart;
  257. Allocation.AllocationSize.QuadPart = NewSize.QuadPart;
  258. Status = NtSetInformationFile(
  259. FileHandle,
  260. &IoStatusBlock,
  261. &EndOfFile,
  262. sizeof(EndOfFile),
  263. FileEndOfFileInformation
  264. );
  265. if (!NT_SUCCESS(Status)) {
  266. goto Exit;
  267. }
  268. Status = NtSetInformationFile(
  269. FileHandle,
  270. &IoStatusBlock,
  271. &Allocation,
  272. sizeof(Allocation),
  273. FileAllocationInformation
  274. );
  275. if (!NT_SUCCESS(Status)) {
  276. goto Exit;
  277. }
  278. Status = STATUS_SUCCESS;
  279. Exit:
  280. if (NT_SUCCESS(Status)) {
  281. return NOERROR;
  282. } else {
  283. return RTLP_FILE_STREAM_HRESULT_FROM_STATUS(Status);
  284. }
  285. }
  286. HRESULT
  287. STDMETHODCALLTYPE
  288. RtlCopyFileStreamTo(
  289. PRTL_FILE_STREAM FileStream,
  290. IStream* AnotherStream,
  291. ULARGE_INTEGER NumberOfBytesToCopyLargeInteger,
  292. ULARGE_INTEGER* NumberOfBytesRead,
  293. ULARGE_INTEGER* NumberOfBytesWrittenLargeInteger
  294. )
  295. {
  296. //
  297. // Memory mapping where possible would be nice (but beware sockets and consoles).
  298. // see \vsee\lib\CWin32Stream.
  299. //
  300. RTLP_FILE_STREAM_NOT_IMPL(CopyTo);
  301. }
  302. HRESULT
  303. STDMETHODCALLTYPE
  304. RtlCommitFileStream(
  305. PRTL_FILE_STREAM FileStream,
  306. ULONG Flags
  307. )
  308. {
  309. RTLP_FILE_STREAM_NOT_IMPL(Commit);
  310. }
  311. HRESULT
  312. STDMETHODCALLTYPE
  313. RtlRevertFileStream(
  314. PRTL_FILE_STREAM FileStream
  315. )
  316. {
  317. RTLP_FILE_STREAM_NOT_IMPL(Revert);
  318. }
  319. HRESULT
  320. STDMETHODCALLTYPE
  321. RtlLockFileStreamRegion(
  322. PRTL_FILE_STREAM FileStream,
  323. ULARGE_INTEGER Offset,
  324. ULARGE_INTEGER NumberOfBytes,
  325. ULONG LockType
  326. )
  327. {
  328. RTLP_FILE_STREAM_NOT_IMPL(LockRegion);
  329. }
  330. HRESULT
  331. STDMETHODCALLTYPE
  332. RtlUnlockFileStreamRegion(
  333. PRTL_FILE_STREAM FileStream,
  334. ULARGE_INTEGER Offset,
  335. ULARGE_INTEGER NumberOfBytes,
  336. ULONG LockType
  337. )
  338. {
  339. RTLP_FILE_STREAM_NOT_IMPL(UnlockRegion);
  340. }
  341. HRESULT
  342. STDMETHODCALLTYPE
  343. RtlStatFileStream(
  344. PRTL_FILE_STREAM FileStream,
  345. STATSTG* StatusInformation,
  346. ULONG Flags
  347. )
  348. {
  349. RTLP_FILE_STREAM_NOT_IMPL(Stat);
  350. }
  351. HRESULT
  352. STDMETHODCALLTYPE
  353. RtlCloneFileStream(
  354. PRTL_FILE_STREAM FileStream,
  355. IStream** NewStream
  356. )
  357. {
  358. RTLP_FILE_STREAM_NOT_IMPL(Clone);
  359. }