Improved time functions.
[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 <wchar.h>
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>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #include "vfat.h"
22
23
24 // function like DosDateTimeToFileTime
25 BOOL FsdDosDateTimeToFileTime(WORD wDosDate,WORD wDosTime, TIME *FileTime)
26 {
27 PDOSTIME pdtime = (PDOSTIME)&wDosTime;
28 PDOSDATE pddate = (PDOSDATE)&wDosDate;
29 TIME_FIELDS TimeFields;
30
31 if (FileTime == NULL)
32 return FALSE;
33
34 TimeFields.Milliseconds = 0;
35 TimeFields.Second = pdtime->Second;
36 TimeFields.Minute = pdtime->Minute;
37 TimeFields.Hour = pdtime->Hour;
38
39 TimeFields.Day = pddate->Day;
40 TimeFields.Month = pddate->Month;
41 TimeFields.Year = 1980 + pddate->Year;
42
43 RtlTimeFieldsToTime(&TimeFields, (PLARGE_INTEGER)FileTime);
44
45 return TRUE;
46 }
47
48
49 unsigned long vfat_wstrlen(PWSTR s)
50 {
51 WCHAR c=' ';
52 unsigned int len=0;
53
54 while(c!=0) {
55 c=*s;
56 s++;
57 len++;
58 };
59 s-=len;
60
61 return len-1;
62 }
63 #define DWORD_ROUND_UP(x) ( (((ULONG)(x))%32) ? ((((ULONG)x)&(~0x1f))+0x20) : ((ULONG)x) )
64
65 NTSTATUS FsdGetFileNameInformation(PVfatFCB pFcb,
66 PFILE_NAMES_INFORMATION pInfo,ULONG BufferLength)
67 {
68 ULONG Length;
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;
77 }
78
79 NTSTATUS FsdGetFileDirectoryInformation(PVfatFCB pFcb,
80 PDEVICE_EXTENSION DeviceExt,
81 PFILE_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
82 {
83 unsigned long long AllocSize;
84 ULONG Length;
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));
92 // pInfo->FileIndex=;
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;
108
109 return STATUS_SUCCESS;
110 }
111
112 NTSTATUS FsdGetFileFullDirectoryInformation(PVfatFCB pFcb,
113 PDEVICE_EXTENSION DeviceExt,
114 PFILE_FULL_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
115 {
116 unsigned long long AllocSize;
117 ULONG Length;
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;
141 // pInfo->EaSize=;
142 return STATUS_SUCCESS;
143 }
144
145 NTSTATUS FsdGetFileBothInformation(PVfatFCB pFcb,
146 PDEVICE_EXTENSION DeviceExt,
147 PFILE_BOTH_DIRECTORY_INFORMATION pInfo,ULONG BufferLength)
148 {
149 short i;
150 unsigned long long AllocSize;
151 ULONG Length;
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;
175 // pInfo->EaSize=;
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;
184 }
185
186 NTSTATUS DoQuery(PDEVICE_OBJECT DeviceObject, PIRP Irp,PIO_STACK_LOCATION Stack)
187 {
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;
196 PVfatFCB pFcb;
197 VfatFCB tmpFcb;
198 PVfatCCB pCcb;
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;
210 pFcb = pCcb->pFcb;
211 if(Stack->Flags & SL_RESTART_SCAN)
212 {//FIXME : what is really use of RestartScan ?
213 pCcb->StartEntry=pCcb->StartSector=0;
214 }
215 // determine Buffer for result :
216 if (Irp->MdlAddress)
217 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
218 else
219 Buffer = Irp->UserBuffer;
220 DPRINT("Buffer=%x tofind=%w\n",Buffer,pSearchPattern->Buffer);
221 if (pSearchPattern==NULL)
222 {
223 star[0]='*';
224 star[1]=0;
225 pCharPattern=star;
226 }
227 else pCharPattern=pSearchPattern->Buffer;
228 tmpFcb.ObjectName=tmpFcb.PathName;
229 while(RC==STATUS_SUCCESS && BufferLength >0)
230 {
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);
237 if (NT_SUCCESS(RC))
238 {
239 switch(FileInformationClass)
240 {
241 case FileNameInformation:
242 RC=FsdGetFileNameInformation(&tmpFcb
243 ,(PFILE_NAMES_INFORMATION)Buffer,BufferLength);
244 break;
245 case FileDirectoryInformation:
246 RC= FsdGetFileDirectoryInformation(&tmpFcb
247 ,DeviceExt,(PFILE_DIRECTORY_INFORMATION)Buffer,BufferLength);
248 break;
249 case FileFullDirectoryInformation :
250 RC= FsdGetFileFullDirectoryInformation(&tmpFcb
251 ,DeviceExt,(PFILE_FULL_DIRECTORY_INFORMATION)Buffer,BufferLength);
252 break;
253 case FileBothDirectoryInformation :
254 RC=FsdGetFileBothInformation(&tmpFcb
255 ,DeviceExt,(PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,BufferLength);
256 break;
257 default:
258 RC=STATUS_INVALID_INFO_CLASS;
259 }
260 }
261 else
262 {
263 if(Buffer0) Buffer0->NextEntryOffset=0;
264 break;
265 }
266 if(RC==STATUS_BUFFER_OVERFLOW)
267 {
268 if(Buffer0) Buffer0->NextEntryOffset=0;
269 pCcb->StartSector=OldSector;
270 pCcb->StartEntry=OldEntry;
271 break;
272 }
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;
278 }
279 if(Buffer0) Buffer0->NextEntryOffset=0;
280 if(FileIndex>0) return STATUS_SUCCESS;
281 return RC;
282 }
283
284
285 NTSTATUS FsdDirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
286 /*
287 * FUNCTION: directory control : read/write directory informations
288 */
289 {
290 NTSTATUS RC = STATUS_SUCCESS;
291 PFILE_OBJECT FileObject = NULL;
292 PIO_STACK_LOCATION Stack;
293 Stack = IoGetCurrentIrpStackLocation(Irp);
294 CHECKPOINT;
295 FileObject = Stack->FileObject;
296 switch (Stack->MinorFunction)
297 {
298 case IRP_MN_QUERY_DIRECTORY:
299 RC=DoQuery(DeviceObject,Irp,Stack);
300 break;
301 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
302 DPRINT(" vfat, dir : change\n");
303 RC=STATUS_NOT_IMPLEMENTED;
304 break;
305 default:
306 // error
307 DbgPrint("unexpected minor function %x in VFAT driver\n",Stack->MinorFunction);
308 RC = STATUS_INVALID_DEVICE_REQUEST;
309 break;
310 }
311 Irp->IoStatus.Status = RC;
312 Irp->IoStatus.Information = 0;
313
314 IoCompleteRequest(Irp, IO_NO_INCREMENT);
315 return RC;
316 }
317