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 specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ANDROID_APEXD_APEXD_ROLLBACK_UTILS_H_
18 #define ANDROID_APEXD_APEXD_ROLLBACK_UTILS_H_
19
20 #include <filesystem>
21 #include <string>
22
23 #include <android-base/logging.h>
24 #include <android-base/macros.h>
25 #include <android-base/result.h>
26 #include <android-base/scopeguard.h>
27 #include <logwrap/logwrap.h>
28
29 namespace android {
30 namespace apex {
31
32 static constexpr const char* kCpPath = "/system/bin/cp";
33
34 /**
35 * Copies everything including directories from the "from" path to the "to"
36 * path. Note that this will fail if run before APEXes are mounted, due to a
37 * dependency on runtime.
38 */
CopyDirectoryRecursive(const char * from,const char * to)39 inline int32_t CopyDirectoryRecursive(const char* from, const char* to) {
40 const char* const argv[] = {
41 kCpPath,
42 "-F", /* delete any existing destination file first
43 (--remove-destination) */
44 "-p", /* preserve timestamps, ownership, and permissions */
45 "-R", /* recurse into subdirectories (DEST must be a directory) */
46 "-P", /* Do not follow symlinks [default] */
47 "-d", /* don't dereference symlinks */
48 from,
49 to};
50
51 LOG(DEBUG) << "Copying " << from << " to " << to;
52 return logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG,
53 false, nullptr);
54 }
55
56 /**
57 * Deletes any files at to_path, and then copies all files and directories
58 * from from_path into to_path. Note that this must be run after APEXes are
59 * mounted.
60 */
ReplaceFiles(const std::string & from_path,const std::string & to_path)61 inline android::base::Result<void> ReplaceFiles(const std::string& from_path,
62 const std::string& to_path) {
63 namespace fs = std::filesystem;
64
65 std::error_code error_code;
66 fs::remove_all(to_path, error_code);
67 if (error_code) {
68 return android::base::Error() << "Failed to delete existing files at "
69 << to_path << " : " << error_code.message();
70 }
71
72 auto deleter = [&] {
73 std::error_code error_code;
74 fs::remove_all(to_path, error_code);
75 if (error_code) {
76 LOG(ERROR) << "Failed to clean up files at " << to_path << " : "
77 << error_code.message();
78 }
79 };
80 auto scope_guard = android::base::make_scope_guard(deleter);
81
82 int rc = CopyDirectoryRecursive(from_path.c_str(), to_path.c_str());
83 if (rc != 0) {
84 return android::base::Error() << "Failed to copy from [" << from_path
85 << "] to [" << to_path << "]";
86 }
87 scope_guard.Disable();
88 return {};
89 }
90
91 } // namespace apex
92 } // namespace android
93
94 #endif // ANDROID_APEXD_APEXD_ROLLBACK_UTILS_H_
95