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