1 // Copyright (C) 2018 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_ 16 #define IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_ 17 18 #include "common/expected.h" 19 #include "inode2filename/inode.h" 20 #include "inode2filename/system_call.h" 21 22 #include <fruit/fruit.h> 23 24 #include <rxcpp/rx.hpp> 25 namespace iorap::inode2filename { 26 27 // Tuple of (Inode -> (Filename|Errno)) 28 struct InodeResult { 29 // We set this error when all root directories have been searched and 30 // yet we still could not find a corresponding filename for the inode under search. 31 static constexpr int kCouldNotFindFilename = -ENOENT; 32 33 Inode inode; 34 // Value: Contains the filename (with a root directory as a prefix). 35 // Error: Contains the errno, usually -ENOENT or perhaps a security error. 36 iorap::expected<std::string /*filename*/, int /*errno*/> data; 37 makeSuccessInodeResult38 static InodeResult makeSuccess(Inode inode, std::string filename) { 39 return InodeResult{inode, std::move(filename)}; 40 } 41 makeFailureInodeResult42 static InodeResult makeFailure(Inode inode, int err_no) { 43 return InodeResult{inode, iorap::unexpected{err_no}}; 44 } 45 46 constexpr operator bool() const { 47 return data.has_value(); 48 } 49 }; 50 51 enum class SearchMode { 52 // Test modes: 53 kInProcessDirect, // Execute the code directly. 54 kInProcessIpc, // Execute code via IPC layer using multiple threads. 55 // Shipping mode: 56 kOutOfProcessIpc, // Execute code via fork+exec with IPC. 57 58 // Note: in-process system-wide stat(2)/readdir/etc is blocked by selinux. 59 // Attempting to call the test modes will fail with -EPERM. 60 // 61 // Use fork+exec mode in shipping configurations, which spawns inode2filename 62 // as a separate command. 63 }; 64 65 struct SearchDirectories { 66 // Type-erased subset of rxcpp::connectable_observable<?> 67 struct RxAnyConnectable { 68 // Connects to the underlying observable. 69 // 70 // This kicks off the graph, streams begin emitting items. 71 // This method will block until all items have been fully emitted 72 // and processed by any subscribers. 73 virtual void connect() = 0; 74 ~RxAnyConnectableSearchDirectories::RxAnyConnectable75 virtual ~RxAnyConnectable(){} 76 }; 77 78 79 // Create a cold observable of inode results (a lazy stream) corresponding 80 // to the inode search list. 81 // 82 // A depth-first search is done on each of the root directories (in order), 83 // until all inodes have been found (or until all directories have been exhausted). 84 // 85 // Some internal errors may occur during emission that aren't part of an InodeResult; 86 // these will be sent to the error logcat and dropped. 87 // 88 // Calling this function does not begin the search. 89 // The returned observable will begin the search after subscribing to it. 90 // 91 // The emitted InodeResult stream has these guarantees: 92 // - All inodes in inode_list will eventually be emitted exactly once in an InodeResult 93 // - When all inodes are found, directory traversal is halted. 94 // - The order of emission can be considered arbitrary. 95 // 96 // Lifetime rules: 97 // - The observable must be fully consumed before deleting any of the SearchDirectory's 98 // borrowed constructor parameters (e.g. the SystemCall). 99 // - SearchDirectory itself can be deleted at any time after creating an observable. 100 rxcpp::observable<InodeResult> 101 FindFilenamesFromInodes(std::vector<std::string> root_directories, 102 std::vector<Inode> inode_list, 103 SearchMode mode); 104 105 // Create a cold observable of inode results (a lazy stream) corresponding 106 // to the inode search list. 107 // 108 // A depth-first search is done on each of the root directories (in order), 109 // until all inodes have been found (or until all directories have been exhausted). 110 // 111 // Some internal errors may occur during emission that aren't part of an InodeResult; 112 // these will be sent to the error logcat and dropped. 113 // 114 // Calling this function does not begin the search. 115 // The returned observable will begin the search after subscribing to it. 116 // 117 // The emitted InodeResult stream has these guarantees: 118 // - All inodes in inode_list will eventually be emitted exactly once in an InodeResult 119 // - When all inodes are found, directory traversal is halted. 120 // - The order of emission can be considered arbitrary. 121 // 122 // Lifetime rules: 123 // - The observable must be fully consumed before deleting any of the SearchDirectory's 124 // borrowed constructor parameters (e.g. the SystemCall). 125 // - SearchDirectory itself can be deleted at any time after creating an observable. 126 std::pair<rxcpp::observable<InodeResult>, std::unique_ptr<RxAnyConnectable>> 127 FindFilenamesFromInodesPair(std::vector<std::string> root_directories, 128 std::vector<Inode> inode_list, 129 SearchMode mode); 130 131 // Any borrowed parameters here can also be borrowed by the observables returned by the above 132 // member functions. 133 // 134 // The observables must be fully consumed within the lifetime of the borrowed parameters. INJECTSearchDirectories135 INJECT(SearchDirectories(borrowed<SystemCall*> system_call)) 136 : system_call_(system_call) {} 137 138 // TODO: is there a way to get rid of this second RxAnyConnectable parameter? 139 private: 140 // This gets passed around to lazy lambdas, so we must finish consuming any observables 141 // before the injected system call is deleted. 142 borrowed<SystemCall*> system_call_; 143 }; 144 145 } // namespace iorap::inode2filename 146 147 #endif // IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_ 148