Create this branch to work on loading of different Kernel-Debugger DLL providers...
[reactos.git] / drivers / filesystems / ext2 / src / dircntrl.c
1 /*************************************************************************
2 *
3 * File: dircntrl.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * Contains code to handle the "directory control" dispatch entry point.
9 *
10 * Author: Manoj Paul Joseph
11 *
12 *
13 *************************************************************************/
14
15 #include "ext2fsd.h"
16
17 // define the file specific bug-check id
18 #define EXT2_BUG_CHECK_ID EXT2_FILE_DIR_CONTROL
19
20 #define DEBUG_LEVEL (DEBUG_TRACE_DIRCTRL)
21
22
23 /*************************************************************************
24 *
25 * Function: Ext2DirControl()
26 *
27 * Description:
28 * The I/O Manager will invoke this routine to handle a directory control
29 * request
30 *
31 * Expected Interrupt Level (for execution) :
32 *
33 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
34 * to be deferred to a worker thread context)
35 *
36 * Return Value: STATUS_SUCCESS/Error
37 *
38 *************************************************************************/
39 NTSTATUS NTAPI Ext2DirControl(
40 PDEVICE_OBJECT DeviceObject, // the logical volume device object
41 PIRP Irp) // I/O Request Packet
42 {
43 NTSTATUS RC = STATUS_SUCCESS;
44 PtrExt2IrpContext PtrIrpContext = NULL;
45 BOOLEAN AreWeTopLevel = FALSE;
46
47 DebugTrace(DEBUG_TRACE_IRP_ENTRY, "DIR Control IRP received...", 0);
48
49
50 FsRtlEnterFileSystem();
51
52 ASSERT(DeviceObject);
53 ASSERT(Irp);
54
55 // set the top level context
56 AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
57
58 try
59 {
60 // get an IRP context structure and issue the request
61 PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
62 ASSERT(PtrIrpContext);
63
64 RC = Ext2CommonDirControl(PtrIrpContext, Irp);
65
66 }
67 except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation()))
68 {
69
70 RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
71
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
73 }
74
75 if (AreWeTopLevel) {
76 IoSetTopLevelIrp(NULL);
77 }
78
79 FsRtlExitFileSystem();
80
81 return(RC);
82 }
83
84
85
86 /*************************************************************************
87 *
88 * Function: Ext2CommonDirControl()
89 *
90 * Description:
91 * The actual work is performed here. This routine may be invoked in one'
92 * of the two possible contexts:
93 * (a) in the context of a system worker thread
94 * (b) in the context of the original caller
95 *
96 * Expected Interrupt Level (for execution) :
97 *
98 * IRQL_PASSIVE_LEVEL
99 *
100 * Return Value: STATUS_SUCCESS/Error
101 *
102 *************************************************************************/
103 NTSTATUS NTAPI Ext2CommonDirControl(
104 PtrExt2IrpContext PtrIrpContext,
105 PIRP PtrIrp)
106 {
107 NTSTATUS RC = STATUS_SUCCESS;
108 PIO_STACK_LOCATION PtrIoStackLocation = NULL;
109 PFILE_OBJECT PtrFileObject = NULL;
110 PtrExt2FCB PtrFCB = NULL;
111 PtrExt2CCB PtrCCB = NULL;
112
113 // First, get a pointer to the current I/O stack location
114 PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
115 ASSERT(PtrIoStackLocation);
116
117 PtrFileObject = PtrIoStackLocation->FileObject;
118 ASSERT(PtrFileObject);
119
120 // Get the FCB and CCB pointers
121 PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2);
122 ASSERT(PtrCCB);
123 PtrFCB = PtrCCB->PtrFCB;
124
125 AssertFCB( PtrFCB );
126
127
128 // Get some of the parameters supplied to us
129 switch (PtrIoStackLocation->MinorFunction) {
130 case IRP_MN_QUERY_DIRECTORY:
131 #ifdef _GNU_NTIFS_
132 RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, (PEXTENDED_IO_STACK_LOCATION)PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
133 #else
134 RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
135 #endif
136 break;
137 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
138 {
139 RC = STATUS_NOT_IMPLEMENTED;
140 PtrIrp->IoStatus.Status = RC;
141 PtrIrp->IoStatus.Information = 0;
142 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
143 }
144 // RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
145 break;
146 default:
147 // This should not happen.
148 RC = STATUS_INVALID_DEVICE_REQUEST;
149 PtrIrp->IoStatus.Status = RC;
150 PtrIrp->IoStatus.Information = 0;
151
152 // Free up the Irp Context
153 Ext2ReleaseIrpContext(PtrIrpContext);
154
155 // complete the IRP
156 IoCompleteRequest(PtrIrp, IO_NO_INCREMENT);
157 break;
158 }
159
160 return(RC);
161 }
162
163
164 /*************************************************************************
165 *
166 * Function: Ext2QueryDirectory()
167 *
168 * Description:
169 * Query directory request.
170 *
171 * Expected Interrupt Level (for execution) :
172 *
173 * IRQL_PASSIVE_LEVEL
174 *
175 * Return Value: STATUS_SUCCESS/Error
176 *
177 *************************************************************************/
178 NTSTATUS NTAPI Ext2QueryDirectory(
179 PtrExt2IrpContext PtrIrpContext,
180 PIRP PtrIrp,
181 #ifdef _GNU_NTIFS_
182 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation,
183 #else
184 PIO_STACK_LOCATION PtrIoStackLocation,
185 #endif
186 PFILE_OBJECT PtrFileObject,
187 PtrExt2FCB PtrFCB,
188 PtrExt2CCB PtrCCB)
189 {
190 NTSTATUS RC = STATUS_SUCCESS;
191 BOOLEAN PostRequest = FALSE;
192 PtrExt2NTRequiredFCB PtrReqdFCB = NULL;
193 BOOLEAN CanWait = FALSE;
194 PtrExt2VCB PtrVCB = NULL;
195 BOOLEAN AcquiredFCB = FALSE;
196 unsigned long BufferLength = 0;
197 unsigned long BufferIndex = 0;
198 unsigned long FileIndex = 0;
199 PUNICODE_STRING PtrSearchPattern = NULL;
200 FILE_INFORMATION_CLASS FileInformationClass;
201 BOOLEAN RestartScan = FALSE;
202 BOOLEAN ReturnSingleEntry = FALSE;
203 BOOLEAN IndexSpecified = FALSE;
204 unsigned char *Buffer = NULL;
205 BOOLEAN FirstTimeQuery = FALSE;
206 unsigned long StartingIndexForSearch = 0;
207 unsigned long BytesReturned = 0;
208 BOOLEAN BufferUsedup = FALSE;
209
210 BOOLEAN SearchWithWildCards = FALSE;
211
212 PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL;
213 PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL;
214
215
216 PEXT2_DIR_ENTRY PtrDirEntry = NULL;
217 PEXT2_INODE PtrInode = NULL;
218
219 unsigned long LogicalBlockSize;
220
221 unsigned long ThisBlock;
222
223 // The starting Physical Block No...
224 //LARGE_INTEGER StartPhysicalBlock;
225 LARGE_INTEGER StartBufferOffset ;
226 ULONG PinBufferLength;
227
228 // Buffer Control Block
229 PBCB PtrBCB = NULL;
230 BYTE * PtrPinnedBlockBuffer = NULL;
231
232 unsigned int j;
233
234 DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer );
235
236 try
237 {
238 // Validate the sent-in FCB
239 if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY))
240 {
241 // We will only allow notify requests on directories.
242 RC = STATUS_INVALID_PARAMETER;
243 }
244
245 PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
246 CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
247 PtrVCB = PtrFCB->PtrVCB;
248
249 //
250 // Asynchronous IO requested
251 // Posting request...
252 //
253 /*
254 * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL
255 * requests aren't handled in the worker thread yet. I tried
256 * adding handling of them to the worked routine, but there
257 * were problems with accessing the PtrIoStackLocation->
258 * Parameters.QueryDirectory.FileName variable.
259 * -- Filip Navara, 18/08/2004
260 */
261 #if 0
262 if (!CanWait)
263 {
264 PostRequest = TRUE;
265 try_return(RC = STATUS_PENDING);
266 }
267 #endif
268
269 // Obtain the callers parameters
270 BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length;
271 PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName;
272 FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass;
273 FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex;
274
275 // Some additional arguments that affect the FSD behavior
276 RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN);
277 ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY);
278 IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED);
279
280 //
281 // Acquiring exclusive access to the FCB.
282 // This is not mandatory
283 //
284 DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0);
285
286 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
287 ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE);
288
289 DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0);
290 AcquiredFCB = TRUE;
291
292 // We must determine the buffer pointer to be used. Since this
293 // routine could either be invoked directly in the context of the
294 // calling thread, or in the context of a worker thread, here is
295 // a general way of determining what we should use.
296 Buffer = Ext2GetCallersBuffer ( PtrIrp );
297
298 // The method of determining where to look from and what to look for is
299 // unfortunately extremely confusing. However, here is a methodology you
300 // you can broadly adopt:
301 // (a) You have to maintain a search buffer per CCB structure.
302 // (b) This search buffer is initialized the very first time
303 // a query directory operation is performed using the file object.
304 // (For the sample FSD, the search buffer is stored in the
305 // DirectorySearchPattern field)
306 // However, the caller still has the option of "overriding" this stored
307 // search pattern by supplying a new one in a query directory operation.
308 //
309
310 if( PtrCCB->DirectorySearchPattern.Length )
311 {
312 if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
313 {
314 DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0);
315 }
316 DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
317 }
318
319 if (PtrSearchPattern != NULL)
320 {
321 // User has supplied a search pattern
322 // Now validate that the search pattern is legitimate
323
324 if ( PtrCCB->DirectorySearchPattern.Length == 0 )
325 {
326 // This must be the very first query request.
327 FirstTimeQuery = TRUE;
328 }
329 else
330 {
331 // We should ignore the search pattern in the CCB and instead,
332 // use the user-supplied pattern for this particular query
333 // directory request.
334 Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
335 }
336
337 // Now, allocate enough memory to contain the caller
338 // supplied search pattern and fill in the DirectorySearchPattern
339 // field in the CCB
340 Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern );
341 /*
342 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) );
343 ASSERT(PtrCCB->DirectorySearchPattern);
344 RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) );
345 */
346 }
347 else if ( PtrCCB->DirectorySearchPattern.Length == 0 )
348 {
349 // This MUST be the first directory query operation (else the
350 // DirectorySearchPattern field would never be empty. Also, the caller
351 // has neglected to provide a pattern so we MUST invent one.
352 // Use "*" (following NT conventions) as your search pattern
353 // and store it in the PtrCCB->DirectorySearchPattern field.
354
355 /*
356 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") );
357 ASSERT(PtrCCB->DirectorySearchPattern);
358 RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/
359
360 Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" );
361
362 FirstTimeQuery = TRUE;
363 }
364 else
365 {
366 // The caller has not supplied any search pattern...
367 // Using previously supplied pattern
368 PtrSearchPattern = &PtrCCB->DirectorySearchPattern;
369 }
370
371 if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
372 {
373 DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 );
374 }
375 DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
376 SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern );
377
378 // There is one other piece of information that your FSD must store
379 // in the CCB structure for query directory support. This is the index
380 // value (i.e. the offset in your on-disk directory structure) from
381 // which you should start searching.
382 // However, the flags supplied with the IRP can make us override this
383 // as well.
384
385 if (FileIndex)
386 {
387 // Caller has told us wherefrom to begin.
388 // You may need to round this to an appropriate directory entry
389 // entry alignment value.
390 StartingIndexForSearch = FileIndex;
391 }
392 else if (RestartScan)
393 {
394 StartingIndexForSearch = 0;
395 }
396 else
397 {
398 // Get the starting offset from the CCB.
399 StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart;
400 }
401
402 // Read in the file inode if it hasn't already been read...
403 Ext2InitializeFCBInodeInfo( PtrFCB );
404
405 if (PtrFileObject->PrivateCacheMap == NULL)
406 {
407 CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
408 TRUE, // We will utilize pin access for directories
409 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
410 PtrCCB); // The context used in callbacks
411 }
412
413
414 //
415 // Read in the next Data Block of this directory
416 //
417 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
418 StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize );
419 StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary...
420
421 PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart;
422
423 if ( !CcMapData( PtrFileObject,
424 &StartBufferOffset,
425 PinBufferLength,
426 TRUE,
427 &PtrBCB,
428 (PVOID*)&PtrPinnedBlockBuffer ) )
429 {
430 // Read Failure
431 DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0);
432 try_return();
433 }
434 else
435 {
436 DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0);
437 }
438
439 PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) );
440
441 //
442 // Walking through the directory entries...
443 for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; )
444 {
445 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ];
446
447 StartingIndexForSearch += PtrDirEntry->rec_len;
448 PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch;
449
450 if( PtrDirEntry->inode == 0 )
451 {
452 continue;
453 }
454 if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 )
455 {
456 //
457 // This should not happen
458 // Hqw can this be so!!!
459 //
460 Ext2BreakPoint();
461 if( BothDirInformation )
462 {
463 BothDirInformation->NextEntryOffset = 0;
464 }
465 if( !BytesReturned )
466 {
467 if( FirstTimeQuery )
468 RC = STATUS_NO_SUCH_FILE;
469 else
470 RC = STATUS_NO_MORE_FILES;
471 }
472 break;
473 }
474
475 // Does this entry match the search criterian?
476 // Checking
477 //
478 {
479 UNICODE_STRING FileName;
480 LONG Matched = 0;
481 // Constructing a counted Unicode string out of PtrDirEntry
482 Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len );
483
484 if ( SearchWithWildCards )
485 {
486 Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL );
487 }
488 else
489 {
490 Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE );
491 }
492
493 Ext2DeallocateUnicodeString( &FileName );
494 if( !Matched )
495 {
496 continue;
497 }
498 }
499
500 switch( FileInformationClass )
501 {
502 case FileBothDirectoryInformation:
503
504 DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 );
505 ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION );
506 ThisBlock += PtrDirEntry->name_len*2;
507 ThisBlock = Ext2QuadAlign( ThisBlock );
508
509 if( ( BufferIndex + ThisBlock ) > BufferLength )
510 {
511 //
512 // Next entry won't fit into the buffer...
513 // will have to return...
514 // :(
515 //
516 if( BothDirInformation )
517 BothDirInformation->NextEntryOffset = 0;
518 if( !BytesReturned )
519 RC = STATUS_NO_MORE_FILES;
520 BufferUsedup = TRUE;
521 break;
522 }
523
524 Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
525 if( !PtrInode )
526 {
527 try_return( RC = STATUS_UNSUCCESSFUL );
528 }
529
530 BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) );
531 BothDirInformation->EaSize = 0;
532 BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512;
533 BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size;
534 BothDirInformation->ChangeTime.QuadPart = 0;
535
536 BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000;
537 BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart;
538
539 BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
540 BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );
541
542 // Getting the file type...
543 BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
544 if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
545 {
546 // Not a reqular file...
547 if( Ext2IsModeDirectory( PtrInode->i_mode) )
548 {
549 // Directory...
550 BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
551 }
552 else
553 {
554 // Special File...
555 // Treated with respect... ;)
556 //
557 BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
558 // FILE_ATTRIBUTE_DEVICE
559 }
560 if ( Ext2IsModeHidden( PtrInode->i_mode ) )
561 {
562 BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
563 }
564
565 if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
566 {
567 BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
568 }
569 }
570
571 BothDirInformation->FileIndex = StartingIndexForSearch;
572 BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
573 BothDirInformation->ShortNameLength = 0;
574 BothDirInformation->ShortName[0] = 0;
575
576 // Copying out the name as WCHAR null terminated strings
577 for( j = 0; j< PtrDirEntry->name_len ; j ++ )
578 {
579 // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j];
580 BothDirInformation->FileName[ j ] = PtrDirEntry->name[j];
581 // if( j < 11 )
582 // BothDirInformation->ShortName[j] = PtrDirEntry->name[j];
583 }
584
585 /*
586 if( j < 11 )
587 {
588 BothDirInformation->ShortNameLength = j * 2 + 2;
589 BothDirInformation->ShortName[ j ] = 0;
590 }
591 else
592 {
593 BothDirInformation->ShortNameLength = 24;
594 BothDirInformation->ShortName[ 11 ] = 0;
595 }*/
596
597 BothDirInformation->FileName[ j ] = 0;
598 BytesReturned += ThisBlock;
599 BufferIndex += ThisBlock;
600
601 if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
602 BothDirInformation->NextEntryOffset = ThisBlock;
603 else
604 BothDirInformation->NextEntryOffset = 0;
605 break;
606
607 case FileDirectoryInformation:
608 // DirectoryInformation
609 DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 );
610 ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION );
611 ThisBlock += PtrDirEntry->name_len*2;
612 ThisBlock = Ext2QuadAlign( ThisBlock );
613
614 if( ( BufferIndex + ThisBlock ) > BufferLength )
615 {
616 //
617 // Next entry won't fit into the buffer...
618 // will have to return...
619 // :(
620 //
621 if( DirectoryInformation )
622 DirectoryInformation->NextEntryOffset = 0;
623 if( !BytesReturned )
624 RC = STATUS_NO_MORE_FILES;
625 BufferUsedup = TRUE;
626 break;
627 }
628
629 Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
630 if( !PtrInode )
631 {
632 try_return( RC = STATUS_UNSUCCESSFUL );
633 }
634
635 DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) );
636 DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512;
637 DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size;
638 DirectoryInformation->ChangeTime.QuadPart = 0;
639
640 DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000;
641 DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart;
642
643 DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
644 DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );
645
646 // Getting the file type...
647 DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
648 if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
649 {
650 // Not a reqular file...
651 if( Ext2IsModeDirectory( PtrInode->i_mode) )
652 {
653 // Directory...
654 DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
655 }
656 else
657 {
658 // Special File...
659 // Treated with respect... ;)
660 //
661 DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
662 // FILE_ATTRIBUTE_DEVICE
663 }
664 if ( Ext2IsModeHidden( PtrInode->i_mode ) )
665 {
666 DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
667 }
668
669 if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
670 {
671 DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
672 }
673 }
674
675 DirectoryInformation->FileIndex = StartingIndexForSearch;
676 DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
677
678 // Copying out the name as WCHAR null terminated strings
679 for( j = 0; j< PtrDirEntry->name_len ; j ++ )
680 {
681 DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j];
682 }
683
684 DirectoryInformation->FileName[ j ] = 0;
685 BytesReturned += ThisBlock;
686 BufferIndex += ThisBlock;
687
688 if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
689 DirectoryInformation->NextEntryOffset = ThisBlock;
690 else
691 DirectoryInformation->NextEntryOffset = 0;
692 break;
693
694 case FileFullDirectoryInformation:
695 // FullDirInformation->
696 DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 );
697 try_return();
698 case FileNamesInformation:
699 // NamesInformation->
700 DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 );
701 try_return();
702 default:
703 DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 );
704 try_return( RC = STATUS_INVALID_INFO_CLASS );
705 }
706 if( ReturnSingleEntry )
707 {
708 break;
709 }
710 }// end of for...
711
712
713
714 if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) )
715 {
716 Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
717 PtrCCB->CurrentByteOffset.QuadPart = 0;
718 if( FirstTimeQuery )
719 RC = STATUS_NO_SUCH_FILE;
720 else
721 RC = STATUS_NO_MORE_FILES;
722 try_return();
723 }
724 else if( BytesReturned )
725 {
726 BothDirInformation->NextEntryOffset = 0;
727 }
728
729 try_exit: NOTHING;
730 }
731 finally
732 {
733
734 if( PtrInode )
735 {
736 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode );
737 ExFreePool( PtrInode );
738 }
739
740 if( PtrBCB )
741 {
742 CcUnpinData( PtrBCB );
743 PtrBCB = NULL;
744 }
745
746 if (PostRequest)
747 {
748 if (AcquiredFCB)
749 {
750 Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
751 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0);
752 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
753 PtrReqdFCB->MainResource.ActiveCount,
754 PtrReqdFCB->MainResource.NumberOfExclusiveWaiters,
755 PtrReqdFCB->MainResource.NumberOfSharedWaiters );
756 }
757
758 // Map the users buffer and then post the request.
759 RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength);
760 ASSERT(NT_SUCCESS(RC));
761
762 RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
763
764 }
765 else if (!(PtrIrpContext->IrpContextFlags &
766 EXT2_IRP_CONTEXT_EXCEPTION))
767 {
768 if (AcquiredFCB)
769 {
770 Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
771 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0);
772 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
773 PtrReqdFCB->MainResource.ActiveCount,
774 PtrReqdFCB->MainResource.NumberOfExclusiveWaiters,
775 PtrReqdFCB->MainResource.NumberOfSharedWaiters );
776 }
777
778 // Complete the request.
779 PtrIrp->IoStatus.Status = RC;
780 PtrIrp->IoStatus.Information = BytesReturned;
781
782 // Free up the Irp Context
783 Ext2ReleaseIrpContext(PtrIrpContext);
784
785 // complete the IRP
786 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
787 }
788
789 // Flush the saved BCBs...
790 // Ext2FlushSavedBCBs ( PtrIrpContext );
791
792 }
793
794 return(RC);
795 }
796
797
798
799 /*************************************************************************
800 *
801 * Function: Ext2NotifyChangeDirectory()
802 *
803 * Description:
804 * Handle the notify request.
805 *
806 * Expected Interrupt Level (for execution) :
807 *
808 * IRQL_PASSIVE_LEVEL
809 *
810 * Return Value: STATUS_SUCCESS/Error
811 *
812 *************************************************************************/
813 NTSTATUS NTAPI Ext2NotifyChangeDirectory(
814 PtrExt2IrpContext PtrIrpContext,
815 PIRP PtrIrp,
816 #ifdef _GNU_NTIFS_
817 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation,
818 #else
819 PIO_STACK_LOCATION PtrIoStackLocation,
820 #endif
821 PFILE_OBJECT PtrFileObject,
822 PtrExt2FCB PtrFCB,
823 PtrExt2CCB PtrCCB)
824 {
825 NTSTATUS RC = STATUS_SUCCESS;
826 BOOLEAN CompleteRequest = FALSE;
827 BOOLEAN PostRequest = FALSE;
828 PtrExt2NTRequiredFCB PtrReqdFCB = NULL;
829 BOOLEAN CanWait = FALSE;
830 ULONG CompletionFilter = 0;
831 BOOLEAN WatchTree = FALSE;
832 PtrExt2VCB PtrVCB = NULL;
833 BOOLEAN AcquiredFCB = FALSE;
834
835 try {
836
837 // Validate the sent-in FCB
838 if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) {
839 // We will only allow notify requests on directories.
840 RC = STATUS_INVALID_PARAMETER;
841 CompleteRequest = TRUE;
842 }
843
844 PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
845 CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
846 PtrVCB = PtrFCB->PtrVCB;
847
848 // Acquire the FCB resource shared
849 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared[DirCtrl]", 0);
850 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
851 if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait))
852 {
853 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [DirCtrl]", 0);
854 PostRequest = TRUE;
855 try_return(RC = STATUS_PENDING);
856 }
857 AcquiredFCB = TRUE;
858 DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0);
859
860 // Obtain some parameters sent by the caller
861 CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter;
862 WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE);
863
864 // If you wish to capture the subject context, you can do so as
865 // follows:
866 // {
867 // PSECURITY_SUBJECT_CONTEXT SubjectContext;
868 // SubjectContext = Ext2AllocatePool(PagedPool,
869 // sizeof(SECURITY_SUBJECT_CONTEXT) );
870 // SeCaptureSubjectContext(SubjectContext);
871 // }
872
873 FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB,
874 (PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp,
875 NULL, // Ext2TraverseAccessCheck(...) ?
876 NULL); // SubjectContext ?
877
878 RC = STATUS_PENDING;
879
880 try_exit: NOTHING;
881
882 }
883 finally
884 {
885
886 if (PostRequest)
887 {
888 // Perform appropriate post related processing here
889 if (AcquiredFCB)
890 {
891 Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
892 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in DirCtrl", 0);
893 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
894 PtrReqdFCB->MainResource.ActiveCount,
895 PtrReqdFCB->MainResource.NumberOfExclusiveWaiters,
896 PtrReqdFCB->MainResource.NumberOfSharedWaiters );
897
898 AcquiredFCB = FALSE;
899 }
900 RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
901 }
902 else if (CompleteRequest)
903 {
904 PtrIrp->IoStatus.Status = RC;
905 PtrIrp->IoStatus.Information = 0;
906
907 // Free up the Irp Context
908 Ext2ReleaseIrpContext(PtrIrpContext);
909
910 // complete the IRP
911 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
912 } else {
913 // Simply free up the IrpContext since the IRP has been queued
914 Ext2ReleaseIrpContext(PtrIrpContext);
915 }
916
917 // Release the FCB resources if acquired.
918 if (AcquiredFCB)
919 {
920 Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
921 DebugTrace(DEBUG_TRACE_MISC, "*** FReleased in [DirCtrl]", 0);
922 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
923 PtrReqdFCB->MainResource.ActiveCount,
924 PtrReqdFCB->MainResource.NumberOfExclusiveWaiters,
925 PtrReqdFCB->MainResource.NumberOfSharedWaiters );
926
927 AcquiredFCB = FALSE;
928 }
929
930 }
931
932 return(RC);
933 }