Sync with trunk (r47116), hopefully without breaking anything.
[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 /* 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 NTSTATUS
481 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
482 {
483 PIRP Irp;
484 PDEVICE_OBJECT DeviceObject;
485 PDEVICE_EXTENSION DeviceExtension;
486 LONG BufferLength = 0;
487 PUNICODE_STRING SearchPattern = NULL;
488 FILE_INFORMATION_CLASS FileInformationClass;
489 ULONG FileIndex = 0;
490 PUCHAR Buffer = NULL;
491 PFILE_NAMES_INFORMATION Buffer0 = NULL;
492 PNTFS_FCB Fcb;
493 PNTFS_CCB Ccb;
494 // FCB TempFcb;
495 BOOLEAN First = FALSE;
496 PIO_STACK_LOCATION Stack;
497 PFILE_OBJECT FileObject;
498 NTSTATUS Status = STATUS_SUCCESS;
499
500 DPRINT1("NtfsQueryDirectory() called\n");
501
502 ASSERT(IrpContext);
503 Irp = IrpContext->Irp;
504 DeviceObject = IrpContext->DeviceObject;
505
506 DeviceExtension = DeviceObject->DeviceExtension;
507 Stack = IoGetCurrentIrpStackLocation(Irp);
508 FileObject = Stack->FileObject;
509
510 Ccb = (PNTFS_CCB)FileObject->FsContext2;
511 Fcb = (PNTFS_FCB)FileObject->FsContext;
512
513 /* Obtain the callers parameters */
514 BufferLength = Stack->Parameters.QueryDirectory.Length;
515 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
516 FileInformationClass =
517 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 Ccb->DirectorySearchPattern[0] = L'*';
548 Ccb->DirectorySearchPattern[1] = 0;
549 }
550 DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
551
552 /* Determine directory index */
553 if (Stack->Flags & SL_INDEX_SPECIFIED)
554 {
555 Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
556 }
557 else if (First || (Stack->Flags & SL_RESTART_SCAN))
558 {
559 Ccb->Entry = 0;
560 }
561
562 /* Determine Buffer for result */
563 if (Irp->MdlAddress)
564 {
565 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
566 }
567 else
568 {
569 Buffer = Irp->UserBuffer;
570 }
571 DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
572 #if 0
573 TempFcb.ObjectName = TempFcb.PathName;
574 while (Status == STATUS_SUCCESS && BufferLength > 0)
575 {
576 Status = CdfsFindFile(DeviceExtension,
577 &TempFcb,
578 Fcb,
579 Ccb->DirectorySearchPattern,
580 &Ccb->Entry,
581 NULL);
582 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
583
584 if (NT_SUCCESS(Status))
585 {
586 switch (FileInformationClass)
587 {
588 case FileNameInformation:
589 Status = CdfsGetNameInformation(&TempFcb,
590 DeviceExtension,
591 (PFILE_NAMES_INFORMATION)Buffer,
592 BufferLength);
593 break;
594
595 case FileDirectoryInformation:
596 Status = CdfsGetDirectoryInformation(&TempFcb,
597 DeviceExtension,
598 (PFILE_DIRECTORY_INFORMATION)Buffer,
599 BufferLength);
600 break;
601
602 case FileFullDirectoryInformation:
603 Status = CdfsGetFullDirectoryInformation(&TempFcb,
604 DeviceExtension,
605 (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
606 BufferLength);
607 break;
608
609 case FileBothDirectoryInformation:
610 Status = NtfsGetBothDirectoryInformation(&TempFcb,
611 DeviceExtension,
612 (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,
613 BufferLength);
614 break;
615
616 default:
617 Status = STATUS_INVALID_INFO_CLASS;
618 }
619
620 if (Status == STATUS_BUFFER_OVERFLOW)
621 {
622 if (Buffer0)
623 {
624 Buffer0->NextEntryOffset = 0;
625 }
626 break;
627 }
628 }
629 else
630 {
631 if (Buffer0)
632 {
633 Buffer0->NextEntryOffset = 0;
634 }
635
636 if (First)
637 {
638 Status = STATUS_NO_SUCH_FILE;
639 }
640 else
641 {
642 Status = STATUS_NO_MORE_FILES;
643 }
644 break;
645 }
646
647 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
648 Buffer0->FileIndex = FileIndex++;
649 Ccb->Entry++;
650
651 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
652 {
653 break;
654 }
655 BufferLength -= Buffer0->NextEntryOffset;
656 Buffer += Buffer0->NextEntryOffset;
657 }
658 #endif
659
660 if (Buffer0)
661 {
662 Buffer0->NextEntryOffset = 0;
663 }
664
665 if (FileIndex > 0)
666 {
667 Status = STATUS_SUCCESS;
668 }
669
670 // return(Status);
671 return(STATUS_NO_MORE_FILES);
672 }
673
674
675
676 NTSTATUS NTAPI
677 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
678 PIRP Irp)
679 {
680 PNTFS_IRP_CONTEXT IrpContext = NULL;
681 NTSTATUS Status = STATUS_UNSUCCESSFUL;
682
683 DPRINT1("NtfsDirectoryControl() called\n");
684
685 FsRtlEnterFileSystem();
686 ASSERT(DeviceObject);
687 ASSERT(Irp);
688
689 NtfsIsIrpTopLevel(Irp);
690
691 IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
692 if (IrpContext)
693 {
694 switch (IrpContext->MinorFunction)
695 {
696 case IRP_MN_QUERY_DIRECTORY:
697 Status = NtfsQueryDirectory(IrpContext);
698 break;
699
700 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
701 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
702 Status = STATUS_NOT_IMPLEMENTED;
703 break;
704
705 default:
706 Status = STATUS_INVALID_DEVICE_REQUEST;
707 break;
708 }
709 }
710 else
711 Status = STATUS_INSUFFICIENT_RESOURCES;
712
713 Irp->IoStatus.Status = Status;
714 Irp->IoStatus.Information = 0;
715 IoCompleteRequest(Irp, IO_NO_INCREMENT);
716
717 if (IrpContext)
718 ExFreePoolWithTag(IrpContext, 'PRIN');
719
720 IoSetTopLevelIrp(NULL);
721 FsRtlExitFileSystem();
722 return Status;
723 }
724
725 /* EOF */