[haiku-commits] r39379 - haiku/trunk/src/add-ons/kernel/file_systems/ext2

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 9 Nov 2010 21:35:00 +0100 (CET)

Author: axeld
Date: 2010-11-09 21:34:59 +0100 (Tue, 09 Nov 2010)
New Revision: 39379
Changeset: http://dev.haiku-os.org/changeset/39379
Ticket: http://dev.haiku-os.org/ticket/6750

Modified:
   haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp
   haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
Log:
* Applied patch by Rohit Yadav that fixes #6750 for ext2. Thanks a lot!
* Fixed warning in Inode::WriteAt(), but left warnings in kernel_interface.cpp
  in there; I guess that's work in progress (although having the io hook would
  be nice).


Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp  2010-11-09 
20:25:43 UTC (rev 39378)
+++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp  2010-11-09 
20:34:59 UTC (rev 39379)
@@ -6,9 +6,9 @@
 
 #include "Inode.h"
 
-#include <fs_cache.h>
 #include <string.h>
 #include <util/AutoLock.h>
+#include <NodeMonitor.h>
 
 #include "CachedBlock.h"
 #include "DataStream.h"
@@ -51,7 +51,7 @@
                fHasExtraAttributes = (fNodeSize == sizeof(ext2_inode)
                        && fNode.ExtraInodeSize() + EXT2_INODE_NORMAL_SIZE
                                == sizeof(ext2_inode));
-               
+
                if (IsDirectory() || (IsSymLink() && Size() < 60)) {
                        TRACE("Inode::Inode(): Not creating the file cache\n");
                        fCached = false;
@@ -130,7 +130,7 @@
                 if (status != B_OK)
                          return status;
        }
-       
+
        CachedBlock cached(fVolume);
        uint8* inodeBlockData = cached.SetToWritable(transaction, blockNum);
        if (inodeBlockData == NULL)
@@ -140,7 +140,7 @@
                "index: %lu, inode size: %lu, node size: %lu, this: %p, node: 
%p\n",
                fID, blockNum, inodeBlockData, fVolume->InodeBlockIndex(fID),
                fVolume->InodeSize(), fNodeSize, this, &fNode);
