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