* Sync to trunk r63845.
[reactos.git] / drivers / filesystems / ntfs / dirctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002,2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/dirctl.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMER: Eric Kohl
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "ntfs.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 #if 0
36 static NTSTATUS
37 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
38 PVOID *Context,
39 PVOID *Block,
40 PLARGE_INTEGER StreamOffset,
41 ULONG DirLength,
42 PVOID *Ptr,
43 PWSTR Name,
44 PULONG pIndex,
45 PULONG pIndex2)
46 /*
47 * FUNCTION: Retrieves the file name, be it in short or long file name format
48 */
49 {
50 PDIR_RECORD Record;
51 NTSTATUS Status;
52 ULONG Index = 0;
53 ULONG Offset = 0;
54 ULONG BlockOffset = 0;
55
56 Record = (PDIR_RECORD)*Block;
57 while(Index < *pIndex)
58 {
59 BlockOffset += Record->RecordLength;
60 Offset += Record->RecordLength;
61
62 Record = (PDIR_RECORD)(*Block + BlockOffset);
63 if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
64 {
65 DPRINT("Map next sector\n");
66 CcUnpinData(*Context);
67 StreamOffset->QuadPart += BLOCKSIZE;
68 Offset = ROUND_UP(Offset, BLOCKSIZE);
69 BlockOffset = 0;
70
71 if (!CcMapData(DeviceExt->StreamFileObject,
72 StreamOffset,
73 BLOCKSIZE, TRUE,
74 Context, Block))
75 {
76 DPRINT("CcMapData() failed\n");
77 return(STATUS_UNSUCCESSFUL);
78 }
79 Record = (PDIR_RECORD)(*Block + BlockOffset);
80 }
81
82 if (Offset >= DirLength)
83 return(STATUS_NO_MORE_ENTRIES);
84
85 Index++;
86 }
87
88 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
89 Index, Record->RecordLength, Offset);
90
91 if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
92 {
93 wcscpy(Name, L".");
94 }
95 else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
96 {
97 wcscpy(Name, L"..");
98 }
99 else
100 {
101 if (DeviceExt->CdInfo.JolietLevel == 0)
102 {
103 ULONG i;
104
105 for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
106 Name[i] = (WCHAR)Record->FileId[i];
107 Name[i] = 0;
108 }
109 else
110 {
111 CdfsSwapString(Name, Record->FileId, Record->FileIdLength);
112 }
113 }
114
115 DPRINT("Name '%S'\n", Name);
116
117 *Ptr = Record;
118
119 *pIndex = Index;
120
121 return(STATUS_SUCCESS);
122 }
123
124
125 static NTSTATUS
126 CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
127 PFCB Fcb,
128 PFCB Parent,
129 PWSTR FileToFind,
130 PULONG pDirIndex,
131 PULONG pDirIndex2)
132 /*
133 * FUNCTION: Find a file
134 */
135 {
136 WCHAR name[256];
137 WCHAR TempStr[2];
138 PVOID Block;
139 NTSTATUS Status;
140 ULONG len;
141 ULONG DirIndex;
142 ULONG Offset;
143 ULONG Read;
144 BOOLEAN IsRoot;
145 PVOID Context = NULL;
146 ULONG DirSize;
147 PUCHAR Ptr;
148 PDIR_RECORD Record;
149 LARGE_INTEGER StreamOffset;
150
151 DPRINT("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n",
152 Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
153 DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",
154 Fcb->PathName, Fcb->ObjectName);
155
156 IsRoot = FALSE;
157 DirIndex = 0;
158 if (wcslen (FileToFind) == 0)
159 {
160 CHECKPOINT;
161 TempStr[0] = (WCHAR) '.';
162 TempStr[1] = 0;
163 FileToFind = (PWSTR)&TempStr;
164 }
165
166 if (Parent)
167 {
168 if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
169 {
170 IsRoot = TRUE;
171 }
172 }
173 else
174 {
175 IsRoot = TRUE;
176 }
177
178 if (IsRoot == TRUE)
179 {
180 StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
181 DirSize = DeviceExt->CdInfo.RootSize;
182
183
184 if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
185 || (FileToFind[0] == '.' && FileToFind[1] == 0))
186 {
187 /* it's root : complete essentials fields then return ok */
188 RtlZeroMemory(Fcb, sizeof(FCB));
189
190 Fcb->PathName[0]='\\';
191 Fcb->ObjectName = &Fcb->PathName[1];
192 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
193 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
194 Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
195
196 if (pDirIndex)
197 *pDirIndex = 0;
198 if (pDirIndex2)
199 *pDirIndex2 = 0;
200 DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
201 return (STATUS_SUCCESS);
202 }
203 }
204 else
205 {
206 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
207 DirSize = Parent->Entry.DataLengthL;
208 }
209
210 DPRINT("StreamOffset %I64u DirSize %lu\n", StreamOffset.QuadPart, DirSize);
211
212 if (pDirIndex && (*pDirIndex))
213 DirIndex = *pDirIndex;
214
215 if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
216 BLOCKSIZE, TRUE, &Context, &Block))
217 {
218 DPRINT("CcMapData() failed\n");
219 return(STATUS_UNSUCCESSFUL);
220 }
221
222 Ptr = (PUCHAR)Block;
223 while(TRUE)
224 {
225 Record = (PDIR_RECORD)Ptr;
226 if (Record->RecordLength == 0)
227 {
228 DPRINT1("Stopped!\n");
229 break;
230 }
231
232 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
233 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
234
235 Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
236 DirSize, (PVOID*)&Ptr, name, &DirIndex, pDirIndex2);
237 if (Status == STATUS_NO_MORE_ENTRIES)
238 {
239 break;
240 }
241 else if (Status == STATUS_UNSUCCESSFUL)
242 {
243 /* Note: the directory cache has already been unpinned */
244 return(Status);
245 }
246
247 DPRINT("Name '%S'\n", name);
248
249 if (wstrcmpjoki(name, FileToFind)) /* || wstrcmpjoki (name2, FileToFind)) */
250 {
251 if (Parent && Parent->PathName)
252 {
253 len = wcslen(Parent->PathName);
254 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
255 Fcb->ObjectName=&Fcb->PathName[len];
256 if (len != 1 || Fcb->PathName[0] != '\\')
257 {
258 Fcb->ObjectName[0] = '\\';
259 Fcb->ObjectName = &Fcb->ObjectName[1];
260 }
261 }
262 else
263 {
264 Fcb->ObjectName=Fcb->PathName;
265 Fcb->ObjectName[0]='\\';
266 Fcb->ObjectName=&Fcb->ObjectName[1];
267 }
268
269 DPRINT("PathName '%S' ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
270
271 memcpy(&Fcb->Entry, Ptr, sizeof(DIR_RECORD));
272 wcsncpy(Fcb->ObjectName, name, MAX_PATH);
273 if (pDirIndex)
274 *pDirIndex = DirIndex;
275
276 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
277 Fcb->PathName, Fcb->ObjectName, DirIndex);
278
279 CcUnpinData(Context);
280
281 return(STATUS_SUCCESS);
282 }
283
284
285 Ptr = Ptr + Record->RecordLength;
286 DirIndex++;
287
288 if (((ULONG)Ptr - (ULONG)Block) >= DirSize)
289 {
290 DPRINT("Stopped!\n");
291 break;
292 }
293 }
294
295 CcUnpinData(Context);
296
297 if (pDirIndex)
298 *pDirIndex = DirIndex;
299
300 return(STATUS_UNSUCCESSFUL);
301 }
302
303
304 static NTSTATUS
305 CdfsGetNameInformation(PFCB Fcb,
306 PDEVICE_EXTENSION DeviceExt,
307 PFILE_NAMES_INFORMATION Info,
308 ULONG BufferLength)
309 {
310 ULONG Length;
311
312 DPRINT("CdfsGetNameInformation() called\n");
313
314 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
315 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
316 return(STATUS_BUFFER_OVERFLOW);
317
318 Info->FileNameLength = Length;
319 Info->NextEntryOffset =
320 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
321 memcpy(Info->FileName, Fcb->ObjectName, Length);
322
323 return(STATUS_SUCCESS);
324 }
325
326
327 static NTSTATUS
328 CdfsGetDirectoryInformation(PFCB Fcb,
329 PDEVICE_EXTENSION DeviceExt,
330 PFILE_DIRECTORY_INFORMATION Info,
331 ULONG BufferLength)
332 {
333 ULONG Length;
334
335 DPRINT("CdfsGetDirectoryInformation() called\n");
336
337 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
338 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
339 return(STATUS_BUFFER_OVERFLOW);
340
341 Info->FileNameLength = Length;
342 Info->NextEntryOffset =
343 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
344 memcpy(Info->FileName, Fcb->ObjectName, Length);
345
346 /* Convert file times */
347 CdfsDateTimeToFileTime(Fcb,
348 &Info->CreationTime);
349 CdfsDateTimeToFileTime(Fcb,
350 &Info->LastAccessTime);
351 CdfsDateTimeToFileTime(Fcb,
352 &Info->LastWriteTime);
353 CdfsDateTimeToFileTime(Fcb,
354 &Info->ChangeTime);
355
356 /* Convert file flags */
357 CdfsFileFlagsToAttributes(Fcb,
358 &Info->FileAttributes);
359
360 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
361
362 /* Make AllocSize a rounded up multiple of the sector size */
363 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
364
365 // Info->FileIndex=;
366
367 return(STATUS_SUCCESS);
368 }
369
370
371 static NTSTATUS
372 CdfsGetFullDirectoryInformation(PFCB Fcb,
373 PDEVICE_EXTENSION DeviceExt,
374 PFILE_FULL_DIRECTORY_INFORMATION Info,
375 ULONG BufferLength)
376 {
377 ULONG Length;
378
379 DPRINT("CdfsGetFullDirectoryInformation() called\n");
380
381 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
382 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
383 return(STATUS_BUFFER_OVERFLOW);
384
385 Info->FileNameLength = Length;
386 Info->NextEntryOffset =
387 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
388 memcpy(Info->FileName, Fcb->ObjectName, Length);
389
390 /* Convert file times */
391 CdfsDateTimeToFileTime(Fcb,
392 &Info->CreationTime);
393 CdfsDateTimeToFileTime(Fcb,
394 &Info->LastAccessTime);
395 CdfsDateTimeToFileTime(Fcb,
396 &Info->LastWriteTime);
397 CdfsDateTimeToFileTime(Fcb,
398 &Info->ChangeTime);
399
400 /* Convert file flags */
401 CdfsFileFlagsToAttributes(Fcb,
402 &Info->FileAttributes);
403
404 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
405
406 /* Make AllocSize a rounded up multiple of the sector size */
407 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
408
409 // Info->FileIndex=;
410 Info->EaSize = 0;
411
412 return(STATUS_SUCCESS);
413 }
414
415
416 static NTSTATUS
417 CdfsGetBothDirectoryInformation(PFCB Fcb,
418 PDEVICE_EXTENSION DeviceExt,
419 PFILE_BOTH_DIRECTORY_INFORMATION Info,
420 ULONG BufferLength)
421 {
422 ULONG Length;
423
424 DPRINT("CdfsGetBothDirectoryInformation() called\n");
425
426 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
427 if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
428 return(STATUS_BUFFER_OVERFLOW);
429
430 Info->FileNameLength = Length;
431 Info->NextEntryOffset =
432 ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
433 memcpy(Info->FileName, Fcb->ObjectName, Length);
434
435 /* Convert file times */
436 CdfsDateTimeToFileTime(Fcb,
437 &Info->CreationTime);
438 CdfsDateTimeToFileTime(Fcb,
439 &Info->LastAccessTime);
440 CdfsDateTimeToFileTime(Fcb,
441 &Info->LastWriteTime);
442 CdfsDateTimeToFileTime(Fcb,
443 &Info->ChangeTime);
444
445 /* Convert file flags */
446 CdfsFileFlagsToAttributes(Fcb,
447 &Info->FileAttributes);
448
449 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
450
451 /* Make AllocSize a rounded up multiple of the sector size */
452 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
453
454 // Info->FileIndex=;
455 Info->EaSize = 0;
456
457 if (DeviceExt->CdInfo.JolietLevel == 0)
458 {
459 /* Standard ISO-9660 format */
460 Info->ShortNameLength = Length;
461 memcpy(Info->ShortName, Fcb->ObjectName, Length);
462 }
463 else
464 {
465 /* Joliet extension */
466
467 /* FIXME: Copy or create a short file name */
468
469 Info->ShortName[0] = 0;
470 Info->ShortNameLength = 0;
471 }
472
473 return(STATUS_SUCCESS);
474 }
475 #endif
476
477
478 NTSTATUS
479 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
480 {
481 PIRP Irp;
482 //PDEVICE_OBJECT DeviceObject;
483 //PDEVICE_EXTENSION DeviceExtension;
484 //LONG BufferLength = 0;
485 PUNICODE_STRING SearchPattern = NULL;
486 //FILE_INFORMATION_CLASS FileInformationClass;
487 ULONG FileIndex = 0;
488 PUCHAR Buffer = NULL;
489 PFILE_NAMES_INFORMATION Buffer0 = NULL;
490 //PNTFS_FCB Fcb;
491 PNTFS_CCB Ccb;
492 // FCB TempFcb;
493 BOOLEAN First = FALSE;
494 PIO_STACK_LOCATION Stack;
495 PFILE_OBJECT FileObject;
496 //NTSTATUS Status = STATUS_SUCCESS;
497
498 DPRINT1("NtfsQueryDirectory() called\n");
499
500 ASSERT(IrpContext);
501 Irp = IrpContext->Irp;
502 // DeviceObject = IrpContext->DeviceObject;
503
504 // DeviceExtension = DeviceObject->DeviceExtension;
505 Stack = IoGetCurrentIrpStackLocation(Irp);
506 FileObject = Stack->FileObject;
507
508 Ccb = (PNTFS_CCB)FileObject->FsContext2;
509 // Fcb = (PNTFS_FCB)FileObject->FsContext;
510
511 /* Obtain the callers parameters */
512 //BufferLength = Stack->Parameters.QueryDirectory.Length;
513 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
514 //FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
515 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
516
517
518 if (SearchPattern != NULL)
519 {
520 if (!Ccb->DirectorySearchPattern)
521 {
522 First = TRUE;
523 Ccb->DirectorySearchPattern =
524 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_NTFS);
525 if (!Ccb->DirectorySearchPattern)
526 {
527 return STATUS_INSUFFICIENT_RESOURCES;
528 }
529
530 memcpy(Ccb->DirectorySearchPattern,
531 SearchPattern->Buffer,
532 SearchPattern->Length);
533 Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
534 }
535 }
536 else if (!Ccb->DirectorySearchPattern)
537 {
538 First = TRUE;
539 Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
540 if (!Ccb->DirectorySearchPattern)
541 {
542 return STATUS_INSUFFICIENT_RESOURCES;
543 }
544
545 Ccb->DirectorySearchPattern[0] = L'*';
546 Ccb->DirectorySearchPattern[1] = 0;
547 }
548
549 DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
550
551 /* Determine directory index */
552 if (Stack->Flags & SL_INDEX_SPECIFIED)
553 {
554 Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
555 }
556 else if (First || (Stack->Flags & SL_RESTART_SCAN))
557 {
558 Ccb->Entry = 0;
559 }
560
561 /* Determine Buffer for result */
562 if (Irp->MdlAddress)
563 {
564 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
565 }
566 else
567 {
568 Buffer = Irp->UserBuffer;
569 }
570
571 DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
572
573 #if 0
574 TempFcb.ObjectName = TempFcb.PathName;
575 while (Status == STATUS_SUCCESS && BufferLength > 0)
576 {
577 Status = CdfsFindFile(DeviceExtension,
578 &TempFcb,
579 Fcb,
580 Ccb->DirectorySearchPattern,
581 &Ccb->Entry,
582 NULL);
583 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
584
585 if (NT_SUCCESS(Status))
586 {
587 switch (FileInformationClass)
588 {
589 case FileNameInformation:
590 Status = CdfsGetNameInformation(&TempFcb,
591 DeviceExtension,
592 (PFILE_NAMES_INFORMATION)Buffer,
593 BufferLength);
594 break;
595
596 case FileDirectoryInformation:
597 Status = CdfsGetDirectoryInformation(&TempFcb,
598 DeviceExtension,
599 (PFILE_DIRECTORY_INFORMATION)Buffer,
600 BufferLength);
601 break;
602
603 case FileFullDirectoryInformation:
604 Status = CdfsGetFullDirectoryInformation(&TempFcb,
605 DeviceExtension,
606 (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
607 BufferLength);
608 break;
609
610 case FileBothDirectoryInformation:
611 Status = NtfsGetBothDirectoryInformation(&TempFcb,
612 DeviceExtension,
613 (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,
614 BufferLength);
615 break;
616
617 default:
618 Status = STATUS_INVALID_INFO_CLASS;
619 }
620
621 if (Status == STATUS_BUFFER_OVERFLOW)
622 {
623 if (Buffer0)
624 {
625 Buffer0->NextEntryOffset = 0;
626 }
627 break;
628 }
629 }
630 else
631 {
632 if (Buffer0)
633 {
634 Buffer0->NextEntryOffset = 0;
635 }
636
637 if (First)
638 {
639 Status = STATUS_NO_SUCH_FILE;
640 }
641 else
642 {
643 Status = STATUS_NO_MORE_FILES;
644 }
645 break;
646 }
647
648 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
649 Buffer0->FileIndex = FileIndex++;
650 Ccb->Entry++;
651
652 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
653 {
654 break;
655 }
656 BufferLength -= Buffer0->NextEntryOffset;
657 Buffer += Buffer0->NextEntryOffset;
658 }
659 #endif
660
661 if (Buffer0)
662 {
663 Buffer0->NextEntryOffset = 0;
664 }
665
666 if (FileIndex > 0)
667 {
668 //Status = STATUS_SUCCESS;
669 }
670
671 // return Status;
672 return STATUS_NO_MORE_FILES;
673 }
674
675
676 NTSTATUS
677 NTAPI
678 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
679 PIRP Irp)
680 {
681 PNTFS_IRP_CONTEXT IrpContext = NULL;
682 NTSTATUS Status = STATUS_UNSUCCESSFUL;
683
684 DPRINT1("NtfsDirectoryControl() called\n");
685
686 FsRtlEnterFileSystem();
687 ASSERT(DeviceObject);
688 ASSERT(Irp);
689
690 NtfsIsIrpTopLevel(Irp);
691
692 IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
693 if (IrpContext)
694 {
695 switch (IrpContext->MinorFunction)
696 {
697 case IRP_MN_QUERY_DIRECTORY:
698 Status = NtfsQueryDirectory(IrpContext);
699 break;
700
701 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
702 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
703 Status = STATUS_NOT_IMPLEMENTED;
704 break;
705
706 default:
707 Status = STATUS_INVALID_DEVICE_REQUEST;
708 break;
709 }
710 }
711 else
712 Status = STATUS_INSUFFICIENT_RESOURCES;
713
714 Irp->IoStatus.Status = Status;
715 Irp->IoStatus.Information = 0;
716 IoCompleteRequest(Irp, IO_NO_INCREMENT);
717
718 if (IrpContext)
719 ExFreePoolWithTag(IrpContext, 'PRIN');
720
721 IoSetTopLevelIrp(NULL);
722 FsRtlExitFileSystem();
723 return Status;
724 }
725
726 /* EOF */