ReactOS 0.4.17-dev-1190-g4c812f4
rw.c File Reference
#include <ntddk.h>
#include "ntfs.h"
#include <debug.h>
Include dependency graph for rw.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define NTFS_GROW_AHEAD_MIN   (64 * 1024)
 
#define NTFS_GROW_AHEAD_MAX   (4 * 1024 * 1024)
 

Functions

NtfsReadWriteVolume

@implemented

Serves a read or write made through a handle on the volume itself.

Parameters
DeviceExtPoints to the target disk's DEVICE_EXTENSION
MajorFunctionIRP_MJ_READ or IRP_MJ_WRITE
BufferSystem-space buffer to transfer to or from
LengthHow much to transfer, in bytes
OffsetByte offset from the start of the volume
IrpThe request being served, so that its buffer can be used directly
LengthTransferredReceives how much was transferred
Returns
STATUS_SUCCESS on success, otherwise the status of the transfer.
Remarks
A volume handle is raw access to the partition: it has no file record and no attributes. Running it through the attribute code would resolve the volume FCB's MFT index of zero and redirect the transfer into $MFT's own $DATA attribute.
static NTSTATUS NtfsReadWriteVolume (PDEVICE_EXTENSION DeviceExt, UCHAR MajorFunction, PUCHAR Buffer, ULONG Length, LONGLONG Offset, PIRP Irp, PULONG LengthTransferred)
 
static NTSTATUS NtfsReadFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PUCHAR Buffer, ULONG Length, ULONGLONG ReadOffset, ULONG IrpFlags, PIRP Irp, PULONG LengthRead)
 
static VOID NTAPI NtfsEnsureCacheMap (_In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb)
 
static NTSTATUS NTAPI NtfsCachedRead (_In_ PNTFS_IRP_CONTEXT IrpContext, _In_ PNTFS_FCB Fcb, _Out_writes_bytes_(Length) PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ReadOffset, _Out_ PULONG LengthRead)
 
NTSTATUS NtfsRead (PNTFS_IRP_CONTEXT IrpContext)
 
static NTSTATUS NTAPI NtfsGrowStream (_In_ PDEVICE_EXTENSION DeviceExt, _In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb, _In_ PNTFS_ATTR_CONTEXT DataContext, _In_ ULONG AttributeOffset, _Inout_ PFILE_RECORD_HEADER FileRecord, _In_ ULONGLONG NewEnd, _In_ BOOLEAN CaseSensitive)
 
NtfsWriteFile

@implemented

Writes a file to the disk. It presently borrows a lot of code from NtfsReadFile() and VFatWriteFileData(). It needs some more work before it will be complete; it won't handle page files, asnyc io, cached writes, etc.

Parameters
DeviceExtPoints to the target disk's DEVICE_EXTENSION
FileObjectPointer to a FILE_OBJECT describing the target file
BufferThe data that's being written to the file

@Param Length The size of the data buffer being written, in bytes

Parameters
WriteOffsetOffset, in bytes, from the beginning of the file. Indicates where to start writing data.
IrpFlagsTODO: flags are presently ignored in code.
CaseSensitiveBoolean indicating if the function should operate in case-sensitive mode. This will be TRUE if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag.
LengthWrittenPointer to a ULONG. This ULONG will be set to the number of bytes successfully written.
Returns
STATUS_SUCCESS if successful, STATUS_NOT_IMPLEMENTED if a required feature isn't implemented, STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_ACCESS_DENIED if the write itself fails, STATUS_PARTIAL_COPY or STATUS_UNSUCCESSFUL if ReadFileRecord() fails, or STATUS_OBJECT_NAME_NOT_FOUND if the file's data stream could not be found.
Remarks
Called by NtfsWrite(). It may perform a read-modify-write operation if the requested write is not sector-aligned. LengthWritten only refers to how much of the requested data has been written; extra data that needs to be written to make the write sector-aligned will not affect it.
NTSTATUS NtfsWriteFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, const PUCHAR Buffer, ULONG Length, ULONGLONG WriteOffset, ULONG IrpFlags, BOOLEAN CaseSensitive, PIRP Irp, PULONG LengthWritten)
 
static NTSTATUS NTAPI NtfsGrowFileForWrite (_In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb, _In_ ULONGLONG NewEnd, _In_ BOOLEAN CaseSensitive)
 
static NTSTATUS NTAPI NtfsCachedWrite (_In_ PNTFS_IRP_CONTEXT IrpContext, _In_ PNTFS_FCB Fcb, _In_reads_bytes_(Length) PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER WriteOffset, _In_ BOOLEAN CaseSensitive, _Out_ PULONG LengthWritten)
 
NtfsWrite

@implemented

Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code from VfatWrite integrated.

Parameters
IrpContextPoints to an NTFS_IRP_CONTEXT which describes the write
Returns
STATUS_SUCCESS if successful, STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_INVALID_DEVICE_REQUEST if called on the main device object, STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented. STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
Remarks
Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented. File locks, transactions, etc - not implemented.
NTSTATUS NtfsWrite (PNTFS_IRP_CONTEXT IrpContext)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 33 of file rw.c.

◆ NTFS_GROW_AHEAD_MAX

#define NTFS_GROW_AHEAD_MAX   (4 * 1024 * 1024)

Definition at line 38 of file rw.c.

◆ NTFS_GROW_AHEAD_MIN

#define NTFS_GROW_AHEAD_MIN   (64 * 1024)

Definition at line 37 of file rw.c.

Function Documentation

◆ NtfsCachedRead()

static NTSTATUS NTAPI NtfsCachedRead ( _In_ PNTFS_IRP_CONTEXT  IrpContext,
_In_ PNTFS_FCB  Fcb,
_Out_writes_bytes_(Length) PVOID  Buffer,
_In_ ULONG  Length,
_In_ PLARGE_INTEGER  ReadOffset,
_Out_ PULONG  LengthRead 
)
static

Definition at line 327 of file rw.c.

