master
cpp 122 lines 2.97 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #include "precomp.h"
3 #include "p9file.h"
4 #include "p9xattr.h"
5 #include "p9util.h"
6
7 namespace p9fs {
8
9 XAttr::XAttr(const std::shared_ptr<const Root>& root, const std::string& fileName, const std::string& name, Access access, UINT64 size, UINT32 flags) :
10 m_Root{root}, m_FileName{fileName}, m_Name{name}, m_Value{size}, m_Access{access}, m_Flags{flags}
11 {
12 }
13
14 Task<Expected<UINT32>> XAttr::Read(UINT64 offset, gsl::span<gsl::byte> buffer)
15 {
16 // In practice, the Linux Plan 9 client never uses a non-zero offset, so
17 // it's not implemented here (otherwise an intermediate buffer would be
18 // needed).
19 if ((m_Access != Access::Read) || (offset != 0))
20 {
21 co_return LxError{LX_EINVAL};
22 }
23
24 auto result = GetValue(buffer);
25 if (!result)
26 {
27 co_return result.Unexpected();
28 }
29
30 co_return static_cast<UINT32>(result.Get());
31 }
32
33 Task<Expected<UINT32>> XAttr::Write(UINT64 offset, gsl::span<const gsl::byte> buffer)
34 {
35 if (m_Access != Access::Write)
36 {
37 co_return LxError{LX_EINVAL};
38 }
39
40 if (offset > m_Value.size())
41 {
42 co_return 0;
43 }
44
45 std::lock_guard<std::shared_mutex> lock{m_Lock};
46 UINT32 length = gsl::narrow_cast<UINT32>(buffer.size());
47 if (length > m_Value.size() - offset)
48 {
49 length = m_Value.size() - offset;
50 }
51
52 if (length > 0)
53 {
54 gsl::copy(buffer.subspan(0, length), gsl::make_span(m_Value).subspan(offset));
55 }
56
57 co_return UINT32{length};
58 }
59
60 LX_INT XAttr::Clunk()
61 {
62 // Nothing to do is this fid is not for write.
63 if (m_Access != Access::Write)
64 {
65 return {};
66 }
67
68 // Make sure in-flight write operations are finished.
69 std::shared_lock<std::shared_mutex> lock{m_Lock};
70
71 // Remove the xattr if its size is 0; otherwise, set the value.
72 // N.B. Plan 9 does not support xattrs with zero-length values.
73 if (m_Value.size() == 0)
74 {
75 const int result = lremovexattr(m_FileName.c_str(), m_Name.c_str());
76 if (result < 0)
77 {
78 return -errno;
79 }
80 }
81 else
82 {
83 int result = lsetxattr(m_FileName.c_str(), m_Name.c_str(), m_Value.data(), m_Value.size(), m_Flags);
84 if (result < 0)
85 {
86 return -errno;
87 }
88 }
89
90 return {};
91 }
92
93 Expected<UINT64> XAttr::GetSize()
94 {
95 return GetValue({});
96 }
97
98 Expected<UINT64> XAttr::GetValue(gsl::span<gsl::byte> buffer)
99 {
100 util::FsUserContext userContext{m_Root->Uid, m_Root->Gid, m_Root->Groups};
101 ssize_t result;
102 if (m_Name.size() > 0)
103 {
104 result = lgetxattr(m_FileName.c_str(), m_Name.c_str(), buffer.data(), buffer.size());
105 if (result < 0)
106 {
107 return LxError{-errno};
108 }
109 }
110 else
111 {
112 result = llistxattr(m_FileName.c_str(), reinterpret_cast<char*>(buffer.data()), buffer.size());
113 if (result < 0)
114 {
115 return LxError{-errno};
116 }
117 }
118
119 return static_cast<UINT64>(result);
120 }
121
122 } // namespace p9fs