CoTryTask BatchedOp::openExists()

in src/meta/store/ops/BatchOperation.cc [557:605]


CoTryTask<bool> BatchedOp::openExists(IReadWriteTransaction &txn, Inode &inode, const CreateReq &req) {
  CO_RETURN_ON_ERROR(req.valid());
  if (inode.isSymlink()) {
    // todo: rarely happens, how to handle this gracefully?
    auto msg = fmt::format("req {}, found symlink {}", req, inode);
    XLOG(WARN, msg);
    co_return makeError(MetaCode::kBusy, std::move(msg));
  }
  if (!inode.isFile()) {
    assert(inode.isDirectory());
    co_return makeError(MetaCode::kIsDirectory);
  }
  if (req.flags.contains(O_EXCL)) {
    co_return makeError(MetaCode::kExists);
  }

  // check permission
  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() && config().check_file_hole()) {
    XLOGF(WARN, "Inode {} contains hole, don't allow O_RDONLY", inode.id);
    co_return makeError(MetaCode::kFileHasHole);
  }

  auto dirty = 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)) {
    dirty |= SetAttr::update(inode.acl.perm, Permission(inode.acl.perm & (~sbits)));
  }
  // update dynamic stripe
  if (req.session.has_value() && req.flags.accessType() != AccessType::READ) {
    CO_RETURN_ON_ERROR(inode.acl.checkPermission(req.user, req.flags.accessType()));
    if (!req.dynStripe && inode.asFile().dynStripe && inode.asFile().dynStripe < inode.asFile().layout.stripeSize) {
      dirty |= SetAttr::update(inode.asFile().dynStripe, 0u);
    }
  }
  // create session
  if (req.session && req.flags.accessType() != AccessType::READ) {
    openWrite.addSample(1);
    CO_RETURN_ON_ERROR(co_await FileSession::create(inode.id, req.session.value()).store(txn));
  }
  co_return dirty;
}