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);
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);
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);
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;
00246 
00247     DPRINT("NtfsGetBothDirectoryInformation() called\n");
00248 
00249     FileName = GetFileNameFromRecord(FileRecord);
00250     ASSERT(FileName != NULL);
00251 
00252     Length = FileName->NameLength * sizeof (WCHAR);
00253     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
00254         return(STATUS_BUFFER_OVERFLOW);
00255 
00256     Info->FileNameLength = Length;
00257     Info->NextEntryOffset =
00258         ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
00259     RtlCopyMemory(Info->FileName, FileName->Name, Length);
00260 
00261     Info->CreationTime.QuadPart = FileName->CreationTime;
00262     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
00263     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
00264     Info->ChangeTime.QuadPart = FileName->ChangeTime;
00265 
00266     /* Convert file flags */
00267     NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
00268 
00269     Info->EndOfFile.QuadPart = FileName->AllocatedSize;
00270     Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
00271 
00272 //  Info->FileIndex=;
00273     Info->EaSize = 0;
00274 
00275     Info->ShortName[0] = 0;
00276     Info->ShortNameLength = 0;
00277 
00278     return STATUS_SUCCESS;
00279 }
00280 
00281 
00282 NTSTATUS
00283 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
00284 {
00285     PIRP Irp;
00286     PDEVICE_OBJECT DeviceObject;
00287     PDEVICE_EXTENSION DeviceExtension;
00288     LONG BufferLength = 0;
00289     PUNICODE_STRING SearchPattern = NULL;
00290     FILE_INFORMATION_CLASS FileInformationClass;
00291     ULONG FileIndex = 0;
00292     PUCHAR Buffer = NULL;
00293     PFILE_NAMES_INFORMATION Buffer0 = NULL;
00294     PNTFS_FCB Fcb;
00295     PNTFS_CCB Ccb;
00296     BOOLEAN First = FALSE;
00297     PIO_STACK_LOCATION Stack;
00298     PFILE_OBJECT FileObject;
00299     NTSTATUS Status = STATUS_SUCCESS;
00300     PFILE_RECORD_HEADER FileRecord;
00301     PNTFS_ATTR_CONTEXT DataContext;
00302     ULONGLONG MFTRecord;
00303     UNICODE_STRING Pattern;
00304 
00305     DPRINT1("NtfsQueryDirectory() called\n");
00306 
00307     ASSERT(IrpContext);
00308     Irp = IrpContext->Irp;
00309     DeviceObject = IrpContext->DeviceObject;
00310 
00311     DeviceExtension = DeviceObject->DeviceExtension;
00312     Stack = IoGetCurrentIrpStackLocation(Irp);
00313     FileObject = Stack->FileObject;
00314 
00315     Ccb = (PNTFS_CCB)FileObject->FsContext2;
00316     Fcb = (PNTFS_FCB)FileObject->FsContext;
00317 
00318     /* Obtain the callers parameters */
00319     BufferLength = Stack->Parameters.QueryDirectory.Length;
00320     SearchPattern = Stack->Parameters.QueryDirectory.FileName;
00321     FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
00322     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
00323 
00324     if (SearchPattern != NULL)
00325     {
00326         if (!Ccb->DirectorySearchPattern)
00327         {
00328             First = TRUE;
00329             Ccb->DirectorySearchPattern =
00330                 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_NTFS);
00331             if (!Ccb->DirectorySearchPattern)
00332             {
00333                 return STATUS_INSUFFICIENT_RESOURCES;
00334             }
00335 
00336             memcpy(Ccb->DirectorySearchPattern,
00337                    SearchPattern->Buffer,
00338                    SearchPattern->Length);
00339             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
00340         }
00341     }
00342     else if (!Ccb->DirectorySearchPattern)
00343     {
00344         First = TRUE;
00345         Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
00346         if (!Ccb->DirectorySearchPattern)
00347         {
00348             return STATUS_INSUFFICIENT_RESOURCES;
00349         }
00350 
00351         Ccb->DirectorySearchPattern[0] = L'*';
00352         Ccb->DirectorySearchPattern[1] = 0;
00353     }
00354 
00355     RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
00356 
00357     DPRINT1("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
00358     DPRINT1("In: '%S'\n", Fcb->PathName);
00359 
00360     /* Determine directory index */
00361     if (Stack->Flags & SL_INDEX_SPECIFIED)
00362     {
00363         Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
00364     }
00365     else if (First || (Stack->Flags & SL_RESTART_SCAN))
00366     {
00367         Ccb->Entry = 0;
00368     }
00369 
00370     /* Determine Buffer for result */
00371     if (Irp->MdlAddress)
00372     {
00373         Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
00374     }
00375     else
00376     {
00377         Buffer = Irp->UserBuffer;
00378     }
00379 
00380     DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
00381 
00382     while (Status == STATUS_SUCCESS && BufferLength > 0)
00383     {
00384         Status = NtfsFindFileAt(DeviceExtension,
00385                                 &Pattern,
00386                                 &Ccb->Entry,
00387                                 &FileRecord,
00388                                 &DataContext,
00389                                 &MFTRecord,
00390                                 Fcb->MFTIndex);
00391       //DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
00392 
00393         if (NT_SUCCESS(Status))
00394         {
00395             switch (FileInformationClass)
00396             {
00397                 case FileNameInformation:
00398                     Status = NtfsGetNameInformation(DeviceExtension,
00399                                                     FileRecord,
00400                                                     DataContext,
00401                                                     (PFILE_NAMES_INFORMATION)Buffer,
00402                                                     BufferLength);
00403                     break;
00404 
00405                 case FileDirectoryInformation:
00406                     Status = NtfsGetDirectoryInformation(DeviceExtension,
00407                                                          FileRecord,
00408                                                          DataContext,
00409                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
00410                                                          BufferLength);
00411                     break;
00412 
00413                 case FileFullDirectoryInformation:
00414                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
00415                                                              FileRecord,
00416                                                              DataContext,
00417                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
00418                                                              BufferLength);
00419                     break;
00420 
00421                 case FileBothDirectoryInformation:
00422                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
00423                                                              FileRecord,
00424                                                              DataContext,
00425                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
00426                                                              BufferLength);
00427                     break;
00428 
00429                 default:
00430                     Status = STATUS_INVALID_INFO_CLASS;
00431             }
00432 
00433             if (Status == STATUS_BUFFER_OVERFLOW)
00434             {
00435                 if (Buffer0)
00436                 {
00437                     Buffer0->NextEntryOffset = 0;
00438                 }
00439                 break;
00440             }
00441         }
00442         else
00443         {
00444             if (Buffer0)
00445             {
00446                 Buffer0->NextEntryOffset = 0;
00447             }
00448 
00449             if (First)
00450             {
00451                 Status = STATUS_NO_SUCH_FILE;
00452             }
00453             else
00454             {
00455                 Status = STATUS_NO_MORE_FILES;
00456             }
00457             break;
00458         }
00459 
00460         Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
00461         Buffer0->FileIndex = FileIndex++;
00462         Ccb->Entry++;
00463 
00464         if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
00465         {
00466             break;
00467         }
00468         BufferLength -= Buffer0->NextEntryOffset;
00469         Buffer += Buffer0->NextEntryOffset;
00470         ExFreePoolWithTag(FileRecord, TAG_NTFS);
00471     }
00472 
00473     if (Buffer0)
00474     {
00475         Buffer0->NextEntryOffset = 0;
00476     }
00477 
00478     if (FileIndex > 0)
00479     {
00480         Status = STATUS_SUCCESS;
00481     }
00482 
00483     return Status;
00484 }
00485 
00486 
00487 NTSTATUS
00488 NTAPI
00489 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
00490                         PIRP Irp)
00491 {
00492     PNTFS_IRP_CONTEXT IrpContext = NULL;
00493     NTSTATUS Status = STATUS_UNSUCCESSFUL;
00494 
00495     DPRINT1("NtfsDirectoryControl() called\n");
00496 
00497     FsRtlEnterFileSystem();
00498     ASSERT(DeviceObject);
00499     ASSERT(Irp);
00500 
00501     NtfsIsIrpTopLevel(Irp);
00502 
00503     IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
00504     if (IrpContext)
00505     {
00506         switch (IrpContext->MinorFunction)
00507         {
00508             case IRP_MN_QUERY_DIRECTORY:
00509                 Status = NtfsQueryDirectory(IrpContext);
00510                 break;
00511 
00512             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
00513                 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
00514                 Status = STATUS_NOT_IMPLEMENTED;
00515                 break;
00516 
00517             default:
00518                 Status = STATUS_INVALID_DEVICE_REQUEST;
00519                 break;
00520         }
00521     }
00522     else
00523         Status = STATUS_INSUFFICIENT_RESOURCES;
00524 
00525     Irp->IoStatus.Status = Status;
00526     Irp->IoStatus.Information = 0;
00527     IoCompleteRequest(Irp, IO_NO_INCREMENT);
00528 
00529     if (IrpContext)
00530         ExFreePoolWithTag(IrpContext, 'PRIN');
00531 
00532     IoSetTopLevelIrp(NULL);
00533     FsRtlExitFileSystem();
00534     return Status;
00535 }
00536 
00537 /* EOF */