changes in IRP for compatibility
[reactos.git] / reactos / drivers / fs / vfat / dir.c
1 /*
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
6 * UPDATE HISTORY:
7 19-12-1998 : created
8
9 */
10
11 #include <ddk/ntddk.h>
12 #include <wchar.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #include "vfat.h"
18
19
20 // function like DosDateTimeToFileTime
21 BOOL FsdDosDateTimeToFileTime(WORD wDosDate,WORD wDosTime, TIME *FileTime)
22 {
23 PDOSTIME pdtime = (PDOSTIME)&wDosTime;
24 PDOSDATE pddate = (PDOSDATE)&wDosDate;
25 TIME_FIELDS TimeFields;
26
27 if (FileTime == NULL)
28 return FALSE;
29
30 TimeFields.Milliseconds = 0;
31 TimeFields.Second = pdtime->Second * 2;
32 TimeFields.Minute = pdtime->Minute;
33 TimeFields.Hour = pdtime->Hour;
34
35 TimeFields.Day = pddate->Day;
36 TimeFields.Month = pddate->Month;
37 TimeFields.Year = 1980 + pddate->Year;
38
39 RtlTimeFieldsToTime(&TimeFields, (PLARGE_INTEGER)FileTime);
40
41 return TRUE;
42 }
43
44
45 // function like FileTimeToDosDateTime
46 BOOL FsdFileTimeToDosDateTime(TIME *FileTime,WORD *pwDosDate,WORD *pwDosTime)
47 {
48 PDOSTIME pdtime = (PDOSTIME)pwDosTime;
49 PDOSDATE pddate = (PDOSDATE)pwDosDate;
50 TIME_FIELDS TimeFields;
51
52 if (FileTime == NULL)
53 return FALSE;
54
55 RtlTimeToTimeFields((PLARGE_INTEGER)FileTime, &TimeFields);
56
57 if (pdtime)
58 {
59 pdtime->Second = TimeFields.Second / 2;
60 pdtime->Minute = TimeFields.Minute;
61 pdtime->Hour = TimeFields.Hour;
62 }
63
64 if (pddate)
65 {
66 pddate->Day = TimeFields.Day;
67 pddate->Month = TimeFields.Month;
68 pddate->Year = TimeFields.Year - 1980;
69 }
70
71 return TRUE;
72 }
73
74
75
76 unsigned long vfat_wstrlen(PWSTR s)
77 {
78 WCHAR c=' ';
79 unsigned int len=0;
80
81 while(c!=0) {
82 c=*s;
83 s++;
84 len++;
85 };
86 s-=len;
87
88 return len-1;
89 }
90 #define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
91
92 NTSTATUS FsdGetFileNameInformation(PVFATFCB pFcb,
93 PFILE_NAMES_INFORMATION pInfo,ULONG BufferLength)
94 {
95 ULONG Length;
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;
104 }
105
106 NTSTATUS FsdGetFileDirectoryInformation(PVFATFCB pFcb,
107 PDEVICE_EXTENSION DeviceExt,
108 PFILE_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
109 {
110 unsigned long long AllocSize;
111 ULONG Length;
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;
135
136 return STATUS_SUCCESS;
137 }
138
139 NTSTATUS FsdGetFileFullDirectoryInformation(PVFATFCB pFcb,
140 PDEVICE_EXTENSION DeviceExt,
141 PFILE_FULL_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
142 {
143 unsigned long long AllocSize;
144 ULONG Length;
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;
168 // pInfo->EaSize=;
169 return STATUS_SUCCESS;
170 }
171
172 NTSTATUS FsdGetFileBothInformation(PVFATFCB pFcb,
173 PDEVICE_EXTENSION DeviceExt,
174 PFILE_BOTH_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
175 {
176 short i;
177 unsigned long long AllocSize;
178 ULONG Length;
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;
202 // pInfo->EaSize=;
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;
211 }
212
213 NTSTATUS DoQuery(PDEVICE_OBJECT DeviceObject, PIRP Irp,PIO_STACK_LOCATION Stack)
214 {
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;
223 PVFATFCB pFcb;
224 VFATFCB tmpFcb;
225 PVFATCCB pCcb;
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;
237 pFcb = pCcb->pFcb;
238 if(Stack->Flags & SL_RESTART_SCAN)
239 {//FIXME : what is really use of RestartScan ?
240 pCcb->StartEntry=pCcb->StartSector=0;
241 }
242 // determine Buffer for result :
243 if (Irp->MdlAddress)
244 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
245 else
246 Buffer = Irp->UserBuffer;
247 DPRINT("Buffer=%x tofind=%S\n",Buffer,pSearchPattern->Buffer);
248 if (pSearchPattern==NULL)
249 {
250 star[0]='*';
251 star[1]=0;
252 pCharPattern=star;
253 }
254 else pCharPattern=pSearchPattern->Buffer;
255 tmpFcb.ObjectName=tmpFcb.PathName;
256 while(RC==STATUS_SUCCESS && BufferLength >0)
257 {
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);
264 if (NT_SUCCESS(RC))
265 {
266 switch(FileInformationClass)
267 {
268 case FileNameInformation:
269 RC=FsdGetFileNameInformation(&tmpFcb
270 ,(PFILE_NAMES_INFORMATION)Buffer,BufferLength);
271 break;
272 case FileDirectoryInformation:
273 RC= FsdGetFileDirectoryInformation(&tmpFcb
274 ,DeviceExt,(PFILE_DIRECTORY_INFORMATION)Buffer,BufferLength);
275 break;
276 case FileFullDirectoryInformation :
277 RC= FsdGetFileFullDirectoryInformation(&tmpFcb
278 ,DeviceExt,(PFILE_FULL_DIRECTORY_INFORMATION)Buffer,BufferLength);
279 break;
280 case FileBothDirectoryInformation :
281 RC=FsdGetFileBothInformation(&tmpFcb
282 ,DeviceExt,(PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,BufferLength);
283 break;
284 default:
285 RC=STATUS_INVALID_INFO_CLASS;
286 }
287 }
288 else
289 {
290 if(Buffer0) Buffer0->NextEntryOffset=0;
291 break;
292 }
293 if(RC==STATUS_BUFFER_OVERFLOW)
294 {
295 if(Buffer0) Buffer0->NextEntryOffset=0;
296 pCcb->StartSector=OldSector;
297 pCcb->StartEntry=OldEntry;
298 break;
299 }
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;
305 }
306 if(Buffer0) Buffer0->NextEntryOffset=0;
307 if(FileIndex>0) return STATUS_SUCCESS;
308 return RC;
309 }
310
311
312 NTSTATUS STDCALL FsdDirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
313 /*
314 * FUNCTION: directory control : read/write directory informations
315 */
316 {
317 NTSTATUS RC = STATUS_SUCCESS;
318 PFILE_OBJECT FileObject = NULL;
319 PIO_STACK_LOCATION Stack;
320 Stack = IoGetCurrentIrpStackLocation(Irp);
321 CHECKPOINT;
322 FileObject = Stack->FileObject;
323 switch (Stack->MinorFunction)
324 {
325 case IRP_MN_QUERY_DIRECTORY:
326 RC=DoQuery(DeviceObject,Irp,Stack);
327 break;
328 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
329 DPRINT(" vfat, dir : change\n");
330 RC=STATUS_NOT_IMPLEMENTED;
331 break;
332 default:
333 // error
334 DbgPrint("unexpected minor function %x in VFAT driver\n",Stack->MinorFunction);
335 RC = STATUS_INVALID_DEVICE_REQUEST;
336 break;
337 }
338 Irp->IoStatus.Status = RC;
339 Irp->IoStatus.Information = 0;
340
341 IoCompleteRequest(Irp, IO_NO_INCREMENT);
342 return RC;
343 }
344