ReactOS  0.4.13-dev-249-gcba1a2f
write.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  Write.c
8 
9 Abstract:
10 
11  This module implements the File Write routine for Write called by the
12  Fsd/Fsp dispatch drivers.
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 // The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId (CDFS_BUG_CHECK_WRITE)
24 
25 //
26 // VOID
27 // SafeZeroMemory (
28 // _Out_ PUCHAR At,
29 // _In_ ULONG ByteCount
30 // );
31 //
32 
33 //
34 // This macro just puts a nice little try-except around RtlZeroMemory
35 //
36 
37 #ifndef __REACTOS__
38 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
39  _SEH2_TRY { \
40  RtlZeroMemory( (AT), (BYTE_COUNT) ); \
41 __pragma(warning(suppress: 6320)) \
42  } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
43  CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
44  } _SEH2_END; \
45 }
46 #else
47 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
48  _SEH2_TRY { \
49  RtlZeroMemory( (AT), (BYTE_COUNT) ); \
50  } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
51  CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
52  } _SEH2_END; \
53 }
54 #endif
55 
56 #ifdef ALLOC_PRAGMA
57 #pragma alloc_text(PAGE, CdCommonWrite)
58 #endif
59 
60 
61 _Requires_lock_held_(_Global_critical_region_)
63 CdCommonWrite (
64  _Inout_ PIRP_CONTEXT IrpContext,
66  )
67 
68 /*++
69 
70 Routine Description:
71 
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
75  block.
76 
77 Arguments:
78 
79  Irp - Supplies the Irp to process
80 
81 Return Value:
82 
83  NTSTATUS - The result of this operation.
84 
85 --*/
86 
87 {
90 
92  PFCB Fcb;
93  PCCB Ccb;
94 
95  BOOLEAN Wait;
96  ULONG SynchronousIo;
97  PVOID UserBuffer;
98 
100  LONGLONG ByteRange;
102  ULONG WriteByteCount;
103  ULONG OriginalByteCount;
104 
105  BOOLEAN ReleaseFile = TRUE;
106 
107  CD_IO_CONTEXT LocalIoContext;
108 
109  PAGED_CODE();
110 
111  //
112  // If this is a zero length write then return SUCCESS immediately.
113  //
114 
115  if (IrpSp->Parameters.Write.Length == 0) {
116 
117  CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
118  return STATUS_SUCCESS;
119  }
120 
121  //
122  // Decode the file object and verify we support write on this. It
123  // must be a volume file.
124  //
125 
126  TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
127 
128  // Internal lock object is acquired if return status is STATUS_PENDING
130 
131  if (TypeOfOpen != UserVolumeOpen) {
132 
135  }
136 
137  //
138  // Examine our input parameters to determine if this is noncached and/or
139  // a paging io operation.
140  //
141 
142  Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
143  SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );
144 
145 
146  //
147  // Extract the range of the Io.
148  //
149 
150  StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart;
151  OriginalByteCount = ByteCount = IrpSp->Parameters.Write.Length;
152 
153  ByteRange = StartingOffset + ByteCount;
154 
155  //
156  // Acquire the file shared to perform the write.
157  //
158 
159  CdAcquireFileShared( IrpContext, Fcb );
160 
161  //
162  // Use a try-finally to facilitate cleanup.
163  //
164 
165  _SEH2_TRY {
166 
167  //
168  // Verify the Fcb. Allow writes if this is a DASD handle that is
169  // dismounting the volume.
170  //
171 
173 
174  CdVerifyFcbOperation( IrpContext, Fcb );
175  }
176 
178 
179  //
180  // Complete the request if it begins beyond the end of file.
181  //
182 
183  if (StartingOffset >= Fcb->FileSize.QuadPart) {
184 
186  }
187 
188  //
189  // Truncate the write if it extends beyond the end of the file.
190  //
191 
192  if (ByteRange > Fcb->FileSize.QuadPart) {
193 
194  ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
195  ByteRange = Fcb->FileSize.QuadPart;
196  }
197  }
198 
199  //
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
203  // sectors.
204  //
205 
206  WriteByteCount = BlockAlign( Fcb->Vcb, ByteCount );
207 
208  if (SectorOffset( StartingOffset ) ||
209  SectorOffset( WriteByteCount ) ||
210  (WriteByteCount > OriginalByteCount)) {
211 
212  if (!Wait) {
213 
214  CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
215  }
216 
217  //
218  // Make sure we don't overwrite the buffer.
219  //
220 
221  WriteByteCount = ByteCount;
222  }
223 
224  //
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.
228  //
229 
230  if (IrpContext->IoContext == NULL ||
231  !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
232 
233  //
234  // If we can wait, use the context on the stack. Otherwise
235  // we need to allocate one.
236  //
237 
238  if (Wait) {
239 
240  IrpContext->IoContext = &LocalIoContext;
241  ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
242 
243  } else {
244 
245  IrpContext->IoContext = CdAllocateIoContext();
246  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
247  }
248  }
249 
250  RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ) );
251 
252  //
253  // Store whether we allocated this context structure in the structure
254  // itself.
255  //
256 
257  IrpContext->IoContext->AllocatedContext =
258  BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
259 
260  if (Wait) {
261 
262  KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
264  FALSE );
265 
266  } else {
267 
268  IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
269  IrpContext->IoContext->Resource = Fcb->Resource;
270  IrpContext->IoContext->RequestedByteCount = ByteCount;
271  }
272 
273  Irp->IoStatus.Information = WriteByteCount;
274 
275  //
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.
280  //
281 
283 
284  //
285  // Dasd access is always non-cached. Call the Dasd write routine to
286  // perform the actual write.
287  //
288 
289  Status = CdVolumeDasdWrite( IrpContext, Fcb, StartingOffset, WriteByteCount );
290 
291  //
292  // Don't complete this request now if STATUS_PENDING was returned.
293  //
294 
295  if (Status == STATUS_PENDING) {
296 
297  Irp = NULL;
298  ReleaseFile = FALSE;
299 
300  //
301  // Test is we should zero part of the buffer or update the
302  // synchronous file position.
303  //
304 
305  } else {
306 
307  //
308  // Convert any unknown error code to IO_ERROR.
309  //
310 
311  if (!NT_SUCCESS( Status )) {
312 
313  //
314  // Set the information field to zero.
315  //
316 
317  Irp->IoStatus.Information = 0;
318 
319  //
320  // Raise if this is a user induced error.
321  //
322 
323  if (IoIsErrorUserInduced( Status )) {
324 
325  CdRaiseStatus( IrpContext, Status );
326  }
327 
329 
330  //
331  // Check if there is any portion of the user's buffer to zero.
332  //
333 
334  } else if (WriteByteCount != ByteCount) {
335 
336  CdMapUserBuffer( IrpContext, &UserBuffer );
337 
338  SafeZeroMemory( IrpContext,
339  Add2Ptr( UserBuffer,
340  ByteCount,
341  PVOID ),
342  WriteByteCount - ByteCount );
343 
344  Irp->IoStatus.Information = ByteCount;
345  }
346 
347  //
348  // Update the file position if this is a synchronous request.
349  //
350 
351  if (SynchronousIo && NT_SUCCESS( Status )) {
352 
353  IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
354  }
355  }
356 
357  try_exit: NOTHING;
358  } _SEH2_FINALLY {
359 
360  //
361  // Release the Fcb.
362  //
363 
364  if (ReleaseFile) {
365 
366  CdReleaseFile( IrpContext, Fcb );
367  }
368  } _SEH2_END;
369 
370  //
371  // Post the request if we got CANT_WAIT.
372  //
373 
374  if (Status == STATUS_CANT_WAIT) {
375 
376  Status = CdFsdPostRequest( IrpContext, Irp );
377 
378  //
379  // Otherwise complete the request.
380  //
381 
382  } else {
383 
384  CdCompleteRequest( IrpContext, Irp, Status );
385  }
386 
387  return Status;
388 }
389 
390 
return TRUE
Definition: write.c:2909
#define ExGetCurrentResourceThread()
Definition: env_spec_w32.h:633
#define _Analysis_suppress_lock_checking_(lock)
Definition: no_sal2.h:685
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define Add2Ptr(PTR, INC)
NTSTATUS Status
Definition: write.c:2825
#define CCB_FLAG_DISMOUNT_ON_CLOSE
Definition: cdstruc.h:1113
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:282
#define IRP_CONTEXT_FLAG_ALLOC_IO
Definition: cdstruc.h:1227
#define CdReleaseFile(IC, F)
Definition: cdprocs.h:1008
_In_ PIRP Irp
Definition: csq.h:116
Definition: cdstruc.h:908
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
#define CCB_FLAG_ALLOW_EXTENDED_DASD_IO
Definition: cdstruc.h:1114
Definition: cdstruc.h:1073
#define CdMapUserBuffer(IC, UB)
Definition: cdprocs.h:376
#define IoIsErrorUserInduced(Status)
Definition: iofuncs.h:2769
LONG NTSTATUS
Definition: precomp.h:26
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define CdAcquireFileShared(IC, F)
Definition: cdprocs.h:1002
#define PAGED_CODE()
Definition: video.h:57
_SEH2_TRY
Definition: create.c:4250
#define STATUS_END_OF_FILE
Definition: shellext.h:62
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1732
#define FO_FILE_MODIFIED
Definition: iotypes.h:1744
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:593
VOID CdCompleteRequest(_Inout_opt_ PIRP_CONTEXT IrpContext, _Inout_opt_ PIRP Irp, _In_ NTSTATUS Status)
Definition: cddata.c:914
_Requires_lock_held_(c->lock) _When_(return !=0
#define SectorOffset(L)
Definition: cdprocs.h:1632
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define SafeZeroMemory(IC, AT, BYTE_COUNT)
Definition: write.c:38
#define BlockAlign(V, L)
Definition: cdprocs.h:1648
int64_t LONGLONG
Definition: typedefs.h:66
#define CdAllocateIoContext()
Definition: cdprocs.h:1349
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define try_return(S)
Definition: cdprocs.h:2189
#define _Inout_
Definition: no_sal2.h:244
ULONG Flags
Definition: ntfs.h:520
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:593
#define NOTHING
Definition: env_spec_w32.h:461
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1060
Status
Definition: gdiplustypes.h:24
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2812
_SEH2_END
Definition: create.c:4424
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define CdRaiseStatus(IC, S)
Definition: cdprocs.h:1869
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4157
_SEH2_FINALLY
Definition: create.c:4395
BOOLEAN CdVerifyFcbOperation(_In_opt_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb)
Definition: verfysup.c:615
#define STATUS_UNEXPECTED_IO_ERROR
Definition: ntstatus.h:455
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
PVCB Vcb
Definition: cdstruc.h:939
NTSTATUS NTAPI FsRtlNormalizeNtstatus(IN NTSTATUS NtStatusToNormalize, IN NTSTATUS NormalizedNtStatus)
Definition: filter.c:90
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
_In_ PFCB Fcb
Definition: cdprocs.h:151
return STATUS_SUCCESS
Definition: btrfs.c:2745
#define STATUS_CANT_WAIT
Definition: ntstatus.h:438
IN BOOLEAN Wait
Definition: fatprocs.h:1529