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;
78 #define DWORD_ROUND_UP(x) ROUND_UP((x), (sizeof(DWORD)))
81 VfatGetFileNameInformation (PVFATFCB pFcb,
82 PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength)
85 Length = wcslen (pFcb->ObjectName) * sizeof(WCHAR);
86 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
87 return STATUS_BUFFER_OVERFLOW;
88 pInfo->FileNameLength = Length;
89 pInfo->NextEntryOffset =
90 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + Length);
91 memcpy (pInfo->FileName, pFcb->ObjectName, Length);
92 return STATUS_SUCCESS;
96 VfatGetFileDirectoryInformation (PVFATFCB pFcb,
97 PDEVICE_EXTENSION DeviceExt,
98 PFILE_DIRECTORY_INFORMATION pInfo,
102 Length = wcslen (pFcb->ObjectName) * sizeof(WCHAR);
103 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
104 return STATUS_BUFFER_OVERFLOW;
105 pInfo->FileNameLength = Length;
106 pInfo->NextEntryOffset =
107 DWORD_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + Length);
108 memcpy (pInfo->FileName, pFcb->ObjectName, Length);
109 // pInfo->FileIndex=;
110 FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
111 pFcb->entry.CreationTime, &pInfo->CreationTime);
112 FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
113 &pInfo->LastAccessTime);
114 FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
115 &pInfo->LastWriteTime);
116 pInfo->ChangeTime = pInfo->LastWriteTime;
117 pInfo->EndOfFile.u.HighPart = 0;
118 pInfo->EndOfFile.u.LowPart = pFcb->entry.FileSize;
119 /* Make allocsize a rounded up multiple of BytesPerCluster */
120 pInfo->AllocationSize.u.HighPart = 0;
121 pInfo->AllocationSize.u.LowPart = ROUND_UP(pFcb->entry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
122 pInfo->FileAttributes = pFcb->entry.Attrib;
124 return STATUS_SUCCESS;
128 VfatGetFileFullDirectoryInformation (PVFATFCB pFcb,
129 PDEVICE_EXTENSION DeviceExt,
130 PFILE_FULL_DIRECTORY_INFORMATION pInfo,
134 Length = wcslen (pFcb->ObjectName) * sizeof(WCHAR);
135 if ((sizeof (FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
136 return STATUS_BUFFER_OVERFLOW;
137 pInfo->FileNameLength = Length;
138 pInfo->NextEntryOffset =
139 DWORD_ROUND_UP (sizeof (FILE_FULL_DIRECTORY_INFORMATION) + Length);
140 memcpy (pInfo->FileName, pFcb->ObjectName, Length);
141 // pInfo->FileIndex=;
142 FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
143 pFcb->entry.CreationTime, &pInfo->CreationTime);
144 FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
145 &pInfo->LastAccessTime);
146 FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
147 &pInfo->LastWriteTime);
148 pInfo->ChangeTime = pInfo->LastWriteTime;
149 pInfo->EndOfFile.u.HighPart = 0;
150 pInfo->EndOfFile.u.LowPart = pFcb->entry.FileSize;
151 /* Make allocsize a rounded up multiple of BytesPerCluster */
152 pInfo->AllocationSize.u.HighPart = 0;
153 pInfo->AllocationSize.u.LowPart = ROUND_UP(pFcb->entry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
154 pInfo->FileAttributes = pFcb->entry.Attrib;
156 return STATUS_SUCCESS;
160 VfatGetFileBothInformation (PVFATFCB pFcb,
161 PDEVICE_EXTENSION DeviceExt,
162 PFILE_BOTH_DIRECTORY_INFORMATION pInfo,
166 Length = wcslen (pFcb->ObjectName) * sizeof(WCHAR);
167 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
168 return STATUS_BUFFER_OVERFLOW;
169 pInfo->FileNameLength = Length;
170 pInfo->NextEntryOffset =
171 DWORD_ROUND_UP (sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length);
173 * vfatGetDirEntryName must be called befor the long name is copyed.
174 * The terminating null will overwrite the first character from long name.
176 vfatGetDirEntryName(&pFcb->entry, pInfo->ShortName);
177 pInfo->ShortNameLength = wcslen(pInfo->ShortName) * sizeof(WCHAR);
178 memcpy (pInfo->FileName, pFcb->ObjectName, Length);
179 // pInfo->FileIndex=;
180 FsdDosDateTimeToFileTime (pFcb->entry.CreationDate,
181 pFcb->entry.CreationTime, &pInfo->CreationTime);
182 FsdDosDateTimeToFileTime (pFcb->entry.AccessDate, 0,
183 &pInfo->LastAccessTime);
184 FsdDosDateTimeToFileTime (pFcb->entry.UpdateDate, pFcb->entry.UpdateTime,
185 &pInfo->LastWriteTime);
186 pInfo->ChangeTime = pInfo->LastWriteTime;
187 pInfo->EndOfFile.u.HighPart = 0;
188 pInfo->EndOfFile.u.LowPart = pFcb->entry.FileSize;
189 /* Make allocsize a rounded up multiple of BytesPerCluster */
190 pInfo->AllocationSize.u.HighPart = 0;
191 pInfo->AllocationSize.u.LowPart = ROUND_UP(pFcb->entry.FileSize, DeviceExt->FatInfo.BytesPerCluster);
192 pInfo->FileAttributes = pFcb->entry.Attrib;
194 return STATUS_SUCCESS;
197 NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext)
199 NTSTATUS RC = STATUS_SUCCESS;
200 long BufferLength = 0;
201 PUNICODE_STRING pSearchPattern = NULL;
202 FILE_INFORMATION_CLASS FileInformationClass;
203 unsigned long FileIndex = 0;
204 unsigned char *Buffer = NULL;
205 PFILE_NAMES_INFORMATION Buffer0 = NULL;
209 BOOLEAN First = FALSE;
211 pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2;
214 if (!ExAcquireResourceSharedLite(&pFcb->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
216 return STATUS_PENDING;
219 // Obtain the callers parameters
220 BufferLength = IrpContext->Stack->Parameters.QueryDirectory.Length;
221 pSearchPattern = IrpContext->Stack->Parameters.QueryDirectory.FileName;
222 FileInformationClass =
223 IrpContext->Stack->Parameters.QueryDirectory.FileInformationClass;
224 FileIndex = IrpContext->Stack->Parameters.QueryDirectory.FileIndex;
227 if (!pCcb->DirectorySearchPattern)
230 pCcb->DirectorySearchPattern =
231 ExAllocatePool(NonPagedPool, pSearchPattern->Length + sizeof(WCHAR));
232 if (!pCcb->DirectorySearchPattern)
234 ExReleaseResourceLite(&pFcb->MainResource);
235 return STATUS_INSUFFICIENT_RESOURCES;
237 memcpy(pCcb->DirectorySearchPattern, pSearchPattern->Buffer,
238 pSearchPattern->Length);
239 pCcb->DirectorySearchPattern[pSearchPattern->Length / sizeof(WCHAR)] = 0;
242 else if (!pCcb->DirectorySearchPattern)
245 pCcb->DirectorySearchPattern = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
246 if (!pCcb->DirectorySearchPattern)
248 ExReleaseResourceLite(&pFcb->MainResource);
249 return STATUS_INSUFFICIENT_RESOURCES;
251 pCcb->DirectorySearchPattern[0] = L'*';
252 pCcb->DirectorySearchPattern[1] = 0;
255 if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
257 pCcb->Entry = pCcb->CurrentByteOffset.u.LowPart;
259 else if (First || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
263 // determine Buffer for result :
264 if (IrpContext->Irp->MdlAddress)
266 Buffer = MmGetSystemAddressForMdl (IrpContext->Irp->MdlAddress);
270 Buffer = IrpContext->Irp->UserBuffer;
272 DPRINT ("Buffer=%x tofind=%S\n", Buffer, pCcb->DirectorySearchPattern);
274 tmpFcb.ObjectName = tmpFcb.PathName;
275 while (RC == STATUS_SUCCESS && BufferLength > 0)
277 RC = FindFile (IrpContext->DeviceExt, &tmpFcb, pFcb,
278 pCcb->DirectorySearchPattern, &pCcb->Entry, NULL);
279 DPRINT ("Found %S, RC=%x, entry %x\n", tmpFcb.ObjectName, RC, pCcb->Entry);
282 switch (FileInformationClass)
284 case FileNameInformation:
285 RC = VfatGetFileNameInformation (&tmpFcb,
286 (PFILE_NAMES_INFORMATION) Buffer, BufferLength);
288 case FileDirectoryInformation:
289 RC = VfatGetFileDirectoryInformation (&tmpFcb, IrpContext->DeviceExt,
290 (PFILE_DIRECTORY_INFORMATION) Buffer, BufferLength);
292 case FileFullDirectoryInformation:
293 RC = VfatGetFileFullDirectoryInformation (&tmpFcb, IrpContext->DeviceExt,
294 (PFILE_FULL_DIRECTORY_INFORMATION) Buffer, BufferLength);
296 case FileBothDirectoryInformation:
297 RC = VfatGetFileBothInformation (&tmpFcb, IrpContext->DeviceExt,
298 (PFILE_BOTH_DIRECTORY_INFORMATION) Buffer, BufferLength);
301 RC = STATUS_INVALID_INFO_CLASS;
303 if (RC == STATUS_BUFFER_OVERFLOW)
307 Buffer0->NextEntryOffset = 0;
316 Buffer0->NextEntryOffset = 0;
320 RC = STATUS_NO_SUCH_FILE;
324 RC = STATUS_NO_MORE_FILES;
328 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
329 Buffer0->FileIndex = FileIndex++;
331 if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
335 BufferLength -= Buffer0->NextEntryOffset;
336 Buffer += Buffer0->NextEntryOffset;
340 Buffer0->NextEntryOffset = 0;
346 ExReleaseResourceLite(&pFcb->MainResource);
351 NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext)
353 * FUNCTION: directory control : read/write directory informations
356 NTSTATUS RC = STATUS_SUCCESS;
358 switch (IrpContext->MinorFunction)
360 case IRP_MN_QUERY_DIRECTORY:
361 RC = DoQuery (IrpContext);
363 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
364 DPRINT (" vfat, dir : change\n");
365 RC = STATUS_NOT_IMPLEMENTED;
369 DbgPrint ("unexpected minor function %x in VFAT driver\n",
370 IrpContext->MinorFunction);
371 RC = STATUS_INVALID_DEVICE_REQUEST;
374 if (RC == STATUS_PENDING)
376 RC = VfatQueueRequest(IrpContext);
380 IrpContext->Irp->IoStatus.Status = RC;
381 IrpContext->Irp->IoStatus.Information = 0;
382 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
383 VfatFreeIrpContext(IrpContext);