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