2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: services/fs/vfat/dir.c
5 * PURPOSE: VFAT Filesystem : directory control
11 #include <ddk/ntddk.h>
20 // function like DosDateTimeToFileTime
21 BOOL
FsdDosDateTimeToFileTime(WORD wDosDate
,WORD wDosTime
, TIME
*FileTime
)
23 PDOSTIME pdtime
= (PDOSTIME
)&wDosTime
;
24 PDOSDATE pddate
= (PDOSDATE
)&wDosDate
;
25 TIME_FIELDS TimeFields
;
30 TimeFields
.Milliseconds
= 0;
31 TimeFields
.Second
= pdtime
->Second
* 2;
32 TimeFields
.Minute
= pdtime
->Minute
;
33 TimeFields
.Hour
= pdtime
->Hour
;
35 TimeFields
.Day
= pddate
->Day
;
36 TimeFields
.Month
= pddate
->Month
;
37 TimeFields
.Year
= 1980 + pddate
->Year
;
39 RtlTimeFieldsToTime(&TimeFields
, (PLARGE_INTEGER
)FileTime
);
45 // function like FileTimeToDosDateTime
46 BOOL
FsdFileTimeToDosDateTime(TIME
*FileTime
,WORD
*pwDosDate
,WORD
*pwDosTime
)
48 PDOSTIME pdtime
= (PDOSTIME
)pwDosTime
;
49 PDOSDATE pddate
= (PDOSDATE
)pwDosDate
;
50 TIME_FIELDS TimeFields
;
55 RtlTimeToTimeFields((PLARGE_INTEGER
)FileTime
, &TimeFields
);
59 pdtime
->Second
= TimeFields
.Second
/ 2;
60 pdtime
->Minute
= TimeFields
.Minute
;
61 pdtime
->Hour
= TimeFields
.Hour
;
66 pddate
->Day
= TimeFields
.Day
;
67 pddate
->Month
= TimeFields
.Month
;
68 pddate
->Year
= TimeFields
.Year
- 1980;
76 unsigned long vfat_wstrlen(PWSTR s
)
90 #define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
92 NTSTATUS
FsdGetFileNameInformation(PVFATFCB pFcb
,
93 PFILE_NAMES_INFORMATION pInfo
,ULONG BufferLength
)
96 Length
=vfat_wstrlen(pFcb
->ObjectName
);
97 if( (sizeof(FILE_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
98 return STATUS_BUFFER_OVERFLOW
;
99 pInfo
->FileNameLength
=Length
;
100 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
)+Length
);
101 memcpy(pInfo
->FileName
,pFcb
->ObjectName
102 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
103 return STATUS_SUCCESS
;
106 NTSTATUS
FsdGetFileDirectoryInformation(PVFATFCB pFcb
,
107 PDEVICE_EXTENSION DeviceExt
,
108 PFILE_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
110 unsigned long long AllocSize
;
112 Length
=vfat_wstrlen(pFcb
->ObjectName
);
113 if( (sizeof(FILE_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
114 return STATUS_BUFFER_OVERFLOW
;
115 pInfo
->FileNameLength
=Length
;
116 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
)+Length
);
117 memcpy(pInfo
->FileName
,pFcb
->ObjectName
118 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
119 // pInfo->FileIndex=;
120 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
121 ,&pInfo
->CreationTime
);
122 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
123 ,&pInfo
->LastAccessTime
);
124 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
125 ,&pInfo
->LastWriteTime
);
126 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
127 ,&pInfo
->ChangeTime
);
128 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
129 /* Make allocsize a rounded up multiple of BytesPerCluster */
130 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
131 DeviceExt
->BytesPerCluster
) *
132 DeviceExt
->BytesPerCluster
;
133 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
134 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
136 return STATUS_SUCCESS
;
139 NTSTATUS
FsdGetFileFullDirectoryInformation(PVFATFCB pFcb
,
140 PDEVICE_EXTENSION DeviceExt
,
141 PFILE_FULL_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
143 unsigned long long AllocSize
;
145 Length
=vfat_wstrlen(pFcb
->ObjectName
);
146 if( (sizeof(FILE_FULL_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
147 return STATUS_BUFFER_OVERFLOW
;
148 pInfo
->FileNameLength
=Length
;
149 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION
)+Length
);
150 memcpy(pInfo
->FileName
,pFcb
->ObjectName
151 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
152 // pInfo->FileIndex=;
153 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
154 ,&pInfo
->CreationTime
);
155 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
156 ,&pInfo
->LastAccessTime
);
157 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
158 ,&pInfo
->LastWriteTime
);
159 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
160 ,&pInfo
->ChangeTime
);
161 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
162 /* Make allocsize a rounded up multiple of BytesPerCluster */
163 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
164 DeviceExt
->BytesPerCluster
) *
165 DeviceExt
->BytesPerCluster
;
166 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
167 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
169 return STATUS_SUCCESS
;
172 NTSTATUS
FsdGetFileBothInformation(PVFATFCB pFcb
,
173 PDEVICE_EXTENSION DeviceExt
,
174 PFILE_BOTH_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
177 unsigned long long AllocSize
;
179 Length
=vfat_wstrlen(pFcb
->ObjectName
);
180 if( (sizeof(FILE_BOTH_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
181 return STATUS_BUFFER_OVERFLOW
;
182 pInfo
->FileNameLength
=Length
;
183 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
)+Length
);
184 memcpy(pInfo
->FileName
,pFcb
->ObjectName
185 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
186 // pInfo->FileIndex=;
187 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
188 ,&pInfo
->CreationTime
);
189 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
190 ,&pInfo
->LastAccessTime
);
191 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
192 ,&pInfo
->LastWriteTime
);
193 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
194 ,&pInfo
->ChangeTime
);
195 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
196 /* Make allocsize a rounded up multiple of BytesPerCluster */
197 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
198 DeviceExt
->BytesPerCluster
) *
199 DeviceExt
->BytesPerCluster
;
200 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
201 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
203 for (i
=0;i
<8 && (pFcb
->entry
.Filename
[i
]!=' ') ;i
++)
204 pInfo
->ShortName
[i
]=pFcb
->entry
.Filename
[i
];
205 pInfo
->ShortNameLength
=i
;
206 pInfo
->ShortName
[i
]='.';
207 for (i
=0 ;i
<3 && (pFcb
->entry
.Ext
[i
]!=' ') ;i
++)
208 pInfo
->ShortName
[i
+1+pInfo
->ShortNameLength
]=pFcb
->entry
.Ext
[i
];
209 if(i
) pInfo
->ShortNameLength
+= (i
+1);
210 return STATUS_SUCCESS
;
213 NTSTATUS
DoQuery(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,PIO_STACK_LOCATION Stack
)
215 NTSTATUS RC
=STATUS_SUCCESS
;
216 long BufferLength
= 0;
217 PUNICODE_STRING pSearchPattern
= NULL
;
218 FILE_INFORMATION_CLASS FileInformationClass
;
219 unsigned long FileIndex
= 0;
220 unsigned char *Buffer
= NULL
;
221 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
222 PFILE_OBJECT pFileObject
= NULL
;
226 PDEVICE_EXTENSION DeviceExt
;
227 WCHAR star
[5],*pCharPattern
;
228 unsigned long OldEntry
,OldSector
;
229 DeviceExt
= DeviceObject
->DeviceExtension
;
230 // Obtain the callers parameters
231 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
232 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
233 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
234 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
235 pFileObject
= Stack
->FileObject
;
236 pCcb
=(PVFATCCB
)pFileObject
->FsContext2
;
238 if(Stack
->Flags
& SL_RESTART_SCAN
)
239 {//FIXME : what is really use of RestartScan ?
240 pCcb
->StartEntry
=pCcb
->StartSector
=0;
242 // determine Buffer for result :
244 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
246 Buffer
= Irp
->UserBuffer
;
247 DPRINT("Buffer=%x tofind=%S\n",Buffer
,pSearchPattern
->Buffer
);
248 if (pSearchPattern
==NULL
)
254 else pCharPattern
=pSearchPattern
->Buffer
;
255 tmpFcb
.ObjectName
=tmpFcb
.PathName
;
256 while(RC
==STATUS_SUCCESS
&& BufferLength
>0)
258 OldSector
=pCcb
->StartSector
;
259 OldEntry
=pCcb
->StartEntry
;
260 if(OldSector
)pCcb
->StartEntry
++;
261 RC
=FindFile(DeviceExt
,&tmpFcb
,pFcb
,pCharPattern
,&pCcb
->StartSector
,&pCcb
->StartEntry
);
262 DPRINT("Found %S,RC=%x, sector %x entry %x\n",tmpFcb
.ObjectName
,RC
263 ,pCcb
->StartSector
,pCcb
->StartEntry
);
266 switch(FileInformationClass
)
268 case FileNameInformation
:
269 RC
=FsdGetFileNameInformation(&tmpFcb
270 ,(PFILE_NAMES_INFORMATION
)Buffer
,BufferLength
);
272 case FileDirectoryInformation
:
273 RC
= FsdGetFileDirectoryInformation(&tmpFcb
274 ,DeviceExt
,(PFILE_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
276 case FileFullDirectoryInformation
:
277 RC
= FsdGetFileFullDirectoryInformation(&tmpFcb
278 ,DeviceExt
,(PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
280 case FileBothDirectoryInformation
:
281 RC
=FsdGetFileBothInformation(&tmpFcb
282 ,DeviceExt
,(PFILE_BOTH_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
285 RC
=STATUS_INVALID_INFO_CLASS
;
290 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
293 if(RC
==STATUS_BUFFER_OVERFLOW
)
295 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
296 pCcb
->StartSector
=OldSector
;
297 pCcb
->StartEntry
=OldEntry
;
300 Buffer0
=(PFILE_NAMES_INFORMATION
)Buffer
;
301 Buffer0
->FileIndex
=FileIndex
++;
302 if(Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
) break;
303 BufferLength
-= Buffer0
->NextEntryOffset
;
304 Buffer
+= Buffer0
->NextEntryOffset
;
306 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
307 if(FileIndex
>0) return STATUS_SUCCESS
;
312 NTSTATUS STDCALL
FsdDirectoryControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
314 * FUNCTION: directory control : read/write directory informations
317 NTSTATUS RC
= STATUS_SUCCESS
;
318 PFILE_OBJECT FileObject
= NULL
;
319 PIO_STACK_LOCATION Stack
;
320 Stack
= IoGetCurrentIrpStackLocation(Irp
);
322 FileObject
= Stack
->FileObject
;
323 switch (Stack
->MinorFunction
)
325 case IRP_MN_QUERY_DIRECTORY
:
326 RC
=DoQuery(DeviceObject
,Irp
,Stack
);
328 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
329 DPRINT(" vfat, dir : change\n");
330 RC
=STATUS_NOT_IMPLEMENTED
;
334 DbgPrint("unexpected minor function %x in VFAT driver\n",Stack
->MinorFunction
);
335 RC
= STATUS_INVALID_DEVICE_REQUEST
;
338 Irp
->IoStatus
.Status
= RC
;
339 Irp
->IoStatus
.Information
= 0;
341 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);