-       memcpy(inodeBlockData + 
+       memcpy(inodeBlockData +
                        fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(),
                (uint8*)&fNode, fNodeSize);
 
@@ -187,32 +187,39 @@
 status_t
 Inode::CheckPermissions(int accessMode) const
 {
-       uid_t user = geteuid();
-       gid_t group = getegid();
-
        // you never have write access to a read-only volume
-       if (accessMode & W_OK && fVolume->IsReadOnly())
+       if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
                return B_READ_ONLY_DEVICE;
 
-       // root users always have full access (but they can't execute files 
without
-       // any execute permissions set)
-       if (user == 0) {
-               if (!((accessMode & X_OK) != 0 && (Mode() & S_IXUSR) == 0)
-                       || S_ISDIR(Mode()))
-                       return B_OK;
-       }
-
-       // shift mode bits, to check directly against accessMode
+       // get node permissions
        mode_t mode = Mode();
-       if (user == (uid_t)fNode.UserID())
-               mode >>= 6;
-       else if (group == (gid_t)fNode.GroupID())
-               mode >>= 3;
+       int userPermissions = (mode & S_IRWXU) >> 6;
+       int groupPermissions = (mode & S_IRWXG) >> 3;
+       int otherPermissions = mode & S_IRWXO;
 
-       if (accessMode & ~(mode & S_IRWXO))
-               return B_NOT_ALLOWED;
+       // get the node permissions for this uid/gid
+       int permissions = 0;
+       uid_t uid = geteuid();
+       gid_t gid = getegid();
 
-       return B_OK;
+       if (uid == 0) {
+               // user is root
+               // root has always read/write permission, but at least one of 
the
+               // X bits must be set for execute permission
+               permissions = userPermissions | groupPermissions | 
otherPermissions
+                       | R_OK | W_OK;
+       } else if (uid == (uid_t)fNode.UserID()) {
+               // user is node owner
+               permissions = userPermissions;
+       } else if (gid == (gid_t)fNode.GroupID()) {
+               // user is in owning group
+               permissions = groupPermissions;
+       } else {
+               // user is one of the others
+               permissions = otherPermissions;
+       }
+
+       return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
 }
 
 
@@ -321,8 +328,8 @@
                                if (_count) {
                                        *_count = 1;
                                        uint32 nextBlock = block;
-                                       while (((++index & (perBlock - 1)) != 
0) 
-                                               && indirectBlocks[index & 
(perBlock - 1)] 
+                                       while (((++index & (perBlock - 1)) != 0)
+                                               && indirectBlocks[index & 
(perBlock - 1)]
                                                        == ++nextBlock)
                                                (*_count)++;
                                }
@@ -391,9 +398,11 @@
 
        // NOTE: Debugging info to find why sometimes resize doesn't happen
        size_t length = *_length;
+#ifdef TRACE_EXT2
        off_t oldEnd = pos + length;
        TRACE("Inode::WriteAt(): Old calc for end? %x:%x\n",
                (int)(oldEnd >> 32), (int)(oldEnd & 0xFFFFFFFF));
+#endif
 
        off_t end = pos + (off_t)length;
        off_t oldSize = Size();
@@ -564,7 +573,7 @@
                if (firstOrphanID != 0) {
                        Vnode firstOrphan(fVolume, firstOrphanID);
                        Inode* nextOrphan;
-               
+
                        status = firstOrphan.Get(&nextOrphan);
                        if (status != B_OK)
                                return status;
@@ -625,7 +634,7 @@
 
                        Vnode vnode(volume, entryID);
                        Inode* inode;
-       
+
                        status = vnode.Get(&inode);
                        if (status != B_OK) {
                                TRACE("Inode::Create() Failed to get the inode 
from the "
@@ -720,7 +729,7 @@
        inode->SetAccessTime(&timespec);
        inode->SetCreationTime(&timespec);
        inode->SetModificationTime(&timespec);
-       
+
        if (sizeof(ext2_inode) < volume->InodeSize())
                node.SetExtraInodeSize(sizeof(ext2_inode) - 
EXT2_INODE_NORMAL_SIZE);
 
@@ -979,9 +988,9 @@
        if (numBlocks > 0xffffffffffffULL) {
                fNode.SetFlag(EXT2_INODE_HUGE_FILE);
                numBlocks /= (fVolume->BlockSize() / 512);
-       } else 
+       } else
                fNode.ClearFlag(EXT2_INODE_HUGE_FILE);
-               
+
        fNode.SetNumBlocks64(numBlocks);
        return B_OK;
 }

Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp       
2010-11-09 20:25:43 UTC (rev 39378)
+++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp       
2010-11-09 20:34:59 UTC (rev 39379)
@@ -257,7 +257,7 @@
        status = inode->WriteBack(transaction);
        if (status != B_OK)
                return status;
-       
+
        TRACE("ext2_remove_vnode(): Freeing inode\n");
        status = volume->FreeInode(transaction, inode->ID(), 
inode->IsDirectory());
 
@@ -414,7 +414,7 @@
                off_t blockOffset = block << volume->BlockShift();
                uint32 blockLength = volume->BlockSize() * count;
 
-               if (index > 0 && (vecs[index - 1].offset 
+               if (index > 0 && (vecs[index - 1].offset
                                == blockOffset - vecs[index - 1].length
                                || (vecs[index - 1].offset == -1 && block == 
0))) {
                        vecs[index - 1].length += blockLength;
@@ -470,17 +470,17 @@
 
        HTree htree(volume, directory);
        DirectoryIterator* iterator;
-       
+
        status = htree.Lookup(name, &iterator);
        if (status != B_OK)
                return status;
-       
+
        ObjectDeleter<DirectoryIterator> iteratorDeleter(iterator);
 
        status = iterator->FindEntry(name, _vnodeID);
        if (status != B_OK)
                return status;
-       
+
        return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
 }
 
@@ -525,7 +525,7 @@
                                }
 
                                TRACE("ioctl: Blocks cleared\n");
-                               
+
                                transaction.Done();
                                transaction.Start(volume->GetJournal());
                        }
@@ -568,7 +568,7 @@
        inode->GetModificationTime(&stat->st_mtim);
        inode->GetChangeTime(&stat->st_ctim);
        inode->GetCreationTime(&stat->st_crtim);
-       
+
        stat->st_size = inode->Size();
        stat->st_blocks = (inode->Size() + 511) / 512;
 
@@ -588,59 +588,72 @@
 
        Inode* inode = (Inode*)_node->private_node;
 
-       status_t status = inode->CheckPermissions(W_OK);
-       if (status < B_OK)
-               return status;
+       ext2_inode& node = inode->Node();
+       bool updateTime = false;
+       uid_t uid = geteuid();
 
+       bool isOwnerOrRoot = uid == 0 || uid == (uid_t)node.UserID();
+       bool hasWriteAccess = inode->CheckPermissions(W_OK) == B_OK;
+
        TRACE("ext2_write_stat: Starting transaction\n");
        Transaction transaction(volume->GetJournal());
        inode->WriteLockInTransaction(transaction);
 
-       bool updateTime = false;
-
-       if ((mask & B_STAT_SIZE) != 0) {
+       if ((mask & B_STAT_SIZE) != 0 && inode->Size() != stat->st_size) {
                if (inode->IsDirectory())
                        return B_IS_A_DIRECTORY;
                if (!inode->IsFile())
                        return B_BAD_VALUE;
+               if (!hasWriteAccess)
+                       return B_NOT_ALLOWED;
 
                TRACE("ext2_write_stat: Old size: %ld, new size: %ld\n",
                        (long)inode->Size(), (long)stat->st_size);
-               if (inode->Size() != stat->st_size) {
-                       off_t oldSize = inode->Size();
 
-                       status = inode->Resize(transaction, stat->st_size);
-                       if(status != B_OK)
-                               return status;
+               off_t oldSize = inode->Size();
 
-                       if ((mask & B_STAT_SIZE_INSECURE) == 0) {
-                               rw_lock_write_unlock(inode->Lock());
-                               inode->FillGapWithZeros(oldSize, inode->Size());
-                               rw_lock_write_lock(inode->Lock());
-                       }
+               status_t status = inode->Resize(transaction, stat->st_size);
+               if(status != B_OK)
+                       return status;
 
-                       updateTime = true;
+               if ((mask & B_STAT_SIZE_INSECURE) == 0) {
+                       rw_lock_write_unlock(inode->Lock());
+                       inode->FillGapWithZeros(oldSize, inode->Size());
+                       rw_lock_write_lock(inode->Lock());
                }
+
+               updateTime = true;
        }
 
-       ext2_inode& node = inode->Node();
-
        if ((mask & B_STAT_MODE) != 0) {
+               // only the user or root can do that
+               if (!isOwnerOrRoot)
+                       return B_NOT_ALLOWED;
                node.UpdateMode(stat->st_mode, S_IUMSK);
                updateTime = true;
        }
 
        if ((mask & B_STAT_UID) != 0) {
+               // only root should be allowed
+               if (uid != 0)
+                       return B_NOT_ALLOWED;
                node.SetUserID(stat->st_uid);
                updateTime = true;
        }
+
        if ((mask & B_STAT_GID) != 0) {
+               // only the user or root can do that
+               if (!isOwnerOrRoot)
+                       return B_NOT_ALLOWED;
                node.SetGroupID(stat->st_gid);
                updateTime = true;
        }
 
        if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime
                || (mask & B_STAT_CHANGE_TIME) != 0) {
+               // the user or root can do that or any user with write access
+               if (!isOwnerOrRoot && !hasWriteAccess)
+                       return B_NOT_ALLOWED;
                struct timespec newTimespec = { 0, 0};
 
                if ((mask & B_STAT_MODIFICATION_TIME) != 0)
@@ -655,10 +668,14 @@
 
                inode->SetModificationTime(&newTimespec);
        }
-       if ((mask & B_STAT_CREATION_TIME) != 0)
+       if ((mask & B_STAT_CREATION_TIME) != 0) {
+               // the user or root can do that or any user with write access
+               if (!isOwnerOrRoot && !hasWriteAccess)
+                       return B_NOT_ALLOWED;
                inode->SetCreationTime(&stat->st_crtim);
+       }
 
-       status = inode->WriteBack(transaction);
+       status_t status = inode->WriteBack(transaction);
        if (status == B_OK)
                status = transaction.Done();
        if (status == B_OK)
@@ -817,7 +834,7 @@
 ext2_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* node)
 {
        // TODO
-       
+
        return B_NOT_SUPPORTED;
 }
 
@@ -943,7 +960,7 @@
 
                        const HTreeRoot* data = (const 
HTreeRoot*)cached.SetTo(blockNum);
                        parentID = data->dotdot.InodeID();
-               } while (parentID != oldID && parentID != oldDirID 
+               } while (parentID != oldID && parentID != oldDirID
                        && parentID != EXT2_ROOT_NODE);
 
                if (parentID == oldID)
@@ -1013,7 +1030,7 @@
                        return status;
        } else
                return status;
-       
+
        // Remove entry from source folder
        status = oldIterator->RemoveEntry(transaction);
        if (status != B_OK)
@@ -1047,7 +1064,7 @@
        if (status != B_OK) {
                entry_cache_remove(volume->ID(), oldDirectory->ID(), newName);
                entry_cache_add(volume->ID(), newDirectory->ID(), oldName, 
oldID);
-       
+
                return status;
        }
 
@@ -1237,7 +1254,7 @@
 static status_t
 ext2_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name,
        int mode)
