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