ReactOS 0.4.15-dev-7127-g2dd0c6c
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
 

Functions

static NTSTATUS NtfsReadFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PUCHAR Buffer, ULONG Length, ULONG ReadOffset, ULONG IrpFlags, PULONG LengthRead)
 
NTSTATUS NtfsRead (PNTFS_IRP_CONTEXT IrpContext)
 
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, ULONG WriteOffset, ULONG IrpFlags, BOOLEAN CaseSensitive, 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. Support for large files (>4gb) is not implemented. Cached writes, 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.

Function Documentation

◆ NtfsRead()

NTSTATUS NtfsRead ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 216 of file rw.c.

217{
218 PDEVICE_EXTENSION DeviceExt;
224 ULONG ReturnedReadLength = 0;
226 PIRP Irp;
228
229 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
230
231 DeviceObject = IrpContext->DeviceObject;
232 Irp = IrpContext->Irp;
233 Stack = IrpContext->Stack;
234 FileObject = IrpContext->FileObject;
235
236 DeviceExt = DeviceObject->DeviceExtension;
237 ReadLength = Stack->Parameters.Read.Length;
238 ReadOffset = Stack->Parameters.Read.ByteOffset;
240
241 Status = NtfsReadFile(DeviceExt,
243 Buffer,
245 ReadOffset.u.LowPart,
246 Irp->Flags,
247 &ReturnedReadLength);
248 if (NT_SUCCESS(Status))
249 {
250 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
251 {
252 FileObject->CurrentByteOffset.QuadPart =
253 ReadOffset.QuadPart + ReturnedReadLength;
254 }
255
256 Irp->IoStatus.Information = ReturnedReadLength;
257 }
258 else
259 {
260 Irp->IoStatus.Information = 0;
261 }
262
263 return Status;
264}
ULONG ReadLength
LONG NTSTATUS
Definition: precomp.h:26
Definition: bufpool.h:45
_In_ PIRP Irp
Definition: csq.h:116
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID NtfsGetUserBuffer(PIRP Irp, BOOLEAN Paging)
Definition: misc.c:120
static NTSTATUS NtfsReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PUCHAR Buffer, ULONG Length, ULONG ReadOffset, ULONG IrpFlags, PULONG LengthRead)
Definition: rw.c:43
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
Status
Definition: gdiplustypes.h:25
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
PFILE_OBJECT FileObject
Definition: ntfs.h:489
PIO_STACK_LOCATION Stack
Definition: ntfs.h:482
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:488
uint32_t ULONG
Definition: typedefs.h:59
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET ReadOffset
Definition: wdfusb.h:2003
#define IRP_PAGING_IO
* PFILE_OBJECT
Definition: iotypes.h:1998
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1776

◆ NtfsReadFile()

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

Definition at line 43 of file rw.c.

