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_blocks
) {
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
= Ext2ReadSymlink(
121 (ULONG
)(Mcb
->Inode
.i_size
),
123 if (!NT_SUCCESS(Status
)) {
128 /* convert Linux slash to Windows backslash */
129 for (i
=0; i
< OemName
.Length
; i
++) {
130 if (OemName
.Buffer
[i
] == '/') {
131 OemName
.Buffer
[i
] = '\\';
135 /* convert oem string to unicode string */
136 UniName
.MaximumLength
= (USHORT
)Ext2OEMToUnicodeSize(Vcb
, &OemName
);
137 if (UniName
.MaximumLength
<= 0) {
138 Status
= STATUS_INSUFFICIENT_RESOURCES
;
142 UniName
.MaximumLength
+= 2;
143 UniName
.Buffer
= Ext2AllocatePool(PagedPool
,
144 UniName
.MaximumLength
,
146 if (UniName
.Buffer
== NULL
) {
147 Status
= STATUS_INSUFFICIENT_RESOURCES
;
150 RtlZeroMemory(UniName
.Buffer
, UniName
.MaximumLength
);
151 Status
= Ext2OEMToUnicode(Vcb
, &UniName
, &OemName
);
152 if (!NT_SUCCESS(Status
)) {
153 Status
= STATUS_INSUFFICIENT_RESOURCES
;
157 /* search the real target */
158 Status
= Ext2LookupFile(
166 if (Target
== NULL
) {
167 Status
= STATUS_LINK_FAILED
;
170 if (Target
== NULL
/* link target doesn't exist */ ||
171 Target
== Mcb
/* symlink points to itself */ ||
172 IsMcbSpecialFile(Target
) /* target not resolved*/ ||
173 IsFileDeleted(Target
) /* target deleted */ ) {
176 ASSERT(Target
->Refercount
> 0);
177 Ext2DerefMcb(Target
);
179 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
180 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
183 } else if (IsMcbSymLink(Target
)) {
185 ASSERT(Target
->Refercount
> 0);
186 ASSERT(Target
->Target
!= NULL
);
187 Ext2ReferMcb(Target
->Target
);
188 Mcb
->Target
= Target
->Target
;
189 Ext2DerefMcb(Target
);
190 ASSERT(!IsMcbSymLink(Target
->Target
));
191 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
192 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
193 ASSERT(Mcb
->Target
->Refercount
> 0);
197 Mcb
->Target
= Target
;
198 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
199 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
200 ASSERT(Mcb
->Target
->Refercount
> 0);
203 /* add directory flag to file attribute */
204 if (Mcb
->Target
&& IsMcbDirectory(Mcb
->Target
)) {
205 Mcb
->FileAttr
|= FILE_ATTRIBUTE_DIRECTORY
;
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
;
292 BOOLEAN bNotFollow
= FALSE
;
296 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
299 bNotFollow
= IsFlagOn(Linkdep
, EXT2_LOOKUP_NOT_FOLLOW
);
301 Linkdep
= ClearFlag(Linkdep
, EXT2_LOOKUP_FLAG_MASK
);
303 ClearFlag(Linkdep
, EXT2_LOOKUP_FLAG_MASK
);
308 DEBUG(DL_RES
, ("Ext2LookupFile: %wZ\n", FullName
));
310 /* check names and parameters */
311 if (FullName
->Buffer
[0] == L
'\\') {
312 Parent
= Vcb
->McbTree
;
316 Parent
= Vcb
->McbTree
;
319 /* make sure the parent is NULL */
320 if (!IsMcbDirectory(Parent
)) {
321 Status
= STATUS_NOT_A_DIRECTORY
;
325 /* use symlink's target as parent directory */
326 if (IsMcbSymLink(Parent
)) {
327 Parent
= Parent
->Target
;
328 ASSERT(!IsMcbSymLink(Parent
));
329 if (IsFileDeleted(Parent
)) {
330 Status
= STATUS_NOT_A_DIRECTORY
;
335 if (NULL
== Parent
) {
336 Status
= STATUS_NOT_A_DIRECTORY
;
340 /* default is the parent Mcb*/
341 Ext2ReferMcb(Parent
);
344 /* is empty file name or root node */
345 End
= FullName
->Length
/sizeof(WCHAR
);
346 if ( (End
== 0) || (End
== 1 &&
347 FullName
->Buffer
[0] == L
'\\')) {
348 Status
= STATUS_SUCCESS
;
352 /* is a directory expected ? */
353 if (FullName
->Buffer
[End
- 1] == L
'\\') {
357 /* loop with every sub name */
362 /* zero the prefix '\' */
363 while (i
< End
&& FullName
->Buffer
[i
] == L
'\\') i
++;
366 /* zero the suffix '\' */
367 while (i
< End
&& (FullName
->Buffer
[i
] != L
'\\')) i
++;
371 FileName
= *FullName
;
372 FileName
.Buffer
+= Start
;
373 FileName
.Length
= (USHORT
)((i
- Start
) * 2);
375 /* make sure the parent is NULL */
376 if (!IsMcbDirectory(Parent
)) {
377 Status
= STATUS_NOT_A_DIRECTORY
;
378 Ext2DerefMcb(Parent
);
382 if (IsMcbSymLink(Parent
)) {
383 if (IsFileDeleted(Parent
->Target
)) {
384 Status
= STATUS_NOT_A_DIRECTORY
;
385 Ext2DerefMcb(Parent
);
388 Ext2ReferMcb(Parent
->Target
);
389 Ext2DerefMcb(Parent
);
390 Parent
= Parent
->Target
;
394 /* search cached Mcb nodes */
395 Mcb
= Ext2SearchMcbWithoutLock(Parent
, &FileName
);
399 /* derefer the parent Mcb */
400 Ext2DerefMcb(Parent
);
401 Status
= STATUS_SUCCESS
;
404 if (IsMcbSymLink(Mcb
) && IsFileDeleted(Mcb
->Target
) &&
405 Mcb
->Refercount
== 1) {
408 ASSERT(Mcb
->Target
->Refercount
> 0);
409 Ext2DerefMcb(Mcb
->Target
);
411 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
412 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
413 Mcb
->FileAttr
= FILE_ATTRIBUTE_NORMAL
;
418 /* need create new Mcb node */
420 /* is a valid ext2 name */
421 if (!Ext2IsNameValid(&FileName
)) {
422 Status
= STATUS_OBJECT_NAME_INVALID
;
423 Ext2DerefMcb(Parent
);
429 Status
= Ext2ScanDir (
437 if (NT_SUCCESS(Status
)) {
439 /* check it's real parent */
440 ASSERT (!IsMcbSymLink(Parent
));
442 /* allocate Mcb ... */
443 Mcb
= Ext2AllocateMcb(Vcb
, &FileName
, &Parent
->FullName
, 0);
445 Status
= STATUS_INSUFFICIENT_RESOURCES
;
446 Ext2DerefMcb(Parent
);
450 Mcb
->de
->d_inode
= &Mcb
->Inode
;
451 Mcb
->Inode
.i_ino
= Inode
;
452 Mcb
->Inode
.i_sb
= &Vcb
->sb
;
455 /* load inode information */
456 if (!Ext2LoadInode(Vcb
, &Mcb
->Inode
)) {
457 Status
= STATUS_CANT_WAIT
;
458 Ext2DerefMcb(Parent
);
459 Ext2FreeMcb(Vcb
, Mcb
);
463 /* set inode attribute */
464 if (!Ext2CheckFileAccess(Vcb
, Mcb
, Ext2FileCanWrite
)) {
465 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_READONLY
);
468 if (S_ISDIR(Mcb
->Inode
.i_mode
)) {
469 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_DIRECTORY
);
471 if (S_ISREG(Mcb
->Inode
.i_mode
)) {
472 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_NORMAL
);
473 } else if (S_ISLNK(Mcb
->Inode
.i_mode
)) {
474 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_REPARSE_POINT
);
476 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
480 /* process special files under root directory */
481 if (IsMcbRoot(Parent
)) {
482 /* set hidden and system attributes for
483 Recycled / RECYCLER / pagefile.sys */
484 BOOLEAN IsDirectory
= IsMcbDirectory(Mcb
);
485 if (Ext2IsSpecialSystemFile(&Mcb
->ShortName
, IsDirectory
)) {
486 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_HIDDEN
);
487 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_SYSTEM
);
491 Mcb
->CreationTime
= Ext2NtTime(Mcb
->Inode
.i_ctime
);
492 Mcb
->LastAccessTime
= Ext2NtTime(Mcb
->Inode
.i_atime
);
493 Mcb
->LastWriteTime
= Ext2NtTime(Mcb
->Inode
.i_mtime
);
494 Mcb
->ChangeTime
= Ext2NtTime(Mcb
->Inode
.i_mtime
);
496 /* process symlink */
497 if (S_ISLNK(Mcb
->Inode
.i_mode
) && !bNotFollow
) {
498 Ext2FollowLink( IrpContext
,
506 /* add reference ... */
509 /* add Mcb to it's parent tree*/
510 Ext2InsertMcb(Vcb
, Parent
, Mcb
);
512 /* it's safe to deref Parent Mcb */
513 Ext2DerefMcb(Parent
);
515 /* linking this Mcb*/
516 Ext2LinkTailMcb(Vcb
, Mcb
);
518 /* set parent to preare re-scan */
523 /* derefernce it's parent */
524 Ext2DerefMcb(Parent
);
531 /* there seems too many \ or / */
532 /* Mcb should be already set to Parent */
533 ASSERT(Mcb
== Parent
);
534 Status
= STATUS_SUCCESS
;
545 if (NT_SUCCESS(Status
)) {
547 if (IsMcbDirectory(Mcb
)) {
551 Status
= STATUS_NOT_A_DIRECTORY
;
559 ExReleaseResourceLite(&Vcb
->McbLock
);
569 IN PEXT2_IRP_CONTEXT IrpContext
,
572 IN PUNICODE_STRING FileName
,
574 OUT
struct dentry
**dentry
577 struct ext3_dir_entry_2
*dir_entry
= NULL
;
578 struct buffer_head
*bh
= NULL
;
579 struct dentry
*de
= NULL
;
581 NTSTATUS Status
= STATUS_NO_SUCH_FILE
;
583 DEBUG(DL_RES
, ("Ext2ScanDir: %wZ\\%wZ\n", &Parent
->FullName
, FileName
));
587 /* grab parent's reference first */
588 Ext2ReferMcb(Parent
);
590 /* bad request ! Can a man be pregnant ? Maybe:) */
591 if (!IsMcbDirectory(Parent
)) {
592 Status
= STATUS_NOT_A_DIRECTORY
;
596 /* parent is a symlink ? */
597 if IsMcbSymLink(Parent
) {
598 if (Parent
->Target
) {
599 Ext2ReferMcb(Parent
->Target
);
600 Ext2DerefMcb(Parent
);
601 Parent
= Parent
->Target
;
602 ASSERT(!IsMcbSymLink(Parent
));
605 Status
= STATUS_NOT_A_DIRECTORY
;
610 de
= Ext2BuildEntry(Vcb
, Parent
, FileName
);
612 DEBUG(DL_ERR
, ( "Ex2ScanDir: failed to allocate dentry.\n"));
613 Status
= STATUS_INSUFFICIENT_RESOURCES
;
617 bh
= ext3_find_entry(IrpContext
, de
, &dir_entry
);
619 Status
= STATUS_SUCCESS
;
620 *Inode
= dir_entry
->inode
;
626 Ext2DerefMcb(Parent
);
631 if (!NT_SUCCESS(Status
)) {
640 NTSTATUS
Ext2AddDotEntries(struct ext2_icb
*icb
, struct inode
*dir
,
643 struct ext3_dir_entry_2
* de
;
644 struct buffer_head
* bh
;
645 ext3_lblk_t block
= 0;
648 bh
= ext3_append(icb
, inode
, &block
, &rc
);
653 de
= (struct ext3_dir_entry_2
*) bh
->b_data
;
654 de
->inode
= cpu_to_le32(inode
->i_ino
);
656 de
->rec_len
= cpu_to_le16(EXT3_DIR_REC_LEN(de
->name_len
));
657 strcpy (de
->name
, ".");
658 ext3_set_de_type(inode
->i_sb
, de
, S_IFDIR
);
659 de
= (struct ext3_dir_entry_2
*)
660 ((char *) de
+ le16_to_cpu(de
->rec_len
));
661 de
->inode
= cpu_to_le32(dir
->i_ino
);
662 de
->rec_len
= cpu_to_le16(inode
->i_sb
->s_blocksize
-EXT3_DIR_REC_LEN(1));
664 strcpy (de
->name
, "..");
665 ext3_set_de_type(inode
->i_sb
, de
, S_IFDIR
);
667 set_buffer_dirty(bh
);
668 ext3_mark_inode_dirty(icb
, inode
);
674 return Ext2WinntError(rc
);
679 PEXT2_IRP_CONTEXT IrpContext
,
684 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
685 PIO_STACK_LOCATION IrpSp
;
686 PEXT2_FCB Fcb
= NULL
;
687 PEXT2_MCB Mcb
= NULL
;
688 PEXT2_MCB SymLink
= NULL
;
689 PEXT2_CCB Ccb
= NULL
;
691 PEXT2_FCB ParentFcb
= NULL
;
692 PEXT2_MCB ParentMcb
= NULL
;
694 UNICODE_STRING FileName
;
698 ULONG CreateDisposition
;
700 BOOLEAN bParentFcbCreated
= FALSE
;
702 BOOLEAN bDir
= FALSE
;
704 BOOLEAN bFcbAllocated
= FALSE
;
705 BOOLEAN bCreated
= FALSE
;
707 BOOLEAN bMainResourceAcquired
= FALSE
;
708 BOOLEAN bFcbLockAcquired
= FALSE
;
710 BOOLEAN OpenDirectory
;
711 BOOLEAN OpenTargetDirectory
;
712 BOOLEAN CreateDirectory
;
713 BOOLEAN SequentialOnly
;
714 BOOLEAN NoIntermediateBuffering
;
715 BOOLEAN IsPagingFile
;
716 BOOLEAN DirectoryFile
;
717 BOOLEAN NonDirectoryFile
;
718 BOOLEAN NoEaKnowledge
;
719 BOOLEAN DeleteOnClose
;
720 BOOLEAN TemporaryFile
;
721 BOOLEAN CaseSensitive
;
722 BOOLEAN OpenReparsePoint
;
724 ACCESS_MASK DesiredAccess
;
728 RtlZeroMemory(&FileName
, sizeof(UNICODE_STRING
));
730 Irp
= IrpContext
->Irp
;
731 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
733 Options
= IrpSp
->Parameters
.Create
.Options
;
735 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
736 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
738 NonDirectoryFile
= IsFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
739 SequentialOnly
= IsFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
740 NoIntermediateBuffering
= IsFlagOn( Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
741 NoEaKnowledge
= IsFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
742 DeleteOnClose
= IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
744 /* Try to open reparse point (symlink) itself ? */
745 OpenReparsePoint
= IsFlagOn(Options
, FILE_OPEN_REPARSE_POINT
);
747 CaseSensitive
= IsFlagOn(IrpSp
->Flags
, SL_CASE_SENSITIVE
);
749 TemporaryFile
= IsFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
750 FILE_ATTRIBUTE_TEMPORARY
);
752 CreateDisposition
= (Options
>> 24) & 0x000000ff;
754 IsPagingFile
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
756 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
757 ((CreateDisposition
== FILE_CREATE
) ||
758 (CreateDisposition
== FILE_OPEN_IF
)));
760 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
761 ((CreateDisposition
== FILE_OPEN
) ||
762 (CreateDisposition
== FILE_OPEN_IF
)));
764 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
765 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
771 FileName
.MaximumLength
= IrpSp
->FileObject
->FileName
.MaximumLength
;
772 FileName
.Length
= IrpSp
->FileObject
->FileName
.Length
;
774 if (IrpSp
->FileObject
->RelatedFileObject
) {
775 ParentFcb
= (PEXT2_FCB
)(IrpSp
->FileObject
->RelatedFileObject
->FsContext
);
779 ParentMcb
= ParentFcb
->Mcb
;
780 Ext2ReferMcb(ParentMcb
);
784 if (FileName
.Length
== 0) {
789 Status
= STATUS_SUCCESS
;
793 Status
= STATUS_INVALID_PARAMETER
;
798 FileName
.Buffer
= Ext2AllocatePool(
800 FileName
.MaximumLength
,
804 if (!FileName
.Buffer
) {
805 DEBUG(DL_ERR
, ( "Ex2CreateFile: failed to allocate FileName.\n"));
806 Status
= STATUS_INSUFFICIENT_RESOURCES
;
810 INC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
812 RtlZeroMemory(FileName
.Buffer
, FileName
.MaximumLength
);
813 RtlCopyMemory(FileName
.Buffer
, IrpSp
->FileObject
->FileName
.Buffer
, FileName
.Length
);
815 if (IrpSp
->FileObject
->RelatedFileObject
&& FileName
.Buffer
[0] == L
'\\') {
816 Status
= STATUS_INVALID_PARAMETER
;
820 if ((FileName
.Length
> sizeof(WCHAR
)) &&
821 (FileName
.Buffer
[1] == L
'\\') &&
822 (FileName
.Buffer
[0] == L
'\\')) {
824 FileName
.Length
-= sizeof(WCHAR
);
826 RtlMoveMemory( &FileName
.Buffer
[0],
831 // Bad Name if there are still beginning backslashes.
834 if ((FileName
.Length
> sizeof(WCHAR
)) &&
835 (FileName
.Buffer
[1] == L
'\\') &&
836 (FileName
.Buffer
[0] == L
'\\')) {
838 Status
= STATUS_OBJECT_NAME_INVALID
;
843 if (IsFlagOn(Options
, FILE_OPEN_BY_FILE_ID
)) {
844 Status
= STATUS_NOT_IMPLEMENTED
;
848 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ Paging=%d Option: %xh:"
849 "Dir=%d NonDir=%d OpenTarget=%d NC=%d DeleteOnClose=%d\n",
850 &FileName
, IsPagingFile
, IrpSp
->Parameters
.Create
.Options
,
851 DirectoryFile
, NonDirectoryFile
, OpenTargetDirectory
,
852 NoIntermediateBuffering
, DeleteOnClose
));
854 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 1st: %wZ at %S\n",
855 &FileName
, ParentMcb
? ParentMcb
->FullName
.Buffer
: L
" "));
856 Status
= Ext2LookupFile(
862 0 /* always follow link */
866 if (!NT_SUCCESS(Status
)) {
868 UNICODE_STRING PathName
;
869 UNICODE_STRING RealName
;
870 UNICODE_STRING RemainName
;
879 if (PathName
.Buffer
[PathName
.Length
/2 - 1] == L
'\\') {
882 PathName
.Buffer
[PathName
.Length
/2] = 0;
884 DirectoryFile
= TRUE
;
889 if (PathName
.Buffer
[0] != L
'\\') {
890 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
893 ParentMcb
= Vcb
->McbTree
;
894 Ext2ReferMcb(ParentMcb
);
900 FsRtlDissectName(PathName
, &RealName
, &RemainName
);
902 if (((RemainName
.Length
!= 0) && (RemainName
.Buffer
[0] == L
'\\')) ||
903 (RealName
.Length
>= 256 * sizeof(WCHAR
))) {
904 Status
= STATUS_OBJECT_NAME_INVALID
;
908 if (RemainName
.Length
!= 0) {
910 PEXT2_MCB RetMcb
= NULL
;
912 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 2nd: %wZ\\%wZ\n",
913 &ParentMcb
->FullName
, &RealName
));
915 Status
= Ext2LookupFile (
923 /* quit name resolving loop */
924 if (!NT_SUCCESS(Status
)) {
925 if (Status
== STATUS_NO_SUCH_FILE
&& RemainName
.Length
!= 0) {
926 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
931 /* deref ParentMcb */
932 Ext2DerefMcb(ParentMcb
);
934 /* RetMcb is already refered */
936 PathName
= RemainName
;
938 /* symlink must use it's target */
939 if (IsMcbSymLink(ParentMcb
)) {
940 Ext2ReferMcb(ParentMcb
->Target
);
941 Ext2DerefMcb(ParentMcb
);
942 ParentMcb
= ParentMcb
->Target
;
943 ASSERT(!IsMcbSymLink(ParentMcb
));
950 if ( FsRtlDoesNameContainWildCards(&RealName
) ||
951 !Ext2IsNameValid(&RealName
)) {
952 Status
= STATUS_OBJECT_NAME_INVALID
;
956 if (!bFcbLockAcquired
) {
957 ExAcquireResourceExclusiveLite(&Vcb
->FcbLock
, TRUE
);
958 bFcbLockAcquired
= TRUE
;
961 /* get the ParentFcb, allocate it if needed ... */
962 ParentFcb
= ParentMcb
->Fcb
;
964 ParentFcb
= Ext2AllocateFcb(Vcb
, ParentMcb
);
966 Status
= STATUS_INSUFFICIENT_RESOURCES
;
969 bParentFcbCreated
= TRUE
;
971 Ext2ReferXcb(&ParentFcb
->ReferenceCount
);
973 if (bFcbLockAcquired
) {
974 ExReleaseResourceLite(&Vcb
->FcbLock
);
975 bFcbLockAcquired
= FALSE
;
978 // We need to create a new one ?
979 if ((CreateDisposition
== FILE_CREATE
) ||
980 (CreateDisposition
== FILE_SUPERSEDE
) ||
981 (CreateDisposition
== FILE_OPEN_IF
) ||
982 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
984 if (IsVcbReadOnly(Vcb
)) {
985 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
989 if (!Ext2CheckFileAccess(Vcb
, ParentMcb
, Ext2FileCanWrite
)) {
990 Status
= STATUS_ACCESS_DENIED
;
994 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
995 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
996 Vcb
->Vpb
->RealDevice
);
997 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
998 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1001 if (DirectoryFile
) {
1002 if (TemporaryFile
) {
1004 Status
= STATUS_INVALID_PARAMETER
;
1010 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
1014 /* allocate inode and construct entry for this file */
1015 Status
= Ext2CreateInode(
1019 DirectoryFile
? EXT2_FT_DIR
: EXT2_FT_REG_FILE
,
1020 IrpSp
->Parameters
.Create
.FileAttributes
,
1024 if (!NT_SUCCESS(Status
)) {
1030 DEBUG(DL_RES
, ("Ext2CreateFile: Confirm creation: %wZ\\%wZ\n",
1031 &ParentMcb
->FullName
, &RealName
));
1033 Irp
->IoStatus
.Information
= FILE_CREATED
;
1034 Status
= Ext2LookupFile (
1041 if (!NT_SUCCESS(Status
)) {
1045 } else if (OpenTargetDirectory
) {
1047 if (IsVcbReadOnly(Vcb
)) {
1048 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1053 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
1057 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1058 IrpSp
->FileObject
->FileName
.MaximumLength
);
1059 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
;
1061 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1069 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
1070 Status
= STATUS_SUCCESS
;
1074 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1078 } else { // File / Dir already exists.
1080 /* here already get Mcb referred */
1081 if (OpenTargetDirectory
) {
1083 UNICODE_STRING RealName
= FileName
;
1086 while (RealName
.Buffer
[RealName
.Length
/2 - 1] == L
'\\') {
1087 RealName
.Length
-= sizeof(WCHAR
);
1088 RealName
.Buffer
[RealName
.Length
/2] = 0;
1090 i
= RealName
.Length
/2;
1091 while (i
> 0 && RealName
.Buffer
[i
- 1] != L
'\\')
1094 if (IsVcbReadOnly(Vcb
)) {
1095 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1100 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1101 Status
= STATUS_SUCCESS
;
1103 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1104 IrpSp
->FileObject
->FileName
.MaximumLength
);
1105 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
- i
* sizeof(WCHAR
);
1106 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
, &RealName
.Buffer
[i
],
1107 IrpSp
->FileObject
->FileName
.Length
);
1109 // use's it's parent since it's open-target operation
1110 Ext2ReferMcb(Mcb
->Parent
);
1117 // We can not create if one exists
1118 if (CreateDisposition
== FILE_CREATE
) {
1119 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1120 Status
= STATUS_OBJECT_NAME_COLLISION
;
1125 /* directory forbits us to do the followings ... */
1126 if (IsMcbDirectory(Mcb
)) {
1128 if ((CreateDisposition
!= FILE_OPEN
) &&
1129 (CreateDisposition
!= FILE_OPEN_IF
)) {
1131 Status
= STATUS_OBJECT_NAME_COLLISION
;
1136 if (NonDirectoryFile
) {
1137 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1142 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
1144 if (OpenTargetDirectory
) {
1146 Status
= STATUS_INVALID_PARAMETER
;
1154 if (DirectoryFile
) {
1155 Status
= STATUS_NOT_A_DIRECTORY
;;
1161 Irp
->IoStatus
.Information
= FILE_OPENED
;
1166 if (!bFcbLockAcquired
) {
1167 ExAcquireResourceExclusiveLite(&Vcb
->FcbLock
, TRUE
);
1168 bFcbLockAcquired
= TRUE
;
1171 /* Mcb should already be referred and symlink is too */
1174 ASSERT(Mcb
->Refercount
> 0);
1176 /* refer it's target if it's a symlink, so both refered */
1177 if (IsMcbSymLink(Mcb
)) {
1179 if (OpenReparsePoint
) {
1181 CcbFlags
= CCB_OPEN_REPARSE_POINT
;
1182 } else if (IsFileDeleted(Mcb
->Target
)) {
1184 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
1185 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
1186 Ext2DerefMcb(Mcb
->Target
);
1192 ASSERT (!IsMcbSymLink(Mcb
));
1196 // Check readonly flag
1197 if (BooleanFlagOn(DesiredAccess
, FILE_GENERIC_READ
) &&
1198 !Ext2CheckFileAccess(Vcb
, Mcb
, Ext2FileCanRead
)) {
1199 Status
= STATUS_ACCESS_DENIED
;
1202 if (!Ext2CheckFileAccess(Vcb
, Mcb
, Ext2FileCanWrite
)) {
1203 if (BooleanFlagOn(DesiredAccess
, FILE_WRITE_DATA
| FILE_APPEND_DATA
|
1204 FILE_ADD_SUBDIRECTORY
| FILE_DELETE_CHILD
)) {
1205 Status
= STATUS_ACCESS_DENIED
;
1207 } else if (IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
)) {
1208 Status
= STATUS_CANNOT_DELETE
;
1216 /* allocate Fcb for this file */
1217 Fcb
= Ext2AllocateFcb (Vcb
, Mcb
);
1219 bFcbAllocated
= TRUE
;
1221 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1225 Status
= STATUS_SHARING_VIOLATION
;
1230 /* Now it's safe to defer Mcb */
1235 /* grab Fcb's reference first to avoid the race between
1236 Ext2Close (it could free the Fcb we are accessing) */
1237 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1240 ExReleaseResourceLite(&Vcb
->FcbLock
);
1241 bFcbLockAcquired
= FALSE
;
1245 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
1246 bMainResourceAcquired
= TRUE
;
1248 /* Open target directory ? */
1254 /* check Mcb reference */
1255 ASSERT(Fcb
->Mcb
->Refercount
> 0);
1258 if (IsFlagOn(Fcb
->Mcb
->Flags
, MCB_FILE_DELETED
)) {
1259 Status
= STATUS_FILE_DELETED
;
1263 if (DeleteOnClose
&& NULL
== SymLink
) {
1264 Status
= Ext2IsFileRemovable(IrpContext
, Vcb
, Fcb
, Ccb
);
1265 if (!NT_SUCCESS(Status
)) {
1270 /* check access and oplock access for opened files */
1271 if (!bFcbAllocated
&& !IsDirectory(Fcb
)) {
1273 /* whether there's batch oplock grabed on the file */
1274 if (FsRtlCurrentBatchOplock(&Fcb
->Oplock
)) {
1276 Irp
->IoStatus
.Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
1278 /* break the batch lock if the sharing check fails */
1279 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1285 if ( Status
!= STATUS_SUCCESS
&&
1286 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1296 // This file is just created.
1299 if (DirectoryFile
) {
1301 Status
= Ext2AddDotEntries(IrpContext
, &ParentMcb
->Inode
, &Mcb
->Inode
);
1302 if (!NT_SUCCESS(Status
)) {
1303 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1309 if ((LONGLONG
)ext3_free_blocks_count(SUPER_BLOCK
) <=
1310 Ext2TotalBlocks(Vcb
, &Irp
->Overlay
.AllocationSize
, NULL
)) {
1312 Status
= STATUS_DISK_FULL
;
1316 /* disable data blocks allocation */
1318 Fcb
->Header
.AllocationSize
.QuadPart
=
1319 Irp
->Overlay
.AllocationSize
.QuadPart
;
1321 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
1322 Status
= Ext2ExpandFile(IrpContext
,
1325 &(Fcb
->Header
.AllocationSize
)
1327 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
1328 if (!NT_SUCCESS(Status
)) {
1329 Fcb
->Header
.AllocationSize
.QuadPart
= 0;
1330 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
,
1331 &Fcb
->Header
.AllocationSize
);
1341 // This file alreayd exists.
1344 if (DeleteOnClose
) {
1346 if (IsVcbReadOnly(Vcb
)) {
1347 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1351 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1352 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1354 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1355 Vcb
->Vpb
->RealDevice
);
1357 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1359 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1365 // Just to Open file (Open/OverWrite ...)
1368 if ((!IsDirectory(Fcb
)) && (IsFlagOn(IrpSp
->FileObject
->Flags
,
1369 FO_NO_INTERMEDIATE_BUFFERING
))) {
1370 Fcb
->Header
.IsFastIoPossible
= FastIoIsPossible
;
1372 if (Fcb
->SectionObject
.DataSectionObject
!= NULL
) {
1374 if (Fcb
->NonCachedOpenCount
== Fcb
->OpenHandleCount
) {
1376 if (!IsVcbReadOnly(Vcb
)) {
1377 CcFlushCache(&Fcb
->SectionObject
, NULL
, 0, NULL
);
1378 ClearLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
1381 CcPurgeCacheSection(&Fcb
->SectionObject
,
1391 if (!IsDirectory(Fcb
)) {
1393 if (!IsVcbReadOnly(Vcb
)) {
1394 if ((CreateDisposition
== FILE_SUPERSEDE
) && !IsPagingFile
) {
1395 DesiredAccess
|= DELETE
;
1396 } else if (((CreateDisposition
== FILE_OVERWRITE
) ||
1397 (CreateDisposition
== FILE_OVERWRITE_IF
)) && !IsPagingFile
) {
1398 DesiredAccess
|= (FILE_WRITE_DATA
| FILE_WRITE_EA
|
1399 FILE_WRITE_ATTRIBUTES
);
1403 if (!bFcbAllocated
) {
1406 // check the oplock state of the file
1409 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1415 if ( Status
!= STATUS_SUCCESS
&&
1416 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1423 if (Fcb
->OpenHandleCount
> 0) {
1425 /* check the shrae access conflicts */
1426 Status
= IoCheckShareAccess( DesiredAccess
,
1429 &(Fcb
->ShareAccess
),
1431 if (!NT_SUCCESS(Status
)) {
1437 /* set share access rights */
1438 IoSetShareAccess( DesiredAccess
,
1441 &(Fcb
->ShareAccess
) );
1444 Ccb
= Ext2AllocateCcb(CcbFlags
, SymLink
);
1446 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1452 SetLongFlag(Ccb
->Flags
, CCB_DELETE_ON_CLOSE
);
1455 Ccb
->filp
.f_dentry
= SymLink
->de
;
1457 Ccb
->filp
.f_dentry
= Fcb
->Mcb
->de
;
1459 Ccb
->filp
.f_version
= Fcb
->Mcb
->Inode
.i_version
;
1460 Ext2ReferXcb(&Fcb
->OpenHandleCount
);
1461 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1463 if (!IsDirectory(Fcb
)) {
1464 if (NoIntermediateBuffering
) {
1465 Fcb
->NonCachedOpenCount
++;
1466 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1468 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1472 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1473 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1475 IrpSp
->FileObject
->FsContext
= (void*) Fcb
;
1476 IrpSp
->FileObject
->FsContext2
= (void*) Ccb
;
1477 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1478 IrpSp
->FileObject
->SectionObjectPointer
= &(Fcb
->SectionObject
);
1480 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ OpenCount=%u ReferCount=%u NonCachedCount=%u\n",
1481 &Fcb
->Mcb
->FullName
, Fcb
->OpenHandleCount
, Fcb
->ReferenceCount
, Fcb
->NonCachedOpenCount
));
1483 Status
= STATUS_SUCCESS
;
1487 if (IsDirectory(Fcb
)) {
1488 Ext2NotifyReportChange(
1492 FILE_NOTIFY_CHANGE_DIR_NAME
,
1493 FILE_ACTION_ADDED
);
1495 Ext2NotifyReportChange(
1499 FILE_NOTIFY_CHANGE_FILE_NAME
,
1500 FILE_ACTION_ADDED
);
1503 } else if (!IsDirectory(Fcb
)) {
1505 if ( DeleteOnClose
||
1506 IsFlagOn(DesiredAccess
, FILE_WRITE_DATA
) ||
1507 (CreateDisposition
== FILE_OVERWRITE
) ||
1508 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1509 if (!MmFlushImageSection( &Fcb
->SectionObject
,
1510 MmFlushForWrite
)) {
1512 Status
= DeleteOnClose
? STATUS_CANNOT_DELETE
:
1513 STATUS_SHARING_VIOLATION
;
1518 if ((CreateDisposition
== FILE_SUPERSEDE
) ||
1519 (CreateDisposition
== FILE_OVERWRITE
) ||
1520 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1522 if (IsDirectory(Fcb
)) {
1523 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1527 if (SymLink
!= NULL
) {
1529 Status
= STATUS_INVALID_PARAMETER
;
1533 if (IsVcbReadOnly(Vcb
)) {
1534 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1538 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1540 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1541 Vcb
->Vpb
->RealDevice
);
1542 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1543 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1546 Status
= Ext2SupersedeOrOverWriteFile(
1551 &Irp
->Overlay
.AllocationSize
,
1552 CreateDisposition
);
1554 if (!NT_SUCCESS(Status
)) {
1559 Ext2NotifyReportChange(
1563 FILE_NOTIFY_CHANGE_LAST_WRITE
|
1564 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
1565 FILE_NOTIFY_CHANGE_SIZE
,
1566 FILE_ACTION_MODIFIED
);
1569 if (CreateDisposition
== FILE_SUPERSEDE
) {
1570 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1572 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
1584 if (bFcbLockAcquired
) {
1585 ExReleaseResourceLite(&Vcb
->FcbLock
);
1589 Ext2DerefMcb(ParentMcb
);
1592 /* cleanup Fcb and Ccb, Mcb if necessary */
1593 if (!NT_SUCCESS(Status
)) {
1599 ASSERT(Fcb
!= NULL
);
1600 ASSERT(Fcb
->Mcb
!= NULL
);
1602 DEBUG(DL_ERR
, ("Ext2CreateFile: failed to create %wZ status = %xh\n",
1603 &Fcb
->Mcb
->FullName
, Status
));
1605 Ext2DerefXcb(&Fcb
->OpenHandleCount
);
1606 Ext2DerefXcb(&Fcb
->ReferenceCount
);
1608 if (!IsDirectory(Fcb
)) {
1609 if (NoIntermediateBuffering
) {
1610 Fcb
->NonCachedOpenCount
--;
1612 ClearFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1616 Ext2DerefXcb(&Vcb
->OpenHandleCount
);
1617 Ext2DerefXcb(&Vcb
->ReferenceCount
);
1619 IoRemoveShareAccess(IrpSp
->FileObject
, &Fcb
->ShareAccess
);
1621 IrpSp
->FileObject
->FsContext
= NULL
;
1622 IrpSp
->FileObject
->FsContext2
= NULL
;
1623 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1624 IrpSp
->FileObject
->SectionObjectPointer
= NULL
;
1626 Ext2FreeCcb(Vcb
, Ccb
);
1631 if (IsFlagOn(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
)) {
1633 ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
);
1636 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1638 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1643 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1648 if (bMainResourceAcquired
) {
1649 ExReleaseResourceLite(&Fcb
->MainResource
);
1652 /* free file name buffer */
1653 if (FileName
.Buffer
) {
1654 DEC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
1655 Ext2FreePool(FileName
.Buffer
, EXT2_FNAME_MAGIC
);
1658 /* dereference Fcb and parent */
1660 Ext2ReleaseFcb(Fcb
);
1663 Ext2ReleaseFcb(ParentFcb
);
1666 /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer
1667 it already. It fails, we need release the refer to let it freed */
1669 Ext2DerefMcb(SymLink
);
1677 Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext
, PEXT2_VCB Vcb
)
1679 PIO_STACK_LOCATION IrpSp
;
1685 ACCESS_MASK DesiredAccess
;
1689 BOOLEAN DirectoryFile
;
1690 BOOLEAN OpenTargetDirectory
;
1692 ULONG CreateDisposition
;
1694 Irp
= IrpContext
->Irp
;
1695 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1697 Options
= IrpSp
->Parameters
.Create
.Options
;
1699 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
1700 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
1702 CreateDisposition
= (Options
>> 24) & 0x000000ff;
1704 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
1705 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
1707 if (DirectoryFile
) {
1708 return STATUS_NOT_A_DIRECTORY
;
1711 if (OpenTargetDirectory
) {
1713 return STATUS_INVALID_PARAMETER
;
1716 if ( (CreateDisposition
!= FILE_OPEN
) &&
1717 (CreateDisposition
!= FILE_OPEN_IF
) ) {
1718 return STATUS_ACCESS_DENIED
;
1721 if ( !FlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1722 Vcb
->OpenVolumeCount
!= 0 ) {
1723 return STATUS_SHARING_VIOLATION
;
1726 Ccb
= Ext2AllocateCcb(0, NULL
);
1728 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1732 Status
= STATUS_SUCCESS
;
1734 if (Vcb
->OpenVolumeCount
> 0) {
1735 Status
= IoCheckShareAccess( DesiredAccess
, ShareAccess
,
1737 &(Vcb
->ShareAccess
), TRUE
);
1739 if (!NT_SUCCESS(Status
)) {
1743 IoSetShareAccess( DesiredAccess
, ShareAccess
,
1745 &(Vcb
->ShareAccess
) );
1749 if (Vcb
->OpenVolumeCount
== 0 &&
1750 !IsFlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1751 !IsFlagOn(ShareAccess
, FILE_SHARE_WRITE
) ){
1753 if (!IsVcbReadOnly(Vcb
)) {
1754 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1755 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1758 SetLongFlag(Vcb
->Flags
, VCB_VOLUME_LOCKED
);
1759 Vcb
->LockFile
= IrpSp
->FileObject
;
1761 if (FlagOn(DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
) ) {
1762 if (!IsVcbReadOnly(Vcb
)) {
1763 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1764 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1769 IrpSp
->FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
1770 IrpSp
->FileObject
->FsContext
= Vcb
;
1771 IrpSp
->FileObject
->FsContext2
= Ccb
;
1772 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1774 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1775 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1776 Ext2ReferXcb(&Vcb
->OpenVolumeCount
);
1778 Irp
->IoStatus
.Information
= FILE_OPENED
;
1787 Ext2Create (IN PEXT2_IRP_CONTEXT IrpContext
)
1789 PDEVICE_OBJECT DeviceObject
;
1791 PIO_STACK_LOCATION IrpSp
;
1793 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1794 PEXT2_FCBVCB Xcb
= NULL
;
1795 BOOLEAN PostIrp
= FALSE
;
1796 BOOLEAN VcbResourceAcquired
= FALSE
;
1798 DeviceObject
= IrpContext
->DeviceObject
;
1799 Irp
= IrpContext
->Irp
;
1800 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1802 Xcb
= (PEXT2_FCBVCB
) (IrpSp
->FileObject
->FsContext
);
1804 if (IsExt2FsDevice(DeviceObject
)) {
1806 DEBUG(DL_INF
, ( "Ext2Create: Create on main device object.\n"));
1808 Status
= STATUS_SUCCESS
;
1809 Irp
->IoStatus
.Information
= FILE_OPENED
;
1811 Ext2CompleteIrpContext(IrpContext
, Status
);
1818 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1819 ASSERT(Vcb
->Identifier
.Type
== EXT2VCB
);
1820 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1822 if (!IsMounted(Vcb
)) {
1824 if (IsFlagOn(Vcb
->Flags
, VCB_DEVICE_REMOVED
)) {
1825 Status
= STATUS_NO_SUCH_DEVICE
;
1827 Status
= STATUS_VOLUME_DISMOUNTED
;
1832 if (!ExAcquireResourceExclusiveLite(
1833 &Vcb
->MainResource
, TRUE
)) {
1834 Status
= STATUS_PENDING
;
1837 VcbResourceAcquired
= TRUE
;
1839 Ext2VerifyVcb(IrpContext
, Vcb
);
1841 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
1842 Status
= STATUS_ACCESS_DENIED
;
1843 if (IsFlagOn(Vcb
->Flags
, VCB_DISMOUNT_PENDING
)) {
1844 Status
= STATUS_VOLUME_DISMOUNTED
;
1849 if ( ((IrpSp
->FileObject
->FileName
.Length
== 0) &&
1850 (IrpSp
->FileObject
->RelatedFileObject
== NULL
)) ||
1851 (Xcb
&& Xcb
->Identifier
.Type
== EXT2VCB
) ) {
1852 Status
= Ext2CreateVolume(IrpContext
, Vcb
);
1855 Status
= Ext2CreateFile(IrpContext
, Vcb
, &PostIrp
);
1860 if (VcbResourceAcquired
) {
1861 ExReleaseResourceLite(&Vcb
->MainResource
);
1864 if (!IrpContext
->ExceptionInProgress
&& !PostIrp
) {
1865 if ( Status
== STATUS_PENDING
||
1866 Status
== STATUS_CANT_WAIT
) {
1867 Status
= Ext2QueueRequest(IrpContext
);
1869 Ext2CompleteIrpContext(IrpContext
, Status
);
1879 PEXT2_IRP_CONTEXT IrpContext
,
1884 PUNICODE_STRING FileName
)
1889 struct inode Inode
= { 0 };
1890 struct dentry
*Dentry
= NULL
;
1892 LARGE_INTEGER SysTime
;
1894 iGrp
= (Parent
->Inode
->i_ino
- 1) / BLOCKS_PER_GROUP
;
1896 DEBUG(DL_INF
, ("Ext2CreateInode: %S in %S(Inode=%xh)\n",
1898 Parent
->Mcb
->ShortName
.Buffer
,
1899 Parent
->Inode
->i_ino
));
1901 Status
= Ext2NewInode(IrpContext
, Vcb
, iGrp
, Type
, &iNo
);
1902 if (!NT_SUCCESS(Status
)) {
1906 KeQuerySystemTime(&SysTime
);
1907 Ext2ClearInode(IrpContext
, Vcb
, iNo
);
1908 Inode
.i_sb
= &Vcb
->sb
;
1910 Inode
.i_ctime
= Inode
.i_mtime
=
1911 Inode
.i_atime
= Ext2LinuxTime(SysTime
);
1912 if (IsFlagOn(Vcb
->Flags
, VCB_USER_IDS
)) {
1913 Inode
.i_uid
= Vcb
->uid
;
1914 Inode
.i_gid
= Vcb
->gid
;
1916 Inode
.i_uid
= Parent
->Mcb
->Inode
.i_uid
;
1917 Inode
.i_gid
= Parent
->Mcb
->Inode
.i_gid
;
1919 Inode
.i_generation
= Parent
->Inode
->i_generation
;
1920 Inode
.i_mode
= S_IPERMISSION_MASK
&
1921 Parent
->Inode
->i_mode
;
1922 if (Type
== EXT2_FT_DIR
) {
1923 Inode
.i_mode
|= S_IFDIR
;
1924 } else if (Type
== EXT2_FT_REG_FILE
) {
1925 Inode
.i_mode
&= S_IFATTR
;
1926 Inode
.i_mode
|= S_IFREG
;
1931 /* Force using extent */
1932 if (IsFlagOn(SUPER_BLOCK
->s_feature_incompat
, EXT4_FEATURE_INCOMPAT_EXTENTS
)) {
1933 Inode
.i_flags
|= EXT2_EXTENTS_FL
;
1934 ext4_ext_tree_init(IrpContext
, NULL
, &Inode
);
1935 /* ext4_ext_tree_init will save inode body */
1937 /* save inode body to cache */
1938 Ext2SaveInode(IrpContext
, Vcb
, &Inode
);
1941 /* add new entry to its parent */
1942 Status
= Ext2AddEntry(
1951 if (!NT_SUCCESS(Status
)) {
1953 Ext2FreeInode(IrpContext
, Vcb
, iNo
, Type
);
1957 DEBUG(DL_INF
, ("Ext2CreateInode: New Inode = %xh (Type=%xh)\n",
1958 Inode
.i_ino
, Type
));
1963 Ext2FreeEntry(Dentry
);
1970 Ext2SupersedeOrOverWriteFile(
1971 IN PEXT2_IRP_CONTEXT IrpContext
,
1972 IN PFILE_OBJECT FileObject
,
1975 IN PLARGE_INTEGER AllocationSize
,
1976 IN ULONG Disposition
1979 LARGE_INTEGER CurrentTime
;
1982 KeQuerySystemTime(&CurrentTime
);
1985 if (!MmCanFileBeTruncated(&(Fcb
->SectionObject
), &(Size
))) {
1986 return STATUS_USER_MAPPED_FILE
;
1989 /* purge all file cache and shrink cache windows size */
1990 CcPurgeCacheSection(&Fcb
->SectionObject
, NULL
, 0, FALSE
);
1991 Fcb
->Header
.AllocationSize
.QuadPart
=
1992 Fcb
->Header
.FileSize
.QuadPart
=
1993 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1994 CcSetFileSizes(FileObject
,
1995 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1997 Size
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
1998 (ULONGLONG
)AllocationSize
->QuadPart
,
1999 (ULONGLONG
)BLOCK_SIZE
);
2001 if ((loff_t
)Size
.QuadPart
> Fcb
->Inode
->i_size
) {
2002 Ext2ExpandFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
2004 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
2007 Fcb
->Header
.AllocationSize
= Size
;
2008 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
2009 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
2010 CcSetFileSizes(FileObject
,
2011 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
2014 /* remove all extent mappings */
2015 DEBUG(DL_EXT
, ("Ext2SuperSede ...: %wZ\n", &Fcb
->Mcb
->FullName
));
2016 Fcb
->Inode
->i_size
= 0;
2018 if (Disposition
== FILE_SUPERSEDE
) {
2019 Fcb
->Inode
->i_ctime
= Ext2LinuxTime(CurrentTime
);
2021 Fcb
->Inode
->i_atime
=
2022 Fcb
->Inode
->i_mtime
= Ext2LinuxTime(CurrentTime
);
2023 Ext2SaveInode(IrpContext
, Vcb
, Fcb
->Inode
);
2025 return STATUS_SUCCESS
;