blob: 2b577bf4afb2b96017e59b849c45c7afa2aab307 [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
Zimbb7c3762020-09-23 13:50:08 +010022#include <atomic>
Nikita Ioffe890e6f22020-06-18 17:35:08 +010023#include <cstdint>
24#include <limits>
Narayan Kamathaef84a12020-01-02 15:20:13 +000025#include <list>
26#include <memory>
27#include <mutex>
Nikita Ioffe890e6f22020-06-18 17:35:08 +010028#include <set>
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +000029#include <sstream>
Narayan Kamathaef84a12020-01-02 15:20:13 +000030#include <string>
Narayan Kamath568f17a2020-02-19 13:45:29 +000031#include <unordered_set>
Nikita Ioffe890e6f22020-06-18 17:35:08 +010032#include <utility>
Narayan Kamathaef84a12020-01-02 15:20:13 +000033#include <vector>
34
35#include "libfuse_jni/ReaddirHelper.h"
36#include "libfuse_jni/RedactionInfo.h"
37
38class NodeTest;
39
40namespace mediaprovider {
41namespace fuse {
42
43struct handle {
Zim148cbe22020-11-17 15:58:29 +000044 explicit handle(int fd, const RedactionInfo* ri, bool cached, bool passthrough, uid_t uid)
45 : fd(fd), ri(ri), cached(cached), passthrough(passthrough), uid(uid) {
Narayan Kamathbd22bb02020-01-08 16:02:50 +000046 CHECK(ri != nullptr);
47 }
48
Narayan Kamathbd22bb02020-01-08 16:02:50 +000049 const int fd;
50 const std::unique_ptr<const RedactionInfo> ri;
51 const bool cached;
Zim148cbe22020-11-17 15:58:29 +000052 const bool passthrough;
Zim9aa6f542020-10-19 15:39:33 +010053 const uid_t uid;
Narayan Kamathaef84a12020-01-02 15:20:13 +000054
55 ~handle() { close(fd); }
56};
57
58struct dirhandle {
Narayan Kamathbd22bb02020-01-08 16:02:50 +000059 explicit dirhandle(DIR* dir) : d(dir), next_off(0) { CHECK(dir != nullptr); }
Narayan Kamathaef84a12020-01-02 15:20:13 +000060
61 DIR* const d;
62 off_t next_off;
63 // Fuse readdir() is called multiple times based on the size of the buffer and
64 // number of directory entries in the given directory. 'de' holds the list
65 // of directory entries for the directory handle and this list is available
66 // across subsequent readdir() calls for the same directory handle.
67 std::vector<std::shared_ptr<DirectoryEntry>> de;
68
69 ~dirhandle() { closedir(d); }
70};
71
Narayan Kamath568f17a2020-02-19 13:45:29 +000072// Whether inode tracking is enabled or not. When enabled, we maintain a
73// separate mapping from inode numbers to "live" nodes so we can detect when
74// we receive a request to a node that has been deleted.
75static constexpr bool kEnableInodeTracking = true;
76
77class node;
78
79// Tracks the set of active nodes associated with a FUSE instance so that we
80// can assert that we only ever return an active node in response to a lookup.
81class NodeTracker {
82 public:
Nandana Duttaa76d1e2020-04-29 09:42:42 +010083 explicit NodeTracker(std::recursive_mutex* lock) : lock_(lock) {}
Narayan Kamath568f17a2020-02-19 13:45:29 +000084
85 void CheckTracked(__u64 ino) const {
86 if (kEnableInodeTracking) {
87 const node* node = reinterpret_cast<const class node*>(ino);
88 std::lock_guard<std::recursive_mutex> guard(*lock_);
89 CHECK(active_nodes_.find(node) != active_nodes_.end());
90 }
91 }
92
93 void NodeDeleted(const node* node) {
94 if (kEnableInodeTracking) {
95 std::lock_guard<std::recursive_mutex> guard(*lock_);
96 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " deleted.";
97
98 CHECK(active_nodes_.find(node) != active_nodes_.end());
99 active_nodes_.erase(node);
100 }
101 }
102
103 void NodeCreated(const node* node) {
104 if (kEnableInodeTracking) {
105 std::lock_guard<std::recursive_mutex> guard(*lock_);
106 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " created.";
107
108 CHECK(active_nodes_.find(node) == active_nodes_.end());
109 active_nodes_.insert(node);
110 }
111 }
112
113 private:
114 std::recursive_mutex* lock_;
115 std::unordered_set<const node*> active_nodes_;
116};
117
Narayan Kamathaef84a12020-01-02 15:20:13 +0000118class node {
119 public:
120 // Creates a new node with the specified parent, name and lock.
Zimbb7c3762020-09-23 13:50:08 +0100121 static node* Create(node* parent, const std::string& name, const std::string& io_path,
Zimded1ab92021-01-15 10:36:17 +0000122 bool should_invalidate, bool transforms_complete, const int transforms,
123 std::recursive_mutex* lock, NodeTracker* tracker) {
Narayan Kamath568f17a2020-02-19 13:45:29 +0000124 // Place the entire constructor under a critical section to make sure
125 // node creation, tracking (if enabled) and the addition to a parent are
126 // atomic.
127 std::lock_guard<std::recursive_mutex> guard(*lock);
Zimded1ab92021-01-15 10:36:17 +0000128 return new node(parent, name, io_path, should_invalidate, transforms_complete, transforms,
129 lock, tracker);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000130 }
131
132 // Creates a new root node. Root nodes have no parents by definition
133 // and their "name" must signify an absolute path.
Narayan Kamath568f17a2020-02-19 13:45:29 +0000134 static node* CreateRoot(const std::string& path, std::recursive_mutex* lock,
135 NodeTracker* tracker) {
136 std::lock_guard<std::recursive_mutex> guard(*lock);
Zimded1ab92021-01-15 10:36:17 +0000137 node* root = new node(nullptr, path, path, false /* should_invalidate */,
138 true /* transforms_complete */, 0, lock, tracker);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000139
140 // The root always has one extra reference to avoid it being
141 // accidentally collected.
142 root->Acquire();
143 return root;
144 }
145
146 // Maps an inode to its associated node.
Narayan Kamath568f17a2020-02-19 13:45:29 +0000147 static inline node* FromInode(__u64 ino, const NodeTracker* tracker) {
148 tracker->CheckTracked(ino);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000149 return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
150 }
151
152 // Maps a node to its associated inode.
153 static __u64 ToInode(node* node) {
154 return static_cast<__u64>(reinterpret_cast<uintptr_t>(node));
155 }
156
Narayan Kamathaef84a12020-01-02 15:20:13 +0000157 // Releases a reference to a node. Returns true iff the refcount dropped to
158 // zero as a result of this call to Release, meaning that it's no longer
159 // safe to perform any operations on references to this node.
160 bool Release(uint32_t count) {
161 std::lock_guard<std::recursive_mutex> guard(*lock_);
162 if (refcount_ >= count) {
163 refcount_ -= count;
164 if (refcount_ == 0) {
165 delete this;
166 return true;
167 }
168 } else {
169 LOG(ERROR) << "Mismatched reference count: refcount_ = " << this->refcount_
170 << " ,count = " << count;
171 }
172
173 return false;
174 }
175
176 // Builds the full path associated with this node, including all path segments
177 // associated with its descendants.
178 std::string BuildPath() const;
179
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +0000180 // Builds the full PII safe path associated with this node, including all path segments
181 // associated with its descendants.
182 std::string BuildSafePath() const;
183
Zimd2b59b42021-01-12 17:06:10 +0000184 // Looks up a direct descendant of this node by case-insensitive |name|. If |acquire| is true,
Narayan Kamatheca34252020-02-11 13:08:37 +0000185 // also Acquire the node before returning a reference to it.
Zimd2b59b42021-01-12 17:06:10 +0000186 // |transforms| is an opaque flag that is used to distinguish multiple nodes sharing the same
187 // |name| but requiring different IO transformations as determined by the MediaProvider.
Zimbb7c3762020-09-23 13:50:08 +0100188 node* LookupChildByName(const std::string& name, bool acquire, const int transforms = 0) const {
189 return ForChild(name, [acquire, transforms](node* child) {
190 if (child->transforms_ == transforms) {
191 if (acquire) {
192 child->Acquire();
193 }
194 return true;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000195 }
Zimbb7c3762020-09-23 13:50:08 +0100196 return false;
Zim53c2d702020-09-23 12:18:27 +0100197 });
Narayan Kamathaef84a12020-01-02 15:20:13 +0000198 }
199
Zim53c2d702020-09-23 12:18:27 +0100200 // Marks this node children as deleted. They are still associated with their parent, and
201 // all open handles etc. to the deleted nodes are preserved until their refcount goes
Narayan Kamathaef84a12020-01-02 15:20:13 +0000202 // to zero.
Zim53c2d702020-09-23 12:18:27 +0100203 void SetDeletedForChild(const std::string& name) {
204 ForChild(name, [](node* child) {
205 child->SetDeleted();
206 return false;
207 });
208 }
209
Narayan Kamathaef84a12020-01-02 15:20:13 +0000210 void SetDeleted() {
211 std::lock_guard<std::recursive_mutex> guard(*lock_);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000212 deleted_ = true;
213 }
214
Zim53c2d702020-09-23 12:18:27 +0100215 void RenameChild(const std::string& old_name, const std::string& new_name, node* new_parent) {
216 ForChild(old_name, [=](node* child) {
217 child->Rename(new_name, new_parent);
218 return false;
219 });
220 }
221
Narayan Kamathaef84a12020-01-02 15:20:13 +0000222 void Rename(const std::string& name, node* new_parent) {
Narayan Kamathaef84a12020-01-02 15:20:13 +0000223 std::lock_guard<std::recursive_mutex> guard(*lock_);
224
Zim87c7bf82020-01-07 18:11:27 +0000225 if (new_parent != parent_) {
226 RemoveFromParent();
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100227 name_ = name;
Zim87c7bf82020-01-07 18:11:27 +0000228 AddToParent(new_parent);
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100229 return;
230 }
231
232 // Changing name_ will change the expected position of this node in parent's set of
233 // children. Consider following scenario:
234 // 1. This node: "b"; parent's set: {"a", "b", "c"}
235 // 2. Rename("b", "d")
236 //
237 // After rename, parent's set should become: {"a", "b", "d"}, but if we simply change the
238 // name it will be {"a", "d", "b"}, which violates properties of the set.
239 //
240 // To make sure that parent's set is always valid, changing name is 3 steps procedure:
241 // 1. Remove this node from parent's set.
242 // 2 Change the name.
243 // 3. Add it back to the set.
244 // Rename of node without changing its parent. Still need to remove and re-add it to make
245 // sure lookup index is correct.
246 if (name_ != name) {
247 // If this is a root node, simply rename it.
248 if (parent_ == nullptr) {
249 name_ = name;
250 return;
251 }
252
253 auto it = parent_->children_.find(this);
254 CHECK(it != parent_->children_.end());
255 parent_->children_.erase(it);
256
257 name_ = name;
258
259 parent_->children_.insert(this);
Zim87c7bf82020-01-07 18:11:27 +0000260 }
Narayan Kamathaef84a12020-01-02 15:20:13 +0000261 }
262
263 const std::string& GetName() const {
264 std::lock_guard<std::recursive_mutex> guard(*lock_);
265 return name_;
266 }
267
Zimbb7c3762020-09-23 13:50:08 +0100268 const std::string& GetIoPath() const { return io_path_; }
269
270 int GetTransforms() const { return transforms_; }
271
272 bool IsTransformsComplete() const {
273 return transforms_complete_.load(std::memory_order_acquire);
274 }
275
276 void SetTransformsComplete() { transforms_complete_.store(true, std::memory_order_release); }
277
Zima76c3492020-02-19 01:23:26 +0000278 node* GetParent() const {
279 std::lock_guard<std::recursive_mutex> guard(*lock_);
280 return parent_;
281 }
282
Narayan Kamathaef84a12020-01-02 15:20:13 +0000283 inline void AddHandle(handle* h) {
284 std::lock_guard<std::recursive_mutex> guard(*lock_);
285 handles_.emplace_back(std::unique_ptr<handle>(h));
286 }
287
288 void DestroyHandle(handle* h) {
289 std::lock_guard<std::recursive_mutex> guard(*lock_);
290
291 auto comp = [h](const std::unique_ptr<handle>& ptr) { return ptr.get() == h; };
292 auto it = std::find_if(handles_.begin(), handles_.end(), comp);
293 CHECK(it != handles_.end());
294 handles_.erase(it);
295 }
296
297 bool HasCachedHandle() const {
298 std::lock_guard<std::recursive_mutex> guard(*lock_);
299
300 for (const auto& handle : handles_) {
301 if (handle->cached) {
302 return true;
303 }
304 }
305 return false;
306 }
307
Zimded1ab92021-01-15 10:36:17 +0000308 bool ShouldInvalidate() const {
Zimf2b47b42020-09-16 14:54:06 +0100309 std::lock_guard<std::recursive_mutex> guard(*lock_);
Zimded1ab92021-01-15 10:36:17 +0000310 return should_invalidate_;
Zimf2b47b42020-09-16 14:54:06 +0100311 }
312
Zimded1ab92021-01-15 10:36:17 +0000313 void SetShouldInvalidate() {
Zimf2b47b42020-09-16 14:54:06 +0100314 std::lock_guard<std::recursive_mutex> guard(*lock_);
Zimded1ab92021-01-15 10:36:17 +0000315 should_invalidate_ = true;
Zimf2b47b42020-09-16 14:54:06 +0100316 }
317
Zim329ba2c2020-09-16 14:23:26 +0100318 bool HasRedactedCache() const {
319 std::lock_guard<std::recursive_mutex> guard(*lock_);
320 return has_redacted_cache_;
321 }
322
323 void SetRedactedCache(bool state) {
324 std::lock_guard<std::recursive_mutex> guard(*lock_);
325 has_redacted_cache_ = state;
326 }
327
Narayan Kamathaef84a12020-01-02 15:20:13 +0000328 inline void AddDirHandle(dirhandle* d) {
329 std::lock_guard<std::recursive_mutex> guard(*lock_);
330
331 dirhandles_.emplace_back(std::unique_ptr<dirhandle>(d));
332 }
333
334 void DestroyDirHandle(dirhandle* d) {
335 std::lock_guard<std::recursive_mutex> guard(*lock_);
336
337 auto comp = [d](const std::unique_ptr<dirhandle>& ptr) { return ptr.get() == d; };
338 auto it = std::find_if(dirhandles_.begin(), dirhandles_.end(), comp);
339 CHECK(it != dirhandles_.end());
340 dirhandles_.erase(it);
341 }
342
343 // Deletes the tree of nodes rooted at |tree|.
344 static void DeleteTree(node* tree);
345
346 // Looks up an absolute path rooted at |root|, or nullptr if no such path
347 // through the hierarchy exists.
348 static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path);
349
350 private:
Zimded1ab92021-01-15 10:36:17 +0000351 node(node* parent, const std::string& name, const std::string& io_path,
352 const bool should_invalidate, const bool transforms_complete, const int transforms,
353 std::recursive_mutex* lock, NodeTracker* tracker)
Narayan Kamath568f17a2020-02-19 13:45:29 +0000354 : name_(name),
Zimbb7c3762020-09-23 13:50:08 +0100355 io_path_(io_path),
356 transforms_complete_(transforms_complete),
357 transforms_(transforms),
Narayan Kamath568f17a2020-02-19 13:45:29 +0000358 refcount_(0),
359 parent_(nullptr),
Zim329ba2c2020-09-16 14:23:26 +0100360 has_redacted_cache_(false),
Zimded1ab92021-01-15 10:36:17 +0000361 should_invalidate_(should_invalidate),
Narayan Kamath568f17a2020-02-19 13:45:29 +0000362 deleted_(false),
363 lock_(lock),
364 tracker_(tracker) {
365 tracker_->NodeCreated(this);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000366 Acquire();
367 // This is a special case for the root node. All other nodes will have a
368 // non-null parent.
369 if (parent != nullptr) {
370 AddToParent(parent);
371 }
Zimded1ab92021-01-15 10:36:17 +0000372 // If the node requires transforms, we MUST never cache it in the VFS
373 if (transforms) {
374 CHECK(should_invalidate_);
375 }
Narayan Kamathaef84a12020-01-02 15:20:13 +0000376 }
377
Narayan Kamatheca34252020-02-11 13:08:37 +0000378 // Acquires a reference to a node. This maps to the "lookup count" specified
379 // by the FUSE documentation and must only happen under the circumstances
380 // documented in libfuse/include/fuse_lowlevel.h.
381 inline void Acquire() {
382 std::lock_guard<std::recursive_mutex> guard(*lock_);
383 refcount_++;
384 }
385
Narayan Kamathaef84a12020-01-02 15:20:13 +0000386 // Adds this node to a specified parent.
387 void AddToParent(node* parent) {
388 std::lock_guard<std::recursive_mutex> guard(*lock_);
389 // This method assumes this node is currently unparented.
390 CHECK(parent_ == nullptr);
391 // Check that the new parent isn't nullptr either.
392 CHECK(parent != nullptr);
393
394 parent_ = parent;
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100395 parent_->children_.insert(this);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000396
397 // TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the
398 // parent node when we're adding a child to it.
399 parent_->Acquire();
400 }
401
402 // Removes this node from its current parent, and set its parent to nullptr.
403 void RemoveFromParent() {
404 std::lock_guard<std::recursive_mutex> guard(*lock_);
405
406 if (parent_ != nullptr) {
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100407 auto it = parent_->children_.find(this);
408 CHECK(it != parent_->children_.end());
409 parent_->children_.erase(it);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000410
Narayan Kamathaef84a12020-01-02 15:20:13 +0000411 parent_->Release(1);
412 parent_ = nullptr;
413 }
414 }
415
Zim53c2d702020-09-23 12:18:27 +0100416 // Finds *all* non-deleted nodes matching |name| and runs the function |callback| on each
417 // node until |callback| returns true.
418 // When |callback| returns true, the matched node is returned
419 node* ForChild(const std::string& name, const std::function<bool(node*)>& callback) const {
420 std::lock_guard<std::recursive_mutex> guard(*lock_);
421
422 // lower_bound will give us the first child with strcasecmp(child->name, name) >=0.
423 // For more context see comment on the NodeCompare struct.
424 auto start = children_.lower_bound(std::make_pair(name, 0));
425 // upper_bound will give us the first child with strcasecmp(child->name, name) > 0
426 auto end =
427 children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max()));
428
429 // Make a copy of the matches because calling callback might modify the list which will
430 // cause issues while iterating over them.
431 std::vector<node*> children(start, end);
432
433 for (node* child : children) {
434 if (!child->deleted_ && callback(child)) {
435 return child;
436 }
437 }
438
439 return nullptr;
440 }
441
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100442 // A custom heterogeneous comparator used for set of this node's children_ to speed up child
443 // node by name lookups.
444 //
445 // This comparator treats node* as pair (node->name_, node): two nodes* are first
446 // compared by their name using case-insenstive comparison function. If their names are equal,
447 // then pointers are compared as integers.
448 //
449 // See LookupChildByName function to see how this comparator is used.
450 //
451 // Note that it's important to first compare by name_, since it will make all nodes with same
452 // name (compared using strcasecmp) together, which allows LookupChildByName function to find
453 // range of the candidate nodes by issuing two binary searches.
454 struct NodeCompare {
455 using is_transparent = void;
456
457 bool operator()(const node* lhs, const node* rhs) const {
458 int cmp = strcasecmp(lhs->name_.c_str(), rhs->name_.c_str());
459 if (cmp != 0) {
460 return cmp < 0;
461 }
462 return reinterpret_cast<uintptr_t>(lhs) < reinterpret_cast<uintptr_t>(rhs);
463 }
464
465 bool operator()(const node* lhs, const std::pair<std::string, uintptr_t>& rhs) const {
466 int cmp = strcasecmp(lhs->name_.c_str(), rhs.first.c_str());
467 if (cmp != 0) {
468 return cmp < 0;
469 }
470 return reinterpret_cast<uintptr_t>(lhs) < rhs.second;
471 }
472
473 bool operator()(const std::pair<std::string, uintptr_t>& lhs, const node* rhs) const {
474 int cmp = strcasecmp(lhs.first.c_str(), rhs->name_.c_str());
475 if (cmp != 0) {
476 return cmp < 0;
477 }
478 return lhs.second < reinterpret_cast<uintptr_t>(rhs);
479 }
480 };
481
Zimuzo Ezeozue67db40c2020-02-21 19:41:33 +0000482 // A helper function to recursively construct the absolute path of a given node.
483 // If |safe| is true, builds a PII safe path instead
484 void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000485
486 // The name of this node. Non-const because it can change during renames.
487 std::string name_;
Zimbb7c3762020-09-23 13:50:08 +0100488 // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath
489 const std::string io_path_;
490 // Whether any transforms required on |io_path_| are complete.
491 // If false, might need to call a node transform function with |transforms| below
492 std::atomic_bool transforms_complete_;
493 // Opaque flags that determine the 'supported' and 'required' transforms to perform on node
494 // before IO. These flags should not be interpreted in native but should be passed as part
495 // of a transform function and if successful, |transforms_complete_| should be set to true
496 const int transforms_;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000497 // The reference count for this node. Guarded by |lock_|.
498 uint32_t refcount_;
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100499 // Set of children of this node. All of them contain a back reference
Narayan Kamathaef84a12020-01-02 15:20:13 +0000500 // to their parent. Guarded by |lock_|.
Nikita Ioffe890e6f22020-06-18 17:35:08 +0100501 std::set<node*, NodeCompare> children_;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000502 // Containing directory for this node. Guarded by |lock_|.
503 node* parent_;
504 // List of file handles associated with this node. Guarded by |lock_|.
505 std::vector<std::unique_ptr<handle>> handles_;
506 // List of directory handles associated with this node. Guarded by |lock_|.
507 std::vector<std::unique_ptr<dirhandle>> dirhandles_;
Zim329ba2c2020-09-16 14:23:26 +0100508 bool has_redacted_cache_;
Zimded1ab92021-01-15 10:36:17 +0000509 bool should_invalidate_;
Zim329ba2c2020-09-16 14:23:26 +0100510 bool deleted_;
Narayan Kamathaef84a12020-01-02 15:20:13 +0000511 std::recursive_mutex* lock_;
512
Narayan Kamath568f17a2020-02-19 13:45:29 +0000513 NodeTracker* const tracker_;
514
Narayan Kamathaef84a12020-01-02 15:20:13 +0000515 ~node() {
516 RemoveFromParent();
517
518 handles_.clear();
519 dirhandles_.clear();
Narayan Kamath568f17a2020-02-19 13:45:29 +0000520
521 tracker_->NodeDeleted(this);
Narayan Kamathaef84a12020-01-02 15:20:13 +0000522 }
523
524 friend class ::NodeTest;
525};
526
527} // namespace fuse
528} // namespace mediaprovider
529
530#endif // MEDIA_PROVIDER_JNI_MODE_INL_H_