3 * Copyright (C) 2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: dirctl.c,v 1.3 2002/05/01 13:15:42 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/fs/cdfs/dirctl.c
24 * PURPOSE: CDROM (ISO 9660) filesystem driver
25 * PROGRAMMER: Art Yerkes
30 /* INCLUDES *****************************************************************/
32 #include <ddk/ntddk.h>
40 /* FUNCTIONS ****************************************************************/
43 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt
,
51 * FUNCTION: Retrieves the file name, be it in short or long file name format
59 Record
= (PDIR_RECORD
)Block
;
60 while(Index
< *pIndex
)
62 Offset
= Offset
+ Record
->RecordLength
;
64 Record
= (PDIR_RECORD
)(Block
+ Offset
);
65 if (Record
->RecordLength
== 0)
67 Offset
= ROUND_UP(Offset
, 2048);
68 Record
= (PDIR_RECORD
)(Block
+ Offset
);
71 if (Offset
>= BlockLength
)
72 return(STATUS_NO_MORE_ENTRIES
);
77 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
78 Index
, Record
->RecordLength
, Offset
);
80 if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 0)
84 else if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 1)
90 if (DeviceExt
->CdInfo
.JolietLevel
== 0)
94 for (i
= 0; i
< Record
->FileIdLength
&& Record
->FileId
[i
] != ';'; i
++)
95 Name
[i
] = (WCHAR
)Record
->FileId
[i
];
100 CdfsSwapString(Name
, Record
->FileId
, Record
->FileIdLength
);
104 DPRINT("Name '%S'\n", Name
);
110 return(STATUS_SUCCESS
);
115 CdfsFindFile(PDEVICE_EXTENSION DeviceExt
,
122 * FUNCTION: Find a file
135 LARGE_INTEGER FileOffset
;
136 PVOID Context
= NULL
;
144 DPRINT("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n",
145 Parent
, FileToFind
, pDirIndex
? *pDirIndex
: 0);
146 DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",
147 Fcb
->PathName
, Fcb
->ObjectName
);
151 if (wcslen (FileToFind
) == 0)
154 TempStr
[0] = (WCHAR
) '.';
156 FileToFind
= (PWSTR
)&TempStr
;
161 FirstSector
= Parent
->Entry
.ExtentLocationL
;
162 if (FirstSector
== DeviceExt
->CdInfo
.RootStart
)
174 FirstSector
= DeviceExt
->CdInfo
.RootStart
;
175 DirSize
= DeviceExt
->CdInfo
.RootSize
;
178 if (FileToFind
[0] == 0 || (FileToFind
[0] == '\\' && FileToFind
[1] == 0)
179 || (FileToFind
[0] == '.' && FileToFind
[1] == 0))
181 /* it's root : complete essentials fields then return ok */
182 RtlZeroMemory(Fcb
, sizeof(FCB
));
184 Fcb
->PathName
[0]='\\';
185 Fcb
->ObjectName
= &Fcb
->PathName
[1];
186 Fcb
->Entry
.ExtentLocationL
= DeviceExt
->CdInfo
.RootStart
;
187 Fcb
->Entry
.DataLengthL
= DeviceExt
->CdInfo
.RootSize
;
188 Fcb
->Entry
.FileFlags
= 0x02; //FILE_ATTRIBUTE_DIRECTORY;
194 DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb
->PathName
, Fcb
->ObjectName
);
195 return (STATUS_SUCCESS
);
200 FirstSector
= Parent
->Entry
.ExtentLocationL
;
201 DirSize
= Parent
->Entry
.DataLengthL
;
204 DPRINT("FirstSector %lu DirSize %lu\n", FirstSector
, DirSize
);
206 if (pDirIndex
&& (*pDirIndex
))
207 DirIndex
= *pDirIndex
;
209 BufferSize
= ROUND_UP(DirSize
, BLOCKSIZE
);
210 SectorCount
= BufferSize
/ BLOCKSIZE
;
212 DPRINT("FirstSector %lu DirSize %lu BufferSize %lu SectorCount %lu\n",
213 FirstSector
, DirSize
, BufferSize
, SectorCount
);
215 block
= ExAllocatePool(NonPagedPool
, BufferSize
);
217 Status
= CdfsReadSectors(DeviceExt
->StorageDevice
,
221 if (!NT_SUCCESS(Status
))
223 DPRINT("Reading directory extent failed (Status %lx)\n", Status
);
231 Record
= (PDIR_RECORD
)Ptr
;
232 if (Record
->RecordLength
== 0)
234 DPRINT1("Stopped!\n");
238 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
239 Record
->RecordLength
, Record
->ExtAttrRecordLength
, Record
->FileIdLength
);
241 Status
= CdfsGetEntryName(DeviceExt
, block
, DirSize
, (PVOID
*)&Ptr
, name
, &DirIndex
, pDirIndex2
);
242 if (Status
== STATUS_NO_MORE_ENTRIES
)
247 DPRINT("Name '%S'\n", name
);
249 if (wstrcmpjoki(name
, FileToFind
)) /* || wstrcmpjoki (name2, FileToFind)) */
251 if (Parent
&& Parent
->PathName
)
253 len
= wcslen(Parent
->PathName
);
254 memcpy(Fcb
->PathName
, Parent
->PathName
, len
*sizeof(WCHAR
));
255 Fcb
->ObjectName
=&Fcb
->PathName
[len
];
256 if (len
!= 1 || Fcb
->PathName
[0] != '\\')
258 Fcb
->ObjectName
[0] = '\\';
259 Fcb
->ObjectName
= &Fcb
->ObjectName
[1];
264 Fcb
->ObjectName
=Fcb
->PathName
;
265 Fcb
->ObjectName
[0]='\\';
266 Fcb
->ObjectName
=&Fcb
->ObjectName
[1];
269 DPRINT("PathName '%S' ObjectName '%S'\n", Fcb
->PathName
, Fcb
->ObjectName
);
271 memcpy(&Fcb
->Entry
, Ptr
, sizeof(DIR_RECORD
));
272 wcsncpy(Fcb
->ObjectName
, name
, MAX_PATH
);
274 *pDirIndex
= DirIndex
;
276 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
277 Fcb
->PathName
, Fcb
->ObjectName
, DirIndex
);
281 return(STATUS_SUCCESS
);
285 Ptr
= Ptr
+ Record
->RecordLength
;
288 if (((ULONG
)Ptr
- (ULONG
)block
) >= DirSize
)
290 DPRINT("Stopped!\n");
298 *pDirIndex
= DirIndex
;
300 return(STATUS_UNSUCCESSFUL
);
305 CdfsGetNameInformation(PFCB Fcb
,
306 PDEVICE_EXTENSION DeviceExt
,
307 PFILE_NAMES_INFORMATION Info
,
312 DPRINT("CdfsGetNameInformation() called\n");
314 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
315 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
316 return(STATUS_BUFFER_OVERFLOW
);
318 Info
->FileNameLength
= Length
;
319 Info
->NextEntryOffset
=
320 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
) + Length
, 4);
321 memcpy(Info
->FileName
, Fcb
->ObjectName
, Length
);
323 return(STATUS_SUCCESS
);
328 CdfsGetDirectoryInformation(PFCB Fcb
,
329 PDEVICE_EXTENSION DeviceExt
,
330 PFILE_DIRECTORY_INFORMATION Info
,
335 DPRINT1("CdfsGetDirectoryInformation() called\n");
337 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
338 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
339 return(STATUS_BUFFER_OVERFLOW
);
341 Info
->FileNameLength
= Length
;
342 Info
->NextEntryOffset
=
343 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
) + Length
, 4);
344 memcpy(Info
->FileName
, Fcb
->ObjectName
, Length
);
346 /* Convert file times */
347 CdfsDateTimeToFileTime(Fcb
,
348 &Info
->CreationTime
);
349 CdfsDateTimeToFileTime(Fcb
,
350 &Info
->LastAccessTime
);
351 CdfsDateTimeToFileTime(Fcb
,
352 &Info
->LastWriteTime
);
353 CdfsDateTimeToFileTime(Fcb
,
356 /* Convert file flags */
357 CdfsFileFlagsToAttributes(Fcb
,
358 &Info
->FileAttributes
);
360 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
362 /* Make AllocSize a rounded up multiple of the sector size */
363 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
367 return(STATUS_SUCCESS
);
372 CdfsGetFullDirectoryInformation(PFCB Fcb
,
373 PDEVICE_EXTENSION DeviceExt
,
374 PFILE_FULL_DIRECTORY_INFORMATION Info
,
379 DPRINT1("CdfsGetFullDirectoryInformation() called\n");
381 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
382 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
383 return(STATUS_BUFFER_OVERFLOW
);
385 Info
->FileNameLength
= Length
;
386 Info
->NextEntryOffset
=
387 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
) + Length
, 4);
388 memcpy(Info
->FileName
, Fcb
->ObjectName
, Length
);
390 /* Convert file times */
391 CdfsDateTimeToFileTime(Fcb
,
392 &Info
->CreationTime
);
393 CdfsDateTimeToFileTime(Fcb
,
394 &Info
->LastAccessTime
);
395 CdfsDateTimeToFileTime(Fcb
,
396 &Info
->LastWriteTime
);
397 CdfsDateTimeToFileTime(Fcb
,
400 /* Convert file flags */
401 CdfsFileFlagsToAttributes(Fcb
,
402 &Info
->FileAttributes
);
404 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
406 /* Make AllocSize a rounded up multiple of the sector size */
407 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
412 return(STATUS_SUCCESS
);
417 CdfsGetBothDirectoryInformation(PFCB Fcb
,
418 PDEVICE_EXTENSION DeviceExt
,
419 PFILE_BOTH_DIRECTORY_INFORMATION Info
,
424 DPRINT("CdfsGetBothDirectoryInformation() called\n");
426 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
427 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
428 return(STATUS_BUFFER_OVERFLOW
);
430 Info
->FileNameLength
= Length
;
431 Info
->NextEntryOffset
=
432 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
) + Length
, 4);
433 memcpy(Info
->FileName
, Fcb
->ObjectName
, Length
);
435 /* Convert file times */
436 CdfsDateTimeToFileTime(Fcb
,
437 &Info
->CreationTime
);
438 CdfsDateTimeToFileTime(Fcb
,
439 &Info
->LastAccessTime
);
440 CdfsDateTimeToFileTime(Fcb
,
441 &Info
->LastWriteTime
);
442 CdfsDateTimeToFileTime(Fcb
,
445 /* Convert file flags */
446 CdfsFileFlagsToAttributes(Fcb
,
447 &Info
->FileAttributes
);
449 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
451 /* Make AllocSize a rounded up multiple of the sector size */
452 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
457 if (DeviceExt
->CdInfo
.JolietLevel
== 0)
459 /* Standard ISO-9660 format */
460 Info
->ShortNameLength
= Length
;
461 memcpy(Info
->ShortName
, Fcb
->ObjectName
, Length
);
465 /* Joliet extension */
467 /* FIXME: Copy or create a short file name */
469 Info
->ShortName
[0] = 0;
470 Info
->ShortNameLength
= 0;
473 return(STATUS_SUCCESS
);
478 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject
,
481 PDEVICE_EXTENSION DeviceExtension
;
482 LONG BufferLength
= 0;
483 PUNICODE_STRING SearchPattern
= NULL
;
484 FILE_INFORMATION_CLASS FileInformationClass
;
486 PUCHAR Buffer
= NULL
;
487 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
491 BOOLEAN First
= FALSE
;
492 PIO_STACK_LOCATION Stack
;
493 PFILE_OBJECT FileObject
;
494 NTSTATUS Status
= STATUS_SUCCESS
;
496 DPRINT("CdfsQueryDirectory() called\n");
498 DeviceExtension
= DeviceObject
->DeviceExtension
;
499 Stack
= IoGetCurrentIrpStackLocation(Irp
);
500 FileObject
= Stack
->FileObject
;
502 Ccb
= (PCCB
)FileObject
->FsContext2
;
505 /* Obtain the callers parameters */
506 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
507 SearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
508 FileInformationClass
=
509 Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
510 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
513 if (SearchPattern
!= NULL
)
515 if (!Ccb
->DirectorySearchPattern
)
518 Ccb
->DirectorySearchPattern
=
519 ExAllocatePool(NonPagedPool
, SearchPattern
->Length
+ sizeof(WCHAR
));
520 if (!Ccb
->DirectorySearchPattern
)
522 return(STATUS_INSUFFICIENT_RESOURCES
);
525 memcpy(Ccb
->DirectorySearchPattern
,
526 SearchPattern
->Buffer
,
527 SearchPattern
->Length
);
528 Ccb
->DirectorySearchPattern
[SearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
531 else if (!Ccb
->DirectorySearchPattern
)
534 Ccb
->DirectorySearchPattern
= ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
535 if (!Ccb
->DirectorySearchPattern
)
537 return(STATUS_INSUFFICIENT_RESOURCES
);
539 Ccb
->DirectorySearchPattern
[0] = L
'*';
540 Ccb
->DirectorySearchPattern
[1] = 0;
542 DPRINT("Search pattern '%S'\n", Ccb
->DirectorySearchPattern
);
544 /* Determine directory index */
545 if (Stack
->Flags
& SL_INDEX_SPECIFIED
)
547 Ccb
->Entry
= Ccb
->CurrentByteOffset
.u
.LowPart
;
549 else if (First
|| (Stack
->Flags
& SL_RESTART_SCAN
))
554 /* Determine Buffer for result */
557 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
561 Buffer
= Irp
->UserBuffer
;
563 DPRINT("Buffer=%x tofind=%S\n", Buffer
, Ccb
->DirectorySearchPattern
);
565 TempFcb
.ObjectName
= TempFcb
.PathName
;
566 while (Status
== STATUS_SUCCESS
&& BufferLength
> 0)
568 Status
= CdfsFindFile(DeviceExtension
,
571 Ccb
->DirectorySearchPattern
,
574 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb
.ObjectName
, Status
, Ccb
->Entry
);
576 if (NT_SUCCESS(Status
))
578 switch (FileInformationClass
)
580 case FileNameInformation
:
581 Status
= CdfsGetNameInformation(&TempFcb
,
583 (PFILE_NAMES_INFORMATION
)Buffer
,
587 case FileDirectoryInformation
:
588 Status
= CdfsGetDirectoryInformation(&TempFcb
,
590 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
594 case FileFullDirectoryInformation
:
595 Status
= CdfsGetFullDirectoryInformation(&TempFcb
,
597 (PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,
601 case FileBothDirectoryInformation
:
602 Status
= CdfsGetBothDirectoryInformation(&TempFcb
,
604 (PFILE_BOTH_DIRECTORY_INFORMATION
)Buffer
,
609 Status
= STATUS_INVALID_INFO_CLASS
;
612 if (Status
== STATUS_BUFFER_OVERFLOW
)
616 Buffer0
->NextEntryOffset
= 0;
625 Buffer0
->NextEntryOffset
= 0;
630 Status
= STATUS_NO_SUCH_FILE
;
634 Status
= STATUS_NO_MORE_FILES
;
639 Buffer0
= (PFILE_NAMES_INFORMATION
)Buffer
;
640 Buffer0
->FileIndex
= FileIndex
++;
643 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
647 BufferLength
-= Buffer0
->NextEntryOffset
;
648 Buffer
+= Buffer0
->NextEntryOffset
;
653 Buffer0
->NextEntryOffset
= 0;
658 Status
= STATUS_SUCCESS
;
667 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject
,
670 PIO_STACK_LOCATION Stack
;
673 DPRINT("CdfsDirectoryControl() called\n");
675 Stack
= IoGetCurrentIrpStackLocation(Irp
);
677 switch (Stack
->MinorFunction
)
679 case IRP_MN_QUERY_DIRECTORY
:
680 Status
= CdfsQueryDirectory(DeviceObject
,
684 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
685 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
686 Status
= STATUS_NOT_IMPLEMENTED
;
690 DPRINT1("CDFS: MinorFunction %d\n", Stack
->MinorFunction
);
691 Status
= STATUS_INVALID_DEVICE_REQUEST
;
695 Irp
->IoStatus
.Status
= Status
;
696 Irp
->IoStatus
.Information
= 0;
698 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);