7387b8572ce2ada76db6563a936cde1eff9648a6
[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
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 if (AllocatedBuffer)
105 {
106 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
107 }
108 return STATUS_INSUFFICIENT_RESOURCES;
109 }
110
111 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
112 if (!NT_SUCCESS(Status))
113 {
114 DPRINT1("Can't find record!\n");
115 ExFreePoolWithTag(FileRecord, TAG_NTFS);
116 if (AllocatedBuffer)
117 {
118 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
119 }
120 return Status;
121 }
122
123 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, L"", 0, &DataContext);
124 if (!NT_SUCCESS(Status))
125 {
126 DPRINT1("No data associated with file!\n");
127 ExFreePoolWithTag(FileRecord, TAG_NTFS);
128 if (AllocatedBuffer)
129 {
130 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
131 }
132 return Status;
133 }
134
135 DPRINT1("Effective read: %lu at %lu\n", RealLength, RealReadOffset);
136 RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
137 if (RealLengthRead != RealLength)
138 {
139 DPRINT1("Read failure!\n");
140 ReleaseAttributeContext(DataContext);
141 ExFreePoolWithTag(FileRecord, TAG_NTFS);
142 if (AllocatedBuffer)
143 {
144 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
145 }
146 return Status;
147 }
148
149 ReleaseAttributeContext(DataContext);
150 ExFreePoolWithTag(FileRecord, TAG_NTFS);
151
152 *LengthRead = ToRead;
153
154 DPRINT1("%lu got read\n", *LengthRead);
155
156 if (AllocatedBuffer)
157 {
158 RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
159 }
160
161 if (ToRead != Length)
162 {
163 RtlZeroMemory(Buffer + ToRead, Length - ToRead);
164 }
165
166 if (AllocatedBuffer)
167 {
168 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
169 }
170
171 return STATUS_SUCCESS;
172 }
173
174
175 NTSTATUS
176 NtfsRead(PNTFS_IRP_CONTEXT IrpContext)
177 {
178 PDEVICE_EXTENSION DeviceExt;
179 PIO_STACK_LOCATION Stack;
180 PFILE_OBJECT FileObject;
181 PVOID Buffer;
182 ULONG ReadLength;
183 LARGE_INTEGER ReadOffset;
184 ULONG ReturnedReadLength = 0;
185 NTSTATUS Status = STATUS_SUCCESS;
186 PIRP Irp;
187 PDEVICE_OBJECT DeviceObject;
188
189 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
190
191 DeviceObject = IrpContext->DeviceObject;
192 Irp = IrpContext->Irp;
193 Stack = IrpContext->Stack;
194 FileObject = IrpContext->FileObject;
195
196 DeviceExt = DeviceObject->DeviceExtension;
197 ReadLength = Stack->Parameters.Read.Length;
198 ReadOffset = Stack->Parameters.Read.ByteOffset;
199 Buffer = NtfsGetUserBuffer(Irp, Irp->Flags & IRP_PAGING_IO);
200
201 Status = NtfsReadFile(DeviceExt,
202 FileObject,
203 Buffer,
204 ReadLength,
205 ReadOffset.u.LowPart,
206 Irp->Flags,
207 &ReturnedReadLength);
208 if (NT_SUCCESS(Status))
209 {
210 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
211 {
212 FileObject->CurrentByteOffset.QuadPart =
213 ReadOffset.QuadPart + ReturnedReadLength;
214 }
215
216 Irp->IoStatus.Information = ReturnedReadLength;
217 }
218 else
219 {
220 Irp->IoStatus.Information = 0;
221 }
222
223 return Status;
224 }
225
226
227 NTSTATUS
228 NtfsWrite(PNTFS_IRP_CONTEXT IrpContext)
229 {
230 DPRINT("NtfsWrite(IrpContext %p)\n",IrpContext);
231
232 IrpContext->Irp->IoStatus.Information = 0;
233 return STATUS_NOT_SUPPORTED;
234 }
235
236 /* EOF */