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
;
703 BOOLEAN bDir
= FALSE
;
705 BOOLEAN bFcbAllocated
= FALSE
;
706 BOOLEAN bCreated
= FALSE
;
707 BOOLEAN bMainResourceAcquired
= FALSE
;
709 BOOLEAN OpenDirectory
;
710 BOOLEAN OpenTargetDirectory
;
711 BOOLEAN CreateDirectory
;
712 BOOLEAN SequentialOnly
;
713 BOOLEAN NoIntermediateBuffering
;
714 BOOLEAN IsPagingFile
;
715 BOOLEAN DirectoryFile
;
716 BOOLEAN NonDirectoryFile
;
717 BOOLEAN NoEaKnowledge
;
718 BOOLEAN DeleteOnClose
;
719 BOOLEAN TemporaryFile
;
720 BOOLEAN CaseSensitive
;
721 BOOLEAN OpenReparsePoint
;
723 ACCESS_MASK DesiredAccess
;
727 RtlZeroMemory(&FileName
, sizeof(UNICODE_STRING
));
729 Irp
= IrpContext
->Irp
;
730 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
732 Options
= IrpSp
->Parameters
.Create
.Options
;
734 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
735 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
737 NonDirectoryFile
= IsFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
738 SequentialOnly
= IsFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
739 NoIntermediateBuffering
= IsFlagOn( Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
740 NoEaKnowledge
= IsFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
741 DeleteOnClose
= IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
743 /* Try to open reparse point (symlink) itself ? */
744 OpenReparsePoint
= IsFlagOn(Options
, FILE_OPEN_REPARSE_POINT
);
746 CaseSensitive
= IsFlagOn(IrpSp
->Flags
, SL_CASE_SENSITIVE
);
748 TemporaryFile
= IsFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
749 FILE_ATTRIBUTE_TEMPORARY
);
751 CreateDisposition
= (Options
>> 24) & 0x000000ff;
753 IsPagingFile
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
755 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
756 ((CreateDisposition
== FILE_CREATE
) ||
757 (CreateDisposition
== FILE_OPEN_IF
)));
759 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
760 ((CreateDisposition
== FILE_OPEN
) ||
761 (CreateDisposition
== FILE_OPEN_IF
)));
763 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
764 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
770 FileName
.MaximumLength
= IrpSp
->FileObject
->FileName
.MaximumLength
;
771 FileName
.Length
= IrpSp
->FileObject
->FileName
.Length
;
773 if (IrpSp
->FileObject
->RelatedFileObject
) {
774 ParentFcb
= (PEXT2_FCB
)(IrpSp
->FileObject
->RelatedFileObject
->FsContext
);
778 ParentMcb
= ParentFcb
->Mcb
;
779 SetLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
780 Ext2ReferMcb(ParentMcb
);
783 if (FileName
.Length
== 0) {
786 Mcb
= ParentFcb
->Mcb
;
788 Status
= STATUS_SUCCESS
;
792 Status
= STATUS_INVALID_PARAMETER
;
797 FileName
.Buffer
= Ext2AllocatePool(
799 FileName
.MaximumLength
,
803 if (!FileName
.Buffer
) {
804 DEBUG(DL_ERR
, ( "Ex2CreateFile: failed to allocate FileName.\n"));
805 Status
= STATUS_INSUFFICIENT_RESOURCES
;
809 INC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
811 RtlZeroMemory(FileName
.Buffer
, FileName
.MaximumLength
);
812 RtlCopyMemory(FileName
.Buffer
, IrpSp
->FileObject
->FileName
.Buffer
, FileName
.Length
);
814 if (ParentFcb
&& FileName
.Buffer
[0] == L
'\\') {
815 Status
= STATUS_INVALID_PARAMETER
;
819 if ((FileName
.Length
> sizeof(WCHAR
)) &&
820 (FileName
.Buffer
[1] == L
'\\') &&
821 (FileName
.Buffer
[0] == L
'\\')) {
823 FileName
.Length
-= sizeof(WCHAR
);
825 RtlMoveMemory( &FileName
.Buffer
[0],
830 // Bad Name if there are still beginning backslashes.
833 if ((FileName
.Length
> sizeof(WCHAR
)) &&
834 (FileName
.Buffer
[1] == L
'\\') &&
835 (FileName
.Buffer
[0] == L
'\\')) {
837 Status
= STATUS_OBJECT_NAME_INVALID
;
842 if (IsFlagOn(Options
, FILE_OPEN_BY_FILE_ID
)) {
843 Status
= STATUS_NOT_IMPLEMENTED
;
847 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ Paging=%d Option: %xh:"
848 "Dir=%d NonDir=%d OpenTarget=%d NC=%d DeleteOnClose=%d\n",
849 &FileName
, IsPagingFile
, IrpSp
->Parameters
.Create
.Options
,
850 DirectoryFile
, NonDirectoryFile
, OpenTargetDirectory
,
851 NoIntermediateBuffering
, DeleteOnClose
));
853 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 1st: %wZ at %S\n",
854 &FileName
, ParentMcb
? ParentMcb
->FullName
.Buffer
: L
" "));
855 Status
= Ext2LookupFile(
861 0 /* always follow link */
865 if (!NT_SUCCESS(Status
)) {
867 UNICODE_STRING PathName
;
868 UNICODE_STRING RealName
;
869 UNICODE_STRING RemainName
;
878 if (PathName
.Buffer
[PathName
.Length
/2 - 1] == L
'\\') {
881 PathName
.Buffer
[PathName
.Length
/2] = 0;
883 DirectoryFile
= TRUE
;
888 if (PathName
.Buffer
[0] != L
'\\') {
889 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
892 ParentMcb
= Vcb
->McbTree
;
893 Ext2ReferMcb(ParentMcb
);
899 FsRtlDissectName(PathName
, &RealName
, &RemainName
);
901 if (((RemainName
.Length
!= 0) && (RemainName
.Buffer
[0] == L
'\\')) ||
902 (RealName
.Length
>= 256 * sizeof(WCHAR
))) {
903 Status
= STATUS_OBJECT_NAME_INVALID
;
907 if (RemainName
.Length
!= 0) {
909 PEXT2_MCB RetMcb
= NULL
;
911 DEBUG(DL_RES
, ("Ext2CreateFile: Lookup 2nd: %wZ\\%wZ\n",
912 &ParentMcb
->FullName
, &RealName
));
914 Status
= Ext2LookupFile (
922 /* quit name resolving loop */
923 if (!NT_SUCCESS(Status
)) {
924 if (Status
== STATUS_NO_SUCH_FILE
&& RemainName
.Length
!= 0) {
925 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
930 /* deref ParentMcb */
931 Ext2DerefMcb(ParentMcb
);
933 /* RetMcb is already refered */
935 PathName
= RemainName
;
937 /* symlink must use it's target */
938 if (IsMcbSymLink(ParentMcb
)) {
939 Ext2ReferMcb(ParentMcb
->Target
);
940 Ext2DerefMcb(ParentMcb
);
941 ParentMcb
= ParentMcb
->Target
;
942 ASSERT(!IsMcbSymLink(ParentMcb
));
949 if ( FsRtlDoesNameContainWildCards(&RealName
) ||
950 !Ext2IsNameValid(&RealName
)) {
951 Status
= STATUS_OBJECT_NAME_INVALID
;
955 /* clear BUSY bit from original ParentFcb */
957 ClearLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
960 /* get the ParentFcb, allocate it if needed ... */
961 ParentFcb
= ParentMcb
->Fcb
;
963 ParentFcb
= Ext2AllocateFcb(Vcb
, ParentMcb
);
965 Status
= STATUS_INSUFFICIENT_RESOURCES
;
968 bParentFcbCreated
= TRUE
;
969 Ext2ReferXcb(&ParentFcb
->ReferenceCount
);
971 SetLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
973 // We need to create a new one ?
974 if ((CreateDisposition
== FILE_CREATE
) ||
975 (CreateDisposition
== FILE_SUPERSEDE
) ||
976 (CreateDisposition
== FILE_OPEN_IF
) ||
977 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
979 if (IsVcbReadOnly(Vcb
)) {
980 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
984 if (!Ext2CheckFileAccess(Vcb
, ParentMcb
, Ext2FileCanWrite
)) {
985 Status
= STATUS_ACCESS_DENIED
;
989 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
990 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
991 Vcb
->Vpb
->RealDevice
);
992 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
993 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
999 Status
= STATUS_INVALID_PARAMETER
;
1005 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
1009 /* allocate inode and construct entry for this file */
1010 Status
= Ext2CreateInode(
1014 DirectoryFile
? EXT2_FT_DIR
: EXT2_FT_REG_FILE
,
1015 IrpSp
->Parameters
.Create
.FileAttributes
,
1019 if (!NT_SUCCESS(Status
)) {
1025 DEBUG(DL_RES
, ("Ext2CreateFile: Confirm creation: %wZ\\%wZ\n",
1026 &ParentMcb
->FullName
, &RealName
));
1028 Irp
->IoStatus
.Information
= FILE_CREATED
;
1029 Status
= Ext2LookupFile (
1036 if (!NT_SUCCESS(Status
)) {
1040 } else if (OpenTargetDirectory
) {
1042 if (IsVcbReadOnly(Vcb
)) {
1043 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1048 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
1052 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1053 IrpSp
->FileObject
->FileName
.MaximumLength
);
1054 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
;
1056 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1064 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
1065 Status
= STATUS_SUCCESS
;
1069 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1073 } else { // File / Dir already exists.
1075 /* here already get Mcb referred */
1076 if (OpenTargetDirectory
) {
1078 UNICODE_STRING RealName
= FileName
;
1081 while (RealName
.Buffer
[RealName
.Length
/2 - 1] == L
'\\') {
1082 RealName
.Length
-= sizeof(WCHAR
);
1083 RealName
.Buffer
[RealName
.Length
/2] = 0;
1085 i
= RealName
.Length
/2;
1086 while (i
> 0 && RealName
.Buffer
[i
- 1] != L
'\\')
1089 if (IsVcbReadOnly(Vcb
)) {
1090 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1095 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1096 Status
= STATUS_SUCCESS
;
1098 RtlZeroMemory( IrpSp
->FileObject
->FileName
.Buffer
,
1099 IrpSp
->FileObject
->FileName
.MaximumLength
);
1100 IrpSp
->FileObject
->FileName
.Length
= RealName
.Length
- i
* sizeof(WCHAR
);
1101 RtlCopyMemory( IrpSp
->FileObject
->FileName
.Buffer
, &RealName
.Buffer
[i
],
1102 IrpSp
->FileObject
->FileName
.Length
);
1104 // use's it's parent since it's open-target operation
1105 Ext2ReferMcb(Mcb
->Parent
);
1112 // We can not create if one exists
1113 if (CreateDisposition
== FILE_CREATE
) {
1114 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1115 Status
= STATUS_OBJECT_NAME_COLLISION
;
1120 /* directory forbits us to do the followings ... */
1121 if (IsMcbDirectory(Mcb
)) {
1123 if ((CreateDisposition
!= FILE_OPEN
) &&
1124 (CreateDisposition
!= FILE_OPEN_IF
)) {
1126 Status
= STATUS_OBJECT_NAME_COLLISION
;
1131 if (NonDirectoryFile
) {
1132 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1137 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
1139 if (OpenTargetDirectory
) {
1141 Status
= STATUS_INVALID_PARAMETER
;
1149 if (DirectoryFile
) {
1150 Status
= STATUS_NOT_A_DIRECTORY
;;
1156 Irp
->IoStatus
.Information
= FILE_OPENED
;
1160 /* Mcb should already be referred and symlink is too */
1163 ASSERT(Mcb
->Refercount
> 0);
1165 /* refer it's target if it's a symlink, so both refered */
1166 if (IsMcbSymLink(Mcb
)) {
1168 if (OpenReparsePoint
) {
1170 CcbFlags
= CCB_OPEN_REPARSE_POINT
;
1171 } else if (IsFileDeleted(Mcb
->Target
)) {
1173 SetLongFlag(Mcb
->Flags
, MCB_TYPE_SPECIAL
);
1174 ClearLongFlag(Mcb
->Flags
, MCB_TYPE_SYMLINK
);
1175 Ext2DerefMcb(Mcb
->Target
);
1181 ASSERT (!IsMcbSymLink(Mcb
));
1185 // Check readonly flag
1186 if (BooleanFlagOn(DesiredAccess
, FILE_GENERIC_READ
) &&
1187 !Ext2CheckFileAccess(Vcb
, Mcb
, Ext2FileCanRead
)) {
1188 Status
= STATUS_ACCESS_DENIED
;
1191 if (!Ext2CheckFileAccess(Vcb
, Mcb
, Ext2FileCanWrite
)) {
1192 if (BooleanFlagOn(DesiredAccess
, FILE_WRITE_DATA
| FILE_APPEND_DATA
|
1193 FILE_ADD_SUBDIRECTORY
| FILE_DELETE_CHILD
)) {
1194 Status
= STATUS_ACCESS_DENIED
;
1196 } else if (IsFlagOn(Options
, FILE_DELETE_ON_CLOSE
)) {
1197 Status
= STATUS_CANNOT_DELETE
;
1205 /* allocate Fcb for this file */
1206 Fcb
= Ext2AllocateFcb (Vcb
, Mcb
);
1208 bFcbAllocated
= TRUE
;
1210 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1214 Status
= STATUS_SHARING_VIOLATION
;
1219 /* Now it's safe to defer Mcb */
1225 /* grab Fcb's reference first to avoid the race between
1226 Ext2Close (it could free the Fcb we are accessing) */
1227 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1229 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
1230 bMainResourceAcquired
= TRUE
;
1232 /* Open target directory ? */
1238 /* check Mcb reference */
1239 ASSERT(Fcb
->Mcb
->Refercount
> 0);
1242 if (IsFlagOn(Fcb
->Mcb
->Flags
, MCB_FILE_DELETED
)) {
1243 Status
= STATUS_FILE_DELETED
;
1247 if (DeleteOnClose
&& NULL
== SymLink
) {
1248 Status
= Ext2IsFileRemovable(IrpContext
, Vcb
, Fcb
, Ccb
);
1249 if (!NT_SUCCESS(Status
)) {
1254 /* check access and oplock access for opened files */
1255 if (!bFcbAllocated
&& !IsDirectory(Fcb
)) {
1257 /* whether there's batch oplock grabed on the file */
1258 if (FsRtlCurrentBatchOplock(&Fcb
->Oplock
)) {
1260 Irp
->IoStatus
.Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
1262 /* break the batch lock if the sharing check fails */
1263 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1269 if ( Status
!= STATUS_SUCCESS
&&
1270 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1280 // This file is just created.
1283 if (DirectoryFile
) {
1285 Status
= Ext2AddDotEntries(IrpContext
, &ParentMcb
->Inode
, &Mcb
->Inode
);
1286 if (!NT_SUCCESS(Status
)) {
1287 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1293 if ((LONGLONG
)ext3_free_blocks_count(SUPER_BLOCK
) <=
1294 Ext2TotalBlocks(Vcb
, &Irp
->Overlay
.AllocationSize
, NULL
)) {
1296 Status
= STATUS_DISK_FULL
;
1300 /* disable data blocks allocation */
1302 Fcb
->Header
.AllocationSize
.QuadPart
=
1303 Irp
->Overlay
.AllocationSize
.QuadPart
;
1305 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
1306 Status
= Ext2ExpandFile(IrpContext
,
1309 &(Fcb
->Header
.AllocationSize
)
1311 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
1312 if (!NT_SUCCESS(Status
)) {
1313 Fcb
->Header
.AllocationSize
.QuadPart
= 0;
1314 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
,
1315 &Fcb
->Header
.AllocationSize
);
1325 // This file alreayd exists.
1328 if (DeleteOnClose
) {
1330 if (IsVcbReadOnly(Vcb
)) {
1331 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1335 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1336 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1338 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1339 Vcb
->Vpb
->RealDevice
);
1341 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1343 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1349 // Just to Open file (Open/OverWrite ...)
1352 if ((!IsDirectory(Fcb
)) && (IsFlagOn(IrpSp
->FileObject
->Flags
,
1353 FO_NO_INTERMEDIATE_BUFFERING
))) {
1354 Fcb
->Header
.IsFastIoPossible
= FastIoIsPossible
;
1356 if (Fcb
->SectionObject
.DataSectionObject
!= NULL
) {
1358 if (Fcb
->NonCachedOpenCount
== Fcb
->OpenHandleCount
) {
1360 if (!IsVcbReadOnly(Vcb
)) {
1361 CcFlushCache(&Fcb
->SectionObject
, NULL
, 0, NULL
);
1362 ClearLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
1365 CcPurgeCacheSection(&Fcb
->SectionObject
,
1375 if (!IsDirectory(Fcb
)) {
1377 if (!IsVcbReadOnly(Vcb
)) {
1378 if ((CreateDisposition
== FILE_SUPERSEDE
) && !IsPagingFile
) {
1379 DesiredAccess
|= DELETE
;
1380 } else if (((CreateDisposition
== FILE_OVERWRITE
) ||
1381 (CreateDisposition
== FILE_OVERWRITE_IF
)) && !IsPagingFile
) {
1382 DesiredAccess
|= (FILE_WRITE_DATA
| FILE_WRITE_EA
|
1383 FILE_WRITE_ATTRIBUTES
);
1387 if (!bFcbAllocated
) {
1390 // check the oplock state of the file
1393 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
1399 if ( Status
!= STATUS_SUCCESS
&&
1400 Status
!= STATUS_OPLOCK_BREAK_IN_PROGRESS
) {
1407 if (Fcb
->OpenHandleCount
> 0) {
1409 /* check the shrae access conflicts */
1410 Status
= IoCheckShareAccess( DesiredAccess
,
1413 &(Fcb
->ShareAccess
),
1415 if (!NT_SUCCESS(Status
)) {
1421 /* set share access rights */
1422 IoSetShareAccess( DesiredAccess
,
1425 &(Fcb
->ShareAccess
) );
1428 Ccb
= Ext2AllocateCcb(CcbFlags
, SymLink
);
1430 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1436 SetLongFlag(Ccb
->Flags
, CCB_DELETE_ON_CLOSE
);
1439 Ccb
->filp
.f_dentry
= SymLink
->de
;
1441 Ccb
->filp
.f_dentry
= Fcb
->Mcb
->de
;
1443 Ccb
->filp
.f_version
= Fcb
->Mcb
->Inode
.i_version
;
1444 Ext2ReferXcb(&Fcb
->OpenHandleCount
);
1445 Ext2ReferXcb(&Fcb
->ReferenceCount
);
1447 if (!IsDirectory(Fcb
)) {
1448 if (NoIntermediateBuffering
) {
1449 Fcb
->NonCachedOpenCount
++;
1450 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1452 SetFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1456 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1457 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1459 IrpSp
->FileObject
->FsContext
= (void*) Fcb
;
1460 IrpSp
->FileObject
->FsContext2
= (void*) Ccb
;
1461 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1462 IrpSp
->FileObject
->SectionObjectPointer
= &(Fcb
->SectionObject
);
1464 DEBUG(DL_INF
, ( "Ext2CreateFile: %wZ OpenCount=%u ReferCount=%u NonCachedCount=%u\n",
1465 &Fcb
->Mcb
->FullName
, Fcb
->OpenHandleCount
, Fcb
->ReferenceCount
, Fcb
->NonCachedOpenCount
));
1467 Status
= STATUS_SUCCESS
;
1471 if (IsDirectory(Fcb
)) {
1472 Ext2NotifyReportChange(
1476 FILE_NOTIFY_CHANGE_DIR_NAME
,
1477 FILE_ACTION_ADDED
);
1479 Ext2NotifyReportChange(
1483 FILE_NOTIFY_CHANGE_FILE_NAME
,
1484 FILE_ACTION_ADDED
);
1487 } else if (!IsDirectory(Fcb
)) {
1489 if ( DeleteOnClose
||
1490 IsFlagOn(DesiredAccess
, FILE_WRITE_DATA
) ||
1491 (CreateDisposition
== FILE_OVERWRITE
) ||
1492 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1493 if (!MmFlushImageSection( &Fcb
->SectionObject
,
1494 MmFlushForWrite
)) {
1496 Status
= DeleteOnClose
? STATUS_CANNOT_DELETE
:
1497 STATUS_SHARING_VIOLATION
;
1502 if ((CreateDisposition
== FILE_SUPERSEDE
) ||
1503 (CreateDisposition
== FILE_OVERWRITE
) ||
1504 (CreateDisposition
== FILE_OVERWRITE_IF
)) {
1506 if (IsDirectory(Fcb
)) {
1507 Status
= STATUS_FILE_IS_A_DIRECTORY
;
1511 if (SymLink
!= NULL
) {
1513 Status
= STATUS_INVALID_PARAMETER
;
1517 if (IsVcbReadOnly(Vcb
)) {
1518 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1522 if (IsFlagOn(Vcb
->Flags
, VCB_WRITE_PROTECTED
)) {
1524 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
1525 Vcb
->Vpb
->RealDevice
);
1526 SetFlag(Vcb
->Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
1527 Ext2RaiseStatus(IrpContext
, STATUS_MEDIA_WRITE_PROTECTED
);
1530 Status
= Ext2SupersedeOrOverWriteFile(
1535 &Irp
->Overlay
.AllocationSize
,
1536 CreateDisposition
);
1538 if (!NT_SUCCESS(Status
)) {
1543 Ext2NotifyReportChange(
1547 FILE_NOTIFY_CHANGE_LAST_WRITE
|
1548 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
1549 FILE_NOTIFY_CHANGE_SIZE
,
1550 FILE_ACTION_MODIFIED
);
1553 if (CreateDisposition
== FILE_SUPERSEDE
) {
1554 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1556 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
1570 Ext2DerefMcb(ParentMcb
);
1573 /* cleanup Fcb and Ccb, Mcb if necessary */
1574 if (!NT_SUCCESS(Status
)) {
1580 ASSERT(Fcb
!= NULL
);
1581 ASSERT(Fcb
->Mcb
!= NULL
);
1583 DEBUG(DL_ERR
, ("Ext2CreateFile: failed to create %wZ status = %xh\n",
1584 &Fcb
->Mcb
->FullName
, Status
));
1586 Ext2DerefXcb(&Fcb
->OpenHandleCount
);
1587 Ext2DerefXcb(&Fcb
->ReferenceCount
);
1589 if (!IsDirectory(Fcb
)) {
1590 if (NoIntermediateBuffering
) {
1591 Fcb
->NonCachedOpenCount
--;
1593 ClearFlag(IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1597 Ext2DerefXcb(&Vcb
->OpenHandleCount
);
1598 Ext2DerefXcb(&Vcb
->ReferenceCount
);
1600 IoRemoveShareAccess(IrpSp
->FileObject
, &Fcb
->ShareAccess
);
1602 IrpSp
->FileObject
->FsContext
= NULL
;
1603 IrpSp
->FileObject
->FsContext2
= NULL
;
1604 IrpSp
->FileObject
->PrivateCacheMap
= NULL
;
1605 IrpSp
->FileObject
->SectionObjectPointer
= NULL
;
1607 Ext2FreeCcb(Vcb
, Ccb
);
1611 if (Fcb
&& Ext2DerefXcb(&Fcb
->ReferenceCount
) == 0) {
1613 if (IsFlagOn(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
)) {
1616 ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
);
1619 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1621 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1626 Ext2DeleteFile(IrpContext
, Vcb
, Fcb
, Mcb
);
1631 bMainResourceAcquired
= FALSE
;
1634 if (bMainResourceAcquired
) {
1635 ExReleaseResourceLite(&Fcb
->MainResource
);
1638 /* free file name buffer */
1639 if (FileName
.Buffer
) {
1640 DEC_MEM_COUNT(PS_FILE_NAME
, FileName
.Buffer
, FileName
.MaximumLength
);
1641 Ext2FreePool(FileName
.Buffer
, EXT2_FNAME_MAGIC
);
1644 /* dereference parent Fcb, free it if it goes to zero */
1646 ClearLongFlag(ParentFcb
->Flags
, FCB_STATE_BUSY
);
1647 if (bParentFcbCreated
) {
1648 if (Ext2DerefXcb(&ParentFcb
->ReferenceCount
) == 0) {
1649 Ext2FreeFcb(ParentFcb
);
1654 /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer
1655 it already. It fails, we need release the refer to let it freed */
1657 Ext2DerefMcb(SymLink
);
1665 Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext
, PEXT2_VCB Vcb
)
1667 PIO_STACK_LOCATION IrpSp
;
1673 ACCESS_MASK DesiredAccess
;
1677 BOOLEAN DirectoryFile
;
1678 BOOLEAN OpenTargetDirectory
;
1680 ULONG CreateDisposition
;
1682 Irp
= IrpContext
->Irp
;
1683 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1685 Options
= IrpSp
->Parameters
.Create
.Options
;
1687 DirectoryFile
= IsFlagOn(Options
, FILE_DIRECTORY_FILE
);
1688 OpenTargetDirectory
= IsFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
1690 CreateDisposition
= (Options
>> 24) & 0x000000ff;
1692 DesiredAccess
= IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
1693 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
1695 if (DirectoryFile
) {
1696 return STATUS_NOT_A_DIRECTORY
;
1699 if (OpenTargetDirectory
) {
1701 return STATUS_INVALID_PARAMETER
;
1704 if ( (CreateDisposition
!= FILE_OPEN
) &&
1705 (CreateDisposition
!= FILE_OPEN_IF
) ) {
1706 return STATUS_ACCESS_DENIED
;
1709 if ( !FlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1710 Vcb
->OpenVolumeCount
!= 0 ) {
1711 return STATUS_SHARING_VIOLATION
;
1714 Ccb
= Ext2AllocateCcb(0, NULL
);
1716 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1720 Status
= STATUS_SUCCESS
;
1722 if (Vcb
->OpenVolumeCount
> 0) {
1723 Status
= IoCheckShareAccess( DesiredAccess
, ShareAccess
,
1725 &(Vcb
->ShareAccess
), TRUE
);
1727 if (!NT_SUCCESS(Status
)) {
1731 IoSetShareAccess( DesiredAccess
, ShareAccess
,
1733 &(Vcb
->ShareAccess
) );
1737 if (Vcb
->OpenVolumeCount
== 0 &&
1738 !IsFlagOn(ShareAccess
, FILE_SHARE_READ
) &&
1739 !IsFlagOn(ShareAccess
, FILE_SHARE_WRITE
) ){
1741 if (!IsVcbReadOnly(Vcb
)) {
1742 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1743 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1746 SetLongFlag(Vcb
->Flags
, VCB_VOLUME_LOCKED
);
1747 Vcb
->LockFile
= IrpSp
->FileObject
;
1749 if (FlagOn(DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
) ) {
1750 if (!IsVcbReadOnly(Vcb
)) {
1751 Ext2FlushFiles(IrpContext
, Vcb
, FALSE
);
1752 Ext2FlushVolume(IrpContext
, Vcb
, FALSE
);
1757 IrpSp
->FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
1758 IrpSp
->FileObject
->FsContext
= Vcb
;
1759 IrpSp
->FileObject
->FsContext2
= Ccb
;
1760 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1762 Ext2ReferXcb(&Vcb
->ReferenceCount
);
1763 Ext2ReferXcb(&Vcb
->OpenHandleCount
);
1764 Ext2ReferXcb(&Vcb
->OpenVolumeCount
);
1766 Irp
->IoStatus
.Information
= FILE_OPENED
;
1775 Ext2Create (IN PEXT2_IRP_CONTEXT IrpContext
)
1777 PDEVICE_OBJECT DeviceObject
;
1779 PIO_STACK_LOCATION IrpSp
;
1781 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1782 PEXT2_FCBVCB Xcb
= NULL
;
1783 BOOLEAN PostIrp
= FALSE
;
1784 BOOLEAN VcbResourceAcquired
= FALSE
;
1786 DeviceObject
= IrpContext
->DeviceObject
;
1787 Irp
= IrpContext
->Irp
;
1788 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1790 Xcb
= (PEXT2_FCBVCB
) (IrpSp
->FileObject
->FsContext
);
1792 if (IsExt2FsDevice(DeviceObject
)) {
1794 DEBUG(DL_INF
, ( "Ext2Create: Create on main device object.\n"));
1796 Status
= STATUS_SUCCESS
;
1797 Irp
->IoStatus
.Information
= FILE_OPENED
;
1799 Ext2CompleteIrpContext(IrpContext
, Status
);
1806 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1807 ASSERT(Vcb
->Identifier
.Type
== EXT2VCB
);
1808 IrpSp
->FileObject
->Vpb
= Vcb
->Vpb
;
1810 if (!IsMounted(Vcb
)) {
1812 if (IsFlagOn(Vcb
->Flags
, VCB_DEVICE_REMOVED
)) {
1813 Status
= STATUS_NO_SUCH_DEVICE
;
1815 Status
= STATUS_VOLUME_DISMOUNTED
;
1820 if (!ExAcquireResourceExclusiveLite(
1821 &Vcb
->MainResource
, TRUE
)) {
1822 Status
= STATUS_PENDING
;
1825 VcbResourceAcquired
= TRUE
;
1827 Ext2VerifyVcb(IrpContext
, Vcb
);
1829 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
1830 Status
= STATUS_ACCESS_DENIED
;
1831 if (IsFlagOn(Vcb
->Flags
, VCB_DISMOUNT_PENDING
)) {
1832 Status
= STATUS_VOLUME_DISMOUNTED
;
1837 if ( ((IrpSp
->FileObject
->FileName
.Length
== 0) &&
1838 (IrpSp
->FileObject
->RelatedFileObject
== NULL
)) ||
1839 (Xcb
&& Xcb
->Identifier
.Type
== EXT2VCB
) ) {
1840 Status
= Ext2CreateVolume(IrpContext
, Vcb
);
1843 Status
= Ext2CreateFile(IrpContext
, Vcb
, &PostIrp
);
1848 if (VcbResourceAcquired
) {
1849 ExReleaseResourceLite(&Vcb
->MainResource
);
1852 if (!IrpContext
->ExceptionInProgress
&& !PostIrp
) {
1853 if ( Status
== STATUS_PENDING
||
1854 Status
== STATUS_CANT_WAIT
) {
1855 Status
= Ext2QueueRequest(IrpContext
);
1857 Ext2CompleteIrpContext(IrpContext
, Status
);
1867 PEXT2_IRP_CONTEXT IrpContext
,
1872 PUNICODE_STRING FileName
)
1877 struct inode Inode
= { 0 };
1878 struct dentry
*Dentry
= NULL
;
1880 LARGE_INTEGER SysTime
;
1882 iGrp
= (Parent
->Inode
->i_ino
- 1) / BLOCKS_PER_GROUP
;
1884 DEBUG(DL_INF
, ("Ext2CreateInode: %S in %S(Inode=%xh)\n",
1886 Parent
->Mcb
->ShortName
.Buffer
,
1887 Parent
->Inode
->i_ino
));
1889 Status
= Ext2NewInode(IrpContext
, Vcb
, iGrp
, Type
, &iNo
);
1890 if (!NT_SUCCESS(Status
)) {
1894 KeQuerySystemTime(&SysTime
);
1895 Ext2ClearInode(IrpContext
, Vcb
, iNo
);
1896 Inode
.i_sb
= &Vcb
->sb
;
1898 Inode
.i_ctime
= Inode
.i_mtime
=
1899 Inode
.i_atime
= Ext2LinuxTime(SysTime
);
1900 if (IsFlagOn(Vcb
->Flags
, VCB_USER_IDS
)) {
1901 Inode
.i_uid
= Vcb
->uid
;
1902 Inode
.i_gid
= Vcb
->gid
;
1904 Inode
.i_uid
= Parent
->Mcb
->Inode
.i_uid
;
1905 Inode
.i_gid
= Parent
->Mcb
->Inode
.i_gid
;
1907 Inode
.i_generation
= Parent
->Inode
->i_generation
;
1908 Inode
.i_mode
= S_IPERMISSION_MASK
&
1909 Parent
->Inode
->i_mode
;
1910 if (Type
== EXT2_FT_DIR
) {
1911 Inode
.i_mode
|= S_IFDIR
;
1912 } else if (Type
== EXT2_FT_REG_FILE
) {
1913 Inode
.i_mode
&= S_IFATTR
;
1914 Inode
.i_mode
|= S_IFREG
;
1919 /* Force using extent */
1920 if (IsFlagOn(SUPER_BLOCK
->s_feature_incompat
, EXT4_FEATURE_INCOMPAT_EXTENTS
)) {
1921 Inode
.i_flags
|= EXT2_EXTENTS_FL
;
1922 ext4_ext_tree_init(IrpContext
, NULL
, &Inode
);
1923 /* ext4_ext_tree_init will save inode body */
1925 /* save inode body to cache */
1926 Ext2SaveInode(IrpContext
, Vcb
, &Inode
);
1929 /* add new entry to its parent */
1930 Status
= Ext2AddEntry(
1939 if (!NT_SUCCESS(Status
)) {
1941 Ext2FreeInode(IrpContext
, Vcb
, iNo
, Type
);
1945 DEBUG(DL_INF
, ("Ext2CreateInode: New Inode = %xh (Type=%xh)\n",
1946 Inode
.i_ino
, Type
));
1951 Ext2FreeEntry(Dentry
);
1958 Ext2SupersedeOrOverWriteFile(
1959 IN PEXT2_IRP_CONTEXT IrpContext
,
1960 IN PFILE_OBJECT FileObject
,
1963 IN PLARGE_INTEGER AllocationSize
,
1964 IN ULONG Disposition
1967 LARGE_INTEGER CurrentTime
;
1970 KeQuerySystemTime(&CurrentTime
);
1973 if (!MmCanFileBeTruncated(&(Fcb
->SectionObject
), &(Size
))) {
1974 return STATUS_USER_MAPPED_FILE
;
1977 /* purge all file cache and shrink cache windows size */
1978 CcPurgeCacheSection(&Fcb
->SectionObject
, NULL
, 0, FALSE
);
1979 Fcb
->Header
.AllocationSize
.QuadPart
=
1980 Fcb
->Header
.FileSize
.QuadPart
=
1981 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
1982 CcSetFileSizes(FileObject
,
1983 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
1985 Size
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
1986 (ULONGLONG
)AllocationSize
->QuadPart
,
1987 (ULONGLONG
)BLOCK_SIZE
);
1989 if ((loff_t
)Size
.QuadPart
> Fcb
->Inode
->i_size
) {
1990 Ext2ExpandFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1992 Ext2TruncateFile(IrpContext
, Vcb
, Fcb
->Mcb
, &Size
);
1995 Fcb
->Header
.AllocationSize
= Size
;
1996 if (Fcb
->Header
.AllocationSize
.QuadPart
> 0) {
1997 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
1998 CcSetFileSizes(FileObject
,
1999 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
2002 /* remove all extent mappings */
2003 DEBUG(DL_EXT
, ("Ext2SuperSede ...: %wZ\n", &Fcb
->Mcb
->FullName
));
2004 Fcb
->Inode
->i_size
= 0;
2006 if (Disposition
== FILE_SUPERSEDE
) {
2007 Fcb
->Inode
->i_ctime
= Ext2LinuxTime(CurrentTime
);
2009 Fcb
->Inode
->i_atime
=
2010 Fcb
->Inode
->i_mtime
= Ext2LinuxTime(CurrentTime
);
2011 Ext2SaveInode(IrpContext
, Vcb
, Fcb
->Inode
);
2013 return STATUS_SUCCESS
;