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            int saved_errno = errno;
197            adb_close(fd);
198            adb_unlink(path);
199            fd = -1;
200            errno = saved_errno;
201            if(fail_errno(s)) return -1;
202        }
203    }
204
205    if(fd >= 0) {
206        struct utimbuf u;
207        adb_close(fd);
208        u.actime = timestamp;
209        u.modtime = timestamp;
210        utime(path, &u);
211
212        msg.status.id = ID_OKAY;
213        msg.status.msglen = 0;
214        if(writex(s, &msg.status, sizeof(msg.status)))
215            return -1;
216    }
217    return 0;
218
219fail:
220    if(fd >= 0)
221        adb_close(fd);
222    adb_unlink(path);
223    return -1;
224}
225
226#ifdef HAVE_SYMLINKS
227static int handle_send_link(int s, char *path, char *buffer)
228{
229    syncmsg msg;
230    unsigned int len;
231    int ret;
232
233    if(readx(s, &msg.data, sizeof(msg.data)))
234        return -1;
235
236    if(msg.data.id != ID_DATA) {
237        fail_message(s, "invalid data message: expected ID_DATA");
238        return -1;
239    }
240
241    len = ltohl(msg.data.size);
242    if(len > SYNC_DATA_MAX) {
243        fail_message(s, "oversize data message");
244        return -1;
245    }
246    if(readx(s, buffer, len))
247        return -1;
248
249    ret = symlink(buffer, path);
250    if(ret && errno == ENOENT) {
251        mkdirs(path);
252        ret = symlink(buffer, path);
253    }
254    if(ret) {
255        fail_errno(s);
256        return -1;
257    }
258
259    if(readx(s, &msg.data, sizeof(msg.data)))
260        return -1;
261
262    if(msg.data.id == ID_DONE) {
263        msg.status.id = ID_OKAY;
264        msg.status.msglen = 0;
265        if(writex(s, &msg.status, sizeof(msg.status)))
266            return -1;
267    } else {
268        fail_message(s, "invalid data message: expected ID_DONE");
269        return -1;
270    }
271
272    return 0;
273}
274#endif /* HAVE_SYMLINKS */
275
276static int do_send(int s, char *path, char *buffer)
277{
278    char *tmp;
279    mode_t mode;
280    int is_link, ret;
281
282    tmp = strrchr(path,',');
283    if(tmp) {
284        *tmp = 0;
285        errno = 0;
286        mode = strtoul(tmp + 1, NULL, 0);
287#ifndef HAVE_SYMLINKS
288        is_link = 0;
289#else
290        is_link = S_ISLNK(mode);
291#endif
292        mode &= 0777;
293    }
294    if(!tmp || errno) {
295        mode = 0644;
296        is_link = 0;
297    }
298
299    adb_unlink(path);
300
301
302#ifdef HAVE_SYMLINKS
303    if(is_link)
304        ret = handle_send_link(s, path, buffer);
305    else {
306#else
307    {
308#endif
309        /* copy user permission bits to "group" and "other" permissions */
310        mode |= ((mode >> 3) & 0070);
311        mode |= ((mode >> 3) & 0007);
312
313        ret = handle_send_file(s, path, mode, buffer);
314    }
315
316    return ret;
317}
318
319static int do_recv(int s, const char *path, char *buffer)
320{
321    syncmsg msg;
322    int fd, r;
323
324    fd = adb_open(path, O_RDONLY);
325    if(fd < 0) {
326        if(fail_errno(s)) return -1;
327        return 0;
328    }
329
330    msg.data.id = ID_DATA;
331    for(;;) {
332        r = adb_read(fd, buffer, SYNC_DATA_MAX);
333        if(r <= 0) {
334            if(r == 0) break;
335            if(errno == EINTR) continue;
336            r = fail_errno(s);
337            adb_close(fd);
338            return r;
339        }
340        msg.data.size = htoll(r);
341        if(writex(s, &msg.data, sizeof(msg.data)) ||
342           writex(s, buffer, r)) {
343            adb_close(fd);
344            return -1;
345        }
346    }
347
348    adb_close(fd);
349
350    msg.data.id = ID_DONE;
351    msg.data.size = 0;
352    if(writex(s, &msg.data, sizeof(msg.data))) {
353        return -1;
354    }
355
356    return 0;
357}
358
359void file_sync_service(int fd, void *cookie)
360{
361    syncmsg msg;
362    char name[1025];
363    unsigned namelen;
364
365    char *buffer = malloc(SYNC_DATA_MAX);
366    if(buffer == 0) goto fail;
367
368    for(;;) {
369        D("sync: waiting for command\n");
370
371        if(readx(fd, &msg.req, sizeof(msg.req))) {
372            fail_message(fd, "command read failure");
373            break;
374        }
375        namelen = ltohl(msg.req.namelen);
376        if(namelen > 1024) {
377            fail_message(fd, "invalid namelen");
378            break;
379        }
380        if(readx(fd, name, namelen)) {
381            fail_message(fd, "filename read failure");
382            break;
383        }
384        name[namelen] = 0;
385
386        msg.req.namelen = 0;
387        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
388
389        switch(msg.req.id) {
390        case ID_STAT:
391            if(do_stat(fd, name)) goto fail;
392            break;
393        case ID_LIST:
394            if(do_list(fd, name)) goto fail;
395            break;
396        case ID_SEND:
397            if(do_send(fd, name, buffer)) goto fail;
398            break;
399        case ID_RECV:
400            if(do_recv(fd, name, buffer)) goto fail;
401            break;
402        case ID_QUIT:
403            goto fail;
404        default:
405            fail_message(fd, "unknown command");
406            goto fail;
407        }
408    }
409
410fail:
411    if(buffer != 0) free(buffer);
412    D("sync: done\n");
413    adb_close(fd);
414}
415