file_sync_service.c

来自「Android 一些工具」· C语言 代码 · 共 413 行

C
413
字号
/* * 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)) {                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)) {            adb_close(fd);            adb_unlink(path);            fd = -1;            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_SYMLINKSstatic 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);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?