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.

316 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Write.c
  5. Abstract:
  6. This module implements the File Write routine for Write called by the
  7. Fsd/Fsp dispatch drivers.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Tom Jolly [tomjolly] 8-Aug-2000
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "UdfProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (UDFS_BUG_CHECK_WRITE)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (UDFS_DEBUG_LEVEL_WRITE)
  23. NTSTATUS
  24. UdfCommonWrite (
  25. IN PIRP_CONTEXT IrpContext,
  26. IN PIRP Irp
  27. )
  28. {
  29. PIO_STACK_LOCATION IrpSp;
  30. PFILE_OBJECT FileObject;
  31. TYPE_OF_OPEN TypeOfOpen;
  32. PFCB Fcb;
  33. PCCB Ccb;
  34. BOOLEAN Wait;
  35. BOOLEAN PagingIo;
  36. BOOLEAN SynchronousIo;
  37. BOOLEAN WriteToEof;
  38. LONGLONG StartingOffset;
  39. LONGLONG ByteCount;
  40. NTSTATUS Status = STATUS_SUCCESS;
  41. UDF_IO_CONTEXT LocalIoContext;
  42. //
  43. // Get current Irp stack location and file object
  44. //
  45. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  46. FileObject = IrpSp->FileObject;
  47. DebugTrace((+1, Dbg, "UdfCommonWrite\n"));
  48. DebugTrace(( 0, Dbg, "Irp = %8lx\n", Irp));
  49. DebugTrace(( 0, Dbg, "ByteCount = %8lx\n", IrpSp->Parameters.Write.Length));
  50. DebugTrace(( 0, Dbg, "ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.LowPart));
  51. DebugTrace(( 0, Dbg, "ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.HighPart));
  52. //
  53. // Extract the nature of the write from the file object, and case on it
  54. //
  55. TypeOfOpen = UdfDecodeFileObject( FileObject, &Fcb, &Ccb);
  56. //
  57. // We only support write to the volume file
  58. //
  59. if (TypeOfOpen != UserVolumeOpen) {
  60. Irp->IoStatus.Information = 0;
  61. UdfCompleteRequest( IrpContext, Irp, STATUS_NOT_IMPLEMENTED );
  62. return STATUS_NOT_IMPLEMENTED;
  63. }
  64. ASSERT( Fcb == IrpContext->Vcb->VolumeDasdFcb);
  65. //
  66. // Initialize the appropriate local variables.
  67. //
  68. Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  69. PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
  70. SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
  71. //
  72. // Extract the bytecount and starting offset
  73. //
  74. ByteCount = IrpSp->Parameters.Write.Length;
  75. StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart;
  76. WriteToEof = (StartingOffset == -1);
  77. Irp->IoStatus.Information = 0;
  78. //
  79. // If there is nothing to write, return immediately
  80. //
  81. if (ByteCount == 0) {
  82. UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  83. return STATUS_SUCCESS;
  84. }
  85. //
  86. // Watch for overflow
  87. //
  88. if ((MAXLONGLONG - StartingOffset) < ByteCount) {
  89. UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  90. return STATUS_INVALID_PARAMETER;
  91. }
  92. //
  93. // Not sure what we're synchronising against, but....
  94. //
  95. UdfAcquireFileShared( IrpContext, Fcb );
  96. try {
  97. //
  98. // Verify the Fcb. Allow writes if this handle is dismounting
  99. // the volume.
  100. //
  101. if ((NULL == Ccb) || !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
  102. UdfVerifyFcbOperation( IrpContext, Fcb );
  103. }
  104. if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
  105. //
  106. // Clamp to volume size
  107. //
  108. if ( StartingOffset >= Fcb->FileSize.QuadPart) {
  109. try_leave( NOTHING);
  110. }
  111. if ( ByteCount > (Fcb->FileSize.QuadPart - StartingOffset)) {
  112. ByteCount = Fcb->FileSize.QuadPart - StartingOffset;
  113. if (0 == ByteCount) {
  114. try_leave( NOTHING);
  115. }
  116. }
  117. }
  118. else {
  119. //
  120. // This has a peculiar interpretation, but just adjust the starting
  121. // byte to the end of the visible volume.
  122. //
  123. if (WriteToEof) {
  124. StartingOffset = Fcb->FileSize.QuadPart;
  125. }
  126. }
  127. //
  128. // Initialize the IoContext for the write.
  129. // If there is a context pointer, we need to make sure it was
  130. // allocated and not a stale stack pointer.
  131. //
  132. if (IrpContext->IoContext == NULL ||
  133. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
  134. //
  135. // If we can wait, use the context on the stack. Otherwise
  136. // we need to allocate one.
  137. //
  138. if (Wait) {
  139. IrpContext->IoContext = &LocalIoContext;
  140. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  141. } else {
  142. IrpContext->IoContext = UdfAllocateIoContext();
  143. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  144. }
  145. }
  146. RtlZeroMemory( IrpContext->IoContext, sizeof( UDF_IO_CONTEXT ));
  147. //
  148. // Store whether we allocated this context structure in the structure
  149. // itself.
  150. //
  151. IrpContext->IoContext->AllocatedContext =
  152. BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  153. if (Wait) {
  154. KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
  155. NotificationEvent,
  156. FALSE );
  157. } else {
  158. IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
  159. IrpContext->IoContext->Resource = Fcb->Resource;
  160. IrpContext->IoContext->RequestedByteCount = (ULONG)ByteCount;
  161. }
  162. //
  163. // For DASD we have to probe and lock the user's buffer
  164. //
  165. UdfLockUserBuffer( IrpContext, (ULONG)ByteCount, IoReadAccess );
  166. //
  167. // Set the FO_MODIFIED flag here to trigger a verify when this
  168. // handle is closed. Note that we can err on the conservative
  169. // side with no problem, i.e. if we accidently do an extra
  170. // verify there is no problem.
  171. //
  172. SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
  173. //
  174. // Write the data and wait for the results
  175. //
  176. Irp->IoStatus.Information = (ULONG)ByteCount;
  177. UdfSingleAsync( IrpContext,
  178. StartingOffset,
  179. (ULONG)ByteCount);
  180. if (!Wait) {
  181. //
  182. // We, nor anybody else, need the IrpContext any more.
  183. //
  184. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO);
  185. UdfCleanupIrpContext( IrpContext, TRUE);
  186. DebugTrace((-1, Dbg, "UdfCommonWrite -> STATUS_PENDING\n"));
  187. try_leave( Status = STATUS_PENDING);
  188. }
  189. UdfWaitSync( IrpContext );
  190. //
  191. // If the call didn't succeed, raise the error status
  192. //
  193. Status = Irp->IoStatus.Status;
  194. if (!NT_SUCCESS( Status)) {
  195. UdfNormalizeAndRaiseStatus( IrpContext, Status );
  196. }
  197. //
  198. // Update the current file position. We assume that
  199. // open/create zeros out the CurrentByteOffset field.
  200. //
  201. if (SynchronousIo && !PagingIo) {
  202. FileObject->CurrentByteOffset.QuadPart =
  203. StartingOffset + Irp->IoStatus.Information;
  204. }
  205. }
  206. finally {
  207. UdfReleaseFile( IrpContext, Fcb);
  208. DebugTrace((-1, Dbg, "UdfCommonWrite -> %08lx\n", Status ));
  209. }
  210. if (STATUS_PENDING != Status) {
  211. UdfCompleteRequest( IrpContext, Irp, Status );
  212. }
  213. return Status;
  214. }