1 /* 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 <sys/types.h> 23 #include <atomic> 24 #include <cstdint> 25 #include <limits> 26 #include <list> 27 #include <memory> 28 #include <mutex> 29 #include <set> 30 #include <sstream> 31 #include <string> 32 #include <unordered_set> 33 #include <utility> 34 #include <vector> 35 36 #include "libfuse_jni/ReaddirHelper.h" 37 #include "libfuse_jni/RedactionInfo.h" 38 39 class NodeTest; 40 41 namespace mediaprovider { 42 namespace fuse { 43 44 struct handle { handlehandle45 explicit handle(int fd, const RedactionInfo* ri, bool cached, bool passthrough, uid_t uid, 46 uid_t transforms_uid) 47 : fd(fd), 48 ri(ri), 49 cached(cached), 50 passthrough(passthrough), 51 uid(uid), 52 transforms_uid(transforms_uid) { 53 CHECK(ri != nullptr); 54 } 55 56 const int fd; 57 const std::unique_ptr<const RedactionInfo> ri; 58 const bool cached; 59 const bool passthrough; 60 const uid_t uid; 61 const uid_t transforms_uid; 62 ~handlehandle63 ~handle() { close(fd); } 64 }; 65 66 struct dirhandle { dirhandledirhandle67 explicit dirhandle(DIR* dir) : d(dir), next_off(0) { CHECK(dir != nullptr); } 68 69 DIR* const d; 70 off_t next_off; 71 // Fuse readdir() is called multiple times based on the size of the buffer and 72 // number of directory entries in the given directory. 'de' holds the list 73 // of directory entries for the directory handle and this list is available 74 // across subsequent readdir() calls for the same directory handle. 75 std::vector<std::shared_ptr<DirectoryEntry>> de; 76 ~dirhandledirhandle77 ~dirhandle() { closedir(d); } 78 }; 79 80 // Whether inode tracking is enabled or not. When enabled, we maintain a 81 // separate mapping from inode numbers to "live" nodes so we can detect when 82 // we receive a request to a node that has been deleted. 83 static constexpr bool kEnableInodeTracking = true; 84 85 class node; 86 87 // Tracks the set of active nodes associated with a FUSE instance so that we 88 // can assert that we only ever return an active node in response to a lookup. 89 class NodeTracker { 90 public: NodeTracker(std::recursive_mutex * lock)91 explicit NodeTracker(std::recursive_mutex* lock) : lock_(lock) {} 92 CheckTracked(__u64 ino)93 void CheckTracked(__u64 ino) const { 94 if (kEnableInodeTracking) { 95 const node* node = reinterpret_cast<const class node*>(ino); 96 std::lock_guard<std::recursive_mutex> guard(*lock_); 97 CHECK(active_nodes_.find(node) != active_nodes_.end()); 98 } 99 } 100 NodeDeleted(const node * node)101 void NodeDeleted(const node* node) { 102 if (kEnableInodeTracking) { 103 std::lock_guard<std::recursive_mutex> guard(*lock_); 104 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " deleted."; 105 106 CHECK(active_nodes_.find(node) != active_nodes_.end()); 107 active_nodes_.erase(node); 108 } 109 } 110 NodeCreated(const node * node)111 void NodeCreated(const node* node) { 112 if (kEnableInodeTracking) { 113 std::lock_guard<std::recursive_mutex> guard(*lock_); 114 LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " created."; 115 116 CHECK(active_nodes_.find(node) == active_nodes_.end()); 117 active_nodes_.insert(node); 118 } 119 } 120 121 private: 122 std::recursive_mutex* lock_; 123 std::unordered_set<const node*> active_nodes_; 124 }; 125 126 class node { 127 public: 128 // Creates a new node with the specified parent, name and lock. Create(node * parent,const std::string & name,const std::string & io_path,bool should_invalidate,bool transforms_complete,const int transforms,const int transforms_reason,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)129 static node* Create(node* parent, const std::string& name, const std::string& io_path, 130 bool should_invalidate, bool transforms_complete, const int transforms, 131 const int transforms_reason, std::recursive_mutex* lock, ino_t ino, 132 NodeTracker* tracker) { 133 // Place the entire constructor under a critical section to make sure 134 // node creation, tracking (if enabled) and the addition to a parent are 135 // atomic. 136 std::lock_guard<std::recursive_mutex> guard(*lock); 137 return new node(parent, name, io_path, should_invalidate, transforms_complete, transforms, 138 transforms_reason, lock, ino, tracker); 139 } 140 141 // Creates a new root node. Root nodes have no parents by definition 142 // and their "name" must signify an absolute path. CreateRoot(const std::string & path,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)143 static node* CreateRoot(const std::string& path, std::recursive_mutex* lock, ino_t ino, 144 NodeTracker* tracker) { 145 std::lock_guard<std::recursive_mutex> guard(*lock); 146 node* root = new node(nullptr, path, path, false /* should_invalidate */, 147 true /* transforms_complete */, 0 /* transforms */, 148 0 /* transforms_reason */, lock, ino, tracker); 149 150 // The root always has one extra reference to avoid it being 151 // accidentally collected. 152 root->Acquire(); 153 return root; 154 } 155 156 // Maps an inode to its associated node. FromInode(__u64 ino,const NodeTracker * tracker)157 static inline node* FromInode(__u64 ino, const NodeTracker* tracker) { 158 tracker->CheckTracked(ino); 159 return reinterpret_cast<node*>(static_cast<uintptr_t>(ino)); 160 } 161 162 // Maps a node to its associated inode. ToInode(node * node)163 static __u64 ToInode(node* node) { 164 return static_cast<__u64>(reinterpret_cast<uintptr_t>(node)); 165 } 166 167 // Releases a reference to a node. Returns true iff the refcount dropped to 168 // zero as a result of this call to Release, meaning that it's no longer 169 // safe to perform any operations on references to this node. Release(uint32_t count)170 bool Release(uint32_t count) { 171 std::lock_guard<std::recursive_mutex> guard(*lock_); 172 if (refcount_ >= count) { 173 refcount_ -= count; 174 if (refcount_ == 0) { 175 delete this; 176 return true; 177 } 178 } else { 179 LOG(ERROR) << "Mismatched reference count: refcount_ = " << this->refcount_ 180 << " ,count = " << count; 181 } 182 183 return false; 184 } 185 186 // Builds the full path associated with this node, including all path segments 187 // associated with its descendants. 188 std::string BuildPath() const; 189 190 // Builds the full PII safe path associated with this node, including all path segments 191 // associated with its descendants. 192 std::string BuildSafePath() const; 193 194 // Looks up a direct descendant of this node by case-insensitive |name|. If |acquire| is true, 195 // also Acquire the node before returning a reference to it. 196 // |transforms| is an opaque flag that is used to distinguish multiple nodes sharing the same 197 // |name| but requiring different IO transformations as determined by the MediaProvider. 198 node* LookupChildByName(const std::string& name, bool acquire, const int transforms = 0) const { 199 return ForChild(name, [acquire, transforms](node* child) { 200 if (child->transforms_ == transforms) { 201 if (acquire) { 202 child->Acquire(); 203 } 204 return true; 205 } 206 return false; 207 }); 208 } 209 210 // Marks this node children as deleted. They are still associated with their parent, and 211 // all open handles etc. to the deleted nodes are preserved until their refcount goes 212 // to zero. SetDeletedForChild(const std::string & name)213 void SetDeletedForChild(const std::string& name) { 214 ForChild(name, [](node* child) { 215 child->SetDeleted(); 216 return false; 217 }); 218 } 219 SetDeleted()220 void SetDeleted() { 221 std::lock_guard<std::recursive_mutex> guard(*lock_); 222 deleted_ = true; 223 } 224 RenameChild(const std::string & old_name,const std::string & new_name,node * new_parent)225 void RenameChild(const std::string& old_name, const std::string& new_name, node* new_parent) { 226 ForChild(old_name, [=](node* child) { 227 child->Rename(new_name, new_parent); 228 return false; 229 }); 230 } 231 Rename(const std::string & name,node * new_parent)232 void Rename(const std::string& name, node* new_parent) { 233 std::lock_guard<std::recursive_mutex> guard(*lock_); 234 235 if (new_parent != parent_) { 236 RemoveFromParent(); 237 name_ = name; 238 AddToParent(new_parent); 239 return; 240 } 241 242 // Changing name_ will change the expected position of this node in parent's set of 243 // children. Consider following scenario: 244 // 1. This node: "b"; parent's set: {"a", "b", "c"} 245 // 2. Rename("b", "d") 246 // 247 // After rename, parent's set should become: {"a", "b", "d"}, but if we simply change the 248 // name it will be {"a", "d", "b"}, which violates properties of the set. 249 // 250 // To make sure that parent's set is always valid, changing name is 3 steps procedure: 251 // 1. Remove this node from parent's set. 252 // 2 Change the name. 253 // 3. Add it back to the set. 254 // Rename of node without changing its parent. Still need to remove and re-add it to make 255 // sure lookup index is correct. 256 if (name_ != name) { 257 // If this is a root node, simply rename it. 258 if (parent_ == nullptr) { 259 name_ = name; 260 return; 261 } 262 263 auto it = parent_->children_.find(this); 264 CHECK(it != parent_->children_.end()); 265 parent_->children_.erase(it); 266 267 name_ = name; 268 269 parent_->children_.insert(this); 270 } 271 } 272 GetName()273 const std::string& GetName() const { 274 std::lock_guard<std::recursive_mutex> guard(*lock_); 275 return name_; 276 } 277 GetIoPath()278 const std::string& GetIoPath() const { return io_path_; } 279 GetTransforms()280 int GetTransforms() const { return transforms_; } 281 GetTransformsReason()282 int GetTransformsReason() const { return transforms_reason_; } 283 IsTransformsComplete()284 bool IsTransformsComplete() const { 285 return transforms_complete_.load(std::memory_order_acquire); 286 } 287 SetTransformsComplete(bool complete)288 void SetTransformsComplete(bool complete) { 289 transforms_complete_.store(complete, std::memory_order_release); 290 } 291 GetParent()292 node* GetParent() const { 293 std::lock_guard<std::recursive_mutex> guard(*lock_); 294 return parent_; 295 } 296 AddHandle(handle * h)297 inline void AddHandle(handle* h) { 298 std::lock_guard<std::recursive_mutex> guard(*lock_); 299 handles_.emplace_back(std::unique_ptr<handle>(h)); 300 } 301 DestroyHandle(handle * h)302 void DestroyHandle(handle* h) { 303 std::lock_guard<std::recursive_mutex> guard(*lock_); 304 305 auto comp = [h](const std::unique_ptr<handle>& ptr) { return ptr.get() == h; }; 306 auto it = std::find_if(handles_.begin(), handles_.end(), comp); 307 CHECK(it != handles_.end()); 308 handles_.erase(it); 309 } 310 HasCachedHandle()311 bool HasCachedHandle() const { 312 std::lock_guard<std::recursive_mutex> guard(*lock_); 313 314 for (const auto& handle : handles_) { 315 if (handle->cached) { 316 return true; 317 } 318 } 319 return false; 320 } 321 ShouldInvalidate()322 bool ShouldInvalidate() const { 323 std::lock_guard<std::recursive_mutex> guard(*lock_); 324 return should_invalidate_; 325 } 326 SetShouldInvalidate()327 void SetShouldInvalidate() { 328 std::lock_guard<std::recursive_mutex> guard(*lock_); 329 should_invalidate_ = true; 330 } 331 HasRedactedCache()332 bool HasRedactedCache() const { 333 std::lock_guard<std::recursive_mutex> guard(*lock_); 334 return has_redacted_cache_; 335 } 336 SetRedactedCache(bool state)337 void SetRedactedCache(bool state) { 338 std::lock_guard<std::recursive_mutex> guard(*lock_); 339 has_redacted_cache_ = state; 340 } 341 AddDirHandle(dirhandle * d)342 inline void AddDirHandle(dirhandle* d) { 343 std::lock_guard<std::recursive_mutex> guard(*lock_); 344 345 dirhandles_.emplace_back(std::unique_ptr<dirhandle>(d)); 346 } 347 DestroyDirHandle(dirhandle * d)348 void DestroyDirHandle(dirhandle* d) { 349 std::lock_guard<std::recursive_mutex> guard(*lock_); 350 351 auto comp = [d](const std::unique_ptr<dirhandle>& ptr) { return ptr.get() == d; }; 352 auto it = std::find_if(dirhandles_.begin(), dirhandles_.end(), comp); 353 CHECK(it != dirhandles_.end()); 354 dirhandles_.erase(it); 355 } 356 357 // Deletes the tree of nodes rooted at |tree|. 358 static void DeleteTree(node* tree); 359 360 // Looks up an absolute path rooted at |root|, or nullptr if no such path 361 // through the hierarchy exists. 362 static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path); 363 364 // Looks up for the node with the given ino rooted at |root|, or nullptr if no such node exists. 365 static const node* LookupInode(const node* root, ino_t ino); 366 367 private: node(node * parent,const std::string & name,const std::string & io_path,const bool should_invalidate,const bool transforms_complete,const int transforms,const int transforms_reason,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)368 node(node* parent, const std::string& name, const std::string& io_path, 369 const bool should_invalidate, const bool transforms_complete, const int transforms, 370 const int transforms_reason, std::recursive_mutex* lock, ino_t ino, NodeTracker* tracker) 371 : name_(name), 372 io_path_(io_path), 373 transforms_complete_(transforms_complete), 374 transforms_(transforms), 375 transforms_reason_(transforms_reason), 376 refcount_(0), 377 parent_(nullptr), 378 has_redacted_cache_(false), 379 should_invalidate_(should_invalidate), 380 deleted_(false), 381 lock_(lock), 382 ino_(ino), 383 tracker_(tracker) { 384 tracker_->NodeCreated(this); 385 Acquire(); 386 // This is a special case for the root node. All other nodes will have a 387 // non-null parent. 388 if (parent != nullptr) { 389 AddToParent(parent); 390 } 391 // If the node requires transforms, we MUST never cache it in the VFS 392 if (transforms) { 393 CHECK(should_invalidate_); 394 } 395 } 396 397 // Acquires a reference to a node. This maps to the "lookup count" specified 398 // by the FUSE documentation and must only happen under the circumstances 399 // documented in libfuse/include/fuse_lowlevel.h. Acquire()400 inline void Acquire() { 401 std::lock_guard<std::recursive_mutex> guard(*lock_); 402 refcount_++; 403 } 404 405 // Adds this node to a specified parent. AddToParent(node * parent)406 void AddToParent(node* parent) { 407 std::lock_guard<std::recursive_mutex> guard(*lock_); 408 // This method assumes this node is currently unparented. 409 CHECK(parent_ == nullptr); 410 // Check that the new parent isn't nullptr either. 411 CHECK(parent != nullptr); 412 413 parent_ = parent; 414 parent_->children_.insert(this); 415 416 // TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the 417 // parent node when we're adding a child to it. 418 parent_->Acquire(); 419 } 420 421 // Removes this node from its current parent, and set its parent to nullptr. RemoveFromParent()422 void RemoveFromParent() { 423 std::lock_guard<std::recursive_mutex> guard(*lock_); 424 425 if (parent_ != nullptr) { 426 auto it = parent_->children_.find(this); 427 CHECK(it != parent_->children_.end()); 428 parent_->children_.erase(it); 429 430 parent_->Release(1); 431 parent_ = nullptr; 432 } 433 } 434 435 // Finds *all* non-deleted nodes matching |name| and runs the function |callback| on each 436 // node until |callback| returns true. 437 // When |callback| returns true, the matched node is returned ForChild(const std::string & name,const std::function<bool (node *)> & callback)438 node* ForChild(const std::string& name, const std::function<bool(node*)>& callback) const { 439 std::lock_guard<std::recursive_mutex> guard(*lock_); 440 441 // lower_bound will give us the first child with strcasecmp(child->name, name) >=0. 442 // For more context see comment on the NodeCompare struct. 443 auto start = children_.lower_bound(std::make_pair(name, 0)); 444 // upper_bound will give us the first child with strcasecmp(child->name, name) > 0 445 auto end = 446 children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max())); 447 448 // Make a copy of the matches because calling callback might modify the list which will 449 // cause issues while iterating over them. 450 std::vector<node*> children(start, end); 451 452 for (node* child : children) { 453 if (!child->deleted_ && callback(child)) { 454 return child; 455 } 456 } 457 458 return nullptr; 459 } 460 461 // A custom heterogeneous comparator used for set of this node's children_ to speed up child 462 // node by name lookups. 463 // 464 // This comparator treats node* as pair (node->name_, node): two nodes* are first 465 // compared by their name using case-insenstive comparison function. If their names are equal, 466 // then pointers are compared as integers. 467 // 468 // See LookupChildByName function to see how this comparator is used. 469 // 470 // Note that it's important to first compare by name_, since it will make all nodes with same 471 // name (compared using strcasecmp) together, which allows LookupChildByName function to find 472 // range of the candidate nodes by issuing two binary searches. 473 struct NodeCompare { 474 using is_transparent = void; 475 operatorNodeCompare476 bool operator()(const node* lhs, const node* rhs) const { 477 int cmp = strcasecmp(lhs->name_.c_str(), rhs->name_.c_str()); 478 if (cmp != 0) { 479 return cmp < 0; 480 } 481 return reinterpret_cast<uintptr_t>(lhs) < reinterpret_cast<uintptr_t>(rhs); 482 } 483 operatorNodeCompare484 bool operator()(const node* lhs, const std::pair<std::string, uintptr_t>& rhs) const { 485 int cmp = strcasecmp(lhs->name_.c_str(), rhs.first.c_str()); 486 if (cmp != 0) { 487 return cmp < 0; 488 } 489 return reinterpret_cast<uintptr_t>(lhs) < rhs.second; 490 } 491 operatorNodeCompare492 bool operator()(const std::pair<std::string, uintptr_t>& lhs, const node* rhs) const { 493 int cmp = strcasecmp(lhs.first.c_str(), rhs->name_.c_str()); 494 if (cmp != 0) { 495 return cmp < 0; 496 } 497 return lhs.second < reinterpret_cast<uintptr_t>(rhs); 498 } 499 }; 500 501 // A helper function to recursively construct the absolute path of a given node. 502 // If |safe| is true, builds a PII safe path instead 503 void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const; 504 505 // The name of this node. Non-const because it can change during renames. 506 std::string name_; 507 // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath 508 const std::string io_path_; 509 // Whether any transforms required on |io_path_| are complete. 510 // If false, might need to call a node transform function with |transforms| below 511 std::atomic_bool transforms_complete_; 512 // Opaque flags that determines the 'required' transforms to perform on node 513 // before IO. These flags should not be interpreted in native but should be passed to the 514 // MediaProvider as part of a transform function and if successful, |transforms_complete_| 515 // should be set to true 516 const int transforms_; 517 // Opaque value indicating the reason why transforms are required. 518 // This value should not be interpreted in native but should be passed to the MediaProvider 519 // as part of a transform function 520 const int transforms_reason_; 521 // The reference count for this node. Guarded by |lock_|. 522 uint32_t refcount_; 523 // Set of children of this node. All of them contain a back reference 524 // to their parent. Guarded by |lock_|. 525 std::set<node*, NodeCompare> children_; 526 // Containing directory for this node. Guarded by |lock_|. 527 node* parent_; 528 // List of file handles associated with this node. Guarded by |lock_|. 529 std::vector<std::unique_ptr<handle>> handles_; 530 // List of directory handles associated with this node. Guarded by |lock_|. 531 std::vector<std::unique_ptr<dirhandle>> dirhandles_; 532 bool has_redacted_cache_; 533 bool should_invalidate_; 534 bool deleted_; 535 std::recursive_mutex* lock_; 536 // Inode number of the file represented by this node. 537 const ino_t ino_; 538 539 NodeTracker* const tracker_; 540 ~node()541 ~node() { 542 RemoveFromParent(); 543 544 handles_.clear(); 545 dirhandles_.clear(); 546 547 tracker_->NodeDeleted(this); 548 } 549 550 friend class ::NodeTest; 551 }; 552 553 } // namespace fuse 554 } // namespace mediaprovider 555 556 #endif // MEDIA_PROVIDER_JNI_MODE_INL_H_ 557