file_sync_service.c revision 35237d135807af84bf9b0e5b8d7f8633e58db6f5
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <dirent.h>
24#include <utime.h>
25
26#include <errno.h>
27
28#include "sysdeps.h"
29
30#define TRACE_TAG  TRACE_SYNC
31#include "adb.h"
32#include "file_sync_service.h"
33
34static int mkdirs(char *name)
35{
36    int ret;
37    char *x = name + 1;
38
39    if(name[0] != '/') return -1;
40
41    for(;;) {
42        x = adb_dirstart(x);
43        if(x == 0) return 0;
44        *x = 0;
45        ret = adb_mkdir(name, 0775);
46        if((ret < 0) && (errno != EEXIST)) {
47            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
48            *x = '/';
49            return ret;
50        }
51        *x++ = '/';
52    }
53    return 0;
54}
55
56static int do_stat(int s, const char *path)
57{
58    syncmsg msg;
59    struct stat st;
60
61    msg.stat.id = ID_STAT;
62
63    if(lstat(path, &st)) {
64        msg.stat.mode = 0;
65        msg.stat.size = 0;
66        msg.stat.time = 0;
67    } else {
68        msg.stat.mode = htoll(st.st_mode);
69        msg.stat.size = htoll(st.st_size);
70        msg.stat.time = htoll(st.st_mtime);
71    }
72
73    return writex(s, &msg.stat, sizeof(msg.stat));
74}
75
76static int do_list(int s, const char *path)
77{
78    DIR *d;
79    struct dirent *de;
80    struct stat st;
81    syncmsg msg;
82    int len;
83
84    char tmp[1024 + 256 + 1];
85    char *fname;
86
87    len = strlen(path);
88    memcpy(tmp, path, len);
89    tmp[len] = '/';
90    fname = tmp + len + 1;
91
92    msg.dent.id = ID_DENT;
93
94    d = opendir(path);
95    if(d == 0) goto done;
96
97    while((de = readdir(d))) {
98        int len = strlen(de->d_name);
99
100            /* not supposed to be possible, but
101               if it does happen, let's not buffer overrun */
102        if(len > 256) continue;
103
104        strcpy(fname, de->d_name);
105        if(lstat(tmp, &st) == 0) {
106            msg.dent.mode = htoll(st.st_mode);
107            msg.dent.size = htoll(st.st_size);
108            msg.dent.time = htoll(st.st_mtime);
109            msg.dent.namelen = htoll(len);
110
111            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
112               writex(s, de->d_name, len)) {
113                return -1;
114            }
115        }
116    }
117
118    closedir(d);
119
120done:
121    msg.dent.id = ID_DONE;
122    msg.dent.mode = 0;
123    msg.dent.size = 0;
124    msg.dent.time = 0;
125    msg.dent.namelen = 0;
126    return writex(s, &msg.dent, sizeof(msg.dent));
127}
128
129static int fail_message(int s, const char *reason)
130{
131    syncmsg msg;
132    int len = strlen(reason);
133
134    D("sync: failure: %s\n", reason);
135
136    msg.data.id = ID_FAIL;
137    msg.data.size = htoll(len);
138    if(writex(s, &msg.data, sizeof(msg.data)) ||
139       writex(s, reason, len)) {
140        return -1;
141    } else {
142        return 0;
143    }
144}
145
146static int fail_errno(int s)
147{
148    return fail_message(s, strerror(errno));
149}
150
151static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
152{
153    syncmsg msg;
154    unsigned int timestamp = 0;
155    int fd;
156
157    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
158    if(fd < 0 && errno == ENOENT) {
159        mkdirs(path);
160        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
161    }
162    if(fd < 0 && errno == EEXIST) {
163        fd = adb_open_mode(path, O_WRONLY, mode);
164    }
165    if(fd < 0) {
166        if(fail_errno(s))
167            return -1;
168        fd = -1;
169    }
170
171    for(;;) {
172        unsigned int len;
173
174        if(readx(s, &msg.data, sizeof(msg.data)))
175            goto fail;
176
177        if(msg.data.id != ID_DATA) {
178            if(msg.data.id == ID_DONE) {
179                timestamp = ltohl(msg.data.size);
180                break;
181            }
182            fail_message(s, "invalid data message");
183            goto fail;
184        }
185        len = ltohl(msg.data.size);
186        if(len > SYNC_DATA_MAX) {
187            fail_message(s, "oversize data message");
188            goto fail;
189        }
190        if(readx(s, buffer, len))
191            goto fail;
192
193        if(fd < 0)
194            continue;
195        if(writex(fd, buffer, len)) {
196            adb_close(fd);
197            adb_unlink(path);
198            fd = -1;
199            if(fail_errno(s)) return -1;
200        }
201    }
202
203    if(fd >= 0) {
204        struct utimbuf u;
205        adb_close(fd);
206        u.actime = timestamp;
207        u.modtime = timestamp;
208        utime(path, &u);
209
210        msg.status.id = ID_OKAY;
211        msg.status.msglen = 0;
212        if(writex(s, &msg.status, sizeof(msg.status)))
213            return -1;
214    }
215    return 0;
216
217fail:
218    if(fd >= 0)
219        adb_close(fd);
220    adb_unlink(path);
221    return -1;
222}
223
224#ifdef HAVE_SYMLINKS
225static int handle_send_link(int s, char *path, char *buffer)
226{
227    syncmsg msg;
228    unsigned int len;
229    int ret;
230
231    if(readx(s, &msg.data, sizeof(msg.data)))
232        return -1;
233
234    if(msg.data.id != ID_DATA) {
235        fail_message(s, "invalid data message: expected ID_DATA");
236        return -1;
237    }
238
239    len = ltohl(msg.data.size);
240    if(len > SYNC_DATA_MAX) {
241        fail_message(s, "oversize data message");
242        return -1;
243    }
244    if(readx(s, buffer, len))
245        return -1;
246
247    ret = symlink(buffer, path);
248    if(ret && errno == ENOENT) {
249        mkdirs(path);
250        ret = symlink(buffer, path);
251    }
252    if(ret) {
253        fail_errno(s);
254        return -1;
255    }
256
257    if(readx(s, &msg.data, sizeof(msg.data)))
258        return -1;
259
260    if(msg.data.id == ID_DONE) {
261        msg.status.id = ID_OKAY;
262        msg.status.msglen = 0;
263        if(writex(s, &msg.status, sizeof(msg.status)))
264            return -1;
265    } else {
266        fail_message(s, "invalid data message: expected ID_DONE");
267        return -1;
268    }
269
270    return 0;
271}
272#endif /* HAVE_SYMLINKS */
273
274static int do_send(int s, char *path, char *buffer)
275{
276    char *tmp;
277    mode_t mode;
278    int is_link, ret;
279
280    tmp = strrchr(path,',');
281    if(tmp) {
282        *tmp = 0;
283        errno = 0;
284        mode = strtoul(tmp + 1, NULL, 0);
285#ifndef HAVE_SYMLINKS
286        is_link = 0;
287#else
288        is_link = S_ISLNK(mode);
289#endif
290        mode &= 0777;
291    }
292    if(!tmp || errno) {
293        mode = 0644;
294        is_link = 0;
295    }
296
297    adb_unlink(path);
298
299
300#ifdef HAVE_SYMLINKS
301    if(is_link)
302        ret = handle_send_link(s, path, buffer);
303    else {
304#else
305    {
306#endif
307        /* copy user permission bits to "group" and "other" permissions */
308        mode |= ((mode >> 3) & 0070);
309        mode |= ((mode >> 3) & 0007);
310
311        ret = handle_send_file(s, path, mode, buffer);
312    }
313
314    return ret;
315}
316
317static int do_recv(int s, const char *path, char *buffer)
318{
319    syncmsg msg;
320    int fd, r;
321
322    fd = adb_open(path, O_RDONLY);
323    if(fd < 0) {
324        if(fail_errno(s)) return -1;
325        return 0;
326    }
327
328    msg.data.id = ID_DATA;
329    for(;;) {
330        r = adb_read(fd, buffer, SYNC_DATA_MAX);
331        if(r <= 0) {
332            if(r == 0) break;
333            if(errno == EINTR) continue;
334            r = fail_errno(s);
335            adb_close(fd);
336            return r;
337        }
338        msg.data.size = htoll(r);
339        if(writex(s, &msg.data, sizeof(msg.data)) ||
340           writex(s, buffer, r)) {
341            adb_close(fd);
342            return -1;
343        }
344    }
345
346    adb_close(fd);
347
348    msg.data.id = ID_DONE;
349    msg.data.size = 0;
350    if(writex(s, &msg.data, sizeof(msg.data))) {
351        return -1;
352    }
353
354    return 0;
355}
356
357void file_sync_service(int fd, void *cookie)
358{
359    syncmsg msg;
360    char name[1025];
361    unsigned namelen;
362
363    char *buffer = malloc(SYNC_DATA_MAX);
364    if(buffer == 0) goto fail;
365
366    for(;;) {
367        D("sync: waiting for command\n");
368
369        if(readx(fd, &msg.req, sizeof(msg.req))) {
370            fail_message(fd, "command read failure");
371            break;
372        }
373        namelen = ltohl(msg.req.namelen);
374        if(namelen > 1024) {
375            fail_message(fd, "invalid namelen");
376            break;
377        }
378        if(readx(fd, name, namelen)) {
379            fail_message(fd, "filename read failure");
380            break;
381        }
382        name[namelen] = 0;
383
384        msg.req.namelen = 0;
385        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
386
387        switch(msg.req.id) {
388        case ID_STAT:
389            if(do_stat(fd, name)) goto fail;
390            break;
391        case ID_LIST:
392            if(do_list(fd, name)) goto fail;
393            break;
394        case ID_SEND:
395            if(do_send(fd, name, buffer)) goto fail;
396            break;
397        case ID_RECV:
398            if(do_recv(fd, name, buffer)) goto fail;
399            break;
400        case ID_QUIT:
401            goto fail;
402        default:
403            fail_message(fd, "unknown command");
404            goto fail;
405        }
406    }
407
408fail:
409    if(buffer != 0) free(buffer);
410    D("sync: done\n");
411    adb_close(fd);
412}
413