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 NTSTATUS
00039 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
00040                        PFILE_RECORD_HEADER FileRecord,
00041                        PNTFS_ATTR_CONTEXT DataContext,
00042                        PFILE_NAMES_INFORMATION Info,
00043                        ULONG BufferLength)
00044 {
00045     ULONG Length;
00046     PFILENAME_ATTRIBUTE FileName;
00047 
00048     DPRINT("NtfsGetNameInformation() called\n");
00049 
00050     FileName = GetBestFileNameFromRecord(FileRecord);
00051     ASSERT(FileName != NULL);
00052 
00053     Length = FileName->NameLength * sizeof (WCHAR);
00054     if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
00055         return(STATUS_BUFFER_OVERFLOW);
00056 
00057     Info->FileNameLength = Length;
00058     Info->NextEntryOffset =
00059         ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
00060     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00061 
00062     return(STATUS_SUCCESS);
00063 }
00064 
00065 
00066 static NTSTATUS
00067 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00068                             PFILE_RECORD_HEADER FileRecord,
00069                             PNTFS_ATTR_CONTEXT DataContext,
00070                             ULONGLONG MFTIndex,
00071                             PFILE_DIRECTORY_INFORMATION Info,
00072                             ULONG BufferLength)
00073 {
00074     ULONG Length;
00075     PFILENAME_ATTRIBUTE FileName;
00076     PSTANDARD_INFORMATION StdInfo;
00077 
00078     DPRINT("NtfsGetDirectoryInformation() called\n");
00079 
00080     FileName = GetBestFileNameFromRecord(FileRecord);
00081     ASSERT(FileName != NULL);
00082 
00083     StdInfo = GetStandardInformationFromRecord(FileRecord);
00084     ASSERT(StdInfo != NULL);
00085 
00086     Length = FileName->NameLength * sizeof (WCHAR);
00087     if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
00088         return(STATUS_BUFFER_OVERFLOW);
00089 
00090     Info->FileNameLength = Length;
00091     Info->NextEntryOffset =
00092         ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00093     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00094 
00095     Info->CreationTime.QuadPart = FileName->CreationTime;
00096     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00097     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00098     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00099 
00100     /* Convert file flags */
00101     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00102 
00103     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00104     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00105 
00106     Info->FileIndex = MFTIndex;
00107 
00108     return STATUS_SUCCESS;
00109 }
00110 
00111 
00112 static NTSTATUS
00113 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00114                                 PFILE_RECORD_HEADER FileRecord,
00115                                 PNTFS_ATTR_CONTEXT DataContext,
00116                                 ULONGLONG MFTIndex,
00117                                 PFILE_FULL_DIRECTORY_INFORMATION Info,
00118                                 ULONG BufferLength)
00119 {
00120     ULONG Length;
00121     PFILENAME_ATTRIBUTE FileName;
00122     PSTANDARD_INFORMATION StdInfo;
00123 
00124     DPRINT("NtfsGetFullDirectoryInformation() called\n");
00125 
00126     FileName = GetBestFileNameFromRecord(FileRecord);
00127     ASSERT(FileName != NULL);
00128 
00129     StdInfo = GetStandardInformationFromRecord(FileRecord);
00130     ASSERT(StdInfo != NULL);
00131 
00132     Length = FileName->NameLength * sizeof (WCHAR);
00133     if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
00134         return(STATUS_BUFFER_OVERFLOW);
00135 
00136     Info->FileNameLength = Length;
00137     Info->NextEntryOffset =
00138         ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00139     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00140 
00141     Info->CreationTime.QuadPart = FileName->CreationTime;
00142     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00143     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00144     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00145 
00146     /* Convert file flags */
00147     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00148 
00149     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00150     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00151 
00152     Info->FileIndex = MFTIndex;
00153     Info->EaSize = 0;
00154 
00155     return STATUS_SUCCESS;
00156 }
00157 
00158 
00159 static NTSTATUS
00160 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00161                                 PFILE_RECORD_HEADER FileRecord,
00162                                 PNTFS_ATTR_CONTEXT DataContext,
00163                                 ULONGLONG MFTIndex,
00164                                 PFILE_BOTH_DIR_INFORMATION Info,
00165                                 ULONG BufferLength)
00166 {
00167     ULONG Length;
00168     PFILENAME_ATTRIBUTE FileName, ShortFileName;
00169     PSTANDARD_INFORMATION StdInfo;
00170 
00171     DPRINT("NtfsGetBothDirectoryInformation() called\n");
00172 
00173     FileName = GetBestFileNameFromRecord(FileRecord);
00174     ASSERT(FileName != NULL);
00175     ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
00176 
00177     StdInfo = GetStandardInformationFromRecord(FileRecord);
00178     ASSERT(StdInfo != NULL);
00179 
00180     Length = FileName->NameLength * sizeof (WCHAR);
00181     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
00182         return(STATUS_BUFFER_OVERFLOW);
00183 
00184     Info->FileNameLength = Length;
00185     Info->NextEntryOffset =
00186         ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
00187     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00188 
00189     if (ShortFileName)
00190     {
00191         /* Should we upcase the filename? */
00192         ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
00193         Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
00194         RtlCopyMemory(Info->ShortName, ShortFileName->Name, Info->ShortNameLength);
00195     }
00196     else
00197     {
00198         Info->ShortName[0] = 0;
00199         Info->ShortNameLength = 0;
00200     }
00201 
00202     Info->CreationTime.QuadPart = FileName->CreationTime;
00203     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00204     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00205     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00206 
00207     /* Convert file flags */
00208     NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
00209 
00210     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00211     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00212 
00213     Info->FileIndex = MFTIndex;
00214     Info->EaSize = 0;
00215 
00216     return STATUS_SUCCESS;
00217 }
00218 
00219 
00220 NTSTATUS
00221 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
00222 {
00223     PIRP Irp;
00224     PDEVICE_OBJECT DeviceObject;
00225     PDEVICE_EXTENSION DeviceExtension;
00226     LONG BufferLength = 0;
00227     PUNICODE_STRING SearchPattern = NULL;
00228     FILE_INFORMATION_CLASS FileInformationClass;
00229     ULONG FileIndex = 0;
00230     PUCHAR Buffer = NULL;
00231     PFILE_NAMES_INFORMATION Buffer0 = NULL;
00232     PNTFS_FCB Fcb;
00233     PNTFS_CCB Ccb;
00234     BOOLEAN First = FALSE;
00235     PIO_STACK_LOCATION Stack;
00236     PFILE_OBJECT FileObject;
00237     NTSTATUS Status = STATUS_SUCCESS;
00238     PFILE_RECORD_HEADER FileRecord;
00239     PNTFS_ATTR_CONTEXT DataContext;
00240     ULONGLONG MFTRecord, OldMFTRecord = 0;
00241     UNICODE_STRING Pattern;
00242 
00243     DPRINT1("NtfsQueryDirectory() called\n");
00244 
00245     ASSERT(IrpContext);
00246     Irp = IrpContext->Irp;
00247     DeviceObject = IrpContext->DeviceObject;
00248 
00249     DeviceExtension = DeviceObject->DeviceExtension;
00250     Stack = IoGetCurrentIrpStackLocation(Irp);
00251     FileObject = Stack->FileObject;
00252 
00253     Ccb = (PNTFS_CCB)FileObject->FsContext2;
00254     Fcb = (PNTFS_FCB)FileObject->FsContext;
00255 
00256     /* Obtain the callers parameters */
00257     BufferLength = Stack->Parameters.QueryDirectory.Length;
00258     SearchPattern = Stack->Parameters.QueryDirectory.FileName;
00259     FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
00260     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
00261 
00262     if (SearchPattern != NULL)
00263     {
00264         if (!Ccb->DirectorySearchPattern)
00265         {
00266             First = TRUE;
00267             Pattern.Length = 0;
00268             Pattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
00269             Ccb->DirectorySearchPattern = Pattern.Buffer =
00270                 ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
00271             if (!Ccb->DirectorySearchPattern)
00272             {
00273                 return STATUS_INSUFFICIENT_RESOURCES;
00274             }
00275 
00276             memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
00277             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
00278         }
00279     }
00280     else if (!Ccb->DirectorySearchPattern)
00281     {
00282         First = TRUE;
00283         Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
00284         if (!Ccb->DirectorySearchPattern)
00285         {
00286             return STATUS_INSUFFICIENT_RESOURCES;
00287         }
00288 
00289         Ccb->DirectorySearchPattern[0] = L'*';
00290         Ccb->DirectorySearchPattern[1] = 0;
00291     }
00292 
00293     RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
00294     DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
00295     DPRINT("In: '%S'\n", Fcb->PathName);
00296 
00297     /* Determine directory index */
00298     if (Stack->Flags & SL_INDEX_SPECIFIED)
00299     {
00300         Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
00301     }
00302     else if (First || (Stack->Flags & SL_RESTART_SCAN))
00303     {
00304         Ccb->Entry = 0;
00305     }
00306 
00307     /* Get Buffer for result */
00308     Buffer = NtfsGetUserBuffer(Irp, FALSE);
00309 
00310     DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
00311 
00312     while (Status == STATUS_SUCCESS && BufferLength > 0)
00313     {
00314         Status = NtfsFindFileAt(DeviceExtension,
00315                                 &Pattern,
00316                                 &Ccb->Entry,
00317                                 &FileRecord,
00318                                 &DataContext,
00319                                 &MFTRecord,
00320                                 Fcb->MFTIndex);
00321 
00322         if (NT_SUCCESS(Status))
00323         {
00324             /* HACK: files with both a short name and a long name are present twice in the index.
00325              * Ignore the second entry, if it is immediately following the first one.
00326              */
00327             if (MFTRecord == OldMFTRecord)
00328             {
00329                 DPRINT("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
00330                 Ccb->Entry++;
00331                 ExFreePoolWithTag(FileRecord, TAG_NTFS);
00332                 continue;
00333             }
00334             OldMFTRecord = MFTRecord;
00335 
00336             switch (FileInformationClass)
00337             {
00338                 case FileNameInformation:
00339                     Status = NtfsGetNameInformation(DeviceExtension,
00340                                                     FileRecord,
00341                                                     DataContext,
00342                                                     (PFILE_NAMES_INFORMATION)Buffer,
00343                                                     BufferLength);
00344                     break;
00345 
00346                 case FileDirectoryInformation:
00347                     Status = NtfsGetDirectoryInformation(DeviceExtension,
00348                                                          FileRecord,
00349                                                          DataContext,
00350                                                          MFTRecord,
00351                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
00352                                                          BufferLength);
00353                     break;
00354 
00355                 case FileFullDirectoryInformation:
00356                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
00357                                                              FileRecord,
00358                                                              DataContext,
00359                                                              MFTRecord,
00360                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
00361                                                              BufferLength);
00362                     break;
00363 
00364                 case FileBothDirectoryInformation:
00365                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
00366                                                              FileRecord,
00367                                                              DataContext,
00368                                                              MFTRecord,
00369                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
00370                                                              BufferLength);
00371                     break;
00372 
00373                 default:
00374                     Status = STATUS_INVALID_INFO_CLASS;
00375             }
00376 
00377             if (Status == STATUS_BUFFER_OVERFLOW)
00378             {
00379                 if (Buffer0)
00380                 {
00381                     Buffer0->NextEntryOffset = 0;
00382                 }
00383                 break;
00384             }
00385         }
00386         else
00387         {
00388             if (Buffer0)
00389             {
00390                 Buffer0->NextEntryOffset = 0;
00391             }
00392 
00393             if (First)
00394             {
00395                 Status = STATUS_NO_SUCH_FILE;
00396             }
00397             else
00398             {
00399                 Status = STATUS_NO_MORE_FILES;
00400             }
00401             break;
00402         }
00403 
00404         Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
00405         Buffer0->FileIndex = FileIndex++;
00406         Ccb->Entry++;
00407 
00408         if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
00409         {
00410             break;
00411         }
00412         BufferLength -= Buffer0->NextEntryOffset;
00413         Buffer += Buffer0->NextEntryOffset;
00414         ExFreePoolWithTag(FileRecord, TAG_NTFS);
00415     }
00416 
00417     if (Buffer0)
00418     {
00419         Buffer0->NextEntryOffset = 0;
00420     }
00421 
00422     if (FileIndex > 0)
00423     {
00424         Status = STATUS_SUCCESS;
00425     }
00426 
00427     return Status;
00428 }
00429 
00430 
00431 NTSTATUS
00432 NtfsDirectoryControl(PNTFS_IRP_CONTEXT IrpContext)
00433 {
00434     NTSTATUS Status = STATUS_UNSUCCESSFUL;
00435 
00436     DPRINT1("NtfsDirectoryControl() called\n");
00437 
00438     switch (IrpContext->MinorFunction)
00439     {
00440         case IRP_MN_QUERY_DIRECTORY:
00441             Status = NtfsQueryDirectory(IrpContext);
00442             break;
00443 
00444         case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
00445             DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
00446             Status = STATUS_NOT_IMPLEMENTED;
00447             break;
00448 
00449         default:
00450             Status = STATUS_INVALID_DEVICE_REQUEST;
00451             break;
00452     }
00453 
00454     IrpContext->Irp->IoStatus.Information = 0;
00455 
00456     return Status;
00457 }
00458 
00459 /* EOF */