Merge my current work done on the kd++ branch:
[reactos.git] / reactos / drivers / filesystems / fastfat / dir.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/dir.c
5 * PURPOSE: VFAT Filesystem : directory control
6 * UPDATE HISTORY:
7 19-12-1998 : created
8
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #define NDEBUG
14 #include "vfat.h"
15
16 /* FUNCTIONS ****************************************************************/
17
18 /* Function like DosDateTimeToFileTime */
19 BOOLEAN
20 FsdDosDateTimeToSystemTime(PDEVICE_EXTENSION DeviceExt,
21 USHORT DosDate,
22 USHORT DosTime,
23 PLARGE_INTEGER SystemTime)
24 {
25 PDOSTIME pdtime = (PDOSTIME)&DosTime;
26 PDOSDATE pddate = (PDOSDATE)&DosDate;
27 TIME_FIELDS TimeFields;
28 LARGE_INTEGER LocalTime;
29
30 if (SystemTime == NULL)
31 return FALSE;
32
33 TimeFields.Milliseconds = 0;
34 TimeFields.Second = pdtime->Second * 2;
35 TimeFields.Minute = pdtime->Minute;
36 TimeFields.Hour = pdtime->Hour;
37
38 TimeFields.Day = pddate->Day;
39 TimeFields.Month = pddate->Month;
40 TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year);
41
42 RtlTimeFieldsToTime(&TimeFields, &LocalTime);
43 ExLocalTimeToSystemTime(&LocalTime, SystemTime);
44
45 return TRUE;
46 }
47
48 /* Function like FileTimeToDosDateTime */
49 BOOLEAN
50 FsdSystemTimeToDosDateTime(PDEVICE_EXTENSION DeviceExt,
51 PLARGE_INTEGER SystemTime,
52 PUSHORT pDosDate,
53 PUSHORT pDosTime)
54 {
55 PDOSTIME pdtime = (PDOSTIME)pDosTime;
56 PDOSDATE pddate = (PDOSDATE)pDosDate;
57 TIME_FIELDS TimeFields;
58 LARGE_INTEGER LocalTime;
59
60 if (SystemTime == NULL)
61 return FALSE;
62
63 ExSystemTimeToLocalTime(SystemTime, &LocalTime);
64 RtlTimeToTimeFields(&LocalTime, &TimeFields);
65
66 if (pdtime)
67 {
68 pdtime->Second = TimeFields.Second / 2;
69 pdtime->Minute = TimeFields.Minute;
70 pdtime->Hour = TimeFields.Hour;
71 }
72
73 if (pddate)
74 {
75 pddate->Day = TimeFields.Day;
76 pddate->Month = TimeFields.Month;
77 pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear);
78 }
79
80 return TRUE;
81 }
82
83 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
84
85 static NTSTATUS
86 VfatGetFileNameInformation(PVFAT_DIRENTRY_CONTEXT DirContext,
87 PFILE_NAMES_INFORMATION pInfo,
88 ULONG BufferLength)
89 {
90 if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
91 return STATUS_BUFFER_OVERFLOW;
92
93 pInfo->FileNameLength = DirContext->LongNameU.Length;
94 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
95 DirContext->LongNameU.Length);
96
97 RtlCopyMemory(pInfo->FileName,
98 DirContext->LongNameU.Buffer,
99 DirContext->LongNameU.Length);
100
101 return STATUS_SUCCESS;
102 }
103
104 static NTSTATUS
105 VfatGetFileDirectoryInformation(PVFAT_DIRENTRY_CONTEXT DirContext,
106 PDEVICE_EXTENSION DeviceExt,
107 PFILE_DIRECTORY_INFORMATION pInfo,
108 ULONG BufferLength)
109 {
110 if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
111 return STATUS_BUFFER_OVERFLOW;
112
113 pInfo->FileNameLength = DirContext->LongNameU.Length;
114 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
115 DirContext->LongNameU.Length);
116 /* pInfo->FileIndex = ; */
117
118 RtlCopyMemory(pInfo->FileName,
119 DirContext->LongNameU.Buffer,
120 DirContext->LongNameU.Length);
121
122 if (DeviceExt->Flags & VCB_IS_FATX)
123 {
124 FsdDosDateTimeToSystemTime(DeviceExt,
125 DirContext->DirEntry.FatX.CreationDate,
126 DirContext->DirEntry.FatX.CreationTime,
127 &pInfo->CreationTime);
128 FsdDosDateTimeToSystemTime(DeviceExt,
129 DirContext->DirEntry.FatX.AccessDate,
130 DirContext->DirEntry.FatX.AccessTime,
131 &pInfo->LastAccessTime);
132 FsdDosDateTimeToSystemTime(DeviceExt,
133 DirContext->DirEntry.FatX.UpdateDate,
134 DirContext->DirEntry.FatX.UpdateTime,
135 &pInfo->LastWriteTime);
136
137 pInfo->ChangeTime = pInfo->LastWriteTime;
138
139 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
140 {
141 pInfo->EndOfFile.QuadPart = 0;
142 pInfo->AllocationSize.QuadPart = 0;
143 }
144 else
145 {
146 pInfo->EndOfFile.u.HighPart = 0;
147 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
148 /* Make allocsize a rounded up multiple of BytesPerCluster */
149 pInfo->AllocationSize.u.HighPart = 0;
150 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
151 DeviceExt->FatInfo.BytesPerCluster);
152 }
153
154 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
155 }
156 else
157 {
158 FsdDosDateTimeToSystemTime(DeviceExt,
159 DirContext->DirEntry.Fat.CreationDate,
160 DirContext->DirEntry.Fat.CreationTime,
161 &pInfo->CreationTime);
162 FsdDosDateTimeToSystemTime(DeviceExt,
163 DirContext->DirEntry.Fat.AccessDate,
164 0,
165 &pInfo->LastAccessTime);
166 FsdDosDateTimeToSystemTime(DeviceExt,
167 DirContext->DirEntry.Fat.UpdateDate,
168 DirContext->DirEntry.Fat.UpdateTime,
169 &pInfo->LastWriteTime);
170
171 pInfo->ChangeTime = pInfo->LastWriteTime;
172
173 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
174 {
175 pInfo->EndOfFile.QuadPart = 0;
176 pInfo->AllocationSize.QuadPart = 0;
177 }
178 else
179 {
180 pInfo->EndOfFile.u.HighPart = 0;
181 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
182 /* Make allocsize a rounded up multiple of BytesPerCluster */
183 pInfo->AllocationSize.u.HighPart = 0;
184 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize,
185 DeviceExt->FatInfo.BytesPerCluster);
186 }
187
188 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
189 }
190
191 return STATUS_SUCCESS;
192 }
193
194 static NTSTATUS
195 VfatGetFileFullDirectoryInformation(PVFAT_DIRENTRY_CONTEXT DirContext,
196 PDEVICE_EXTENSION DeviceExt,
197 PFILE_FULL_DIR_INFORMATION pInfo,
198 ULONG BufferLength)
199 {
200 if ((sizeof(FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
201 return STATUS_BUFFER_OVERFLOW;
202
203 pInfo->FileNameLength = DirContext->LongNameU.Length;
204 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
205 DirContext->LongNameU.Length);
206 /* pInfo->FileIndex = ; */
207 /* pInfo->EaSize = ; */
208
209 RtlCopyMemory(pInfo->FileName,
210 DirContext->LongNameU.Buffer,
211 DirContext->LongNameU.Length);
212
213 if (DeviceExt->Flags & VCB_IS_FATX)
214 {
215 FsdDosDateTimeToSystemTime(DeviceExt,
216 DirContext->DirEntry.FatX.CreationDate,
217 DirContext->DirEntry.FatX.CreationTime,
218 &pInfo->CreationTime);
219 FsdDosDateTimeToSystemTime(DeviceExt,
220 DirContext->DirEntry.FatX.AccessDate,
221 DirContext->DirEntry.FatX.AccessTime,
222 &pInfo->LastAccessTime);
223 FsdDosDateTimeToSystemTime(DeviceExt,
224 DirContext->DirEntry.FatX.UpdateDate,
225 DirContext->DirEntry.FatX.UpdateTime,
226 &pInfo->LastWriteTime);
227
228 pInfo->ChangeTime = pInfo->LastWriteTime;
229 pInfo->EndOfFile.u.HighPart = 0;
230 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
231 /* Make allocsize a rounded up multiple of BytesPerCluster */
232 pInfo->AllocationSize.u.HighPart = 0;
233 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
234 DeviceExt->FatInfo.BytesPerCluster);
235 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
236 }
237 else
238 {
239 FsdDosDateTimeToSystemTime(DeviceExt,
240 DirContext->DirEntry.Fat.CreationDate,
241 DirContext->DirEntry.Fat.CreationTime,
242 &pInfo->CreationTime);
243 FsdDosDateTimeToSystemTime(DeviceExt,
244 DirContext->DirEntry.Fat.AccessDate,
245 0,
246 &pInfo->LastAccessTime);
247 FsdDosDateTimeToSystemTime(DeviceExt,
248 DirContext->DirEntry.Fat.UpdateDate,
249 DirContext->DirEntry.Fat.UpdateTime,
250 &pInfo->LastWriteTime);
251
252 pInfo->ChangeTime = pInfo->LastWriteTime;
253 pInfo->EndOfFile.u.HighPart = 0;
254 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
255 /* Make allocsize a rounded up multiple of BytesPerCluster */
256 pInfo->AllocationSize.u.HighPart = 0;
257 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize,
258 DeviceExt->FatInfo.BytesPerCluster);
259 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
260 }
261
262 return STATUS_SUCCESS;
263 }
264
265 static NTSTATUS
266 VfatGetFileBothInformation(PVFAT_DIRENTRY_CONTEXT DirContext,
267 PDEVICE_EXTENSION DeviceExt,
268 PFILE_BOTH_DIR_INFORMATION pInfo,
269 ULONG BufferLength)
270 {
271 if ((sizeof(FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
272 return STATUS_BUFFER_OVERFLOW;
273
274 pInfo->EaSize = 0;
275
276 if (DeviceExt->Flags & VCB_IS_FATX)
277 {
278 pInfo->FileNameLength = DirContext->LongNameU.Length;
279
280 RtlCopyMemory(pInfo->FileName,
281 DirContext->LongNameU.Buffer,
282 DirContext->LongNameU.Length);
283
284 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
285 DirContext->LongNameU.Length);
286 pInfo->ShortName[0] = 0;
287 pInfo->ShortNameLength = 0;
288 /* pInfo->FileIndex = ; */
289
290 FsdDosDateTimeToSystemTime(DeviceExt,
291 DirContext->DirEntry.FatX.CreationDate,
292 DirContext->DirEntry.FatX.CreationTime,
293 &pInfo->CreationTime);
294 FsdDosDateTimeToSystemTime(DeviceExt,
295 DirContext->DirEntry.FatX.AccessDate,
296 DirContext->DirEntry.FatX.AccessTime,
297 &pInfo->LastAccessTime);
298 FsdDosDateTimeToSystemTime(DeviceExt,
299 DirContext->DirEntry.FatX.UpdateDate,
300 DirContext->DirEntry.FatX.UpdateTime,
301 &pInfo->LastWriteTime);
302
303 pInfo->ChangeTime = pInfo->LastWriteTime;
304
305 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
306 {
307 pInfo->EndOfFile.QuadPart = 0;
308 pInfo->AllocationSize.QuadPart = 0;
309 }
310 else
311 {
312 pInfo->EndOfFile.u.HighPart = 0;
313 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
314 /* Make allocsize a rounded up multiple of BytesPerCluster */
315 pInfo->AllocationSize.u.HighPart = 0;
316 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
317 DeviceExt->FatInfo.BytesPerCluster);
318 }
319
320 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
321 }
322 else
323 {
324 pInfo->FileNameLength = DirContext->LongNameU.Length;
325 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
326 DirContext->LongNameU.Length);
327
328 RtlCopyMemory(pInfo->ShortName,
329 DirContext->ShortNameU.Buffer,
330 DirContext->ShortNameU.Length);
331
332 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
333
334 RtlCopyMemory(pInfo->FileName,
335 DirContext->LongNameU.Buffer,
336 DirContext->LongNameU.Length);
337
338 /* pInfo->FileIndex = ; */
339
340 FsdDosDateTimeToSystemTime(DeviceExt,
341 DirContext->DirEntry.Fat.CreationDate,
342 DirContext->DirEntry.Fat.CreationTime,
343 &pInfo->CreationTime);
344 FsdDosDateTimeToSystemTime(DeviceExt,
345 DirContext->DirEntry.Fat.AccessDate,
346 0,
347 &pInfo->LastAccessTime);
348 FsdDosDateTimeToSystemTime(DeviceExt,
349 DirContext->DirEntry.Fat.UpdateDate,
350 DirContext->DirEntry.Fat.UpdateTime,
351 &pInfo->LastWriteTime);
352
353 pInfo->ChangeTime = pInfo->LastWriteTime;
354
355 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
356 {
357 pInfo->EndOfFile.QuadPart = 0;
358 pInfo->AllocationSize.QuadPart = 0;
359 }
360 else
361 {
362 pInfo->EndOfFile.u.HighPart = 0;
363 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
364 /* Make allocsize a rounded up multiple of BytesPerCluster */
365 pInfo->AllocationSize.u.HighPart = 0;
366 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
367 }
368
369 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
370 }
371
372 return STATUS_SUCCESS;
373 }
374
375 static NTSTATUS
376 DoQuery(PVFAT_IRP_CONTEXT IrpContext)
377 {
378 NTSTATUS Status = STATUS_SUCCESS;
379 LONG BufferLength = 0;
380 PUNICODE_STRING pSearchPattern = NULL;
381 FILE_INFORMATION_CLASS FileInformationClass;
382 PUCHAR Buffer = NULL;
383 PFILE_NAMES_INFORMATION Buffer0 = NULL;
384 PVFATFCB pFcb;
385 PVFATCCB pCcb;
386 BOOLEAN FirstQuery = FALSE;
387 BOOLEAN FirstCall = TRUE;
388 VFAT_DIRENTRY_CONTEXT DirContext;
389 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
390 WCHAR ShortNameBuffer[13];
391
392 PIO_STACK_LOCATION Stack = IrpContext->Stack;
393
394 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
395 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;
396
397 /* Determine Buffer for result : */
398 BufferLength = Stack->Parameters.QueryDirectory.Length;
399 #if 0
400 /* Do not probe the user buffer until SEH is available */
401 if (IrpContext->Irp->RequestorMode != KernelMode &&
402 IrpContext->Irp->MdlAddress == NULL &&
403 IrpContext->Irp->UserBuffer != NULL)
404 {
405 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
406 }
407 #endif
408 Buffer = VfatGetUserBuffer(IrpContext->Irp);
409
410 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
411 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
412 {
413 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
414 if (NT_SUCCESS(Status))
415 Status = STATUS_PENDING;
416
417 return Status;
418 }
419
420 /* Obtain the callers parameters */
421 #ifdef _MSC_VER
422 /* HACKHACK: Bug in the MS ntifs.h header:
423 * FileName is really a PUNICODE_STRING, not a PSTRING */
424 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
425 #else
426 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
427 #endif
428 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
429
430 /* Allocate search pattern in case:
431 * -> We don't have one already in context
432 * -> We have been given an input pattern
433 * -> The pattern length is not null
434 * -> The pattern buffer is not null
435 * Otherwise, we'll fall later and allocate a match all (*) pattern
436 */
437 if (pSearchPattern &&
438 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
439 {
440 if (!pCcb->SearchPattern.Buffer)
441 {
442 FirstQuery = TRUE;
443 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
444 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
445 pCcb->SearchPattern.MaximumLength,
446 TAG_VFAT);
447 if (!pCcb->SearchPattern.Buffer)
448 {
449 ExReleaseResourceLite(&pFcb->MainResource);
450 return STATUS_INSUFFICIENT_RESOURCES;
451 }
452 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
453 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
454 }
455 }
456 else if (!pCcb->SearchPattern.Buffer)
457 {
458 FirstQuery = TRUE;
459 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
460 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
461 2 * sizeof(WCHAR),
462 TAG_VFAT);
463 if (!pCcb->SearchPattern.Buffer)
464 {
465 ExReleaseResourceLite(&pFcb->MainResource);
466 return STATUS_INSUFFICIENT_RESOURCES;
467 }
468 pCcb->SearchPattern.Buffer[0] = L'*';
469 pCcb->SearchPattern.Buffer[1] = 0;
470 pCcb->SearchPattern.Length = sizeof(WCHAR);
471 }
472
473 if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
474 {
475 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
476 }
477 else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
478 {
479 DirContext.DirIndex = pCcb->Entry = 0;
480 }
481 else
482 {
483 DirContext.DirIndex = pCcb->Entry;
484 }
485
486 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
487
488 DirContext.LongNameU.Buffer = LongNameBuffer;
489 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
490 DirContext.ShortNameU.Buffer = ShortNameBuffer;
491 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
492
493 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
494 {
495 Status = FindFile(IrpContext->DeviceExt,
496 pFcb,
497 &pCcb->SearchPattern,
498 &DirContext,
499 FirstCall);
500 pCcb->Entry = DirContext.DirIndex;
501
502 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
503
504 FirstCall = FALSE;
505 if (NT_SUCCESS(Status))
506 {
507 switch (FileInformationClass)
508 {
509 case FileNameInformation:
510 Status = VfatGetFileNameInformation(&DirContext,
511 (PFILE_NAMES_INFORMATION)Buffer,
512 BufferLength);
513 break;
514
515 case FileDirectoryInformation:
516 Status = VfatGetFileDirectoryInformation(&DirContext,
517 IrpContext->DeviceExt,
518 (PFILE_DIRECTORY_INFORMATION)Buffer,
519 BufferLength);
520 break;
521
522 case FileFullDirectoryInformation:
523 Status = VfatGetFileFullDirectoryInformation(&DirContext,
524 IrpContext->DeviceExt,
525 (PFILE_FULL_DIR_INFORMATION)Buffer,
526 BufferLength);
527 break;
528
529 case FileBothDirectoryInformation:
530 Status = VfatGetFileBothInformation(&DirContext,
531 IrpContext->DeviceExt,
532 (PFILE_BOTH_DIR_INFORMATION)Buffer,
533 BufferLength);
534 break;
535
536 default:
537 Status = STATUS_INVALID_INFO_CLASS;
538 break;
539 }
540
541 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
542 break;
543 }
544 else
545 {
546 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
547 break;
548 }
549
550 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
551 Buffer0->FileIndex = DirContext.DirIndex;
552 pCcb->Entry = ++DirContext.DirIndex;
553 BufferLength -= Buffer0->NextEntryOffset;
554
555 if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
556 break;
557
558 Buffer += Buffer0->NextEntryOffset;
559 }
560
561 if (Buffer0)
562 {
563 Buffer0->NextEntryOffset = 0;
564 Status = STATUS_SUCCESS;
565 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
566 }
567
568 ExReleaseResourceLite(&pFcb->MainResource);
569
570 return Status;
571 }
572
573
574 /*
575 * FUNCTION: directory control : read/write directory informations
576 */
577 NTSTATUS
578 VfatDirectoryControl(PVFAT_IRP_CONTEXT IrpContext)
579 {
580 NTSTATUS Status = STATUS_SUCCESS;
581
582 IrpContext->Irp->IoStatus.Information = 0;
583
584 switch (IrpContext->MinorFunction)
585 {
586 case IRP_MN_QUERY_DIRECTORY:
587 Status = DoQuery (IrpContext);
588 break;
589
590 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
591 DPRINT("VFAT, dir : change\n");
592 Status = STATUS_NOT_IMPLEMENTED;
593 break;
594
595 default:
596 /* Error */
597 DPRINT("Unexpected minor function %x in VFAT driver\n",
598 IrpContext->MinorFunction);
599 Status = STATUS_INVALID_DEVICE_REQUEST;
600 break;
601 }
602
603 if (Status == STATUS_PENDING)
604 {
605 Status = VfatQueueRequest(IrpContext);
606 }
607 else
608 {
609 IrpContext->Irp->IoStatus.Status = Status;
610 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
611 VfatFreeIrpContext(IrpContext);
612 }
613
614 return Status;
615 }
616
617 /* EOF */