160 lines
4.2 KiB
C++
160 lines
4.2 KiB
C++
#include "PosixACL.h"
|
|
|
|
const std::string PosixACL::defaultACLXAttrName = "system.posix_acl_default";
|
|
const std::string PosixACL::accessACLXAttrName = "system.posix_acl_access";
|
|
|
|
/**
|
|
* @param xattr serialized form of the posix ACL to fill the PosixACL from.
|
|
*/
|
|
bool PosixACL::deserializeXAttr(const CharVector& xattr)
|
|
{
|
|
Deserializer des(&xattr[0], xattr.size());
|
|
|
|
{
|
|
int32_t version;
|
|
|
|
des % version;
|
|
if (!des.good() || version != ACLEntry::POSIX_ACL_XATTR_VERSION)
|
|
return false;
|
|
}
|
|
|
|
entries.clear();
|
|
while (des.good() && des.size() < xattr.size())
|
|
{
|
|
ACLEntry newEntry;
|
|
|
|
des % newEntry;
|
|
entries.push_back(newEntry);
|
|
}
|
|
|
|
return des.good();
|
|
}
|
|
|
|
/**
|
|
* Serialize the ACL in posix_acl_xattr form.
|
|
*/
|
|
void PosixACL::serializeXAttr(CharVector& xattr) const
|
|
{
|
|
xattr.clear();
|
|
|
|
// run twice: once with empty buffer, to calculate the size, then with proper buffer
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Serializer ser(&xattr[0], xattr.size());
|
|
|
|
ser % ACLEntry::POSIX_ACL_XATTR_VERSION;
|
|
|
|
// entries
|
|
for (ACLEntryVecCIter entryIt = entries.begin(); entryIt != entries.end(); ++entryIt)
|
|
ser % *entryIt;
|
|
|
|
xattr.resize(ser.size());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Modify the ACL based on the given mode bits. Also modifies the mode bits according to the
|
|
* permissions granted in the ACL.
|
|
* This effectively turns a directory default ACL into a file access ACL.
|
|
*
|
|
* @param mode Mode bits of the new file.
|
|
* @returns whether an ACL is necessary for the newly created file.
|
|
*/
|
|
FhgfsOpsErr PosixACL::modifyModeBits(int& outMode, bool& outNeedsACL)
|
|
{
|
|
outNeedsACL = false;
|
|
int newMode = outMode;
|
|
|
|
// Pointers to the group/mask mode of the ACL. In case we find group/mask entries, we have to
|
|
// take them into account last.
|
|
unsigned short* groupPerm = NULL;
|
|
unsigned short* maskPerm = NULL;
|
|
|
|
for (ACLEntryVecIter entryIt = entries.begin(); entryIt != entries.end(); ++entryIt)
|
|
{
|
|
ACLEntry& entry = *entryIt;
|
|
|
|
switch (entry.tag)
|
|
{
|
|
case ACLEntry::ACL_USER_OBJ:
|
|
{
|
|
// Apply 'user' permission of the mode to the ACL's 'owner' entry.
|
|
entry.perm &= (newMode >> 6) | ~0007;
|
|
|
|
// Apply 'owner' entry of the ACL to the owner's permission in the mode flags.
|
|
newMode &= (entry.perm << 6) | ~0700;
|
|
}
|
|
break;
|
|
|
|
case ACLEntry::ACL_USER:
|
|
case ACLEntry::ACL_GROUP:
|
|
{
|
|
// If the ACL has named user/group entries, it can't be represented using only
|
|
// mode bits.
|
|
outNeedsACL = true;
|
|
}
|
|
break;
|
|
|
|
case ACLEntry::ACL_GROUP_OBJ:
|
|
{
|
|
groupPerm = &entry.perm;
|
|
}
|
|
break;
|
|
|
|
case ACLEntry::ACL_OTHER:
|
|
{
|
|
// Apply 'other' permission from the mode to the ACL's 'other' entry.
|
|
entry.perm &= newMode | ~0007;
|
|
|
|
// Apply 'other' entry of the ACL to the 'other' permission in the mode flags.
|
|
newMode &= entry.perm | ~0007;
|
|
}
|
|
break;
|
|
|
|
case ACLEntry::ACL_MASK:
|
|
{
|
|
maskPerm = &entry.perm;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FhgfsOpsErr_INTERNAL;
|
|
}
|
|
}
|
|
|
|
if (maskPerm)
|
|
{
|
|
// The 'mask' entry of the ACL influences the 'group' access bits and vice-versa.
|
|
*maskPerm &= (newMode >> 3) | ~0007;
|
|
newMode &= (*maskPerm << 3) | ~0070;
|
|
}
|
|
else
|
|
{
|
|
// If there's no mask, the group mode bits are determined using the group acl entry.
|
|
if (!groupPerm)
|
|
return FhgfsOpsErr_INTERNAL;
|
|
|
|
*groupPerm &= (newMode >> 3) | ~0007;
|
|
newMode &= (*groupPerm << 3) | ~0070;
|
|
}
|
|
|
|
// Apply changes to the last nine mode bits.
|
|
outMode = (outMode & ~0777) | newMode;
|
|
|
|
return FhgfsOpsErr_SUCCESS;
|
|
}
|
|
|
|
std::string PosixACL::toString()
|
|
{
|
|
std::ostringstream ostr;
|
|
|
|
ostr << "ACL Size: " << entries.size() << std::endl;
|
|
|
|
for (ACLEntryVecCIter it = entries.begin(); it != entries.end(); ++it)
|
|
ostr << "Entry[ "
|
|
<< "tag: " << it->tag << " perm: " << it->perm << " id: " << it->id
|
|
<< " ]" << std::endl;
|
|
|
|
return ostr.str();
|
|
}
|