50{
53 PFILE_RECORD_HEADER FileRecord;
54 PNTFS_ATTR_CONTEXT DataContext;
55 ULONG RealLength;
56 ULONG RealReadOffset;
57 ULONG RealLengthRead;
58 ULONG ToRead;
59 BOOLEAN AllocatedBuffer = FALSE;
61 ULONGLONG StreamSize;
62
63 DPRINT("NtfsReadFile(%p, %p, %p, %lu, %lu, %lx, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
64
65 *LengthRead = 0;
66
67 if (Length == 0)
68 {
69 DPRINT1("Null read!\n");
70 return STATUS_SUCCESS;
71 }
72
73 Fcb = (PNTFS_FCB)FileObject->FsContext;
74
76 {
77 DPRINT1("Compressed file!\n");
80 }
81
83 {
84 DPRINT1("Encrypted file!\n");
87 }
88
89 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
90 if (FileRecord == NULL)
91 {
92 DPRINT1("Not enough memory!\n");
94 }
95
96 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT1("Can't find record!\n");
100 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
101 return Status;
102 }
103
104
105 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext, NULL);
106 if (!NT_SUCCESS(Status))
107 {
108 NTSTATUS BrowseStatus;
110 PNTFS_ATTR_RECORD Attribute;
111
112 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
113
114 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
115 while (NT_SUCCESS(BrowseStatus))
116 {
117 if (Attribute->Type == AttributeData)
118 {
120
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);
125 }
126
127 BrowseStatus = FindNextAttribute(&Context, &Attribute);
128 }
130
131 ReleaseAttributeContext(DataContext);
132 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
133 return Status;
134 }
135
136 StreamSize = AttributeDataLength(DataContext->pRecord);
137 if (ReadOffset >= StreamSize)
138 {
139 DPRINT1("Reading beyond stream end!\n");
140 ReleaseAttributeContext(DataContext);
141 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
142 return STATUS_END_OF_FILE;
143 }
144
145 ToRead = Length;
146 if (ReadOffset + Length > StreamSize)
147 ToRead = StreamSize - ReadOffset;
148
149 RealReadOffset = ReadOffset;
150 RealLength = ToRead;
151
152 if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
153 {
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)
158 {
159 if (RealReadOffset + RealLength + DeviceExt->NtfsInfo.BytesPerSector <= AttributeAllocatedLength(DataContext->pRecord))
160 RealLength += DeviceExt->NtfsInfo.BytesPerSector;
161 }
162
163
165 if (ReadBuffer == NULL)
166 {
167 DPRINT1("Not enough memory!\n");
168 ReleaseAttributeContext(DataContext);
169 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
171 }
172 AllocatedBuffer = TRUE;
173 }
174
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)
178 {
179 DPRINT1("Read failure!\n");
180 ReleaseAttributeContext(DataContext);
181 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
182 if (AllocatedBuffer)
183 {
185 }
186 return Status;
187 }
188
189 ReleaseAttributeContext(DataContext);
190 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
191
192 *LengthRead = ToRead;
193
194 DPRINT("%lu got read\n", *LengthRead);
195
196 if (AllocatedBuffer)
197 {
198 RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
199 }
200
201 if (ToRead != Length)
202 {
203 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
204 }
205
206 if (AllocatedBuffer)
207 {
209 }
210
211 return STATUS_SUCCESS;
212}
unsigned char BOOLEAN
struct NameRec_ * Name
Definition: cdprocs.h:460
#define ReadBuffer(BaseIoAddress, Buffer, Count)
Definition: atapi.h:339
#define DPRINT1
Definition: precomp.h:8
#define UNIMPLEMENTED
Definition: debug.h:115
_In_ PFCB Fcb
Definition: cdprocs.h:159
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1383
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1465
NTSTATUS FindNextAttribute(PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1431
@ AttributeData
Definition: ntfs.h:168
struct _FCB * PNTFS_FCB
#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_UP(n, align)
Definition: eventvwr.h:34
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
if(dx< 0)
Definition: linetemp.h:194
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
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
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
ULONGLONG AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:249
#define PCHAR
Definition: match.c:90
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
BOOLEAN NtfsFCBIsEncrypted(PNTFS_FCB Fcb)
Definition: fcb.c:152
BOOLEAN NtfsFCBIsCompressed(PNTFS_FCB Fcb)
Definition: fcb.c:146
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define STATUS_END_OF_FILE
Definition: shellext.h:67
USHORT NameOffset
Definition: ntfs.h:130
UCHAR NameLength
Definition: ntfs.h:129
ULONG Type
Definition: ntfs.h:126
Definition: cdstruc.h:902
ULONGLONG MFTIndex
Definition: ntfs.h:539
WCHAR Stream[MAX_PATH]
Definition: ntfs.h:523
#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
uint64_t ULONGLONG
Definition: typedefs.h:67
char * PCHAR
Definition: typedefs.h:51
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by NtfsRead().

◆ NtfsWrite()

NTSTATUS NtfsWrite ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 537 of file rw.c.

538{
544 ULONG Length = 0;
545 ULONG ReturnedWriteLength = 0;
547 PDEVICE_EXTENSION DeviceExt = NULL;
549 PIRP Irp = NULL;
550 ULONG BytesPerSector;
551
552 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext);
553 ASSERT(IrpContext);
554
555 // get the I/O request packet
556 Irp = IrpContext->Irp;
557
558 // This request is not allowed on the main device object
559 if (IrpContext->DeviceObject == NtfsGlobalData->DeviceObject)
560 {
561 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
562
563 Irp->IoStatus.Information = 0;
565 }
566
567 // get the File control block
568 Fcb = (PNTFS_FCB)IrpContext->FileObject->FsContext;
569 ASSERT(Fcb);
570
571 DPRINT("About to write %wS\n", Fcb->ObjectName);
572 DPRINT("NTFS Version: %d.%d\n", Fcb->Vcb->NtfsInfo.MajorVersion, Fcb->Vcb->NtfsInfo.MinorVersion);
573
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;
580
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)
585 {
586 ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
587 }
588
589 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset.QuadPart,
590 Length, BytesPerSector);
591
592 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
593 {
594 // TODO: Support large files
595 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
597 }
598
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)
602 {
603 // non-cached and non-buffered writes must be sector aligned
604 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
605 {
606 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
608 }
609 }
610
611 if (Length == 0)
612 {
613 DPRINT1("Null write!\n");
614
615 IrpContext->Irp->IoStatus.Information = 0;
616
617 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
618 if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
619 {
620 // FIXME: Update last write time
621 return STATUS_SUCCESS;
622 }
623
625 }
626
627 // get the Resource
628 if (Fcb->Flags & FCB_IS_VOLUME)
629 {
630 Resource = &DeviceExt->DirResource;
631 }
632 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
633 {
635 }
636 else
637 {
639 }
640
641 // acquire exclusive access to the Resource
643 {
644 return STATUS_CANT_WAIT;
645 }
646
647 /* From VfatWrite(). Todo: Handle file locks
648 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
649 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
650 {
651 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
652 {
653 Status = STATUS_FILE_LOCK_CONFLICT;
654 goto ByeBye;
655 }
656 }*/
657
658 // Is this an async request to a file?
659 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
660 {
661 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
662
665 }
666
667 // get the buffer of data the user is trying to write
669 ASSERT(Buffer);
670
671 // lock the buffer
673
674 // were we unable to lock the buffer?
675 if (!NT_SUCCESS(Status))
676 {
677 DPRINT1("Unable to lock user buffer!\n");
678
680 return Status;
681 }
682
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);
685
686 // TODO: handle HighPart of ByteOffset (large files)
687
688 // write the file
689 Status = NtfsWriteFile(DeviceExt,
691 Buffer,
692 Length,
693 ByteOffset.LowPart,
694 Irp->Flags,
696 &ReturnedWriteLength);
697
698 IrpContext->Irp->IoStatus.Status = Status;
699
700 // was the write successful?
701 if (NT_SUCCESS(Status))
702 {
703 // TODO: Update timestamps
704
705 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
706 {
707 // advance the file pointer
708 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + ReturnedWriteLength;
709 }
710
711 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
712 }
713 else
714 {
715 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength);
716 }
717
718 Irp->IoStatus.Information = ReturnedWriteLength;
719
720 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
721
723
724 return Status;
725}
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:843
NTSTATUS NtfsLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
Definition: misc.c:158
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:36
#define IRPCONTEXT_CANWAIT
Definition: ntfs.h:474
#define FCB_IS_VOLUME
Definition: ntfs.h:510
NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, const PUCHAR Buffer, ULONG Length, ULONG WriteOffset, ULONG IrpFlags, BOOLEAN CaseSensitive, PULONG LengthWritten)
Definition: rw.c:311
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
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:731
#define FILE_NO_INTERMEDIATE_BUFFERING
Definition: from_kernel.h:28
#define ASSERT(a)
Definition: mode.c:44
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
#define STATUS_CANT_WAIT
Definition: ntstatus.h:452
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:148
ULONG Flags
Definition: ntfs.h:481
CCHAR PriorityBoost
Definition: ntfs.h:491
ULONG Flags
Definition: ntfs.h:536
PVCB Vcb
Definition: cdstruc.h:933
FSRTL_COMMON_FCB_HEADER RFCB
Definition: ntfs.h:517
ERESOURCE PagingIoResource
Definition: ntfs.h:527
WCHAR * ObjectName
Definition: ntfs.h:524
ERESOURCE MainResource
Definition: ntfs.h:528
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
IO_STATUS_BLOCK IoStatus
unsigned char * PUCHAR
Definition: typedefs.h:53
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
LONGLONG QuadPart
Definition: typedefs.h:114
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define IRP_NOCACHE
#define SL_CASE_SENSITIVE
Definition: iotypes.h:1820
@ IoReadAccess
Definition: ketypes.h:863

