xref: /reactos/drivers/filesystems/ntfs/rw.c (revision c2c66aff)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002, 2014 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  *
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)
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include <ntddk.h>
30 #include "ntfs.h"
31 
32 #define NDEBUG
33 #include <debug.h>
34 
35 /* FUNCTIONS ****************************************************************/
36 
37 /*
38  * FUNCTION: Reads data from a file
39  */
40 static
41 NTSTATUS
42 NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
43              PFILE_OBJECT FileObject,
44              PUCHAR Buffer,
45              ULONG Length,
46              ULONG ReadOffset,
47              ULONG IrpFlags,
48              PULONG LengthRead)
49 {
50     NTSTATUS Status = STATUS_SUCCESS;
51     PNTFS_FCB Fcb;
52     PFILE_RECORD_HEADER FileRecord;
53     PNTFS_ATTR_CONTEXT DataContext;
54     ULONG RealLength;
55     ULONG RealReadOffset;
56     ULONG RealLengthRead;
57     ULONG ToRead;
58     BOOLEAN AllocatedBuffer = FALSE;
59     PCHAR ReadBuffer = (PCHAR)Buffer;
60     ULONGLONG StreamSize;
61 
62     DPRINT1("NtfsReadFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
63 
64     *LengthRead = 0;
65 
66     if (Length == 0)
67     {
68         DPRINT1("Null read!\n");
69         return STATUS_SUCCESS;
70     }
71 
72     Fcb = (PNTFS_FCB)FileObject->FsContext;
73 
74     if (NtfsFCBIsCompressed(Fcb))
75     {
76         DPRINT1("Compressed file!\n");
77         UNIMPLEMENTED;
78         return STATUS_NOT_IMPLEMENTED;
79     }
80 
81     FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
82     if (FileRecord == NULL)
83     {
84         DPRINT1("Not enough memory!\n");
85         return STATUS_INSUFFICIENT_RESOURCES;
86     }
87 
88     Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
89     if (!NT_SUCCESS(Status))
90     {
91         DPRINT1("Can't find record!\n");
92         ExFreePoolWithTag(FileRecord, TAG_NTFS);
93         return Status;
94     }
95 
96 
97     Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
98     if (!NT_SUCCESS(Status))
99     {
100         NTSTATUS BrowseStatus;
101         FIND_ATTR_CONTXT Context;
102         PNTFS_ATTR_RECORD Attribute;
103 
104         DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
105 
106         BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
107         while (NT_SUCCESS(BrowseStatus))
108         {
109             if (Attribute->Type == AttributeData)
110             {
111                 UNICODE_STRING Name;
112 
113                 Name.Length = Attribute->NameLength * sizeof(WCHAR);
114                 Name.MaximumLength = Name.Length;
115                 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
116                 DPRINT1("Data stream: '%wZ' available\n", &Name);
117             }
118 
119             BrowseStatus = FindNextAttribute(&Context, &Attribute);
120         }
121         FindCloseAttribute(&Context);
122 
123         ReleaseAttributeContext(DataContext);
124         ExFreePoolWithTag(FileRecord, TAG_NTFS);
125         return Status;
126     }
127 
128     StreamSize = AttributeDataLength(&DataContext->Record);
129     if (ReadOffset >= StreamSize)
130     {
131         DPRINT1("Reading beyond stream end!\n");
132         ReleaseAttributeContext(DataContext);
133         ExFreePoolWithTag(FileRecord, TAG_NTFS);
134         return STATUS_END_OF_FILE;
135     }
136 
137     ToRead = Length;
138     if (ReadOffset + Length > StreamSize)
139         ToRead = StreamSize - ReadOffset;
140 
141     RealReadOffset = ReadOffset;
142     RealLength = ToRead;
143 
144     if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
145     {
146         RealReadOffset = ROUND_DOWN(ReadOffset, DeviceExt->NtfsInfo.BytesPerSector);
147         RealLength = ROUND_UP(ToRead, DeviceExt->NtfsInfo.BytesPerSector);
148         /* do we need to extend RealLength by one sector? */
149         if (RealLength + RealReadOffset < ReadOffset + Length)
150         {
151             if (RealReadOffset + RealLength + DeviceExt->NtfsInfo.BytesPerSector <= AttributeAllocatedLength(&DataContext->Record))
152                 RealLength += DeviceExt->NtfsInfo.BytesPerSector;
153         }
154 
155 
156         ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength, TAG_NTFS);
157         if (ReadBuffer == NULL)
158         {
159             DPRINT1("Not enough memory!\n");
160             ReleaseAttributeContext(DataContext);
161             ExFreePoolWithTag(FileRecord, TAG_NTFS);
162             return STATUS_INSUFFICIENT_RESOURCES;
163         }
164         AllocatedBuffer = TRUE;
165     }
166 
167     DPRINT1("Effective read: %lu at %lu for stream '%S'\n", RealLength, RealReadOffset, Fcb->Stream);
168     RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
169     if (RealLengthRead == 0)
170     {
171         DPRINT1("Read failure!\n");
172         ReleaseAttributeContext(DataContext);
173         ExFreePoolWithTag(FileRecord, TAG_NTFS);
174         if (AllocatedBuffer)
175         {
176             ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
177         }
178         return Status;
179     }
180 
181     ReleaseAttributeContext(DataContext);
182     ExFreePoolWithTag(FileRecord, TAG_NTFS);
183 
184     *LengthRead = ToRead;
185 
186     DPRINT1("%lu got read\n", *LengthRead);
187 
188     if (AllocatedBuffer)
189     {
190         RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
191     }
192 
193     if (ToRead != Length)
194     {
195         RtlZeroMemory(Buffer + ToRead, Length - ToRead);
196     }
197 
198     if (AllocatedBuffer)
199     {
200         ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
201     }
202 
203     return STATUS_SUCCESS;
204 }
205 
206 
207 NTSTATUS
208 NtfsRead(PNTFS_IRP_CONTEXT IrpContext)
209 {
210     PDEVICE_EXTENSION DeviceExt;
211     PIO_STACK_LOCATION Stack;
212     PFILE_OBJECT FileObject;
213     PVOID Buffer;
214     ULONG ReadLength;
215     LARGE_INTEGER ReadOffset;
216     ULONG ReturnedReadLength = 0;
217     NTSTATUS Status = STATUS_SUCCESS;
218     PIRP Irp;
219     PDEVICE_OBJECT DeviceObject;
220 
221     DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
222 
223     DeviceObject = IrpContext->DeviceObject;
224     Irp = IrpContext->Irp;
225     Stack = IrpContext->Stack;
226     FileObject = IrpContext->FileObject;
227 
228     DeviceExt = DeviceObject->DeviceExtension;
229     ReadLength = Stack->Parameters.Read.Length;
230     ReadOffset = Stack->Parameters.Read.ByteOffset;
231     Buffer = NtfsGetUserBuffer(Irp, BooleanFlagOn(Irp->Flags, IRP_PAGING_IO));
232 
233     Status = NtfsReadFile(DeviceExt,
234                           FileObject,
235                           Buffer,
236                           ReadLength,
237                           ReadOffset.u.LowPart,
238                           Irp->Flags,
239                           &ReturnedReadLength);
240     if (NT_SUCCESS(Status))
241     {
242         if (FileObject->Flags & FO_SYNCHRONOUS_IO)
243         {
244             FileObject->CurrentByteOffset.QuadPart =
245                 ReadOffset.QuadPart + ReturnedReadLength;
246         }
247 
248         Irp->IoStatus.Information = ReturnedReadLength;
249     }
250     else
251     {
252         Irp->IoStatus.Information = 0;
253     }
254 
255     return Status;
256 }
257 
258 
259 NTSTATUS
260 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext)
261 {
262     DPRINT("NtfsWrite(IrpContext %p)\n",IrpContext);
263 
264     IrpContext->Irp->IoStatus.Information = 0;
265     return STATUS_NOT_SUPPORTED;
266 }
267 
268 /* EOF */
269