334{
335 PFILE_OBJECT FileObject = IrpContext->FileObject;
336 BOOLEAN CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
339 BOOLEAN Done = FALSE;
340
341 *LengthRead = 0;
342
344 {
347 }
348
350 goto Post;
351
352 if (ReadOffset->QuadPart >= Fcb->RFCB.FileSize.QuadPart)
353 {
355 return STATUS_END_OF_FILE;
356 }
357
358 if (Length > Fcb->RFCB.FileSize.QuadPart - ReadOffset->QuadPart)
359 Length = (ULONG)(Fcb->RFCB.FileSize.QuadPart - ReadOffset->QuadPart);
360
362 {
364
366 Status = Done ? IoStatus.Status : STATUS_PENDING;
367 }
369 {
370 Done = TRUE;
372 }
373 _SEH2_END;
374
376
377 if (Done)
378 {
379 if (NT_SUCCESS(Status))
380 *LengthRead = (ULONG)IoStatus.Information;
381
382 return Status;
383 }
384
385Post:
386 /* The data isn't in yet, read it from a worker that can wait */
387 Status = NtfsLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
388 if (!NT_SUCCESS(Status))
389 return Status;
390
391 return NtfsMarkIrpContextForQueue(IrpContext);
392}
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
_In_ PFCB Fcb
Definition: cdprocs.h:159
Definition: bufpool.h:45
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
NTSTATUS NtfsLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
Definition: misc.c:158
FORCEINLINE NTSTATUS NtfsMarkIrpContextForQueue(PNTFS_IRP_CONTEXT IrpContext)
Definition: ntfs.h:652
#define IRPCONTEXT_CANWAIT
Definition: ntfs.h:505
static VOID NTAPI NtfsEnsureCacheMap(_In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb)
Definition: rw.c:310
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
Status
Definition: gdiplustypes.h:24
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
BOOLEAN NtfsFCBIsEncrypted(PNTFS_FCB Fcb)
Definition: fcb.c:179
BOOLEAN NtfsFCBIsCompressed(PNTFS_FCB Fcb)
Definition: fcb.c:173
BOOLEAN NTAPI CcCopyRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus)
Definition: copysup.c:43
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define STATUS_END_OF_FILE
Definition: shellext.h:67
FSRTL_COMMON_FCB_HEADER RFCB
Definition: ntfs.h:593
ERESOURCE MainResource
Definition: ntfs.h:607
#define STATUS_PENDING
Definition: telnetd.h:14
uint32_t ULONG
Definition: typedefs.h:59
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET ReadOffset
Definition: wdfusb.h:2003
* PFILE_OBJECT
Definition: iotypes.h:1998
@ IoWriteAccess
Definition: ketypes.h:932

Referenced by NtfsRead().

◆ NtfsCachedWrite()

static NTSTATUS NTAPI NtfsCachedWrite ( _In_ PNTFS_IRP_CONTEXT  IrpContext,
_In_ PNTFS_FCB  Fcb,
_In_reads_bytes_(Length) PVOID  Buffer,
_In_ ULONG  Length,
_In_ PLARGE_INTEGER  WriteOffset,
_In_ BOOLEAN  CaseSensitive,
_Out_ PULONG  LengthWritten 
)
static

Definition at line 862 of file rw.c.

870{
871 PFILE_OBJECT FileObject = IrpContext->FileObject;
872 LONGLONG WriteEnd = WriteOffset->QuadPart + Length;
873 LARGE_INTEGER OldValidData;
874 BOOLEAN HideNewData = FALSE;
876
877 *LengthWritten = 0;
878
880 {
883 }
884
885 /* Let Cc throttle us before we hold anything */
887
889
891 {
893
894 OldValidData = Fcb->RFCB.ValidDataLength;
895
896 if (WriteEnd > Fcb->RFCB.FileSize.QuadPart)
897 {
898 Status = NtfsGrowFileForWrite(FileObject, Fcb, WriteEnd, CaseSensitive);
899 if (!NT_SUCCESS(Status))
901 }
902
903 /* Don't let Cc read from disk what we are about to overwrite, and
904 * make whatever lies before the write read as zeroes */
905 if (WriteEnd > OldValidData.QuadPart)
906 {
907 CC_FILE_SIZES Sizes;
908
910 Sizes.FileSize = Fcb->RFCB.FileSize;
911 Sizes.ValidDataLength = OldValidData;
912 CcSetFileSizes(FileObject, &Sizes);
913 HideNewData = TRUE;
914
915 if (WriteOffset->QuadPart > OldValidData.QuadPart)
916 CcZeroData(FileObject, &OldValidData, WriteOffset, TRUE);
917 }
918
920 {
923 }
924
925 *LengthWritten = Length;
926 }
928 {
930 }
931 _SEH2_END;
932
933 /* Back to the real valid data length, or a page Mm drops would read back as zeroes */
934 if (HideNewData)
936
938
939 return Status;
940}
static NTSTATUS NTAPI NtfsGrowFileForWrite(_In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb, _In_ ULONGLONG NewEnd, _In_ BOOLEAN CaseSensitive)
Definition: rw.c:827
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
BOOLEAN NTAPI CcZeroData(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER StartOffset, IN PLARGE_INTEGER EndOffset, IN BOOLEAN Wait)
Definition: fssup.c:414
BOOLEAN NTAPI CcCopyWrite(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN PVOID Buffer)
Definition: copysup.c:129
BOOLEAN NTAPI CcCanIWrite(IN PFILE_OBJECT FileObject, IN ULONG BytesToWrite, IN BOOLEAN Wait, IN UCHAR Retrying)
Definition: copysup.c:214
#define _SEH2_LEAVE
Definition: pseh2_64.h:206
#define STATUS_SUCCESS
Definition: shellext.h:65
LARGE_INTEGER FileSize
Definition: cctypes.h:16
LARGE_INTEGER ValidDataLength
Definition: cctypes.h:17
LARGE_INTEGER AllocationSize
Definition: cctypes.h:15
LARGE_INTEGER AllocationSize
Definition: env_spec_w32.h:755
LARGE_INTEGER ValidDataLength
Definition: env_spec_w32.h:757
int64_t LONGLONG
Definition: typedefs.h:68
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET WriteOffset
Definition: wdfusb.h:1921

