NtWriteFile must append to file if it was opened with the FILE_APPEND_DATA access.
[reactos.git] / reactos / ntoskrnl / io / rw.c
1 /* $Id: rw.c,v 1.55 2004/09/28 10:51:05 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/rw.c
6 * PURPOSE: Implements read/write APIs
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 30/05/98: Created
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* FUNCTIONS ***************************************************************/
19
20
21 /**********************************************************************
22 * NAME EXPORTED
23 * NtReadFile
24 *
25 * DESCRIPTION
26 *
27 * ARGUMENTS
28 *
29 * RETURN VALUE
30 *
31 * REVISIONS
32 *
33 * @implemented
34 */
35 NTSTATUS STDCALL
36 NtReadFile (IN HANDLE FileHandle,
37 IN HANDLE Event OPTIONAL,
38 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
39 IN PVOID ApcContext OPTIONAL,
40 OUT PIO_STATUS_BLOCK IoStatusBlock,
41 OUT PVOID Buffer,
42 IN ULONG Length,
43 IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
44 IN PULONG Key OPTIONAL)
45 {
46 NTSTATUS Status;
47 PFILE_OBJECT FileObject;
48 PIRP Irp;
49 PIO_STACK_LOCATION StackPtr;
50 KPROCESSOR_MODE PreviousMode;
51 PKEVENT EventObject = NULL;
52
53 DPRINT("NtReadFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
54 "IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
55 IoStatusBlock);
56
57 if (IoStatusBlock == NULL)
58 return STATUS_ACCESS_VIOLATION;
59
60 PreviousMode = ExGetPreviousMode();
61
62 Status = ObReferenceObjectByHandle(FileHandle,
63 FILE_READ_DATA,
64 IoFileObjectType,
65 PreviousMode,
66 (PVOID*)&FileObject,
67 NULL);
68 if (!NT_SUCCESS(Status))
69 {
70 return Status;
71 }
72
73 if (ByteOffset == NULL)
74 {
75 /* a valid ByteOffset is required if asynch. op. */
76 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
77 {
78 DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n");
79 ObDereferenceObject(FileObject);
80 return STATUS_INVALID_PARAMETER;
81 }
82
83 ByteOffset = &FileObject->CurrentByteOffset;
84 }
85
86 if (Event != NULL)
87 {
88 Status = ObReferenceObjectByHandle(Event,
89 SYNCHRONIZE,
90 ExEventObjectType,
91 PreviousMode,
92 (PVOID*)&EventObject,
93 NULL);
94 if (!NT_SUCCESS(Status))
95 {
96 ObDereferenceObject(FileObject);
97 return Status;
98 }
99
100 KeClearEvent(EventObject);
101 }
102
103 KeClearEvent(&FileObject->Event);
104
105 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
106 FileObject->DeviceObject,
107 Buffer,
108 Length,
109 ByteOffset,
110 EventObject,
111 IoStatusBlock);
112
113 /* Trigger FileObject/Event dereferencing */
114 Irp->Tail.Overlay.OriginalFileObject = FileObject;
115
116 Irp->RequestorMode = PreviousMode;
117
118 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
119 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
120
121 StackPtr = IoGetNextIrpStackLocation(Irp);
122 StackPtr->FileObject = FileObject;
123 StackPtr->Parameters.Read.Key = Key ? *Key : 0;
124
125 Status = IoCallDriver(FileObject->DeviceObject, Irp);
126 if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
127 {
128 Status = KeWaitForSingleObject(&FileObject->Event,
129 Executive,
130 PreviousMode,
131 FileObject->Flags & FO_ALERTABLE_IO,
132 NULL);
133 if (Status != STATUS_WAIT_0)
134 {
135 /* Wait failed. */
136 return Status;
137 }
138
139 Status = IoStatusBlock->Status;
140 }
141
142 return Status;
143 }
144
145
146 /**********************************************************************
147 * NAME EXPORTED
148 * NtWriteFile
149 *
150 * DESCRIPTION
151 *
152 * ARGUMENTS
153 *
154 * RETURN VALUE
155 *
156 * REVISIONS
157 *
158 * @implemented
159 */
160 NTSTATUS STDCALL
161 NtWriteFile (IN HANDLE FileHandle,
162 IN HANDLE Event OPTIONAL,
163 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
164 IN PVOID ApcContext OPTIONAL,
165 OUT PIO_STATUS_BLOCK IoStatusBlock,
166 IN PVOID Buffer,
167 IN ULONG Length,
168 IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
169 IN PULONG Key OPTIONAL)
170 {
171 OBJECT_HANDLE_INFORMATION HandleInformation;
172 NTSTATUS Status;
173 PFILE_OBJECT FileObject;
174 PIRP Irp;
175 PIO_STACK_LOCATION StackPtr;
176 KPROCESSOR_MODE PreviousMode;
177 PKEVENT EventObject = NULL;
178 LARGE_INTEGER Offset;
179
180 DPRINT("NtWriteFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
181 "IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
182 IoStatusBlock);
183
184 if (IoStatusBlock == NULL)
185 return STATUS_ACCESS_VIOLATION;
186
187 PreviousMode = ExGetPreviousMode();
188
189 Status = ObReferenceObjectByHandle(FileHandle,
190 0,
191 IoFileObjectType,
192 PreviousMode,
193 (PVOID*)&FileObject,
194 &HandleInformation);
195 if (!NT_SUCCESS(Status))
196 {
197 return Status;
198 }
199
200 /* Must have FILE_WRITE_DATA | FILE_APPEND_DATA access */
201 if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
202 {
203 DPRINT1("Invalid access rights\n");
204 ObDereferenceObject(FileObject);
205 return STATUS_ACCESS_DENIED;
206 }
207
208 if (HandleInformation.GrantedAccess & FILE_WRITE_DATA)
209 {
210 if (ByteOffset == NULL)
211 {
212 /* a valid ByteOffset is required if asynch. op. */
213 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
214 {
215 DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
216 ObDereferenceObject(FileObject);
217 return STATUS_INVALID_PARAMETER;
218 }
219
220 ByteOffset = &FileObject->CurrentByteOffset;
221 }
222 }
223 else if (HandleInformation.GrantedAccess & FILE_APPEND_DATA)
224 {
225 /* a valid ByteOffset is required if asynch. op. */
226 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
227 {
228 DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
229 ObDereferenceObject(FileObject);
230 return STATUS_INVALID_PARAMETER;
231 }
232
233 Offset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
234 Offset.u.HighPart = 0xffffffff;
235 ByteOffset = &Offset;
236 }
237
238 if (Event != NULL)
239 {
240 Status = ObReferenceObjectByHandle(Event,
241 SYNCHRONIZE,
242 ExEventObjectType,
243 PreviousMode,
244 (PVOID*)&EventObject,
245 NULL);
246 if (!NT_SUCCESS(Status))
247 {
248 ObDereferenceObject(FileObject);
249 return Status;
250 }
251
252 KeClearEvent(EventObject);
253 }
254
255 KeClearEvent(&FileObject->Event);
256
257 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
258 FileObject->DeviceObject,
259 Buffer,
260 Length,
261 ByteOffset,
262 EventObject,
263 IoStatusBlock);
264
265 /* Trigger FileObject/Event dereferencing */
266 Irp->Tail.Overlay.OriginalFileObject = FileObject;
267
268 Irp->RequestorMode = PreviousMode;
269
270 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
271 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
272
273 StackPtr = IoGetNextIrpStackLocation(Irp);
274 StackPtr->FileObject = FileObject;
275 StackPtr->Parameters.Write.Key = Key ? *Key : 0;
276
277 Status = IoCallDriver(FileObject->DeviceObject, Irp);
278 if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
279 {
280 Status = KeWaitForSingleObject(&FileObject->Event,
281 Executive,
282 PreviousMode,
283 FileObject->Flags & FO_ALERTABLE_IO,
284 NULL);
285 if (Status != STATUS_WAIT_0)
286 {
287 /* Wait failed. */
288 return Status;
289 }
290
291 Status = IoStatusBlock->Status;
292 }
293
294 return Status;
295 }
296
297
298 /**********************************************************************
299 * NAME EXPORTED
300 * NtReadFileScatter
301 *
302 * DESCRIPTION
303 *
304 * ARGUMENTS
305 *
306 * RETURN VALUE
307 *
308 * REVISIONS
309 */
310 NTSTATUS
311 STDCALL
312 NtReadFileScatter (
313 IN HANDLE FileHandle,
314 IN HANDLE Event OPTIONAL,
315 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
316 IN PVOID UserApcContext OPTIONAL,
317 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
318 IN FILE_SEGMENT_ELEMENT BufferDescription [],
319 IN ULONG BufferLength,
320 IN PLARGE_INTEGER ByteOffset,
321 IN PULONG Key OPTIONAL
322 )
323 {
324 UNIMPLEMENTED;
325 return(STATUS_NOT_IMPLEMENTED);
326 }
327
328
329 /**********************************************************************
330 * NAME EXPORTED
331 * NtWriteFileGather
332 *
333 * DESCRIPTION
334 *
335 * ARGUMENTS
336 *
337 * RETURN VALUE
338 *
339 * REVISIONS
340 */
341 NTSTATUS
342 STDCALL
343 NtWriteFileGather (
344 IN HANDLE FileHandle,
345 IN HANDLE Event OPTIONAL,
346 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
347 IN PVOID ApcContext OPTIONAL,
348 OUT PIO_STATUS_BLOCK IoStatusBlock,
349 IN FILE_SEGMENT_ELEMENT BufferDescription [],
350 IN ULONG BufferLength,
351 IN PLARGE_INTEGER ByteOffset,
352 IN PULONG Key OPTIONAL
353 )
354 {
355 UNIMPLEMENTED;
356 return(STATUS_NOT_IMPLEMENTED);
357 }
358
359
360 /* EOF */