| 1 | // Copyright (C) Microsoft Corporation. All rights reserved. |
| 2 | #pragma once |
| 3 | |
| 4 | #include "p9io.h" |
| 5 | #include "p9fid.h" |
| 6 | #include "p9readdir.h" |
| 7 | #include <pwd.h> |
| 8 | #include <grp.h> |
| 9 | |
| 10 | namespace p9fs { |
| 11 | |
| 12 | struct Share |
| 13 | { |
| 14 | wil::unique_fd RootFd; |
| 15 | }; |
| 16 | |
| 17 | struct Root final : public IRoot |
| 18 | { |
| 19 | Root(std::shared_ptr<const Share> share, int rootFd, uid_t uid, gid_t gid) : Share{share}, RootFd{rootFd}, Uid{uid}, Gid{gid} |
| 20 | { |
| 21 | Plan9TraceLoggingProvider::LogMessage(std::format("Instantiate root, uid={}", uid)); |
| 22 | if (uid == -1) |
| 23 | { |
| 24 | return; // No uid passed, don't try to get the additional groups. |
| 25 | } |
| 26 | |
| 27 | auto bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
| 28 | if (bufsize == -1) |
| 29 | { |
| 30 | bufsize = 16384; // Recommended by the man page if _SC_GETPW_R_SIZE_MAX is not set. |
| 31 | } |
| 32 | |
| 33 | std::vector<char> buffer(bufsize); |
| 34 | passwd pwd{}; |
| 35 | passwd* result = nullptr; |
| 36 | if (getpwuid_r(uid, &pwd, buffer.data(), buffer.size(), &result) != 0 || result == nullptr) |
| 37 | { |
| 38 | Plan9TraceLoggingProvider::LogMessage(std::format("getpwuid_r failed for uid: {}, errno={}", uid, errno)); |
| 39 | return; |
| 40 | } |
| 41 | |
| 42 | // Find the number of groups |
| 43 | int groupCount = 0; |
| 44 | getgrouplist(pwd.pw_name, gid, nullptr, &groupCount); |
| 45 | Groups.resize(groupCount); |
| 46 | |
| 47 | // Query the groups |
| 48 | if (getgrouplist(pwd.pw_name, gid, Groups.data(), &groupCount) < 0) |
| 49 | { |
| 50 | Plan9TraceLoggingProvider::LogMessage(std::format("getgrouplist failed for user: {}, errno={}", pwd.pw_name, errno)); |
| 51 | Groups.clear(); |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | std::shared_ptr<const Share> Share; |
| 56 | |
| 57 | int RootFd; |
| 58 | |
| 59 | // The uid that the client attached with, and the associated primary gid. |
| 60 | // If these are -1, then no change is necessary. |
| 61 | uid_t Uid; |
| 62 | gid_t Gid; |
| 63 | std::vector<gid_t> Groups; |
| 64 | |
| 65 | bool ReadOnly() const |
| 66 | { |
| 67 | return false; |
| 68 | } |
| 69 | }; |
| 70 | |
| 71 | class File final : public Fid |
| 72 | { |
| 73 | public: |
| 74 | File(std::shared_ptr<const Root> root); |
| 75 | File(const File&); |
| 76 | |
| 77 | Expected<Qid> Initialize(); |
| 78 | Expected<Qid> Walk(std::string_view Name) override; |
| 79 | Expected<std::tuple<UINT64, Qid, StatResult>> GetAttr(UINT64 Mask) override; |
| 80 | LX_INT SetAttr(UINT32 Valid, const StatResult& Stat) override; |
| 81 | Expected<Qid> Open(OpenFlags Flags) override; |
| 82 | Expected<Qid> Create(std::string_view Name, OpenFlags /* Flags */, UINT32 /* Mode */, UINT32 /* Gid */) override; |
| 83 | Expected<Qid> MkDir(std::string_view Name, UINT32 /* Mode */, UINT32 /* Gid */) override; |
| 84 | LX_INT ReadDir(UINT64 Offset, SpanWriter& writer, bool includeAttributes) override; |
| 85 | Task<Expected<UINT32>> Read(UINT64 Offset, gsl::span<gsl::byte> Buffer) override; |
| 86 | Task<Expected<UINT32>> Write(UINT64 Offset, gsl::span<const gsl::byte> Buffer) override; |
| 87 | LX_INT UnlinkAt(std::string_view Name, UINT32 /* Flags */) override; |
| 88 | LX_INT Remove() override; |
| 89 | LX_INT RenameAt(std::string_view OldName, Fid& NewParent, std::string_view NewName) override; |
| 90 | LX_INT Rename(Fid& NewParent, std::string_view NewName) override; |
| 91 | Expected<Qid> SymLink(std::string_view /* name */, std::string_view /* target */, UINT32 /* gid */) override; |
| 92 | Expected<Qid> MkNod(std::string_view /* name */, UINT32 /* mode */, UINT32 /* major */, UINT32 /* minor */, UINT32 /* gid */) override; |
| 93 | LX_INT Link(std::string_view /* name */, Fid& /* target */) override; |
| 94 | Expected<UINT32> ReadLink(gsl::span<char> /* name */) override; |
| 95 | LX_INT Fsync() override; |
| 96 | Expected<StatFsResult> StatFs() override; |
| 97 | Expected<LockStatus> Lock(LockType Type, UINT32 Flags, UINT64 Start, UINT64 Length, UINT32 ProcId, std::string_view ClientId) override; |
| 98 | Expected<std::tuple<LockType, UINT64, UINT64, UINT32, std::string_view>> GetLock( |
| 99 | LockType Type, UINT64 Start, UINT64 Length, UINT32 ProcId, std::string_view ClientId) override; |
| 100 | Expected<std::shared_ptr<XAttrBase>> XattrWalk(const std::string& Name) override; |
| 101 | Expected<std::shared_ptr<XAttrBase>> XattrCreate(const std::string& Name, UINT64 Size, UINT32 Flags) override; |
| 102 | |
| 103 | // 9P2000.W operations |
| 104 | LX_INT Access(AccessFlags Flags) override; |
| 105 | |
| 106 | std::shared_ptr<Fid> Clone() const override; |
| 107 | bool IsOnRoot(const std::shared_ptr<const IRoot>& root) override; |
| 108 | bool IsFile() const override; |
| 109 | Qid GetQid() const override; |
| 110 | bool IsOpen() const; |
| 111 | |
| 112 | private: |
| 113 | Expected<wil::unique_fd> OpenFile(int openFlags); |
| 114 | LX_INT ValidateExists(); |
| 115 | std::string GetFileName() const; |
| 116 | std::string ChildPath(std::string_view name); |
| 117 | std::string ChildPathWithLockHeld(std::string_view name); |
| 118 | Expected<struct stat> Stat(); |
| 119 | LX_INT ReadDirHelper(UINT64 offset, SpanWriter& writer, bool extendedAttributes); |
| 120 | |
| 121 | // This lock protects all state except: |
| 122 | // - Read access to m_File: once non-NULL, this member never becomes NULL |
| 123 | // again. |
| 124 | // - m_Root, m_Uid: these members don't change after initialization. |
| 125 | mutable std::shared_mutex m_Lock; |
| 126 | std::string m_FileName; |
| 127 | std::unique_ptr<DirectoryEnumerator> m_Enumerator; |
| 128 | wil::unique_fd m_File; |
| 129 | CoroutineIoIssuer m_Io; |
| 130 | const std::shared_ptr<const Root> m_Root; |
| 131 | Qid m_Qid{}; |
| 132 | dev_t m_Device{}; |
| 133 | }; |
| 134 | } // namespace p9fs |