2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS *****************************************************************/
16 extern PEXT2_GLOBAL Ext2Global
;
18 /* DEFINITIONS *************************************************************/
21 #pragma alloc_text(PAGE, Ext2IsNameValid)
22 #pragma alloc_text(PAGE, Ext2FollowLink)
23 #pragma alloc_text(PAGE, Ext2IsSpecialSystemFile)
24 #pragma alloc_text(PAGE, Ext2LookupFile)
25 #pragma alloc_text(PAGE, Ext2ScanDir)
26 #pragma alloc_text(PAGE, Ext2CreateFile)
27 #pragma alloc_text(PAGE, Ext2CreateVolume)
28 #pragma alloc_text(PAGE, Ext2Create)
29 #pragma alloc_text(PAGE, Ext2CreateInode)
30 #pragma alloc_text(PAGE, Ext2SupersedeOrOverWriteFile)
35 Ext2IsNameValid(PUNICODE_STRING FileName
)
38 PUSHORT pName
= (PUSHORT
) FileName
->Buffer
;
40 if (FileName
== NULL
) {
44 while (i
< (FileName
->Length
/ sizeof(WCHAR
))) {
50 if (pName
[i
] == L
'|' || pName
[i
] == L
':' ||
51 pName
[i
] == L
'/' || pName
[i
] == L
'*' ||
52 pName
[i
] == L
'?' || pName
[i
] == L
'\"' ||
53 pName
[i
] == L
'<' || pName
[i
] == L
'>' ) {
67 IN PEXT2_IRP_CONTEXT IrpContext
,
74 NTSTATUS Status
= STATUS_LINK_FAILED
;
76 UNICODE_STRING UniName
;
78 BOOLEAN bOemBuffer
= FALSE
;
80 PEXT2_MCB Target
= NULL
;
86 RtlZeroMemory(&UniName
, sizeof(UNICODE_STRING
));
87 RtlZeroMemory(&OemName
, sizeof(OEM_STRING
));
89 /* exit if we jump into a possible symlink forever loop */
90 if ((Linkdep
+ 1) > EXT2_MAX_NESTED_LINKS
||
91 IoGetRemainingStackSize() < 1024) {
95 /* read the symlink target path */
96 if (Mcb
->Inode
.i_size
< EXT2_LINKLEN_IN_INODE
) {
98 OemName
.Buffer
= (PUCHAR
) (&Mcb
->Inode
.i_block
[0]);
99 OemName
.Length
= (USHORT
)Mcb
->Inode
.i_size
;
100 OemName
.MaximumLength
= OemName
.Length
+ 1;
104 OemName
.Length
= (USHORT
)Mcb
->Inode
.i_size
;
105 OemName
.MaximumLength
= OemName
.Length
+ 1;
106 OemName
.Buffer
= Ext2AllocatePool(PagedPool
,
107 OemName
.MaximumLength
,
109 if (OemName
.Buffer
== NULL
) {
110 Status
= STATUS_INSUFFICIENT_RESOURCES
;
114 RtlZeroMemory(OemName
.Buffer
, OemName
.MaximumLength
);
116 Status
= Ext2ReadInode(
122 (ULONG
)(Mcb
->Inode
.i_size
),
125 if (!NT_SUCCESS(Status
)) {
130 /* convert Linux slash to Windows backslash */
131 for (i
=0; i
< OemName
.Length
; i
++) {
132 if (OemName
.Buffer
[i
] == '/') {
133 OemName
.Buffer
[i
] = '\\';
137 /* convert oem string to unicode string */
138 UniName
.MaximumLength
= (USHORT
)Ext2OEMToUnicodeSize(Vcb
, &OemName
);
139 if (UniName
.MaximumLength
<= 0) {
140 Status
= STATUS_INSUFFICIENT_RESOURCES
;
144 UniName
.MaximumLength
+= 2;
145 UniName
.Buffer
= Ext2AllocatePool(PagedPool
,
146 UniName
.MaximumLength
,
148 if (UniName
.Buffer
== NULL
) {
149 Status
= STATUS_INSUFFICIENT_RESOURCES
;
152 RtlZeroMemory(UniName
.Buffer
, UniName
.MaximumLength
);
153 Status
= Ext2OEMToUnicode(Vcb
, &UniName
, &OemName
);
154 if (!NT_SUCCESS(Status
)) {
155 Status
= STATUS_INSUFFICIENT_RESOURCES
;
159 /* search the real target */
160 Status
= Ext2LookupFile(
168 if (Target
== NULL
) {
169 Status
= STATUS_LINK_FAILED
;
172 if (Target
== NULL
/* link target doesn't exist */ ||
173 Target
== Mcb
/* symlink points to itself */ ||
174 IsMcbSpecialFile(Target
) /* target not resolved*/ ||
175 IsFileDeleted(Target
) /* target deleted */ ) {
178 ASSERT(Target
->Refercount
> 0);
179 Ext2DerefMcb(Target
);
181 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
182 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
183 Mcb
->FileAttr
= FILE_ATTRIBUTE_NORMAL
;
186 } else if (IsMcbSymLink(Target
)) {
188 ASSERT(Target
->Refercount
> 0);
189 ASSERT(Target
->Target
!= NULL
);
190 Ext2ReferMcb(Target
->Target
);
191 Mcb
->Target
= Target
->Target
;
192 Ext2DerefMcb(Target
);
193 ASSERT(!IsMcbSymLink(Target
->Target
));
194 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
195 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
196 ASSERT(Mcb
->Target
->Refercount
> 0);
197 Mcb
->FileAttr
= Target
->FileAttr
;
201 Mcb
->Target
= Target
;
202 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
203 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
204 ASSERT(Mcb
->Target
->Refercount
> 0);
205 Mcb
->FileAttr
= Target
->FileAttr
;
211 Ext2FreePool(OemName
.Buffer
, 'NL2E');
214 if (UniName
.Buffer
) {
215 Ext2FreePool(UniName
.Buffer
, 'NL2E');
223 Ext2IsSpecialSystemFile(
224 IN PUNICODE_STRING FileName
,
225 IN BOOLEAN bDirectory
228 PWSTR SpecialFileList
[] = {
235 PWSTR SpecialDirList
[] = {
246 for (i
= 0; TRUE
; i
++) {
249 entryName
= SpecialDirList
[i
];
251 entryName
= SpecialFileList
[i
];
254 if (NULL
== entryName
) {
258 length
= wcslen(entryName
) * sizeof(WCHAR
);
259 if (FileName
->Length
== length
) {
260 if ( 0 == _wcsnicmp( entryName
,
262 length
/ sizeof(WCHAR
) )) {
273 IN PEXT2_IRP_CONTEXT IrpContext
,
275 IN PUNICODE_STRING FullName
,
277 OUT PEXT2_MCB
* Ext2Mcb
,
281 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
282 UNICODE_STRING FileName
;
283 PEXT2_MCB Mcb
= NULL
;
284 struct dentry
*de
= NULL
;
289 BOOLEAN bParent
= FALSE
;
290 BOOLEAN bDirectory
= FALSE
;
291 BOOLEAN LockAcquired
= FALSE
;
295 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
300 DEBUG(DL_RES
, ("Ext2LookupFile: %wZ\n", FullName
));
302 /* check names and parameters */
303 if (FullName
->Buffer
[0] == L
'\\') {
304 Parent
= Vcb
->McbTree
;
308 Parent
= Vcb
->McbTree
;
311 /* make sure the parent is NULL */
312 if (!IsMcbDirectory(Parent
)) {
313 Status
= STATUS_NOT_A_DIRECTORY
;
317 /* use symlink's target as parent directory */
318 if (IsMcbSymLink(Parent
)) {
319 Parent
= Parent
->Target
;
320 ASSERT(!IsMcbSymLink(Parent
));
321 if (IsFileDeleted(Parent
)) {
322 Status
= STATUS_NOT_A_DIRECTORY
;
327 if (NULL
== Parent
) {
328 Status
= STATUS_NOT_A_DIRECTORY
;
332 /* default is the parent Mcb*/
333 Ext2ReferMcb(Parent
);
336 /* is empty file name or root node */
337 End
= FullName
->Length
/sizeof(WCHAR
);
338 if ( (End
== 0) || (End
== 1 &&
339 FullName
->Buffer
[0] == L
'\\')) {
340 Status
= STATUS_SUCCESS
;
344 /* is a directory expected ? */
345 if (FullName
->Buffer
[End
- 1] == L
'\\') {
349 /* loop with every sub name */
354 /* zero the prefix '\' */
355 while (i
< End
&& FullName
->Buffer
[i
] == L
'\\') i
++;
358 /* zero the suffix '\' */
359 while (i
< End
&& (FullName
->Buffer
[i
] != L
'\\')) i
++;
363 FileName
= *FullName
;
364 FileName
.Buffer
+= Start
;
365 FileName
.Length
= (USHORT
)((i
- Start
) * 2);
367 /* make sure the parent is NULL */
368 if (!IsMcbDirectory(Parent
)) {
369 Status
= STATUS_NOT_A_DIRECTORY
;
370 Ext2DerefMcb(Parent
);
374 if (IsMcbSymLink(Parent
)) {
375 if (IsFileDeleted(Parent
->Target
)) {
376 Status
= STATUS_NOT_A_DIRECTORY
;
377 Ext2DerefMcb(Parent
);
380 Ext2ReferMcb(Parent
->Target
);
381 Ext2DerefMcb(Parent
);
382 Parent
= Parent
->Target
;
386 /* search cached Mcb nodes */
387 Mcb
= Ext2SearchMcbWithoutLock(Parent
, &FileName
);
391 /* derefer the parent Mcb */
392 Ext2DerefMcb(Parent
);
393 Status
= STATUS_SUCCESS
;
396 if (IsMcbSymLink(Mcb
) && IsFileDeleted(Mcb
->Target
) &&
397 (Mcb
->Refercount
== 1)) {
400 ASSERT(Mcb
->Target
->Refercount
> 0);
401 Ext2DerefMcb(Mcb
->Target
);
403 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
404 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
405 Mcb
->FileAttr
= FILE_ATTRIBUTE_NORMAL
;
410 /* need create new Mcb node */
412 /* is a valid ext2 name */
413 if (!Ext2IsNameValid(&FileName
)) {
414 Status
= STATUS_OBJECT_NAME_INVALID
;
415 Ext2DerefMcb(Parent
);
421 Status
= Ext2ScanDir (
429 if (NT_SUCCESS(Status
)) {
431 /* check it's real parent */
432 ASSERT (!IsMcbSymLink(Parent
));
434 /* allocate Mcb ... */
435 Mcb
= Ext2AllocateMcb(Vcb
, &FileName
, &Parent
->FullName
, 0);
437 Status
= STATUS_INSUFFICIENT_RESOURCES
;
438 Ext2DerefMcb(Parent
);
442 Mcb
->de
->d_inode
= &Mcb
->Inode
;
443 Mcb
->Inode
.i_ino
= Inode
;
444 Mcb
->Inode
.i_sb
= &Vcb
->sb
;
447 /* load inode information */
448 if (!Ext2LoadInode(Vcb
, &Mcb
->Inode
)) {
449 Status
= STATUS_CANT_WAIT
;
450 Ext2DerefMcb(Parent
);
451 Ext2FreeMcb(Vcb
, Mcb
);
455 /* set inode attribute */
456 if (!CanIWrite(Vcb
) && Ext2IsOwnerReadOnly(Mcb
->Inode
.i_mode
)) {
457 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_READONLY
);
460 if (S_ISDIR(Mcb
->Inode
.i_mode
)) {
461 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_DIRECTORY
);
463 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_NORMAL
);
464 if (!S_ISREG(Mcb
->Inode
.i_mode
) &&
465 !S_ISLNK(Mcb
->Inode
.i_mode
)) {
466 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
470 /* process special files under root directory */
471 if (IsMcbRoot(Parent
)) {
472 /* set hidden and system attributes for
473 Recycled / RECYCLER / pagefile.sys */
474 BOOLEAN IsDirectory
= IsMcbDirectory(Mcb
);
475 if (Ext2IsSpecialSystemFile(&Mcb
->ShortName
, IsDirectory
)) {
476 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_HIDDEN
);
477 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_SYSTEM
);
481 Mcb
->CreationTime
= Ext2NtTime(Mcb
->Inode
.i_ctime
);
482 Mcb
->LastAccessTime
= Ext2NtTime(Mcb
->Inode
.i_atime
);
483 Mcb
->LastWriteTime
= Ext2NtTime(Mcb
->Inode
.i_mtime
);
484 Mcb
->ChangeTime
= Ext2NtTime(Mcb
->Inode
.i_mtime
);
486 /* process symlink */
487 if (S_ISLNK(Mcb
->Inode
.i_mode
)) {
488 Ext2FollowLink( IrpContext
,
496 /* add reference ... */
499 /* add Mcb to it's parent tree*/
500 Ext2InsertMcb(Vcb
, Parent
, Mcb
);
502 /* it's safe to deref Parent Mcb */
503 Ext2DerefMcb(Parent
);
505 /* linking this Mcb*/
506 Ext2LinkTailMcb(Vcb
, Mcb
);
508 /* set parent to preare re-scan */
513 /* derefernce it's parent */
514 Ext2DerefMcb(Parent
);
521 /* there seems too many \ or / */
522 /* Mcb should be already set to Parent */
523 ASSERT(Mcb
== Parent
);
524 Status
= STATUS_SUCCESS
;
535 if (NT_SUCCESS(Status
)) {
537 if (IsMcbDirectory(Mcb
)) {
541 Status
= STATUS_NOT_A_DIRECTORY
;
549 ExReleaseResourceLite(&Vcb
->McbLock
);
559 IN PEXT2_IRP_CONTEXT IrpContext
,
562 IN PUNICODE_STRING FileName
,
564 OUT
struct dentry
**dentry
567 struct ext3_dir_entry_2
*dir_entry
= NULL
;
568 struct buffer_head
*bh
= NULL
;
569 struct dentry
*de
= NULL
;
571 NTSTATUS Status
= STATUS_NO_SUCH_FILE
;
573 DEBUG(DL_RES
, ("Ext2ScanDir: %wZ\\%wZ\n", &Parent
->FullName
, FileName
));
577 /* grab parent's reference first */
578 Ext2ReferMcb(Parent
);
580 /* bad request ! Can a man be pregnant ? Maybe:) */
581 if (!IsMcbDirectory(Parent
)) {
582 Status
= STATUS_NOT_A_DIRECTORY
;
586 /* parent is a symlink ? */
587 if IsMcbSymLink(Parent
) {
588 if (Parent
->Target
) {
589 Ext2ReferMcb(Parent
->Target
);
590 Ext2DerefMcb(Parent
);
591 Parent
= Parent
->Target
;
592 ASSERT(!IsMcbSymLink(Parent
));
595 Status
= STATUS_NOT_A_DIRECTORY
;
600 de
= Ext2BuildEntry(Vcb
, Parent
, FileName
);
602 DEBUG(DL_ERR
, ( "Ex2ScanDir: failed to allocate dentry.\n"));
603 Status
= STATUS_INSUFFICIENT_RESOURCES
;
607 bh
= ext3_find_entry(IrpContext
, de
, &dir_entry
);
609 Status
= STATUS_SUCCESS
;
610 *Inode
= dir_entry
->inode
;
616 Ext2DerefMcb(Parent
);
621 if (!NT_SUCCESS(Status
)) {
630 NTSTATUS
Ext2AddDotEntries(struct ext2_icb
*icb
, struct inode
*dir
,
633 struct ext3_dir_entry_2
* de
;
634 struct buffer_head
* bh
;
635 ext3_lblk_t block
= 0;
638 bh
= ext3_append(icb
, inode
, &block
, &rc
);
643 de
= (struct ext3_dir_entry_2
*) bh
->b_data
;
644 de
->inode
= cpu_to_le32(inode
->i_ino
);
646 de
->rec_len
= cpu_to_le16(EXT3_DIR_REC_LEN(de
->name_len
));
647 strcpy (de
->name
, ".");
648 ext3_set_de_type(inode
->i_sb
, de
, S_IFDIR
);
649 de
= (struct ext3_dir_entry_2
*)
650 ((char *) de
+ le16_to_cpu(de
->rec_len
));
651 de
->inode
= cpu_to_le32(dir
->i_ino
);
652 de
->rec_len
= cpu_to_le16(inode
->i_sb
->s_blocksize
-EXT3_DIR_REC_LEN(1));
654 strcpy (de
->name
, "..");
655 ext3_set_de_type(inode
->i_sb
, de
, S_IFDIR
);
657 set_buffer_dirty(bh
);
658 ext3_mark_inode_dirty(icb
, inode
);
664 return Ext2WinntError(rc
);
669 PEXT2_IRP_CONTEXT IrpContext
,
674 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
675 PIO_STACK_LOCATION IrpSp
;
676 PEXT2_FCB Fcb
= NULL
;
677 PEXT2_MCB Mcb
= NULL
;
678 PEXT2_MCB SymLink
= NULL
;
679 PEXT2_CCB Ccb
= NULL
;
681 PEXT2_FCB ParentFcb
= NULL
;
682 PEXT2_MCB ParentMcb
= NULL
;
684 UNICODE_STRING FileName
;
688 ULONG CreateDisposition
;
690 BOOLEAN bParentFcbCreated
= FALSE
;
693 BOOLEAN bDir
= FALSE
;
695 BOOLEAN bFcbAllocated
= FALSE
;
696 BOOLEAN bCreated
= FALSE
;
697 BOOLEAN bMainResourceAcquired
= FALSE
;
699 BOOLEAN OpenDirectory
;
700 BOOLEAN OpenTargetDirectory
;
701 BOOLEAN CreateDirectory
;
702 BOOLEAN SequentialOnly
;
703 BOOLEAN NoIntermediateBuffering
;
704 BOOLEAN IsPagingFile
;
705 BOOLEAN DirectoryFile
;
706 BOOLEAN NonDirectoryFile
;
707 BOOLEAN NoEaKnowledge
;
708 BOOLEAN DeleteOnClose
;
709 BOOLEAN TemporaryFile
;
710 BOOLEAN CaseSensitive
;
712 ACCESS_MASK DesiredAccess
;
715 RtlZeroMemory(&FileName
, sizeof(UNICODE_STRING
));
717 Irp
= IrpContext
->Irp
;
718 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
720 Options
= IrpSp
->Parameters
.Create
.Options
;
722 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
723 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
725 NonDirectoryFile
= IsFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
726 SequentialOnly
= IsFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
727 NoIntermediateBuffering
= IsFlagOn( Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
728 NoEaKnowledge
= IsFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
729 DeleteOnClose
= IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
731 CaseSensitive
= IsFlagOn(IrpSp
->Flags
, SL_CASE_SENSITIVE
);
733 TemporaryFile
= IsFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
734 FILE_ATTRIBUTE_TEMPORARY
);
736 CreateDisposition
= (Options
>> 24) & 0x000000ff;
738 IsPagingFile
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
740 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
741 ((CreateDisposition
== FILE_CREATE
) ||
742 (CreateDisposition
== FILE_OPEN_IF
)));
744 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
745 ((CreateDisposition
== FILE_OPEN
) ||
746 (CreateDisposition
== FILE_OPEN_IF
)));
748 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
749 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
755 FileName
.MaximumLength
= IrpSp
->FileObject
->FileName
.MaximumLength
;
756 FileName
.Length
= IrpSp
->FileObject
->FileName
.Length
;
758 if (IrpSp
->FileObject
->RelatedFileObject
) {
759 ParentFcb
= (PEXT2_FCB
)(IrpSp
->FileObject
->RelatedFileObject
->FsContext
);
763 ParentMcb
= ParentFcb
->Mcb
;
764 SetLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
765 Ext2ReferMcb(ParentMcb
);
768 if (FileName
.Length
== 0) {
771 Mcb
= ParentFcb
->Mcb
;
773 Status
= STATUS_SUCCESS
;
777 Status
= STATUS_INVALID_PARAMETER
;
782 FileName
.Buffer
= Ext2AllocatePool(
784 FileName
.MaximumLength
,
788 if (!FileName
.Buffer
) {
789 DEBUG(DL_ERR
, ( "Ex2CreateFile: failed to allocate FileName.\n"));
790 Status
= STATUS_INSUFFICIENT_RESOURCES
;
794 INC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
796 RtlZeroMemory(FileName
.Buffer
, FileName
.MaximumLength
);
797 RtlCopyMemory(FileName
.Buffer
, IrpSp
->FileObject
->FileName
.Buffer
, FileName
.Length
);
799 if (ParentFcb
&& FileName
.Buffer
[0] == L
'\\') {
800 Status
= STATUS_INVALID_PARAMETER
;
804 if ((FileName
.Length
> sizeof(WCHAR
)) &&
805 (FileName
.Buffer
[1] == L
'\\') &&
806 (FileName
.Buffer
[0] == L
'\\')) {
808 FileName
.Length
-= sizeof(WCHAR
);
810 RtlMoveMemory( &FileName
.Buffer
[0],
815 // Bad Name if there are still beginning backslashes.
818 if ((FileName
.Length
> sizeof(WCHAR
)) &&
819 (FileName
.Buffer
[1] == L
'\\') &&
820 (FileName
.Buffer
[0] == L
'\\')) {
822 Status
= STATUS_OBJECT_NAME_INVALID
;
827 if (IsFlagOn(Options
, FILE_OPEN_BY_FILE_ID
)) {
828 Status
= STATUS_NOT_IMPLEMENTED
;
832 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ Paging=%d Option: %xh:"
833 "Dir=%d NonDir=%d OpenTarget=%d NC=%d DeleteOnClose=%d\n",
834 &FileName
, IsPagingFile
, IrpSp
->Parameters
.Create
.Options
,
835 DirectoryFile
, NonDirectoryFile
, OpenTargetDirectory
,
836 NoIntermediateBuffering
, DeleteOnClose
));
838 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 1st: %wZ at %S\n",
839 &FileName
, ParentMcb
? ParentMcb
->FullName
.Buffer
: L
" "));
840 Status
= Ext2LookupFile(
849 if (!NT_SUCCESS(Status
)) {
851 UNICODE_STRING PathName
;
852 UNICODE_STRING RealName
;
853 UNICODE_STRING RemainName
;
861 if (PathName
.Buffer
[PathName
.Length
/2 - 1] == L
'\\') {
864 PathName
.Buffer
[PathName
.Length
/2] = 0;
866 DirectoryFile
= TRUE
;
871 if (PathName
.Buffer
[0] != L
'\\') {
872 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
875 ParentMcb
= Vcb
->McbTree
;
876 Ext2ReferMcb(ParentMcb
);
882 FsRtlDissectName(PathName
, &RealName
, &RemainName
);
884 if (((RemainName
.Length
!= 0) && (RemainName
.Buffer
[0] == L
'\\')) ||
885 (RealName
.Length
>= 256 * sizeof(WCHAR
))) {
886 Status
= STATUS_OBJECT_NAME_INVALID
;
890 if (RemainName
.Length
!= 0) {
892 PEXT2_MCB RetMcb
= NULL
;
894 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 2nd: %wZ\\%wZ\n",
895 &ParentMcb
->FullName
, &RealName
));
897 Status
= Ext2LookupFile (
905 /* quit name resolving loop */
906 if (!NT_SUCCESS(Status
)) {
907 if (Status
== STATUS_NO_SUCH_FILE
&& RemainName
.Length
!= 0) {
908 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
913 /* deref ParentMcb */
914 Ext2DerefMcb(ParentMcb
);
916 /* RetMcb is already refered */
918 PathName
= RemainName
;
920 /* symlink must use it's target */
921 if (IsMcbSymLink(ParentMcb
)) {
922 Ext2ReferMcb(ParentMcb
->Target
);
923 Ext2DerefMcb(ParentMcb
);
924 ParentMcb
= ParentMcb
->Target
;
925 ASSERT(!IsMcbSymLink(ParentMcb
));
932 if ( FsRtlDoesNameContainWildCards(&RealName
) ||
933 !Ext2IsNameValid(&RealName
)) {
934 Status
= STATUS_OBJECT_NAME_INVALID
;
938 /* clear BUSY bit from original ParentFcb */
940 ClearLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
943 /* get the ParentFcb, allocate it if needed ... */
944 ParentFcb
= ParentMcb
->Fcb
;
946 ParentFcb
= Ext2AllocateFcb(Vcb
, ParentMcb
);
948 Status
= STATUS_INSUFFICIENT_RESOURCES
;
951 bParentFcbCreated
= TRUE
;
952 Ext2ReferXcb(&ParentFcb
->ReferenceCount
);
954 SetLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
956 // We need to create a new one ?
957 if ((CreateDisposition
== FILE_CREATE
) ||
958 (CreateDisposition
== FILE_SUPERSEDE
) ||
959 (CreateDisposition
== FILE_OPEN_IF
) ||
960 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
962 if (IsVcbReadOnly(Vcb
)) {
963 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
967 if (!CanIWrite(Vcb
) && Ext2IsOwnerReadOnly(ParentFcb
->Mcb
->Inode
.i_mode
)) {
968 Status
= STATUS_ACCESS_DENIED
;
972 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
973 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
974 Vcb
->Vpb
->RealDevice
);
975 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
976 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
982 Status
= STATUS_INVALID_PARAMETER
;
988 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
992 /* allocate inode and construct entry for this file */
993 Status
= Ext2CreateInode(
997 DirectoryFile
? EXT2_FT_DIR
: EXT2_FT_REG_FILE
,
998 IrpSp
->Parameters
.Create
.FileAttributes
,
1002 if (!NT_SUCCESS(Status
)) {
1008 DEBUG(DL_RES
, ("Ext2CreateFile: Confirm creation: %wZ\\%wZ\n",
1009 &ParentMcb
->FullName
, &RealName
));
1011 Irp
->IoStatus
.Information
= FILE_CREATED
;
1012 Status
= Ext2LookupFile (
1019 if (!NT_SUCCESS(Status
)) {
1023 } else if (OpenTargetDirectory
) {
1025 if (IsVcbReadOnly(Vcb
)) {
1026 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1031 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
1035 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1036 IrpSp
->FileObject
->FileName
.MaximumLength
);
1037 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
;
1039 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1047 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
1048 Status
= STATUS_SUCCESS
;
1052 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1056 } else { // File / Dir already exists.
1058 /* here already get Mcb referred */
1059 if (OpenTargetDirectory
) {
1061 UNICODE_STRING RealName
= FileName
;
1064 while (RealName
.Buffer
[RealName
.Length
/2 - 1] == L
'\\') {
1065 RealName
.Length
-= sizeof(WCHAR
);
1066 RealName
.Buffer
[RealName
.Length
/2] = 0;
1068 i
= RealName
.Length
/2;
1069 while (i
> 0 && RealName
.Buffer
[i
- 1] != L
'\\')
1072 if (IsVcbReadOnly(Vcb
)) {
1073 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1078 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1079 Status
= STATUS_SUCCESS
;
1081 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1082 IrpSp
->FileObject
->FileName
.MaximumLength
);
1083 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
- i
* sizeof(WCHAR
);
1084 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
, &RealName
.Buffer
[i
],
1085 IrpSp
->FileObject
->FileName
.Length
);
1087 // use's it's parent since it's open-target operation
1088 Ext2ReferMcb(Mcb
->Parent
);
1095 // We can not create if one exists
1096 if (CreateDisposition
== FILE_CREATE
) {
1097 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1098 Status
= STATUS_OBJECT_NAME_COLLISION
;
1103 /* directory forbits us to do the followings ... */
1104 if (IsMcbDirectory(Mcb
)) {
1106 if ((CreateDisposition
!= FILE_OPEN
) &&
1107 (CreateDisposition
!= FILE_OPEN_IF
)) {
1109 Status
= STATUS_OBJECT_NAME_COLLISION
;
1114 if (NonDirectoryFile
) {
1115 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1120 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
1122 if (OpenTargetDirectory
) {
1124 Status
= STATUS_INVALID_PARAMETER
;
1132 if (DirectoryFile
) {
1133 Status
= STATUS_NOT_A_DIRECTORY
;;
1139 Irp
->IoStatus
.Information
= FILE_OPENED
;
1143 /* Mcb should already be referred and symlink is too */
1146 ASSERT(Mcb
->Refercount
> 0);
1148 /* refer it's target if it's a symlink, so both refered */
1149 if (IsMcbSymLink(Mcb
)) {
1150 if (IsFileDeleted(Mcb
->Target
)) {
1152 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
1153 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
1154 Ext2DerefMcb(Mcb
->Target
);
1160 ASSERT (!IsMcbSymLink(Mcb
));
1164 // Check readonly flag
1165 if (!CanIWrite(Vcb
) && Ext2IsOwnerReadOnly(Mcb
->Inode
.i_mode
)) {
1166 if (BooleanFlagOn(DesiredAccess
, FILE_WRITE_DATA
| FILE_APPEND_DATA
|
1167 FILE_ADD_SUBDIRECTORY
| FILE_DELETE_CHILD
)) {
1168 Status
= STATUS_ACCESS_DENIED
;
1170 } else if (IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
)) {
1171 Status
= STATUS_CANNOT_DELETE
;
1179 /* allocate Fcb for this file */
1180 Fcb
= Ext2AllocateFcb (Vcb
, Mcb
);
1182 bFcbAllocated
= TRUE
;
1184 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1188 Status
= STATUS_SHARING_VIOLATION
;
1193 /* Now it's safe to defer Mcb */
1199 /* grab Fcb's reference first to avoid the race between
1200 Ext2Close (it could free the Fcb we are accessing) */
1201 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1203 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
1204 bMainResourceAcquired
= TRUE
;
1206 /* Open target directory ? */
1212 /* check Mcb reference */
1213 ASSERT(Fcb
->Mcb
->Refercount
> 0);
1216 if (IsFlagOn(Fcb
->Mcb
->Flags
, MCB_FILE_DELETED
)) {
1217 Status
= STATUS_FILE_DELETED
;
1221 if (DeleteOnClose
&& NULL
== SymLink
) {
1222 Status
= Ext2IsFileRemovable(IrpContext
, Vcb
, Fcb
, Ccb
);
1223 if (!NT_SUCCESS(Status
)) {
1228 /* check access and oplock access for opened files */
1229 if (!bFcbAllocated
&& !IsDirectory(Fcb
)) {
1231 /* whether there's batch oplock grabed on the file */
1232 if (FsRtlCurrentBatchOplock(&Fcb
->Oplock
)) {
1234 Irp
->IoStatus
.Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
1236 /* break the batch lock if the sharing check fails */
1237 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1243 if ( Status
!= STATUS_SUCCESS
&&
1244 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1254 // This file is just created.
1257 if (DirectoryFile
) {
1259 Status
= Ext2AddDotEntries(IrpContext
, &ParentMcb
->Inode
, &Mcb
->Inode
);
1260 if (!NT_SUCCESS(Status
)) {
1261 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1267 if ((LONGLONG
)ext3_free_blocks_count(SUPER_BLOCK
) <=
1268 Ext2TotalBlocks(Vcb
, &Irp
->Overlay
.AllocationSize
, NULL
)) {
1270 Status
= STATUS_DISK_FULL
;
1274 /* disable data blocks allocation */
1276 Fcb
->Header
.AllocationSize
.QuadPart
=
1277 Irp
->Overlay
.AllocationSize
.QuadPart
;
1279 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
1280 Status
= Ext2ExpandFile(IrpContext
,
1283 &(Fcb
->Header
.AllocationSize
)
1285 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
1286 if (!NT_SUCCESS(Status
)) {
1287 Fcb
->Header
.AllocationSize
.QuadPart
= 0;
1288 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
,
1289 &Fcb
->Header
.AllocationSize
);
1299 // This file alreayd exists.
1302 if (DeleteOnClose
) {
1304 if (IsVcbReadOnly(Vcb
)) {
1305 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1309 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1310 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1312 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1313 Vcb
->Vpb
->RealDevice
);
1315 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1317 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1323 // Just to Open file (Open/OverWrite ...)
1326 if ((!IsDirectory(Fcb
)) && (IsFlagOn(IrpSp
->FileObject
->Flags
,
1327 FO_NO_INTERMEDIATE_BUFFERING
))) {
1328 Fcb
->Header
.IsFastIoPossible
= FastIoIsPossible
;
1330 if (Fcb
->SectionObject
.DataSectionObject
!= NULL
) {
1332 if (Fcb
->NonCachedOpenCount
== Fcb
->OpenHandleCount
) {
1334 if (!IsVcbReadOnly(Vcb
)) {
1335 CcFlushCache(&Fcb
->SectionObject
, NULL
, 0, NULL
);
1336 ClearLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
1339 CcPurgeCacheSection(&Fcb
->SectionObject
,
1349 if (!IsDirectory(Fcb
)) {
1351 if (!IsVcbReadOnly(Vcb
)) {
1352 if ((CreateDisposition
== FILE_SUPERSEDE
) && !IsPagingFile
) {
1353 DesiredAccess
|= DELETE
;
1354 } else if (((CreateDisposition
== FILE_OVERWRITE
) ||
1355 (CreateDisposition
== FILE_OVERWRITE_IF
)) && !IsPagingFile
) {
1356 DesiredAccess
|= (FILE_WRITE_DATA
| FILE_WRITE_EA
|
1357 FILE_WRITE_ATTRIBUTES
);
1361 if (!bFcbAllocated
) {
1364 // check the oplock state of the file
1366 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1372 if ( Status
!= STATUS_SUCCESS
&&
1373 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1380 if (Fcb
->OpenHandleCount
> 0) {
1382 /* check the shrae access conflicts */
1383 Status
= IoCheckShareAccess( DesiredAccess
,
1386 &(Fcb
->ShareAccess
),
1388 if (!NT_SUCCESS(Status
)) {
1394 /* set share access rights */
1395 IoSetShareAccess( DesiredAccess
,
1398 &(Fcb
->ShareAccess
) );
1401 Ccb
= Ext2AllocateCcb(SymLink
);
1403 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1409 SetLongFlag(Ccb
->Flags
, CCB_DELETE_ON_CLOSE
);
1412 Ccb
->filp
.f_dentry
= SymLink
->de
;
1414 Ccb
->filp
.f_dentry
= Fcb
->Mcb
->de
;
1416 Ccb
->filp
.f_version
= Fcb
->Mcb
->Inode
.i_version
;
1417 Ext2ReferXcb(&Fcb
->OpenHandleCount
);
1418 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1420 if (!IsDirectory(Fcb
)) {
1421 if (NoIntermediateBuffering
) {
1422 Fcb
->NonCachedOpenCount
++;
1423 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1425 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1429 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1430 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1432 IrpSp
->FileObject
->FsContext
= (void*) Fcb
;
1433 IrpSp
->FileObject
->FsContext2
= (void*) Ccb
;
1434 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1435 IrpSp
->FileObject
->SectionObjectPointer
= &(Fcb
->SectionObject
);
1437 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ OpenCount=%u ReferCount=%u NonCachedCount=%u\n",
1438 &Fcb
->Mcb
->FullName
, Fcb
->OpenHandleCount
, Fcb
->ReferenceCount
, Fcb
->NonCachedOpenCount
));
1440 Status
= STATUS_SUCCESS
;
1444 if (IsDirectory(Fcb
)) {
1445 Ext2NotifyReportChange(
1449 FILE_NOTIFY_CHANGE_DIR_NAME
,
1450 FILE_ACTION_ADDED
);
1452 Ext2NotifyReportChange(
1456 FILE_NOTIFY_CHANGE_FILE_NAME
,
1457 FILE_ACTION_ADDED
);
1460 } else if (!IsDirectory(Fcb
)) {
1462 if ( DeleteOnClose
||
1463 IsFlagOn(DesiredAccess
, FILE_WRITE_DATA
) ||
1464 (CreateDisposition
== FILE_OVERWRITE
) ||
1465 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1466 if (!MmFlushImageSection( &Fcb
->SectionObject
,
1467 MmFlushForWrite
)) {
1469 Status
= DeleteOnClose
? STATUS_CANNOT_DELETE
:
1470 STATUS_SHARING_VIOLATION
;
1475 if ((CreateDisposition
== FILE_SUPERSEDE
) ||
1476 (CreateDisposition
== FILE_OVERWRITE
) ||
1477 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1479 if (IsDirectory(Fcb
)) {
1480 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1484 if (SymLink
!= NULL
) {
1486 Status
= STATUS_INVALID_PARAMETER
;
1490 if (IsVcbReadOnly(Vcb
)) {
1491 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1495 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1497 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1498 Vcb
->Vpb
->RealDevice
);
1499 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1500 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1503 Status
= Ext2SupersedeOrOverWriteFile(
1508 &Irp
->Overlay
.AllocationSize
,
1509 CreateDisposition
);
1511 if (!NT_SUCCESS(Status
)) {
1516 Ext2NotifyReportChange(
1520 FILE_NOTIFY_CHANGE_LAST_WRITE
|
1521 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
1522 FILE_NOTIFY_CHANGE_SIZE
,
1523 FILE_ACTION_MODIFIED
);
1526 if (CreateDisposition
== FILE_SUPERSEDE
) {
1527 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1529 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
1543 Ext2DerefMcb(ParentMcb
);
1546 /* cleanup Fcb and Ccb, Mcb if necessary */
1547 if (!NT_SUCCESS(Status
)) {
1553 ASSERT(Fcb
!= NULL
);
1554 ASSERT(Fcb
->Mcb
!= NULL
);
1556 DEBUG(DL_ERR
, ("Ext2CreateFile: failed to create %wZ status = %xh\n",
1557 &Fcb
->Mcb
->FullName
, Status
));
1559 Ext2DerefXcb(&Fcb
->OpenHandleCount
);
1560 Ext2DerefXcb(&Fcb
->ReferenceCount
);
1562 if (!IsDirectory(Fcb
)) {
1563 if (NoIntermediateBuffering
) {
1564 Fcb
->NonCachedOpenCount
--;
1566 ClearFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1570 Ext2DerefXcb(&Vcb
->OpenHandleCount
);
1571 Ext2DerefXcb(&Vcb
->ReferenceCount
);
1573 IoRemoveShareAccess(IrpSp
->FileObject
, &Fcb
->ShareAccess
);
1575 IrpSp
->FileObject
->FsContext
= NULL
;
1576 IrpSp
->FileObject
->FsContext2
= NULL
;
1577 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1578 IrpSp
->FileObject
->SectionObjectPointer
= NULL
;
1580 Ext2FreeCcb(Vcb
, Ccb
);
1584 if (Fcb
&& Ext2DerefXcb(&Fcb
->ReferenceCount
) == 0) {
1586 if (IsFlagOn(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
)) {
1589 ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
);
1592 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1594 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1599 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1604 bMainResourceAcquired
= FALSE
;
1607 if (bMainResourceAcquired
) {
1608 ExReleaseResourceLite(&Fcb
->MainResource
);
1611 /* free file name buffer */
1612 if (FileName
.Buffer
) {
1613 DEC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
1614 Ext2FreePool(FileName
.Buffer
, EXT2_FNAME_MAGIC
);
1617 /* dereference parent Fcb, free it if it goes to zero */
1619 ClearLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
1620 if (bParentFcbCreated
) {
1621 if (Ext2DerefXcb(&ParentFcb
->ReferenceCount
) == 0) {
1622 Ext2FreeFcb(ParentFcb
);
1627 /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer
1628 it already. It fails, we need release the refer to let it freed */
1630 Ext2DerefMcb(SymLink
);
1638 Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext
, PEXT2_VCB Vcb
)
1640 PIO_STACK_LOCATION IrpSp
;
1646 ACCESS_MASK DesiredAccess
;
1650 BOOLEAN DirectoryFile
;
1651 BOOLEAN OpenTargetDirectory
;
1653 ULONG CreateDisposition
;
1655 Irp
= IrpContext
->Irp
;
1656 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1658 Options
= IrpSp
->Parameters
.Create
.Options
;
1660 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
1661 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
1663 CreateDisposition
= (Options
>> 24) & 0x000000ff;
1665 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
1666 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
1668 if (DirectoryFile
) {
1669 return STATUS_NOT_A_DIRECTORY
;
1672 if (OpenTargetDirectory
) {
1674 return STATUS_INVALID_PARAMETER
;
1677 if ( (CreateDisposition
!= FILE_OPEN
) &&
1678 (CreateDisposition
!= FILE_OPEN_IF
) ) {
1679 return STATUS_ACCESS_DENIED
;
1682 if ( !FlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1683 Vcb
->OpenVolumeCount
!= 0 ) {
1684 return STATUS_SHARING_VIOLATION
;
1687 Ccb
= Ext2AllocateCcb(NULL
);
1689 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1693 Status
= STATUS_SUCCESS
;
1695 if (Vcb
->OpenVolumeCount
> 0) {
1696 Status
= IoCheckShareAccess( DesiredAccess
, ShareAccess
,
1698 &(Vcb
->ShareAccess
), TRUE
);
1700 if (!NT_SUCCESS(Status
)) {
1704 IoSetShareAccess( DesiredAccess
, ShareAccess
,
1706 &(Vcb
->ShareAccess
) );
1710 if (Vcb
->OpenVolumeCount
== 0 &&
1711 !IsFlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1712 !IsFlagOn(ShareAccess
, FILE_SHARE_WRITE
) ){
1714 if (!IsVcbReadOnly(Vcb
)) {
1715 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1716 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1719 SetLongFlag(Vcb
->Flags
, VCB_VOLUME_LOCKED
);
1720 Vcb
->LockFile
= IrpSp
->FileObject
;
1722 if (FlagOn(DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
) ) {
1723 if (!IsVcbReadOnly(Vcb
)) {
1724 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1725 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1730 IrpSp
->FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
1731 IrpSp
->FileObject
->FsContext
= Vcb
;
1732 IrpSp
->FileObject
->FsContext2
= Ccb
;
1733 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1735 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1736 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1737 Ext2ReferXcb(&Vcb
->OpenVolumeCount
);
1739 Irp
->IoStatus
.Information
= FILE_OPENED
;
1748 Ext2Create (IN PEXT2_IRP_CONTEXT IrpContext
)
1750 PDEVICE_OBJECT DeviceObject
;
1752 PIO_STACK_LOCATION IrpSp
;
1754 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1755 PEXT2_FCBVCB Xcb
= NULL
;
1756 BOOLEAN PostIrp
= FALSE
;
1757 BOOLEAN VcbResourceAcquired
= FALSE
;
1759 DeviceObject
= IrpContext
->DeviceObject
;
1760 Irp
= IrpContext
->Irp
;
1761 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1763 Xcb
= (PEXT2_FCBVCB
) (IrpSp
->FileObject
->FsContext
);
1765 if (IsExt2FsDevice(DeviceObject
)) {
1767 DEBUG(DL_INF
, ( "Ext2Create: Create on main device object.\n"));
1769 Status
= STATUS_SUCCESS
;
1770 Irp
->IoStatus
.Information
= FILE_OPENED
;
1772 Ext2CompleteIrpContext(IrpContext
, Status
);
1779 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1780 ASSERT(Vcb
->Identifier
.Type
== EXT2VCB
);
1781 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1783 if (!IsMounted(Vcb
)) {
1785 if (IsFlagOn(Vcb
->Flags
, VCB_DEVICE_REMOVED
)) {
1786 Status
= STATUS_NO_SUCH_DEVICE
;
1788 Status
= STATUS_VOLUME_DISMOUNTED
;
1793 if (!ExAcquireResourceExclusiveLite(
1794 &Vcb
->MainResource
, TRUE
)) {
1795 Status
= STATUS_PENDING
;
1798 VcbResourceAcquired
= TRUE
;
1800 Ext2VerifyVcb(IrpContext
, Vcb
);
1802 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
1803 Status
= STATUS_ACCESS_DENIED
;
1804 if (IsFlagOn(Vcb
->Flags
, VCB_DISMOUNT_PENDING
)) {
1805 Status
= STATUS_VOLUME_DISMOUNTED
;
1810 if ( ((IrpSp
->FileObject
->FileName
.Length
== 0) &&
1811 (IrpSp
->FileObject
->RelatedFileObject
== NULL
)) ||
1812 (Xcb
&& Xcb
->Identifier
.Type
== EXT2VCB
) ) {
1813 Status
= Ext2CreateVolume(IrpContext
, Vcb
);
1816 Status
= Ext2CreateFile(IrpContext
, Vcb
, &PostIrp
);
1821 if (VcbResourceAcquired
) {
1822 ExReleaseResourceLite(&Vcb
->MainResource
);
1825 if (!IrpContext
->ExceptionInProgress
&& !PostIrp
) {
1826 if ( Status
== STATUS_PENDING
||
1827 Status
== STATUS_CANT_WAIT
) {
1828 Status
= Ext2QueueRequest(IrpContext
);
1830 Ext2CompleteIrpContext(IrpContext
, Status
);
1840 PEXT2_IRP_CONTEXT IrpContext
,
1845 PUNICODE_STRING FileName
)
1850 struct inode Inode
= { 0 };
1851 struct dentry
*Dentry
= NULL
;
1853 LARGE_INTEGER SysTime
;
1855 iGrp
= (Parent
->Inode
->i_ino
- 1) / BLOCKS_PER_GROUP
;
1857 DEBUG(DL_INF
, ("Ext2CreateInode: %S in %S(Inode=%xh)\n",
1859 Parent
->Mcb
->ShortName
.Buffer
,
1860 Parent
->Inode
->i_ino
));
1862 Status
= Ext2NewInode(IrpContext
, Vcb
, iGrp
, Type
, &iNo
);
1863 if (!NT_SUCCESS(Status
)) {
1867 KeQuerySystemTime(&SysTime
);
1868 Ext2ClearInode(IrpContext
, Vcb
, iNo
);
1869 Inode
.i_sb
= &Vcb
->sb
;
1871 Inode
.i_ctime
= Inode
.i_mtime
=
1872 Inode
.i_atime
= Ext2LinuxTime(SysTime
);
1873 Inode
.i_uid
= Parent
->Inode
->i_uid
;
1874 Inode
.i_gid
= Parent
->Inode
->i_gid
;
1875 Inode
.i_generation
= Parent
->Inode
->i_generation
;
1876 Inode
.i_mode
= S_IPERMISSION_MASK
&
1877 Parent
->Inode
->i_mode
;
1878 if (Type
== EXT2_FT_DIR
) {
1879 Inode
.i_mode
|= S_IFDIR
;
1880 } else if (Type
== EXT2_FT_REG_FILE
) {
1881 Inode
.i_mode
&= S_IFATTR
;
1882 Inode
.i_mode
|= S_IFREG
;
1887 /* Force using extent */
1888 if (IsFlagOn(SUPER_BLOCK
->s_feature_incompat
, EXT4_FEATURE_INCOMPAT_EXTENTS
)) {
1889 Inode
.i_flags
|= EXT2_EXTENTS_FL
;
1892 /* add new entry to its parent */
1893 Status
= Ext2AddEntry(
1902 if (!NT_SUCCESS(Status
)) {
1904 Ext2FreeInode(IrpContext
, Vcb
, iNo
, Type
);
1908 DEBUG(DL_INF
, ("Ext2CreateInode: New Inode = %xh (Type=%xh)\n",
1909 Inode
.i_ino
, Type
));
1914 Ext2FreeEntry(Dentry
);
1921 Ext2SupersedeOrOverWriteFile(
1922 IN PEXT2_IRP_CONTEXT IrpContext
,
1923 IN PFILE_OBJECT FileObject
,
1926 IN PLARGE_INTEGER AllocationSize
,
1927 IN ULONG Disposition
1930 LARGE_INTEGER CurrentTime
;
1933 KeQuerySystemTime(&CurrentTime
);
1936 if (!MmCanFileBeTruncated(&(Fcb
->SectionObject
), &(Size
))) {
1937 return STATUS_USER_MAPPED_FILE
;
1940 /* purge all file cache and shrink cache windows size */
1941 CcPurgeCacheSection(&Fcb
->SectionObject
, NULL
, 0, FALSE
);
1942 Fcb
->Header
.AllocationSize
.QuadPart
=
1943 Fcb
->Header
.FileSize
.QuadPart
=
1944 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1945 CcSetFileSizes(FileObject
,
1946 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1948 Size
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
1949 (ULONGLONG
)AllocationSize
->QuadPart
,
1950 (ULONGLONG
)BLOCK_SIZE
);
1952 if ((loff_t
)Size
.QuadPart
> Fcb
->Inode
->i_size
) {
1953 Ext2ExpandFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1955 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1958 Fcb
->Header
.AllocationSize
= Size
;
1959 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
1960 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
1961 CcSetFileSizes(FileObject
,
1962 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1965 /* remove all extent mappings */
1966 DEBUG(DL_EXT
, ("Ext2SuperSede ...: %wZ\n", &Fcb
->Mcb
->FullName
));
1967 Fcb
->Inode
->i_size
= 0;
1969 if (Disposition
== FILE_SUPERSEDE
) {
1970 Fcb
->Inode
->i_ctime
= Ext2LinuxTime(CurrentTime
);
1972 Fcb
->Inode
->i_atime
=
1973 Fcb
->Inode
->i_mtime
= Ext2LinuxTime(CurrentTime
);
1974 Ext2SaveInode(IrpContext
, Vcb
, Fcb
->Inode
);
1976 return STATUS_SUCCESS
;