- Update to r53061
[reactos.git] / 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 #define NDEBUG
12 #include "vfat.h"
13
14
15 // function like DosDateTimeToFileTime
16 BOOLEAN
17 FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, USHORT DosDate, USHORT DosTime, PLARGE_INTEGER SystemTime)
18 {
19 PDOSTIME pdtime = (PDOSTIME) &DosTime;
20 PDOSDATE pddate = (PDOSDATE) &DosDate;
21 TIME_FIELDS TimeFields;
22 LARGE_INTEGER LocalTime;
23
24 if (SystemTime == NULL)
25 return FALSE;
26
27 TimeFields.Milliseconds = 0;
28 TimeFields.Second = pdtime->Second * 2;
29 TimeFields.Minute = pdtime->Minute;
30 TimeFields.Hour = pdtime->Hour;
31
32 TimeFields.Day = pddate->Day;
33 TimeFields.Month = pddate->Month;
34 TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year);
35
36 RtlTimeFieldsToTime (&TimeFields, &LocalTime);
37 ExLocalTimeToSystemTime(&LocalTime, SystemTime);
38
39 return TRUE;
40 }
41
42 // function like FileTimeToDosDateTime
43 BOOLEAN
44 FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, PLARGE_INTEGER SystemTime, USHORT *pDosDate, USHORT *pDosTime)
45 {
46 PDOSTIME pdtime = (PDOSTIME) pDosTime;
47 PDOSDATE pddate = (PDOSDATE) pDosDate;
48 TIME_FIELDS TimeFields;
49 LARGE_INTEGER LocalTime;
50
51 if (SystemTime == NULL)
52 return FALSE;
53
54 ExSystemTimeToLocalTime (SystemTime, &LocalTime);
55 RtlTimeToTimeFields (&LocalTime, &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 = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear);
69 }
70
71 return TRUE;
72 }
73
74 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
75
76 static NTSTATUS
77 VfatGetFileNameInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
78 PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength)
79 {
80 if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
81 return STATUS_BUFFER_OVERFLOW;
82 pInfo->FileNameLength = DirContext->LongNameU.Length;
83 pInfo->NextEntryOffset =
84 ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
85 RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
86 return STATUS_SUCCESS;
87 }
88
89 static NTSTATUS
90 VfatGetFileDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
91 PDEVICE_EXTENSION DeviceExt,
92 PFILE_DIRECTORY_INFORMATION pInfo,
93 ULONG BufferLength)
94 {
95 if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
96 return STATUS_BUFFER_OVERFLOW;
97 pInfo->FileNameLength = DirContext->LongNameU.Length;
98 pInfo->NextEntryOffset =
99 ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length);
100 RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
101 // pInfo->FileIndex=;
102 if (DeviceExt->Flags & VCB_IS_FATX)
103 {
104 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
105 DirContext->DirEntry.FatX.CreationTime,
106 &pInfo->CreationTime);
107 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
108 DirContext->DirEntry.FatX.AccessTime,
109 &pInfo->LastAccessTime);
110 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
111 DirContext->DirEntry.FatX.UpdateTime,
112 &pInfo->LastWriteTime);
113 pInfo->ChangeTime = pInfo->LastWriteTime;
114 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
115 {
116 pInfo->EndOfFile.QuadPart = 0;
117 pInfo->AllocationSize.QuadPart = 0;
118 }
119 else
120 {
121 pInfo->EndOfFile.u.HighPart = 0;
122 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
123 /* Make allocsize a rounded up multiple of BytesPerCluster */
124 pInfo->AllocationSize.u.HighPart = 0;
125 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
126 }
127 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
128 }
129 else
130 {
131 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
132 DirContext->DirEntry.Fat.CreationTime,
133 &pInfo->CreationTime);
134 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0,
135 &pInfo->LastAccessTime);
136 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
137 DirContext->DirEntry.Fat.UpdateTime,
138 &pInfo->LastWriteTime);
139 pInfo->ChangeTime = pInfo->LastWriteTime;
140 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
141 {
142 pInfo->EndOfFile.QuadPart = 0;
143 pInfo->AllocationSize.QuadPart = 0;
144 }
145 else
146 {
147 pInfo->EndOfFile.u.HighPart = 0;
148 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
149 /* Make allocsize a rounded up multiple of BytesPerCluster */
150 pInfo->AllocationSize.u.HighPart = 0;
151 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
152 }
153 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
154 }
155
156 return STATUS_SUCCESS;
157 }
158
159 static NTSTATUS
160 VfatGetFileFullDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
161 PDEVICE_EXTENSION DeviceExt,
162 PFILE_FULL_DIR_INFORMATION pInfo,
163 ULONG BufferLength)
164 {
165 if ((sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
166 return STATUS_BUFFER_OVERFLOW;
167 pInfo->FileNameLength = DirContext->LongNameU.Length;
168 pInfo->NextEntryOffset =
169 ULONG_ROUND_UP (sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length);
170 RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
171 // pInfo->FileIndex=;
172 if (DeviceExt->Flags & VCB_IS_FATX)
173 {
174 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
175 DirContext->DirEntry.FatX.CreationTime,
176 &pInfo->CreationTime);
177 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
178 DirContext->DirEntry.FatX.AccessTime,
179 &pInfo->LastAccessTime);
180 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
181 DirContext->DirEntry.FatX.UpdateTime,
182 &pInfo->LastWriteTime);
183 pInfo->ChangeTime = pInfo->LastWriteTime;
184 pInfo->EndOfFile.u.HighPart = 0;
185 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
186 /* Make allocsize a rounded up multiple of BytesPerCluster */
187 pInfo->AllocationSize.u.HighPart = 0;
188 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
189 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
190 }
191 else
192 {
193 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
194 DirContext->DirEntry.Fat.CreationTime,
195 &pInfo->CreationTime);
196 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate,
197 0, &pInfo->LastAccessTime);
198 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
199 DirContext->DirEntry.Fat.UpdateTime,
200 &pInfo->LastWriteTime);
201 pInfo->ChangeTime = pInfo->LastWriteTime;
202 pInfo->EndOfFile.u.HighPart = 0;
203 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
204 /* Make allocsize a rounded up multiple of BytesPerCluster */
205 pInfo->AllocationSize.u.HighPart = 0;
206 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
207 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
208 }
209 // pInfo->EaSize=;
210 return STATUS_SUCCESS;
211 }
212
213 static NTSTATUS
214 VfatGetFileBothInformation (PVFAT_DIRENTRY_CONTEXT DirContext,
215 PDEVICE_EXTENSION DeviceExt,
216 PFILE_BOTH_DIR_INFORMATION pInfo,
217 ULONG BufferLength)
218 {
219 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
220 return STATUS_BUFFER_OVERFLOW;
221
222 if (DeviceExt->Flags & VCB_IS_FATX)
223 {
224 pInfo->FileNameLength = DirContext->LongNameU.Length;
225 RtlCopyMemory(pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
226 pInfo->NextEntryOffset =
227 ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length);
228 pInfo->ShortName[0] = 0;
229 pInfo->ShortNameLength = 0;
230 // pInfo->FileIndex=;
231 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate,
232 DirContext->DirEntry.FatX.CreationTime,
233 &pInfo->CreationTime);
234 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate,
235 DirContext->DirEntry.FatX.AccessTime,
236 &pInfo->LastAccessTime);
237 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate,
238 DirContext->DirEntry.FatX.UpdateTime,
239 &pInfo->LastWriteTime);
240 pInfo->ChangeTime = pInfo->LastWriteTime;
241 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
242 {
243 pInfo->EndOfFile.QuadPart = 0;
244 pInfo->AllocationSize.QuadPart = 0;
245 }
246 else
247 {
248 pInfo->EndOfFile.u.HighPart = 0;
249 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
250 /* Make allocsize a rounded up multiple of BytesPerCluster */
251 pInfo->AllocationSize.u.HighPart = 0;
252 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster);
253 }
254 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
255 }
256 else
257 {
258 pInfo->FileNameLength = DirContext->LongNameU.Length;
259 pInfo->NextEntryOffset =
260 ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length);
261 RtlCopyMemory(pInfo->ShortName, DirContext->ShortNameU.Buffer, DirContext->ShortNameU.Length);
262 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
263 RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length);
264 // pInfo->FileIndex=;
265 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate,
266 DirContext->DirEntry.Fat.CreationTime,
267 &pInfo->CreationTime);
268 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0,
269 &pInfo->LastAccessTime);
270 FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate,
271 DirContext->DirEntry.Fat.UpdateTime,
272 &pInfo->LastWriteTime);
273 pInfo->ChangeTime = pInfo->LastWriteTime;
274 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
275 {
276 pInfo->EndOfFile.QuadPart = 0;
277 pInfo->AllocationSize.QuadPart = 0;
278 }
279 else
280 {
281 pInfo->EndOfFile.u.HighPart = 0;
282 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
283 /* Make allocsize a rounded up multiple of BytesPerCluster */
284 pInfo->AllocationSize.u.HighPart = 0;
285 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
286 }
287 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
288 }
289 pInfo->EaSize=0;
290 return STATUS_SUCCESS;
291 }
292
293 static NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext)
294 {
295 NTSTATUS RC = STATUS_SUCCESS;
296 long BufferLength = 0;
297 PUNICODE_STRING pSearchPattern = NULL;
298 FILE_INFORMATION_CLASS FileInformationClass;
299 unsigned char *Buffer = NULL;
300 PFILE_NAMES_INFORMATION Buffer0 = NULL;
301 PVFATFCB pFcb;
302 PVFATCCB pCcb;
303 BOOLEAN FirstQuery = FALSE;
304 BOOLEAN FirstCall = TRUE;
305 VFAT_DIRENTRY_CONTEXT DirContext;
306 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
307 WCHAR ShortNameBuffer[13];
308
309 PIO_STACK_LOCATION Stack = IrpContext->Stack;
310
311 pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2;
312 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
313
314 // determine Buffer for result :
315 BufferLength = Stack->Parameters.QueryDirectory.Length;
316 #if 0
317 /* Do not probe the user buffer until SEH is available */
318 if (IrpContext->Irp->RequestorMode != KernelMode &&
319 IrpContext->Irp->MdlAddress == NULL &&
320 IrpContext->Irp->UserBuffer != NULL)
321 {
322 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
323 }
324 #endif
325 Buffer = VfatGetUserBuffer(IrpContext->Irp);
326
327 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
328 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
329 {
330 RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
331 if (NT_SUCCESS(RC))
332 {
333 RC = STATUS_PENDING;
334 }
335 return RC;
336 }
337
338 /* Obtain the callers parameters */
339 #ifdef _MSC_VER
340 /* HACKHACK: Bug in the MS ntifs.h header:
341 * FileName is really a PUNICODE_STRING, not a PSTRING */
342 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
343 #else
344 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
345 #endif
346 FileInformationClass =
347 Stack->Parameters.QueryDirectory.FileInformationClass;
348 if (pSearchPattern)
349 {
350 if (!pCcb->SearchPattern.Buffer)
351 {
352 FirstQuery = TRUE;
353 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
354 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, pCcb->SearchPattern.MaximumLength, TAG_VFAT);
355 if (!pCcb->SearchPattern.Buffer)
356 {
357 ExReleaseResourceLite(&pFcb->MainResource);
358 return STATUS_INSUFFICIENT_RESOURCES;
359 }
360 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
361 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
362 }
363 }
364 else if (!pCcb->SearchPattern.Buffer)
365 {
366 FirstQuery = TRUE;
367 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
368 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_VFAT);
369 if (!pCcb->SearchPattern.Buffer)
370 {
371 ExReleaseResourceLite(&pFcb->MainResource);
372 return STATUS_INSUFFICIENT_RESOURCES;
373 }
374 pCcb->SearchPattern.Buffer[0] = L'*';
375 pCcb->SearchPattern.Buffer[1] = 0;
376 pCcb->SearchPattern.Length = sizeof(WCHAR);
377 }
378
379 if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
380 {
381 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
382 }
383 else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
384 {
385 DirContext.DirIndex = pCcb->Entry = 0;
386 }
387 else
388 {
389 DirContext.DirIndex = pCcb->Entry;
390 }
391
392 DPRINT ("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
393
394 DirContext.LongNameU.Buffer = LongNameBuffer;
395 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
396 DirContext.ShortNameU.Buffer = ShortNameBuffer;
397 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
398
399 while (RC == STATUS_SUCCESS && BufferLength > 0)
400 {
401 RC = FindFile (IrpContext->DeviceExt, pFcb,
402 &pCcb->SearchPattern, &DirContext, FirstCall);
403 pCcb->Entry = DirContext.DirIndex;
404 DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext.LongNameU, RC, pCcb->Entry);
405 FirstCall = FALSE;
406 if (NT_SUCCESS (RC))
407 {
408 switch (FileInformationClass)
409 {
410 case FileNameInformation:
411 RC = VfatGetFileNameInformation (&DirContext,
412 (PFILE_NAMES_INFORMATION) Buffer,
413 BufferLength);
414 break;
415 case FileDirectoryInformation:
416 RC = VfatGetFileDirectoryInformation (&DirContext,
417 IrpContext->DeviceExt,
418 (PFILE_DIRECTORY_INFORMATION) Buffer,
419 BufferLength);
420 break;
421 case FileFullDirectoryInformation:
422 RC = VfatGetFileFullDirectoryInformation (&DirContext,
423 IrpContext->DeviceExt,
424 (PFILE_FULL_DIR_INFORMATION) Buffer,
425 BufferLength);
426 break;
427 case FileBothDirectoryInformation:
428 RC = VfatGetFileBothInformation (&DirContext,
429 IrpContext->DeviceExt,
430 (PFILE_BOTH_DIR_INFORMATION) Buffer,
431 BufferLength);
432 break;
433 default:
434 RC = STATUS_INVALID_INFO_CLASS;
435 }
436 if (RC == STATUS_BUFFER_OVERFLOW)
437 {
438 break;
439 }
440 }
441 else
442 {
443 if (FirstQuery)
444 {
445 RC = STATUS_NO_SUCH_FILE;
446 }
447 else
448 {
449 RC = STATUS_NO_MORE_FILES;
450 }
451 break;
452 }
453 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
454 Buffer0->FileIndex = DirContext.DirIndex;
455 pCcb->Entry = ++DirContext.DirIndex;
456 BufferLength -= Buffer0->NextEntryOffset;
457 if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
458 {
459 break;
460 }
461 Buffer += Buffer0->NextEntryOffset;
462 }
463 if (Buffer0)
464 {
465 Buffer0->NextEntryOffset = 0;
466 RC = STATUS_SUCCESS;
467 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
468
469 }
470 ExReleaseResourceLite(&pFcb->MainResource);
471 return RC;
472 }
473
474
475 NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext)
476 /*
477 * FUNCTION: directory control : read/write directory informations
478 */
479 {
480 NTSTATUS RC = STATUS_SUCCESS;
481 IrpContext->Irp->IoStatus.Information = 0;
482 switch (IrpContext->MinorFunction)
483 {
484 case IRP_MN_QUERY_DIRECTORY:
485 RC = DoQuery (IrpContext);
486 break;
487 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
488 DPRINT (" vfat, dir : change\n");
489 RC = STATUS_NOT_IMPLEMENTED;
490 break;
491 default:
492 // error
493 DbgPrint ("unexpected minor function %x in VFAT driver\n",
494 IrpContext->MinorFunction);
495 RC = STATUS_INVALID_DEVICE_REQUEST;
496 break;
497 }
498 if (RC == STATUS_PENDING)
499 {
500 RC = VfatQueueRequest(IrpContext);
501 }
502 else
503 {
504 IrpContext->Irp->IoStatus.Status = RC;
505 IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT);
506 VfatFreeIrpContext(IrpContext);
507 }
508 return RC;
509 }
510
511