pf_move returns EXDEV if node not tracked

This returns EXDEV if we rename, but the second id isn't tracked. This
is likely because it was set up via fuse-bpf. Until we have a better
tracking method, we can fall back on EXDEV to handle this situation with
a copy/delete.

Bug: 202785178
Test: CtsAppSecurityHostTestCases
Test: mv /sdcard/DCIM/file /storage/emulated/0/Android/data/<pkg>/
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Alessio Balsini <balsini@google.com>
Change-Id: I6e4311a75f641fc019bfad7fa26bd23398cbf252
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 575951f..9f6d61d 100755
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -291,6 +291,14 @@
         return node::FromInode(inode, &tracker);
     }
 
+    inline node* FromInodeNoThrow(__u64 inode) {
+        if (inode == FUSE_ROOT_ID) {
+            return root;
+        }
+
+        return node::FromInodeNoThrow(inode, &tracker);
+    }
+
     inline __u64 ToInode(node* node) const {
         if (IsRoot(node)) {
             return FUSE_ROOT_ID;
@@ -1225,8 +1233,14 @@
         return ENOENT;
     }
 
-    node* new_parent_node = fuse->FromInode(new_parent);
-    if (!new_parent_node) return ENOENT;
+    node* new_parent_node;
+    if (fuse->bpf) {
+        new_parent_node = fuse->FromInodeNoThrow(new_parent);
+        if (!new_parent_node) return EXDEV;
+    } else {
+        new_parent_node = fuse->FromInode(new_parent);
+        if (!new_parent_node) return ENOENT;
+    }
     const string new_parent_path = new_parent_node->BuildPath();
     if (!is_app_accessible_path(fuse, new_parent_path, ctx->uid)) {
         return ENOENT;
diff --git a/jni/node-inl.h b/jni/node-inl.h
index 01d6cba..c2bb260 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -90,6 +90,14 @@
   public:
     explicit NodeTracker(std::recursive_mutex* lock) : lock_(lock) {}
 
+    bool Exists(__u64 ino) const {
+        if (kEnableInodeTracking) {
+            const node* node = reinterpret_cast<const class node*>(ino);
+            std::lock_guard<std::recursive_mutex> guard(*lock_);
+            return active_nodes_.find(node) != active_nodes_.end();
+        }
+    }
+
     void CheckTracked(__u64 ino) const {
         if (kEnableInodeTracking) {
             const node* node = reinterpret_cast<const class node*>(ino);
@@ -158,6 +166,12 @@
         return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
     }
 
+    // TODO(b/215235604)
+    static inline node* FromInodeNoThrow(__u64 ino, const NodeTracker* tracker) {
+        if (!tracker->Exists(ino)) return nullptr;
+        return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
+    }
+
     // Maps a node to its associated inode.
     static __u64 ToInode(node* node) {
         return static_cast<__u64>(reinterpret_cast<uintptr_t>(node));