xref: /aosp_15_r20/art/artd/file_utils.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "file_utils.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
20*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
21*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
22*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include <filesystem>
25*795d594fSAndroid Build Coastguard Worker #include <memory>
26*795d594fSAndroid Build Coastguard Worker #include <string>
27*795d594fSAndroid Build Coastguard Worker #include <string_view>
28*795d594fSAndroid Build Coastguard Worker #include <system_error>
29*795d594fSAndroid Build Coastguard Worker #include <unordered_set>
30*795d594fSAndroid Build Coastguard Worker #include <utility>
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker #include "aidl/com/android/server/art/FsPermission.h"
33*795d594fSAndroid Build Coastguard Worker #include "android-base/errors.h"
34*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
35*795d594fSAndroid Build Coastguard Worker #include "android-base/result.h"
36*795d594fSAndroid Build Coastguard Worker #include "android-base/scopeguard.h"
37*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
38*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
39*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker namespace art {
42*795d594fSAndroid Build Coastguard Worker namespace artd {
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker namespace {
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker using ::aidl::com::android::server::art::FsPermission;
47*795d594fSAndroid Build Coastguard Worker using ::android::base::make_scope_guard;
48*795d594fSAndroid Build Coastguard Worker using ::android::base::Result;
49*795d594fSAndroid Build Coastguard Worker 
UnlinkIfExists(std::string_view path)50*795d594fSAndroid Build Coastguard Worker void UnlinkIfExists(std::string_view path) {
51*795d594fSAndroid Build Coastguard Worker   std::error_code ec;
52*795d594fSAndroid Build Coastguard Worker   std::filesystem::remove(path, ec);
53*795d594fSAndroid Build Coastguard Worker   if (ec) {
54*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << ART_FORMAT("Failed to remove file '{}': {}", path, ec.message());
55*795d594fSAndroid Build Coastguard Worker   }
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker }  // namespace
59*795d594fSAndroid Build Coastguard Worker 
Create(const std::string & path,const FsPermission & fs_permission)60*795d594fSAndroid Build Coastguard Worker Result<std::unique_ptr<NewFile>> NewFile::Create(const std::string& path,
61*795d594fSAndroid Build Coastguard Worker                                                  const FsPermission& fs_permission) {
62*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<NewFile> output_file(new NewFile(path, fs_permission));
63*795d594fSAndroid Build Coastguard Worker   OR_RETURN(output_file->Init());
64*795d594fSAndroid Build Coastguard Worker   return output_file;
65*795d594fSAndroid Build Coastguard Worker }
66*795d594fSAndroid Build Coastguard Worker 
~NewFile()67*795d594fSAndroid Build Coastguard Worker NewFile::~NewFile() { Cleanup(); }
68*795d594fSAndroid Build Coastguard Worker 
Keep()69*795d594fSAndroid Build Coastguard Worker Result<void> NewFile::Keep() {
70*795d594fSAndroid Build Coastguard Worker   if (close(std::exchange(fd_, -1)) != 0) {
71*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to close file '{}'", temp_path_);
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker   return {};
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker 
CommitOrAbandon()76*795d594fSAndroid Build Coastguard Worker Result<void> NewFile::CommitOrAbandon() {
77*795d594fSAndroid Build Coastguard Worker   auto cleanup = make_scope_guard([this] { Unlink(); });
78*795d594fSAndroid Build Coastguard Worker   OR_RETURN(Keep());
79*795d594fSAndroid Build Coastguard Worker   std::error_code ec;
80*795d594fSAndroid Build Coastguard Worker   std::filesystem::rename(temp_path_, final_path_, ec);
81*795d594fSAndroid Build Coastguard Worker   if (ec) {
82*795d594fSAndroid Build Coastguard Worker     // If this fails because the temp file doesn't exist, it could be that the file is deleted by
83*795d594fSAndroid Build Coastguard Worker     // `Artd::cleanup` if that method is run simultaneously. At the time of writing, this should
84*795d594fSAndroid Build Coastguard Worker     // never happen because `Artd::cleanup` is only called at the end of the backgrond dexopt job.
85*795d594fSAndroid Build Coastguard Worker     return Errorf(
86*795d594fSAndroid Build Coastguard Worker         "Failed to move new file '{}' to path '{}': {}", temp_path_, final_path_, ec.message());
87*795d594fSAndroid Build Coastguard Worker   }
88*795d594fSAndroid Build Coastguard Worker   cleanup.Disable();
89*795d594fSAndroid Build Coastguard Worker   return {};
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker 
Cleanup()92*795d594fSAndroid Build Coastguard Worker void NewFile::Cleanup() {
93*795d594fSAndroid Build Coastguard Worker   if (fd_ >= 0) {
94*795d594fSAndroid Build Coastguard Worker     Unlink();
95*795d594fSAndroid Build Coastguard Worker     if (close(std::exchange(fd_, -1)) != 0) {
96*795d594fSAndroid Build Coastguard Worker       // Nothing we can do. If the file is already unlinked, it will go away when the process exits.
97*795d594fSAndroid Build Coastguard Worker       PLOG(WARNING) << "Failed to close file '" << temp_path_ << "'";
98*795d594fSAndroid Build Coastguard Worker     }
99*795d594fSAndroid Build Coastguard Worker   }
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker 
Init()102*795d594fSAndroid Build Coastguard Worker Result<void> NewFile::Init() {
103*795d594fSAndroid Build Coastguard Worker   mode_t mode = FileFsPermissionToMode(fs_permission_);
104*795d594fSAndroid Build Coastguard Worker   // "<path_>.XXXXXX.tmp".
105*795d594fSAndroid Build Coastguard Worker   temp_path_ = BuildTempPath(final_path_, "XXXXXX");
106*795d594fSAndroid Build Coastguard Worker   fd_ = mkstemps(temp_path_.data(), /*suffixlen=*/4);
107*795d594fSAndroid Build Coastguard Worker   if (fd_ < 0) {
108*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to create temp file for '{}'", final_path_);
109*795d594fSAndroid Build Coastguard Worker   }
110*795d594fSAndroid Build Coastguard Worker   temp_id_ = temp_path_.substr(/*pos=*/final_path_.length() + 1, /*count=*/6);
111*795d594fSAndroid Build Coastguard Worker   if (fchmod(fd_, mode) != 0) {
112*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to chmod file '{}'", temp_path_);
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker   OR_RETURN(Chown(temp_path_, fs_permission_));
115*795d594fSAndroid Build Coastguard Worker   return {};
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker 
Unlink()118*795d594fSAndroid Build Coastguard Worker void NewFile::Unlink() {
119*795d594fSAndroid Build Coastguard Worker   // This should never fail. We were able to create the file, so we should be able to remove it.
120*795d594fSAndroid Build Coastguard Worker   UnlinkIfExists(temp_path_);
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker 
CommitAllOrAbandon(const std::vector<NewFile * > & files_to_commit,const std::vector<std::string_view> & files_to_remove)123*795d594fSAndroid Build Coastguard Worker Result<void> NewFile::CommitAllOrAbandon(const std::vector<NewFile*>& files_to_commit,
124*795d594fSAndroid Build Coastguard Worker                                          const std::vector<std::string_view>& files_to_remove) {
125*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<std::string_view, std::string_view>> files_to_move;
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   auto cleanup = make_scope_guard([&]() {
128*795d594fSAndroid Build Coastguard Worker     for (NewFile* file : files_to_commit) {
129*795d594fSAndroid Build Coastguard Worker       file->Unlink();
130*795d594fSAndroid Build Coastguard Worker     }
131*795d594fSAndroid Build Coastguard Worker   });
132*795d594fSAndroid Build Coastguard Worker   for (NewFile* file : files_to_commit) {
133*795d594fSAndroid Build Coastguard Worker     OR_RETURN(file->Keep());
134*795d594fSAndroid Build Coastguard Worker     files_to_move.emplace_back(file->TempPath(), file->FinalPath());
135*795d594fSAndroid Build Coastguard Worker   }
136*795d594fSAndroid Build Coastguard Worker   cleanup.Disable();
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker   return MoveAllOrAbandon(files_to_move, files_to_remove);
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker 
MoveAllOrAbandon(const std::vector<std::pair<std::string_view,std::string_view>> & files_to_move,const std::vector<std::string_view> & files_to_remove)141*795d594fSAndroid Build Coastguard Worker Result<void> MoveAllOrAbandon(
142*795d594fSAndroid Build Coastguard Worker     const std::vector<std::pair<std::string_view, std::string_view>>& files_to_move,
143*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string_view>& files_to_remove) {
144*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<std::string_view, std::string>> moved_files;
145*795d594fSAndroid Build Coastguard Worker   std::unordered_set<std::string_view> committed_files;
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker   auto cleanup = make_scope_guard([&]() {
148*795d594fSAndroid Build Coastguard Worker     // Clean up `files_to_move`.
149*795d594fSAndroid Build Coastguard Worker     for (const auto& [src_path, dst_path] : files_to_move) {
150*795d594fSAndroid Build Coastguard Worker       if (committed_files.find(dst_path) != committed_files.end()) {
151*795d594fSAndroid Build Coastguard Worker         UnlinkIfExists(dst_path);
152*795d594fSAndroid Build Coastguard Worker       } else {
153*795d594fSAndroid Build Coastguard Worker         UnlinkIfExists(src_path);
154*795d594fSAndroid Build Coastguard Worker       }
155*795d594fSAndroid Build Coastguard Worker     }
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker     // Move old files back.
158*795d594fSAndroid Build Coastguard Worker     for (const auto& [original_path, temp_path] : moved_files) {
159*795d594fSAndroid Build Coastguard Worker       std::error_code ec;
160*795d594fSAndroid Build Coastguard Worker       std::filesystem::rename(temp_path, original_path, ec);
161*795d594fSAndroid Build Coastguard Worker       if (ec) {
162*795d594fSAndroid Build Coastguard Worker         // This should never happen. We were able to move the file from `original_path` to
163*795d594fSAndroid Build Coastguard Worker         // `temp_path`. We should be able to move it back.
164*795d594fSAndroid Build Coastguard Worker         LOG(WARNING) << ART_FORMAT("Failed to move old file '{}' back from temporary path '{}': {}",
165*795d594fSAndroid Build Coastguard Worker                                    original_path,
166*795d594fSAndroid Build Coastguard Worker                                    temp_path,
167*795d594fSAndroid Build Coastguard Worker                                    ec.message());
168*795d594fSAndroid Build Coastguard Worker       }
169*795d594fSAndroid Build Coastguard Worker     }
170*795d594fSAndroid Build Coastguard Worker   });
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker   // Move old files to temporary locations.
173*795d594fSAndroid Build Coastguard Worker   std::vector<std::string_view> all_files_to_remove;
174*795d594fSAndroid Build Coastguard Worker   all_files_to_remove.reserve(files_to_move.size() + files_to_remove.size());
175*795d594fSAndroid Build Coastguard Worker   for (const auto& [src_path, dst_path] : files_to_move) {
176*795d594fSAndroid Build Coastguard Worker     all_files_to_remove.push_back(dst_path);
177*795d594fSAndroid Build Coastguard Worker   }
178*795d594fSAndroid Build Coastguard Worker   all_files_to_remove.insert(
179*795d594fSAndroid Build Coastguard Worker       all_files_to_remove.end(), files_to_remove.begin(), files_to_remove.end());
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker   for (std::string_view original_path : all_files_to_remove) {
182*795d594fSAndroid Build Coastguard Worker     std::error_code ec;
183*795d594fSAndroid Build Coastguard Worker     std::filesystem::file_status status = std::filesystem::status(original_path, ec);
184*795d594fSAndroid Build Coastguard Worker     if (!std::filesystem::status_known(status)) {
185*795d594fSAndroid Build Coastguard Worker       return Errorf("Failed to get status of old file '{}': {}", original_path, ec.message());
186*795d594fSAndroid Build Coastguard Worker     }
187*795d594fSAndroid Build Coastguard Worker     if (std::filesystem::is_directory(status)) {
188*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Old file '{}' is a directory", original_path);
189*795d594fSAndroid Build Coastguard Worker     }
190*795d594fSAndroid Build Coastguard Worker     if (std::filesystem::exists(status)) {
191*795d594fSAndroid Build Coastguard Worker       std::string temp_path = NewFile::BuildTempPath(original_path, "XXXXXX");
192*795d594fSAndroid Build Coastguard Worker       int fd = mkstemps(temp_path.data(), /*suffixlen=*/4);
193*795d594fSAndroid Build Coastguard Worker       if (fd < 0) {
194*795d594fSAndroid Build Coastguard Worker         return ErrnoErrorf("Failed to create temporary path for old file '{}'", original_path);
195*795d594fSAndroid Build Coastguard Worker       }
196*795d594fSAndroid Build Coastguard Worker       close(fd);
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker       std::filesystem::rename(original_path, temp_path, ec);
199*795d594fSAndroid Build Coastguard Worker       if (ec) {
200*795d594fSAndroid Build Coastguard Worker         UnlinkIfExists(temp_path);
201*795d594fSAndroid Build Coastguard Worker         return Errorf("Failed to move old file '{}' to temporary path '{}': {}",
202*795d594fSAndroid Build Coastguard Worker                       original_path,
203*795d594fSAndroid Build Coastguard Worker                       temp_path,
204*795d594fSAndroid Build Coastguard Worker                       ec.message());
205*795d594fSAndroid Build Coastguard Worker       }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker       moved_files.push_back({original_path, std::move(temp_path)});
208*795d594fSAndroid Build Coastguard Worker     }
209*795d594fSAndroid Build Coastguard Worker   }
210*795d594fSAndroid Build Coastguard Worker 
211*795d594fSAndroid Build Coastguard Worker   // Move `files_to_move`.
212*795d594fSAndroid Build Coastguard Worker   for (const auto& [src_path, dst_path] : files_to_move) {
213*795d594fSAndroid Build Coastguard Worker     std::error_code ec;
214*795d594fSAndroid Build Coastguard Worker     std::filesystem::rename(src_path, dst_path, ec);
215*795d594fSAndroid Build Coastguard Worker     if (ec) {
216*795d594fSAndroid Build Coastguard Worker       return Errorf("Failed to move file from '{}' to '{}': {}", src_path, dst_path, ec.message());
217*795d594fSAndroid Build Coastguard Worker     }
218*795d594fSAndroid Build Coastguard Worker     committed_files.insert(dst_path);
219*795d594fSAndroid Build Coastguard Worker   }
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker   cleanup.Disable();
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   // Clean up old files.
224*795d594fSAndroid Build Coastguard Worker   for (const auto& [original_path, temp_path] : moved_files) {
225*795d594fSAndroid Build Coastguard Worker     // This should never fail.  We were able to move the file to `temp_path`. We should be able to
226*795d594fSAndroid Build Coastguard Worker     // remove it.
227*795d594fSAndroid Build Coastguard Worker     UnlinkIfExists(temp_path);
228*795d594fSAndroid Build Coastguard Worker   }
229*795d594fSAndroid Build Coastguard Worker 
230*795d594fSAndroid Build Coastguard Worker   return {};
231*795d594fSAndroid Build Coastguard Worker }
232*795d594fSAndroid Build Coastguard Worker 
MoveAllOrAbandon(const std::vector<std::pair<std::string,std::string>> & files_to_move,const std::vector<std::string> & files_to_remove)233*795d594fSAndroid Build Coastguard Worker android::base::Result<void> MoveAllOrAbandon(
234*795d594fSAndroid Build Coastguard Worker     const std::vector<std::pair<std::string, std::string>>& files_to_move,
235*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& files_to_remove) {
236*795d594fSAndroid Build Coastguard Worker   std::vector<std::pair<std::string_view, std::string_view>> files_to_move_view;
237*795d594fSAndroid Build Coastguard Worker   files_to_move_view.reserve(files_to_move.size());
238*795d594fSAndroid Build Coastguard Worker   for (const auto& [src, dst] : files_to_move) {
239*795d594fSAndroid Build Coastguard Worker     files_to_move_view.emplace_back(src, dst);
240*795d594fSAndroid Build Coastguard Worker   }
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker   std::vector<std::string_view> files_to_remove_view;
243*795d594fSAndroid Build Coastguard Worker   files_to_remove_view.reserve(files_to_remove.size());
244*795d594fSAndroid Build Coastguard Worker   for (const std::string& file : files_to_remove) {
245*795d594fSAndroid Build Coastguard Worker     files_to_remove_view.emplace_back(file);
246*795d594fSAndroid Build Coastguard Worker   }
247*795d594fSAndroid Build Coastguard Worker   return MoveAllOrAbandon(files_to_move_view, files_to_remove_view);
248*795d594fSAndroid Build Coastguard Worker }
249*795d594fSAndroid Build Coastguard Worker 
BuildTempPath(std::string_view final_path,const std::string & id)250*795d594fSAndroid Build Coastguard Worker std::string NewFile::BuildTempPath(std::string_view final_path, const std::string& id) {
251*795d594fSAndroid Build Coastguard Worker   return ART_FORMAT("{}.{}.tmp", final_path, id);
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker 
OpenFileForReading(const std::string & path)254*795d594fSAndroid Build Coastguard Worker Result<std::unique_ptr<File>> OpenFileForReading(const std::string& path) {
255*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> file(OS::OpenFileForReading(path.c_str()));
256*795d594fSAndroid Build Coastguard Worker   if (file == nullptr) {
257*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to open file '{}'", path);
258*795d594fSAndroid Build Coastguard Worker   }
259*795d594fSAndroid Build Coastguard Worker   return file;
260*795d594fSAndroid Build Coastguard Worker }
261*795d594fSAndroid Build Coastguard Worker 
FileFsPermissionToMode(const FsPermission & fs_permission)262*795d594fSAndroid Build Coastguard Worker mode_t FileFsPermissionToMode(const FsPermission& fs_permission) {
263*795d594fSAndroid Build Coastguard Worker   return S_IRUSR | S_IWUSR | S_IRGRP | (fs_permission.isOtherReadable ? S_IROTH : 0) |
264*795d594fSAndroid Build Coastguard Worker          (fs_permission.isOtherExecutable ? S_IXOTH : 0);
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker 
DirFsPermissionToMode(const FsPermission & fs_permission)267*795d594fSAndroid Build Coastguard Worker mode_t DirFsPermissionToMode(const FsPermission& fs_permission) {
268*795d594fSAndroid Build Coastguard Worker   return FileFsPermissionToMode(fs_permission) | S_IXUSR | S_IXGRP;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker 
Chown(const std::string & path,const FsPermission & fs_permission)271*795d594fSAndroid Build Coastguard Worker Result<void> Chown(const std::string& path, const FsPermission& fs_permission) {
272*795d594fSAndroid Build Coastguard Worker   if (fs_permission.uid < 0 && fs_permission.gid < 0) {
273*795d594fSAndroid Build Coastguard Worker     // Keep the default owner.
274*795d594fSAndroid Build Coastguard Worker   } else if (fs_permission.uid < 0 || fs_permission.gid < 0) {
275*795d594fSAndroid Build Coastguard Worker     return Errorf("uid and gid must be both non-negative or both negative, got {} and {}.",
276*795d594fSAndroid Build Coastguard Worker                   fs_permission.uid,
277*795d594fSAndroid Build Coastguard Worker                   fs_permission.gid);
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker   if (chown(path.c_str(), fs_permission.uid, fs_permission.gid) != 0) {
280*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to chown '{}'", path);
281*795d594fSAndroid Build Coastguard Worker   }
282*795d594fSAndroid Build Coastguard Worker   return {};
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker }  // namespace artd
286*795d594fSAndroid Build Coastguard Worker }  // namespace art
287