Referenced by NtfsWrite().

◆ NtfsEnsureCacheMap()

static VOID NTAPI NtfsEnsureCacheMap ( _In_ PFILE_OBJECT  FileObject,
_In_ PNTFS_FCB  Fcb 
)
static

Definition at line 310 of file rw.c.

313{
314 if (FileObject->PrivateCacheMap == NULL)
315 {
318 FALSE,
320 Fcb);
321 }
322}
#define NULL
Definition: types.h:112
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:36
VOID NTAPI CcInitializeCacheMap(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes, IN BOOLEAN PinAccess, IN PCACHE_MANAGER_CALLBACKS Callbacks, IN PVOID LazyWriteContext)
Definition: fssup.c:195
CACHE_MANAGER_CALLBACKS CacheMgrCallbacks
Definition: ntfs.h:176

Referenced by NtfsCachedRead(), and NtfsCachedWrite().

◆ NtfsGrowFileForWrite()

static NTSTATUS NTAPI NtfsGrowFileForWrite ( _In_ PFILE_OBJECT  FileObject,
_In_ PNTFS_FCB  Fcb,
_In_ ULONGLONG  NewEnd,
_In_ BOOLEAN  CaseSensitive 
)
static

Definition at line 827 of file rw.c.

832{
833 PDEVICE_EXTENSION DeviceExt = Fcb->Vcb;
834 PFILE_RECORD_HEADER FileRecord;
835 PNTFS_ATTR_CONTEXT DataContext;
836 ULONG AttributeOffset;
838
839 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
840 if (FileRecord == NULL)
842
843 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
844 if (NT_SUCCESS(Status))
845 {
846 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext, &AttributeOffset);
847 if (NT_SUCCESS(Status))
848 {
849 Status = NtfsGrowStream(DeviceExt, FileObject, Fcb, DataContext, AttributeOffset, FileRecord, NewEnd, CaseSensitive);
850 ReleaseAttributeContext(DataContext);
851 }
852 }
853
854 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
855
856 return Status;
857}
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2988
@ AttributeData
Definition: ntfs.h:195
static NTSTATUS NTAPI NtfsGrowStream(_In_ PDEVICE_EXTENSION DeviceExt, _In_ PFILE_OBJECT FileObject, _In_ PNTFS_FCB Fcb, _In_ PNTFS_ATTR_CONTEXT DataContext, _In_ ULONG AttributeOffset, _Inout_ PFILE_RECORD_HEADER FileRecord, _In_ ULONGLONG NewEnd, _In_ BOOLEAN CaseSensitive)
Definition: rw.c:508
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1936
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
NTSTATUS FindAttribute(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, ULONG Type, PCWSTR Name, ULONG NameLength, PNTFS_ATTR_CONTEXT *AttrCtx, PULONG Offset)
Definition: mft.c:131
PVCB Vcb
Definition: cdstruc.h:933
ULONGLONG MFTIndex
Definition: ntfs.h:622
WCHAR Stream[MAX_PATH]
Definition: ntfs.h:602
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by NtfsCachedWrite().

◆ NtfsGrowStream()

static NTSTATUS NTAPI NtfsGrowStream ( _In_ PDEVICE_EXTENSION  DeviceExt,
_In_ PFILE_OBJECT  FileObject,
_In_ PNTFS_FCB  Fcb,
_In_ PNTFS_ATTR_CONTEXT  DataContext,
_In_ ULONG  AttributeOffset,
_Inout_ PFILE_RECORD_HEADER  FileRecord,
_In_ ULONGLONG  NewEnd,
_In_ BOOLEAN  CaseSensitive 
)
static

Definition at line 508 of file rw.c.

