file_sync_service.cpp revision 65fe2516b402ed8903f2ce39a86fa0bdc2b263a6
1/* 2 * Copyright (C) 2007 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#define TRACE_TAG SYNC 18 19#include "sysdeps.h" 20#include "file_sync_service.h" 21 22#include <dirent.h> 23#include <errno.h> 24#include <selinux/android.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <sys/stat.h> 29#include <sys/types.h> 30#include <unistd.h> 31#include <utime.h> 32 33#include "adb.h" 34#include "adb_io.h" 35#include "private/android_filesystem_config.h" 36 37#include <base/stringprintf.h> 38#include <base/strings.h> 39 40static bool should_use_fs_config(const std::string& path) { 41 // TODO: use fs_config to configure permissions on /data. 42 return android::base::StartsWith(path, "/system/") || 43 android::base::StartsWith(path, "/vendor/") || 44 android::base::StartsWith(path, "/oem/"); 45} 46 47static bool secure_mkdirs(const std::string& path) { 48 uid_t uid = -1; 49 gid_t gid = -1; 50 unsigned int mode = 0775; 51 uint64_t cap = 0; 52 53 if (path[0] != '/') return false; 54 55 std::vector<std::string> path_components = android::base::Split(path, "/"); 56 path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin". 57 58 std::string partial_path; 59 for (const auto& path_component : path_components) { 60 if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR; 61 partial_path += path_component; 62 63 if (should_use_fs_config(partial_path)) { 64 fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap); 65 } 66 if (adb_mkdir(partial_path.c_str(), mode) == -1) { 67 if (errno != EEXIST) { 68 return false; 69 } 70 } else { 71 if (chown(partial_path.c_str(), uid, gid) == -1) { 72 return false; 73 } 74 // Not all filesystems support setting SELinux labels. http://b/23530370. 75 selinux_android_restorecon(partial_path.c_str(), 0); 76 } 77 } 78 return true; 79} 80 81static bool do_stat(int s, const char* path) { 82 syncmsg msg; 83 msg.stat.id = ID_STAT; 84 85 struct stat st; 86 memset(&st, 0, sizeof(st)); 87 // TODO: add a way to report that the stat failed! 88 lstat(path, &st); 89 msg.stat.mode = st.st_mode; 90 msg.stat.size = st.st_size; 91 msg.stat.time = st.st_mtime; 92 93 return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)); 94} 95 96static bool do_list(int s, const char* path) { 97 dirent* de; 98 99 syncmsg msg; 100 msg.dent.id = ID_DENT; 101 102 std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir); 103 if (!d) goto done; 104 105 while ((de = readdir(d.get()))) { 106 std::string filename(android::base::StringPrintf("%s/%s", path, de->d_name)); 107 108 struct stat st; 109 if (lstat(filename.c_str(), &st) == 0) { 110 size_t d_name_length = strlen(de->d_name); 111 msg.dent.mode = st.st_mode; 112 msg.dent.size = st.st_size; 113 msg.dent.time = st.st_mtime; 114 msg.dent.namelen = d_name_length; 115 116 if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) || 117 !WriteFdExactly(s, de->d_name, d_name_length)) { 118 return false; 119 } 120 } 121 } 122 123done: 124 msg.dent.id = ID_DONE; 125 msg.dent.mode = 0; 126 msg.dent.size = 0; 127 msg.dent.time = 0; 128 msg.dent.namelen = 0; 129 return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)); 130} 131 132static bool SendSyncFail(int fd, const std::string& reason) { 133 D("sync: failure: %s", reason.c_str()); 134 135 syncmsg msg; 136 msg.data.id = ID_FAIL; 137 msg.data.size = reason.size(); 138 return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason); 139} 140 141static bool SendSyncFailErrno(int fd, const std::string& reason) { 142 return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno))); 143} 144 145static bool handle_send_file(int s, const char* path, uid_t uid, 146 gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) { 147 syncmsg msg; 148 unsigned int timestamp = 0; 149 150 int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); 151 if (fd < 0 && errno == ENOENT) { 152 if (!secure_mkdirs(path)) { 153 SendSyncFailErrno(s, "secure_mkdirs failed"); 154 goto fail; 155 } 156 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); 157 } 158 if (fd < 0 && errno == EEXIST) { 159 fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode); 160 } 161 if (fd < 0) { 162 SendSyncFailErrno(s, "couldn't create file"); 163 goto fail; 164 } else { 165 if (fchown(fd, uid, gid) == -1) { 166 SendSyncFailErrno(s, "fchown failed"); 167 goto fail; 168 } 169 170 // Not all filesystems support setting SELinux labels. http://b/23530370. 171 selinux_android_restorecon(path, 0); 172 173 // fchown clears the setuid bit - restore it if present. 174 // Ignore the result of calling fchmod. It's not supported 175 // by all filesystems. b/12441485 176 fchmod(fd, mode); 177 } 178 179 while (true) { 180 unsigned int len; 181 182 if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail; 183 184 if (msg.data.id != ID_DATA) { 185 if (msg.data.id == ID_DONE) { 186 timestamp = msg.data.size; 187 break; 188 } 189 SendSyncFail(s, "invalid data message"); 190 goto fail; 191 } 192 len = msg.data.size; 193 if (len > buffer.size()) { // TODO: resize buffer? 194 SendSyncFail(s, "oversize data message"); 195 goto fail; 196 } 197 198 if (!ReadFdExactly(s, &buffer[0], len)) goto fail; 199 200 if (!WriteFdExactly(fd, &buffer[0], len)) { 201 SendSyncFailErrno(s, "write failed"); 202 goto fail; 203 } 204 } 205 206 adb_close(fd); 207 208 utimbuf u; 209 u.actime = timestamp; 210 u.modtime = timestamp; 211 utime(path, &u); 212 213 msg.status.id = ID_OKAY; 214 msg.status.msglen = 0; 215 return WriteFdExactly(s, &msg.status, sizeof(msg.status)); 216 217fail: 218 if (fd >= 0) adb_close(fd); 219 if (do_unlink) adb_unlink(path); 220 return false; 221} 222 223#if defined(_WIN32) 224extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows"))); 225#else 226static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) { 227 syncmsg msg; 228 unsigned int len; 229 int ret; 230 231 if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; 232 233 if (msg.data.id != ID_DATA) { 234 SendSyncFail(s, "invalid data message: expected ID_DATA"); 235 return false; 236 } 237 238 len = msg.data.size; 239 if (len > buffer.size()) { // TODO: resize buffer? 240 SendSyncFail(s, "oversize data message"); 241 return false; 242 } 243 if (!ReadFdExactly(s, &buffer[0], len)) return false; 244 245 ret = symlink(&buffer[0], path.c_str()); 246 if (ret && errno == ENOENT) { 247 if (!secure_mkdirs(path)) { 248 SendSyncFailErrno(s, "secure_mkdirs failed"); 249 return false; 250 } 251 ret = symlink(&buffer[0], path.c_str()); 252 } 253 if (ret) { 254 SendSyncFailErrno(s, "symlink failed"); 255 return false; 256 } 257 258 if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; 259 260 if (msg.data.id == ID_DONE) { 261 msg.status.id = ID_OKAY; 262 msg.status.msglen = 0; 263 if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; 264 } else { 265 SendFail(s, "invalid data message: expected ID_DONE"); 266 return false; 267 } 268 269 return true; 270} 271#endif 272 273static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) { 274 // 'spec' is of the form "/some/path,0755". Break it up. 275 size_t comma = spec.find_last_of(','); 276 if (comma == std::string::npos) { 277 SendFail(s, "missing , in ID_SEND"); 278 return false; 279 } 280 281 std::string path = spec.substr(0, comma); 282 283 errno = 0; 284 mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0); 285 if (errno != 0) { 286 SendFail(s, "bad mode"); 287 return false; 288 } 289 290 // Don't delete files before copying if they are not "regular" or symlinks. 291 struct stat st; 292 bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); 293 if (do_unlink) { 294 adb_unlink(path.c_str()); 295 } 296 297 if (S_ISLNK(mode)) { 298 return handle_send_link(s, path.c_str(), buffer); 299 } 300 301 // Copy user permission bits to "group" and "other" permissions. 302 mode &= 0777; 303 mode |= ((mode >> 3) & 0070); 304 mode |= ((mode >> 3) & 0007); 305 306 uid_t uid = -1; 307 gid_t gid = -1; 308 uint64_t cap = 0; 309 if (should_use_fs_config(path)) { 310 unsigned int broken_api_hack = mode; 311 fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &cap); 312 mode = broken_api_hack; 313 } 314 return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink); 315} 316 317static bool do_recv(int s, const char* path, std::vector<char>& buffer) { 318 int fd = adb_open(path, O_RDONLY | O_CLOEXEC); 319 if (fd < 0) { 320 SendSyncFailErrno(s, "open failed"); 321 return false; 322 } 323 324 syncmsg msg; 325 msg.data.id = ID_DATA; 326 while (true) { 327 int r = adb_read(fd, &buffer[0], buffer.size()); 328 if (r <= 0) { 329 if (r == 0) break; 330 SendSyncFailErrno(s, "read failed"); 331 adb_close(fd); 332 return false; 333 } 334 msg.data.size = r; 335 if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) { 336 adb_close(fd); 337 return false; 338 } 339 } 340 341 adb_close(fd); 342 343 msg.data.id = ID_DONE; 344 msg.data.size = 0; 345 return WriteFdExactly(s, &msg.data, sizeof(msg.data)); 346} 347 348static bool handle_sync_command(int fd, std::vector<char>& buffer) { 349 D("sync: waiting for request"); 350 351 SyncRequest request; 352 if (!ReadFdExactly(fd, &request, sizeof(request))) { 353 SendSyncFail(fd, "command read failure"); 354 return false; 355 } 356 size_t path_length = request.path_length; 357 if (path_length > 1024) { 358 SendSyncFail(fd, "path too long"); 359 return false; 360 } 361 char name[1025]; 362 if (!ReadFdExactly(fd, name, path_length)) { 363 SendSyncFail(fd, "filename read failure"); 364 return false; 365 } 366 name[path_length] = 0; 367 368 const char* id = reinterpret_cast<const char*>(&request.id); 369 D("sync: '%.4s' '%s'", id, name); 370 371 switch (request.id) { 372 case ID_STAT: 373 if (!do_stat(fd, name)) return false; 374 break; 375 case ID_LIST: 376 if (!do_list(fd, name)) return false; 377 break; 378 case ID_SEND: 379 if (!do_send(fd, name, buffer)) return false; 380 break; 381 case ID_RECV: 382 if (!do_recv(fd, name, buffer)) return false; 383 break; 384 case ID_QUIT: 385 return false; 386 default: 387 SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", 388 id, request.id)); 389 return false; 390 } 391 392 return true; 393} 394 395void file_sync_service(int fd, void* cookie) { 396 std::vector<char> buffer(SYNC_DATA_MAX); 397 398 while (handle_sync_command(fd, buffer)) { 399 } 400 401 D("sync: done"); 402 adb_close(fd); 403} 404