blob: 5098316c42f6fe1ee05ca420ecb3e47a90460842 [file] [log] [blame]
Narayan Kamathaef84a12020-01-02 15:20:13 +00001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specic language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef MEDIA_PROVIDER_JNI_NODE_INL_H_
18#define MEDIA_PROVIDER_JNI_NODE_INL_H_
19
20#include <android-base/logging.h>
21
22#include <list>
23#include <memory>
24#include <mutex>
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +000025#include <sstream>
Narayan Kamathaef84a12020-01-02 15:20:13 +000026#include <string>
Narayan Kamath568f17a2020-02-19 13:45:29 +000027#include <unordered_set>
Narayan Kamathaef84a12020-01-02 15:20:13 +000028#include <vector>
29
30#include "libfuse_jni/ReaddirHelper.h"
31#include "libfuse_jni/RedactionInfo.h"
32
33class NodeTest;
34
35namespace mediaprovider {
36namespace fuse {
37
38struct handle {
Sahana Raoc0211d12020-02-17 10:11:56 +000039 explicit handle(const std::string& path, int fd, const RedactionInfo* ri, uid_t owner_uid,
40 bool cached)
41 : path(path), fd(fd), ri(ri), owner_uid(owner_uid), cached(cached) {
Narayan Kamathbd22bb02020-01-08 16:02:50 +000042 CHECK(ri != nullptr);
43 }
44
Narayan Kamathaef84a12020-01-02 15:20:13 +000045 const std::string path;
Narayan Kamathbd22bb02020-01-08 16:02:50 +000046 const int fd;
47 const std::unique_ptr<const RedactionInfo> ri;
Sahana Raoc0211d12020-02-17 10:11:56 +000048 const uid_t owner_uid;
Narayan Kamathbd22bb02020-01-08 16:02:50 +000049 const bool cached;
Narayan Kamathaef84a12020-01-02 15:20:13 +000050
51 ~handle() { close(fd); }
52};
53
54struct dirhandle {
Narayan Kamathbd22bb02020-01-08 16:02:50 +000055 explicit dirhandle(DIR* dir) : d(dir), next_off(0) { CHECK(dir != nullptr); }
Narayan Kamathaef84a12020-01-02 15:20:13 +000056
57 DIR* const d;
58 off_t next_off;
59 // Fuse readdir() is called multiple times based on the size of the buffer and
60 // number of directory entries in the given directory. 'de' holds the list
61 // of directory entries for the directory handle and this list is available
62 // across subsequent readdir() calls for the same directory handle.
63 std::vector<std::shared_ptr<DirectoryEntry>> de;
64
65 ~dirhandle() { closedir(d); }
66};
67
Narayan Kamath568f17a2020-02-19 13:45:29 +000068// Whether inode tracking is enabled or not. When enabled, we maintain a
69// separate mapping from inode numbers to "live" nodes so we can detect when
70// we receive a request to a node that has been deleted.
71static constexpr bool kEnableInodeTracking = true;
72
73class node;
74
75// Tracks the set of active nodes associated with a FUSE instance so that we
76// can assert that we only ever return an active node in response to a lookup.
77class NodeTracker {
78 public:
79 NodeTracker(std::recursive_mutex* lock) : lock_(lock) {}
80
81 void CheckTracked(__u64 ino) const {
82 if (kEnableInodeTracking) {
83 const node* node = reinterpret_cast<const class node*>(ino);
84 std::lock_guard<std::recursive_mutex> guard(*lock_);
85 CHECK(active_nodes_.find(node) != active_nodes_.end());
86 }
87 }
88
89 void NodeDeleted(const node* node) {
90 if (kEnableInodeTracking) {
91 std::lock_guard<std::recursive_mutex> guard(*lock_);
92 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " deleted.";
93
94 CHECK(active_nodes_.find(node) != active_nodes_.end());
95 active_nodes_.erase(node);
96 }
97 }
98
99 void NodeCreated(const node* node) {
100 if (kEnableInodeTracking) {
101 std::lock_guard<std::recursive_mutex> guard(*lock_);
102 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " created.";
103
104 CHECK(active_nodes_.find(node) == active_nodes_.end());
105 active_nodes_.insert(node);
106 }
107 }
108
109 private:
110 std::recursive_mutex* lock_;
111 std::unordered_set<const node*> active_nodes_;
112};
113
Narayan Kamathaef84a12020-01-02 15:20:13 +0000114class node {
115 public:
116 // Creates a new node with the specified parent, name and lock.
Narayan Kamath568f17a2020-02-19 13:45:29 +0000117 static node* Create(node* parent, const std::string& name, std::recursive_mutex* lock,
118 NodeTracker* tracker) {
119 // Place the entire constructor under a critical section to make sure
120 // node creation, tracking (if enabled) and the addition to a parent are
121 // atomic.
122 std::lock_guard<std::recursive_mutex> guard(*lock);
123 return new node(parent, name, lock, tracker);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000124 }
125
126 // Creates a new root node. Root nodes have no parents by definition
127 // and their "name" must signify an absolute path.
Narayan Kamath568f17a2020-02-19 13:45:29 +0000128 static node* CreateRoot(const std::string& path, std::recursive_mutex* lock,
129 NodeTracker* tracker) {
130 std::lock_guard<std::recursive_mutex> guard(*lock);
131 node* root = new node(nullptr, path, lock, tracker);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000132
133 // The root always has one extra reference to avoid it being
134 // accidentally collected.
135 root->Acquire();
136 return root;
137 }
138
139 // Maps an inode to its associated node.
Narayan Kamath568f17a2020-02-19 13:45:29 +0000140 static inline node* FromInode(__u64 ino, const NodeTracker* tracker) {
141 tracker->CheckTracked(ino);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000142 return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
143 }
144
145 // Maps a node to its associated inode.
146 static __u64 ToInode(node* node) {
147 return static_cast<__u64>(reinterpret_cast<uintptr_t>(node));
148 }
149
Narayan Kamathaef84a12020-01-02 15:20:13 +0000150 // Releases a reference to a node. Returns true iff the refcount dropped to
151 // zero as a result of this call to Release, meaning that it's no longer
152 // safe to perform any operations on references to this node.
153 bool Release(uint32_t count) {
154 std::lock_guard<std::recursive_mutex> guard(*lock_);
155 if (refcount_ >= count) {
156 refcount_ -= count;
157 if (refcount_ == 0) {
158 delete this;
159 return true;
160 }
161 } else {
162 LOG(ERROR) << "Mismatched reference count: refcount_ = " << this->refcount_
163 << " ,count = " << count;
164 }
165
166 return false;
167 }
168
169 // Builds the full path associated with this node, including all path segments
170 // associated with its descendants.
171 std::string BuildPath() const;
172
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +0000173 // Builds the full PII safe path associated with this node, including all path segments
174 // associated with its descendants.
175 std::string BuildSafePath() const;
176
Narayan Kamatheca34252020-02-11 13:08:37 +0000177 // Looks up a direct descendant of this node by name. If |acquire| is true,
178 // also Acquire the node before returning a reference to it.
179 node* LookupChildByName(const std::string& name, bool acquire) const {
Narayan Kamathaef84a12020-01-02 15:20:13 +0000180 std::lock_guard<std::recursive_mutex> guard(*lock_);
181
182 for (node* child : children_) {
183 // Use exact string comparison, nodes that differ by case
184 // must be considered distinct even if they refer to the same
185 // underlying file as otherwise operations such as "mv x x"
186 // will not work because the source and target nodes are the same.
187
188 if ((name == child->name_) && !child->deleted_) {
Narayan Kamatheca34252020-02-11 13:08:37 +0000189 if (acquire) {
190 child->Acquire();
191 }
192
Narayan Kamathaef84a12020-01-02 15:20:13 +0000193 return child;
194 }
195 }
196 return nullptr;
197 }
198
199 // Marks this node as deleted. It is still associated with its parent, and
200 // all open handles etc. to this node are preserved until its refcount goes
201 // to zero.
202 void SetDeleted() {
203 std::lock_guard<std::recursive_mutex> guard(*lock_);
204
205 deleted_ = true;
206 }
207
208 void Rename(const std::string& name, node* new_parent) {
Narayan Kamathaef84a12020-01-02 15:20:13 +0000209 std::lock_guard<std::recursive_mutex> guard(*lock_);
210
211 name_ = name;
Zim87c7bf82020-01-07 18:11:27 +0000212 if (new_parent != parent_) {
213 RemoveFromParent();
214 AddToParent(new_parent);
215 }
Narayan Kamathaef84a12020-01-02 15:20:13 +0000216 }
217
218 const std::string& GetName() const {
219 std::lock_guard<std::recursive_mutex> guard(*lock_);
220 return name_;
221 }
222
Zima76c3492020-02-19 01:23:26 +0000223 node* GetParent() const {
224 std::lock_guard<std::recursive_mutex> guard(*lock_);
225 return parent_;
226 }
227
Narayan Kamathaef84a12020-01-02 15:20:13 +0000228 inline void AddHandle(handle* h) {
229 std::lock_guard<std::recursive_mutex> guard(*lock_);
230 handles_.emplace_back(std::unique_ptr<handle>(h));
231 }
232
233 void DestroyHandle(handle* h) {
234 std::lock_guard<std::recursive_mutex> guard(*lock_);
235
236 auto comp = [h](const std::unique_ptr<handle>& ptr) { return ptr.get() == h; };
237 auto it = std::find_if(handles_.begin(), handles_.end(), comp);
238 CHECK(it != handles_.end());
239 handles_.erase(it);
240 }
241
242 bool HasCachedHandle() const {
243 std::lock_guard<std::recursive_mutex> guard(*lock_);
244
245 for (const auto& handle : handles_) {
246 if (handle->cached) {
247 return true;
248 }
249 }
250 return false;
251 }
252
253 inline void AddDirHandle(dirhandle* d) {
254 std::lock_guard<std::recursive_mutex> guard(*lock_);
255
256 dirhandles_.emplace_back(std::unique_ptr<dirhandle>(d));
257 }
258
259 void DestroyDirHandle(dirhandle* d) {
260 std::lock_guard<std::recursive_mutex> guard(*lock_);
261
262 auto comp = [d](const std::unique_ptr<dirhandle>& ptr) { return ptr.get() == d; };
263 auto it = std::find_if(dirhandles_.begin(), dirhandles_.end(), comp);
264 CHECK(it != dirhandles_.end());
265 dirhandles_.erase(it);
266 }
267
268 // Deletes the tree of nodes rooted at |tree|.
269 static void DeleteTree(node* tree);
270
271 // Looks up an absolute path rooted at |root|, or nullptr if no such path
272 // through the hierarchy exists.
273 static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path);
274
275 private:
Narayan Kamath568f17a2020-02-19 13:45:29 +0000276 node(node* parent, const std::string& name, std::recursive_mutex* lock, NodeTracker* tracker)
277 : name_(name),
278 refcount_(0),
279 parent_(nullptr),
280 deleted_(false),
281 lock_(lock),
282 tracker_(tracker) {
283 tracker_->NodeCreated(this);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000284 Acquire();
285 // This is a special case for the root node. All other nodes will have a
286 // non-null parent.
287 if (parent != nullptr) {
288 AddToParent(parent);
289 }
290 }
291
Narayan Kamatheca34252020-02-11 13:08:37 +0000292 // Acquires a reference to a node. This maps to the "lookup count" specified
293 // by the FUSE documentation and must only happen under the circumstances
294 // documented in libfuse/include/fuse_lowlevel.h.
295 inline void Acquire() {
296 std::lock_guard<std::recursive_mutex> guard(*lock_);
297 refcount_++;
298 }
299
Narayan Kamathaef84a12020-01-02 15:20:13 +0000300 // Adds this node to a specified parent.
301 void AddToParent(node* parent) {
302 std::lock_guard<std::recursive_mutex> guard(*lock_);
303 // This method assumes this node is currently unparented.
304 CHECK(parent_ == nullptr);
305 // Check that the new parent isn't nullptr either.
306 CHECK(parent != nullptr);
307
308 parent_ = parent;
309 parent_->children_.push_back(this);
310
311 // TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the
312 // parent node when we're adding a child to it.
313 parent_->Acquire();
314 }
315
316 // Removes this node from its current parent, and set its parent to nullptr.
317 void RemoveFromParent() {
318 std::lock_guard<std::recursive_mutex> guard(*lock_);
319
320 if (parent_ != nullptr) {
321 std::list<node*>& children = parent_->children_;
322 std::list<node*>::iterator it = std::find(children.begin(), children.end(), this);
323
324 CHECK(it != children.end());
325 children.erase(it);
326 parent_->Release(1);
327 parent_ = nullptr;
328 }
329 }
330
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +0000331 // A helper function to recursively construct the absolute path of a given node.
332 // If |safe| is true, builds a PII safe path instead
333 void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000334
335 // The name of this node. Non-const because it can change during renames.
336 std::string name_;
337 // The reference count for this node. Guarded by |lock_|.
338 uint32_t refcount_;
339 // List of children of this node. All of them contain a back reference
340 // to their parent. Guarded by |lock_|.
341 std::list<node*> children_;
342 // Containing directory for this node. Guarded by |lock_|.
343 node* parent_;
344 // List of file handles associated with this node. Guarded by |lock_|.
345 std::vector<std::unique_ptr<handle>> handles_;
346 // List of directory handles associated with this node. Guarded by |lock_|.
347 std::vector<std::unique_ptr<dirhandle>> dirhandles_;
348 bool deleted_;
349 std::recursive_mutex* lock_;
350
Narayan Kamath568f17a2020-02-19 13:45:29 +0000351 NodeTracker* const tracker_;
352
Narayan Kamathaef84a12020-01-02 15:20:13 +0000353 ~node() {
354 RemoveFromParent();
355
356 handles_.clear();
357 dirhandles_.clear();
Narayan Kamath568f17a2020-02-19 13:45:29 +0000358
359 tracker_->NodeDeleted(this);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000360 }
361
362 friend class ::NodeTest;
363};
364
365} // namespace fuse
366} // namespace mediaprovider
367
368#endif // MEDIA_PROVIDER_JNI_MODE_INL_H_