* 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).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39379 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-11-09 20:34:59 +00:00
parent 48ec4fbb40
commit ea75a051ad
2 changed files with 96 additions and 68 deletions

View File

@ -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"
@ -187,32 +187,39 @@ Inode::UpdateNodeFromDisk()
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;
// get node permissions
mode_t mode = Mode();
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
gid_t gid = getegid();
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;
}
// shift mode bits, to check directly against accessMode
mode_t mode = Mode();
if (user == (uid_t)fNode.UserID())
mode >>= 6;
else if (group == (gid_t)fNode.GroupID())
mode >>= 3;
if (accessMode & ~(mode & S_IRWXO))
return B_NOT_ALLOWED;
return B_OK;
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
}
@ -391,9 +398,11 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
// 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();

View File

@ -588,28 +588,31 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
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);
status_t status = inode->Resize(transaction, stat->st_size);
if(status != B_OK)
return status;
@ -621,26 +624,36 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
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 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
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)
@ -1610,6 +1627,7 @@ fs_volume_ops gExt2VolumeOps = {
&ext2_get_vnode,
};
fs_vnode_ops gExt2VnodeOps = {
/* vnode operations */
&ext2_lookup,
@ -1680,9 +1698,9 @@ fs_vnode_ops gExt2VnodeOps = {
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 @@ static file_system_module_info sExt2FileSystem = {
NULL,
};
module_info *modules[] = {
(module_info *)&sExt2FileSystem,
NULL,