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
12 #include <internal/string.h>
13 #include <ddk/ntddk.h>
14 #include <ddk/cctypes.h>
15 #include <ddk/zwtypes.h>
16 //#include <ddk/rtl.h>
19 #include <internal/debug.h>
24 // function like DosDateTimeToFileTime
25 BOOL
FsdDosDateTimeToFileTime(WORD wDosDate
,WORD wDosTime
, TIME
*FileTime
)
27 PDOSTIME pdtime
= (PDOSTIME
)&wDosTime
;
28 PDOSDATE pddate
= (PDOSDATE
)&wDosDate
;
29 TIME_FIELDS TimeFields
;
34 TimeFields
.Milliseconds
= 0;
35 TimeFields
.Second
= pdtime
->Second
;
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
, (PLARGE_INTEGER
)FileTime
);
49 unsigned long vfat_wstrlen(PWSTR s
)
63 #define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
65 NTSTATUS
FsdGetFileNameInformation(PVfatFCB pFcb
,
66 PFILE_NAMES_INFORMATION pInfo
,ULONG BufferLength
)
69 Length
=vfat_wstrlen(pFcb
->ObjectName
);
70 if( (sizeof(FILE_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
71 return STATUS_BUFFER_OVERFLOW
;
72 pInfo
->FileNameLength
=Length
;
73 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
)+Length
);
74 memcpy(pInfo
->FileName
,pFcb
->ObjectName
75 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
76 return STATUS_SUCCESS
;
79 NTSTATUS
FsdGetFileDirectoryInformation(PVfatFCB pFcb
,
80 PDEVICE_EXTENSION DeviceExt
,
81 PFILE_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
83 unsigned long long AllocSize
;
85 Length
=vfat_wstrlen(pFcb
->ObjectName
);
86 if( (sizeof(FILE_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
87 return STATUS_BUFFER_OVERFLOW
;
88 pInfo
->FileNameLength
=Length
;
89 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
)+Length
);
90 memcpy(pInfo
->FileName
,pFcb
->ObjectName
91 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
93 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
94 ,&pInfo
->CreationTime
);
95 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
96 ,&pInfo
->LastAccessTime
);
97 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
98 ,&pInfo
->LastWriteTime
);
99 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
100 ,&pInfo
->ChangeTime
);
101 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
102 /* Make allocsize a rounded up multiple of BytesPerCluster */
103 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
104 DeviceExt
->BytesPerCluster
) *
105 DeviceExt
->BytesPerCluster
;
106 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
107 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
109 return STATUS_SUCCESS
;
112 NTSTATUS
FsdGetFileFullDirectoryInformation(PVfatFCB pFcb
,
113 PDEVICE_EXTENSION DeviceExt
,
114 PFILE_FULL_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
116 unsigned long long AllocSize
;
118 Length
=vfat_wstrlen(pFcb
->ObjectName
);
119 if( (sizeof(FILE_FULL_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
120 return STATUS_BUFFER_OVERFLOW
;
121 pInfo
->FileNameLength
=Length
;
122 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION
)+Length
);
123 memcpy(pInfo
->FileName
,pFcb
->ObjectName
124 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
125 // pInfo->FileIndex=;
126 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
127 ,&pInfo
->CreationTime
);
128 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
129 ,&pInfo
->LastAccessTime
);
130 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
131 ,&pInfo
->LastWriteTime
);
132 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
133 ,&pInfo
->ChangeTime
);
134 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
135 /* Make allocsize a rounded up multiple of BytesPerCluster */
136 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
137 DeviceExt
->BytesPerCluster
) *
138 DeviceExt
->BytesPerCluster
;
139 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
140 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
142 return STATUS_SUCCESS
;
145 NTSTATUS
FsdGetFileBothInformation(PVfatFCB pFcb
,
146 PDEVICE_EXTENSION DeviceExt
,
147 PFILE_BOTH_DIRECTORY_INFORMATION pInfo
,ULONG BufferLength
)
150 unsigned long long AllocSize
;
152 Length
=vfat_wstrlen(pFcb
->ObjectName
);
153 if( (sizeof(FILE_BOTH_DIRECTORY_INFORMATION
)+Length
) >BufferLength
)
154 return STATUS_BUFFER_OVERFLOW
;
155 pInfo
->FileNameLength
=Length
;
156 pInfo
->NextEntryOffset
=DWORD_ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION
)+Length
);
157 memcpy(pInfo
->FileName
,pFcb
->ObjectName
158 ,sizeof(WCHAR
)*(pInfo
->FileNameLength
));
159 // pInfo->FileIndex=;
160 FsdDosDateTimeToFileTime(pFcb
->entry
.CreationDate
,pFcb
->entry
.CreationTime
161 ,&pInfo
->CreationTime
);
162 FsdDosDateTimeToFileTime(pFcb
->entry
.AccessDate
,0
163 ,&pInfo
->LastAccessTime
);
164 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
165 ,&pInfo
->LastWriteTime
);
166 FsdDosDateTimeToFileTime(pFcb
->entry
.UpdateDate
,pFcb
->entry
.UpdateTime
167 ,&pInfo
->ChangeTime
);
168 pInfo
->EndOfFile
=RtlConvertUlongToLargeInteger(pFcb
->entry
.FileSize
);
169 /* Make allocsize a rounded up multiple of BytesPerCluster */
170 AllocSize
= ((pFcb
->entry
.FileSize
+ DeviceExt
->BytesPerCluster
- 1) /
171 DeviceExt
->BytesPerCluster
) *
172 DeviceExt
->BytesPerCluster
;
173 pInfo
->AllocationSize
.QuadPart
= AllocSize
;
174 pInfo
->FileAttributes
=pFcb
->entry
.Attrib
;
176 for (i
=0;i
<8 && (pFcb
->entry
.Filename
[i
]!=' ') ;i
++)
177 pInfo
->ShortName
[i
]=pFcb
->entry
.Filename
[i
];
178 pInfo
->ShortNameLength
=i
;
179 pInfo
->ShortName
[i
]='.';
180 for (i
=0 ;i
<3 && (pFcb
->entry
.Ext
[i
]!=' ') ;i
++)
181 pInfo
->ShortName
[i
+1+pInfo
->ShortNameLength
]=pFcb
->entry
.Ext
[i
];
182 if(i
) pInfo
->ShortNameLength
+= (i
+1);
183 return STATUS_SUCCESS
;
186 NTSTATUS
DoQuery(PDEVICE_OBJECT DeviceObject
, PIRP Irp
,PIO_STACK_LOCATION Stack
)
188 NTSTATUS RC
=STATUS_SUCCESS
;
189 long BufferLength
= 0;
190 PUNICODE_STRING pSearchPattern
= NULL
;
191 FILE_INFORMATION_CLASS FileInformationClass
;
192 unsigned long FileIndex
= 0;
193 unsigned char *Buffer
= NULL
;
194 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
195 PFILE_OBJECT pFileObject
= NULL
;
199 PDEVICE_EXTENSION DeviceExt
;
200 WCHAR star
[5],*pCharPattern
;
201 unsigned long OldEntry
,OldSector
;
202 DeviceExt
= DeviceObject
->DeviceExtension
;
203 // Obtain the callers parameters
204 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
205 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
206 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
207 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
208 pFileObject
= Stack
->FileObject
;
209 pCcb
=(PVfatCCB
)pFileObject
->FsContext2
;
211 if(Stack
->Flags
& SL_RESTART_SCAN
)
212 {//FIXME : what is really use of RestartScan ?
213 pCcb
->StartEntry
=pCcb
->StartSector
=0;
215 // determine Buffer for result :
217 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
219 Buffer
= Irp
->UserBuffer
;
220 DPRINT("Buffer=%x tofind=%w\n",Buffer
,pSearchPattern
->Buffer
);
221 if (pSearchPattern
==NULL
)
227 else pCharPattern
=pSearchPattern
->Buffer
;
228 tmpFcb
.ObjectName
=tmpFcb
.PathName
;
229 while(RC
==STATUS_SUCCESS
&& BufferLength
>0)
231 OldSector
=pCcb
->StartSector
;
232 OldEntry
=pCcb
->StartEntry
;
233 if(OldSector
)pCcb
->StartEntry
++;
234 RC
=FindFile(DeviceExt
,&tmpFcb
,pFcb
,pCharPattern
,&pCcb
->StartSector
,&pCcb
->StartEntry
);
235 DPRINT("Found %w,RC=%x, sector %x entry %x\n",tmpFcb
.ObjectName
,RC
236 ,pCcb
->StartSector
,pCcb
->StartEntry
);
239 switch(FileInformationClass
)
241 case FileNameInformation
:
242 RC
=FsdGetFileNameInformation(&tmpFcb
243 ,(PFILE_NAMES_INFORMATION
)Buffer
,BufferLength
);
245 case FileDirectoryInformation
:
246 RC
= FsdGetFileDirectoryInformation(&tmpFcb
247 ,DeviceExt
,(PFILE_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
249 case FileFullDirectoryInformation
:
250 RC
= FsdGetFileFullDirectoryInformation(&tmpFcb
251 ,DeviceExt
,(PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
253 case FileBothDirectoryInformation
:
254 RC
=FsdGetFileBothInformation(&tmpFcb
255 ,DeviceExt
,(PFILE_BOTH_DIRECTORY_INFORMATION
)Buffer
,BufferLength
);
258 RC
=STATUS_INVALID_INFO_CLASS
;
263 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
266 if(RC
==STATUS_BUFFER_OVERFLOW
)
268 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
269 pCcb
->StartSector
=OldSector
;
270 pCcb
->StartEntry
=OldEntry
;
273 Buffer0
=(PFILE_NAMES_INFORMATION
)Buffer
;
274 Buffer0
->FileIndex
=FileIndex
++;
275 if(Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
) break;
276 BufferLength
-= Buffer0
->NextEntryOffset
;
277 Buffer
+= Buffer0
->NextEntryOffset
;
279 if(Buffer0
) Buffer0
->NextEntryOffset
=0;
280 if(FileIndex
>0) return STATUS_SUCCESS
;
285 NTSTATUS
FsdDirectoryControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
287 * FUNCTION: directory control : read/write directory informations
290 NTSTATUS RC
= STATUS_SUCCESS
;
291 PFILE_OBJECT FileObject
= NULL
;
292 PIO_STACK_LOCATION Stack
;
293 Stack
= IoGetCurrentIrpStackLocation(Irp
);
295 FileObject
= Stack
->FileObject
;
296 switch (Stack
->MinorFunction
)
298 case IRP_MN_QUERY_DIRECTORY
:
299 RC
=DoQuery(DeviceObject
,Irp
,Stack
);
301 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
302 DPRINT(" vfat, dir : change\n");
303 RC
=STATUS_NOT_IMPLEMENTED
;
307 DbgPrint("unexpected minor function %x in VFAT driver\n",Stack
->MinorFunction
);
308 RC
= STATUS_INVALID_DEVICE_REQUEST
;
311 Irp
->IoStatus
.Status
= RC
;
312 Irp
->IoStatus
.Information
= 0;
314 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);