// Copyright (C) Microsoft Corporation. All rights reserved. #pragma once #include "p9io.h" #include "p9fid.h" #include "p9readdir.h" #include #include namespace p9fs { struct Share { wil::unique_fd RootFd; }; struct Root final : public IRoot { Root(std::shared_ptr share, int rootFd, uid_t uid, gid_t gid) : Share{share}, RootFd{rootFd}, Uid{uid}, Gid{gid} { Plan9TraceLoggingProvider::LogMessage(std::format("Instantiate root, uid={}", uid)); if (uid == -1) { return; // No uid passed, don't try to get the additional groups. } auto bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) { bufsize = 16384; // Recommended by the man page if _SC_GETPW_R_SIZE_MAX is not set. } std::vector buffer(bufsize); passwd pwd{}; passwd* result = nullptr; if (getpwuid_r(uid, &pwd, buffer.data(), buffer.size(), &result) < 0 || result == nullptr) { Plan9TraceLoggingProvider::LogMessage(std::format("getpwuid_r failed for uid: {}, errno={}", uid, errno)); return; } // Find the number of groups int groupCount = 0; getgrouplist(pwd.pw_name, gid, nullptr, &groupCount); Groups.resize(groupCount); // Query the groups if (getgrouplist(pwd.pw_name, gid, Groups.data(), &groupCount) < 0) { Plan9TraceLoggingProvider::LogMessage(std::format("getgrouplist failed for user: {}, errno={}", pwd.pw_name, errno)); Groups.clear(); } } std::shared_ptr Share; int RootFd; // The uid that the client attached with, and the associated primary gid. // If these are -1, then no change is necessary. uid_t Uid; gid_t Gid; std::vector Groups; bool ReadOnly() const { return false; } }; class File final : public Fid { public: File(std::shared_ptr root); File(const File&); Expected Initialize(); Expected Walk(std::string_view Name) override; Expected> GetAttr(UINT64 Mask) override; LX_INT SetAttr(UINT32 Valid, const StatResult& Stat) override; Expected Open(OpenFlags Flags) override; Expected Create(std::string_view Name, OpenFlags /* Flags */, UINT32 /* Mode */, UINT32 /* Gid */) override; Expected MkDir(std::string_view Name, UINT32 /* Mode */, UINT32 /* Gid */) override; LX_INT ReadDir(UINT64 Offset, SpanWriter& writer, bool includeAttributes) override; Task> Read(UINT64 Offset, gsl::span Buffer) override; Task> Write(UINT64 Offset, gsl::span Buffer) override; LX_INT UnlinkAt(std::string_view Name, UINT32 /* Flags */) override; LX_INT Remove() override; LX_INT RenameAt(std::string_view OldName, Fid& NewParent, std::string_view NewName) override; LX_INT Rename(Fid& NewParent, std::string_view NewName) override; Expected SymLink(std::string_view /* name */, std::string_view /* target */, UINT32 /* gid */) override; Expected MkNod(std::string_view /* name */, UINT32 /* mode */, UINT32 /* major */, UINT32 /* minor */, UINT32 /* gid */) override; LX_INT Link(std::string_view /* name */, Fid& /* target */) override; Expected ReadLink(gsl::span /* name */) override; LX_INT Fsync() override; Expected StatFs() override; Expected Lock(LockType Type, UINT32 Flags, UINT64 Start, UINT64 Length, UINT32 ProcId, std::string_view ClientId) override; Expected> GetLock( LockType Type, UINT64 Start, UINT64 Length, UINT32 ProcId, std::string_view ClientId) override; Expected> XattrWalk(const std::string& Name) override; Expected> XattrCreate(const std::string& Name, UINT64 Size, UINT32 Flags) override; // 9P2000.W operations LX_INT Access(AccessFlags Flags) override; std::shared_ptr Clone() const override; bool IsOnRoot(const std::shared_ptr& root) override; bool IsFile() const override; Qid GetQid() const override; bool IsOpen() const; private: Expected OpenFile(int openFlags); LX_INT ValidateExists(); std::string GetFileName() const; std::string ChildPath(std::string_view name); std::string ChildPathWithLockHeld(std::string_view name); Expected Stat(); LX_INT ReadDirHelper(UINT64 offset, SpanWriter& writer, bool extendedAttributes); // This lock protects all state except: // - Read access to m_File: once non-NULL, this member never becomes NULL // again. // - m_Root, m_Uid: these members don't change after initialization. mutable std::shared_mutex m_Lock; std::string m_FileName; std::unique_ptr m_Enumerator; wil::unique_fd m_File; CoroutineIoIssuer m_Io; const std::shared_ptr m_Root; Qid m_Qid{}; dev_t m_Device{}; }; } // namespace p9fs