3 * Copyright (C) 2002, 2014 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/rw.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Art Yerkes
24 * Pierre Schweitzer (pierre@reactos.org)
28 /* INCLUDES *****************************************************************/
36 /* FUNCTIONS ****************************************************************/
39 * FUNCTION: Reads data from a file
43 NtfsReadFile(PDEVICE_EXTENSION DeviceExt
,
44 PFILE_OBJECT FileObject
,
51 NTSTATUS Status
= STATUS_SUCCESS
;
53 PFILE_RECORD_HEADER FileRecord
;
54 PNTFS_ATTR_CONTEXT DataContext
;
59 BOOLEAN AllocatedBuffer
= FALSE
;
60 PCHAR ReadBuffer
= (PCHAR
)Buffer
;
63 DPRINT1("NtfsReadFile(%p, %p, %p, %lu, %lu, %lx, %p)\n", DeviceExt
, FileObject
, Buffer
, Length
, ReadOffset
, IrpFlags
, LengthRead
);
69 DPRINT1("Null read!\n");
70 return STATUS_SUCCESS
;
73 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
75 if (NtfsFCBIsCompressed(Fcb
))
77 DPRINT1("Compressed file!\n");
79 return STATUS_NOT_IMPLEMENTED
;
82 FileRecord
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExt
->NtfsInfo
.BytesPerFileRecord
, TAG_NTFS
);
83 if (FileRecord
== NULL
)
85 DPRINT1("Not enough memory!\n");
86 return STATUS_INSUFFICIENT_RESOURCES
;
89 Status
= ReadFileRecord(DeviceExt
, Fcb
->MFTIndex
, FileRecord
);
90 if (!NT_SUCCESS(Status
))
92 DPRINT1("Can't find record!\n");
93 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
98 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Fcb
->Stream
, wcslen(Fcb
->Stream
), &DataContext
, NULL
);
99 if (!NT_SUCCESS(Status
))
101 NTSTATUS BrowseStatus
;
102 FIND_ATTR_CONTXT Context
;
103 PNTFS_ATTR_RECORD Attribute
;
105 DPRINT1("No '%S' data stream associated with file!\n", Fcb
->Stream
);
107 BrowseStatus
= FindFirstAttribute(&Context
, DeviceExt
, FileRecord
, FALSE
, &Attribute
);
108 while (NT_SUCCESS(BrowseStatus
))
110 if (Attribute
->Type
== AttributeData
)
114 Name
.Length
= Attribute
->NameLength
* sizeof(WCHAR
);
115 Name
.MaximumLength
= Name
.Length
;
116 Name
.Buffer
= (PWCHAR
)((ULONG_PTR
)Attribute
+ Attribute
->NameOffset
);
117 DPRINT1("Data stream: '%wZ' available\n", &Name
);
120 BrowseStatus
= FindNextAttribute(&Context
, &Attribute
);
122 FindCloseAttribute(&Context
);
124 ReleaseAttributeContext(DataContext
);
125 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
129 StreamSize
= AttributeDataLength(DataContext
->pRecord
);
130 if (ReadOffset
>= StreamSize
)
132 DPRINT1("Reading beyond stream end!\n");
133 ReleaseAttributeContext(DataContext
);
134 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
135 return STATUS_END_OF_FILE
;
139 if (ReadOffset
+ Length
> StreamSize
)
140 ToRead
= StreamSize
- ReadOffset
;
142 RealReadOffset
= ReadOffset
;
145 if ((ReadOffset
% DeviceExt
->NtfsInfo
.BytesPerSector
) != 0 || (ToRead
% DeviceExt
->NtfsInfo
.BytesPerSector
) != 0)
147 RealReadOffset
= ROUND_DOWN(ReadOffset
, DeviceExt
->NtfsInfo
.BytesPerSector
);
148 RealLength
= ROUND_UP(ToRead
, DeviceExt
->NtfsInfo
.BytesPerSector
);
149 /* do we need to extend RealLength by one sector? */
150 if (RealLength
+ RealReadOffset
< ReadOffset
+ Length
)
152 if (RealReadOffset
+ RealLength
+ DeviceExt
->NtfsInfo
.BytesPerSector
<= AttributeAllocatedLength(DataContext
->pRecord
))
153 RealLength
+= DeviceExt
->NtfsInfo
.BytesPerSector
;
157 ReadBuffer
= ExAllocatePoolWithTag(NonPagedPool
, RealLength
, TAG_NTFS
);
158 if (ReadBuffer
== NULL
)
160 DPRINT1("Not enough memory!\n");
161 ReleaseAttributeContext(DataContext
);
162 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
163 return STATUS_INSUFFICIENT_RESOURCES
;
165 AllocatedBuffer
= TRUE
;
168 DPRINT("Effective read: %lu at %lu for stream '%S'\n", RealLength
, RealReadOffset
, Fcb
->Stream
);
169 RealLengthRead
= ReadAttribute(DeviceExt
, DataContext
, RealReadOffset
, (PCHAR
)ReadBuffer
, RealLength
);
170 if (RealLengthRead
== 0)
172 DPRINT1("Read failure!\n");
173 ReleaseAttributeContext(DataContext
);
174 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
177 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
182 ReleaseAttributeContext(DataContext
);
183 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
185 *LengthRead
= ToRead
;
187 DPRINT("%lu got read\n", *LengthRead
);
191 RtlCopyMemory(Buffer
, ReadBuffer
+ (ReadOffset
- RealReadOffset
), ToRead
);
194 if (ToRead
!= Length
)
196 RtlZeroMemory(Buffer
+ ToRead
, Length
- ToRead
);
201 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
204 return STATUS_SUCCESS
;
209 NtfsRead(PNTFS_IRP_CONTEXT IrpContext
)
211 PDEVICE_EXTENSION DeviceExt
;
212 PIO_STACK_LOCATION Stack
;
213 PFILE_OBJECT FileObject
;
216 LARGE_INTEGER ReadOffset
;
217 ULONG ReturnedReadLength
= 0;
218 NTSTATUS Status
= STATUS_SUCCESS
;
220 PDEVICE_OBJECT DeviceObject
;
222 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext
);
224 DeviceObject
= IrpContext
->DeviceObject
;
225 Irp
= IrpContext
->Irp
;
226 Stack
= IrpContext
->Stack
;
227 FileObject
= IrpContext
->FileObject
;
229 DeviceExt
= DeviceObject
->DeviceExtension
;
230 ReadLength
= Stack
->Parameters
.Read
.Length
;
231 ReadOffset
= Stack
->Parameters
.Read
.ByteOffset
;
232 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
234 Status
= NtfsReadFile(DeviceExt
,
238 ReadOffset
.u
.LowPart
,
240 &ReturnedReadLength
);
241 if (NT_SUCCESS(Status
))
243 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
245 FileObject
->CurrentByteOffset
.QuadPart
=
246 ReadOffset
.QuadPart
+ ReturnedReadLength
;
249 Irp
->IoStatus
.Information
= ReturnedReadLength
;
253 Irp
->IoStatus
.Information
= 0;
260 * @name NtfsWriteFile
263 * Writes a file to the disk. It presently borrows a lot of code from NtfsReadFile() and
264 * VFatWriteFileData(). It needs some more work before it will be complete; it won't handle
265 * page files, asnyc io, cached writes, etc.
268 * Points to the target disk's DEVICE_EXTENSION
271 * Pointer to a FILE_OBJECT describing the target file
274 * The data that's being written to the file
277 * The size of the data buffer being written, in bytes
280 * Offset, in bytes, from the beginning of the file. Indicates where to start
284 * TODO: flags are presently ignored in code.
286 * @param CaseSensitive
287 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
288 * if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag.
290 * @param LengthWritten
291 * Pointer to a ULONG. This ULONG will be set to the number of bytes successfully written.
294 * STATUS_SUCCESS if successful, STATUS_NOT_IMPLEMENTED if a required feature isn't implemented,
295 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_ACCESS_DENIED if the write itself fails,
296 * STATUS_PARTIAL_COPY or STATUS_UNSUCCESSFUL if ReadFileRecord() fails, or
297 * STATUS_OBJECT_NAME_NOT_FOUND if the file's data stream could not be found.
299 * @remarks Called by NtfsWrite(). It may perform a read-modify-write operation if the requested write is
300 * not sector-aligned. LengthWritten only refers to how much of the requested data has been written;
301 * extra data that needs to be written to make the write sector-aligned will not affect it.
304 NTSTATUS
NtfsWriteFile(PDEVICE_EXTENSION DeviceExt
,
305 PFILE_OBJECT FileObject
,
310 BOOLEAN CaseSensitive
,
311 PULONG LengthWritten
)
313 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
315 PFILE_RECORD_HEADER FileRecord
;
316 PNTFS_ATTR_CONTEXT DataContext
;
317 ULONG AttributeOffset
;
318 ULONGLONG StreamSize
;
320 DPRINT("NtfsWriteFile(%p, %p, %p, %lu, %lu, %x, %s, %p)\n",
327 (CaseSensitive
? "TRUE" : "FALSE"),
337 return STATUS_SUCCESS
;
339 return STATUS_INVALID_PARAMETER
;
342 // get the File control block
343 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
346 DPRINT("Fcb->PathName: %wS\n", Fcb
->PathName
);
347 DPRINT("Fcb->ObjectName: %wS\n", Fcb
->ObjectName
);
349 // we don't yet handle compression
350 if (NtfsFCBIsCompressed(Fcb
))
352 DPRINT("Compressed file!\n");
354 return STATUS_NOT_IMPLEMENTED
;
357 // allocate non-paged memory for the FILE_RECORD_HEADER
358 FileRecord
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExt
->NtfsInfo
.BytesPerFileRecord
, TAG_NTFS
);
359 if (FileRecord
== NULL
)
361 DPRINT1("Not enough memory! Can't write %wS!\n", Fcb
->PathName
);
362 return STATUS_INSUFFICIENT_RESOURCES
;
365 // read the FILE_RECORD_HEADER from the drive (or cache)
366 DPRINT("Reading file record...\n");
367 Status
= ReadFileRecord(DeviceExt
, Fcb
->MFTIndex
, FileRecord
);
368 if (!NT_SUCCESS(Status
))
370 // We couldn't get the file's record. Free the memory and return the error
371 DPRINT1("Can't find record for %wS!\n", Fcb
->ObjectName
);
372 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
376 DPRINT("Found record for %wS\n", Fcb
->ObjectName
);
378 // Find the attribute with the data stream for our file
379 DPRINT("Finding Data Attribute...\n");
380 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Fcb
->Stream
, wcslen(Fcb
->Stream
), &DataContext
,
383 // Did we fail to find the attribute?
384 if (!NT_SUCCESS(Status
))
386 NTSTATUS BrowseStatus
;
387 FIND_ATTR_CONTXT Context
;
388 PNTFS_ATTR_RECORD Attribute
;
390 DPRINT1("No '%S' data stream associated with file!\n", Fcb
->Stream
);
392 // Couldn't find the requested data stream; print a list of streams available
393 BrowseStatus
= FindFirstAttribute(&Context
, DeviceExt
, FileRecord
, FALSE
, &Attribute
);
394 while (NT_SUCCESS(BrowseStatus
))
396 if (Attribute
->Type
== AttributeData
)
400 Name
.Length
= Attribute
->NameLength
* sizeof(WCHAR
);
401 Name
.MaximumLength
= Name
.Length
;
402 Name
.Buffer
= (PWCHAR
)((ULONG_PTR
)Attribute
+ Attribute
->NameOffset
);
403 DPRINT1("Data stream: '%wZ' available\n", &Name
);
406 BrowseStatus
= FindNextAttribute(&Context
, &Attribute
);
408 FindCloseAttribute(&Context
);
410 ReleaseAttributeContext(DataContext
);
411 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
415 // Get the size of the stream on disk
416 StreamSize
= AttributeDataLength(DataContext
->pRecord
);
418 DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset
, StreamSize
);
420 // Are we trying to write beyond the end of the stream?
421 if (WriteOffset
+ Length
> StreamSize
)
423 // is increasing the stream size allowed?
424 if (!(Fcb
->Flags
& FCB_IS_VOLUME
) &&
425 !(IrpFlags
& IRP_PAGING_IO
))
427 LARGE_INTEGER DataSize
;
428 ULONGLONG AllocationSize
;
429 PFILENAME_ATTRIBUTE fileNameAttribute
;
430 ULONGLONG ParentMFTId
;
431 UNICODE_STRING filename
;
433 DataSize
.QuadPart
= WriteOffset
+ Length
;
435 // set the attribute data length
436 Status
= SetAttributeDataLength(FileObject
, Fcb
, DataContext
, AttributeOffset
, FileRecord
, &DataSize
);
437 if (!NT_SUCCESS(Status
))
439 ReleaseAttributeContext(DataContext
);
440 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
445 AllocationSize
= AttributeAllocatedLength(DataContext
->pRecord
);
447 // now we need to update this file's size in every directory index entry that references it
448 // TODO: put this code in its own function and adapt it to work with every filename / hardlink
449 // stored in the file record.
450 fileNameAttribute
= GetBestFileNameFromRecord(Fcb
->Vcb
, FileRecord
);
451 ASSERT(fileNameAttribute
);
453 ParentMFTId
= fileNameAttribute
->DirectoryFileReferenceNumber
& NTFS_MFT_MASK
;
455 filename
.Buffer
= fileNameAttribute
->Name
;
456 filename
.Length
= fileNameAttribute
->NameLength
* sizeof(WCHAR
);
457 filename
.MaximumLength
= filename
.Length
;
459 Status
= UpdateFileNameRecord(Fcb
->Vcb
,
470 // TODO - just fail for now
471 ReleaseAttributeContext(DataContext
);
472 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
474 return STATUS_ACCESS_DENIED
;
478 DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length
, WriteOffset
, StreamSize
);
480 // Write the data to the attribute
481 Status
= WriteAttribute(DeviceExt
, DataContext
, WriteOffset
, Buffer
, Length
, LengthWritten
, FileRecord
);
483 // Did the write fail?
484 if (!NT_SUCCESS(Status
))
486 DPRINT1("Write failure!\n");
487 ReleaseAttributeContext(DataContext
);
488 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
493 // This should never happen:
494 if (*LengthWritten
!= Length
)
496 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
497 *LengthWritten
, Length
);
498 Status
= STATUS_UNEXPECTED_IO_ERROR
;
501 ReleaseAttributeContext(DataContext
);
502 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
511 * Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from
512 * VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code
513 * from VfatWrite integrated.
516 * Points to an NTFS_IRP_CONTEXT which describes the write
519 * STATUS_SUCCESS if successful,
520 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
521 * STATUS_INVALID_DEVICE_REQUEST if called on the main device object,
522 * STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented.
523 * STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
525 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented.
526 * Support for large files (>4gb) is not implemented. Cached writes, file locks, transactions, etc - not implemented.
530 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext
)
533 PERESOURCE Resource
= NULL
;
534 LARGE_INTEGER ByteOffset
;
536 NTSTATUS Status
= STATUS_SUCCESS
;
538 ULONG ReturnedWriteLength
= 0;
539 PDEVICE_OBJECT DeviceObject
= NULL
;
540 PDEVICE_EXTENSION DeviceExt
= NULL
;
541 PFILE_OBJECT FileObject
= NULL
;
543 ULONG BytesPerSector
;
545 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext
);
548 // This request is not allowed on the main device object
549 if (IrpContext
->DeviceObject
== NtfsGlobalData
->DeviceObject
)
551 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
553 Irp
->IoStatus
.Information
= 0;
554 return STATUS_INVALID_DEVICE_REQUEST
;
557 // get the I/O request packet
558 Irp
= IrpContext
->Irp
;
560 // get the File control block
561 Fcb
= (PNTFS_FCB
)IrpContext
->FileObject
->FsContext
;
564 DPRINT("About to write %wS\n", Fcb
->ObjectName
);
565 DPRINT("NTFS Version: %d.%d\n", Fcb
->Vcb
->NtfsInfo
.MajorVersion
, Fcb
->Vcb
->NtfsInfo
.MinorVersion
);
567 // setup some more locals
568 FileObject
= IrpContext
->FileObject
;
569 DeviceObject
= IrpContext
->DeviceObject
;
570 DeviceExt
= DeviceObject
->DeviceExtension
;
571 BytesPerSector
= DeviceExt
->StorageDevice
->SectorSize
;
572 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
574 // get the file offset we'll be writing to
575 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
576 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
577 ByteOffset
.u
.HighPart
== -1)
579 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
582 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset
.QuadPart
,
583 Length
, BytesPerSector
);
585 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
587 // TODO: Support large files
588 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
589 return STATUS_INVALID_PARAMETER
;
592 // Is this a non-cached write? A non-buffered write?
593 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
) ||
594 IrpContext
->FileObject
->Flags
& FILE_NO_INTERMEDIATE_BUFFERING
)
596 // non-cached and non-buffered writes must be sector aligned
597 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
599 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
600 return STATUS_INVALID_PARAMETER
;
606 DPRINT1("Null write!\n");
608 IrpContext
->Irp
->IoStatus
.Information
= 0;
610 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
611 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
613 // FIXME: Update last write time
614 return STATUS_SUCCESS
;
617 return STATUS_INVALID_PARAMETER
;
621 if (Fcb
->Flags
& FCB_IS_VOLUME
)
623 Resource
= &DeviceExt
->DirResource
;
625 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
627 Resource
= &Fcb
->PagingIoResource
;
631 Resource
= &Fcb
->MainResource
;
634 // acquire exclusive access to the Resource
635 if (!ExAcquireResourceExclusiveLite(Resource
, BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
637 return STATUS_CANT_WAIT
;
640 /* From VfatWrite(). Todo: Handle file locks
641 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
642 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
644 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
646 Status = STATUS_FILE_LOCK_CONFLICT;
651 // Is this an async request to a file?
652 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
654 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
656 ExReleaseResourceLite(Resource
);
657 return STATUS_NOT_IMPLEMENTED
;
660 // get the buffer of data the user is trying to write
661 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
665 Status
= NtfsLockUserBuffer(Irp
, Length
, IoReadAccess
);
667 // were we unable to lock the buffer?
668 if (!NT_SUCCESS(Status
))
670 DPRINT1("Unable to lock user buffer!\n");
672 ExReleaseResourceLite(Resource
);
676 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb
->RFCB
.FileSize
.QuadPart
);
677 DPRINT("About to write the data. Length: %lu\n", Length
);
679 // TODO: handle HighPart of ByteOffset (large files)
682 Status
= NtfsWriteFile(DeviceExt
,
688 BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_CASE_SENSITIVE
),
689 &ReturnedWriteLength
);
691 IrpContext
->Irp
->IoStatus
.Status
= Status
;
693 // was the write successful?
694 if (NT_SUCCESS(Status
))
696 // TODO: Update timestamps
698 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
700 // advance the file pointer
701 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ ReturnedWriteLength
;
704 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
708 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength
);
711 Irp
->IoStatus
.Information
= ReturnedWriteLength
;
713 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
715 ExReleaseResourceLite(Resource
);