Skip to content

Commit 0a8e12b

Browse files
committed
refactor(master): allow ACL ops in KV backends
Thread FilesystemOperationContext through all ACL methods (deleteAcl, setAcl, getAcl, applySetAcl, applySetRichAcl) in both IFilesystemNodeOperations and IFilesystemOperations, removing the internal transaction creation that was hardcoded inside each FilesystemOperationsBase method body. Callers (matoclserv, restore) now own the transaction lifecycle, enabling KV backends to participate in ACL operations as part of a single coordinated transaction. Introduce a protected virtual `getAclForAccess()` method to abstract ACL retrieval inside `access()`. The default in-memory implementation reads from `aclStorage`; KV backends can override it to materialise the ACL from the key-value store. Pass `FilesystemOperationContext` through `access()` at all call sites so the new virtual hook receives the context it needs. A caller-supplied `RichACL scratch` buffer is provided so temporary ACLs can be returned without extra allocation. The in-memory base implementation is not affected by the changes. Also document all affected interface declarations according to their implementations. Signed-off-by: guillex <guillex@leil.io>
1 parent 83eb181 commit 0a8e12b

10 files changed

+397
-109
lines changed

src/master/filesystem_node.cc

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,7 +1938,9 @@ void FilesystemNodeOperationsBase::setExtraAttrRecursive(FSNode *node, uint32_t
19381938
fsnodes_update_checksum(node);
19391939
}
19401940