517{
520
521 DataSize.QuadPart = NewEnd;
522
523 /* Paging writes look the runs up again, keep them out while those change */
525
526 /* Reserve room past the new end, so the appends that follow fit
527 * without touching the bitmap or the run list. Cleanup gives back
528 * what's left over. */
529 if (DataContext->pRecord->IsNonResident &&
530 (ULONGLONG)DataSize.QuadPart > DataContext->pRecord->NonResident.AllocatedSize)
531 {
532 ULONGLONG Ahead;
533
534 Ahead = min(max(DataSize.QuadPart / 4, NTFS_GROW_AHEAD_MIN), NTFS_GROW_AHEAD_MAX);
535 Status = NtfsExtendAllocation(DeviceExt,
536 DataContext,
537 AttributeOffset,
538 FileRecord,
539 ROUND_UP(DataSize.QuadPart + Ahead, DeviceExt->NtfsInfo.BytesPerCluster));
540 if (!NT_SUCCESS(Status))
541 {
542 /* Not fatal; SetAttributeDataLength() still allocates what's needed */
543 DPRINT("Couldn't reserve ahead of %wS (Status %lx)\n", Fcb->ObjectName, Status);
544 }
545 }
546
547 // set the attribute data length
548 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, &DataSize);
549
551
552 if (!NT_SUCCESS(Status))
553 return Status;
554
555 // The file grew, so every copy of its size has to follow.
556 // TODO: adapt this to every filename / hardlink in the record.
558 FileRecord,
559 Fcb->MFTIndex,
561 CaseSensitive);
562
563 return STATUS_SUCCESS;
564}
#define NTFS_FILENAME_UPDATE_SIZES
Definition: ntfs.h:1332
#define NTFS_GROW_AHEAD_MIN
Definition: rw.c:37
#define NTFS_GROW_AHEAD_MAX
Definition: rw.c:38
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
NTSTATUS NtfsUpdateDuplicatedInformation(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, ULONGLONG MFTIndex, ULONG Flags, BOOLEAN CaseSensitive)
Definition: mft.c:1995
NTSTATUS NtfsExtendAllocation(_In_ PDEVICE_EXTENSION Vcb, _In_ PNTFS_ATTR_CONTEXT AttrContext, _In_ ULONG AttrOffset, _In_ PFILE_RECORD_HEADER FileRecord, _In_ ULONGLONG AllocationSize)
Definition: mft.c:753
NTSTATUS SetAttributeDataLength(PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:615
#define min(a, b)
Definition: monoChain.cc:55
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
#define DPRINT
Definition: sndvol32.h:73
ERESOURCE PagingIoResource
Definition: ntfs.h:606
WCHAR * ObjectName
Definition: ntfs.h:603
#define max(a, b)
Definition: svc.c:63
uint64_t ULONGLONG
Definition: typedefs.h:67

Referenced by NtfsGrowFileForWrite(), and NtfsWriteFile().

◆ NtfsRead()

NTSTATUS NtfsRead ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 396 of file rw.c.

397{
398 PDEVICE_EXTENSION DeviceExt;
404 ULONG ReturnedReadLength = 0;
406 PIRP Irp;
408
409 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
410
411 DeviceObject = IrpContext->DeviceObject;
412 Irp = IrpContext->Irp;
413 Stack = IrpContext->Stack;
414 FileObject = IrpContext->FileObject;
415
416 DeviceExt = DeviceObject->DeviceExtension;
417 ReadLength = Stack->Parameters.Read.Length;
418 ReadOffset = Stack->Parameters.Read.ByteOffset;
420
421 /* Once dismounted the metadata can't be trusted; only raw volume access
422 * is still served */
423 if ((DeviceExt->Flags & VCB_VOLUME_DISMOUNTED) &&
424 !(((PNTFS_FCB)FileObject->FsContext)->Flags & FCB_IS_VOLUME))
425 {
426 Irp->IoStatus.Information = 0;
428 }
429
430 /* A handle on the volume itself is raw access to the partition. */
431 if (((PNTFS_FCB)FileObject->FsContext)->Flags & FCB_IS_VOLUME)
432 {
433 Status = NtfsReadWriteVolume(DeviceExt,
435 Buffer,
437 ReadOffset.QuadPart,
438 Irp,
439 &ReturnedReadLength);
440 }
441 else if (NtfsFCBIsDirectory((PNTFS_FCB)FileObject->FsContext))
442 {
443 /* A directory has no data stream to read */
444 Irp->IoStatus.Information = 0;
446 }
447 else if (!(Irp->Flags & IRP_PAGING_IO) && NtfsIsRegularFileObject(FileObject) &&
448 !FsRtlCheckLockForReadAccess(&((PNTFS_FCB)FileObject->FsContext)->FileLock, Irp))
449 {
450 Irp->IoStatus.Information = 0;
452 }
454 {
455 Status = NtfsCachedRead(IrpContext,
456 (PNTFS_FCB)FileObject->FsContext,
457 Buffer,
459 &ReadOffset,
460 &ReturnedReadLength);
461 if (Status == STATUS_PENDING)
462 return Status;
463 }
464 else
465 {
466 PNTFS_FCB Fcb = (PNTFS_FCB)FileObject->FsContext;
467
468 /* A non cached read must not miss what is still dirty in the cache */
471 {
473
475 }
476
477 Status = NtfsReadFile(DeviceExt,
479 Buffer,
481 ReadOffset.QuadPart,
482 Irp->Flags,
483 Irp,
484 &ReturnedReadLength);
485 }
486 if (NT_SUCCESS(Status))
487 {
488 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
489 {
490 FileObject->CurrentByteOffset.QuadPart =
491 ReadOffset.QuadPart + ReturnedReadLength;
492 }
493
494 Irp->IoStatus.Information = ReturnedReadLength;
495 }
496 else
497 {
498 Irp->IoStatus.Information = 0;
499 }
500
501 return Status;
502}
ULONG ReadLength
VOID NTAPI CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:222
PVOID NtfsGetUserBuffer(PIRP Irp, BOOLEAN Paging)
Definition: misc.c:120
#define VCB_VOLUME_DISMOUNTED
Definition: ntfs.h:148
struct _FCB * PNTFS_FCB
#define FCB_IS_VOLUME
Definition: ntfs.h:585
static NTSTATUS NtfsReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PUCHAR Buffer, ULONG Length, ULONGLONG ReadOffset, ULONG IrpFlags, PIRP Irp, PULONG LengthRead)
Definition: rw.c:124
static NTSTATUS NtfsReadWriteVolume(PDEVICE_EXTENSION DeviceExt, UCHAR MajorFunction, PUCHAR Buffer, ULONG Length, LONGLONG Offset, PIRP Irp, PULONG LengthTransferred)
Definition: rw.c:80
static NTSTATUS NTAPI NtfsCachedRead(_In_ PNTFS_IRP_CONTEXT IrpContext, _In_ PNTFS_FCB Fcb, _Out_writes_bytes_(Length) PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER ReadOffset, _Out_ PULONG LengthRead)
Definition: rw.c:327
BOOLEAN NTAPI FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock, IN PIRP Irp)
Definition: filelock.c:672
_In_ PIRP Irp
Definition: kse.h:79
if(dx< 0)
Definition: linetemp.h:194
BOOLEAN NtfsFCBIsDirectory(PNTFS_FCB Fcb)
Definition: fcb.c:144
BOOLEAN NTAPI NtfsIsRegularFileObject(_In_ PFILE_OBJECT FileObject)
Definition: fcb.c:153
#define STATUS_FILE_LOCK_CONFLICT
Definition: ntstatus.h:414
#define STATUS_VOLUME_DISMOUNTED
Definition: ntstatus.h:869
#define IRP_MJ_READ
Definition: rdpdr.c:46
PFILE_OBJECT FileObject
Definition: ntfs.h:564
PIO_STACK_LOCATION Stack
Definition: ntfs.h:557
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:563
Definition: cdstruc.h:902
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: ntfs.h:597
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
#define IRP_PAGING_IO
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1776
#define IRP_NOCACHE

◆ NtfsReadFile()

static NTSTATUS NtfsReadFile ( PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject,
PUCHAR  Buffer,
ULONG  Length,
ULONGLONG  ReadOffset,
ULONG  IrpFlags,
PIRP  Irp,
PULONG  LengthRead 
)
static

