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:
commit
ba8fc8293f
1 changed files with 86 additions and 104 deletions
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue