Bring back ext2 code from branch
[reactos.git] / reactos / drivers / filesystems / ext2 / src / create.c
1 /*************************************************************************
2 *
3 * File: create.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * Contains code to handle the "Create"/"Open" 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_CREATE
19
20 #define DEBUG_LEVEL (DEBUG_TRACE_CREATE)
21
22
23 /*************************************************************************
24 *
25 * Function: Ext2Create()
26 *
27 * Description:
28 * The I/O Manager will invoke this routine to handle a create/open
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 Ext2Create(
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;
45 BOOLEAN AreWeTopLevel = FALSE;
46
47 DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Create Control IRP received...", 0);
48
49 FsRtlEnterFileSystem();
50
51 // Ext2BreakPoint();
52
53 ASSERT(DeviceObject);
54 ASSERT(Irp);
55
56 // sometimes, we may be called here with the device object representing
57 // the file system (instead of the device object created for a logical
58 // volume. In this case, there is not much we wish to do (this create
59 // typically will happen 'cause some process has to open the FSD device
60 // object so as to be able to send an IOCTL to the FSD)
61
62 // All of the logical volume device objects we create have a device
63 // extension whereas the device object representing the FSD has no
64 // device extension. This seems like a good enough method to identify
65 // between the two device objects ...
66 if (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT)))
67 {
68 // this is an open of the FSD itself
69 DebugTrace( DEBUG_TRACE_MISC, " === Open for the FSD itself", 0);
70 Irp->IoStatus.Status = RC;
71 Irp->IoStatus.Information = FILE_OPENED;
72
73 IoCompleteRequest(Irp, IO_NO_INCREMENT);
74 return(RC);
75 }
76
77 // set the top level context
78 AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
79
80 try
81 {
82
83 // get an IRP context structure and issue the request
84 PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
85 ASSERT(PtrIrpContext);
86
87 RC = Ext2CommonCreate(PtrIrpContext, Irp, TRUE );
88
89 }
90 except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation()))
91 {
92
93 RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
94
95 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
96 }
97
98 if (AreWeTopLevel)
99 {
100 IoSetTopLevelIrp(NULL);
101 }
102
103 FsRtlExitFileSystem();
104
105 return(RC);
106 }
107
108
109
110 /*************************************************************************
111 *
112 * Function: Ext2CommonCreate()
113 *
114 * Description:
115 * The actual work is performed here. This routine may be invoked in one'
116 * of the two possible contexts:
117 * (a) in the context of a system worker thread
118 * (b) in the context of the original caller
119 *
120 * Expected Interrupt Level (for execution) :
121 *
122 * IRQL_PASSIVE_LEVEL
123 *
124 * Return Value: STATUS_SUCCESS/Error
125 *
126 *************************************************************************/
127 NTSTATUS Ext2CommonCreate(
128 PtrExt2IrpContext PtrIrpContext,
129 PIRP PtrIrp,
130 BOOLEAN FirstAttempt)
131 {
132 NTSTATUS RC = STATUS_SUCCESS;
133 PIO_STACK_LOCATION PtrIoStackLocation = NULL;
134 PIO_SECURITY_CONTEXT PtrSecurityContext = NULL;
135 PFILE_OBJECT PtrNewFileObject = NULL;
136 PFILE_OBJECT PtrRelatedFileObject = NULL;
137 uint32 AllocationSize = 0; // if we create a new file
138 PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL;
139 unsigned long RequestedOptions = 0;
140 unsigned long RequestedDisposition = 0;
141 uint8 FileAttributes = 0;
142 unsigned short ShareAccess = 0;
143 unsigned long ExtAttrLength = 0;
144 ACCESS_MASK DesiredAccess;
145
146 BOOLEAN DeferredProcessing = FALSE;
147
148 PtrExt2VCB PtrVCB = NULL;
149 BOOLEAN AcquiredVCB = FALSE;
150
151 BOOLEAN DirectoryOnlyRequested = FALSE;
152 BOOLEAN FileOnlyRequested = FALSE;
153 BOOLEAN NoBufferingSpecified = FALSE;
154 BOOLEAN WriteThroughRequested = FALSE;
155 BOOLEAN DeleteOnCloseSpecified = FALSE;
156 BOOLEAN NoExtAttrKnowledge = FALSE;
157 BOOLEAN CreateTreeConnection = FALSE;
158 BOOLEAN OpenByFileId = FALSE;
159
160 BOOLEAN SequentialOnly = FALSE;
161 BOOLEAN RandomAccess = FALSE;
162
163 // Are we dealing with a page file?
164 BOOLEAN PageFileManipulation = FALSE;
165
166 // Is this open for a target directory (used in rename operations)?
167 BOOLEAN OpenTargetDirectory = FALSE;
168
169 // Should we ignore case when attempting to locate the object?
170 BOOLEAN IgnoreCaseWhenChecking = FALSE;
171
172 PtrExt2CCB PtrRelatedCCB = NULL, PtrNewCCB = NULL;
173 PtrExt2FCB PtrRelatedFCB = NULL, PtrNewFCB = NULL;
174
175 unsigned long ReturnedInformation = -1;
176
177 UNICODE_STRING TargetObjectName;
178 UNICODE_STRING RelatedObjectName;
179
180 UNICODE_STRING AbsolutePathName;
181 UNICODE_STRING RenameLinkTargetFileName;
182
183 LARGE_INTEGER FileAllocationSize, FileEndOfFile;
184
185
186 ASSERT(PtrIrpContext);
187 ASSERT(PtrIrp);
188
189 try
190 {
191
192 AbsolutePathName.Buffer = NULL;
193 AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0;
194
195 // Getting a pointer to the current I/O stack location
196 PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
197 ASSERT(PtrIoStackLocation);
198
199 // Can we block?
200 if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK))
201 {
202 // Asynchronous processing required...
203 RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
204 DeferredProcessing = TRUE;
205 try_return(RC);
206 }
207
208 // Obtaining the parameters specified by the user.
209 PtrNewFileObject = PtrIoStackLocation->FileObject;
210 TargetObjectName = PtrNewFileObject->FileName;
211 PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject;
212
213 if( PtrNewFileObject->FileName.Length && PtrNewFileObject->FileName.Buffer )
214 {
215 if( PtrNewFileObject->FileName.Buffer[ PtrNewFileObject->FileName.Length/2 ] != 0 )
216 {
217 DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrFileObject->FileName not NULL terminated! [Create]", 0 );
218 }
219 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -%S- [Create]", PtrNewFileObject->FileName.Buffer );
220 }
221 else
222 {
223 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -null- [Create]", 0);
224 }
225
226 // Is this a Relative Create/Open?
227 if (PtrRelatedFileObject)
228 {
229 PtrRelatedCCB = (PtrExt2CCB)(PtrRelatedFileObject->FsContext2);
230 ASSERT(PtrRelatedCCB);
231 ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
232 // each CCB in turn points to a FCB
233 PtrRelatedFCB = PtrRelatedCCB->PtrFCB;
234 ASSERT(PtrRelatedFCB);
235 if( PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB &&
236 PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB )
237 {
238 // How the hell can this happen!!!
239 Ext2BreakPoint();
240 }
241
242 AssertFCBorVCB( PtrRelatedFCB );
243
244 RelatedObjectName = PtrRelatedFileObject->FileName;
245
246 if( PtrRelatedFileObject->FileName.Length && PtrRelatedFileObject->FileName.Buffer )
247 {
248 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -%S-", PtrRelatedFileObject->FileName.Buffer );
249 }
250 else
251 {
252 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -null-",0);
253 }
254
255 }
256
257
258 AllocationSize = PtrIrp->Overlay.AllocationSize.LowPart;
259 // Only 32 bit file sizes supported...
260
261 if (PtrIrp->Overlay.AllocationSize.HighPart)
262 {
263 RC = STATUS_INVALID_PARAMETER;
264 try_return(RC);
265 }
266
267 // Getting a pointer to the supplied security context
268 PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext;
269
270 // Obtaining the desired access
271 DesiredAccess = PtrSecurityContext->DesiredAccess;
272
273 // Getting the options supplied by the user...
274 RequestedOptions = (PtrIoStackLocation->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS);
275 RequestedDisposition = ((PtrIoStackLocation->Parameters.Create.Options >> 24) & 0xFF);
276
277 FileAttributes = (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS);
278 ShareAccess = PtrIoStackLocation->Parameters.Create.ShareAccess;
279 PtrExtAttrBuffer = PtrIrp->AssociatedIrp.SystemBuffer;
280
281 ExtAttrLength = PtrIoStackLocation->Parameters.Create.EaLength;
282
283 SequentialOnly = ((RequestedOptions & FILE_SEQUENTIAL_ONLY ) ? TRUE : FALSE);
284 RandomAccess = ((RequestedOptions & FILE_RANDOM_ACCESS ) ? TRUE : FALSE);
285
286
287 DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
288 FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE);
289 NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE);
290 WriteThroughRequested = ((RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE);
291 DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE);
292 NoExtAttrKnowledge = ((RequestedOptions & FILE_NO_EA_KNOWLEDGE) ? TRUE : FALSE);
293 CreateTreeConnection = ((RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE);
294 OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE);
295 PageFileManipulation = ((PtrIoStackLocation->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE);
296 OpenTargetDirectory = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE);
297 IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE);
298
299 // Ensure that the operation has been directed to a valid VCB ...
300 PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
301 ASSERT(PtrVCB);
302 ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
303
304
305 if( !PtrNewFileObject->Vpb )
306 {
307 PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
308 }
309
310 // Acquiring the VCBResource Exclusively...
311 // This is done to synchronise with the close and cleanup routines...
312
313 DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Create]", 0);
314
315 DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Create]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
316 ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE);
317
318 AcquiredVCB = TRUE;
319
320 DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in Create", 0);
321 if( PtrNewFileObject )
322 {
323 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject);
324 }
325
326 // Verify Volume...
327 // if (!NT_SUCCESS(RC = Ext2VerifyVolume(PtrVCB)))
328 // {
329 // try_return(RC);
330 // }
331
332 // If the volume has been locked, fail the request
333
334 if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_LOCKED)
335 {
336 DebugTrace(DEBUG_TRACE_MISC, "Volume locked. Failing Create", 0 );
337 RC = STATUS_ACCESS_DENIED;
338 try_return(RC);
339 }
340
341
342 if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) ||
343 (PtrRelatedFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB)))
344 {
345 //
346 // >>>>>>>>>>>>> Volume Open requested. <<<<<<<<<<<<<
347 //
348
349 // Performing validity checks...
350 if ((OpenTargetDirectory) || (PtrExtAttrBuffer))
351 {
352 RC = STATUS_INVALID_PARAMETER;
353 try_return(RC);
354 }
355
356 if (DirectoryOnlyRequested)
357 {
358 // a volume is not a directory
359 RC = STATUS_NOT_A_DIRECTORY;
360 try_return(RC);
361 }
362
363 if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF))
364 {
365 // cannot create a new volume, I'm afraid ...
366 RC = STATUS_ACCESS_DENIED;
367 try_return(RC);
368 }
369 DebugTrace(DEBUG_TRACE_MISC, "Volume open requested", 0 );
370 RC = Ext2OpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject);
371 ReturnedInformation = PtrIrp->IoStatus.Information;
372
373 try_return(RC);
374 }
375
376 if (OpenByFileId)
377 {
378 DebugTrace(DEBUG_TRACE_MISC, "Open by File Id requested", 0 );
379 RC = STATUS_ACCESS_DENIED;
380 try_return(RC);
381 }
382
383 // Relative path name specified...
384 if (PtrRelatedFileObject)
385 {
386
387 if (!(PtrRelatedFCB->FCBFlags & EXT2_FCB_DIRECTORY))
388 {
389 // we must have a directory as the "related" object
390 RC = STATUS_INVALID_PARAMETER;
391 try_return(RC);
392 }
393
394 // Performing validity checks...
395 if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\'))
396 {
397 RC = STATUS_INVALID_PARAMETER;
398 try_return(RC);
399 }
400
401 if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\'))
402 {
403 RC = STATUS_INVALID_PARAMETER;
404 try_return(RC);
405 }
406
407 // Creating an absolute path-name.
408 {
409 AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR);
410 if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength )))
411 {
412 RC = STATUS_INSUFFICIENT_RESOURCES;
413 try_return(RC);
414 }
415
416 RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength);
417
418 RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length);
419 AbsolutePathName.Length = RelatedObjectName.Length;
420 RtlAppendUnicodeToString(&AbsolutePathName, L"\\");
421 RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer);
422 }
423
424 }
425 // Absolute Path name specified...
426 else
427 {
428
429
430 // Validity Checks...
431 if (TargetObjectName.Buffer[0] != L'\\')
432 {
433 RC = STATUS_INVALID_PARAMETER;
434 try_return(RC);
435 }
436
437 {
438 AbsolutePathName.MaximumLength = TargetObjectName.Length;
439 if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) {
440 RC = STATUS_INSUFFICIENT_RESOURCES;
441 try_return(RC);
442 }
443
444 RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength);
445
446 RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length);
447 AbsolutePathName.Length = TargetObjectName.Length;
448 }
449 }
450
451
452 // Parsing the path...
453 if (AbsolutePathName.Length == 2)
454 {
455
456 // this is an open of the root directory, ensure that the caller has not requested a file only
457 if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) ||
458 (RequestedDisposition == FILE_OVERWRITE_IF))
459 {
460 RC = STATUS_FILE_IS_A_DIRECTORY;
461 try_return(RC);
462 }
463
464 RC = Ext2OpenRootDirectory(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject);
465 DebugTrace(DEBUG_TRACE_MISC, " === Root directory opened", 0 );
466 try_return(RC);
467 }
468
469
470 {
471 // Used during parsing the file path...
472 UNICODE_STRING RemainingName;
473 UNICODE_STRING CurrentName;
474 UNICODE_STRING NextRemainingName;
475 PEXT2_INODE PtrNextInode = NULL;
476 ULONG CurrInodeNo = 0;
477 PtrExt2FCB PtrCurrFCB = NULL;
478 PtrExt2FCB PtrNextFCB = NULL;
479 PFILE_OBJECT PtrCurrFileObject = NULL;
480 UINT NameBufferIndex;
481 ULONG Type = 0;
482 LARGE_INTEGER ZeroSize;
483 BOOLEAN Found = FALSE;
484
485 ZeroSize.QuadPart = 0;
486 if ( PtrRelatedFileObject )
487 {
488 CurrInodeNo = PtrRelatedFCB->INodeNo;
489 PtrCurrFCB = PtrRelatedFCB;
490 }
491 else
492 {
493 CurrInodeNo = PtrVCB->PtrRootDirectoryFCB->INodeNo;
494 PtrCurrFCB = PtrVCB->PtrRootDirectoryFCB;
495
496 }
497
498 // Ext2ZerooutUnicodeString( &RemainingName );
499 Ext2ZerooutUnicodeString( &CurrentName );
500 Ext2ZerooutUnicodeString( &NextRemainingName );
501
502 RemainingName = TargetObjectName;
503
504 while ( !Found && CurrInodeNo )
505 {
506 FsRtlDissectName ( RemainingName, &CurrentName, &NextRemainingName );
507
508 RemainingName = NextRemainingName;
509 // CurrInodeNo is the parent inode for the entry I am searching for
510 // PtrCurrFCB is the parent's FCB
511 // Current Name is its name...
512
513
514 PtrNextFCB = Ext2LocateChildFCBInCore ( PtrVCB, &CurrentName, CurrInodeNo );
515
516 if( PtrNextFCB )
517 {
518 CurrInodeNo = PtrNextFCB->INodeNo;
519
520 if( NextRemainingName.Length == 0 )
521 {
522 //
523 // Done Parsing...
524 // Found the file...
525 //
526 Found = TRUE;
527
528 if( OpenTargetDirectory )
529 {
530 int i;
531 //
532 // This is for a rename/move operation...
533 //
534 ReturnedInformation = FILE_EXISTS;
535
536 // Now replace the file name field with that of the
537 // Target file name...
538 Ext2CopyUnicodeString(
539 &RenameLinkTargetFileName,
540 &CurrentName );
541 /*
542
543 for( i = 0; i < (CurrentName.Length/2); i++ )
544 {
545 PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i];
546 }
547 PtrNewFileObject->FileName.Length = CurrentName.Length;
548 */
549 // Now open the Parent Directory...
550 PtrNextFCB = PtrCurrFCB;
551 CurrInodeNo = PtrNextFCB->INodeNo;
552 }
553
554 //
555 // Relating the FCB to the New File Object
556 //
557 PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
558 PtrNewFileObject->PrivateCacheMap = NULL;
559 PtrNewFileObject->FsContext = (void *)( &(PtrNextFCB->NTRequiredFCB.CommonFCBHeader) );
560 PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject) ;
561 break;
562 }
563
564 else if( !Ext2IsFlagOn( PtrNextFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
565 {
566 // Invalid path...
567 // Can have only a directory in the middle of the path...
568 //
569 RC = STATUS_OBJECT_PATH_NOT_FOUND;
570 try_return( RC );
571 }
572 }
573 else // searching on the disk...
574 {
575 CurrInodeNo = Ext2LocateFileInDisk( PtrVCB, &CurrentName, PtrCurrFCB, &Type );
576 if( !CurrInodeNo )
577 {
578 //
579 // Not found...
580 // Quit searching...
581 //
582
583 if( ( NextRemainingName.Length == 0 ) &&
584 ( RequestedDisposition == FILE_CREATE ) ||
585 ( RequestedDisposition == FILE_OPEN_IF) ||
586 ( RequestedDisposition == FILE_OVERWRITE_IF) )
587
588 {
589 //
590 // Just the last component was not found...
591 // A create was requested...
592 //
593 if( DirectoryOnlyRequested )
594 {
595 Type = EXT2_FT_DIR;
596 }
597 else
598 {
599 Type = EXT2_FT_REG_FILE;
600 }
601
602 CurrInodeNo = Ext2CreateFile( PtrIrpContext, PtrVCB,
603 &CurrentName, PtrCurrFCB, Type );
604
605 if( !CurrInodeNo )
606 {
607 RC = STATUS_OBJECT_PATH_NOT_FOUND;
608 try_return( RC );
609 }
610 // Set the allocation size for the object is specified
611 //IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess));
612 // RC = STATUS_SUCCESS;
613 ReturnedInformation = FILE_CREATED;
614
615 // Should also create a CCB structure...
616 // Doing that a little fathre down... ;)
617
618 }
619 else if( NextRemainingName.Length == 0 && OpenTargetDirectory )
620 {
621 int i;
622 //
623 // This is for a rename/move operation...
624 // Just the last component was not found...
625 //
626 ReturnedInformation = FILE_DOES_NOT_EXIST;
627
628 // Now replace the file name field with that of the
629 // Target file name...
630 Ext2CopyUnicodeString(
631 &RenameLinkTargetFileName,
632 &CurrentName );
633 /*
634 for( i = 0; i < (CurrentName.Length/2); i++ )
635 {
636 PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i];
637 }
638 PtrNewFileObject->FileName.Length = CurrentName.Length;
639 */
640
641 // Now open the Parent Directory...
642 PtrNextFCB = PtrCurrFCB;
643 CurrInodeNo = PtrNextFCB->INodeNo;
644 // Initialize the FsContext
645 PtrNewFileObject->FsContext = &PtrNextFCB->NTRequiredFCB.CommonFCBHeader;
646 // Initialize the section object pointer...
647 PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject);
648 PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
649 PtrNewFileObject->PrivateCacheMap = NULL;
650
651 break;
652 }
653 else
654 {
655 RC = STATUS_OBJECT_PATH_NOT_FOUND;
656 try_return( RC );
657 }
658 }
659
660 if( NextRemainingName.Length )
661 {
662 // Should be a directory...
663 if( Type != EXT2_FT_DIR )
664 {
665 // Invalid path...
666 // Can have only a directory in the middle of the path...
667 //
668 RC = STATUS_OBJECT_PATH_NOT_FOUND;
669 try_return( RC );
670 }
671
672 PtrCurrFileObject = NULL;
673 }
674 else
675 {
676 //
677 // Done Parsing...
678 // Found the file...
679 //
680 Found = TRUE;
681
682 //
683 // Was I supposed to create a new file?
684 //
685 if (RequestedDisposition == FILE_CREATE &&
686 ReturnedInformation != FILE_CREATED )
687 {
688 ReturnedInformation = FILE_EXISTS;
689 RC = STATUS_OBJECT_NAME_COLLISION;
690 try_return(RC);
691 }
692
693 // Is this the type of file I was looking for?
694 // Do some checking here...
695
696 if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE )
697 {
698 // Deny access!
699 // Cannot open a special file...
700 RC = STATUS_ACCESS_DENIED;
701 try_return( RC );
702
703 }
704 if( DirectoryOnlyRequested && Type != EXT2_FT_DIR )
705 {
706 RC = STATUS_NOT_A_DIRECTORY;
707 try_return( RC );
708 }
709 if( FileOnlyRequested && Type == EXT2_FT_DIR )
710 {
711 RC = STATUS_FILE_IS_A_DIRECTORY;
712 try_return(RC);
713 }
714
715 PtrCurrFileObject = PtrNewFileObject;
716 // Things seem to be ok enough!
717 // Proceeing with the Open/Create...
718
719 }
720
721
722 //
723 // Create an FCB and initialise it...
724 //
725 {
726 PtrExt2ObjectName PtrObjectName;
727
728 // Initialising the object name...
729 PtrObjectName = Ext2AllocateObjectName();
730 Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &CurrentName );
731 // RtlInitUnicodeString( &PtrObjectName->ObjectName, CurrentName.Buffer );
732
733 if( !NT_SUCCESS( Ext2CreateNewFCB(
734 &PtrNextFCB, // the new FCB
735 ZeroSize, // AllocationSize,
736 ZeroSize, // EndOfFile,
737 PtrCurrFileObject, // The File Object
738 PtrVCB,
739 PtrObjectName ) ) )
740 {
741 RC = STATUS_INSUFFICIENT_RESOURCES;
742 try_return(RC);
743 }
744
745 if( Type == EXT2_FT_DIR )
746 PtrNextFCB->FCBFlags |= EXT2_FCB_DIRECTORY;
747 else if( Type != EXT2_FT_REG_FILE )
748 PtrNextFCB->FCBFlags |= EXT2_FCB_SPECIAL_FILE;
749
750 PtrNextFCB->INodeNo = CurrInodeNo ;
751 PtrNextFCB->ParentINodeNo = PtrCurrFCB->INodeNo;
752
753 if( PtrCurrFileObject == NULL && CurrInodeNo != EXT2_ROOT_INO )
754 {
755 // This is an FCB created to cache the reads done while parsing
756 // Put this FCB on the ClosableFCBList
757 if( !PtrNextFCB->ClosableFCBs.OnClosableFCBList )
758 {
759 InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
760 &PtrNextFCB->ClosableFCBs.ClosableFCBList );
761 PtrVCB->ClosableFCBs.Count++;
762 PtrNextFCB->ClosableFCBs.OnClosableFCBList = TRUE;
763 }
764 }
765 }
766 }
767
768 //
769 // Still not done parsing...
770 // miles to go before I open... ;)
771 //
772 PtrCurrFCB = PtrNextFCB;
773 }
774
775 PtrNewFCB = PtrNextFCB;
776 }
777
778
779 // If I get this far...
780 // it means, I have located the file...
781 // I even have an FCB to represent it!!!
782
783 if ( NT_SUCCESS (RC) )
784 {
785
786 if ((PtrNewFCB->FCBFlags & EXT2_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) ||
787 (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF )))
788 {
789 RC = STATUS_FILE_IS_A_DIRECTORY;
790 try_return(RC);
791 }
792
793
794 // Check share access and fail if the share conflicts with an existing
795 // open.
796
797 if (PtrNewFCB->OpenHandleCount > 0)
798 {
799 // The FCB is currently in use by some thread.
800 // We must check whether the requested access/share access
801 // conflicts with the existing open operations.
802
803 if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject,
804 &(PtrNewFCB->FCBShareAccess), TRUE)))
805 {
806 // Ext2CloseCCB(PtrNewCCB);
807 try_return(RC);
808 }
809 }
810 else
811 {
812 IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess));
813 }
814
815 //
816 // Allocating a new CCB Structure...
817 //
818 Ext2CreateNewCCB( &PtrNewCCB, PtrNewFCB, PtrNewFileObject);
819 PtrNewFileObject->FsContext2 = (void *) PtrNewCCB;
820 Ext2CopyUnicodeString( &(PtrNewCCB->AbsolutePathName), &AbsolutePathName );
821
822 if( ReturnedInformation == -1 )
823 {
824 //
825 // ReturnedInformation has not been set so far...
826 //
827 ReturnedInformation = FILE_OPENED;
828 }
829
830 // If a supersede or overwrite was requested, do so now ...
831 if (RequestedDisposition == FILE_SUPERSEDE)
832 {
833 // Attempt the operation here ...
834 if( Ext2SupersedeFile( PtrNewFCB, PtrIrpContext) )
835 {
836 ReturnedInformation = FILE_SUPERSEDED;
837 }
838 }
839
840 else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF))
841 {
842 // Attempt the overwrite operation...
843 if( Ext2OverwriteFile( PtrNewFCB, PtrIrpContext) )
844 {
845 ReturnedInformation = FILE_OVERWRITTEN;
846 }
847 }
848 if( AllocationSize )
849 {
850 if( ReturnedInformation == FILE_CREATED ||
851 ReturnedInformation == FILE_SUPERSEDED )
852 {
853 ULONG CurrentSize;
854 ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
855
856 for( CurrentSize = 0; CurrentSize < AllocationSize; CurrentSize += LogicalBlockSize )
857 {
858 Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrNewFCB, PtrNewFileObject, FALSE );
859 }
860 }
861 }
862
863 if( ReturnedInformation == FILE_CREATED )
864 {
865 // Allocate some data blocks if
866 // 1. initial file size has been specified...
867 // 2. if the file is a Directory...
868 // In case of (2) make entries for '.' and '..'
869 // Zero out the Blocks...
870
871 UNICODE_STRING Name;
872
873 if( DirectoryOnlyRequested )
874 {
875
876 Ext2CopyCharToUnicodeString( &Name, ".", 1 );
877 Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->INodeNo);
878
879 Name.Buffer[1] = '.';
880 Name.Buffer[2] = '\0';
881 Name.Length += 2;
882 Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->ParentINodeNo );
883 Ext2DeallocateUnicodeString( &Name );
884 }
885 }
886 if( OpenTargetDirectory )
887 {
888 //
889 // Save the taget file name in the CCB...
890 //
891 Ext2CopyUnicodeString(
892 &PtrNewCCB->RenameLinkTargetFileName,
893 &RenameLinkTargetFileName );
894 Ext2DeallocateUnicodeString( &RenameLinkTargetFileName );
895 }
896 }
897
898 try_exit: NOTHING;
899
900 }
901 finally
902 {
903 if (AcquiredVCB)
904 {
905 ASSERT(PtrVCB);
906 Ext2ReleaseResource(&(PtrVCB->VCBResource));
907
908 AcquiredVCB = FALSE;
909 DebugTrace(DEBUG_TRACE_MISC, "*** VCB released [Create]", 0);
910
911 if( PtrNewFileObject )
912 {
913 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject);
914 }
915 }
916
917 if (AbsolutePathName.Buffer != NULL)
918 {
919 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", AbsolutePathName.Buffer );
920 ExFreePool(AbsolutePathName.Buffer);
921 }
922
923 // Complete the request unless we are here as part of unwinding
924 // when an exception condition was encountered, OR
925 // if the request has been deferred (i.e. posted for later handling)
926 if (RC != STATUS_PENDING)
927 {
928 // If we acquired any FCB resources, release them now ...
929
930 // If any intermediate (directory) open operations were performed,
931 // implement the corresponding close (do *not* however close
932 // the target you have opened on behalf of the caller ...).
933
934 if (NT_SUCCESS(RC))
935 {
936 // Update the file object such that:
937 // (a) the FsContext field points to the NTRequiredFCB field
938 // in the FCB
939 // (b) the FsContext2 field points to the CCB created as a
940 // result of the open operation
941
942 // If write-through was requested, then mark the file object
943 // appropriately
944 if (WriteThroughRequested)
945 {
946 PtrNewFileObject->Flags |= FO_WRITE_THROUGH;
947 }
948 DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open successful", 0 );
949 }
950 else
951 {
952 DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open failed", 0 );
953 // Perform failure related post-processing now
954 }
955
956 // As long as this unwinding is not being performed as a result of
957 // an exception condition, complete the IRP ...
958 if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION))
959 {
960 PtrIrp->IoStatus.Status = RC;
961 PtrIrp->IoStatus.Information = ReturnedInformation;
962
963 // Free up the Irp Context
964 Ext2ReleaseIrpContext(PtrIrpContext);
965
966 // complete the IRP
967 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
968 }
969 }
970 }
971 return(RC);
972 }
973
974
975 /*************************************************************************
976 *
977 * Function: Ext2OpenVolume()
978 *
979 * Description:
980 * Open a logical volume for the caller.
981 *
982 * Expected Interrupt Level (for execution) :
983 *
984 * IRQL_PASSIVE_LEVEL
985 *
986 * Return Value: STATUS_SUCCESS/Error
987 *
988 *************************************************************************/
989 NTSTATUS Ext2OpenVolume(
990 PtrExt2VCB PtrVCB, // volume to be opened
991 PtrExt2IrpContext PtrIrpContext, // IRP context
992 PIRP PtrIrp, // original/user IRP
993 unsigned short ShareAccess, // share access
994 PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access)
995 PFILE_OBJECT PtrNewFileObject) // I/O Mgr. created file object
996 {
997 NTSTATUS RC = STATUS_SUCCESS;
998 PtrExt2CCB PtrCCB = NULL;
999
1000 try {
1001 // check for exclusive open requests (using share modes supplied)
1002 // and determine whether it is even possible to open the volume
1003 // with the specified share modes (e.g. if caller does not
1004 // wish to share read or share write ...)
1005
1006 // Use IoCheckShareAccess() and IoSetShareAccess() here ...
1007 // They are defined in the DDK.
1008
1009 // You might also wish to check the caller's security context
1010 // to see whether you wish to allow the volume open or not.
1011 // Use the SeAccessCheck() routine described in the DDK for this purpose.
1012
1013 // create a new CCB structure
1014 if (!(PtrCCB = Ext2AllocateCCB()))
1015 {
1016 RC = STATUS_INSUFFICIENT_RESOURCES;
1017 try_return(RC);
1018 }
1019
1020 // initialize the CCB
1021 PtrCCB->PtrFCB = (PtrExt2FCB)(PtrVCB);
1022 InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB));
1023
1024 // initialize the CCB to point to the file object
1025 PtrCCB->PtrFileObject = PtrNewFileObject;
1026
1027 Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_VOLUME_OPEN);
1028
1029 // initialize the file object appropriately
1030 PtrNewFileObject->FsContext = (void *)( &(PtrVCB->CommonVCBHeader) );
1031 PtrNewFileObject->FsContext2 = (void *)(PtrCCB);
1032
1033 // increment the number of outstanding open operations on this
1034 // logical volume (i.e. volume cannot be dismounted)
1035
1036 // You might be concerned about 32 bit wrap-around though I would
1037 // argue that it is unlikely ... :-)
1038 (PtrVCB->VCBOpenCount)++;
1039
1040 // now set the IoStatus Information value correctly in the IRP
1041 // (caller will set the status field)
1042 PtrIrp->IoStatus.Information = FILE_OPENED;
1043
1044 try_exit: NOTHING;
1045 }
1046 finally
1047 {
1048 NOTHING;
1049 }
1050
1051 return(RC);
1052 }
1053
1054 /*************************************************************************
1055 *
1056 * Function: Ext2InitializeFCB()
1057 *
1058 * Description:
1059 * Initialize a new FCB structure and also the sent-in file object
1060 * (if supplied)
1061 *
1062 * Expected Interrupt Level (for execution) :
1063 *
1064 * IRQL_PASSIVE_LEVEL
1065 *
1066 * Return Value: None
1067 *
1068 *************************************************************************
1069 void Ext2InitializeFCB(
1070 PtrExt2FCB PtrNewFCB, // FCB structure to be initialized
1071 PtrExt2VCB PtrVCB, // logical volume (VCB) pointer
1072 PtrExt2ObjectName PtrObjectName, // name of the object
1073 uint32 Flags, // is this a file/directory, etc.
1074 PFILE_OBJECT PtrFileObject) // optional file object to be initialized
1075 {
1076 // Initialize the disk dependent portion as you see fit
1077
1078 // Initialize the two ERESOURCE objects
1079 ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource));
1080 ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource));
1081
1082 PtrNewFCB->FCBFlags |= EXT2_INITIALIZED_MAIN_RESOURCE | EXT2_INITIALIZED_PAGING_IO_RESOURCE | Flags;
1083
1084 PtrNewFCB->PtrVCB = PtrVCB;
1085
1086 // caller MUST ensure that VCB has been acquired exclusively
1087 InsertTailList(&(PtrVCB->FCBListHead), &(PtrNewFCB->NextFCB));
1088
1089 // initialize the various list heads
1090 InitializeListHead(&(PtrNewFCB->CCBListHead));
1091
1092 // PtrNewFCB->ReferenceCount = 1;
1093 // PtrNewFCB->OpenHandleCount = 1;
1094
1095 if( PtrObjectName )
1096 {
1097 PtrNewFCB->FCBName = PtrObjectName;
1098 }
1099
1100 if ( PtrFileObject )
1101 {
1102 PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB));
1103 }
1104
1105 return;
1106 }
1107 */
1108
1109 /*************************************************************************
1110 *
1111 * Function: Ext2OpenRootDirectory()
1112 *
1113 * Description:
1114 * Open the root directory for a volume
1115 *
1116 *
1117 * Expected Interrupt Level (for execution) :
1118 *
1119 * ???
1120 *
1121 * Return Value: None
1122 *
1123 *************************************************************************/
1124 NTSTATUS Ext2OpenRootDirectory(
1125 PtrExt2VCB PtrVCB, // volume
1126 PtrExt2IrpContext PtrIrpContext, // IRP context
1127 PIRP PtrIrp, // original/user IRP
1128 unsigned short ShareAccess, // share access
1129 PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access)
1130 PFILE_OBJECT PtrNewFileObject // I/O Mgr. created file object
1131 )
1132 {
1133 // Declerations...
1134 PtrExt2CCB PtrCCB;
1135
1136 ASSERT( PtrVCB );
1137 ASSERT( PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
1138 ASSERT( PtrVCB->PtrRootDirectoryFCB );
1139 AssertFCB( PtrVCB->PtrRootDirectoryFCB );
1140
1141 PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO;
1142
1143 // Create a new CCB...
1144 Ext2CreateNewCCB( &PtrCCB, PtrVCB->PtrRootDirectoryFCB, PtrNewFileObject);
1145 PtrNewFileObject->FsContext = (void *) &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader);
1146 PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY;
1147 PtrNewFileObject->FsContext2 = (void *) PtrCCB;
1148 PtrNewFileObject->SectionObjectPointer = &PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject;
1149 PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
1150
1151 Ext2CopyUnicodeString( &(PtrCCB->AbsolutePathName), &PtrVCB->PtrRootDirectoryFCB->FCBName->ObjectName );
1152
1153
1154 return STATUS_SUCCESS;
1155 }
1156
1157
1158
1159 PtrExt2FCB Ext2LocateChildFCBInCore(
1160 PtrExt2VCB PtrVCB,
1161 PUNICODE_STRING PtrName,
1162 ULONG ParentInodeNo )
1163 {
1164
1165 PtrExt2FCB PtrFCB = NULL;
1166 ULONG InodeNo = 0;
1167 PLIST_ENTRY PtrEntry;
1168
1169 if( IsListEmpty( &(PtrVCB->FCBListHead) ) )
1170 {
1171 return NULL; // Failure;
1172 }
1173
1174 for( PtrEntry = PtrVCB->FCBListHead.Flink;
1175 PtrEntry != &PtrVCB->FCBListHead;
1176 PtrEntry = PtrEntry->Flink )
1177 {
1178 PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB );
1179 ASSERT( PtrFCB );
1180 if( PtrFCB->ParentINodeNo == ParentInodeNo )
1181 {
1182 if( RtlCompareUnicodeString( &PtrFCB->FCBName->ObjectName, PtrName, TRUE ) == 0 )
1183 return PtrFCB;
1184 }
1185 }
1186
1187 return NULL;
1188 }
1189
1190 PtrExt2FCB Ext2LocateFCBInCore(
1191 PtrExt2VCB PtrVCB,
1192 ULONG InodeNo )
1193 {
1194 PtrExt2FCB PtrFCB = NULL;
1195 PLIST_ENTRY PtrEntry;
1196
1197 if( IsListEmpty( &(PtrVCB->FCBListHead) ) )
1198 {
1199 return NULL; // Failure;
1200 }
1201
1202 for( PtrEntry = PtrVCB->FCBListHead.Flink;
1203 PtrEntry != &PtrVCB->FCBListHead;
1204 PtrEntry = PtrEntry->Flink )
1205 {
1206 PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB );
1207 ASSERT( PtrFCB );
1208 if( PtrFCB->INodeNo == InodeNo )
1209 {
1210 return PtrFCB;
1211 }
1212 }
1213
1214 return NULL;
1215 }
1216
1217
1218 ULONG Ext2LocateFileInDisk (
1219 PtrExt2VCB PtrVCB,
1220 PUNICODE_STRING PtrCurrentName,
1221 PtrExt2FCB PtrParentFCB,
1222 ULONG *Type )
1223 {
1224
1225 PtrExt2FCB PtrNewFCB = NULL;
1226 PFILE_OBJECT PtrFileObject = NULL;
1227 ULONG InodeNo = 0;
1228
1229 *Type = EXT2_FT_UNKNOWN;
1230
1231 // 1.
1232 // Initialize the Blocks in the FCB...
1233 //
1234 Ext2InitializeFCBInodeInfo( PtrParentFCB );
1235
1236
1237 // 2.
1238 // Is there a file object I can use for caching??
1239 // If not create one...
1240 //
1241 if( !PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject )
1242 {
1243 //
1244 // No Directory File Object?
1245 // No problem, will create one...
1246 //
1247
1248 // Acquire the MainResource first though...
1249
1250 PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject = IoCreateStreamFileObject(NULL, PtrVCB->TargetDeviceObject );
1251 PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
1252
1253 if( !PtrFileObject )
1254 {
1255 Ext2BreakPoint();
1256 return 0;
1257 }
1258 PtrFileObject->ReadAccess = TRUE;
1259 PtrFileObject->WriteAccess = TRUE;
1260
1261 // Associate the file stream with the Volume parameter block...
1262 PtrFileObject->Vpb = PtrVCB->PtrVPB;
1263
1264 // No caching as yet...
1265 PtrFileObject->PrivateCacheMap = NULL;
1266
1267 // this establishes the FCB - File Object connection...
1268 PtrFileObject->FsContext = (void *)( & (PtrParentFCB->NTRequiredFCB.CommonFCBHeader) );
1269
1270 // Initialize the section object pointer...
1271 PtrFileObject->SectionObjectPointer = &(PtrParentFCB->NTRequiredFCB.SectionObject);
1272 }
1273 else
1274 {
1275 //
1276 // I do have a file object...
1277 // I am using it now!
1278 //
1279 PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
1280 }
1281
1282 // 3.
1283 // Got hold of a file object? Good ;)
1284 // Now initiating Caching, pinned access to be precise ...
1285 //
1286 if (PtrFileObject->PrivateCacheMap == NULL)
1287 {
1288 CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
1289 TRUE, // We utilize pin access for directories
1290 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
1291 PtrParentFCB ); // The context used in callbacks
1292 }
1293
1294 // 4.
1295 // Getting down to the real business now... ;)
1296 // Read in the directory contents and do a search
1297 // a sequential search to be precise...
1298 // Wish Mm'm Renuga were reading this
1299 // Would feel proud... ;)
1300 //
1301 {
1302 LARGE_INTEGER StartBufferOffset;
1303 ULONG PinBufferLength;
1304 ULONG BufferIndex;
1305 PBCB PtrBCB = NULL;
1306 BYTE * PtrPinnedBlockBuffer = NULL;
1307 PEXT2_DIR_ENTRY PtrDirEntry = NULL;
1308 BOOLEAN Found;
1309 int i;
1310
1311
1312 StartBufferOffset.QuadPart = 0;
1313
1314 //
1315 // Read in the whole damn directory
1316 // **Bad programming**
1317 // Will do for now.
1318 //
1319 PinBufferLength = PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
1320 if (!CcMapData( PtrFileObject,
1321 &StartBufferOffset,
1322 PinBufferLength,
1323 TRUE,
1324 &PtrBCB,
1325 (PVOID*)&PtrPinnedBlockBuffer ) )
1326 {
1327
1328
1329 }
1330 //
1331 // Walking through now...
1332 //
1333
1334 for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
1335 {
1336 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
1337 if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 || PtrDirEntry->inode == 0)
1338 {
1339 // Invalid entry...
1340 // Ignore...
1341 continue;
1342 }
1343 //
1344 // Comparing ( case sensitive )
1345 // Directory entry is not NULL terminated...
1346 // nor is the CurrentName...
1347 //
1348 if( PtrDirEntry->name_len != (PtrCurrentName->Length / 2) )
1349 continue;
1350
1351 for( i = 0, Found = TRUE ; i < PtrDirEntry->name_len ; i++ )
1352 {
1353 if( PtrDirEntry->name[ i ] != PtrCurrentName->Buffer[ i ] )
1354 {
1355 Found = FALSE;
1356 break;
1357
1358 }
1359 }
1360
1361 }
1362 if( Found )
1363 {
1364 InodeNo = PtrDirEntry->inode;
1365
1366 if( PtrDirEntry->file_type == EXT2_FT_UNKNOWN )
1367 {
1368
1369 // Old Fashioned Directory entries...
1370 // Will have to read in the Inode to determine the File Type...
1371 EXT2_INODE Inode;
1372 // PtrInode = Ext2AllocatePool( NonPagedPool, sizeof( EXT2_INODE ) );
1373 Ext2ReadInode( PtrVCB, InodeNo, &Inode );
1374
1375 if( Ext2IsModeRegularFile( Inode.i_mode ) )
1376 {
1377 *Type = EXT2_FT_REG_FILE;
1378 }
1379 else if ( Ext2IsModeDirectory( Inode.i_mode) )
1380 {
1381 // Directory...
1382 *Type = EXT2_FT_DIR;
1383 }
1384 else if( Ext2IsModeSymbolicLink(Inode.i_mode) )
1385 {
1386 *Type = EXT2_FT_SYMLINK;
1387 }
1388 else if( Ext2IsModePipe(Inode.i_mode) )
1389 {
1390 *Type = EXT2_FT_FIFO;
1391 }
1392 else if( Ext2IsModeCharacterDevice(Inode.i_mode) )
1393 {
1394 *Type = EXT2_FT_CHRDEV;
1395 }
1396 else if( Ext2IsModeBlockDevice(Inode.i_mode) )
1397 {
1398 *Type = EXT2_FT_BLKDEV;
1399 }
1400 else if( Ext2IsModeSocket(Inode.i_mode) )
1401 {
1402 *Type = EXT2_FT_SOCK;
1403 }
1404 else
1405 {
1406 *Type = EXT2_FT_UNKNOWN;
1407 }
1408
1409 //DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", PtrInode );
1410 //ExFreePool( PtrInode );
1411 }
1412 else
1413 {
1414 *Type = PtrDirEntry->file_type;
1415 }
1416 }
1417
1418 CcUnpinData( PtrBCB );
1419 PtrBCB = NULL;
1420
1421 return InodeNo;
1422 }
1423 }
1424
1425
1426 /*************************************************************************
1427 *
1428 * Function: Ext2CreateFile()
1429 *
1430 * Description:
1431 * Creates a new file on the disk
1432 *
1433 * Expected Interrupt Level (for execution) :
1434 * IRQL_PASSIVE_LEVEL
1435 *
1436 * Restrictions:
1437 * Expects the VCB to be acquired Exclusively before being invoked
1438 *
1439 * Return Value: None
1440 *
1441 *************************************************************************/
1442 ULONG Ext2CreateFile(
1443 PtrExt2IrpContext PtrIrpContext,
1444 PtrExt2VCB PtrVCB,
1445 PUNICODE_STRING PtrName,
1446 PtrExt2FCB PtrParentFCB,
1447 ULONG Type)
1448 {
1449 EXT2_INODE Inode, ParentInode;
1450
1451 ULONG NewInodeNo = 0;
1452 BOOLEAN FCBAcquired = FALSE;
1453
1454 ULONG LogicalBlockSize = 0;
1455
1456 try
1457 {
1458
1459
1460 // 0. Verify if the creation is possible,,,
1461 if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE )
1462 {
1463 //
1464 // Can create only a directory or a regular file...
1465 //
1466 return 0;
1467 }
1468
1469 // 1. Allocate an i-node...
1470
1471 NewInodeNo = Ext2AllocInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo );
1472
1473 // NewInodeNo = 12;
1474
1475 if( !NewInodeNo )
1476 {
1477 return 0;
1478 }
1479
1480 // 2. Acquire the Parent FCB Exclusively...
1481 if( !ExAcquireResourceExclusiveLite(&( PtrParentFCB->NTRequiredFCB.MainResource ), TRUE) )
1482 {
1483 Ext2DeallocInode( PtrIrpContext, PtrVCB, NewInodeNo );
1484 try_return( NewInodeNo = 0);
1485 }
1486 FCBAcquired = TRUE;
1487
1488 // 3. Make an entry in the parent Directory...
1489 ASSERT( PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject );
1490
1491 Ext2MakeNewDirectoryEntry(
1492 PtrIrpContext,
1493 PtrParentFCB,
1494 PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject,
1495 PtrName, Type, NewInodeNo );
1496
1497
1498 // 4. Initialize an inode entry and write it to disk...
1499 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1500
1501 {
1502 // To be deleted
1503 Ext2ReadInode( PtrVCB, NewInodeNo, &Inode );
1504 }
1505
1506 RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) );
1507 if( Type == EXT2_FT_DIR )
1508 {
1509 Inode.i_mode = 0x41ff;
1510
1511 // In addition to the usual link,
1512 // there will be an additional link in the directory itself - the '.' entry
1513 Inode.i_links_count = 2;
1514
1515 // Incrementing the link count for the parent as well...
1516 Ext2ReadInode( PtrVCB, PtrParentFCB->INodeNo, &ParentInode );
1517 ParentInode.i_links_count++;
1518 Ext2WriteInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo, &ParentInode );
1519
1520 }
1521 else
1522 {
1523 Inode.i_mode = 0x81ff;
1524 Inode.i_links_count = 1;
1525 }
1526
1527
1528 {
1529 //
1530 // Setting the time fields in the inode...
1531 //
1532 ULONG Time;
1533 Time = Ext2GetCurrentTime();
1534 Inode.i_ctime = Time;
1535 Inode.i_atime = Time;
1536 Inode.i_mtime = Time;
1537 Inode.i_dtime = 0; // Deleted time;
1538 }
1539
1540 Ext2WriteInode( PtrIrpContext, PtrVCB, NewInodeNo, &Inode );
1541
1542 try_exit: NOTHING;
1543 }
1544 finally
1545 {
1546 if( FCBAcquired )
1547 {
1548 Ext2ReleaseResource( &(PtrParentFCB->NTRequiredFCB.MainResource) );
1549 }
1550 }
1551
1552 return NewInodeNo ;
1553 }
1554
1555 /*************************************************************************
1556 *
1557 * Function: Ext2CreateFile()
1558 *
1559 * Description:
1560 * Overwrites an existing file on the disk
1561 *
1562 * Expected Interrupt Level (for execution) :
1563 * IRQL_PASSIVE_LEVEL
1564 *
1565 * Restrictions:
1566 * Expects the VCB to be acquired Exclusively before being invoked
1567 *
1568 * Return Value: None
1569 *
1570 *************************************************************************/
1571 BOOLEAN Ext2OverwriteFile(
1572 PtrExt2FCB PtrFCB,
1573 PtrExt2IrpContext PtrIrpContext)
1574 {
1575 EXT2_INODE Inode;
1576 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
1577 ULONG i;
1578 ULONG Time;
1579 Time = Ext2GetCurrentTime();
1580
1581 Ext2InitializeFCBInodeInfo( PtrFCB );
1582 // 1.
1583 // Update the inode...
1584 if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1585 {
1586 return FALSE;
1587 }
1588
1589 Inode.i_size = 0;
1590 Inode.i_blocks = 0;
1591 Inode.i_atime = Time;
1592 Inode.i_mtime = Time;
1593 Inode.i_dtime = 0;
1594
1595 for( i = 0; i < EXT2_N_BLOCKS; i++ )
1596 {
1597 Inode.i_block[ i ] = 0;
1598 }
1599
1600 if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1601 {
1602 return FALSE;
1603 }
1604
1605 // 2.
1606 // Release all the data blocks...
1607 if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) )
1608 {
1609 return FALSE;
1610 }
1611
1612 Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
1613 Ext2InitializeFCBInodeInfo( PtrFCB );
1614
1615 return TRUE;
1616 }
1617
1618 /*************************************************************************
1619 *
1620 * Function: Ext2SupersedeFile()
1621 *
1622 * Description:
1623 * Supersedes an existing file on the disk
1624 *
1625 * Expected Interrupt Level (for execution) :
1626 * IRQL_PASSIVE_LEVEL
1627 *
1628 * Restrictions:
1629 * Expects the VCB to be acquired Exclusively before being invoked
1630 *
1631 * Return Value: None
1632 *
1633 *************************************************************************/
1634 BOOLEAN Ext2SupersedeFile(
1635 PtrExt2FCB PtrFCB,
1636 PtrExt2IrpContext PtrIrpContext)
1637 {
1638 EXT2_INODE Inode;
1639 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
1640 ULONG i;
1641
1642 Ext2InitializeFCBInodeInfo( PtrFCB );
1643
1644 // 1.
1645 // Initialize the inode...
1646 RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) );
1647
1648 // Setting the file mode...
1649 // This operation is allowed only for a regular file...
1650 Inode.i_mode = 0x81ff;
1651
1652 // Maintaining the old link count...
1653 Inode.i_links_count = PtrFCB->LinkCount;
1654
1655 // Setting the time fields in the inode...
1656 {
1657 ULONG Time;
1658 Time = Ext2GetCurrentTime();
1659 Inode.i_ctime = Time;
1660 Inode.i_atime = Time;
1661 Inode.i_mtime = Time;
1662 Inode.i_dtime = 0; // Deleted time;
1663 }
1664
1665 if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1666 {
1667 return FALSE;
1668 }
1669
1670 // 2.
1671 // Release all the data blocks...
1672 if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) )
1673 {
1674 return FALSE;
1675 }
1676
1677 Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
1678 Ext2InitializeFCBInodeInfo( PtrFCB );
1679
1680 return TRUE;
1681 }