Definition at line 124 of file rw.c.

132{
135 PFILE_RECORD_HEADER FileRecord;
136 PNTFS_ATTR_CONTEXT DataContext = NULL;
137 ULONG RealLength;
138 ULONGLONG RealReadOffset;
139 ULONG RealLengthRead;
140 ULONG ToRead;
141 BOOLEAN AllocatedBuffer = FALSE;
143 ULONGLONG StreamSize;
144
145 DPRINT("NtfsReadFile(%p, %p, %p, %lu, %I64u, %lx, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
146
147 *LengthRead = 0;
148
149 if (Length == 0)
150 {
151 DPRINT1("Null read!\n");
152 return STATUS_SUCCESS;
153 }
154
155 Fcb = (PNTFS_FCB)FileObject->FsContext;
156
158 {
159 DPRINT1("Compressed file!\n");
162 }
163
165 {
166 DPRINT1("Encrypted file!\n");
169 }
170
171 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
172 if (FileRecord == NULL)
173 {
174 DPRINT1("Not enough memory!\n");
176 }
177
178 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
179 if (!NT_SUCCESS(Status))
180 {
181 DPRINT1("Can't find record!\n");
182 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
183 return Status;
184 }
185
186
187 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext, NULL);
188 if (!NT_SUCCESS(Status))
189 {
190 NTSTATUS BrowseStatus;
192 PNTFS_ATTR_RECORD Attribute;
193
194 DPRINT1("No '%S' data stream associated with file '%wS' (MFT record %I64u, record flags 0x%x)!\n",
195 Fcb->Stream, Fcb->ObjectName, Fcb->MFTIndex, FileRecord->Flags);
196
197 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
198 while (NT_SUCCESS(BrowseStatus))
199 {
200 if (Attribute->Type == AttributeData)
201 {
203
204 Name.Length = Attribute->NameLength * sizeof(WCHAR);
205 Name.MaximumLength = Name.Length;
206 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
207 DPRINT1("Data stream: '%wZ' available\n", &Name);
208 }
209
210 BrowseStatus = FindNextAttribute(&Context, &Attribute);
211 }
213
214 /* FindAttribute() failed, so DataContext was never set; there is
215 * nothing to release here. */
216 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
217 return Status;
218 }
219
220 StreamSize = AttributeDataLength(DataContext->pRecord);
221 if (ReadOffset >= StreamSize)
222 {
223 DPRINT("Reading beyond stream end!\n");
224 ReleaseAttributeContext(DataContext);
225 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
226 return STATUS_END_OF_FILE;
227 }
228
229 ToRead = Length;
230 if (ReadOffset + Length > StreamSize)
231 ToRead = (ULONG)(StreamSize - ReadOffset);
232
233 RealReadOffset = ReadOffset;
234 RealLength = ToRead;
235
236 if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
237 {
238 RealReadOffset = ROUND_DOWN(ReadOffset, DeviceExt->NtfsInfo.BytesPerSector);
239 RealLength = ROUND_UP(ToRead, DeviceExt->NtfsInfo.BytesPerSector);
240 /* do we need to extend RealLength by one sector? */
241 if (RealLength + RealReadOffset < ReadOffset + Length)
242 {
243 if (RealReadOffset + RealLength + DeviceExt->NtfsInfo.BytesPerSector <= AttributeAllocatedLength(DataContext->pRecord))
244 RealLength += DeviceExt->NtfsInfo.BytesPerSector;
245 }
246
247
249 if (ReadBuffer == NULL)
250 {
251 DPRINT1("Not enough memory!\n");
252 ReleaseAttributeContext(DataContext);
253 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
255 }
256 AllocatedBuffer = TRUE;
257 }
258
259 DPRINT("Effective read: %lu at %I64u for stream '%S'\n", RealLength, RealReadOffset, Fcb->Stream);
260 /* Only hand the IRP down when reading straight into its buffer: a
261 * forwarded transfer lands at the start of the IRP's MDL, so a bounced
262 * read would end up in the wrong place */
263 RealLengthRead = ReadAttributeToIrp(DeviceExt,
264 DataContext,
265 RealReadOffset,
267 RealLength,
268 AllocatedBuffer ? NULL : Irp);
269 if (RealLengthRead == 0)
270 {
271 DPRINT1("Read failure!\n");
272 ReleaseAttributeContext(DataContext);
273 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
274 if (AllocatedBuffer)
275 {
277 }
278 return Status;
279 }
280
281 ReleaseAttributeContext(DataContext);
282 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
283
284 *LengthRead = ToRead;
285
286 DPRINT("%lu got read\n", *LengthRead);
287
288 if (AllocatedBuffer)
289 {
290 RtlCopyMemory(Buffer, ReadBuffer + (ULONG)(ReadOffset - RealReadOffset), ToRead);
291 }
292
293 if (ToRead != Length)
294 {
295 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
296 }
297
298 if (AllocatedBuffer)
299 {
301 }
302
303 return STATUS_SUCCESS;
304}
#define ReadBuffer(BaseIoAddress, Buffer, Count)
Definition: atapi.h:339
#define DPRINT1
Definition: precomp.h:8
LPWSTR Name
Definition: desk.c:124
NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1413
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1495
NTSTATUS FindNextAttribute(PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1461
#define TAG_NTFS
Definition: ntfs.h:12
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
ULONGLONG AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:249
ULONG ReadAttributeToIrp(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length, PIRP Irp)
Definition: mft.c:1556
#define PCHAR
Definition: match.c:90
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
short WCHAR
Definition: pedump.c:58
USHORT NameOffset
Definition: ntfs.h:138
UCHAR NameLength
Definition: ntfs.h:137
ULONG Type
Definition: ntfs.h:134
USHORT Flags
Definition: ntfs.h:287
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint16_t * PWCHAR
Definition: typedefs.h:56
char * PCHAR
Definition: typedefs.h:51

Referenced by NtfsRead().

◆ NtfsReadWriteVolume()

static NTSTATUS NtfsReadWriteVolume ( PDEVICE_EXTENSION  DeviceExt,
UCHAR  MajorFunction,
PUCHAR  Buffer,
ULONG  Length,
LONGLONG  Offset,
PIRP  Irp,
PULONG  LengthTransferred 
)
static

Definition at line 80 of file rw.c.

87{
88 NTFS_IO_RUN_LIST RunList;
90
91 DPRINT("NtfsReadWriteVolume(%p, %u, %p, %lu, %I64u, %p, %p)\n",
92 DeviceExt, MajorFunction, Buffer, Length, Offset, Irp, LengthTransferred);
93
94 *LengthTransferred = 0;
95
96 if (Length == 0)
97 return STATUS_SUCCESS;
98
99 NtfsInitIoRunList(&RunList);
100
101 Status = NtfsAddIoRun(&RunList, Offset, Length);
102 if (NT_SUCCESS(Status))
103 {
104 Status = NtfsPerformIrpIoRuns(DeviceExt->StorageDevice,
106 DeviceExt->NtfsInfo.BytesPerSector,
107 Irp,
108 Buffer,
109 &RunList,
110 FALSE,
111 LengthTransferred);
112 }
113
114 NtfsFreeIoRunList(&RunList);
115
116 return Status;
117}
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
VOID NtfsFreeIoRunList(IN OUT PNTFS_IO_RUN_LIST RunList)
Definition: blockdev.c:140
NTSTATUS NtfsAddIoRun(IN OUT PNTFS_IO_RUN_LIST RunList, IN LONGLONG Lbo, IN ULONG ByteCount)
Definition: blockdev.c:74
VOID NtfsInitIoRunList(OUT PNTFS_IO_RUN_LIST RunList)
Definition: blockdev.c:40
NTSTATUS NtfsPerformIrpIoRuns(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MajorFunction, IN ULONG SectorSize, IN PIRP Irp, IN OUT PUCHAR Buffer, IN PNTFS_IO_RUN_LIST RunList, IN BOOLEAN Override, OUT PULONG BytesTransferred)
Definition: blockdev.c:743
_In_ UCHAR MajorFunction
Definition: wdfdevice.h:1703

Referenced by NtfsRead(), and NtfsWrite().

◆ NtfsWrite()

NTSTATUS NtfsWrite ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 965 of file rw.c.

966{
972 ULONG Length = 0;
973 ULONG ReturnedWriteLength = 0;
975 PDEVICE_EXTENSION DeviceExt = NULL;
977 PIRP Irp = NULL;
978 ULONG BytesPerSector;
979
980 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext);
981 ASSERT(IrpContext);
982
983 // get the I/O request packet
984 Irp = IrpContext->Irp;
985
986 // This request is not allowed on the main device object
987 if (IrpContext->DeviceObject == NtfsGlobalData->DeviceObject)
988 {
989 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
990
991 Irp->IoStatus.Information = 0;
993 }
994
995 // get the File control block
996 Fcb = (PNTFS_FCB)IrpContext->FileObject->FsContext;
997 ASSERT(Fcb);
998
999 DPRINT("About to write %wS\n", Fcb->ObjectName);
1000 DPRINT("NTFS Version: %d.%d\n", Fcb->Vcb->NtfsInfo.MajorVersion, Fcb->Vcb->NtfsInfo.MinorVersion);
1001
1002 // setup some more locals
1003 FileObject = IrpContext->FileObject;
1004 DeviceObject = IrpContext->DeviceObject;
1005 DeviceExt = DeviceObject->DeviceExtension;
1006 BytesPerSector = DeviceExt->StorageDevice->SectorSize;
1007 Length = IrpContext->Stack->Parameters.Write.Length;
1008
1009 // get the file offset we'll be writing to
1010 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
1011 if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
1012 ByteOffset.u.HighPart == -1)
1013 {
1014 ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
1015 }
1016
1017 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset.QuadPart,
1018 Length, BytesPerSector);
1019
1020 /* Offsets are 64 bits all the way down, only reject what can't be a file position */
1021 if (ByteOffset.QuadPart < 0 || ByteOffset.QuadPart + Length < ByteOffset.QuadPart)
1022 {
1023 DPRINT1("Invalid write offset %I64d, length %lu\n", ByteOffset.QuadPart, Length);
1025 }
1026
1027 // Is this a non-cached write? A non-buffered write?
1028 if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME) ||
1029 IrpContext->FileObject->Flags & FILE_NO_INTERMEDIATE_BUFFERING)
1030 {
1031 // non-cached and non-buffered writes must be sector aligned
1032 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
1033 {
1034 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
1036 }
1037 }
1038
1039 /* A zero length write is a valid no-op */
1040 if (Length == 0)
1041 {
1042 // FIXME: Update last write time
1043 IrpContext->Irp->IoStatus.Information = 0;
1044 return STATUS_SUCCESS;
1045 }
1046
1047 /* Is this an async request to a file? Serving a write means reading the
1048 * file record, walking its attributes and possibly growing the allocation,
1049 * all of it blocking metadata I/O, so post it to a worker thread which
1050 * runs the same path with IRPCONTEXT_CANWAIT set. Lock the user buffer
1051 * here, while we're still in the requesting thread's address space. */
1052 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
1053 {
1055 if (!NT_SUCCESS(Status))
1056 {
1057 DPRINT1("Unable to lock user buffer!\n");
1058 return Status;
1059 }
1060
1061 return NtfsMarkIrpContextForQueue(IrpContext);
1062 }
1063
1064 /* Byte range locks only stop other handles, never Mm or Cc */
1067 {
1068 Irp->IoStatus.Information = 0;
1070 }
1071
1072 /* Regular writes go through the cache, the lazy writer brings them to disk */
1073 if (!(Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE)) &&
1076 {
1077 if (DeviceExt->Flags & VCB_VOLUME_DISMOUNTED)
1078 {
1079 Irp->IoStatus.Information = 0;
1081 }
1082
1083 Status = NtfsCachedWrite(IrpContext,
1084 Fcb,
1086 Length,
1087 &ByteOffset,
1089 &ReturnedWriteLength);
1090 if (NT_SUCCESS(Status))
1091 {
1092 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1093 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + ReturnedWriteLength;
1094
1095 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
1096 }
1097
1098 Irp->IoStatus.Information = NT_SUCCESS(Status) ? ReturnedWriteLength : 0;
1099 return Status;
1100 }
1101
1102 // get the Resource
1103 if (Fcb->Flags & FCB_IS_VOLUME)
1104 {
1105 Resource = &DeviceExt->DirResource;
1106 }
1107 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
1108 {
1110 }
1111 else
1112 {
1114 }
1115
1116 /* Paging writes never change the sizes, and Cc or Mm may already hold the
1117 * paging resource shared for us. Size changes take it exclusive. */
1118 if (Resource == &Fcb->PagingIoResource)
1119 {
1121 return STATUS_CANT_WAIT;
1122 }
1124 {
1125 return STATUS_CANT_WAIT;
1126 }
1127
1128 // get the buffer of data the user is trying to write
1130 ASSERT(Buffer);
1131
1132 // lock the buffer
1134
1135 // were we unable to lock the buffer?
1136 if (!NT_SUCCESS(Status))
1137 {
1138 DPRINT1("Unable to lock user buffer!\n");
1139
1141 return Status;
1142 }
1143
1144 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb->RFCB.FileSize.QuadPart);
1145 DPRINT("About to write the data. Length: %lu\n", Length);
1146
1147
1148 /* See NtfsRead() */
1149 if ((DeviceExt->Flags & VCB_VOLUME_DISMOUNTED) &&
1150 !(Fcb->Flags & FCB_IS_VOLUME))
1151 {
1153 Irp->IoStatus.Information = 0;
1155 }
1156
1157 // write the file
1158 if (Fcb->Flags & FCB_IS_VOLUME)
1159 {
1160 /* Raw access to the partition, including after a dismount. */
1161 Status = NtfsReadWriteVolume(DeviceExt,
1163 Buffer,
1164 Length,
1165 ByteOffset.QuadPart,
1166 Irp,
1167 &ReturnedWriteLength);
1168 }
1169 else if (NtfsFCBIsDirectory(Fcb))
1170 {
1171 /* A directory has no data stream to write */
1173 Irp->IoStatus.Information = 0;
1175 }
1176 else
1177 {
1178 /* What goes straight to disk must not be overwritten by stale cached data later */
1181 {
1183
1186 }
1187
1188 Status = NtfsWriteFile(DeviceExt,
1189 FileObject,
1190 Buffer,
1191 Length,
1192 ByteOffset.QuadPart,
1193 Irp->Flags,
1195 Irp,
1196 &ReturnedWriteLength);
1197 }
1198
1199 IrpContext->Irp->IoStatus.Status = Status;
1200
1201 // was the write successful?
1202 if (NT_SUCCESS(Status))
1203 {
1204 // TODO: Update timestamps
1205
1206 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1207 {
1208 // advance the file pointer
1209 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + ReturnedWriteLength;
1210 }
1211
1212 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
1213 }
1214 else
1215 {
1216 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength);
1217 }
1218
1219 Irp->IoStatus.Information = ReturnedWriteLength;
1220
1221 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
1222
1224
1225 return Status;
1226}
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:843
NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, const PUCHAR Buffer, ULONG Length, ULONGLONG WriteOffset, ULONG IrpFlags, BOOLEAN CaseSensitive, PIRP Irp, PULONG LengthWritten)
Definition: rw.c:611
static NTSTATUS NTAPI NtfsCachedWrite(_In_ PNTFS_IRP_CONTEXT IrpContext, _In_ PNTFS_FCB Fcb, _In_reads_bytes_(Length) PVOID Buffer, _In_ ULONG Length, _In_ PLARGE_INTEGER WriteOffset, _In_ BOOLEAN CaseSensitive, _Out_ PULONG LengthWritten)
Definition: rw.c:862
ERESOURCE * PERESOURCE
Definition: env_spec_w32.h:595
#define FILE_WRITE_TO_END_OF_FILE
Definition: ext2fs.h:278
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:732
BOOLEAN NTAPI FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock, IN PIRP Irp)
Definition: filelock.c:712
#define FILE_NO_INTERMEDIATE_BUFFERING
Definition: from_kernel.h:28
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:386
#define ASSERT(a)
Definition: mode.c:44
#define STATUS_CANT_WAIT
Definition: ntstatus.h:546
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:175
ULONG Flags
Definition: ntfs.h:556
CCHAR PriorityBoost
Definition: ntfs.h:566
ULONG Flags
Definition: ntfs.h:618
FILE_LOCK FileLock
Definition: fatstruc.h:1071
struct _IO_STACK_LOCATION::@5020::@5025 Write
union _IO_STACK_LOCATION::@1814 Parameters
IO_STATUS_BLOCK IoStatus
unsigned char * PUCHAR
Definition: typedefs.h:53
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define FO_NO_INTERMEDIATE_BUFFERING
Definition: iotypes.h:1778
#define SL_CASE_SENSITIVE
Definition: iotypes.h:1820
@ IoReadAccess
Definition: ketypes.h:931

