2 * $Id: dir.c,v 1.20 2001/10/10 22:13:26 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
);
104 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
)) > BufferLength
)
105 return STATUS_BUFFER_OVERFLOW
;
106 pInfo
->FileNameLength
= Length
;
107 pInfo
->NextEntryOffset
=
108 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
));
109 memcpy (pInfo
->FileName
, pFcb
->ObjectName
,
110 sizeof (WCHAR
) * (pInfo
->FileNameLength
));
111 return STATUS_SUCCESS
;
115 VfatGetFileDirectoryInformation (PVFATFCB pFcb
,
116 PDEVICE_EXTENSION DeviceExt
,
117 PFILE_DIRECTORY_INFORMATION pInfo
,
120 unsigned long long AllocSize
;
122 Length
= vfat_wstrlen (pFcb
->ObjectName
);
123 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
)) > BufferLength
)
124 return STATUS_BUFFER_OVERFLOW
;
125 pInfo
->FileNameLength
= Length
;
126 pInfo
->NextEntryOffset
=
127 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
));
128 memcpy (pInfo
->FileName
, pFcb
->ObjectName
,
129 sizeof (WCHAR
) * (pInfo
->FileNameLength
));
130 // pInfo->FileIndex=;
131 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
132 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
133 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
134 &pInfo
->LastAccessTime
);
135 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
136 &pInfo
->LastWriteTime
);
137 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
139 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
140 /* Make allocsize a rounded up multiple of BytesPerCluster */
141 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
142 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
143 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
144 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
146 return STATUS_SUCCESS
;
150 VfatGetFileFullDirectoryInformation (PVFATFCB pFcb
,
151 PDEVICE_EXTENSION DeviceExt
,
152 PFILE_FULL_DIRECTORY_INFORMATION pInfo
,
155 unsigned long long AllocSize
;
157 Length
= vfat_wstrlen (pFcb
->ObjectName
);
158 if ((sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
)) > BufferLength
)
159 return STATUS_BUFFER_OVERFLOW
;
160 pInfo
->FileNameLength
= Length
;
161 pInfo
->NextEntryOffset
=
162 DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
));
163 memcpy (pInfo
->FileName
, pFcb
->ObjectName
,
164 sizeof (WCHAR
) * (pInfo
->FileNameLength
));
165 // pInfo->FileIndex=;
166 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
167 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
168 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
169 &pInfo
->LastAccessTime
);
170 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
171 &pInfo
->LastWriteTime
);
172 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
174 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
175 /* Make allocsize a rounded up multiple of BytesPerCluster */
176 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
177 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
178 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
179 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
181 return STATUS_SUCCESS
;
185 VfatGetFileBothInformation (PVFATFCB pFcb
,
186 PDEVICE_EXTENSION DeviceExt
,
187 PFILE_BOTH_DIRECTORY_INFORMATION pInfo
,
191 unsigned long long AllocSize
;
193 Length
= vfat_wstrlen (pFcb
->ObjectName
);
194 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
)) > BufferLength
)
195 return STATUS_BUFFER_OVERFLOW
;
196 pInfo
->FileNameLength
= Length
;
197 pInfo
->NextEntryOffset
=
198 DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION
) + Length
* sizeof(WCHAR
));
199 memcpy (pInfo
->FileName
, pFcb
->ObjectName
,
200 sizeof (WCHAR
) * (pInfo
->FileNameLength
));
201 // pInfo->FileIndex=;
202 FsdDosDateTimeToFileTime (pFcb
->entry
.CreationDate
,
203 pFcb
->entry
.CreationTime
, &pInfo
->CreationTime
);
204 FsdDosDateTimeToFileTime (pFcb
->entry
.AccessDate
, 0,
205 &pInfo
->LastAccessTime
);
206 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
207 &pInfo
->LastWriteTime
);
208 FsdDosDateTimeToFileTime (pFcb
->entry
.UpdateDate
, pFcb
->entry
.UpdateTime
,
210 pInfo
->EndOfFile
= RtlConvertUlongToLargeInteger (pFcb
->entry
.FileSize
);
211 /* Make allocsize a rounded up multiple of BytesPerCluster */
212 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
213 DeviceExt
->BytesPerCluster
) * DeviceExt
->BytesPerCluster
;
214 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
215 pInfo
->FileAttributes
= pFcb
->entry
.Attrib
;
217 for (i
= 0; i
< 8 && (pFcb
->entry
.Filename
[i
] != ' '); i
++)
218 pInfo
->ShortName
[i
] = pFcb
->entry
.Filename
[i
];
219 pInfo
->ShortNameLength
= i
;
220 pInfo
->ShortName
[i
] = '.';
221 for (i
= 0; i
< 3 && (pFcb
->entry
.Ext
[i
] != ' '); i
++)
222 pInfo
->ShortName
[i
+ 1 + pInfo
->ShortNameLength
] = pFcb
->entry
.Ext
[i
];
224 pInfo
->ShortNameLength
+= (i
+ 1);
225 return STATUS_SUCCESS
;
229 DoQuery (PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PIO_STACK_LOCATION Stack
)
231 NTSTATUS RC
= STATUS_SUCCESS
;
232 long BufferLength
= 0;
233 PUNICODE_STRING pSearchPattern
= NULL
;
234 FILE_INFORMATION_CLASS FileInformationClass
;
235 unsigned long FileIndex
= 0;
236 unsigned char *Buffer
= NULL
;
237 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
238 PFILE_OBJECT pFileObject
= NULL
;
242 PDEVICE_EXTENSION DeviceExt
;
243 WCHAR star
[5], *pCharPattern
;
244 unsigned long OldEntry
, OldSector
;
245 DeviceExt
= DeviceObject
->DeviceExtension
;
246 // Obtain the callers parameters
247 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
248 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
249 FileInformationClass
=
250 Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
251 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
252 pFileObject
= Stack
->FileObject
;
253 pCcb
= (PVFATCCB
) pFileObject
->FsContext2
;
255 if (Stack
->Flags
& SL_RESTART_SCAN
)
256 { //FIXME : what is really use of RestartScan ?
257 pCcb
->StartEntry
= pCcb
->StartSector
= 0;
259 // determine Buffer for result :
261 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
263 Buffer
= Irp
->UserBuffer
;
264 DPRINT ("Buffer=%x tofind=%S\n", Buffer
, pSearchPattern
->Buffer
);
265 if (pSearchPattern
== NULL
)
272 pCharPattern
= pSearchPattern
->Buffer
;
273 tmpFcb
.ObjectName
= tmpFcb
.PathName
;
274 while (RC
== STATUS_SUCCESS
&& BufferLength
> 0)
276 OldSector
= pCcb
->StartSector
;
277 OldEntry
= pCcb
->StartEntry
;
281 FindFile (DeviceExt
, &tmpFcb
, pFcb
, pCharPattern
, &pCcb
->StartEntry
, NULL
);
282 pCcb
->StartSector
= 1;
283 DPRINT ("Found %S,RC=%x, sector %x entry %x\n", tmpFcb
.ObjectName
, RC
,
284 pCcb
->StartSector
, pCcb
->StartEntry
);
287 switch (FileInformationClass
)
289 case FileNameInformation
:
291 VfatGetFileNameInformation (&tmpFcb
,
292 (PFILE_NAMES_INFORMATION
) Buffer
,
295 case FileDirectoryInformation
:
297 VfatGetFileDirectoryInformation (&tmpFcb
, DeviceExt
,
298 (PFILE_DIRECTORY_INFORMATION
)
299 Buffer
, BufferLength
);
301 case FileFullDirectoryInformation
:
303 VfatGetFileFullDirectoryInformation (&tmpFcb
, DeviceExt
,
304 (PFILE_FULL_DIRECTORY_INFORMATION
)
305 Buffer
, BufferLength
);
307 case FileBothDirectoryInformation
:
309 VfatGetFileBothInformation (&tmpFcb
, DeviceExt
,
310 (PFILE_BOTH_DIRECTORY_INFORMATION
)
311 Buffer
, BufferLength
);
314 RC
= STATUS_INVALID_INFO_CLASS
;
320 Buffer0
->NextEntryOffset
= 0;
323 if (RC
== STATUS_BUFFER_OVERFLOW
)
326 Buffer0
->NextEntryOffset
= 0;
327 pCcb
->StartSector
= OldSector
;
328 pCcb
->StartEntry
= OldEntry
;
331 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
332 Buffer0
->FileIndex
= FileIndex
++;
333 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
335 BufferLength
-= Buffer0
->NextEntryOffset
;
336 Buffer
+= Buffer0
->NextEntryOffset
;
339 Buffer0
->NextEntryOffset
= 0;
341 return STATUS_SUCCESS
;
347 VfatDirectoryControl (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
349 * FUNCTION: directory control : read/write directory informations
352 NTSTATUS RC
= STATUS_SUCCESS
;
353 PFILE_OBJECT FileObject
= NULL
;
354 PIO_STACK_LOCATION Stack
;
355 Stack
= IoGetCurrentIrpStackLocation (Irp
);
357 FileObject
= Stack
->FileObject
;
358 switch (Stack
->MinorFunction
)
360 case IRP_MN_QUERY_DIRECTORY
:
361 RC
= DoQuery (DeviceObject
, Irp
, Stack
);
363 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
364 DPRINT (" vfat, dir : change\n");
365 RC
= STATUS_NOT_IMPLEMENTED
;
369 DbgPrint ("unexpected minor function %x in VFAT driver\n",
370 Stack
->MinorFunction
);
371 RC
= STATUS_INVALID_DEVICE_REQUEST
;
374 Irp
->IoStatus
.Status
= RC
;
375 Irp
->IoStatus
.Information
= 0;
377 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);