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