Referenced by NtfsDispatch().

◆ NtfsWriteFile()

NTSTATUS NtfsWriteFile ( PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject,
const PUCHAR  Buffer,
ULONG  Length,
ULONGLONG  WriteOffset,
ULONG  IrpFlags,
BOOLEAN  CaseSensitive,
PIRP  Irp,
PULONG  LengthWritten 
)

Definition at line 611 of file rw.c.

620{
623 PFILE_RECORD_HEADER FileRecord;
624 PNTFS_ATTR_CONTEXT DataContext = NULL;
625 ULONG AttributeOffset;
626 ULONGLONG StreamSize;
627 ULONG RequestedLength = 0;
628
629 DPRINT("NtfsWriteFile(%p, %p, %p, %lu, %I64u, %x, %s, %p)\n",
630 DeviceExt,
632 Buffer,
633 Length,
635 IrpFlags,
636 (CaseSensitive ? "TRUE" : "FALSE"),
637 LengthWritten);
638
639 *LengthWritten = 0;
640
641 ASSERT(DeviceExt);
642
643 if (Length == 0)
644 {
645 if (Buffer == NULL)
646 return STATUS_SUCCESS;
647 else
649 }
650
651 // get the File control block
652 Fcb = (PNTFS_FCB)FileObject->FsContext;
653 ASSERT(Fcb);
654
655 DPRINT("Fcb->PathName: %wS\n", Fcb->PathName);
656 DPRINT("Fcb->ObjectName: %wS\n", Fcb->ObjectName);
657
658 // we don't yet handle compression
660 {
661 DPRINT("Compressed file!\n");
664 }
665
666 // allocate non-paged memory for the FILE_RECORD_HEADER
667 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
668 if (FileRecord == NULL)
669 {
670 DPRINT1("Not enough memory! Can't write %wS!\n", Fcb->PathName);
672 }
673
674 // read the FILE_RECORD_HEADER from the drive (or cache)
675 DPRINT("Reading file record...\n");
676 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
677 if (!NT_SUCCESS(Status))
678 {
679 // We couldn't get the file's record. Free the memory and return the error
680 DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName);
681 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
682 return Status;
683 }
684
685 DPRINT("Found record for %wS\n", Fcb->ObjectName);
686
687 // Find the attribute with the data stream for our file
688 DPRINT("Finding Data Attribute...\n");
689 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext,
690 &AttributeOffset);
691
692 // Did we fail to find the attribute?
693 if (!NT_SUCCESS(Status))
694 {
695 NTSTATUS BrowseStatus;
697 PNTFS_ATTR_RECORD Attribute;
698
699 DPRINT1("No '%S' data stream associated with file '%wS' (MFT record %I64u, record flags 0x%x)!\n",
700 Fcb->Stream, Fcb->ObjectName, Fcb->MFTIndex, FileRecord->Flags);
701
702 // Couldn't find the requested data stream; print a list of streams available
703 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
704 while (NT_SUCCESS(BrowseStatus))
705 {
706 if (Attribute->Type == AttributeData)
707 {
709
710 Name.Length = Attribute->NameLength * sizeof(WCHAR);
711 Name.MaximumLength = Name.Length;
712 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
713 DPRINT1("Data stream: '%wZ' available\n", &Name);
714 }
715
716 BrowseStatus = FindNextAttribute(&Context, &Attribute);
717 }
719
720 /* FindAttribute() failed, so DataContext was never set; there is
721 * nothing to release here. */
722 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
723 return Status;
724 }
725
726 // Get the size of the stream on disk
727 StreamSize = AttributeDataLength(DataContext->pRecord);
728
729 DPRINT("WriteOffset: %I64u\tStreamSize: %I64u\n", WriteOffset, StreamSize);
730
731 // Are we trying to write beyond the end of the stream?
732 if (WriteOffset + Length > StreamSize)
733 {
734 // is increasing the stream size allowed?
735 if (!(Fcb->Flags & FCB_IS_VOLUME) &&
736 !(IrpFlags & IRP_PAGING_IO))
737 {
738 Status = NtfsGrowStream(DeviceExt,
740 Fcb,
741 DataContext,
742 AttributeOffset,
743 FileRecord,
745 CaseSensitive);
746 if (!NT_SUCCESS(Status))
747 {
748 ReleaseAttributeContext(DataContext);
749 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
750 *LengthWritten = 0;
751 return Status;
752 }
753 }
754 else if (IrpFlags & IRP_PAGING_IO)
755 {
756 /* Mm flushes whole pages, so a file's last page routinely reaches
757 * past its end. A paging write must not change the file size, so
758 * clamp instead of failing - refusing it would lose the valid
759 * bytes before the end too. */
760 if (WriteOffset >= StreamSize)
761 {
762 DPRINT("Paging write entirely past the end of the stream; nothing to do\n");
763
764 ReleaseAttributeContext(DataContext);
765 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
766 *LengthWritten = Length;
767 return STATUS_SUCCESS;
768 }
769
770 DPRINT("Clamping paging write of %lu bytes at %I64u to stream size %I64u\n",
771 Length, WriteOffset, StreamSize);
772
773 RequestedLength = Length;
774 Length = (ULONG)(StreamSize - WriteOffset);
775 }
776 else
777 {
778 /* The volume stream is the size of the volume and cannot grow */
779 ReleaseAttributeContext(DataContext);
780 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
781 *LengthWritten = 0;
783 }
784 }
785
786 DPRINT("Length: %lu\tWriteOffset: %I64u\tStreamSize: %I64u\n", Length, WriteOffset, StreamSize);
787
788 // Write the data to the attribute
789 /* Buffer is the system mapping of this IRP's MDL, so hand the IRP down too
790 * and let the run layer borrow it instead of locking these pages twice,
791 * which the paging path forbids */
792 Status = WriteAttributeFromIrp(DeviceExt, DataContext, WriteOffset, Buffer, Length, LengthWritten, FileRecord, Irp);
793
794 // Did the write fail?
795 if (!NT_SUCCESS(Status))
796 {
797 DPRINT1("Write failure!\n");
798 ReleaseAttributeContext(DataContext);
799 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
800
801 return Status;
802 }
803
804 // This should never happen:
805 if (*LengthWritten != Length)
806 {
807 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
808 *LengthWritten, Length);
810 }
811
812 // A clamped paging write stored all the stream had room for, so as far as
813 // Mm is concerned the whole page is done
814 if (RequestedLength != 0 && NT_SUCCESS(Status))
815 *LengthWritten = RequestedLength;
816
817 ReleaseAttributeContext(DataContext);
818 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
819
820 return Status;
821}
NTSTATUS WriteAttributeFromIrp(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG RealLengthWritten, PFILE_RECORD_HEADER FileRecord, PIRP Irp)
Definition: mft.c:1677
#define STATUS_UNEXPECTED_IO_ERROR
Definition: ntstatus.h:563
WCHAR PathName[MAX_PATH]
Definition: ntfs.h:604
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145

Referenced by NtfsWrite().