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 DPRINT1("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 DPRINT1("%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 LengthWritten
287 * Pointer to a ULONG. This ULONG will be set to the number of bytes successfully written.
290 * STATUS_SUCCESS if successful, STATUS_NOT_IMPLEMENTED if a required feature isn't implemented,
291 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_ACCESS_DENIED if the write itself fails,
292 * STATUS_PARTIAL_COPY or STATUS_UNSUCCESSFUL if ReadFileRecord() fails, or
293 * STATUS_OBJECT_NAME_NOT_FOUND if the file's data stream could not be found.
295 * @remarks Called by NtfsWrite(). It may perform a read-modify-write operation if the requested write is
296 * not sector-aligned. LengthWritten only refers to how much of the requested data has been written;
297 * extra data that needs to be written to make the write sector-aligned will not affect it.
300 NTSTATUS
NtfsWriteFile(PDEVICE_EXTENSION DeviceExt
,
301 PFILE_OBJECT FileObject
,
306 PULONG LengthWritten
)
308 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
310 PFILE_RECORD_HEADER FileRecord
;
311 PNTFS_ATTR_CONTEXT DataContext
;
312 ULONG AttributeOffset
;
313 ULONGLONG StreamSize
;
315 DPRINT("NtfsWriteFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt
, FileObject
, Buffer
, Length
, WriteOffset
, IrpFlags
, LengthWritten
);
324 return STATUS_SUCCESS
;
326 return STATUS_INVALID_PARAMETER
;
329 // get the File control block
330 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
333 DPRINT("Fcb->PathName: %wS\n", Fcb
->PathName
);
334 DPRINT("Fcb->ObjectName: %wS\n", Fcb
->ObjectName
);
336 // we don't yet handle compression
337 if (NtfsFCBIsCompressed(Fcb
))
339 DPRINT("Compressed file!\n");
341 return STATUS_NOT_IMPLEMENTED
;
344 // allocate non-paged memory for the FILE_RECORD_HEADER
345 FileRecord
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExt
->NtfsInfo
.BytesPerFileRecord
, TAG_NTFS
);
346 if (FileRecord
== NULL
)
348 DPRINT1("Not enough memory! Can't write %wS!\n", Fcb
->PathName
);
349 return STATUS_INSUFFICIENT_RESOURCES
;
352 // read the FILE_RECORD_HEADER from the drive (or cache)
353 DPRINT("Reading file record...\n");
354 Status
= ReadFileRecord(DeviceExt
, Fcb
->MFTIndex
, FileRecord
);
355 if (!NT_SUCCESS(Status
))
357 // We couldn't get the file's record. Free the memory and return the error
358 DPRINT1("Can't find record for %wS!\n", Fcb
->ObjectName
);
359 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
363 DPRINT("Found record for %wS\n", Fcb
->ObjectName
);
365 // Find the attribute with the data stream for our file
366 DPRINT("Finding Data Attribute...\n");
367 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Fcb
->Stream
, wcslen(Fcb
->Stream
), &DataContext
,
370 // Did we fail to find the attribute?
371 if (!NT_SUCCESS(Status
))
373 NTSTATUS BrowseStatus
;
374 FIND_ATTR_CONTXT Context
;
375 PNTFS_ATTR_RECORD Attribute
;
377 DPRINT1("No '%S' data stream associated with file!\n", Fcb
->Stream
);
379 // Couldn't find the requested data stream; print a list of streams available
380 BrowseStatus
= FindFirstAttribute(&Context
, DeviceExt
, FileRecord
, FALSE
, &Attribute
);
381 while (NT_SUCCESS(BrowseStatus
))
383 if (Attribute
->Type
== AttributeData
)
387 Name
.Length
= Attribute
->NameLength
* sizeof(WCHAR
);
388 Name
.MaximumLength
= Name
.Length
;
389 Name
.Buffer
= (PWCHAR
)((ULONG_PTR
)Attribute
+ Attribute
->NameOffset
);
390 DPRINT1("Data stream: '%wZ' available\n", &Name
);
393 BrowseStatus
= FindNextAttribute(&Context
, &Attribute
);
395 FindCloseAttribute(&Context
);
397 ReleaseAttributeContext(DataContext
);
398 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
402 // Get the size of the stream on disk
403 StreamSize
= AttributeDataLength(&DataContext
->Record
);
405 DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset
, StreamSize
);
407 // Are we trying to write beyond the end of the stream?
408 if (WriteOffset
+ Length
> StreamSize
)
410 // is increasing the stream size allowed?
411 if (!(Fcb
->Flags
& FCB_IS_VOLUME
) &&
412 !(IrpFlags
& IRP_PAGING_IO
))
414 LARGE_INTEGER DataSize
;
415 ULONGLONG AllocationSize
;
416 PFILENAME_ATTRIBUTE fileNameAttribute
;
417 ULONGLONG ParentMFTId
;
418 UNICODE_STRING filename
;
420 DataSize
.QuadPart
= WriteOffset
+ Length
;
422 AllocationSize
= ROUND_UP(DataSize
.QuadPart
, Fcb
->Vcb
->NtfsInfo
.BytesPerCluster
);
424 // set the attribute data length
425 Status
= SetAttributeDataLength(FileObject
, Fcb
, DataContext
, AttributeOffset
, FileRecord
, &DataSize
);
427 if (!NT_SUCCESS(Status
))
429 ReleaseAttributeContext(DataContext
);
430 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
435 // at this point the record in DataContext may be stale, so we need to refresh it
436 ReleaseAttributeContext(DataContext
);
438 Status
= FindAttribute(DeviceExt
,
445 if (!NT_SUCCESS(Status
))
447 DPRINT1("DRIVER ERROR: Couldn't find $DATA attribute after setting size!\n");
451 // now we need to update this file's size in every directory index entry that references it
452 // TODO: put this code in its own function and adapt it to work with every filename / hardlink
453 // stored in the file record.
454 fileNameAttribute
= GetBestFileNameFromRecord(Fcb
->Vcb
, FileRecord
);
455 ASSERT(fileNameAttribute
);
457 ParentMFTId
= fileNameAttribute
->DirectoryFileReferenceNumber
& NTFS_MFT_MASK
;
459 filename
.Buffer
= fileNameAttribute
->Name
;
460 filename
.Length
= fileNameAttribute
->NameLength
* sizeof(WCHAR
);
461 filename
.MaximumLength
= filename
.Length
;
463 Status
= UpdateFileNameRecord(Fcb
->Vcb
, ParentMFTId
, &filename
, FALSE
, DataSize
.QuadPart
, AllocationSize
);
468 // TODO - just fail for now
469 ReleaseAttributeContext(DataContext
);
470 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
472 return STATUS_ACCESS_DENIED
;
476 DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length
, WriteOffset
, StreamSize
);
478 // Write the data to the attribute
479 Status
= WriteAttribute(DeviceExt
, DataContext
, WriteOffset
, Buffer
, Length
, LengthWritten
);
481 // Did the write fail?
482 if (!NT_SUCCESS(Status
))
484 DPRINT1("Write failure!\n");
485 ReleaseAttributeContext(DataContext
);
486 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
491 // This should never happen:
492 if (*LengthWritten
!= Length
)
494 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
495 *LengthWritten
, Length
);
496 Status
= STATUS_UNEXPECTED_IO_ERROR
;
499 ReleaseAttributeContext(DataContext
);
500 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
509 * Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from
510 * VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code
511 * from VfatWrite integrated.
514 * Points to an NTFS_IRP_CONTEXT which describes the write
517 * STATUS_SUCCESS if successful,
518 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
519 * STATUS_INVALID_DEVICE_REQUEST if called on the main device object,
520 * STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented.
521 * STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
523 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented.
524 * Support for large files (>4gb) is not implemented. Cached writes, file locks, transactions, etc - not implemented.
528 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext
)
531 PERESOURCE Resource
= NULL
;
532 LARGE_INTEGER ByteOffset
;
534 NTSTATUS Status
= STATUS_SUCCESS
;
536 ULONG ReturnedWriteLength
= 0;
537 PDEVICE_OBJECT DeviceObject
= NULL
;
538 PDEVICE_EXTENSION DeviceExt
= NULL
;
539 PFILE_OBJECT FileObject
= NULL
;
541 ULONG BytesPerSector
;
543 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext
);
546 // This request is not allowed on the main device object
547 if (IrpContext
->DeviceObject
== NtfsGlobalData
->DeviceObject
)
549 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
551 Irp
->IoStatus
.Information
= 0;
552 return STATUS_INVALID_DEVICE_REQUEST
;
555 // get the I/O request packet
556 Irp
= IrpContext
->Irp
;
558 // get the File control block
559 Fcb
= (PNTFS_FCB
)IrpContext
->FileObject
->FsContext
;
562 DPRINT("About to write %wS\n", Fcb
->ObjectName
);
563 DPRINT("NTFS Version: %d.%d\n", Fcb
->Vcb
->NtfsInfo
.MajorVersion
, Fcb
->Vcb
->NtfsInfo
.MinorVersion
);
565 // setup some more locals
566 FileObject
= IrpContext
->FileObject
;
567 DeviceObject
= IrpContext
->DeviceObject
;
568 DeviceExt
= DeviceObject
->DeviceExtension
;
569 BytesPerSector
= DeviceExt
->StorageDevice
->SectorSize
;
570 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
572 // get the file offset we'll be writing to
573 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
574 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
575 ByteOffset
.u
.HighPart
== -1)
577 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
580 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset
.QuadPart
,
581 Length
, BytesPerSector
);
583 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
585 // TODO: Support large files
586 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
587 return STATUS_INVALID_PARAMETER
;
590 // Is this a non-cached write? A non-buffered write?
591 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
) ||
592 IrpContext
->FileObject
->Flags
& FILE_NO_INTERMEDIATE_BUFFERING
)
594 // non-cached and non-buffered writes must be sector aligned
595 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
597 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
598 return STATUS_INVALID_PARAMETER
;
604 DPRINT1("Null write!\n");
606 IrpContext
->Irp
->IoStatus
.Information
= 0;
608 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
609 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
611 // FIXME: Update last write time
612 return STATUS_SUCCESS
;
615 return STATUS_INVALID_PARAMETER
;
619 if (Fcb
->Flags
& FCB_IS_VOLUME
)
621 Resource
= &DeviceExt
->DirResource
;
623 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
625 Resource
= &Fcb
->PagingIoResource
;
629 Resource
= &Fcb
->MainResource
;
632 // acquire exclusive access to the Resource
633 if (!ExAcquireResourceExclusiveLite(Resource
, BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
635 return STATUS_CANT_WAIT
;
638 /* From VfatWrite(). Todo: Handle file locks
639 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
640 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
642 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
644 Status = STATUS_FILE_LOCK_CONFLICT;
649 // Is this an async request to a file?
650 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
652 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
654 ExReleaseResourceLite(Resource
);
655 return STATUS_NOT_IMPLEMENTED
;
658 // get the buffer of data the user is trying to write
659 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
663 Status
= NtfsLockUserBuffer(Irp
, Length
, IoReadAccess
);
665 // were we unable to lock the buffer?
666 if (!NT_SUCCESS(Status
))
668 DPRINT1("Unable to lock user buffer!\n");
670 ExReleaseResourceLite(Resource
);
674 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb
->RFCB
.FileSize
.QuadPart
);
675 DPRINT("About to write the data. Length: %lu\n", Length
);
677 // TODO: handle HighPart of ByteOffset (large files)
680 Status
= NtfsWriteFile(DeviceExt
,
686 &ReturnedWriteLength
);
688 IrpContext
->Irp
->IoStatus
.Status
= Status
;
690 // was the write successful?
691 if (NT_SUCCESS(Status
))
693 // TODO: Update timestamps
695 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
697 // advance the file pointer
698 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ ReturnedWriteLength
;
701 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
705 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength
);
708 Irp
->IoStatus
.Information
= ReturnedWriteLength
;
710 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
712 ExReleaseResourceLite(Resource
);