3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Write routine for Write called by the
12 Fsd/Fsp dispatch drivers.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_WRITE)
29 // _In_ ULONG ByteCount
34 // This macro just puts a nice little try-except around RtlZeroMemory
38 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
40 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
41 __pragma(warning(suppress: 6320)) \
42 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
43 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
47 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
49 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
50 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
51 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
57 #pragma alloc_text(PAGE, CdCommonWrite)
61 _Requires_lock_held_(_Global_critical_region_
)
64 _Inout_ PIRP_CONTEXT IrpContext
,
72 This is the common entry point for NtWriteFile calls. For synchronous requests,
73 CommonWrite will complete the request in the current thread. If not
74 synchronous the request will be passed to the Fsp if there is a need to
79 Irp - Supplies the Irp to process
83 NTSTATUS - The result of this operation.
88 NTSTATUS Status
= STATUS_SUCCESS
;
89 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
91 TYPE_OF_OPEN TypeOfOpen
;
99 LONGLONG StartingOffset
;
102 ULONG WriteByteCount
;
103 ULONG OriginalByteCount
;
105 BOOLEAN ReleaseFile
= TRUE
;
107 CD_IO_CONTEXT LocalIoContext
;
112 // If this is a zero length write then return SUCCESS immediately.
115 if (IrpSp
->Parameters
.Write
.Length
== 0) {
117 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
118 return STATUS_SUCCESS
;
122 // Decode the file object and verify we support write on this. It
123 // must be a volume file.
126 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
128 // Internal lock object is acquired if return status is STATUS_PENDING
129 _Analysis_suppress_lock_checking_(Fcb
->Resource
);
131 if (TypeOfOpen
!= UserVolumeOpen
) {
133 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
134 return STATUS_INVALID_DEVICE_REQUEST
;
138 // Examine our input parameters to determine if this is noncached and/or
139 // a paging io operation.
142 Wait
= BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
143 SynchronousIo
= FlagOn( IrpSp
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
147 // Extract the range of the Io.
150 StartingOffset
= IrpSp
->Parameters
.Write
.ByteOffset
.QuadPart
;
151 OriginalByteCount
= ByteCount
= IrpSp
->Parameters
.Write
.Length
;
153 ByteRange
= StartingOffset
+ ByteCount
;
156 // Acquire the file shared to perform the write.
159 CdAcquireFileShared( IrpContext
, Fcb
);
162 // Use a try-finally to facilitate cleanup.
168 // Verify the Fcb. Allow writes if this is a DASD handle that is
169 // dismounting the volume.
172 if (!FlagOn( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
)) {
174 CdVerifyFcbOperation( IrpContext
, Fcb
);
177 if (!FlagOn( Ccb
->Flags
, CCB_FLAG_ALLOW_EXTENDED_DASD_IO
)) {
180 // Complete the request if it begins beyond the end of file.
183 if (StartingOffset
>= Fcb
->FileSize
.QuadPart
) {
185 try_return( Status
= STATUS_END_OF_FILE
);
189 // Truncate the write if it extends beyond the end of the file.
192 if (ByteRange
> Fcb
->FileSize
.QuadPart
) {
194 ByteCount
= (ULONG
) (Fcb
->FileSize
.QuadPart
- StartingOffset
);
195 ByteRange
= Fcb
->FileSize
.QuadPart
;
200 // If we have an unaligned transfer then post this request if
201 // we can't wait. Unaligned means that the starting offset
202 // is not on a sector boundary or the write is not integral
206 WriteByteCount
= BlockAlign( Fcb
->Vcb
, ByteCount
);
208 if (SectorOffset( StartingOffset
) ||
209 SectorOffset( WriteByteCount
) ||
210 (WriteByteCount
> OriginalByteCount
)) {
214 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
218 // Make sure we don't overwrite the buffer.
221 WriteByteCount
= ByteCount
;
225 // Initialize the IoContext for the write.
226 // If there is a context pointer, we need to make sure it was
227 // allocated and not a stale stack pointer.
230 if (IrpContext
->IoContext
== NULL
||
231 !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
234 // If we can wait, use the context on the stack. Otherwise
235 // we need to allocate one.
240 IrpContext
->IoContext
= &LocalIoContext
;
241 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
245 IrpContext
->IoContext
= CdAllocateIoContext();
246 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
250 RtlZeroMemory( IrpContext
->IoContext
, sizeof( CD_IO_CONTEXT
) );
253 // Store whether we allocated this context structure in the structure
257 IrpContext
->IoContext
->AllocatedContext
=
258 BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
262 KeInitializeEvent( &IrpContext
->IoContext
->SyncEvent
,
268 IrpContext
->IoContext
->ResourceThreadId
= ExGetCurrentResourceThread();
269 IrpContext
->IoContext
->Resource
= Fcb
->Resource
;
270 IrpContext
->IoContext
->RequestedByteCount
= ByteCount
;
273 Irp
->IoStatus
.Information
= WriteByteCount
;
276 // Set the FO_MODIFIED flag here to trigger a verify when this
277 // handle is closed. Note that we can err on the conservative
278 // side with no problem, i.e. if we accidently do an extra
279 // verify there is no problem.
282 SetFlag( IrpSp
->FileObject
->Flags
, FO_FILE_MODIFIED
);
285 // Dasd access is always non-cached. Call the Dasd write routine to
286 // perform the actual write.
289 Status
= CdVolumeDasdWrite( IrpContext
, Fcb
, StartingOffset
, WriteByteCount
);
292 // Don't complete this request now if STATUS_PENDING was returned.
295 if (Status
== STATUS_PENDING
) {
301 // Test is we should zero part of the buffer or update the
302 // synchronous file position.
308 // Convert any unknown error code to IO_ERROR.
311 if (!NT_SUCCESS( Status
)) {
314 // Set the information field to zero.
317 Irp
->IoStatus
.Information
= 0;
320 // Raise if this is a user induced error.
323 if (IoIsErrorUserInduced( Status
)) {
325 CdRaiseStatus( IrpContext
, Status
);
328 Status
= FsRtlNormalizeNtstatus( Status
, STATUS_UNEXPECTED_IO_ERROR
);
331 // Check if there is any portion of the user's buffer to zero.
334 } else if (WriteByteCount
!= ByteCount
) {
336 CdMapUserBuffer( IrpContext
, &UserBuffer
);
338 SafeZeroMemory( IrpContext
,
342 WriteByteCount
- ByteCount
);
344 Irp
->IoStatus
.Information
= ByteCount
;
348 // Update the file position if this is a synchronous request.
351 if (SynchronousIo
&& NT_SUCCESS( Status
)) {
353 IrpSp
->FileObject
->CurrentByteOffset
.QuadPart
= ByteRange
;
366 CdReleaseFile( IrpContext
, Fcb
);
371 // Post the request if we got CANT_WAIT.
374 if (Status
== STATUS_CANT_WAIT
) {
376 Status
= CdFsdPostRequest( IrpContext
, Irp
);
379 // Otherwise complete the request.
384 CdCompleteRequest( IrpContext
, Irp
, Status
);