Referenced by NtfsDispatch().

◆ NtfsWriteFile()

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

Definition at line 311 of file rw.c.

319{
322 PFILE_RECORD_HEADER FileRecord;
323 PNTFS_ATTR_CONTEXT DataContext;
324 ULONG AttributeOffset;
325 ULONGLONG StreamSize;
326
327 DPRINT("NtfsWriteFile(%p, %p, %p, %lu, %lu, %x, %s, %p)\n",
328 DeviceExt,
330 Buffer,
331 Length,
333 IrpFlags,
334 (CaseSensitive ? "TRUE" : "FALSE"),
335 LengthWritten);
336
337 *LengthWritten = 0;
338
339 ASSERT(DeviceExt);
340
341 if (Length == 0)
342 {
343 if (Buffer == NULL)
344 return STATUS_SUCCESS;
345 else
347 }
348
349 // get the File control block
350 Fcb = (PNTFS_FCB)FileObject->FsContext;
351 ASSERT(Fcb);
352
353 DPRINT("Fcb->PathName: %wS\n", Fcb->PathName);
354 DPRINT("Fcb->ObjectName: %wS\n", Fcb->ObjectName);
355
356 // we don't yet handle compression
358 {
359 DPRINT("Compressed file!\n");
362 }
363
364 // allocate non-paged memory for the FILE_RECORD_HEADER
365 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
366 if (FileRecord == NULL)
367 {
368 DPRINT1("Not enough memory! Can't write %wS!\n", Fcb->PathName);
370 }
371
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))
376 {
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);
380 return Status;
381 }
382
383 DPRINT("Found record for %wS\n", Fcb->ObjectName);
384
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,
388 &AttributeOffset);
389
390 // Did we fail to find the attribute?
391 if (!NT_SUCCESS(Status))
392 {
393 NTSTATUS BrowseStatus;
395 PNTFS_ATTR_RECORD Attribute;
396
397 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
398
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))
402 {
403 if (Attribute->Type == AttributeData)
404 {
406
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);
411 }
412
413 BrowseStatus = FindNextAttribute(&Context, &Attribute);
414 }
416
417 ReleaseAttributeContext(DataContext);
418 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
419 return Status;
420 }
421
422 // Get the size of the stream on disk
423 StreamSize = AttributeDataLength(DataContext->pRecord);
424
425 DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset, StreamSize);
426
427 // Are we trying to write beyond the end of the stream?
428 if (WriteOffset + Length > StreamSize)
429 {
430 // is increasing the stream size allowed?
431 if (!(Fcb->Flags & FCB_IS_VOLUME) &&
432 !(IrpFlags & IRP_PAGING_IO))
433 {
436 PFILENAME_ATTRIBUTE fileNameAttribute;
437 ULONGLONG ParentMFTId;
439
440 DataSize.QuadPart = WriteOffset + Length;
441
442 // set the attribute data length
443 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, &DataSize);
444 if (!NT_SUCCESS(Status))
445 {
446 ReleaseAttributeContext(DataContext);
447 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
448 *LengthWritten = 0;
449 return Status;
450 }
451
452 AllocationSize = AttributeAllocatedLength(DataContext->pRecord);
453
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);
459
460 ParentMFTId = fileNameAttribute->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
461
462 filename.Buffer = fileNameAttribute->Name;
463 filename.Length = fileNameAttribute->NameLength * sizeof(WCHAR);
464 filename.MaximumLength = filename.Length;
465
467 ParentMFTId,
468 &filename,
469 FALSE,
470 DataSize.QuadPart,
472 CaseSensitive);
473
474 }
475 else
476 {
477 // TODO - just fail for now
478 ReleaseAttributeContext(DataContext);
479 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
480 *LengthWritten = 0;
482 }
483 }
484
485 DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length, WriteOffset, StreamSize);
486
487 // Write the data to the attribute
488 Status = WriteAttribute(DeviceExt, DataContext, WriteOffset, Buffer, Length, LengthWritten, FileRecord);
489
490 // Did the write fail?
491 if (!NT_SUCCESS(Status))
492 {
493 DPRINT1("Write failure!\n");
494 ReleaseAttributeContext(DataContext);
495 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
496
497 return Status;
498 }
499
500 // This should never happen:
501 if (*LengthWritten != Length)
502 {
503 DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
504 *LengthWritten, Length);
506 }
507
508 ReleaseAttributeContext(DataContext);
509 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
510
511 return Status;
512}
#define NTFS_MFT_MASK
Definition: ntfs.h:68
PFILENAME_ATTRIBUTE GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1985
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:322
const char * filename
Definition: ioapi.h:137
NTSTATUS UpdateFileNameRecord(PDEVICE_EXTENSION Vcb, ULONGLONG ParentMFTIndex, PUNICODE_STRING FileName, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocationSize, BOOLEAN CaseSensitive)
Definition: mft.c:1660
NTSTATUS WriteAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG RealLengthWritten, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1315
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
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
#define STATUS_UNEXPECTED_IO_ERROR
Definition: ntstatus.h:469
UCHAR NameLength
Definition: ntfs.h:377
ULONGLONG DirectoryFileReferenceNumber
Definition: ntfs.h:360
WCHAR Name[1]
Definition: ntfs.h:379
WCHAR PathName[MAX_PATH]
Definition: ntfs.h:525
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET WriteOffset
Definition: wdfusb.h:1921

Referenced by NtfsWrite().