1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002 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/dirctl.c 22 * PURPOSE: NTFS filesystem driver 23 * PROGRAMMERS: Eric Kohl 24 * Hervé Poussineau (hpoussin@reactos.org) 25 * Pierre Schweitzer (pierre@reactos.org) 26 */ 27 28 /* INCLUDES *****************************************************************/ 29 30 #include "ntfs.h" 31 32 #define NDEBUG 33 #include <debug.h> 34 35 /* FUNCTIONS ****************************************************************/ 36 37 /* 38 * FUNCTION: Retrieve the standard file information 39 */ 40 static 41 NTSTATUS 42 NtfsGetStandardInformation(PNTFS_FCB Fcb, 43 PDEVICE_OBJECT DeviceObject, 44 PFILE_STANDARD_INFORMATION StandardInfo, 45 PULONG BufferLength) 46 { 47 UNREFERENCED_PARAMETER(DeviceObject); 48 49 DPRINT1("NtfsGetStandardInformation(%p, %p, %p, %p)\n", Fcb, DeviceObject, StandardInfo, BufferLength); 50 51 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION)) 52 return STATUS_BUFFER_TOO_SMALL; 53 54 /* PRECONDITION */ 55 ASSERT(StandardInfo != NULL); 56 ASSERT(Fcb != NULL); 57 58 RtlZeroMemory(StandardInfo, 59 sizeof(FILE_STANDARD_INFORMATION)); 60 61 StandardInfo->AllocationSize = Fcb->RFCB.AllocationSize; 62 StandardInfo->EndOfFile = Fcb->RFCB.FileSize; 63 StandardInfo->NumberOfLinks = Fcb->LinkCount; 64 StandardInfo->DeletePending = FALSE; 65 StandardInfo->Directory = NtfsFCBIsDirectory(Fcb); 66 67 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION); 68 69 return STATUS_SUCCESS; 70 } 71 72 73 static 74 NTSTATUS 75 NtfsGetPositionInformation(PFILE_OBJECT FileObject, 76 PFILE_POSITION_INFORMATION PositionInfo, 77 PULONG BufferLength) 78 { 79 DPRINT1("NtfsGetPositionInformation(%p, %p, %p)\n", FileObject, PositionInfo, BufferLength); 80 81 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION)) 82 return STATUS_BUFFER_TOO_SMALL; 83 84 PositionInfo->CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart; 85 86 DPRINT("Getting position %I64x\n", 87 PositionInfo->CurrentByteOffset.QuadPart); 88 89 *BufferLength -= sizeof(FILE_POSITION_INFORMATION); 90 91 return STATUS_SUCCESS; 92 } 93 94 95 static 96 NTSTATUS 97 NtfsGetBasicInformation(PFILE_OBJECT FileObject, 98 PNTFS_FCB Fcb, 99 PDEVICE_OBJECT DeviceObject, 100 PFILE_BASIC_INFORMATION BasicInfo, 101 PULONG BufferLength) 102 { 103 PFILENAME_ATTRIBUTE FileName = &Fcb->Entry; 104 105 DPRINT1("NtfsGetBasicInformation(%p, %p, %p, %p, %p)\n", FileObject, Fcb, DeviceObject, BasicInfo, BufferLength); 106 107 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION)) 108 return STATUS_BUFFER_TOO_SMALL; 109 110 BasicInfo->CreationTime.QuadPart = FileName->CreationTime; 111 BasicInfo->LastAccessTime.QuadPart = FileName->LastAccessTime; 112 BasicInfo->LastWriteTime.QuadPart = FileName->LastWriteTime; 113 BasicInfo->ChangeTime.QuadPart = FileName->ChangeTime; 114 115 NtfsFileFlagsToAttributes(FileName->FileAttributes, &BasicInfo->FileAttributes); 116 117 *BufferLength -= sizeof(FILE_BASIC_INFORMATION); 118 119 return STATUS_SUCCESS; 120 } 121 122 123 /* 124 * FUNCTION: Retrieve the file name information 125 */ 126 static 127 NTSTATUS 128 NtfsGetNameInformation(PFILE_OBJECT FileObject, 129 PNTFS_FCB Fcb, 130 PDEVICE_OBJECT DeviceObject, 131 PFILE_NAME_INFORMATION NameInfo, 132 PULONG BufferLength) 133 { 134 ULONG BytesToCopy; 135 136 UNREFERENCED_PARAMETER(FileObject); 137 UNREFERENCED_PARAMETER(DeviceObject); 138 139 DPRINT1("NtfsGetNameInformation(%p, %p, %p, %p, %p)\n", FileObject, Fcb, DeviceObject, NameInfo, BufferLength); 140 141 ASSERT(NameInfo != NULL); 142 ASSERT(Fcb != NULL); 143 144 /* If buffer can't hold at least the file name length, bail out */ 145 if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) 146 return STATUS_BUFFER_TOO_SMALL; 147 148 /* Save file name length, and as much file len, as buffer length allows */ 149 NameInfo->FileNameLength = wcslen(Fcb->PathName) * sizeof(WCHAR); 150 151 /* Calculate amount of bytes to copy not to overflow the buffer */ 152 BytesToCopy = min(NameInfo->FileNameLength, 153 *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])); 154 155 /* Fill in the bytes */ 156 RtlCopyMemory(NameInfo->FileName, Fcb->PathName, BytesToCopy); 157 158 /* Check if we could write more but are not able to */ 159 if (*BufferLength < NameInfo->FileNameLength + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) 160 { 161 /* Return number of bytes written */ 162 *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy; 163 return STATUS_BUFFER_OVERFLOW; 164 } 165 166 /* We filled up as many bytes, as needed */ 167 *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + NameInfo->FileNameLength); 168 169 return STATUS_SUCCESS; 170 } 171 172 173 static 174 NTSTATUS 175 NtfsGetInternalInformation(PNTFS_FCB Fcb, 176 PFILE_INTERNAL_INFORMATION InternalInfo, 177 PULONG BufferLength) 178 { 179 DPRINT1("NtfsGetInternalInformation(%p, %p, %p)\n", Fcb, InternalInfo, BufferLength); 180 181 ASSERT(InternalInfo); 182 ASSERT(Fcb); 183 184 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION)) 185 return STATUS_BUFFER_TOO_SMALL; 186 187 InternalInfo->IndexNumber.QuadPart = Fcb->MFTIndex; 188 189 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION); 190 191 return STATUS_SUCCESS; 192 } 193 194 static 195 NTSTATUS 196 NtfsGetNetworkOpenInformation(PNTFS_FCB Fcb, 197 PDEVICE_EXTENSION DeviceExt, 198 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo, 199 PULONG BufferLength) 200 { 201 PFILENAME_ATTRIBUTE FileName = &Fcb->Entry; 202 203 DPRINT1("NtfsGetNetworkOpenInformation(%p, %p, %p, %p)\n", Fcb, DeviceExt, NetworkInfo, BufferLength); 204 205 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION)) 206 return STATUS_BUFFER_TOO_SMALL; 207 208 NetworkInfo->CreationTime.QuadPart = FileName->CreationTime; 209 NetworkInfo->LastAccessTime.QuadPart = FileName->LastAccessTime; 210 NetworkInfo->LastWriteTime.QuadPart = FileName->LastWriteTime; 211 NetworkInfo->ChangeTime.QuadPart = FileName->ChangeTime; 212 213 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize; 214 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize; 215 216 NtfsFileFlagsToAttributes(FileName->FileAttributes, &NetworkInfo->FileAttributes); 217 218 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION); 219 return STATUS_SUCCESS; 220 } 221 222 static 223 NTSTATUS 224 NtfsGetSteamInformation(PNTFS_FCB Fcb, 225 PDEVICE_EXTENSION DeviceExt, 226 PFILE_STREAM_INFORMATION StreamInfo, 227 PULONG BufferLength) 228 { 229 ULONG CurrentSize; 230 FIND_ATTR_CONTXT Context; 231 PNTFS_ATTR_RECORD Attribute; 232 NTSTATUS Status, BrowseStatus; 233 PFILE_RECORD_HEADER FileRecord; 234 PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL; 235 236 if (*BufferLength < sizeof(FILE_STREAM_INFORMATION)) 237 return STATUS_BUFFER_TOO_SMALL; 238 239 FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS); 240 if (FileRecord == NULL) 241 { 242 DPRINT1("Not enough memory!\n"); 243 return STATUS_INSUFFICIENT_RESOURCES; 244 } 245 246 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord); 247 if (!NT_SUCCESS(Status)) 248 { 249 DPRINT1("Can't find record!\n"); 250 ExFreePoolWithTag(FileRecord, TAG_NTFS); 251 return Status; 252 } 253 254 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute); 255 while (NT_SUCCESS(BrowseStatus)) 256 { 257 if (Attribute->Type == AttributeData) 258 { 259 CurrentSize = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) + Attribute->NameLength * sizeof(WCHAR) + wcslen(L"::$DATA") * sizeof(WCHAR); 260 261 if (CurrentSize > *BufferLength) 262 { 263 Status = STATUS_BUFFER_OVERFLOW; 264 break; 265 } 266 267 CurrentInfo->NextEntryOffset = 0; 268 CurrentInfo->StreamNameLength = (Attribute->NameLength + wcslen(L"::$DATA")) * sizeof(WCHAR); 269 CurrentInfo->StreamSize.QuadPart = AttributeDataLength(Attribute); 270 CurrentInfo->StreamAllocationSize.QuadPart = AttributeAllocatedLength(Attribute); 271 CurrentInfo->StreamName[0] = L':'; 272 RtlMoveMemory(&CurrentInfo->StreamName[1], (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset), CurrentInfo->StreamNameLength); 273 RtlMoveMemory(&CurrentInfo->StreamName[Attribute->NameLength + 1], L":$DATA", sizeof(L":$DATA") - sizeof(UNICODE_NULL)); 274 275 if (Previous != NULL) 276 { 277 Previous->NextEntryOffset = (ULONG_PTR)CurrentInfo - (ULONG_PTR)Previous; 278 } 279 Previous = CurrentInfo; 280 CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)CurrentInfo + CurrentSize); 281 *BufferLength -= CurrentSize; 282 } 283 284 BrowseStatus = FindNextAttribute(&Context, &Attribute); 285 } 286 287 FindCloseAttribute(&Context); 288 ExFreePoolWithTag(FileRecord, TAG_NTFS); 289 return Status; 290 } 291 292 /* 293 * FUNCTION: Retrieve the specified file information 294 */ 295 NTSTATUS 296 NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext) 297 { 298 FILE_INFORMATION_CLASS FileInformationClass; 299 PIO_STACK_LOCATION Stack; 300 PFILE_OBJECT FileObject; 301 PNTFS_FCB Fcb; 302 PVOID SystemBuffer; 303 ULONG BufferLength; 304 PIRP Irp; 305 PDEVICE_OBJECT DeviceObject; 306 NTSTATUS Status = STATUS_SUCCESS; 307 308 DPRINT1("NtfsQueryInformation(%p)\n", IrpContext); 309 310 Irp = IrpContext->Irp; 311 Stack = IrpContext->Stack; 312 DeviceObject = IrpContext->DeviceObject; 313 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; 314 FileObject = IrpContext->FileObject; 315 Fcb = FileObject->FsContext; 316 317 SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 318 BufferLength = Stack->Parameters.QueryFile.Length; 319 320 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, 321 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 322 { 323 return NtfsMarkIrpContextForQueue(IrpContext); 324 } 325 326 switch (FileInformationClass) 327 { 328 case FileStandardInformation: 329 Status = NtfsGetStandardInformation(Fcb, 330 DeviceObject, 331 SystemBuffer, 332 &BufferLength); 333 break; 334 335 case FilePositionInformation: 336 Status = NtfsGetPositionInformation(FileObject, 337 SystemBuffer, 338 &BufferLength); 339 break; 340 341 case FileBasicInformation: 342 Status = NtfsGetBasicInformation(FileObject, 343 Fcb, 344 DeviceObject, 345 SystemBuffer, 346 &BufferLength); 347 break; 348 349 case FileNameInformation: 350 Status = NtfsGetNameInformation(FileObject, 351 Fcb, 352 DeviceObject, 353 SystemBuffer, 354 &BufferLength); 355 break; 356 357 case FileInternalInformation: 358 Status = NtfsGetInternalInformation(Fcb, 359 SystemBuffer, 360 &BufferLength); 361 break; 362 363 case FileNetworkOpenInformation: 364 Status = NtfsGetNetworkOpenInformation(Fcb, 365 DeviceObject->DeviceExtension, 366 SystemBuffer, 367 &BufferLength); 368 break; 369 370 case FileStreamInformation: 371 Status = NtfsGetSteamInformation(Fcb, 372 DeviceObject->DeviceExtension, 373 SystemBuffer, 374 &BufferLength); 375 break; 376 377 case FileAlternateNameInformation: 378 case FileAllInformation: 379 DPRINT1("Unimplemented information class %u\n", FileInformationClass); 380 Status = STATUS_NOT_IMPLEMENTED; 381 break; 382 383 default: 384 DPRINT1("Unimplemented information class %u\n", FileInformationClass); 385 Status = STATUS_INVALID_PARAMETER; 386 } 387 388 ExReleaseResourceLite(&Fcb->MainResource); 389 390 if (NT_SUCCESS(Status)) 391 Irp->IoStatus.Information = 392 Stack->Parameters.QueryFile.Length - BufferLength; 393 else 394 Irp->IoStatus.Information = 0; 395 396 return Status; 397 } 398 399 /* EOF */ 400