1941-
uint8_t FilesystemNodeOperationsBase::deleteAcl(FSNode *node, AclType type, uint32_t timeStamp) {
1941+
uint8_t FilesystemNodeOperationsBase::deleteAcl(
1942+
[[maybe_unused]] const FilesystemOperationContext &fsOpContext, FSNode *node, AclType type,
1943+
uint32_t timeStamp) {
19421944
if (type == AclType::kRichACL) {
19431945
gMetadata->aclStorage.erase(node->id);
19441946
} else if (type == AclType::kDefault) {
@@ -1979,7 +1981,8 @@ uint8_t FilesystemNodeOperationsBase::deleteAcl(FSNode *node, AclType type, uint
19791981
}
19801982

19811983
#ifndef METARESTORE
1982-
uint8_t FilesystemNodeOperationsBase::getAcl(FSNode *node, RichACL &acl) {
1984+
uint8_t FilesystemNodeOperationsBase::getAcl(
1985+
[[maybe_unused]] const FilesystemOperationContext &fsOpContext, FSNode *node, RichACL &acl) {
19831986
const RichACL *richAcl = gMetadata->aclStorage.get(node->id);
19841987

19851988
if (!richAcl) { return SAUNAFS_ERROR_ENOATTR; }
@@ -1991,7 +1994,9 @@ uint8_t FilesystemNodeOperationsBase::getAcl(FSNode *node, RichACL &acl) {
19911994
}
19921995
#endif
19931996

1994-
uint8_t FilesystemNodeOperationsBase::setAcl(FSNode *node, const RichACL &acl, uint32_t timeStamp) {
1997+
uint8_t FilesystemNodeOperationsBase::setAcl(
1998+
[[maybe_unused]] const FilesystemOperationContext &fsOpContext, FSNode *node,
1999+
const RichACL &acl, uint32_t timeStamp) {
19952000
if (!acl.checkInheritFlags(node->type == FSNodeType::kDirectory)) {
19962001
return SAUNAFS_ERROR_ENOTSUP;
19972002
}
@@ -2021,8 +2026,9 @@ uint8_t FilesystemNodeOperationsBase::setAcl(FSNode *node, const RichACL &acl, u
20212026
return SAUNAFS_STATUS_OK;
20222027
}
20232028

2024-
uint8_t FilesystemNodeOperationsBase::setAcl(FSNode *node, AclType type,
2025-
const AccessControlList &acl, uint32_t timeStamp) {
2029+
uint8_t FilesystemNodeOperationsBase::setAcl(
2030+
[[maybe_unused]] const FilesystemOperationContext &fsOpContext, FSNode *node, AclType type,
2031+
const AccessControlList &acl, uint32_t timeStamp) {
20262032
if (type != AclType::kDefault && type != AclType::kAccess) {
20272033
return SAUNAFS_ERROR_EINVAL;
20282034
}
@@ -2076,12 +2082,21 @@ int FilesystemNodeOperationsBase::nameCheck(const std::string &name) {
20762082
return 0;
20772083
}
20782084

2079-
int FilesystemNodeOperationsBase::access(const FsContext &context, FSNode *node, uint8_t modeMask) {
2085+
const RichACL *FilesystemNodeOperationsBase::getAclForAccess(
2086+
[[maybe_unused]] const FilesystemOperationContext &fsOpContext, FSNode *node,
2087+
[[maybe_unused]] std::optional<RichACL> &scratch) {
2088+
return gMetadata->aclStorage.get(node->id);
2089+
}
2090+
2091+
int FilesystemNodeOperationsBase::access(const FsContext &context,
2092+
const FilesystemOperationContext &fsOpContext,
2093+
FSNode *node, uint8_t modeMask) {
20802094
if ((context.sesflags() & SESFLAG_NOMASTERPERMCHECK) || context.uid() == 0) {
20812095
return 1; // super user or no permission check
20822096
}
20832097

2084-
const RichACL *nodeAcl = gMetadata->aclStorage.get(node->id);
2098+
std::optional<RichACL> aclScratch; // not constructed here; KV backends emplace() as needed
2099+
const RichACL *nodeAcl = getAclForAccess(fsOpContext, node, aclScratch);
20852100

20862101
// If ACLs are present, use it for permission checking
20872102
if (nodeAcl != nullptr) {
@@ -2238,7 +2253,7 @@ uint8_t FilesystemNodeOperationsBase::getNodeForOperation(
22382253
return SAUNAFS_ERROR_EPERM;
22392254
}
22402255

2241-
if (context.canCheckPermissions() && !access(context, candidateNode, modeMask)) {
2256+
if (context.canCheckPermissions() && !access(context, fsOpContext, candidateNode, modeMask)) {
22422257
return SAUNAFS_ERROR_EACCES;
22432258
}
22442259

src/master/filesystem_node.h

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#include "common/platform.h"
2424

25+
#include <optional>
26+
2527
#include "master/filesystem_node_operations_interface.h"
2628
#include "master/filesystem_node_types.h"
2729
#include "master/fs_context.h"
@@ -174,13 +176,28 @@ class FilesystemNodeOperationsBase : public IFilesystemNodeOperations {
174176
std::string escapeName(const std::string &name) override;
175177

176178
// ACL operations
177-
uint8_t setAcl(FSNode *node, const RichACL &acl, uint32_t timeStamp) override;
178-
uint8_t setAcl(FSNode *node, AclType type, const AccessControlList &acl,
179-
uint32_t timeStamp) override;
179+
180+
/// Stores a RichACL on a node, replacing any previously stored ACL.
181+
/// @see IFilesystemNodeOperations::setAcl
182+
uint8_t setAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
183+
const RichACL &acl, uint32_t timeStamp) override;
184+
185+
/// Merges a POSIX ACL into the node's stored RichACL.
186+
/// @see IFilesystemNodeOperations::setAcl
187+
uint8_t setAcl(const FilesystemOperationContext &fsOpContext, FSNode *node, AclType type,
188+
const AccessControlList &acl, uint32_t timeStamp) override;
189+
180190
#ifndef METARESTORE
181-
uint8_t getAcl(FSNode *node, RichACL &acl) override;
191+
/// Retrieves the stored RichACL for a node.
192+
/// @see IFilesystemNodeOperations::getAcl
193+
uint8_t getAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
194+
RichACL &acl) override;
182195
#endif // METARESTORE
183-
uint8_t deleteAcl(FSNode *node, AclType type, uint32_t timeStamp) override;
196+
197+
/// Removes or prunes the ACL stored on a node according to the ACL type.
198+
/// @see IFilesystemNodeOperations::deleteAcl
199+
uint8_t deleteAcl(const FilesystemOperationContext &fsOpContext, FSNode *node, AclType type,
200+
uint32_t timeStamp) override;
184201

185202
// Recursive operations
186203
#ifndef METARESTORE
@@ -208,7 +225,18 @@ class FilesystemNodeOperationsBase : public IFilesystemNodeOperations {
208225
inode_t *permissionDeniedINodesOut) override;
209226

210227
// Access control operations
211-
int access(const FsContext &context, FSNode *node, uint8_t modeMask) override;
228+
int access(const FsContext &context, const FilesystemOperationContext &fsOpContext,
229+
FSNode *node, uint8_t modeMask) override;
230+
231+
protected:
232+
/// Returns the stored RichACL for @p node, or nullptr if none is present.
233+
/// @p scratch is an optional caller-supplied buffer; implementations that need
234+
/// to materialise a temporary ACL (e.g. KV backends) emplace into @p scratch
235+
/// and return &scratch->value(), while the default in-memory implementation
236+
/// leaves @p scratch empty and returns a pointer into aclStorage directly.
237+
/// The caller avoids constructing a RichACL when it is not needed.
238+
virtual const RichACL *getAclForAccess(const FilesystemOperationContext &fsOpContext,
239+
FSNode *node, std::optional<RichACL> &scratch);
212240
int stickyAccess(FSNode *parent, FSNode *node, uint32_t uid) override;
213241
int nameCheck(const std::string &name) override;
214242
uint8_t verifySession(const FsContext &context, OperationMode operationMode,

src/master/filesystem_node_operations_interface.h

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,13 +466,78 @@ class IFilesystemNodeOperations {
466466
virtual std::string escapeName(const std::string &name) = 0;
467467

468468
// ACL operations
469-
virtual uint8_t setAcl(FSNode *node, const RichACL &acl, uint32_t timeStamp) = 0;
470-
virtual uint8_t setAcl(FSNode *node, AclType type, const AccessControlList &acl,
471-
uint32_t timeStamp) = 0;
469+
470+
/// Stores a RichACL on a node, replacing any previously stored ACL.
471+
///
472+
/// If the ACL is equivalent to the node's POSIX mode bits (RichACL::equivMode returns true),
473+
/// the stored ACL is erased and only the mode bits are updated. Otherwise the ACL is written
474+
/// to storage after resolving the auto-set-mode flag: if kAutoSetMode is set, the flag is
475+
/// cleared and the ACL's mode is derived from the node's current mode bits before storing.
476+
/// In both cases node->mode is updated to reflect the new permission bits, and the node's
477+
/// ctime and checksum are updated.
478+
///
479+
/// @param fsOpContext The filesystem operation context (transaction).
480+
/// @param node The node on which to set the ACL.
481+
/// @param acl The RichACL to store.
482+
/// @param timeStamp The timestamp used to update the node's ctime.
483+
/// @return SAUNAFS_STATUS_OK on success, SAUNAFS_ERROR_ENOTSUP if the ACL's inherit flags
484+
/// are invalid for the node type.
485+
virtual uint8_t setAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
486+
const RichACL &acl, uint32_t timeStamp) = 0;
487+
488+
/// Merges a POSIX ACL into the node's stored RichACL.
489+
///
490+
/// Reads the current RichACL (if any), calls createExplicitInheritance() and
491+
/// removeInheritOnly() to normalise inheritance, then appends the POSIX ACL entries:
492+
/// - kDefault: calls appendDefaultPosixACL() and refreshes the mode bits from the node.
493+
/// - kAccess: calls appendPosixACL() and updates node->mode from the resulting RichACL.
494+
/// The merged ACL is always written back to storage. node->ctime and checksum are updated.
495+
///
496+
/// @param fsOpContext The filesystem operation context (transaction).
497+
/// @param node The node on which to set the ACL.
498+
/// @param type Must be AclType::kAccess or AclType::kDefault.
499+
/// @param acl The POSIX ACL entries to merge in.
500+
/// @param timeStamp The timestamp used to update the node's ctime.
501+
/// @return SAUNAFS_STATUS_OK on success.
502+
/// SAUNAFS_ERROR_EINVAL if type is neither kAccess nor kDefault.
503+
/// SAUNAFS_ERROR_ENOTSUP if type is kDefault and node is not a directory.
504+
virtual uint8_t setAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
505+
AclType type, const AccessControlList &acl, uint32_t timeStamp) = 0;
506+
472507
#ifndef METARESTORE
473-
virtual uint8_t getAcl(FSNode *node, RichACL &acl) = 0;
508+
/// Retrieves the stored RichACL for a node.
509+
///
510+
/// Looks up the ACL in storage. If no ACL is stored for the node (i.e. permissions are
511+
/// fully described by the mode bits alone), returns SAUNAFS_ERROR_ENOATTR. Otherwise
512+
/// copies the stored ACL into @p acl and asserts that node->mode matches the ACL's mode.
513+
///
514+
/// @param fsOpContext The filesystem operation context (transaction).
515+
/// @param node The node whose ACL to retrieve.
516+
/// @param[out] acl Receives the stored RichACL.
517+
/// @return SAUNAFS_STATUS_OK on success, SAUNAFS_ERROR_ENOATTR if no ACL is stored.
518+
virtual uint8_t getAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
519+
RichACL &acl) = 0;
474520
#endif // METARESTORE
475-
virtual uint8_t deleteAcl(FSNode *node, AclType type, uint32_t timeStamp) = 0;
521+
522+
/// Removes or prunes the ACL stored on a node according to the ACL type.
523+
///
524+
/// - kRichACL: removes the entire stored ACL unconditionally.
525+
/// - kDefault: only valid on directories; reads the current ACL, calls
526+
/// createExplicitInheritance() and removeInheritOnly(true) to strip default
527+
/// (inherit-only) entries, then erases the ACL if empty or writes back the pruned ACL.
528+
/// - kAccess: reads the current ACL, calls createExplicitInheritance() and
529+
/// removeInheritOnly(false) to strip access entries, then erases or writes back.
530+
/// In all cases node->ctime and checksum are updated.
531+
///
532+
/// @param fsOpContext The filesystem operation context (transaction).
533+
/// @param node The node whose ACL to delete or prune.
534+
/// @param type The ACL type to remove (kRichACL, kDefault, or kAccess).
535+
/// @param timeStamp The timestamp used to update the node's ctime.
536+
/// @return SAUNAFS_STATUS_OK on success.
537+
/// SAUNAFS_ERROR_ENOTSUP if type is kDefault and node is not a directory.
538+
/// SAUNAFS_ERROR_EINVAL if type is not kRichACL, kDefault, or kAccess.
539+
virtual uint8_t deleteAcl(const FilesystemOperationContext &fsOpContext, FSNode *node,
540+
AclType type, uint32_t timeStamp) = 0;
476541

477542
// Recursive operations
478543
#ifndef METARESTORE
@@ -501,7 +566,8 @@ class IFilesystemNodeOperations {
501566
inode_t *permissionDeniedINodesOut) = 0;
502567

503568
// Access control operations
504-
virtual int access(const FsContext &context, FSNode *node, uint8_t modeMask) = 0;
569+
virtual int access(const FsContext &context, const FilesystemOperationContext &fsOpContext,
570+
FSNode *node, uint8_t modeMask) = 0;
505571
virtual int stickyAccess(FSNode *parent, FSNode *node, uint32_t uid) = 0;
506572
virtual int nameCheck(const std::string &name) = 0;
507573
virtual uint8_t verifySession(const FsContext &context, OperationMode operationMode,

0 commit comments

Comments
 (0)