3 * Copyright (C) 2002,2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/dirctl.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMER: Eric Kohl
26 /* INCLUDES *****************************************************************/
33 /* FUNCTIONS ****************************************************************/
37 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt
,
40 PLARGE_INTEGER StreamOffset
,
47 * FUNCTION: Retrieves the file name, be it in short or long file name format
54 ULONG BlockOffset
= 0;
56 Record
= (PDIR_RECORD
)*Block
;
57 while(Index
< *pIndex
)
59 BlockOffset
+= Record
->RecordLength
;
60 Offset
+= Record
->RecordLength
;
62 Record
= (PDIR_RECORD
)(*Block
+ BlockOffset
);
63 if (BlockOffset
>= BLOCKSIZE
|| Record
->RecordLength
== 0)
65 DPRINT("Map next sector\n");
66 CcUnpinData(*Context
);
67 StreamOffset
->QuadPart
+= BLOCKSIZE
;
68 Offset
= ROUND_UP(Offset
, BLOCKSIZE
);
71 if (!CcMapData(DeviceExt
->StreamFileObject
,
76 DPRINT("CcMapData() failed\n");
77 return(STATUS_UNSUCCESSFUL
);
79 Record
= (PDIR_RECORD
)(*Block
+ BlockOffset
);
82 if (Offset
>= DirLength
)
83 return(STATUS_NO_MORE_ENTRIES
);
88 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
89 Index
, Record
->RecordLength
, Offset
);
91 if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 0)
95 else if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 1)
101 if (DeviceExt
->CdInfo
.JolietLevel
== 0)
105 for (i
= 0; i
< Record
->FileIdLength
&& Record
->FileId
[i
] != ';'; i
++)
106 Name
[i
] = (WCHAR
)Record
->FileId
[i
];
111 CdfsSwapString(Name
, Record
->FileId
, Record
->FileIdLength
);
115 DPRINT("Name '%S'\n", Name
);
121 return(STATUS_SUCCESS
);
127 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt
,
128 PFILE_RECORD_HEADER FileRecord
,
129 PNTFS_ATTR_CONTEXT DataContext
,
130 PFILE_NAMES_INFORMATION Info
,
134 PFILENAME_ATTRIBUTE FileName
;
136 DPRINT("NtfsGetNameInformation() called\n");
138 FileName
= GetFileNameFromRecord(FileRecord
, NTFS_FILE_NAME_WIN32
);
139 ASSERT(FileName
!= NULL
);
141 Length
= FileName
->NameLength
* sizeof (WCHAR
);
142 if ((sizeof(FILE_NAMES_INFORMATION
) + Length
) > BufferLength
)
143 return(STATUS_BUFFER_OVERFLOW
);
145 Info
->FileNameLength
= Length
;
146 Info
->NextEntryOffset
=
147 ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) + Length
, sizeof(ULONG
));
148 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
150 return(STATUS_SUCCESS
);
155 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
156 PFILE_RECORD_HEADER FileRecord
,
157 PNTFS_ATTR_CONTEXT DataContext
,
158 PFILE_DIRECTORY_INFORMATION Info
,
162 PFILENAME_ATTRIBUTE FileName
;
164 DPRINT("NtfsGetDirectoryInformation() called\n");
166 FileName
= GetFileNameFromRecord(FileRecord
, NTFS_FILE_NAME_WIN32
);
167 ASSERT(FileName
!= NULL
);
169 Length
= FileName
->NameLength
* sizeof (WCHAR
);
170 if ((sizeof(FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
171 return(STATUS_BUFFER_OVERFLOW
);
173 Info
->FileNameLength
= Length
;
174 Info
->NextEntryOffset
=
175 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
176 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
178 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
179 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
180 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
181 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
183 /* Convert file flags */
184 NtfsFileFlagsToAttributes(FileName
->FileAttributes
, &Info
->FileAttributes
);
186 Info
->EndOfFile
.QuadPart
= FileName
->AllocatedSize
;
187 Info
->AllocationSize
.QuadPart
= ROUND_UP(FileName
->AllocatedSize
, DeviceExt
->NtfsInfo
.BytesPerCluster
);
191 return STATUS_SUCCESS
;
196 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
197 PFILE_RECORD_HEADER FileRecord
,
198 PNTFS_ATTR_CONTEXT DataContext
,
199 PFILE_FULL_DIRECTORY_INFORMATION Info
,
203 PFILENAME_ATTRIBUTE FileName
;
205 DPRINT("NtfsGetFullDirectoryInformation() called\n");
207 FileName
= GetFileNameFromRecord(FileRecord
, NTFS_FILE_NAME_WIN32
);
208 ASSERT(FileName
!= NULL
);
210 Length
= FileName
->NameLength
* sizeof (WCHAR
);
211 if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
212 return(STATUS_BUFFER_OVERFLOW
);
214 Info
->FileNameLength
= Length
;
215 Info
->NextEntryOffset
=
216 ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
217 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
219 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
220 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
221 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
222 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
224 /* Convert file flags */
225 NtfsFileFlagsToAttributes(FileName
->FileAttributes
, &Info
->FileAttributes
);
227 Info
->EndOfFile
.QuadPart
= FileName
->AllocatedSize
;
228 Info
->AllocationSize
.QuadPart
= ROUND_UP(FileName
->AllocatedSize
, DeviceExt
->NtfsInfo
.BytesPerCluster
);
233 return STATUS_SUCCESS
;
238 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
239 PFILE_RECORD_HEADER FileRecord
,
240 PNTFS_ATTR_CONTEXT DataContext
,
241 PFILE_BOTH_DIR_INFORMATION Info
,
245 PFILENAME_ATTRIBUTE FileName
, ShortFileName
;
247 DPRINT("NtfsGetBothDirectoryInformation() called\n");
249 FileName
= GetFileNameFromRecord(FileRecord
, NTFS_FILE_NAME_WIN32
);
250 ASSERT(FileName
!= NULL
);
251 ShortFileName
= GetFileNameFromRecord(FileRecord
, NTFS_FILE_NAME_DOS
);
253 Length
= FileName
->NameLength
* sizeof (WCHAR
);
254 if ((sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
) > BufferLength
)
255 return(STATUS_BUFFER_OVERFLOW
);
257 Info
->FileNameLength
= Length
;
258 Info
->NextEntryOffset
=
259 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
, sizeof(ULONG
));
260 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
264 /* Should we upcase the filename? */
265 ASSERT(ShortFileName
->NameLength
<= ARRAYSIZE(Info
->ShortName
));
266 Info
->ShortNameLength
= ShortFileName
->NameLength
* sizeof(WCHAR
);
267 RtlCopyMemory(Info
->ShortName
, ShortFileName
->Name
, Info
->ShortNameLength
);
271 Info
->ShortName
[0] = 0;
272 Info
->ShortNameLength
= 0;
275 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
276 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
277 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
278 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
280 /* Convert file flags */
281 NtfsFileFlagsToAttributes(FileName
->FileAttributes
, &Info
->FileAttributes
);
283 Info
->EndOfFile
.QuadPart
= FileName
->AllocatedSize
;
284 Info
->AllocationSize
.QuadPart
= ROUND_UP(FileName
->AllocatedSize
, DeviceExt
->NtfsInfo
.BytesPerCluster
);
289 return STATUS_SUCCESS
;
294 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext
)
297 PDEVICE_OBJECT DeviceObject
;
298 PDEVICE_EXTENSION DeviceExtension
;
299 LONG BufferLength
= 0;
300 PUNICODE_STRING SearchPattern
= NULL
;
301 FILE_INFORMATION_CLASS FileInformationClass
;
303 PUCHAR Buffer
= NULL
;
304 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
307 BOOLEAN First
= FALSE
;
308 PIO_STACK_LOCATION Stack
;
309 PFILE_OBJECT FileObject
;
310 NTSTATUS Status
= STATUS_SUCCESS
;
311 PFILE_RECORD_HEADER FileRecord
;
312 PNTFS_ATTR_CONTEXT DataContext
;
314 UNICODE_STRING Pattern
;
316 DPRINT1("NtfsQueryDirectory() called\n");
319 Irp
= IrpContext
->Irp
;
320 DeviceObject
= IrpContext
->DeviceObject
;
322 DeviceExtension
= DeviceObject
->DeviceExtension
;
323 Stack
= IoGetCurrentIrpStackLocation(Irp
);
324 FileObject
= Stack
->FileObject
;
326 Ccb
= (PNTFS_CCB
)FileObject
->FsContext2
;
327 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
329 /* Obtain the callers parameters */
330 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
331 SearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
332 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
333 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
335 if (SearchPattern
!= NULL
)
337 if (!Ccb
->DirectorySearchPattern
)
340 Ccb
->DirectorySearchPattern
=
341 ExAllocatePoolWithTag(NonPagedPool
, SearchPattern
->Length
+ sizeof(WCHAR
), TAG_NTFS
);
342 if (!Ccb
->DirectorySearchPattern
)
344 return STATUS_INSUFFICIENT_RESOURCES
;
347 memcpy(Ccb
->DirectorySearchPattern
,
348 SearchPattern
->Buffer
,
349 SearchPattern
->Length
);
350 Ccb
->DirectorySearchPattern
[SearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
353 else if (!Ccb
->DirectorySearchPattern
)
356 Ccb
->DirectorySearchPattern
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), TAG_NTFS
);
357 if (!Ccb
->DirectorySearchPattern
)
359 return STATUS_INSUFFICIENT_RESOURCES
;
362 Ccb
->DirectorySearchPattern
[0] = L
'*';
363 Ccb
->DirectorySearchPattern
[1] = 0;
366 RtlInitUnicodeString(&Pattern
, Ccb
->DirectorySearchPattern
);
368 DPRINT1("Search pattern '%S'\n", Ccb
->DirectorySearchPattern
);
369 DPRINT1("In: '%S'\n", Fcb
->PathName
);
371 /* Determine directory index */
372 if (Stack
->Flags
& SL_INDEX_SPECIFIED
)
374 Ccb
->Entry
= Ccb
->CurrentByteOffset
.u
.LowPart
;
376 else if (First
|| (Stack
->Flags
& SL_RESTART_SCAN
))
381 /* Determine Buffer for result */
384 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
388 Buffer
= Irp
->UserBuffer
;
391 DPRINT("Buffer=%p tofind=%S\n", Buffer
, Ccb
->DirectorySearchPattern
);
393 while (Status
== STATUS_SUCCESS
&& BufferLength
> 0)
395 Status
= NtfsFindFileAt(DeviceExtension
,
402 //DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
404 if (NT_SUCCESS(Status
))
406 switch (FileInformationClass
)
408 case FileNameInformation
:
409 Status
= NtfsGetNameInformation(DeviceExtension
,
412 (PFILE_NAMES_INFORMATION
)Buffer
,
416 case FileDirectoryInformation
:
417 Status
= NtfsGetDirectoryInformation(DeviceExtension
,
420 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
424 case FileFullDirectoryInformation
:
425 Status
= NtfsGetFullDirectoryInformation(DeviceExtension
,
428 (PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,
432 case FileBothDirectoryInformation
:
433 Status
= NtfsGetBothDirectoryInformation(DeviceExtension
,
436 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
441 Status
= STATUS_INVALID_INFO_CLASS
;
444 if (Status
== STATUS_BUFFER_OVERFLOW
)
448 Buffer0
->NextEntryOffset
= 0;
457 Buffer0
->NextEntryOffset
= 0;
462 Status
= STATUS_NO_SUCH_FILE
;
466 Status
= STATUS_NO_MORE_FILES
;
471 Buffer0
= (PFILE_NAMES_INFORMATION
)Buffer
;
472 Buffer0
->FileIndex
= FileIndex
++;
475 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
479 BufferLength
-= Buffer0
->NextEntryOffset
;
480 Buffer
+= Buffer0
->NextEntryOffset
;
481 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
486 Buffer0
->NextEntryOffset
= 0;
491 Status
= STATUS_SUCCESS
;
500 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject
,
503 PNTFS_IRP_CONTEXT IrpContext
= NULL
;
504 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
506 DPRINT1("NtfsDirectoryControl() called\n");
508 FsRtlEnterFileSystem();
509 ASSERT(DeviceObject
);
512 NtfsIsIrpTopLevel(Irp
);
514 IrpContext
= NtfsAllocateIrpContext(DeviceObject
, Irp
);
517 switch (IrpContext
->MinorFunction
)
519 case IRP_MN_QUERY_DIRECTORY
:
520 Status
= NtfsQueryDirectory(IrpContext
);
523 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
524 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
525 Status
= STATUS_NOT_IMPLEMENTED
;
529 Status
= STATUS_INVALID_DEVICE_REQUEST
;
534 Status
= STATUS_INSUFFICIENT_RESOURCES
;
536 Irp
->IoStatus
.Status
= Status
;
537 Irp
->IoStatus
.Information
= 0;
538 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
541 ExFreePoolWithTag(IrpContext
, 'PRIN');
543 IoSetTopLevelIrp(NULL
);
544 FsRtlExitFileSystem();