am d3c72606: Merge "Clean up error handling/reporting in file_sync_service.cpp."

* commit 'd3c726064aa8e676ca4756e8461a5732b16aa7a9':
  Clean up error handling/reporting in file_sync_service.cpp.
This commit is contained in:
Elliott Hughes 2015-08-25 17:50:51 +00:00 committed by Android Git Automerger
commit ba8fc8293f

View file

@ -128,101 +128,89 @@ done:
return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)); 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()); D("sync: failure: %s\n", reason.c_str());
syncmsg msg; syncmsg msg;
msg.data.id = ID_FAIL; msg.data.id = ID_FAIL;
msg.data.size = reason.size(); 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 static bool SendSyncFailErrno(int fd, const std::string& reason) {
// return value (http://b/23437039). return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
static bool fail_errno(int s) {
return fail_message(s, 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<char>& buffer, bool do_unlink) { gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
syncmsg msg; syncmsg msg;
unsigned int timestamp = 0; unsigned int timestamp = 0;
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); 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 (!secure_mkdirs(path)) {
if (fail_errno(s)) return false; SendSyncFailErrno(s, "secure_mkdirs failed");
fd = -1; goto fail;
} else {
fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
} }
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); fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
} }
if(fd < 0) { if (fd < 0) {
if (fail_errno(s)) return false; SendSyncFailErrno(s, "couldn't create file");
fd = -1; goto fail;
} else { } else {
if(fchown(fd, uid, gid) != 0) { if (fchown(fd, uid, gid) == -1) {
fail_errno(s); SendSyncFailErrno(s, "fchown failed");
errno = 0; goto fail;
} }
/* // fchown clears the setuid bit - restore it if present.
* fchown clears the setuid bit - restore it if present. // Ignore the result of calling fchmod. It's not supported
* Ignore the result of calling fchmod. It's not supported // by all filesystems. b/12441485
* by all filesystems. b/12441485
*/
fchmod(fd, mode); fchmod(fd, mode);
} }
while (true) { while (true) {
unsigned int len; unsigned int len;
if(!ReadFdExactly(s, &msg.data, sizeof(msg.data))) if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
goto fail;
if(msg.data.id != ID_DATA) { if (msg.data.id != ID_DATA) {
if(msg.data.id == ID_DONE) { if (msg.data.id == ID_DONE) {
timestamp = msg.data.size; timestamp = msg.data.size;
break; break;
} }
fail_message(s, "invalid data message"); SendSyncFail(s, "invalid data message");
goto fail; goto fail;
} }
len = msg.data.size; len = msg.data.size;
if (len > buffer.size()) { // TODO: resize buffer? if (len > buffer.size()) { // TODO: resize buffer?
fail_message(s, "oversize data message"); SendSyncFail(s, "oversize data message");
goto fail; goto fail;
} }
if (!ReadFdExactly(s, &buffer[0], len)) goto fail; if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
if (fd < 0) continue;
if (!WriteFdExactly(fd, &buffer[0], len)) { if (!WriteFdExactly(fd, &buffer[0], len)) {
int saved_errno = errno; SendSyncFailErrno(s, "write failed");
adb_close(fd); goto fail;
if (do_unlink) adb_unlink(path);
fd = -1;
errno = saved_errno;
if (fail_errno(s)) return false;
} }
} }
if(fd >= 0) { adb_close(fd);
struct utimbuf u;
adb_close(fd);
selinux_android_restorecon(path, 0);
u.actime = timestamp;
u.modtime = timestamp;
utime(path, &u);
msg.status.id = ID_OKAY; selinux_android_restorecon(path, 0);
msg.status.msglen = 0;
if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; utimbuf u;
} u.actime = timestamp;
return true; u.modtime = timestamp;
utime(path, &u);
msg.status.id = ID_OKAY;
msg.status.msglen = 0;
return WriteFdExactly(s, &msg.status, sizeof(msg.status));
fail: fail:
if (fd >= 0) adb_close(fd); if (fd >= 0) adb_close(fd);
@ -231,9 +219,9 @@ fail:
} }
#if defined(_WIN32) #if defined(_WIN32)
extern bool handle_send_link(int s, char *path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows"))); extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
#else #else
static bool handle_send_link(int s, char *path, std::vector<char>& buffer) { static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
syncmsg msg; syncmsg msg;
unsigned int len; unsigned int len;
int ret; int ret;
@ -241,27 +229,27 @@ static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
if (msg.data.id != ID_DATA) { 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; return false;
} }
len = msg.data.size; len = msg.data.size;
if (len > buffer.size()) { // TODO: resize buffer? if (len > buffer.size()) { // TODO: resize buffer?
fail_message(s, "oversize data message"); SendSyncFail(s, "oversize data message");
return false; return false;
} }
if (!ReadFdExactly(s, &buffer[0], len)) 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 (ret && errno == ENOENT) {
if (!secure_mkdirs(path)) { if (!secure_mkdirs(path)) {
fail_errno(s); SendSyncFailErrno(s, "secure_mkdirs failed");
return false; return false;
} }
ret = symlink(&buffer[0], path); ret = symlink(&buffer[0], path.c_str());
} }
if (ret) { if (ret) {
fail_errno(s); SendSyncFailErrno(s, "symlink failed");
return false; return false;
} }
@ -272,7 +260,7 @@ static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
msg.status.msglen = 0; msg.status.msglen = 0;
if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
} else { } else {
fail_message(s, "invalid data message: expected ID_DONE"); SendFail(s, "invalid data message: expected ID_DONE");
return false; return false;
} }
@ -280,59 +268,53 @@ static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
} }
#endif #endif
static bool do_send(int s, char* path, std::vector<char>& buffer) { static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) {
unsigned int mode; // 'spec' is of the form "/some/path,0755". Break it up.
bool is_link = false; size_t comma = spec.find_last_of(',');
bool do_unlink; if (comma == std::string::npos) {
SendFail(s, "missing , in ID_SEND");
char* tmp = strrchr(path,','); return false;
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);
}
} }
if (is_link) { std::string path = spec.substr(0, comma);
return handle_send_link(s, path, buffer);
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; uid_t uid = -1;
gid_t gid = -1; gid_t gid = -1;
uint64_t cap = 0; 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)) { 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<char>& buffer) { static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
int fd = adb_open(path, O_RDONLY | O_CLOEXEC); int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) { if (fd < 0) {
if (fail_errno(s)) return false; SendSyncFailErrno(s, "open failed");
return true; return false;
} }
syncmsg msg; syncmsg msg;
@ -342,9 +324,9 @@ static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
if (r <= 0) { if (r <= 0) {
if (r == 0) break; if (r == 0) break;
if (errno == EINTR) continue; if (errno == EINTR) continue;
bool status = fail_errno(s); SendSyncFailErrno(s, "read failed");
adb_close(fd); adb_close(fd);
return status; return false;
} }
msg.data.size = r; msg.data.size = r;
if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], 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<char>& buffer) {
SyncRequest request; SyncRequest request;
if (!ReadFdExactly(fd, &request, sizeof(request))) { if (!ReadFdExactly(fd, &request, sizeof(request))) {
fail_message(fd, "command read failure"); SendSyncFail(fd, "command read failure");
return false; return false;
} }
size_t path_length = request.path_length; size_t path_length = request.path_length;
if (path_length > 1024) { if (path_length > 1024) {
fail_message(fd, "path too long"); SendSyncFail(fd, "path too long");
return false; return false;
} }
char name[1025]; char name[1025];
if (!ReadFdExactly(fd, name, path_length)) { if (!ReadFdExactly(fd, name, path_length)) {
fail_message(fd, "filename read failure"); SendSyncFail(fd, "filename read failure");
return false; return false;
} }
name[path_length] = 0; name[path_length] = 0;
@ -399,7 +381,7 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) {
case ID_QUIT: case ID_QUIT:
return false; return false;
default: default:
fail_message(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
id, request.id)); id, request.id));
return false; return false;
} }