* Sync up to trunk head (r65394).
[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
61 DPRINT1("NtfsReadFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
62
63 *LengthRead = 0;
64
65 if (Length == 0)
66 {
67 DPRINT1("Null read!\n");
68 return STATUS_SUCCESS;
69 }
70
71 Fcb = (PNTFS_FCB)FileObject->FsContext;
72
73 if (ReadOffset >= Fcb->Entry.AllocatedSize)
74 {
75 DPRINT1("Reading beyond file end!\n");
76 return STATUS_END_OF_FILE;
77 }
78
79 ToRead = Length;
80 if (ReadOffset + Length > Fcb->Entry.AllocatedSize)
81 ToRead = Fcb->Entry.AllocatedSize - ReadOffset;
82
83 RealReadOffset = ReadOffset;
84 RealLength = ToRead;
85
86 if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
87 {
88 RealReadOffset = ROUND_DOWN(ReadOffset, DeviceExt->NtfsInfo.BytesPerSector);
89 RealLength = ROUND_UP(ToRead, DeviceExt->NtfsInfo.BytesPerSector);
90
91 ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS);
92 if (ReadBuffer == NULL)
93 {
94 DPRINT1("Not enough memory!\n");
95 return STATUS_INSUFFICIENT_RESOURCES;
96 }
97 AllocatedBuffer = TRUE;
98 }
99
100 FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
101 if (FileRecord == NULL)
102 {
103 DPRINT1("Not enough memory!\n");
104 return STATUS_INSUFFICIENT_RESOURCES;
105 }
106
107 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
108 if (!NT_SUCCESS(Status))
109 {
110 DPRINT1("Can't find record!\n");
111 ExFreePoolWithTag(FileRecord, TAG_NTFS);
112 return Status;
113 }
114
115 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, L"", 0, &DataContext);
116 if (!NT_SUCCESS(Status))
117 {
118 DPRINT1("No data associated with file!\n");
119 ExFreePoolWithTag(FileRecord, TAG_NTFS);
120 return Status;
121 }
122
123 DPRINT1("Effective read: %lu at %lu\n", RealLength, RealReadOffset);
124 RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
125 if (RealLengthRead != RealLength)
126 {
127 DPRINT1("Read failure!\n");
128 ReleaseAttributeContext(DataContext);
129 ExFreePoolWithTag(FileRecord, TAG_NTFS);
130 if (AllocatedBuffer)
131 {
132 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
133 }
134 return Status;
135 }
136
137 ReleaseAttributeContext(DataContext);
138 ExFreePoolWithTag(FileRecord, TAG_NTFS);
139
140 *LengthRead = ToRead;
141
142 DPRINT1("%lu got read\n", *LengthRead);
143
144 if (AllocatedBuffer)
145 {
146 RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
147 }
148
149 if (ToRead != Length)
150 {
151 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
152 }
153
154 if (AllocatedBuffer)
155 {
156 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
157 }
158
159 return STATUS_SUCCESS;
160 }
161
162
163 NTSTATUS
164 NTAPI
165 NtfsFsdRead(PDEVICE_OBJECT DeviceObject,
166 PIRP Irp)
167 {
168 PDEVICE_EXTENSION DeviceExt;
169 PIO_STACK_LOCATION Stack;
170 PFILE_OBJECT FileObject;
171 PVOID Buffer;
172 ULONG ReadLength;
173 LARGE_INTEGER ReadOffset;
174 ULONG ReturnedReadLength = 0;
175 NTSTATUS Status = STATUS_SUCCESS;
176
177 DPRINT("NtfsRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
178
179 DeviceExt = DeviceObject->DeviceExtension;
180 Stack = IoGetCurrentIrpStackLocation(Irp);
181 FileObject = Stack->FileObject;
182
183 ReadLength = Stack->Parameters.Read.Length;
184 ReadOffset = Stack->Parameters.Read.ByteOffset;
185 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
186
187 Status = NtfsReadFile(DeviceExt,
188 FileObject,
189 Buffer,
190 ReadLength,
191 ReadOffset.u.LowPart,
192 Irp->Flags,
193 &ReturnedReadLength);
194 if (NT_SUCCESS(Status))
195 {
196 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
197 {
198 FileObject->CurrentByteOffset.QuadPart =
199 ReadOffset.QuadPart + ReturnedReadLength;
200 }
201
202 Irp->IoStatus.Information = ReturnedReadLength;
203 }
204 else
205 {
206 Irp->IoStatus.Information = 0;
207 }
208
209 Irp->IoStatus.Status = Status;
210 IoCompleteRequest(Irp,IO_NO_INCREMENT);
211
212 return Status;
213 }
214
215
216 NTSTATUS
217 NTAPI
218 NtfsFsdWrite(PDEVICE_OBJECT DeviceObject,
219 PIRP Irp)
220 {
221 DPRINT("NtfwWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
222
223 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
224 Irp->IoStatus.Information = 0;
225 return STATUS_NOT_SUPPORTED;
226 }
227
228 /* EOF */