2 * $Id: dir.c,v 1.35 2004/11/06 13:44:57 ekohl Exp $
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: drivers/fs/vfat/dir.c
7 * PURPOSE: VFAT Filesystem : directory control
13 #include <ddk/ntddk.h>
22 // function like DosDateTimeToFileTime
24 FsdDosDateTimeToSystemTime (WORD wDosDate
, WORD wDosTime
, PLARGE_INTEGER SystemTime
)
26 PDOSTIME pdtime
= (PDOSTIME
) & wDosTime
;
27 PDOSDATE pddate
= (PDOSDATE
) & wDosDate
;
28 TIME_FIELDS TimeFields
;
29 LARGE_INTEGER LocalTime
;
31 if (SystemTime
== NULL
)
34 TimeFields
.Milliseconds
= 0;
35 TimeFields
.Second
= pdtime
->Second
* 2;
36 TimeFields
.Minute
= pdtime
->Minute
;
37 TimeFields
.Hour
= pdtime
->Hour
;
39 TimeFields
.Day
= pddate
->Day
;
40 TimeFields
.Month
= pddate
->Month
;
41 TimeFields
.Year
= 1980 + pddate
->Year
;
43 RtlTimeFieldsToTime (&TimeFields
, &LocalTime
);
44 ExLocalTimeToSystemTime(&LocalTime
, SystemTime
);
50 // function like FileTimeToDosDateTime
52 FsdSystemTimeToDosDateTime (PLARGE_INTEGER SystemTime
, WORD
* pwDosDate
, WORD
* pwDosTime
)
54 PDOSTIME pdtime
= (PDOSTIME
) pwDosTime
;
55 PDOSDATE pddate
= (PDOSDATE
) pwDosDate
;
56 TIME_FIELDS TimeFields
;
57 LARGE_INTEGER LocalTime
;
59 if (SystemTime
== NULL
)
62 ExSystemTimeToLocalTime (SystemTime
, &LocalTime
);
63 RtlTimeToTimeFields (&LocalTime
, &TimeFields
);
67 pdtime
->Second
= TimeFields
.Second
/ 2;
68 pdtime
->Minute
= TimeFields
.Minute
;
69 pdtime
->Hour
= TimeFields
.Hour
;
74 pddate
->Day
= TimeFields
.Day
;
75 pddate
->Month
= TimeFields
.Month
;
76 pddate
->Year
= TimeFields
.Year
- 1980;
83 #define DWORD_ROUND_UP(x) ROUND_UP((x), (sizeof(DWORD)))
86 VfatGetFileNameInformation (PVFAT_DIRENTRY_CONTEXT DirContext
,
87 PFILE_NAMES_INFORMATION pInfo
, ULONG BufferLength
)
89 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
90 return STATUS_BUFFER_OVERFLOW
;
91 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
92 pInfo
->NextEntryOffset
=
93 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
);
94 memcpy (pInfo
->FileName
, DirContext
->LongNameU
.Buffer
, DirContext
->LongNameU
.Length
);
95 return STATUS_SUCCESS
;
99 VfatGetFileDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext
,
100 PDEVICE_EXTENSION DeviceExt
,
101 PFILE_DIRECTORY_INFORMATION pInfo
,
104 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
105 return STATUS_BUFFER_OVERFLOW
;
106 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
107 pInfo
->NextEntryOffset
=
108 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
);
109 memcpy (pInfo
->FileName
, DirContext
->LongNameU
.Buffer
, DirContext
->LongNameU
.Length
);
110 // pInfo->FileIndex=;
111 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.CreationDate
,
112 DirContext
->FatDirEntry
.CreationTime
,
113 &pInfo
->CreationTime
);
114 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.AccessDate
, 0,
115 &pInfo
->LastAccessTime
);
116 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.UpdateDate
,
117 DirContext
->FatDirEntry
.UpdateTime
,
118 &pInfo
->LastWriteTime
);
119 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
120 if (DirContext
->FatDirEntry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
122 pInfo
->EndOfFile
.QuadPart
= 0LL;
123 pInfo
->AllocationSize
.QuadPart
= 0LL;
127 pInfo
->EndOfFile
.u
.HighPart
= 0;
128 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->FatDirEntry
.FileSize
;
129 /* Make allocsize a rounded up multiple of BytesPerCluster */
130 pInfo
->AllocationSize
.u
.HighPart
= 0;
131 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->FatDirEntry
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
133 pInfo
->FileAttributes
= DirContext
->FatDirEntry
.Attrib
& 0x3f;
135 return STATUS_SUCCESS
;
139 VfatGetFileFullDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext
,
140 PDEVICE_EXTENSION DeviceExt
,
141 PFILE_FULL_DIRECTORY_INFORMATION pInfo
,
144 if ((sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
145 return STATUS_BUFFER_OVERFLOW
;
146 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
147 pInfo
->NextEntryOffset
=
148 DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
);
149 memcpy (pInfo
->FileName
, DirContext
->LongNameU
.Buffer
, DirContext
->LongNameU
.Length
);
150 // pInfo->FileIndex=;
151 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.CreationDate
,
152 DirContext
->FatDirEntry
.CreationTime
,
153 &pInfo
->CreationTime
);
154 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.AccessDate
,
155 0, &pInfo
->LastAccessTime
);
156 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.UpdateDate
,
157 DirContext
->FatDirEntry
.UpdateTime
,
158 &pInfo
->LastWriteTime
);
159 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
160 pInfo
->EndOfFile
.u
.HighPart
= 0;
161 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->FatDirEntry
.FileSize
;
162 /* Make allocsize a rounded up multiple of BytesPerCluster */
163 pInfo
->AllocationSize
.u
.HighPart
= 0;
164 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->FatDirEntry
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
165 pInfo
->FileAttributes
= DirContext
->FatDirEntry
.Attrib
& 0x3f;
167 return STATUS_SUCCESS
;
171 VfatGetFileBothInformation (PVFAT_DIRENTRY_CONTEXT DirContext
,
172 PDEVICE_EXTENSION DeviceExt
,
173 PFILE_BOTH_DIRECTORY_INFORMATION pInfo
,
176 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
177 return STATUS_BUFFER_OVERFLOW
;
178 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
179 pInfo
->NextEntryOffset
=
180 DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
);
181 memcpy(pInfo
->ShortName
, DirContext
->ShortNameU
.Buffer
, DirContext
->ShortNameU
.Length
);
182 pInfo
->ShortNameLength
= DirContext
->ShortNameU
.Length
;
183 memcpy (pInfo
->FileName
, DirContext
->LongNameU
.Buffer
, DirContext
->LongNameU
.Length
);
184 // pInfo->FileIndex=;
185 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.CreationDate
,
186 DirContext
->FatDirEntry
.CreationDate
,
187 &pInfo
->CreationTime
);
188 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.AccessDate
, 0,
189 &pInfo
->LastAccessTime
);
190 FsdDosDateTimeToSystemTime (DirContext
->FatDirEntry
.UpdateDate
,
191 DirContext
->FatDirEntry
.UpdateTime
,
192 &pInfo
->LastWriteTime
);
193 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
194 if (DirContext
->FatDirEntry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
196 pInfo
->EndOfFile
.QuadPart
= 0LL;
197 pInfo
->AllocationSize
.QuadPart
= 0LL;
201 pInfo
->EndOfFile
.u
.HighPart
= 0;
202 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->FatDirEntry
.FileSize
;
203 /* Make allocsize a rounded up multiple of BytesPerCluster */
204 pInfo
->AllocationSize
.u
.HighPart
= 0;
205 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->FatDirEntry
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
207 pInfo
->FileAttributes
= DirContext
->FatDirEntry
.Attrib
& 0x3f;
209 return STATUS_SUCCESS
;
212 NTSTATUS
DoQuery (PVFAT_IRP_CONTEXT IrpContext
)
214 NTSTATUS RC
= STATUS_SUCCESS
;
215 long BufferLength
= 0;
216 PUNICODE_STRING pSearchPattern
= NULL
;
217 FILE_INFORMATION_CLASS FileInformationClass
;
218 unsigned long FileIndex
= 0;
219 unsigned char *Buffer
= NULL
;
220 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
223 BOOLEAN First
= FALSE
;
225 VFAT_DIRENTRY_CONTEXT DirContext
;
226 WCHAR LongNameBuffer
[MAX_PATH
];
227 WCHAR ShortNameBuffer
[13];
229 PEXTENDED_IO_STACK_LOCATION Stack
= (PEXTENDED_IO_STACK_LOCATION
) IrpContext
->Stack
;
231 pCcb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
232 pFcb
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
234 // determine Buffer for result :
235 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
237 /* Do not probe the user buffer until SEH is available */
238 if (IrpContext
->Irp
->RequestorMode
!= KernelMode
&&
239 IrpContext
->Irp
->MdlAddress
== NULL
&&
240 IrpContext
->Irp
->UserBuffer
!= NULL
)
242 ProbeForWrite(IrpContext
->Irp
->UserBuffer
, BufferLength
, 1);
245 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
247 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
,
248 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
250 RC
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
258 /* Obtain the callers parameters */
259 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
260 FileInformationClass
=
261 Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
262 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
265 if (!pCcb
->SearchPattern
.Buffer
)
268 pCcb
->SearchPattern
.MaximumLength
= pSearchPattern
->Length
+ sizeof(WCHAR
);
269 pCcb
->SearchPattern
.Buffer
= ExAllocatePool(NonPagedPool
, pCcb
->SearchPattern
.MaximumLength
);
270 if (!pCcb
->SearchPattern
.Buffer
)
272 ExReleaseResourceLite(&pFcb
->MainResource
);
273 return STATUS_INSUFFICIENT_RESOURCES
;
275 RtlCopyUnicodeString(&pCcb
->SearchPattern
, pSearchPattern
);
276 pCcb
->SearchPattern
.Buffer
[pCcb
->SearchPattern
.Length
/ sizeof(WCHAR
)] = 0;
279 else if (!pCcb
->SearchPattern
.Buffer
)
282 pCcb
->SearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
283 pCcb
->SearchPattern
.Buffer
= ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
284 if (!pCcb
->SearchPattern
.Buffer
)
286 ExReleaseResourceLite(&pFcb
->MainResource
);
287 return STATUS_INSUFFICIENT_RESOURCES
;
289 pCcb
->SearchPattern
.Buffer
[0] = L
'*';
290 pCcb
->SearchPattern
.Buffer
[1] = 0;
291 pCcb
->SearchPattern
.Length
= sizeof(WCHAR
);
294 if (IrpContext
->Stack
->Flags
& SL_INDEX_SPECIFIED
)
296 DirContext
.DirIndex
= pCcb
->Entry
= pCcb
->CurrentByteOffset
.u
.LowPart
;
299 else if (First
|| (IrpContext
->Stack
->Flags
& SL_RESTART_SCAN
))
301 DirContext
.DirIndex
= pCcb
->Entry
= 0;
306 DirContext
.DirIndex
= pCcb
->Entry
;
310 DPRINT ("Buffer=%x tofind=%wZ\n", Buffer
, &pCcb
->SearchPattern
);
312 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
313 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
314 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
315 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
317 while (RC
== STATUS_SUCCESS
&& BufferLength
> 0)
319 RC
= FindFile (IrpContext
->DeviceExt
, pFcb
,
320 &pCcb
->SearchPattern
, &DirContext
, FirstCall
);
321 pCcb
->Entry
= DirContext
.DirIndex
;
322 DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext
.LongNameU
, RC
, pCcb
->Entry
);
326 switch (FileInformationClass
)
328 case FileNameInformation
:
329 RC
= VfatGetFileNameInformation (&DirContext
,
330 (PFILE_NAMES_INFORMATION
) Buffer
,
333 case FileDirectoryInformation
:
334 RC
= VfatGetFileDirectoryInformation (&DirContext
,
335 IrpContext
->DeviceExt
,
336 (PFILE_DIRECTORY_INFORMATION
) Buffer
,
339 case FileFullDirectoryInformation
:
340 RC
= VfatGetFileFullDirectoryInformation (&DirContext
,
341 IrpContext
->DeviceExt
,
342 (PFILE_FULL_DIRECTORY_INFORMATION
) Buffer
,
345 case FileBothDirectoryInformation
:
346 RC
= VfatGetFileBothInformation (&DirContext
,
347 IrpContext
->DeviceExt
,
348 (PFILE_BOTH_DIRECTORY_INFORMATION
) Buffer
,
352 RC
= STATUS_INVALID_INFO_CLASS
;
354 if (RC
== STATUS_BUFFER_OVERFLOW
)
358 Buffer0
->NextEntryOffset
= 0;
367 Buffer0
->NextEntryOffset
= 0;
371 RC
= STATUS_NO_SUCH_FILE
;
375 RC
= STATUS_NO_MORE_FILES
;
379 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
380 Buffer0
->FileIndex
= FileIndex
++;
381 pCcb
->Entry
= ++DirContext
.DirIndex
;
382 if (IrpContext
->Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
386 BufferLength
-= Buffer0
->NextEntryOffset
;
387 Buffer
+= Buffer0
->NextEntryOffset
;
391 Buffer0
->NextEntryOffset
= 0;
397 ExReleaseResourceLite(&pFcb
->MainResource
);
402 NTSTATUS
VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext
)
404 * FUNCTION: directory control : read/write directory informations
407 NTSTATUS RC
= STATUS_SUCCESS
;
409 switch (IrpContext
->MinorFunction
)
411 case IRP_MN_QUERY_DIRECTORY
:
412 RC
= DoQuery (IrpContext
);
414 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
415 DPRINT (" vfat, dir : change\n");
416 RC
= STATUS_NOT_IMPLEMENTED
;
420 DbgPrint ("unexpected minor function %x in VFAT driver\n",
421 IrpContext
->MinorFunction
);
422 RC
= STATUS_INVALID_DEVICE_REQUEST
;
425 if (RC
== STATUS_PENDING
)
427 RC
= VfatQueueRequest(IrpContext
);
431 IrpContext
->Irp
->IoStatus
.Status
= RC
;
432 IrpContext
->Irp
->IoStatus
.Information
= 0;
433 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
434 VfatFreeIrpContext(IrpContext
);