diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp index 3e4644716..6b5c51ff1 100644 --- a/adb/file_sync_service.cpp +++ b/adb/file_sync_service.cpp @@ -128,101 +128,89 @@ done: return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)); } -static bool fail_message(int s, const std::string& reason) { +static bool SendSyncFail(int fd, const std::string& reason) { D("sync: failure: %s\n", reason.c_str()); syncmsg msg; msg.data.id = ID_FAIL; msg.data.size = reason.size(); - return WriteFdExactly(s, &msg.data, sizeof(msg.data)) && WriteFdExactly(s, reason); + return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason); } -// TODO: callers of this have already failed, and should probably ignore its -// return value (http://b/23437039). -static bool fail_errno(int s) { - return fail_message(s, strerror(errno)); +static bool SendSyncFailErrno(int fd, const std::string& reason) { + return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno))); } -static bool handle_send_file(int s, char *path, uid_t uid, +static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, mode_t mode, std::vector& buffer, bool do_unlink) { syncmsg msg; unsigned int timestamp = 0; int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); - if(fd < 0 && errno == ENOENT) { + if (fd < 0 && errno == ENOENT) { if (!secure_mkdirs(path)) { - if (fail_errno(s)) return false; - fd = -1; - } else { - fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); + SendSyncFailErrno(s, "secure_mkdirs failed"); + goto fail; } + fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); } - if(fd < 0 && errno == EEXIST) { + if (fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode); } - if(fd < 0) { - if (fail_errno(s)) return false; - fd = -1; + if (fd < 0) { + SendSyncFailErrno(s, "couldn't create file"); + goto fail; } else { - if(fchown(fd, uid, gid) != 0) { - fail_errno(s); - errno = 0; + if (fchown(fd, uid, gid) == -1) { + SendSyncFailErrno(s, "fchown failed"); + goto fail; } - /* - * fchown clears the setuid bit - restore it if present. - * Ignore the result of calling fchmod. It's not supported - * by all filesystems. b/12441485 - */ + // fchown clears the setuid bit - restore it if present. + // Ignore the result of calling fchmod. It's not supported + // by all filesystems. b/12441485 fchmod(fd, mode); } while (true) { unsigned int len; - if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) - goto fail; + if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail; - if(msg.data.id != ID_DATA) { - if(msg.data.id == ID_DONE) { + if (msg.data.id != ID_DATA) { + if (msg.data.id == ID_DONE) { timestamp = msg.data.size; break; } - fail_message(s, "invalid data message"); + SendSyncFail(s, "invalid data message"); goto fail; } len = msg.data.size; if (len > buffer.size()) { // TODO: resize buffer? - fail_message(s, "oversize data message"); + SendSyncFail(s, "oversize data message"); goto fail; } + if (!ReadFdExactly(s, &buffer[0], len)) goto fail; - if (fd < 0) continue; - if (!WriteFdExactly(fd, &buffer[0], len)) { - int saved_errno = errno; - adb_close(fd); - if (do_unlink) adb_unlink(path); - fd = -1; - errno = saved_errno; - if (fail_errno(s)) return false; + SendSyncFailErrno(s, "write failed"); + goto fail; } } - if(fd >= 0) { - struct utimbuf u; - adb_close(fd); - selinux_android_restorecon(path, 0); - u.actime = timestamp; - u.modtime = timestamp; - utime(path, &u); + adb_close(fd); - msg.status.id = ID_OKAY; - msg.status.msglen = 0; - if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; - } - return true; + selinux_android_restorecon(path, 0); + + utimbuf u; + u.actime = timestamp; + u.modtime = timestamp; + utime(path, &u); + + msg.status.id = ID_OKAY; + msg.status.msglen = 0; + return WriteFdExactly(s, &msg.status, sizeof(msg.status)); fail: if (fd >= 0) adb_close(fd); @@ -231,9 +219,9 @@ fail: } #if defined(_WIN32) -extern bool handle_send_link(int s, char *path, std::vector& buffer) __attribute__((error("no symlinks on Windows"))); +extern bool handle_send_link(int s, const std::string& path, std::vector& buffer) __attribute__((error("no symlinks on Windows"))); #else -static bool handle_send_link(int s, char *path, std::vector& buffer) { +static bool handle_send_link(int s, const std::string& path, std::vector& buffer) { syncmsg msg; unsigned int len; int ret; @@ -241,27 +229,27 @@ static bool handle_send_link(int s, char *path, std::vector& buffer) { if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; if (msg.data.id != ID_DATA) { - fail_message(s, "invalid data message: expected ID_DATA"); + SendSyncFail(s, "invalid data message: expected ID_DATA"); return false; } len = msg.data.size; if (len > buffer.size()) { // TODO: resize buffer? - fail_message(s, "oversize data message"); + SendSyncFail(s, "oversize data message"); return false; } if (!ReadFdExactly(s, &buffer[0], len)) return false; - ret = symlink(&buffer[0], path); + ret = symlink(&buffer[0], path.c_str()); if (ret && errno == ENOENT) { if (!secure_mkdirs(path)) { - fail_errno(s); + SendSyncFailErrno(s, "secure_mkdirs failed"); return false; } - ret = symlink(&buffer[0], path); + ret = symlink(&buffer[0], path.c_str()); } if (ret) { - fail_errno(s); + SendSyncFailErrno(s, "symlink failed"); return false; } @@ -272,7 +260,7 @@ static bool handle_send_link(int s, char *path, std::vector& buffer) { msg.status.msglen = 0; if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; } else { - fail_message(s, "invalid data message: expected ID_DONE"); + SendFail(s, "invalid data message: expected ID_DONE"); return false; } @@ -280,59 +268,53 @@ static bool handle_send_link(int s, char *path, std::vector& buffer) { } #endif -static bool do_send(int s, char* path, std::vector& buffer) { - unsigned int mode; - bool is_link = false; - bool do_unlink; - - char* tmp = strrchr(path,','); - if(tmp) { - *tmp = 0; - errno = 0; - mode = strtoul(tmp + 1, NULL, 0); - is_link = S_ISLNK((mode_t) mode); - mode &= 0777; - } - if(!tmp || errno) { - mode = 0644; - is_link = 0; - do_unlink = true; - } else { - struct stat st; - /* Don't delete files before copying if they are not "regular" */ - do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); - if (do_unlink) { - adb_unlink(path); - } +static bool do_send(int s, const std::string& spec, std::vector& buffer) { + // 'spec' is of the form "/some/path,0755". Break it up. + size_t comma = spec.find_last_of(','); + if (comma == std::string::npos) { + SendFail(s, "missing , in ID_SEND"); + return false; } - if (is_link) { - return handle_send_link(s, path, buffer); + std::string path = spec.substr(0, comma); + + errno = 0; + mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0); + if (errno != 0) { + SendFail(s, "bad mode"); + return false; } + // Don't delete files before copying if they are not "regular" or symlinks. + struct stat st; + bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); + if (do_unlink) { + adb_unlink(path.c_str()); + } + + if (S_ISLNK(mode)) { + return handle_send_link(s, path.c_str(), buffer); + } + + // Copy user permission bits to "group" and "other" permissions. + mode &= 0777; + mode |= ((mode >> 3) & 0070); + mode |= ((mode >> 3) & 0007); + uid_t uid = -1; gid_t gid = -1; uint64_t cap = 0; - - /* copy user permission bits to "group" and "other" permissions */ - mode |= ((mode >> 3) & 0070); - mode |= ((mode >> 3) & 0007); - - tmp = path; - if(*tmp == '/') { - tmp++; - } if (should_use_fs_config(path)) { - fs_config(tmp, 0, &uid, &gid, &mode, &cap); + fs_config(path.c_str(), 0, &uid, &gid, &mode, &cap); } - return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); + return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink); } static bool do_recv(int s, const char* path, std::vector& buffer) { int fd = adb_open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { - if (fail_errno(s)) return false; - return true; + SendSyncFailErrno(s, "open failed"); + return false; } syncmsg msg; @@ -342,9 +324,9 @@ static bool do_recv(int s, const char* path, std::vector& buffer) { if (r <= 0) { if (r == 0) break; if (errno == EINTR) continue; - bool status = fail_errno(s); + SendSyncFailErrno(s, "read failed"); adb_close(fd); - return status; + return false; } msg.data.size = r; if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) { @@ -365,17 +347,17 @@ static bool handle_sync_command(int fd, std::vector& buffer) { SyncRequest request; if (!ReadFdExactly(fd, &request, sizeof(request))) { - fail_message(fd, "command read failure"); + SendSyncFail(fd, "command read failure"); return false; } size_t path_length = request.path_length; if (path_length > 1024) { - fail_message(fd, "path too long"); + SendSyncFail(fd, "path too long"); return false; } char name[1025]; if (!ReadFdExactly(fd, name, path_length)) { - fail_message(fd, "filename read failure"); + SendSyncFail(fd, "filename read failure"); return false; } name[path_length] = 0; @@ -399,7 +381,7 @@ static bool handle_sync_command(int fd, std::vector& buffer) { case ID_QUIT: return false; default: - fail_message(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", + SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id)); return false; }