13e9d86595e228a4c6d50e86a7402e084c74df32
[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 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
149 ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS);
150 if (ReadBuffer == NULL)
151 {
152 DPRINT1("Not enough memory!\n");
153 ReleaseAttributeContext(DataContext);
154 ExFreePoolWithTag(FileRecord, TAG_NTFS);
155 return STATUS_INSUFFICIENT_RESOURCES;
156 }
157 AllocatedBuffer = TRUE;
158 }
159
160 DPRINT1("Effective read: %lu at %lu for stream '%S'\n", RealLength, RealReadOffset, Fcb->Stream);
161 RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
162 if (RealLengthRead == 0)
163 {
164 DPRINT1("Read failure!\n");
165 ReleaseAttributeContext(DataContext);
166 ExFreePoolWithTag(FileRecord, TAG_NTFS);
167 if (AllocatedBuffer)
168 {
169 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
170 }
171 return Status;
172 }
173
174 ReleaseAttributeContext(DataContext);
175 ExFreePoolWithTag(FileRecord, TAG_NTFS);
176
177 *LengthRead = ToRead;
178
179 DPRINT1("%lu got read\n", *LengthRead);
180
181 if (AllocatedBuffer)
182 {
183 RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
184 }
185
186 if (ToRead != Length)
187 {
188 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
189 }
190
191 if (AllocatedBuffer)
192 {
193 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
194 }
195
196 return STATUS_SUCCESS;
197 }
198
199
200 NTSTATUS
201 NtfsRead(PNTFS_IRP_CONTEXT IrpContext)
202 {
203 PDEVICE_EXTENSION DeviceExt;
204 PIO_STACK_LOCATION Stack;
205 PFILE_OBJECT FileObject;
206 PVOID Buffer;
207 ULONG ReadLength;
208 LARGE_INTEGER ReadOffset;
209 ULONG ReturnedReadLength = 0;
210 NTSTATUS Status = STATUS_SUCCESS;
211 PIRP Irp;
212 PDEVICE_OBJECT DeviceObject;
213
214 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
215
216 DeviceObject = IrpContext->DeviceObject;
217 Irp = IrpContext->Irp;
218 Stack = IrpContext->Stack;
219 FileObject = IrpContext->FileObject;
220
221 DeviceExt = DeviceObject->DeviceExtension;
222 ReadLength = Stack->Parameters.Read.Length;
223 ReadOffset = Stack->Parameters.Read.ByteOffset;
224 Buffer = NtfsGetUserBuffer(Irp, BooleanFlagOn(Irp->Flags, IRP_PAGING_IO));
225
226 Status = NtfsReadFile(DeviceExt,
227 FileObject,
228 Buffer,
229 ReadLength,
230 ReadOffset.u.LowPart,
231 Irp->Flags,
232 &ReturnedReadLength);
233 if (NT_SUCCESS(Status))
234 {
235 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
236 {
237 FileObject->CurrentByteOffset.QuadPart =
238 ReadOffset.QuadPart + ReturnedReadLength;
239 }
240
241 Irp->IoStatus.Information = ReturnedReadLength;
242 }
243 else
244 {
245 Irp->IoStatus.Information = 0;
246 }
247
248 return Status;
249 }
250
251
252 NTSTATUS
253 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext)
254 {
255 DPRINT("NtfsWrite(IrpContext %p)\n",IrpContext);
256
257 IrpContext->Irp->IoStatus.Information = 0;
258 return STATUS_NOT_SUPPORTED;
259 }
260
261 /* EOF */