Doxygen

dirctl.c
Go to the documentation of this file.
00001 /*
00002  *  ReactOS kernel
00003  *  Copyright (C) 2002, 2003, 2014 ReactOS Team
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * COPYRIGHT:        See COPYING in the top level directory
00020  * PROJECT:          ReactOS kernel
00021  * FILE:             drivers/filesystem/ntfs/dirctl.c
00022  * PURPOSE:          NTFS filesystem driver
00023  * PROGRAMMERS:      Eric Kohl
00024  *                   Pierre Schweitzer (pierre@reactos.org)
00025  *                   Hervé Poussineau (hpoussin@reactos.org)
00026  */
00027 
00028 /* INCLUDES *****************************************************************/
00029 
00030 #include "ntfs.h"
00031 
00032 #define NDEBUG
00033 #include <debug.h>
00034 
00035 /* FUNCTIONS ****************************************************************/
00036 
00037 
00038 static ULONGLONG
00039 NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
00040                 PFILE_RECORD_HEADER FileRecord,
00041                 PFILENAME_ATTRIBUTE FileName)
00042 {
00043     ULONGLONG Size;
00044     NTSTATUS Status;
00045     PNTFS_ATTR_CONTEXT DataContext;
00046 
00047     Size = FileName->AllocatedSize;
00048     Status = FindAttribute(DeviceExt, FileRecord, AttributeData, L"", 0, &DataContext);
00049     if (NT_SUCCESS(Status))
00050     {
00051         Size = AttributeDataLength(&DataContext->Record);
00052         ReleaseAttributeContext(DataContext);
00053     }
00054 
00055     return Size;
00056 }
00057 
00058 
00059 static NTSTATUS
00060 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
00061                        PFILE_RECORD_HEADER FileRecord,
00062                        ULONGLONG MFTIndex,
00063                        PFILE_NAMES_INFORMATION Info,
00064                        ULONG BufferLength)
00065 {
00066     ULONG Length;
00067     PFILENAME_ATTRIBUTE FileName;
00068 
00069     DPRINT("NtfsGetNameInformation() called\n");
00070 
00071     FileName = GetBestFileNameFromRecord(FileRecord);
00072     if (FileName == NULL)
00073     {
00074         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
00075         NtfsDumpFileAttributes(DeviceExt, FileRecord);
00076         return STATUS_OBJECT_NAME_NOT_FOUND;
00077     }
00078 
00079     Length = FileName->NameLength * sizeof (WCHAR);
00080     if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
00081         return(STATUS_BUFFER_OVERFLOW);
00082 
00083     Info->FileNameLength = Length;
00084     Info->NextEntryOffset =
00085         ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
00086     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00087 
00088     return(STATUS_SUCCESS);
00089 }
00090 
00091 
00092 static NTSTATUS
00093 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00094                             PFILE_RECORD_HEADER FileRecord,
00095                             ULONGLONG MFTIndex,
00096                             PFILE_DIRECTORY_INFORMATION Info,
00097                             ULONG BufferLength)
00098 {
00099     ULONG Length;
00100     PFILENAME_ATTRIBUTE FileName;
00101     PSTANDARD_INFORMATION StdInfo;
00102 
00103     DPRINT("NtfsGetDirectoryInformation() called\n");
00104 
00105     FileName = GetBestFileNameFromRecord(FileRecord);
00106     if (FileName == NULL)
00107     {
00108         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
00109         NtfsDumpFileAttributes(DeviceExt, FileRecord);
00110         return STATUS_OBJECT_NAME_NOT_FOUND;
00111     }
00112 
00113     StdInfo = GetStandardInformationFromRecord(FileRecord);
00114     ASSERT(StdInfo != NULL);
00115 
00116     Length = FileName->NameLength * sizeof (WCHAR);
00117     if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
00118         return(STATUS_BUFFER_OVERFLOW);
00119 
00120     Info->FileNameLength = Length;
00121     Info->NextEntryOffset =
00122         ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00123     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00124 
00125     Info->CreationTime.QuadPart = FileName->CreationTime;
00126     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00127     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00128     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00129 
00130     /* Convert file flags */
00131     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00132 
00133     Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, FileName);
00134     Info->AllocationSize.QuadPart = ROUND_UP(Info->EndOfFile.QuadPart, DeviceExt->NtfsInfo.BytesPerCluster);
00135 
00136     Info->FileIndex = MFTIndex;
00137 
00138     return STATUS_SUCCESS;
00139 }
00140 
00141 
00142 static NTSTATUS
00143 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00144                                 PFILE_RECORD_HEADER FileRecord,
00145                                 ULONGLONG MFTIndex,
00146                                 PFILE_FULL_DIRECTORY_INFORMATION Info,
00147                                 ULONG BufferLength)
00148 {
00149     ULONG Length;
00150     PFILENAME_ATTRIBUTE FileName;
00151     PSTANDARD_INFORMATION StdInfo;
00152 
00153     DPRINT("NtfsGetFullDirectoryInformation() called\n");
00154 
00155     FileName = GetBestFileNameFromRecord(FileRecord);
00156     if (FileName == NULL)
00157     {
00158         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
00159         NtfsDumpFileAttributes(DeviceExt, FileRecord);
00160         return STATUS_OBJECT_NAME_NOT_FOUND;
00161     }
00162 
00163     StdInfo = GetStandardInformationFromRecord(FileRecord);
00164     ASSERT(StdInfo != NULL);
00165 
00166     Length = FileName->NameLength * sizeof (WCHAR);
00167     if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
00168         return(STATUS_BUFFER_OVERFLOW);
00169 
00170     Info->FileNameLength = Length;
00171     Info->NextEntryOffset =
00172         ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00173     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00174 
00175     Info->CreationTime.QuadPart = FileName->CreationTime;
00176     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00177     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00178     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00179 
00180     /* Convert file flags */
00181     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00182 
00183     Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, FileName);
00184     Info->AllocationSize.QuadPart = ROUND_UP(Info->EndOfFile.QuadPart, DeviceExt->NtfsInfo.BytesPerCluster);
00185 
00186     Info->FileIndex = MFTIndex;
00187     Info->EaSize = 0;
00188 
00189     return STATUS_SUCCESS;
00190 }
00191 
00192 
00193 static NTSTATUS
00194 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00195                                 PFILE_RECORD_HEADER FileRecord,
00196                                 ULONGLONG MFTIndex,
00197                                 PFILE_BOTH_DIR_INFORMATION Info,
00198                                 ULONG BufferLength)
00199 {
00200     ULONG Length;
00201     PFILENAME_ATTRIBUTE FileName, ShortFileName;
00202     PSTANDARD_INFORMATION StdInfo;
00203 
00204     DPRINT("NtfsGetBothDirectoryInformation() called\n");
00205 
00206     FileName = GetBestFileNameFromRecord(FileRecord);
00207     if (FileName == NULL)
00208     {
00209         DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
00210         NtfsDumpFileAttributes(DeviceExt, FileRecord);
00211         return STATUS_OBJECT_NAME_NOT_FOUND;
00212     }
00213     ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
00214 
00215     StdInfo = GetStandardInformationFromRecord(FileRecord);
00216     ASSERT(StdInfo != NULL);
00217 
00218     Length = FileName->NameLength * sizeof (WCHAR);
00219     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
00220         return(STATUS_BUFFER_OVERFLOW);
00221 
00222     Info->FileNameLength = Length;
00223     Info->NextEntryOffset =
00224         ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
00225     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00226 
00227     if (ShortFileName)
00228     {
00229         /* Should we upcase the filename? */
00230         ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
00231         Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
00232         RtlCopyMemory(Info->ShortName, ShortFileName->Name, Info->ShortNameLength);
00233     }
00234     else
00235     {
00236         Info->ShortName[0] = 0;
00237         Info->ShortNameLength = 0;
00238     }
00239 
00240     Info->CreationTime.QuadPart = FileName->CreationTime;
00241     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00242     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00243     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00244 
00245     /* Convert file flags */
00246     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00247 
00248     Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, FileName);
00249     Info->AllocationSize.QuadPart = ROUND_UP(Info->EndOfFile.QuadPart, DeviceExt->NtfsInfo.BytesPerCluster);
00250 
00251     Info->FileIndex = MFTIndex;
00252     Info->EaSize = 0;
00253 
00254     return STATUS_SUCCESS;
00255 }
00256 
00257 
00258 NTSTATUS
00259 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
00260 {
00261     PIRP Irp;
00262     PDEVICE_OBJECT DeviceObject;
00263     PDEVICE_EXTENSION DeviceExtension;
00264     LONG BufferLength = 0;
00265     PUNICODE_STRING SearchPattern = NULL;
00266     FILE_INFORMATION_CLASS FileInformationClass;
00267     ULONG FileIndex = 0;
00268     PUCHAR Buffer = NULL;
00269     PFILE_NAMES_INFORMATION Buffer0 = NULL;
00270     PNTFS_FCB Fcb;
00271     PNTFS_CCB Ccb;
00272     BOOLEAN First = FALSE;
00273     PIO_STACK_LOCATION Stack;
00274     PFILE_OBJECT FileObject;
00275     NTSTATUS Status = STATUS_SUCCESS;
00276     PFILE_RECORD_HEADER FileRecord;
00277     ULONGLONG MFTRecord, OldMFTRecord = 0;
00278     UNICODE_STRING Pattern;
00279 
00280     DPRINT1("NtfsQueryDirectory() called\n");
00281 
00282     ASSERT(IrpContext);
00283     Irp = IrpContext->Irp;
00284     DeviceObject = IrpContext->DeviceObject;
00285 
00286     DeviceExtension = DeviceObject->DeviceExtension;
00287     Stack = IoGetCurrentIrpStackLocation(Irp);
00288     FileObject = Stack->FileObject;
00289 
00290     Ccb = (PNTFS_CCB)FileObject->FsContext2;
00291     Fcb = (PNTFS_FCB)FileObject->FsContext;
00292 
00293     /* Obtain the callers parameters */
00294     BufferLength = Stack->Parameters.QueryDirectory.Length;
00295     SearchPattern = Stack->Parameters.QueryDirectory.FileName;
00296     FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
00297     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
00298 
00299     if (SearchPattern != NULL)
00300     {
00301         if (!Ccb->DirectorySearchPattern)
00302         {
00303             First = TRUE;
00304             Pattern.Length = 0;
00305             Pattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
00306             Ccb->DirectorySearchPattern = Pattern.Buffer =
00307                 ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
00308             if (!Ccb->DirectorySearchPattern)
00309             {
00310                 return STATUS_INSUFFICIENT_RESOURCES;
00311             }
00312 
00313             memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
00314             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
00315         }
00316     }
00317     else if (!Ccb->DirectorySearchPattern)
00318     {
00319         First = TRUE;
00320         Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
00321         if (!Ccb->DirectorySearchPattern)
00322         {
00323             return STATUS_INSUFFICIENT_RESOURCES;
00324         }
00325 
00326         Ccb->DirectorySearchPattern[0] = L'*';
00327         Ccb->DirectorySearchPattern[1] = 0;
00328     }
00329 
00330     RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
00331     DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
00332     DPRINT("In: '%S'\n", Fcb->PathName);
00333 
00334     /* Determine directory index */
00335     if (Stack->Flags & SL_INDEX_SPECIFIED)
00336     {
00337         Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
00338     }
00339     else if (First || (Stack->Flags & SL_RESTART_SCAN))
00340     {
00341         Ccb->Entry = 0;
00342     }
00343 
00344     /* Get Buffer for result */
00345     Buffer = NtfsGetUserBuffer(Irp, FALSE);
00346 
00347     DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
00348 
00349     while (Status == STATUS_SUCCESS && BufferLength > 0)
00350     {
00351         Status = NtfsFindFileAt(DeviceExtension,
00352                                 &Pattern,
00353                                 &Ccb->Entry,
00354                                 &FileRecord,
00355                                 &MFTRecord,
00356                                 Fcb->MFTIndex);
00357 
00358         if (NT_SUCCESS(Status))
00359         {
00360             /* HACK: files with both a short name and a long name are present twice in the index.
00361              * Ignore the second entry, if it is immediately following the first one.
00362              */
00363             if (MFTRecord == OldMFTRecord)
00364             {
00365                 DPRINT("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
00366                 Ccb->Entry++;
00367                 ExFreePoolWithTag(FileRecord, TAG_NTFS);
00368                 continue;
00369             }
00370             OldMFTRecord = MFTRecord;
00371 
00372             switch (FileInformationClass)
00373             {
00374                 case FileNameInformation:
00375                     Status = NtfsGetNameInformation(DeviceExtension,
00376                                                     FileRecord,
00377                                                     MFTRecord,
00378                                                     (PFILE_NAMES_INFORMATION)Buffer,
00379                                                     BufferLength);
00380                     break;
00381 
00382                 case FileDirectoryInformation:
00383                     Status = NtfsGetDirectoryInformation(DeviceExtension,
00384                                                          FileRecord,
00385                                                          MFTRecord,
00386                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
00387                                                          BufferLength);
00388                     break;
00389 
00390                 case FileFullDirectoryInformation:
00391                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
00392                                                              FileRecord,
00393                                                              MFTRecord,
00394                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
00395                                                              BufferLength);
00396                     break;
00397 
00398                 case FileBothDirectoryInformation:
00399                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
00400                                                              FileRecord,
00401                                                              MFTRecord,
00402                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
00403                                                              BufferLength);
00404                     break;
00405 
00406                 default:
00407                     Status = STATUS_INVALID_INFO_CLASS;
00408             }
00409 
00410             if (Status == STATUS_BUFFER_OVERFLOW)
00411             {
00412                 if (Buffer0)
00413                 {
00414                     Buffer0->NextEntryOffset = 0;
00415                 }
00416                 break;
00417             }
00418         }
00419         else
00420         {
00421             if (Buffer0)
00422             {
00423                 Buffer0->NextEntryOffset = 0;
00424             }
00425 
00426             if (First)
00427             {
00428                 Status = STATUS_NO_SUCH_FILE;
00429             }
00430             else
00431             {
00432                 Status = STATUS_NO_MORE_FILES;
00433             }
00434             break;
00435         }
00436 
00437         Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
00438         Buffer0->FileIndex = FileIndex++;
00439         Ccb->Entry++;
00440 
00441         if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
00442         {
00443             break;
00444         }
00445         BufferLength -= Buffer0->NextEntryOffset;
00446         Buffer += Buffer0->NextEntryOffset;
00447         ExFreePoolWithTag(FileRecord, TAG_NTFS);
00448     }
00449 
00450     if (Buffer0)
00451     {
00452         Buffer0->NextEntryOffset = 0;
00453     }
00454 
00455     if (FileIndex > 0)
00456     {
00457         Status = STATUS_SUCCESS;
00458     }
00459 
00460     return Status;
00461 }
00462 
00463 
00464 NTSTATUS
00465 NtfsDirectoryControl(PNTFS_IRP_CONTEXT IrpContext)
00466 {
00467     NTSTATUS Status = STATUS_UNSUCCESSFUL;
00468 
00469     DPRINT1("NtfsDirectoryControl() called\n");
00470 
00471     switch (IrpContext->MinorFunction)
00472     {
00473         case IRP_MN_QUERY_DIRECTORY:
00474             Status = NtfsQueryDirectory(IrpContext);
00475             break;
00476 
00477         case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
00478             DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
00479             Status = STATUS_NOT_IMPLEMENTED;
00480             break;
00481 
00482         default:
00483             Status = STATUS_INVALID_DEVICE_REQUEST;
00484             break;
00485     }
00486 
00487     IrpContext->Irp->IoStatus.Information = 0;
00488 
00489     return Status;
00490 }
00491 
00492 /* EOF */