572bd8507837d0fb470695cce05122e881db4640
[reactos.git] / reactos / 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 FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
75 if (FileRecord == NULL)
76 {
77 DPRINT1("Not enough memory!\n");
78 return STATUS_INSUFFICIENT_RESOURCES;
79 }
80
81 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
82 if (!NT_SUCCESS(Status))
83 {
84 DPRINT1("Can't find record!\n");
85 ExFreePoolWithTag(FileRecord, TAG_NTFS);
86 return Status;
87 }
88
89
90 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
91 if (!NT_SUCCESS(Status))
92 {
93 NTSTATUS BrowseStatus;
94 FIND_ATTR_CONTXT Context;
95 PNTFS_ATTR_RECORD Attribute;
96
97 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
98
99 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
100 while (NT_SUCCESS(BrowseStatus))
101 {
102 if (Attribute->Type == AttributeData)
103 {
104 UNICODE_STRING Name;
105
106 Name.Length = Attribute->NameLength * sizeof(WCHAR);
107 Name.MaximumLength = Name.Length;
108 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
109 DPRINT1("Data stream: '%wZ' available\n", &Name);
110 }
111
112 BrowseStatus = FindNextAttribute(&Context, &Attribute);
113 }
114 FindCloseAttribute(&Context);
115
116 ReleaseAttributeContext(DataContext);
117 ExFreePoolWithTag(FileRecord, TAG_NTFS);
118 return Status;
119 }
120
121 StreamSize = AttributeDataLength(&DataContext->Record);
122 if (ReadOffset >= StreamSize)
123 {
124 DPRINT1("Reading beyond stream end!\n");
125 ReleaseAttributeContext(DataContext);
126 ExFreePoolWithTag(FileRecord, TAG_NTFS);
127 return STATUS_END_OF_FILE;
128 }
129
130 ToRead = Length;
131 if (ReadOffset + Length > StreamSize)
132 ToRead = StreamSize - ReadOffset;
133
134 RealReadOffset = ReadOffset;
135 RealLength = ToRead;
136
137 if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
138 {
139 RealReadOffset = ROUND_DOWN(ReadOffset, DeviceExt->NtfsInfo.BytesPerSector);
140 RealLength = ROUND_UP(ToRead, DeviceExt->NtfsInfo.BytesPerSector);
141
142 ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS);
143 if (ReadBuffer == NULL)
144 {
145 DPRINT1("Not enough memory!\n");
146 ReleaseAttributeContext(DataContext);
147 ExFreePoolWithTag(FileRecord, TAG_NTFS);
148 return STATUS_INSUFFICIENT_RESOURCES;
149 }
150 AllocatedBuffer = TRUE;
151 }
152
153 DPRINT1("Effective read: %lu at %lu for stream '%S'\n", RealLength, RealReadOffset, Fcb->Stream);
154 RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
155 if (RealLengthRead == 0)
156 {
157 DPRINT1("Read failure!\n");
158 ReleaseAttributeContext(DataContext);
159 ExFreePoolWithTag(FileRecord, TAG_NTFS);
160 if (AllocatedBuffer)
161 {
162 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
163 }
164 return Status;
165 }
166
167 ReleaseAttributeContext(DataContext);
168 ExFreePoolWithTag(FileRecord, TAG_NTFS);
169
170 *LengthRead = ToRead;
171
172 DPRINT1("%lu got read\n", *LengthRead);
173
174 if (AllocatedBuffer)
175 {
176 RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
177 }
178
179 if (ToRead != Length)
180 {
181 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
182 }
183
184 if (AllocatedBuffer)
185 {
186 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
187 }
188
189 return STATUS_SUCCESS;
190 }
191
192
193 NTSTATUS
194 NtfsRead(PNTFS_IRP_CONTEXT IrpContext)
195 {
196 PDEVICE_EXTENSION DeviceExt;
197 PIO_STACK_LOCATION Stack;
198 PFILE_OBJECT FileObject;
199 PVOID Buffer;
200 ULONG ReadLength;
201 LARGE_INTEGER ReadOffset;
202 ULONG ReturnedReadLength = 0;
203 NTSTATUS Status = STATUS_SUCCESS;
204 PIRP Irp;
205 PDEVICE_OBJECT DeviceObject;
206
207 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
208
209 DeviceObject = IrpContext->DeviceObject;
210 Irp = IrpContext->Irp;
211 Stack = IrpContext->Stack;
212 FileObject = IrpContext->FileObject;
213
214 DeviceExt = DeviceObject->DeviceExtension;
215 ReadLength = Stack->Parameters.Read.Length;
216 ReadOffset = Stack->Parameters.Read.ByteOffset;
217 Buffer = NtfsGetUserBuffer(Irp, BooleanFlagOn(Irp->Flags, IRP_PAGING_IO));
218
219 Status = NtfsReadFile(DeviceExt,
220 FileObject,
221 Buffer,
222 ReadLength,
223 ReadOffset.u.LowPart,
224 Irp->Flags,
225 &ReturnedReadLength);
226 if (NT_SUCCESS(Status))
227 {
228 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
229 {
230 FileObject->CurrentByteOffset.QuadPart =
231 ReadOffset.QuadPart + ReturnedReadLength;
232 }
233
234 Irp->IoStatus.Information = ReturnedReadLength;
235 }
236 else
237 {
238 Irp->IoStatus.Information = 0;
239 }
240
241 return Status;
242 }
243
244
245 NTSTATUS
246 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext)
247 {
248 DPRINT("NtfsWrite(IrpContext %p)\n",IrpContext);
249
250 IrpContext->Irp->IoStatus.Information = 0;
251 return STATUS_NOT_SUPPORTED;
252 }
253
254 /* EOF */