CoTryTask openExistsFile()

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);
  }