master
h 224 lines 5.98 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #pragma once
3
4 namespace p9fs::util {
5
6 // Writes a StatResult to a SpanWriter using the format used by Rgetattr and Rwreaddir.
7 inline void SpanWriteStatResult(SpanWriter& writer, const StatResult& stat)
8 {
9 writer.U32(stat.Mode);
10 writer.U32(stat.Uid);
11 writer.U32(stat.Gid);
12 writer.U64(stat.NLink);
13 writer.U64(stat.RDev);
14 writer.U64(stat.Size);
15 writer.U64(stat.BlockSize);
16 writer.U64(stat.Blocks);
17 writer.U64(stat.AtimeSec);
18 writer.U64(stat.AtimeNsec);
19 writer.U64(stat.MtimeSec);
20 writer.U64(stat.MtimeNsec);
21 writer.U64(stat.CtimeSec);
22 writer.U64(stat.CtimeNsec);
23 }
24
25 // Writes a directory entry to a span writer, returning whether the entry fit.
26 inline bool SpanWriteDirectoryEntry(SpanWriter& writer, std::string_view name, const Qid& qid, UINT64 nextOffset, UCHAR type, const StatResult* stat = nullptr)
27 {
28 size_t dirEntrySize = QidSize + sizeof(UINT64) + sizeof(UCHAR) + sizeof(UINT16) + name.size();
29 if (stat != nullptr)
30 {
31 dirEntrySize += StatResultSize;
32 }
33
34 if (static_cast<size_t>(writer.Peek().size()) < dirEntrySize)
35 {
36 return false;
37 }
38
39 writer.Qid(qid);
40 writer.U64(nextOffset);
41 writer.U8(type); // type is bits 12-15 of the file mode
42 writer.String(name);
43 if (stat != nullptr)
44 {
45 SpanWriteStatResult(writer, *stat);
46 }
47
48 return true;
49 }
50
51 // Determines the QidType to use for a DT_* enumeration value.
52 inline QidType DirEntryTypeToQidType(int type)
53 {
54 switch (type)
55 {
56 case LX_DT_DIR:
57 return QidType::Directory;
58
59 case LX_DT_LNK:
60 return QidType::Symlink;
61
62 default:
63 return QidType::File;
64 }
65 }
66
67 // Converts a DT_* value to a S_IF* value.
68 // N.B. These constants uses the same values for the same file types, just shifted by 12 bits to
69 // make space for the permission bits.
70 inline LX_MODE_T DirEntryTypeToMode(int type)
71 {
72 return (type << 12);
73 }
74
75 // Container-like wrapper around LIST_ENTRY based linked lists.
76 // N.B. It's assumed the value type has an entry named Link of type LIST_ENTRY.
77 // N.B. This is by no means intended to meet the requirements of a true STL container, but provides
78 // enough functionality to at least use a for-each loop.
79 template <typename T>
80 class LinkedList
81 {
82 public:
83 using value_type = T;
84 using reference = T&;
85 using const_reference = const T&;
86 using difference_type = ptrdiff_t;
87 using size_type = size_t;
88
89 // Bidirectional forward iterator for the LinkedList class.
90 class iterator
91 {
92 public:
93 using iterator_category = std::bidirectional_iterator_tag;
94 using value_type = T;
95 using difference_type = ptrdiff_t;
96 using pointer = T*;
97 using reference = T&;
98
99 // Creates an iterator that refers to the specified list entry.
100 explicit iterator(PLIST_ENTRY entry) : m_entry{entry}
101 {
102 }
103
104 // Moves to the next element in the list.
105 iterator& operator++()
106 {
107 m_entry = m_entry->Flink;
108 return *this;
109 }
110
111 // Moves to the next element in the list.
112 iterator operator++(int)
113 {
114 auto result = *this;
115 m_entry = m_entry->Flink;
116 return result;
117 }
118
119 // Moves to the previous element in the list.
120 iterator& operator--()
121 {
122 m_entry = m_entry->Blink;
123 return *this;
124 }
125
126 // Moves to the previous element in the list.
127 iterator operator--(int)
128 {
129 auto result = *this;
130 m_entry = m_entry->Blink;
131 return result;
132 }
133
134 // Checks whether two iterators refer to the same entry.
135 bool operator==(const iterator& other) const
136 {
137 return m_entry == other.m_entry;
138 }
139
140 // Checks whether two iterators do not refer to the same entry.
141 bool operator!=(const iterator& other) const
142 {
143 return m_entry != other.m_entry;
144 }
145
146 // Returns the value referred to by the iterator.
147 reference operator*()
148 {
149 return *CONTAINING_RECORD(m_entry, T, Link);
150 }
151
152 private:
153 PLIST_ENTRY m_entry;
154 };
155
156 // Initializes a new LinkedList.
157 LinkedList()
158 {
159 InitializeListHead(&m_head);
160 }
161
162 // Destroys the LinkedList.
163 ~LinkedList()
164 {
165 // LinkedList doesn't own the items, so it can't clear the list on destruction. Instead,
166 // the list should already be cleared.
167 WI_ASSERT(IsListEmpty(&m_head));
168 }
169
170 // This class is not copyable or moveable.
171 // N.B. It could be made moveable, but that would require modifying the list to point to the
172 // new list head, and is not done here.
173 LinkedList(const LinkedList&) = delete;
174 LinkedList& operator=(const LinkedList&) = delete;
175 LinkedList(LinkedList&&) = delete;
176 LinkedList& operator=(LinkedList&&) = delete;
177
178 // Inserts a new item into the list.
179 void Insert(T& value)
180 {
181 InsertTailList(&m_head, std::addressof(value.Link));
182 }
183
184 // Removes an item from the list.
185 // N.B. This could be static, but isn't for ease of invocation and so debug builds can assert
186 // the entry belongs to this list.
187 void Remove(T& value)
188 {
189 WI_ASSERT(Contains(value));
190
191 RemoveEntryList(std::addressof(value.Link));
192 }
193
194 // Checks whether the list contains a specific entry.
195 bool Contains(const T& value)
196 {
197 for (auto entry = m_head.Flink; entry != &m_head; entry = entry->Flink)
198 {
199 if (entry == std::addressof(value.Link))
200 {
201 return true;
202 }
203 }
204
205 return false;
206 }
207
208 // Returns an iterator to the first element.
209 iterator begin()
210 {
211 return iterator{m_head.Flink};
212 }
213
214 // Returns an iterator beyond the last element.
215 iterator end()
216 {
217 return iterator{&m_head};
218 }
219
220 private:
221 LIST_ENTRY m_head;
222 };
223
224 } // namespace p9fs::util