[EXT2]
[reactos.git] / reactos / drivers / filesystems / ext2 / src / create.c
index 43703ea..6ef28f7 100644 (file)
@@ -68,7 +68,7 @@ Ext2FollowLink (
     IN PEXT2_VCB            Vcb,
     IN PEXT2_MCB            Parent,
     IN PEXT2_MCB            Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 )
 {
     NTSTATUS        Status = STATUS_LINK_FAILED;
@@ -88,7 +88,7 @@ Ext2FollowLink (
 
         /* exit if we jump into a possible symlink forever loop */
         if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
-                IoGetRemainingStackSize() < 1024) {
+            IoGetRemainingStackSize() < 1024) {
             _SEH2_LEAVE;
         }
 
@@ -113,14 +113,12 @@ Ext2FollowLink (
             bOemBuffer = TRUE;
             RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
 
-            Status = Ext2ReadInode(
+            Status = Ext2ReadSymlink(
                          IrpContext,
                          Vcb,
                          Mcb,
-                         (ULONGLONG)0,
                          OemName.Buffer,
                          (ULONG)(Mcb->Inode.i_size),
-                         FALSE,
                          NULL);
             if (!NT_SUCCESS(Status)) {
                 _SEH2_LEAVE;
@@ -170,9 +168,9 @@ Ext2FollowLink (
         }
 
         if (Target == NULL /* link target doesn't exist */      ||
-                Target == Mcb  /* symlink points to itself */       ||
-                IsMcbSpecialFile(Target) /* target not resolved*/   ||
-                IsFileDeleted(Target)  /* target deleted */         ) {
+            Target == Mcb  /* symlink points to itself */       ||
+            IsMcbSpecialFile(Target) /* target not resolved*/   ||
+            IsFileDeleted(Target)  /* target deleted */         ) {
 
             if (Target) {
                 ASSERT(Target->Refercount > 0);
@@ -180,7 +178,6 @@ Ext2FollowLink (
             }
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
-            Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
             Mcb->Target = NULL;
 
         } else if (IsMcbSymLink(Target)) {
@@ -194,15 +191,18 @@ Ext2FollowLink (
             SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
             ASSERT(Mcb->Target->Refercount > 0);
-            Mcb->FileAttr = Target->FileAttr;
-
+            
         } else {
 
             Mcb->Target = Target;
             SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
             ASSERT(Mcb->Target->Refercount > 0);
-            Mcb->FileAttr = Target->FileAttr;
+        }
+
+        /* add directory flag to file attribute */
+        if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
+            Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
         }
 
     } _SEH2_FINALLY {
@@ -275,7 +275,7 @@ Ext2LookupFile (
     IN PUNICODE_STRING      FullName,
     IN PEXT2_MCB            Parent,
     OUT PEXT2_MCB *         Ext2Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 )
 {
     NTSTATUS        Status = STATUS_OBJECT_NAME_NOT_FOUND;
@@ -289,12 +289,20 @@ Ext2LookupFile (
     BOOLEAN         bParent = FALSE;
     BOOLEAN         bDirectory = FALSE;
     BOOLEAN         LockAcquired = FALSE;
+    BOOLEAN         bNotFollow = FALSE;
 
     _SEH2_TRY {
 
         ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
         LockAcquired = TRUE;
 
+        bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
+#ifndef __REACTOS__
+        Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#else
+        ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#endif
+
         *Ext2Mcb = NULL;
 
         DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
@@ -394,7 +402,7 @@ Ext2LookupFile (
                     Parent = Mcb;
 
                     if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
-                            (Mcb->Refercount == 1)) {
+                        Mcb->Refercount == 1) {
 
                         ASSERT(Mcb->Target);
                         ASSERT(Mcb->Target->Refercount > 0);
@@ -453,16 +461,18 @@ Ext2LookupFile (
                         }
 
                         /* set inode attribute */
-                        if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+                        if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
                             SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY);
                         }
 
                         if (S_ISDIR(Mcb->Inode.i_mode)) {
                             SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
                         } else {
-                            SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
-                            if (!S_ISREG(Mcb->Inode.i_mode) &&
-                                    !S_ISLNK(Mcb->Inode.i_mode)) {
+                            if (S_ISREG(Mcb->Inode.i_mode)) {
+                                SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
+                            } else if (S_ISLNK(Mcb->Inode.i_mode)) {
+                                SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+                            } else {
                                 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
                             }
                         }
@@ -484,7 +494,7 @@ Ext2LookupFile (
                         Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
 
                         /* process symlink */
-                        if (S_ISLNK(Mcb->Inode.i_mode)) {
+                        if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
                             Ext2FollowLink( IrpContext,
                                             Vcb,
                                             Parent,
@@ -616,7 +626,7 @@ Ext2ScanDir (
         Ext2DerefMcb(Parent);
 
         if (bh)
-            brelse(bh);
+            __brelse(bh);
 
         if (!NT_SUCCESS(Status)) {
             if (de)
@@ -659,7 +669,7 @@ NTSTATUS Ext2AddDotEntries(struct ext2_icb *icb, struct inode *dir,
 
 errorout:
     if (bh)
-        brelse (bh);
+        __brelse (bh);
 
     return Ext2WinntError(rc);
 }
@@ -708,9 +718,11 @@ Ext2CreateFile(
     BOOLEAN             DeleteOnClose;
     BOOLEAN             TemporaryFile;
     BOOLEAN             CaseSensitive;
+    BOOLEAN             OpenReparsePoint;
 
     ACCESS_MASK         DesiredAccess;
     ULONG               ShareAccess;
+    ULONG               CcbFlags = 0;
 
     RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
 
@@ -728,6 +740,9 @@ Ext2CreateFile(
     NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
     DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
 
+    /* Try to open reparse point (symlink) itself ? */
+    OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
+
     CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
 
     TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
@@ -843,7 +858,8 @@ Ext2CreateFile(
                      &FileName,
                      ParentMcb,
                      &Mcb,
-                     0 );
+                     0  /* always follow link */
+                    );
 McbExisting:
 
         if (!NT_SUCCESS(Status)) {
@@ -964,7 +980,7 @@ Dissecting:
                     _SEH2_LEAVE;
                 }
 
-                if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(ParentFcb->Mcb->Inode.i_mode)) {
+                if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) {
                     Status = STATUS_ACCESS_DENIED;
                     _SEH2_LEAVE;
                 }
@@ -1104,7 +1120,7 @@ Dissecting:
             if (IsMcbDirectory(Mcb)) {
 
                 if ((CreateDisposition != FILE_OPEN) &&
-                        (CreateDisposition != FILE_OPEN_IF)) {
+                    (CreateDisposition != FILE_OPEN_IF)) {
 
                     Status = STATUS_OBJECT_NAME_COLLISION;
                     Ext2DerefMcb(Mcb);
@@ -1147,7 +1163,11 @@ Openit:
 
             /* refer it's target if it's a symlink, so both refered */
             if (IsMcbSymLink(Mcb)) {
-                if (IsFileDeleted(Mcb->Target)) {
+
+                if (OpenReparsePoint) {
+                    /* set Ccb flag */
+                    CcbFlags = CCB_OPEN_REPARSE_POINT;
+                } else if (IsFileDeleted(Mcb->Target)) {
                     DbgBreak();
                     SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
                     ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
@@ -1162,7 +1182,12 @@ Openit:
             }
 
             // Check readonly flag
-            if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+            if (BooleanFlagOn(DesiredAccess,  FILE_GENERIC_READ) &&
+                !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) {
+                Status = STATUS_ACCESS_DENIED;
+                _SEH2_LEAVE;
+            }
+            if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
                 if (BooleanFlagOn(DesiredAccess,  FILE_WRITE_DATA | FILE_APPEND_DATA |
                                   FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) {
                     Status = STATUS_ACCESS_DENIED;
@@ -1398,7 +1423,7 @@ Openit:
                                   &(Fcb->ShareAccess) );
             }
 
-            Ccb = Ext2AllocateCcb(SymLink);
+            Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
             if (!Ccb) {
                 Status = STATUS_INSUFFICIENT_RESOURCES;
                 DbgBreak();
@@ -1684,7 +1709,7 @@ Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
         return STATUS_SHARING_VIOLATION;
     }
 
-    Ccb = Ext2AllocateCcb(NULL);
+    Ccb = Ext2AllocateCcb(0, NULL);
     if (Ccb == NULL) {
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto errorout;
@@ -1869,9 +1894,9 @@ Ext2CreateInode(
     Inode.i_sb = &Vcb->sb;
     Inode.i_ino = iNo;
     Inode.i_ctime = Inode.i_mtime =
-                        Inode.i_atime = Ext2LinuxTime(SysTime);
-    Inode.i_uid = Parent->Inode->i_uid;
-    Inode.i_gid = Parent->Inode->i_gid;
+    Inode.i_atime = Ext2LinuxTime(SysTime);
+    Inode.i_uid = Vcb->uid;
+    Inode.i_gid = Vcb->gid;
     Inode.i_generation = Parent->Inode->i_generation;
     Inode.i_mode = S_IPERMISSION_MASK &
                    Parent->Inode->i_mode;
@@ -1887,6 +1912,11 @@ Ext2CreateInode(
     /* Force using extent */
     if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
         Inode.i_flags |= EXT2_EXTENTS_FL;
+        ext4_ext_tree_init(IrpContext, NULL, &Inode);
+        /* ext4_ext_tree_init will save inode body */
+    } else {
+        /* save inode body to cache */
+        Ext2SaveInode(IrpContext, Vcb, &Inode);
     }
 
     /* add new entry to its parent */