-{ 
+{
        TRACE("ext2_create_dir()\n");
        Volume* volume = (Volume*)_volume->private_volume;
        Inode* directory = (Inode*)_directory->private_node;
@@ -1416,7 +1433,7 @@
 }
 
 
-static status_t 
+static status_t
 ext2_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
 {
        Inode* inode = (Inode*)_node->private_node;
@@ -1512,7 +1529,7 @@
        int openMode, void** _cookie)
 {
        TRACE("%s()\n", __FUNCTION__);
-       
+
        Volume* volume = (Volume*)_volume->private_volume;
        Inode* inode = (Inode*)_node->private_node;
        Attribute attribute(inode);
@@ -1610,6 +1627,7 @@
        &ext2_get_vnode,
 };
 
+
 fs_vnode_ops gExt2VnodeOps = {
        /* vnode operations */
        &ext2_lookup,
@@ -1680,9 +1698,9 @@
        NULL, //&ext2_write_attr_stat,
        NULL, //&ext2_rename_attr,
        NULL, //&ext2_remove_attr,
-       
 };
 
+
 static file_system_module_info sExt2FileSystem = {
        {
                "file_systems/ext2" B_CURRENT_FS_API_VERSION,
@@ -1705,6 +1723,7 @@
        NULL,
 };
 
+
 module_info *modules[] = {
        (module_info *)&sExt2FileSystem,
        NULL,


Other related posts:

  • » [haiku-commits] r39379 - haiku/trunk/src/add-ons/kernel/file_systems/ext2 - axeld