Doxygen

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