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