2 * $Id: dir.c,v 1.23 2002/02/05 21:31:03 hbirr Exp $
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/dir.c
7 * PURPOSE: VFAT Filesystem : directory control
13 #include <ddk/ntddk.h>
22 // function like DosDateTimeToFileTime
23 BOOL
FsdDosDateTimeToFileTime (WORD wDosDate
, WORD wDosTime
, TIME
* FileTime
)
25 PDOSTIME pdtime
= (PDOSTIME
) & wDosTime
;
26 PDOSDATE pddate
= (PDOSDATE
) & wDosDate
;
27 TIME_FIELDS TimeFields
;
32 TimeFields
.Milliseconds
= 0;
33 TimeFields
.Second
= pdtime
->Second
* 2;
34 TimeFields
.Minute
= pdtime
->Minute
;
35 TimeFields
.Hour
= pdtime
->Hour
;
37 TimeFields
.Day
= pddate
->Day
;
38 TimeFields
.Month
= pddate
->Month
;
39 TimeFields
.Year
= 1980 + pddate
->Year
;
41 RtlTimeFieldsToTime (&TimeFields
, (PLARGE_INTEGER
) FileTime
);
47 // function like FileTimeToDosDateTime
49 FsdFileTimeToDosDateTime (TIME
* FileTime
, WORD
* pwDosDate
, WORD
* pwDosTime
)
51 PDOSTIME pdtime
= (PDOSTIME
) pwDosTime
;
52 PDOSDATE pddate
= (PDOSDATE
) pwDosDate
;
53 TIME_FIELDS TimeFields
;
58 RtlTimeToTimeFields ((PLARGE_INTEGER
) FileTime
, &TimeFields
);
62 pdtime
->Second
= TimeFields
.Second
/ 2;
63 pdtime
->Minute
= TimeFields
.Minute
;
64 pdtime
->Hour
= TimeFields
.Hour
;
69 pddate
->Day
= TimeFields
.Day
;
70 pddate
->Month
= TimeFields
.Month
;
71 pddate
->Year
= TimeFields
.Year
- 1980;
80 vfat_wstrlen (PWSTR s
)
96 #define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
99 VfatGetFileNameInformation (PVFATFCB pFcb
,
100 PFILE_NAMES_INFORMATION pInfo
, ULONG BufferLength
)
103 Length
= vfat_wstrlen (pFcb
->ObjectName
) * sizeof(WCHAR
);
104 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
105 return STATUS_BUFFER_OVERFLOW
;
106 pInfo
->FileNameLength
= Length
;
107 pInfo
->NextEntryOffset
=
108 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + Length
);
109 memcpy (pInfo
->FileName
, pFcb
->ObjectName
, Length
);
110 return STATUS_SUCCESS
;
114 VfatGetFileDirectoryInformation (PVFATFCB pFcb
,
115 PDEVICE_EXTENSION DeviceExt
,
116 PFILE_DIRECTORY_INFORMATION pInfo
,
119 unsigned long long AllocSize
;
121 Length
= vfat_wstrlen (pFcb
->ObjectName
) * sizeof(WCHAR
);
122 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
123 return STATUS_BUFFER_OVERFLOW
;
124 pInfo
->FileNameLength
= Length
;
125 pInfo
->NextEntryOffset
=
126 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + Length
);
127 memcpy (pInfo
->FileName
, pFcb
->ObjectName
, Length
);
128 // pInfo->FileIndex=;
129 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
130 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
131 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
132 &pInfo
->LastAccessTime
);
133 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
134 &pInfo
->LastWriteTime
);
135 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
137 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
138 /* Make allocsize a rounded up multiple of BytesPerCluster */
139 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
140 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
141 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
142 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
144 return STATUS_SUCCESS
;
148 VfatGetFileFullDirectoryInformation (PVFATFCB pFcb
,
149 PDEVICE_EXTENSION DeviceExt
,
150 PFILE_FULL_DIRECTORY_INFORMATION pInfo
,
153 unsigned long long AllocSize
;
155 Length
= vfat_wstrlen (pFcb
->ObjectName
) * sizeof(WCHAR
);
156 if ((sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
157 return STATUS_BUFFER_OVERFLOW
;
158 pInfo
->FileNameLength
= Length
;
159 pInfo
->NextEntryOffset
=
160 DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + Length
);
161 memcpy (pInfo
->FileName
, pFcb
->ObjectName
, Length
);
162 // pInfo->FileIndex=;
163 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
164 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
165 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
166 &pInfo
->LastAccessTime
);
167 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
168 &pInfo
->LastWriteTime
);
169 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
171 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
172 /* Make allocsize a rounded up multiple of BytesPerCluster */
173 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
174 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
175 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
176 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
178 return STATUS_SUCCESS
;
182 VfatGetFileBothInformation (PVFATFCB pFcb
,
183 PDEVICE_EXTENSION DeviceExt
,
184 PFILE_BOTH_DIRECTORY_INFORMATION pInfo
,
188 unsigned long long AllocSize
;
190 Length
= vfat_wstrlen (pFcb
->ObjectName
) * sizeof(WCHAR
);
191 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
192 return STATUS_BUFFER_OVERFLOW
;
193 pInfo
->FileNameLength
= Length
;
194 pInfo
->NextEntryOffset
=
195 DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
);
196 memcpy (pInfo
->FileName
, pFcb
->ObjectName
, Length
);
197 // pInfo->FileIndex=;
198 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
199 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
200 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
201 &pInfo
->LastAccessTime
);
202 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
203 &pInfo
->LastWriteTime
);
204 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
206 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
207 /* Make allocsize a rounded up multiple of BytesPerCluster */
208 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
209 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
210 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
211 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
213 for (i
= 0; i
< 8 && (pFcb
->entry
.Filename
[i
] != ' '); i
++)
214 pInfo
->ShortName
[i
] = pFcb
->entry
.Filename
[i
];
215 pInfo
->ShortNameLength
= i
;
216 pInfo
->ShortName
[i
] = '.';
217 for (i
= 0; i
< 3 && (pFcb
->entry
.Ext
[i
] != ' '); i
++)
218 pInfo
->ShortName
[i
+ 1 + pInfo
->ShortNameLength
] = pFcb
->entry
.Ext
[i
];
220 pInfo
->ShortNameLength
+= (i
+ 1);
221 pInfo
->ShortNameLength
*= sizeof(WCHAR
);
222 return STATUS_SUCCESS
;
225 NTSTATUS
DoQuery (PVFAT_IRP_CONTEXT IrpContext
)
227 NTSTATUS RC
= STATUS_SUCCESS
;
228 long BufferLength
= 0;
229 PUNICODE_STRING pSearchPattern
= NULL
;
230 FILE_INFORMATION_CLASS FileInformationClass
;
231 unsigned long FileIndex
= 0;
232 unsigned char *Buffer
= NULL
;
233 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
237 BOOLEAN First
= FALSE
;
239 pCcb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
242 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
244 return STATUS_PENDING
;
247 // Obtain the callers parameters
248 BufferLength
= IrpContext
->Stack
->Parameters
.QueryDirectory
.Length
;
249 pSearchPattern
= IrpContext
->Stack
->Parameters
.QueryDirectory
.FileName
;
250 FileInformationClass
=
251 IrpContext
->Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
252 FileIndex
= IrpContext
->Stack
->Parameters
.QueryDirectory
.FileIndex
;
255 if (!pCcb
->DirectorySearchPattern
)
258 pCcb
->DirectorySearchPattern
=
259 ExAllocatePool(NonPagedPool
, pSearchPattern
->Length
+ sizeof(WCHAR
));
260 if (!pCcb
->DirectorySearchPattern
)
262 return STATUS_INSUFFICIENT_RESOURCES
;
264 memcpy(pCcb
->DirectorySearchPattern
, pSearchPattern
->Buffer
,
265 pSearchPattern
->Length
);
266 pCcb
->DirectorySearchPattern
[pSearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
269 else if (!pCcb
->DirectorySearchPattern
)
272 pCcb
->DirectorySearchPattern
= ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
273 if (!pCcb
->DirectorySearchPattern
)
275 return STATUS_INSUFFICIENT_RESOURCES
;
277 pCcb
->DirectorySearchPattern
[0] = L
'*';
278 pCcb
->DirectorySearchPattern
[1] = 0;
281 if (IrpContext
->Stack
->Flags
& SL_INDEX_SPECIFIED
)
283 pCcb
->Entry
= pCcb
->CurrentByteOffset
.u
.LowPart
;
285 else if (First
|| (IrpContext
->Stack
->Flags
& SL_RESTART_SCAN
))
289 // determine Buffer for result :
290 if (IrpContext
->Irp
->MdlAddress
)
292 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
296 Buffer
= IrpContext
->Irp
->UserBuffer
;
298 DPRINT ("Buffer=%x tofind=%S\n", Buffer
, pCcb
->DirectorySearchPattern
);
300 tmpFcb
.ObjectName
= tmpFcb
.PathName
;
301 while (RC
== STATUS_SUCCESS
&& BufferLength
> 0)
303 RC
= FindFile (IrpContext
->DeviceExt
, &tmpFcb
, pFcb
,
304 pCcb
->DirectorySearchPattern
, &pCcb
->Entry
, NULL
);
305 DPRINT ("Found %S, RC=%x, entry %x\n", tmpFcb
.ObjectName
, RC
, pCcb
->Entry
);
308 switch (FileInformationClass
)
310 case FileNameInformation
:
311 RC
= VfatGetFileNameInformation (&tmpFcb
,
312 (PFILE_NAMES_INFORMATION
) Buffer
, BufferLength
);
314 case FileDirectoryInformation
:
315 RC
= VfatGetFileDirectoryInformation (&tmpFcb
, IrpContext
->DeviceExt
,
316 (PFILE_DIRECTORY_INFORMATION
) Buffer
, BufferLength
);
318 case FileFullDirectoryInformation
:
319 RC
= VfatGetFileFullDirectoryInformation (&tmpFcb
, IrpContext
->DeviceExt
,
320 (PFILE_FULL_DIRECTORY_INFORMATION
) Buffer
, BufferLength
);
322 case FileBothDirectoryInformation
:
323 RC
= VfatGetFileBothInformation (&tmpFcb
, IrpContext
->DeviceExt
,
324 (PFILE_BOTH_DIRECTORY_INFORMATION
) Buffer
, BufferLength
);
327 RC
= STATUS_INVALID_INFO_CLASS
;
329 if (RC
== STATUS_BUFFER_OVERFLOW
)
333 Buffer0
->NextEntryOffset
= 0;
342 Buffer0
->NextEntryOffset
= 0;
346 RC
= STATUS_NO_SUCH_FILE
;
350 RC
= STATUS_NO_MORE_FILES
;
354 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
355 Buffer0
->FileIndex
= FileIndex
++;
357 if (IrpContext
->Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
361 BufferLength
-= Buffer0
->NextEntryOffset
;
362 Buffer
+= Buffer0
->NextEntryOffset
;
366 Buffer0
->NextEntryOffset
= 0;
372 if (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)
374 ExReleaseResourceLite(&pFcb
->MainResource
);
381 NTSTATUS
VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext
)
383 * FUNCTION: directory control : read/write directory informations
386 NTSTATUS RC
= STATUS_SUCCESS
;
388 switch (IrpContext
->MinorFunction
)
390 case IRP_MN_QUERY_DIRECTORY
:
391 RC
= DoQuery (IrpContext
);
393 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
394 DPRINT (" vfat, dir : change\n");
395 RC
= STATUS_NOT_IMPLEMENTED
;
399 DbgPrint ("unexpected minor function %x in VFAT driver\n",
400 IrpContext
->MinorFunction
);
401 RC
= STATUS_INVALID_DEVICE_REQUEST
;
404 if (RC
== STATUS_PENDING
)
406 RC
= VfatQueueRequest(IrpContext
);
410 IrpContext
->Irp
->IoStatus
.Status
= RC
;
411 IrpContext
->Irp
->IoStatus
.Information
= 0;
412 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
413 VfatFreeIrpContext(IrpContext
);