123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- /*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <utime.h>
- #include <errno.h>
- #include "sysdeps.h"
- #define TRACE_TAG TRACE_SYNC
- #include "adb.h"
- #include "file_sync_service.h"
- static int mkdirs(char *name)
- {
- int ret;
- char *x = name + 1;
- if(name[0] != '/') return -1;
- for(;;) {
- x = adb_dirstart(x);
- if(x == 0) return 0;
- *x = 0;
- ret = adb_mkdir(name, 0775);
- if((ret < 0) && (errno != EEXIST)) {
- D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
- *x = '/';
- return ret;
- }
- *x++ = '/';
- }
- return 0;
- }
- static int do_stat(int s, const char *path)
- {
- syncmsg msg;
- struct stat st;
- msg.stat.id = ID_STAT;
- if(lstat(path, &st)) {
- msg.stat.mode = 0;
- msg.stat.size = 0;
- msg.stat.time = 0;
- } else {
- msg.stat.mode = htoll(st.st_mode);
- msg.stat.size = htoll(st.st_size);
- msg.stat.time = htoll(st.st_mtime);
- }
- return writex(s, &msg.stat, sizeof(msg.stat));
- }
- static int do_list(int s, const char *path)
- {
- DIR *d;
- struct dirent *de;
- struct stat st;
- syncmsg msg;
- int len;
- char tmp[1024 + 256 + 1];
- char *fname;
- len = strlen(path);
- memcpy(tmp, path, len);
- tmp[len] = '/';
- fname = tmp + len + 1;
- msg.dent.id = ID_DENT;
- d = opendir(path);
- if(d == 0) goto done;
- while((de = readdir(d))) {
- int len = strlen(de->d_name);
- /* not supposed to be possible, but
- if it does happen, let's not buffer overrun */
- if(len > 256) continue;
- strcpy(fname, de->d_name);
- if(lstat(tmp, &st) == 0) {
- msg.dent.mode = htoll(st.st_mode);
- msg.dent.size = htoll(st.st_size);
- msg.dent.time = htoll(st.st_mtime);
- msg.dent.namelen = htoll(len);
- if(writex(s, &msg.dent, sizeof(msg.dent)) ||
- writex(s, de->d_name, len)) {
- closedir(d);
- return -1;
- }
- }
- }
- closedir(d);
- done:
- msg.dent.id = ID_DONE;
- msg.dent.mode = 0;
- msg.dent.size = 0;
- msg.dent.time = 0;
- msg.dent.namelen = 0;
- return writex(s, &msg.dent, sizeof(msg.dent));
- }
- static int fail_message(int s, const char *reason)
- {
- syncmsg msg;
- int len = strlen(reason);
- D("sync: failure: %s\n", reason);
- msg.data.id = ID_FAIL;
- msg.data.size = htoll(len);
- if(writex(s, &msg.data, sizeof(msg.data)) ||
- writex(s, reason, len)) {
- return -1;
- } else {
- return 0;
- }
- }
- static int fail_errno(int s)
- {
- return fail_message(s, strerror(errno));
- }
- static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
- {
- syncmsg msg;
- unsigned int timestamp = 0;
- int fd;
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
- if(fd < 0 && errno == ENOENT) {
- mkdirs(path);
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
- }
- if(fd < 0 && errno == EEXIST) {
- fd = adb_open_mode(path, O_WRONLY, mode);
- }
- if(fd < 0) {
- if(fail_errno(s))
- return -1;
- fd = -1;
- }
- for(;;) {
- unsigned int len;
- if(readx(s, &msg.data, sizeof(msg.data)))
- goto fail;
- if(msg.data.id != ID_DATA) {
- if(msg.data.id == ID_DONE) {
- timestamp = ltohl(msg.data.size);
- break;
- }
- fail_message(s, "invalid data message");
- goto fail;
- }
- len = ltohl(msg.data.size);
- if(len > SYNC_DATA_MAX) {
- fail_message(s, "oversize data message");
- goto fail;
- }
- if(readx(s, buffer, len))
- goto fail;
- if(fd < 0)
- continue;
- if(writex(fd, buffer, len)) {
- int saved_errno = errno;
- adb_close(fd);
- adb_unlink(path);
- fd = -1;
- errno = saved_errno;
- if(fail_errno(s)) return -1;
- }
- }
- if(fd >= 0) {
- struct utimbuf u;
- adb_close(fd);
- u.actime = timestamp;
- u.modtime = timestamp;
- utime(path, &u);
- msg.status.id = ID_OKAY;
- msg.status.msglen = 0;
- if(writex(s, &msg.status, sizeof(msg.status)))
- return -1;
- }
- return 0;
- fail:
- if(fd >= 0)
- adb_close(fd);
- adb_unlink(path);
- return -1;
- }
- #ifdef HAVE_SYMLINKS
- static int handle_send_link(int s, char *path, char *buffer)
- {
- syncmsg msg;
- unsigned int len;
- int ret;
- if(readx(s, &msg.data, sizeof(msg.data)))
- return -1;
- if(msg.data.id != ID_DATA) {
- fail_message(s, "invalid data message: expected ID_DATA");
- return -1;
- }
- len = ltohl(msg.data.size);
- if(len > SYNC_DATA_MAX) {
- fail_message(s, "oversize data message");
- return -1;
- }
- if(readx(s, buffer, len))
- return -1;
- ret = symlink(buffer, path);
- if(ret && errno == ENOENT) {
- mkdirs(path);
- ret = symlink(buffer, path);
- }
- if(ret) {
- fail_errno(s);
- return -1;
- }
- if(readx(s, &msg.data, sizeof(msg.data)))
- return -1;
- if(msg.data.id == ID_DONE) {
- msg.status.id = ID_OKAY;
- msg.status.msglen = 0;
- if(writex(s, &msg.status, sizeof(msg.status)))
- return -1;
- } else {
- fail_message(s, "invalid data message: expected ID_DONE");
- return -1;
- }
- return 0;
- }
- #endif /* HAVE_SYMLINKS */
- static int do_send(int s, char *path, char *buffer)
- {
- char *tmp;
- mode_t mode;
- int is_link, ret;
- tmp = strrchr(path,',');
- if(tmp) {
- *tmp = 0;
- errno = 0;
- mode = strtoul(tmp + 1, NULL, 0);
- #ifndef HAVE_SYMLINKS
- is_link = 0;
- #else
- is_link = S_ISLNK(mode);
- #endif
- mode &= 0777;
- }
- if(!tmp || errno) {
- mode = 0644;
- is_link = 0;
- }
- adb_unlink(path);
- #ifdef HAVE_SYMLINKS
- if(is_link)
- ret = handle_send_link(s, path, buffer);
- else {
- #else
- {
- #endif
- /* copy user permission bits to "group" and "other" permissions */
- mode |= ((mode >> 3) & 0070);
- mode |= ((mode >> 3) & 0007);
- ret = handle_send_file(s, path, mode, buffer);
- }
- return ret;
- }
- static int do_recv(int s, const char *path, char *buffer)
- {
- syncmsg msg;
- int fd, r;
- fd = adb_open(path, O_RDONLY);
- if(fd < 0) {
- if(fail_errno(s)) return -1;
- return 0;
- }
- msg.data.id = ID_DATA;
- for(;;) {
- r = adb_read(fd, buffer, SYNC_DATA_MAX);
- if(r <= 0) {
- if(r == 0) break;
- if(errno == EINTR) continue;
- r = fail_errno(s);
- adb_close(fd);
- return r;
- }
- msg.data.size = htoll(r);
- if(writex(s, &msg.data, sizeof(msg.data)) ||
- writex(s, buffer, r)) {
- adb_close(fd);
- return -1;
- }
- }
- adb_close(fd);
- msg.data.id = ID_DONE;
- msg.data.size = 0;
- if(writex(s, &msg.data, sizeof(msg.data))) {
- return -1;
- }
- return 0;
- }
- void file_sync_service(int fd, void *cookie)
- {
- syncmsg msg;
- char name[1025];
- unsigned namelen;
- char *buffer = malloc(SYNC_DATA_MAX);
- if(buffer == 0) goto fail;
- for(;;) {
- D("sync: waiting for command\n");
- if(readx(fd, &msg.req, sizeof(msg.req))) {
- fail_message(fd, "command read failure");
- break;
- }
- namelen = ltohl(msg.req.namelen);
- if(namelen > 1024) {
- fail_message(fd, "invalid namelen");
- break;
- }
- if(readx(fd, name, namelen)) {
- fail_message(fd, "filename read failure");
- break;
- }
- name[namelen] = 0;
- msg.req.namelen = 0;
- D("sync: '%s' '%s'\n", (char*) &msg.req, name);
- switch(msg.req.id) {
- case ID_STAT:
- if(do_stat(fd, name)) goto fail;
- break;
- case ID_LIST:
- if(do_list(fd, name)) goto fail;
- break;
- case ID_SEND:
- if(do_send(fd, name, buffer)) goto fail;
- break;
- case ID_RECV:
- if(do_recv(fd, name, buffer)) goto fail;
- break;
- case ID_QUIT:
- goto fail;
- default:
- fail_message(fd, "unknown command");
- goto fail;
- }
- }
- fail:
- if(buffer != 0) free(buffer);
- D("sync: done\n");
- adb_close(fd);
- }
|