in src/meta/store/ops/Open.cc [108:171]
CoTryTask<Rsp> openExistsFile(IReadOnlyTransaction &txn,
std::optional<DirEntry> &entry,
Inode &inode,
bool checkHole) {
XLOGF_IF(FATAL, !inode.isFile(), "Inode {} is not file", inode);
bool dirty = false;
// check permission
if (req_.flags.contains(O_DIRECTORY)) {
co_return makeError(MetaCode::kNotDirectory);
}
if (req_.flags.accessType() != AccessType::READ && (inode.acl.iflags & FS_IMMUTABLE_FL)) {
co_return makeError(MetaCode::kNoPermission, fmt::format("FS_IMMUTABLE_FL set on inode {}", inode.id));
}
CO_RETURN_ON_ERROR(inode.acl.checkPermission(req_.user, req_.flags.accessType()));
// check hole
auto rdonly = req_.flags.accessType() == AccessType::READ;
if (rdonly && inode.asFile().hasHole() && checkHole) {
XLOGF(WARN, "Inode {} contains hole, don't allow O_RDONLY", inode.id);
co_return makeError(MetaCode::kFileHasHole);
}
// handle otrunc
bool otrunc = req_.flags.contains(O_TRUNC);
XLOGF(DBG, "inode {}, otrunc {}", inode, otrunc);
if (otrunc && entry.has_value()) {
BEGIN_WRITE();
auto replaced = co_await replaceExistsFile(rwTxn, *entry, inode);
CO_RETURN_ON_ERROR(replaced);
if (*replaced) {
co_return Rsp(std::move(inode), false);
}
}
// clear SUID SGID sticky bits on write by non owner
constexpr uint32_t sbits = S_ISUID | S_ISGID | S_ISVTX;
static_assert(sbits == 07000);
if (!rdonly && req_.user.uid != inode.acl.uid && (inode.acl.perm & sbits)) {
inode.acl.perm = Permission(inode.acl.perm & (~sbits));
dirty = true;
}
if (req_.session.has_value() && req_.flags.accessType() != AccessType::READ) {
BEGIN_WRITE();
CO_RETURN_ON_ERROR(co_await createSession(rwTxn, inode, req_.flags));
if (!req_.dynStripe && inode.asFile().dynStripe && inode.asFile().dynStripe < inode.asFile().layout.stripeSize) {
inode.asFile().dynStripe = 0;
dirty = true;
}
}
if (dirty) {
BEGIN_WRITE();
CO_RETURN_ON_ERROR(co_await inode.addIntoReadConflict(rwTxn));
CO_RETURN_ON_ERROR(co_await inode.store(rwTxn));
}
XLOGF(DBG, "inode {}, otrunc {}", inode, otrunc);
co_return Rsp(std::move(inode), otrunc);
}