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, %u, %u, %x, %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
->Record
);
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
->Record
))
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, %u, %u, %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
->Record
);
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 AllocationSize
= ROUND_UP(DataSize
.QuadPart
, Fcb
->Vcb
->NtfsInfo
.BytesPerCluster
);
437 // set the attribute data length
438 Status
= SetAttributeDataLength(FileObject
, Fcb
, DataContext
, AttributeOffset
, FileRecord
, &DataSize
);
440 if (!NT_SUCCESS(Status
))
442 ReleaseAttributeContext(DataContext
);
443 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
448 // now we need to update this file's size in every directory index entry that references it
449 // TODO: put this code in its own function and adapt it to work with every filename / hardlink
450 // stored in the file record.
451 fileNameAttribute
= GetBestFileNameFromRecord(Fcb
->Vcb
, FileRecord
);
452 ASSERT(fileNameAttribute
);
454 ParentMFTId
= fileNameAttribute
->DirectoryFileReferenceNumber
& NTFS_MFT_MASK
;
456 filename
.Buffer
= fileNameAttribute
->Name
;
457 filename
.Length
= fileNameAttribute
->NameLength
* sizeof(WCHAR
);
458 filename
.MaximumLength
= filename
.Length
;
460 Status
= UpdateFileNameRecord(Fcb
->Vcb
,
471 // TODO - just fail for now
472 ReleaseAttributeContext(DataContext
);
473 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
475 return STATUS_ACCESS_DENIED
;
479 DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length
, WriteOffset
, StreamSize
);
481 // Write the data to the attribute
482 Status
= WriteAttribute(DeviceExt
, DataContext
, WriteOffset
, Buffer
, Length
, LengthWritten
);
484 // Did the write fail?
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("Write failure!\n");
488 ReleaseAttributeContext(DataContext
);
489 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
494 // This should never happen:
495 if (*LengthWritten
!= Length
)
497 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
498 *LengthWritten
, Length
);
499 Status
= STATUS_UNEXPECTED_IO_ERROR
;
502 ReleaseAttributeContext(DataContext
);
503 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
512 * Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from
513 * VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code
514 * from VfatWrite integrated.
517 * Points to an NTFS_IRP_CONTEXT which describes the write
520 * STATUS_SUCCESS if successful,
521 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
522 * STATUS_INVALID_DEVICE_REQUEST if called on the main device object,
523 * STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented.
524 * STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
526 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented.
527 * Support for large files (>4gb) is not implemented. Cached writes, file locks, transactions, etc - not implemented.
531 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext
)
534 PERESOURCE Resource
= NULL
;
535 LARGE_INTEGER ByteOffset
;
537 NTSTATUS Status
= STATUS_SUCCESS
;
539 ULONG ReturnedWriteLength
= 0;
540 PDEVICE_OBJECT DeviceObject
= NULL
;
541 PDEVICE_EXTENSION DeviceExt
= NULL
;
542 PFILE_OBJECT FileObject
= NULL
;
544 ULONG BytesPerSector
;
546 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext
);
549 // This request is not allowed on the main device object
550 if (IrpContext
->DeviceObject
== NtfsGlobalData
->DeviceObject
)
552 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
554 Irp
->IoStatus
.Information
= 0;
555 return STATUS_INVALID_DEVICE_REQUEST
;
558 // get the I/O request packet
559 Irp
= IrpContext
->Irp
;
561 // get the File control block
562 Fcb
= (PNTFS_FCB
)IrpContext
->FileObject
->FsContext
;
565 DPRINT("About to write %wS\n", Fcb
->ObjectName
);
566 DPRINT("NTFS Version: %d.%d\n", Fcb
->Vcb
->NtfsInfo
.MajorVersion
, Fcb
->Vcb
->NtfsInfo
.MinorVersion
);
568 // setup some more locals
569 FileObject
= IrpContext
->FileObject
;
570 DeviceObject
= IrpContext
->DeviceObject
;
571 DeviceExt
= DeviceObject
->DeviceExtension
;
572 BytesPerSector
= DeviceExt
->StorageDevice
->SectorSize
;
573 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
575 // get the file offset we'll be writing to
576 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
577 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
578 ByteOffset
.u
.HighPart
== -1)
580 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
583 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset
.QuadPart
,
584 Length
, BytesPerSector
);
586 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
588 // TODO: Support large files
589 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
590 return STATUS_INVALID_PARAMETER
;
593 // Is this a non-cached write? A non-buffered write?
594 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
) ||
595 IrpContext
->FileObject
->Flags
& FILE_NO_INTERMEDIATE_BUFFERING
)
597 // non-cached and non-buffered writes must be sector aligned
598 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
600 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
601 return STATUS_INVALID_PARAMETER
;
607 DPRINT1("Null write!\n");
609 IrpContext
->Irp
->IoStatus
.Information
= 0;
611 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
612 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
614 // FIXME: Update last write time
615 return STATUS_SUCCESS
;
618 return STATUS_INVALID_PARAMETER
;
622 if (Fcb
->Flags
& FCB_IS_VOLUME
)
624 Resource
= &DeviceExt
->DirResource
;
626 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
628 Resource
= &Fcb
->PagingIoResource
;
632 Resource
= &Fcb
->MainResource
;
635 // acquire exclusive access to the Resource
636 if (!ExAcquireResourceExclusiveLite(Resource
, BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
638 return STATUS_CANT_WAIT
;
641 /* From VfatWrite(). Todo: Handle file locks
642 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
643 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
645 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
647 Status = STATUS_FILE_LOCK_CONFLICT;
652 // Is this an async request to a file?
653 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
655 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
657 ExReleaseResourceLite(Resource
);
658 return STATUS_NOT_IMPLEMENTED
;
661 // get the buffer of data the user is trying to write
662 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
666 Status
= NtfsLockUserBuffer(Irp
, Length
, IoReadAccess
);
668 // were we unable to lock the buffer?
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("Unable to lock user buffer!\n");
673 ExReleaseResourceLite(Resource
);
677 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb
->RFCB
.FileSize
.QuadPart
);
678 DPRINT("About to write the data. Length: %lu\n", Length
);
680 // TODO: handle HighPart of ByteOffset (large files)
683 Status
= NtfsWriteFile(DeviceExt
,
689 (IrpContext
->Stack
->Flags
& SL_CASE_SENSITIVE
),
690 &ReturnedWriteLength
);
692 IrpContext
->Irp
->IoStatus
.Status
= Status
;
694 // was the write successful?
695 if (NT_SUCCESS(Status
))
697 // TODO: Update timestamps
699 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
701 // advance the file pointer
702 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ ReturnedWriteLength
;
705 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
709 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength
);
712 Irp
->IoStatus
.Information
= ReturnedWriteLength
;
714 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
716 ExReleaseResourceLite(Resource
);