2 * $Id: dir.c,v 1.21 2001/11/02 22:44:34 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
;
228 NTSTATUS
DoQuery (PVFAT_IRP_CONTEXT IrpContext
)
230 NTSTATUS RC
= STATUS_SUCCESS
;
231 long BufferLength
= 0;
232 PUNICODE_STRING pSearchPattern
= NULL
;
233 FILE_INFORMATION_CLASS FileInformationClass
;
234 unsigned long FileIndex
= 0;
235 unsigned char *Buffer
= NULL
;
236 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
240 WCHAR star
[5], *pCharPattern
;
241 unsigned long OldEntry
, OldSector
;
243 pCcb
= (PVFATCCB
) IrpContext
->FileObject
->FsContext2
;
246 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
248 return STATUS_PENDING
;
251 // Obtain the callers parameters
252 BufferLength
= IrpContext
->Stack
->Parameters
.QueryDirectory
.Length
;
253 pSearchPattern
= IrpContext
->Stack
->Parameters
.QueryDirectory
.FileName
;
254 FileInformationClass
=
255 IrpContext
->Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
256 FileIndex
= IrpContext
->Stack
->Parameters
.QueryDirectory
.FileIndex
;
257 if (IrpContext
->Stack
->Flags
& SL_RESTART_SCAN
)
258 { //FIXME : what is really use of RestartScan ?
259 pCcb
->StartEntry
= pCcb
->StartSector
= 0;
261 // determine Buffer for result :
262 if (IrpContext
->Irp
->MdlAddress
)
263 Buffer
= MmGetSystemAddressForMdl (IrpContext
->Irp
->MdlAddress
);
265 Buffer
= IrpContext
->Irp
->UserBuffer
;
266 DPRINT ("Buffer=%x tofind=%S\n", Buffer
, pSearchPattern
->Buffer
);
267 if (pSearchPattern
== NULL
)
274 pCharPattern
= pSearchPattern
->Buffer
;
275 tmpFcb
.ObjectName
= tmpFcb
.PathName
;
276 while (RC
== STATUS_SUCCESS
&& BufferLength
> 0)
278 OldSector
= pCcb
->StartSector
;
279 OldEntry
= pCcb
->StartEntry
;
283 FindFile (IrpContext
->DeviceExt
, &tmpFcb
, pFcb
, pCharPattern
, &pCcb
->StartEntry
, NULL
);
284 pCcb
->StartSector
= 1;
285 DPRINT ("Found %S,RC=%x, sector %x entry %x\n", tmpFcb
.ObjectName
, RC
,
286 pCcb
->StartSector
, pCcb
->StartEntry
);
289 switch (FileInformationClass
)
291 case FileNameInformation
:
293 VfatGetFileNameInformation (&tmpFcb
,
294 (PFILE_NAMES_INFORMATION
) Buffer
,
297 case FileDirectoryInformation
:
299 VfatGetFileDirectoryInformation (&tmpFcb
, IrpContext
->DeviceExt
,
300 (PFILE_DIRECTORY_INFORMATION
)
301 Buffer
, BufferLength
);
303 case FileFullDirectoryInformation
:
305 VfatGetFileFullDirectoryInformation (&tmpFcb
, IrpContext
->DeviceExt
,
306 (PFILE_FULL_DIRECTORY_INFORMATION
)
307 Buffer
, BufferLength
);
309 case FileBothDirectoryInformation
:
311 VfatGetFileBothInformation (&tmpFcb
, IrpContext
->DeviceExt
,
312 (PFILE_BOTH_DIRECTORY_INFORMATION
)
313 Buffer
, BufferLength
);
316 RC
= STATUS_INVALID_INFO_CLASS
;
322 Buffer0
->NextEntryOffset
= 0;
325 if (RC
== STATUS_BUFFER_OVERFLOW
)
328 Buffer0
->NextEntryOffset
= 0;
329 pCcb
->StartSector
= OldSector
;
330 pCcb
->StartEntry
= OldEntry
;
333 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
334 Buffer0
->FileIndex
= FileIndex
++;
335 if (IrpContext
->Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
337 BufferLength
-= Buffer0
->NextEntryOffset
;
338 Buffer
+= Buffer0
->NextEntryOffset
;
341 Buffer0
->NextEntryOffset
= 0;
345 if (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)
347 ExReleaseResourceLite(&pFcb
->MainResource
);
354 NTSTATUS
VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext
)
356 * FUNCTION: directory control : read/write directory informations
359 NTSTATUS RC
= STATUS_SUCCESS
;
361 switch (IrpContext
->MinorFunction
)
363 case IRP_MN_QUERY_DIRECTORY
:
364 RC
= DoQuery (IrpContext
);
366 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
367 DPRINT (" vfat, dir : change\n");
368 RC
= STATUS_NOT_IMPLEMENTED
;
372 DbgPrint ("unexpected minor function %x in VFAT driver\n",
373 IrpContext
->MinorFunction
);
374 RC
= STATUS_INVALID_DEVICE_REQUEST
;
377 if (RC
== STATUS_PENDING
)
379 RC
= VfatQueueRequest(IrpContext
);
383 IrpContext
->Irp
->IoStatus
.Status
= RC
;
384 IrpContext
->Irp
->IoStatus
.Information
= 0;
385 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
386 VfatFreeIrpContext(IrpContext
);