[FASTFAT] Fix size checking in VfatGetFileNameInformation()
[reactos.git] / drivers / filesystems / ntfs / rw.c
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 */