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 #if 0
00038 static NTSTATUS
00039 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
00040          PVOID *Context,
00041          PVOID *Block,
00042          PLARGE_INTEGER StreamOffset,
00043          ULONG DirLength,
00044          PVOID *Ptr,
00045          PWSTR Name,
00046          PULONG pIndex,
00047          PULONG pIndex2)
00048 /*
00049  * FUNCTION: Retrieves the file name, be it in short or long file name format
00050  */
00051 {
00052   PDIR_RECORD Record;
00053   NTSTATUS Status;
00054   ULONG Index = 0;
00055   ULONG Offset = 0;
00056   ULONG BlockOffset = 0;
00057 
00058   Record = (PDIR_RECORD)*Block;
00059   while(Index < *pIndex)
00060     {
00061       BlockOffset += Record->RecordLength;
00062       Offset += Record->RecordLength;
00063 
00064       Record = (PDIR_RECORD)(*Block + BlockOffset);
00065       if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
00066     {
00067       DPRINT("Map next sector\n");
00068       CcUnpinData(*Context);
00069       StreamOffset->QuadPart += BLOCKSIZE;
00070       Offset = ROUND_UP(Offset, BLOCKSIZE);
00071       BlockOffset = 0;
00072 
00073       if (!CcMapData(DeviceExt->StreamFileObject,
00074              StreamOffset,
00075              BLOCKSIZE, TRUE,
00076              Context, Block))
00077         {
00078           DPRINT("CcMapData() failed\n");
00079           return(STATUS_UNSUCCESSFUL);
00080         }
00081       Record = (PDIR_RECORD)(*Block + BlockOffset);
00082     }
00083 
00084       if (Offset >= DirLength)
00085     return(STATUS_NO_MORE_ENTRIES);
00086 
00087       Index++;
00088     }
00089 
00090   DPRINT("Index %lu  RecordLength %lu  Offset %lu\n",
00091      Index, Record->RecordLength, Offset);
00092 
00093   if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
00094     {
00095       wcscpy(Name, L".");
00096     }
00097   else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
00098     {
00099       wcscpy(Name, L"..");
00100     }
00101   else
00102     {
00103       if (DeviceExt->CdInfo.JolietLevel == 0)
00104     {
00105       ULONG i;
00106 
00107       for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
00108         Name[i] = (WCHAR)Record->FileId[i];
00109       Name[i] = 0;
00110     }
00111       else
00112     {
00113       CdfsSwapString(Name, Record->FileId, Record->FileIdLength);
00114     }
00115     }
00116 
00117   DPRINT("Name '%S'\n", Name);
00118 
00119   *Ptr = Record;
00120 
00121   *pIndex = Index;
00122 
00123   return(STATUS_SUCCESS);
00124 }
00125 #endif
00126 
00127 
00128 static NTSTATUS
00129 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
00130                        PFILE_RECORD_HEADER FileRecord,
00131                        PNTFS_ATTR_CONTEXT DataContext,
00132                        PFILE_NAMES_INFORMATION Info,
00133                        ULONG BufferLength)
00134 {
00135     ULONG Length;
00136     PFILENAME_ATTRIBUTE FileName;
00137 
00138     DPRINT("NtfsGetNameInformation() called\n");
00139 
00140     FileName = GetBestFileNameFromRecord(FileRecord);
00141     ASSERT(FileName != NULL);
00142 
00143     Length = FileName->NameLength * sizeof (WCHAR);
00144     if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
00145         return(STATUS_BUFFER_OVERFLOW);
00146 
00147     Info->FileNameLength = Length;
00148     Info->NextEntryOffset =
00149         ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
00150     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00151 
00152     return(STATUS_SUCCESS);
00153 }
00154 
00155 
00156 static NTSTATUS
00157 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00158                             PFILE_RECORD_HEADER FileRecord,
00159                             PNTFS_ATTR_CONTEXT DataContext,
00160                             PFILE_DIRECTORY_INFORMATION Info,
00161                             ULONG BufferLength)
00162 {
00163     ULONG Length;
00164     PFILENAME_ATTRIBUTE FileName;
00165 
00166     DPRINT("NtfsGetDirectoryInformation() called\n");
00167 
00168     FileName = GetBestFileNameFromRecord(FileRecord);
00169     ASSERT(FileName != NULL);
00170 
00171     Length = FileName->NameLength * sizeof (WCHAR);
00172     if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
00173         return(STATUS_BUFFER_OVERFLOW);
00174 
00175     Info->FileNameLength = Length;
00176     Info->NextEntryOffset =
00177         ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00178     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00179 
00180     Info->CreationTime.QuadPart = FileName->CreationTime;
00181     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00182     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00183     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00184 
00185     /* Convert file flags */
00186     NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
00187 
00188     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00189     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00190 
00191 //  Info->FileIndex=;
00192 
00193     return STATUS_SUCCESS;
00194 }
00195 
00196 
00197 static NTSTATUS
00198 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00199                                 PFILE_RECORD_HEADER FileRecord,
00200                                 PNTFS_ATTR_CONTEXT DataContext,
00201                                 PFILE_FULL_DIRECTORY_INFORMATION Info,
00202                                 ULONG BufferLength)
00203 {
00204     ULONG Length;
00205     PFILENAME_ATTRIBUTE FileName;
00206 
00207     DPRINT("NtfsGetFullDirectoryInformation() called\n");
00208 
00209     FileName = GetBestFileNameFromRecord(FileRecord);
00210     ASSERT(FileName != NULL);
00211 
00212     Length = FileName->NameLength * sizeof (WCHAR);
00213     if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
00214         return(STATUS_BUFFER_OVERFLOW);
00215 
00216     Info->FileNameLength = Length;
00217     Info->NextEntryOffset =
00218         ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
00219     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00220 
00221     Info->CreationTime.QuadPart = FileName->CreationTime;
00222     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00223     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00224     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00225 
00226     /* Convert file flags */
00227     NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
00228 
00229     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00230     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00231 
00232 //  Info->FileIndex=;
00233     Info->EaSize = 0;
00234 
00235     return STATUS_SUCCESS;
00236 }
00237 
00238 
00239 static NTSTATUS
00240 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
00241                                 PFILE_RECORD_HEADER FileRecord,
00242                                 PNTFS_ATTR_CONTEXT DataContext,
00243                                 PFILE_BOTH_DIR_INFORMATION Info,
00244                                 ULONG BufferLength)
00245 {
00246     ULONG Length;
00247     PFILENAME_ATTRIBUTE FileName, ShortFileName;
00248 
00249     DPRINT("NtfsGetBothDirectoryInformation() called\n");
00250 
00251     FileName = GetBestFileNameFromRecord(FileRecord);
00252     ASSERT(FileName != NULL);
00253     ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
00254 
00255     Length = FileName->NameLength * sizeof (WCHAR);
00256     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
00257         return(STATUS_BUFFER_OVERFLOW);
00258 
00259     Info->FileNameLength = Length;
00260     Info->NextEntryOffset =
00261         ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
00262     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00263 
00264     if (ShortFileName)
00265     {
00266         /* Should we upcase the filename? */
00267         ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
00268         Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
00269         RtlCopyMemory(Info->ShortName, ShortFileName->Name, Info->ShortNameLength);
00270     }
00271     else
00272     {
00273         Info->ShortName[0] = 0;
00274         Info->ShortNameLength = 0;
00275     }
00276 
00277     Info->CreationTime.QuadPart = FileName->CreationTime;
00278     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00279     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00280     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00281 
00282     /* Convert file flags */
00283     NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
00284 
00285     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00286     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00287 
00288 //  Info->FileIndex=;
00289     Info->EaSize = 0;
00290 
00291     return STATUS_SUCCESS;
00292 }
00293 
00294 
00295 NTSTATUS
00296 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
00297 {
00298     PIRP Irp;
00299     PDEVICE_OBJECT DeviceObject;
00300     PDEVICE_EXTENSION DeviceExtension;
00301     LONG BufferLength = 0;
00302     PUNICODE_STRING SearchPattern = NULL;
00303     FILE_INFORMATION_CLASS FileInformationClass;
00304     ULONG FileIndex = 0;
00305     PUCHAR Buffer = NULL;
00306     PFILE_NAMES_INFORMATION Buffer0 = NULL;
00307     PNTFS_FCB Fcb;
00308     PNTFS_CCB Ccb;
00309     BOOLEAN First = FALSE;
00310     PIO_STACK_LOCATION Stack;
00311     PFILE_OBJECT FileObject;
00312     NTSTATUS Status = STATUS_SUCCESS;
00313     PFILE_RECORD_HEADER FileRecord;
00314     PNTFS_ATTR_CONTEXT DataContext;
00315     ULONGLONG MFTRecord, OldMFTRecord = 0;
00316     UNICODE_STRING Pattern;
00317 
00318     DPRINT1("NtfsQueryDirectory() called\n");
00319 
00320     ASSERT(IrpContext);
00321     Irp = IrpContext->Irp;
00322     DeviceObject = IrpContext->DeviceObject;
00323 
00324     DeviceExtension = DeviceObject->DeviceExtension;
00325     Stack = IoGetCurrentIrpStackLocation(Irp);
00326     FileObject = Stack->FileObject;
00327 
00328     Ccb = (PNTFS_CCB)FileObject->FsContext2;
00329     Fcb = (PNTFS_FCB)FileObject->FsContext;
00330 
00331     /* Obtain the callers parameters */
00332     BufferLength = Stack->Parameters.QueryDirectory.Length;
00333     SearchPattern = Stack->Parameters.QueryDirectory.FileName;
00334     FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
00335     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
00336 
00337     if (SearchPattern != NULL)
00338     {
00339         if (!Ccb->DirectorySearchPattern)
00340         {
00341             First = TRUE;
00342             Pattern.Length = 0;
00343             Pattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
00344             Ccb->DirectorySearchPattern = Pattern.Buffer =
00345                 ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
00346             if (!Ccb->DirectorySearchPattern)
00347             {
00348                 return STATUS_INSUFFICIENT_RESOURCES;
00349             }
00350 
00351             memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
00352             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
00353         }
00354     }
00355     else if (!Ccb->DirectorySearchPattern)
00356     {
00357         First = TRUE;
00358         Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
00359         if (!Ccb->DirectorySearchPattern)
00360         {
00361             return STATUS_INSUFFICIENT_RESOURCES;
00362         }
00363 
00364         Ccb->DirectorySearchPattern[0] = L'*';
00365         Ccb->DirectorySearchPattern[1] = 0;
00366     }
00367 
00368     RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
00369     DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
00370     DPRINT("In: '%S'\n", Fcb->PathName);
00371 
00372     /* Determine directory index */
00373     if (Stack->Flags & SL_INDEX_SPECIFIED)
00374     {
00375         Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
00376     }
00377     else if (First || (Stack->Flags & SL_RESTART_SCAN))
00378     {
00379         Ccb->Entry = 0;
00380     }
00381 
00382     /* Determine Buffer for result */
00383     if (Irp->MdlAddress)
00384     {
00385         Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
00386     }
00387     else
00388     {
00389         Buffer = Irp->UserBuffer;
00390     }
00391 
00392     DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
00393 
00394     while (Status == STATUS_SUCCESS && BufferLength > 0)
00395     {
00396         Status = NtfsFindFileAt(DeviceExtension,
00397                                 &Pattern,
00398                                 &Ccb->Entry,
00399                                 &FileRecord,
00400                                 &DataContext,
00401                                 &MFTRecord,
00402                                 Fcb->MFTIndex);
00403 
00404         if (NT_SUCCESS(Status))
00405         {
00406             /* HACK: files with both a short name and a long name are present twice in the index.
00407              * Ignore the second entry, if it is immediately following the first one.
00408              */
00409             if (MFTRecord == OldMFTRecord)
00410             {
00411                 DPRINT("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
00412                 Ccb->Entry++;
00413                 ExFreePoolWithTag(FileRecord, TAG_NTFS);
00414                 continue;
00415             }
00416             OldMFTRecord = MFTRecord;
00417 
00418             switch (FileInformationClass)
00419             {
00420                 case FileNameInformation:
00421                     Status = NtfsGetNameInformation(DeviceExtension,
00422                                                     FileRecord,
00423                                                     DataContext,
00424                                                     (PFILE_NAMES_INFORMATION)Buffer,
00425                                                     BufferLength);
00426                     break;
00427 
00428                 case FileDirectoryInformation:
00429                     Status = NtfsGetDirectoryInformation(DeviceExtension,
00430                                                          FileRecord,
00431                                                          DataContext,
00432                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
00433                                                          BufferLength);
00434                     break;
00435 
00436                 case FileFullDirectoryInformation:
00437                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
00438                                                              FileRecord,
00439                                                              DataContext,
00440                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
00441                                                              BufferLength);
00442                     break;
00443 
00444                 case FileBothDirectoryInformation:
00445                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
00446                                                              FileRecord,
00447                                                              DataContext,
00448                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
00449                                                              BufferLength);
00450                     break;
00451 
00452                 default:
00453                     Status = STATUS_INVALID_INFO_CLASS;
00454             }
00455 
00456             if (Status == STATUS_BUFFER_OVERFLOW)
00457             {
00458                 if (Buffer0)
00459                 {
00460                     Buffer0->NextEntryOffset = 0;
00461                 }
00462                 break;
00463             }
00464         }
00465         else
00466         {
00467             if (Buffer0)
00468             {
00469                 Buffer0->NextEntryOffset = 0;
00470             }
00471 
00472             if (First)
00473             {
00474                 Status = STATUS_NO_SUCH_FILE;
00475             }
00476             else
00477             {
00478                 Status = STATUS_NO_MORE_FILES;
00479             }
00480             break;
00481         }
00482 
00483         Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
00484         Buffer0->FileIndex = FileIndex++;
00485         Ccb->Entry++;
00486 
00487         if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
00488         {
00489             break;
00490         }
00491         BufferLength -= Buffer0->NextEntryOffset;
00492         Buffer += Buffer0->NextEntryOffset;
00493         ExFreePoolWithTag(FileRecord, TAG_NTFS);
00494     }
00495 
00496     if (Buffer0)
00497     {
00498         Buffer0->NextEntryOffset = 0;
00499     }
00500 
00501     if (FileIndex > 0)
00502     {
00503         Status = STATUS_SUCCESS;
00504     }
00505 
00506     return Status;
00507 }
00508 
00509 
00510 NTSTATUS
00511 NTAPI
00512 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
00513                         PIRP Irp)
00514 {
00515     PNTFS_IRP_CONTEXT IrpContext = NULL;
00516     NTSTATUS Status = STATUS_UNSUCCESSFUL;
00517 
00518     DPRINT1("NtfsDirectoryControl() called\n");
00519 
00520     FsRtlEnterFileSystem();
00521     ASSERT(DeviceObject);
00522     ASSERT(Irp);
00523 
00524     NtfsIsIrpTopLevel(Irp);
00525 
00526     IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
00527     if (IrpContext)
00528     {
00529         switch (IrpContext->MinorFunction)
00530         {
00531             case IRP_MN_QUERY_DIRECTORY:
00532                 Status = NtfsQueryDirectory(IrpContext);
00533                 break;
00534 
00535             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
00536                 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
00537                 Status = STATUS_NOT_IMPLEMENTED;
00538                 break;
00539 
00540             default:
00541                 Status = STATUS_INVALID_DEVICE_REQUEST;
00542                 break;
00543         }
00544     }
00545     else
00546         Status = STATUS_INSUFFICIENT_RESOURCES;
00547 
00548     Irp->IoStatus.Status = Status;
00549     Irp->IoStatus.Information = 0;
00550     IoCompleteRequest(Irp, IO_NO_INCREMENT);
00551 
00552     if (IrpContext)
00553         ExFreePoolWithTag(IrpContext, 'PRIN');
00554 
00555     IoSetTopLevelIrp(NULL);
00556     FsRtlExitFileSystem();
00557     return Status;
00558 }
00559 
00560 /* EOF */