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 DPRINT("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 if (NtfsFCBIsEncrypted(Fcb
))
84 DPRINT1("Encrypted file!\n");
86 return STATUS_NOT_IMPLEMENTED
;
89 FileRecord
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
90 if (FileRecord
== NULL
)
92 DPRINT1("Not enough memory!\n");
93 return STATUS_INSUFFICIENT_RESOURCES
;
96 Status
= ReadFileRecord(DeviceExt
, Fcb
->MFTIndex
, FileRecord
);
97 if (!NT_SUCCESS(Status
))
99 DPRINT1("Can't find record!\n");
100 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
105 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Fcb
->Stream
, wcslen(Fcb
->Stream
), &DataContext
, NULL
);
106 if (!NT_SUCCESS(Status
))
108 NTSTATUS BrowseStatus
;
109 FIND_ATTR_CONTXT Context
;
110 PNTFS_ATTR_RECORD Attribute
;
112 DPRINT1("No '%S' data stream associated with file!\n", Fcb
->Stream
);
114 BrowseStatus
= FindFirstAttribute(&Context
, DeviceExt
, FileRecord
, FALSE
, &Attribute
);
115 while (NT_SUCCESS(BrowseStatus
))
117 if (Attribute
->Type
== AttributeData
)
121 Name
.Length
= Attribute
->NameLength
* sizeof(WCHAR
);
122 Name
.MaximumLength
= Name
.Length
;
123 Name
.Buffer
= (PWCHAR
)((ULONG_PTR
)Attribute
+ Attribute
->NameOffset
);
124 DPRINT1("Data stream: '%wZ' available\n", &Name
);
127 BrowseStatus
= FindNextAttribute(&Context
, &Attribute
);
129 FindCloseAttribute(&Context
);
131 ReleaseAttributeContext(DataContext
);
132 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
136 StreamSize
= AttributeDataLength(DataContext
->pRecord
);
137 if (ReadOffset
>= StreamSize
)
139 DPRINT1("Reading beyond stream end!\n");
140 ReleaseAttributeContext(DataContext
);
141 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
142 return STATUS_END_OF_FILE
;
146 if (ReadOffset
+ Length
> StreamSize
)
147 ToRead
= StreamSize
- ReadOffset
;
149 RealReadOffset
= ReadOffset
;
152 if ((ReadOffset
% DeviceExt
->NtfsInfo
.BytesPerSector
) != 0 || (ToRead
% DeviceExt
->NtfsInfo
.BytesPerSector
) != 0)
154 RealReadOffset
= ROUND_DOWN(ReadOffset
, DeviceExt
->NtfsInfo
.BytesPerSector
);
155 RealLength
= ROUND_UP(ToRead
, DeviceExt
->NtfsInfo
.BytesPerSector
);
156 /* do we need to extend RealLength by one sector? */
157 if (RealLength
+ RealReadOffset
< ReadOffset
+ Length
)
159 if (RealReadOffset
+ RealLength
+ DeviceExt
->NtfsInfo
.BytesPerSector
<= AttributeAllocatedLength(DataContext
->pRecord
))
160 RealLength
+= DeviceExt
->NtfsInfo
.BytesPerSector
;
164 ReadBuffer
= ExAllocatePoolWithTag(NonPagedPool
, RealLength
, TAG_NTFS
);
165 if (ReadBuffer
== NULL
)
167 DPRINT1("Not enough memory!\n");
168 ReleaseAttributeContext(DataContext
);
169 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
170 return STATUS_INSUFFICIENT_RESOURCES
;
172 AllocatedBuffer
= TRUE
;
175 DPRINT("Effective read: %lu at %lu for stream '%S'\n", RealLength
, RealReadOffset
, Fcb
->Stream
);
176 RealLengthRead
= ReadAttribute(DeviceExt
, DataContext
, RealReadOffset
, (PCHAR
)ReadBuffer
, RealLength
);
177 if (RealLengthRead
== 0)
179 DPRINT1("Read failure!\n");
180 ReleaseAttributeContext(DataContext
);
181 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
184 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
189 ReleaseAttributeContext(DataContext
);
190 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
192 *LengthRead
= ToRead
;
194 DPRINT("%lu got read\n", *LengthRead
);
198 RtlCopyMemory(Buffer
, ReadBuffer
+ (ReadOffset
- RealReadOffset
), ToRead
);
201 if (ToRead
!= Length
)
203 RtlZeroMemory(Buffer
+ ToRead
, Length
- ToRead
);
208 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
211 return STATUS_SUCCESS
;
216 NtfsRead(PNTFS_IRP_CONTEXT IrpContext
)
218 PDEVICE_EXTENSION DeviceExt
;
219 PIO_STACK_LOCATION Stack
;
220 PFILE_OBJECT FileObject
;
223 LARGE_INTEGER ReadOffset
;
224 ULONG ReturnedReadLength
= 0;
225 NTSTATUS Status
= STATUS_SUCCESS
;
227 PDEVICE_OBJECT DeviceObject
;
229 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext
);
231 DeviceObject
= IrpContext
->DeviceObject
;
232 Irp
= IrpContext
->Irp
;
233 Stack
= IrpContext
->Stack
;
234 FileObject
= IrpContext
->FileObject
;
236 DeviceExt
= DeviceObject
->DeviceExtension
;
237 ReadLength
= Stack
->Parameters
.Read
.Length
;
238 ReadOffset
= Stack
->Parameters
.Read
.ByteOffset
;
239 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
241 Status
= NtfsReadFile(DeviceExt
,
245 ReadOffset
.u
.LowPart
,
247 &ReturnedReadLength
);
248 if (NT_SUCCESS(Status
))
250 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
252 FileObject
->CurrentByteOffset
.QuadPart
=
253 ReadOffset
.QuadPart
+ ReturnedReadLength
;
256 Irp
->IoStatus
.Information
= ReturnedReadLength
;
260 Irp
->IoStatus
.Information
= 0;
267 * @name NtfsWriteFile
270 * Writes a file to the disk. It presently borrows a lot of code from NtfsReadFile() and
271 * VFatWriteFileData(). It needs some more work before it will be complete; it won't handle
272 * page files, asnyc io, cached writes, etc.
275 * Points to the target disk's DEVICE_EXTENSION
278 * Pointer to a FILE_OBJECT describing the target file
281 * The data that's being written to the file
284 * The size of the data buffer being written, in bytes
287 * Offset, in bytes, from the beginning of the file. Indicates where to start
291 * TODO: flags are presently ignored in code.
293 * @param CaseSensitive
294 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
295 * if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag.
297 * @param LengthWritten
298 * Pointer to a ULONG. This ULONG will be set to the number of bytes successfully written.
301 * STATUS_SUCCESS if successful, STATUS_NOT_IMPLEMENTED if a required feature isn't implemented,
302 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_ACCESS_DENIED if the write itself fails,
303 * STATUS_PARTIAL_COPY or STATUS_UNSUCCESSFUL if ReadFileRecord() fails, or
304 * STATUS_OBJECT_NAME_NOT_FOUND if the file's data stream could not be found.
306 * @remarks Called by NtfsWrite(). It may perform a read-modify-write operation if the requested write is
307 * not sector-aligned. LengthWritten only refers to how much of the requested data has been written;
308 * extra data that needs to be written to make the write sector-aligned will not affect it.
311 NTSTATUS
NtfsWriteFile(PDEVICE_EXTENSION DeviceExt
,
312 PFILE_OBJECT FileObject
,
317 BOOLEAN CaseSensitive
,
318 PULONG LengthWritten
)
320 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
322 PFILE_RECORD_HEADER FileRecord
;
323 PNTFS_ATTR_CONTEXT DataContext
;
324 ULONG AttributeOffset
;
325 ULONGLONG StreamSize
;
327 DPRINT("NtfsWriteFile(%p, %p, %p, %lu, %lu, %x, %s, %p)\n",
334 (CaseSensitive
? "TRUE" : "FALSE"),
344 return STATUS_SUCCESS
;
346 return STATUS_INVALID_PARAMETER
;
349 // get the File control block
350 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
353 DPRINT("Fcb->PathName: %wS\n", Fcb
->PathName
);
354 DPRINT("Fcb->ObjectName: %wS\n", Fcb
->ObjectName
);
356 // we don't yet handle compression
357 if (NtfsFCBIsCompressed(Fcb
))
359 DPRINT("Compressed file!\n");
361 return STATUS_NOT_IMPLEMENTED
;
364 // allocate non-paged memory for the FILE_RECORD_HEADER
365 FileRecord
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
366 if (FileRecord
== NULL
)
368 DPRINT1("Not enough memory! Can't write %wS!\n", Fcb
->PathName
);
369 return STATUS_INSUFFICIENT_RESOURCES
;
372 // read the FILE_RECORD_HEADER from the drive (or cache)
373 DPRINT("Reading file record...\n");
374 Status
= ReadFileRecord(DeviceExt
, Fcb
->MFTIndex
, FileRecord
);
375 if (!NT_SUCCESS(Status
))
377 // We couldn't get the file's record. Free the memory and return the error
378 DPRINT1("Can't find record for %wS!\n", Fcb
->ObjectName
);
379 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
383 DPRINT("Found record for %wS\n", Fcb
->ObjectName
);
385 // Find the attribute with the data stream for our file
386 DPRINT("Finding Data Attribute...\n");
387 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Fcb
->Stream
, wcslen(Fcb
->Stream
), &DataContext
,
390 // Did we fail to find the attribute?
391 if (!NT_SUCCESS(Status
))
393 NTSTATUS BrowseStatus
;
394 FIND_ATTR_CONTXT Context
;
395 PNTFS_ATTR_RECORD Attribute
;
397 DPRINT1("No '%S' data stream associated with file!\n", Fcb
->Stream
);
399 // Couldn't find the requested data stream; print a list of streams available
400 BrowseStatus
= FindFirstAttribute(&Context
, DeviceExt
, FileRecord
, FALSE
, &Attribute
);
401 while (NT_SUCCESS(BrowseStatus
))
403 if (Attribute
->Type
== AttributeData
)
407 Name
.Length
= Attribute
->NameLength
* sizeof(WCHAR
);
408 Name
.MaximumLength
= Name
.Length
;
409 Name
.Buffer
= (PWCHAR
)((ULONG_PTR
)Attribute
+ Attribute
->NameOffset
);
410 DPRINT1("Data stream: '%wZ' available\n", &Name
);
413 BrowseStatus
= FindNextAttribute(&Context
, &Attribute
);
415 FindCloseAttribute(&Context
);
417 ReleaseAttributeContext(DataContext
);
418 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
422 // Get the size of the stream on disk
423 StreamSize
= AttributeDataLength(DataContext
->pRecord
);
425 DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset
, StreamSize
);
427 // Are we trying to write beyond the end of the stream?
428 if (WriteOffset
+ Length
> StreamSize
)
430 // is increasing the stream size allowed?
431 if (!(Fcb
->Flags
& FCB_IS_VOLUME
) &&
432 !(IrpFlags
& IRP_PAGING_IO
))
434 LARGE_INTEGER DataSize
;
435 ULONGLONG AllocationSize
;
436 PFILENAME_ATTRIBUTE fileNameAttribute
;
437 ULONGLONG ParentMFTId
;
438 UNICODE_STRING filename
;
440 DataSize
.QuadPart
= WriteOffset
+ Length
;
442 // set the attribute data length
443 Status
= SetAttributeDataLength(FileObject
, Fcb
, DataContext
, AttributeOffset
, FileRecord
, &DataSize
);
444 if (!NT_SUCCESS(Status
))
446 ReleaseAttributeContext(DataContext
);
447 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
452 AllocationSize
= AttributeAllocatedLength(DataContext
->pRecord
);
454 // now we need to update this file's size in every directory index entry that references it
455 // TODO: put this code in its own function and adapt it to work with every filename / hardlink
456 // stored in the file record.
457 fileNameAttribute
= GetBestFileNameFromRecord(Fcb
->Vcb
, FileRecord
);
458 ASSERT(fileNameAttribute
);
460 ParentMFTId
= fileNameAttribute
->DirectoryFileReferenceNumber
& NTFS_MFT_MASK
;
462 filename
.Buffer
= fileNameAttribute
->Name
;
463 filename
.Length
= fileNameAttribute
->NameLength
* sizeof(WCHAR
);
464 filename
.MaximumLength
= filename
.Length
;
466 Status
= UpdateFileNameRecord(Fcb
->Vcb
,
477 // TODO - just fail for now
478 ReleaseAttributeContext(DataContext
);
479 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
481 return STATUS_ACCESS_DENIED
;
485 DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length
, WriteOffset
, StreamSize
);
487 // Write the data to the attribute
488 Status
= WriteAttribute(DeviceExt
, DataContext
, WriteOffset
, Buffer
, Length
, LengthWritten
, FileRecord
);
490 // Did the write fail?
491 if (!NT_SUCCESS(Status
))
493 DPRINT1("Write failure!\n");
494 ReleaseAttributeContext(DataContext
);
495 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
500 // This should never happen:
501 if (*LengthWritten
!= Length
)
503 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
504 *LengthWritten
, Length
);
505 Status
= STATUS_UNEXPECTED_IO_ERROR
;
508 ReleaseAttributeContext(DataContext
);
509 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
518 * Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from
519 * VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code
520 * from VfatWrite integrated.
523 * Points to an NTFS_IRP_CONTEXT which describes the write
526 * STATUS_SUCCESS if successful,
527 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
528 * STATUS_INVALID_DEVICE_REQUEST if called on the main device object,
529 * STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented.
530 * STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
532 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented.
533 * Support for large files (>4gb) is not implemented. Cached writes, file locks, transactions, etc - not implemented.
537 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext
)
540 PERESOURCE Resource
= NULL
;
541 LARGE_INTEGER ByteOffset
;
543 NTSTATUS Status
= STATUS_SUCCESS
;
545 ULONG ReturnedWriteLength
= 0;
546 PDEVICE_OBJECT DeviceObject
= NULL
;
547 PDEVICE_EXTENSION DeviceExt
= NULL
;
548 PFILE_OBJECT FileObject
= NULL
;
550 ULONG BytesPerSector
;
552 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext
);
555 // get the I/O request packet
556 Irp
= IrpContext
->Irp
;
558 // This request is not allowed on the main device object
559 if (IrpContext
->DeviceObject
== NtfsGlobalData
->DeviceObject
)
561 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
563 Irp
->IoStatus
.Information
= 0;
564 return STATUS_INVALID_DEVICE_REQUEST
;
567 // get the File control block
568 Fcb
= (PNTFS_FCB
)IrpContext
->FileObject
->FsContext
;
571 DPRINT("About to write %wS\n", Fcb
->ObjectName
);
572 DPRINT("NTFS Version: %d.%d\n", Fcb
->Vcb
->NtfsInfo
.MajorVersion
, Fcb
->Vcb
->NtfsInfo
.MinorVersion
);
574 // setup some more locals
575 FileObject
= IrpContext
->FileObject
;
576 DeviceObject
= IrpContext
->DeviceObject
;
577 DeviceExt
= DeviceObject
->DeviceExtension
;
578 BytesPerSector
= DeviceExt
->StorageDevice
->SectorSize
;
579 Length
= IrpContext
->Stack
->Parameters
.Write
.Length
;
581 // get the file offset we'll be writing to
582 ByteOffset
= IrpContext
->Stack
->Parameters
.Write
.ByteOffset
;
583 if (ByteOffset
.u
.LowPart
== FILE_WRITE_TO_END_OF_FILE
&&
584 ByteOffset
.u
.HighPart
== -1)
586 ByteOffset
.QuadPart
= Fcb
->RFCB
.FileSize
.QuadPart
;
589 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset
.QuadPart
,
590 Length
, BytesPerSector
);
592 if (ByteOffset
.u
.HighPart
&& !(Fcb
->Flags
& FCB_IS_VOLUME
))
594 // TODO: Support large files
595 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
596 return STATUS_INVALID_PARAMETER
;
599 // Is this a non-cached write? A non-buffered write?
600 if (IrpContext
->Irp
->Flags
& (IRP_PAGING_IO
| IRP_NOCACHE
) || (Fcb
->Flags
& FCB_IS_VOLUME
) ||
601 IrpContext
->FileObject
->Flags
& FILE_NO_INTERMEDIATE_BUFFERING
)
603 // non-cached and non-buffered writes must be sector aligned
604 if (ByteOffset
.u
.LowPart
% BytesPerSector
!= 0 || Length
% BytesPerSector
!= 0)
606 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
607 return STATUS_INVALID_PARAMETER
;
613 DPRINT1("Null write!\n");
615 IrpContext
->Irp
->IoStatus
.Information
= 0;
617 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
618 if (Irp
->UserBuffer
== NULL
&& Irp
->MdlAddress
== NULL
)
620 // FIXME: Update last write time
621 return STATUS_SUCCESS
;
624 return STATUS_INVALID_PARAMETER
;
628 if (Fcb
->Flags
& FCB_IS_VOLUME
)
630 Resource
= &DeviceExt
->DirResource
;
632 else if (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
)
634 Resource
= &Fcb
->PagingIoResource
;
638 Resource
= &Fcb
->MainResource
;
641 // acquire exclusive access to the Resource
642 if (!ExAcquireResourceExclusiveLite(Resource
, BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
644 return STATUS_CANT_WAIT
;
647 /* From VfatWrite(). Todo: Handle file locks
648 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
649 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
651 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
653 Status = STATUS_FILE_LOCK_CONFLICT;
658 // Is this an async request to a file?
659 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) && !(Fcb
->Flags
& FCB_IS_VOLUME
))
661 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
663 ExReleaseResourceLite(Resource
);
664 return STATUS_NOT_IMPLEMENTED
;
667 // get the buffer of data the user is trying to write
668 Buffer
= NtfsGetUserBuffer(Irp
, BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
));
672 Status
= NtfsLockUserBuffer(Irp
, Length
, IoReadAccess
);
674 // were we unable to lock the buffer?
675 if (!NT_SUCCESS(Status
))
677 DPRINT1("Unable to lock user buffer!\n");
679 ExReleaseResourceLite(Resource
);
683 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb
->RFCB
.FileSize
.QuadPart
);
684 DPRINT("About to write the data. Length: %lu\n", Length
);
686 // TODO: handle HighPart of ByteOffset (large files)
689 Status
= NtfsWriteFile(DeviceExt
,
695 BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_CASE_SENSITIVE
),
696 &ReturnedWriteLength
);
698 IrpContext
->Irp
->IoStatus
.Status
= Status
;
700 // was the write successful?
701 if (NT_SUCCESS(Status
))
703 // TODO: Update timestamps
705 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
707 // advance the file pointer
708 FileObject
->CurrentByteOffset
.QuadPart
= ByteOffset
.QuadPart
+ ReturnedWriteLength
;
711 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
715 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength
);
718 Irp
->IoStatus
.Information
= ReturnedWriteLength
;
720 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
722 ExReleaseResourceLite(Resource
);