blob: 79338585167d44aa02f350e986b5a6d6a83f4b1d [file] [log] [blame]
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001/*
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>
Liang Cheng155c49a2014-01-02 18:27:51 -080025#include <unistd.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026
27#include <errno.h>
Liang Cheng155c49a2014-01-02 18:27:51 -080028#include <private/android_filesystem_config.h>
29#include <selinux/android.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030#include "sysdeps.h"
31
32#define TRACE_TAG TRACE_SYNC
33#include "adb.h"
34#include "file_sync_service.h"
35
Liang Cheng155c49a2014-01-02 18:27:51 -080036/* TODO: use fs_config to configure permissions on /data */
37static bool is_on_system(const char *name) {
38 const char *SYSTEM = "/system/";
39 return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
40}
41
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -070042static bool is_on_vendor(const char *name) {
43 const char *VENDOR = "/vendor/";
44 return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
45}
46
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080047static int mkdirs(char *name)
48{
49 int ret;
50 char *x = name + 1;
Nick Kralevich29e78132014-01-17 16:16:42 -080051 uid_t uid = -1;
52 gid_t gid = -1;
Liang Cheng155c49a2014-01-02 18:27:51 -080053 unsigned int mode = 0775;
54 uint64_t cap = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080055
56 if(name[0] != '/') return -1;
57
58 for(;;) {
59 x = adb_dirstart(x);
60 if(x == 0) return 0;
61 *x = 0;
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -070062 if (is_on_system(name) || is_on_vendor(name)) {
Liang Cheng155c49a2014-01-02 18:27:51 -080063 fs_config(name, 1, &uid, &gid, &mode, &cap);
64 }
65 ret = adb_mkdir(name, mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080066 if((ret < 0) && (errno != EEXIST)) {
67 D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
68 *x = '/';
69 return ret;
Liang Cheng155c49a2014-01-02 18:27:51 -080070 } else if(ret == 0) {
71 ret = chown(name, uid, gid);
72 if (ret < 0) {
73 *x = '/';
74 return ret;
75 }
Stephen Smalley3392e9c2014-02-07 09:14:13 -050076 selinux_android_restorecon(name, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080077 }
78 *x++ = '/';
79 }
80 return 0;
81}
82
83static int do_stat(int s, const char *path)
84{
85 syncmsg msg;
86 struct stat st;
87
88 msg.stat.id = ID_STAT;
89
90 if(lstat(path, &st)) {
91 msg.stat.mode = 0;
92 msg.stat.size = 0;
93 msg.stat.time = 0;
94 } else {
95 msg.stat.mode = htoll(st.st_mode);
96 msg.stat.size = htoll(st.st_size);
97 msg.stat.time = htoll(st.st_mtime);
98 }
99
100 return writex(s, &msg.stat, sizeof(msg.stat));
101}
102
103static int do_list(int s, const char *path)
104{
105 DIR *d;
106 struct dirent *de;
107 struct stat st;
108 syncmsg msg;
109 int len;
110
111 char tmp[1024 + 256 + 1];
112 char *fname;
113
114 len = strlen(path);
115 memcpy(tmp, path, len);
116 tmp[len] = '/';
117 fname = tmp + len + 1;
118
119 msg.dent.id = ID_DENT;
120
121 d = opendir(path);
122 if(d == 0) goto done;
123
124 while((de = readdir(d))) {
125 int len = strlen(de->d_name);
126
127 /* not supposed to be possible, but
128 if it does happen, let's not buffer overrun */
129 if(len > 256) continue;
130
131 strcpy(fname, de->d_name);
132 if(lstat(tmp, &st) == 0) {
133 msg.dent.mode = htoll(st.st_mode);
134 msg.dent.size = htoll(st.st_size);
135 msg.dent.time = htoll(st.st_mtime);
136 msg.dent.namelen = htoll(len);
137
138 if(writex(s, &msg.dent, sizeof(msg.dent)) ||
139 writex(s, de->d_name, len)) {
Elliott Hughes968b6a72013-10-29 14:12:46 -0700140 closedir(d);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800141 return -1;
142 }
143 }
144 }
145
146 closedir(d);
147
148done:
149 msg.dent.id = ID_DONE;
150 msg.dent.mode = 0;
151 msg.dent.size = 0;
152 msg.dent.time = 0;
153 msg.dent.namelen = 0;
154 return writex(s, &msg.dent, sizeof(msg.dent));
155}
156
157static int fail_message(int s, const char *reason)
158{
159 syncmsg msg;
160 int len = strlen(reason);
161
162 D("sync: failure: %s\n", reason);
163
164 msg.data.id = ID_FAIL;
165 msg.data.size = htoll(len);
166 if(writex(s, &msg.data, sizeof(msg.data)) ||
167 writex(s, reason, len)) {
168 return -1;
169 } else {
170 return 0;
171 }
172}
173
174static int fail_errno(int s)
175{
176 return fail_message(s, strerror(errno));
177}
178
Nick Kralevich29e78132014-01-17 16:16:42 -0800179static int handle_send_file(int s, char *path, uid_t uid,
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800180 gid_t gid, mode_t mode, char *buffer, bool do_unlink)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800181{
182 syncmsg msg;
183 unsigned int timestamp = 0;
184 int fd;
185
Nick Kralevich777523e2014-07-18 20:57:35 -0700186 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800187 if(fd < 0 && errno == ENOENT) {
Liang Cheng155c49a2014-01-02 18:27:51 -0800188 if(mkdirs(path) != 0) {
189 if(fail_errno(s))
190 return -1;
191 fd = -1;
192 } else {
Nick Kralevich777523e2014-07-18 20:57:35 -0700193 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
Liang Cheng155c49a2014-01-02 18:27:51 -0800194 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800195 }
196 if(fd < 0 && errno == EEXIST) {
Nick Kralevich777523e2014-07-18 20:57:35 -0700197 fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800198 }
199 if(fd < 0) {
200 if(fail_errno(s))
201 return -1;
202 fd = -1;
Liang Cheng155c49a2014-01-02 18:27:51 -0800203 } else {
204 if(fchown(fd, uid, gid) != 0) {
205 fail_errno(s);
206 errno = 0;
207 }
Nick Kralevich29e78132014-01-17 16:16:42 -0800208
209 /*
210 * fchown clears the setuid bit - restore it if present.
211 * Ignore the result of calling fchmod. It's not supported
212 * by all filesystems. b/12441485
213 */
214 fchmod(fd, mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800215 }
216
217 for(;;) {
218 unsigned int len;
219
220 if(readx(s, &msg.data, sizeof(msg.data)))
221 goto fail;
222
223 if(msg.data.id != ID_DATA) {
224 if(msg.data.id == ID_DONE) {
225 timestamp = ltohl(msg.data.size);
226 break;
227 }
228 fail_message(s, "invalid data message");
229 goto fail;
230 }
231 len = ltohl(msg.data.size);
232 if(len > SYNC_DATA_MAX) {
233 fail_message(s, "oversize data message");
234 goto fail;
235 }
236 if(readx(s, buffer, len))
237 goto fail;
238
239 if(fd < 0)
240 continue;
241 if(writex(fd, buffer, len)) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700242 int saved_errno = errno;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800243 adb_close(fd);
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800244 if (do_unlink) adb_unlink(path);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800245 fd = -1;
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700246 errno = saved_errno;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800247 if(fail_errno(s)) return -1;
248 }
249 }
250
251 if(fd >= 0) {
252 struct utimbuf u;
253 adb_close(fd);
Stephen Smalley3392e9c2014-02-07 09:14:13 -0500254 selinux_android_restorecon(path, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800255 u.actime = timestamp;
256 u.modtime = timestamp;
257 utime(path, &u);
258
259 msg.status.id = ID_OKAY;
260 msg.status.msglen = 0;
261 if(writex(s, &msg.status, sizeof(msg.status)))
262 return -1;
263 }
264 return 0;
265
266fail:
267 if(fd >= 0)
268 adb_close(fd);
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800269 if (do_unlink) adb_unlink(path);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800270 return -1;
271}
272
273#ifdef HAVE_SYMLINKS
274static int handle_send_link(int s, char *path, char *buffer)
275{
276 syncmsg msg;
277 unsigned int len;
278 int ret;
279
280 if(readx(s, &msg.data, sizeof(msg.data)))
281 return -1;
282
283 if(msg.data.id != ID_DATA) {
284 fail_message(s, "invalid data message: expected ID_DATA");
285 return -1;
286 }
287
288 len = ltohl(msg.data.size);
289 if(len > SYNC_DATA_MAX) {
290 fail_message(s, "oversize data message");
291 return -1;
292 }
293 if(readx(s, buffer, len))
294 return -1;
295
296 ret = symlink(buffer, path);
297 if(ret && errno == ENOENT) {
Liang Cheng155c49a2014-01-02 18:27:51 -0800298 if(mkdirs(path) != 0) {
299 fail_errno(s);
300 return -1;
301 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800302 ret = symlink(buffer, path);
303 }
304 if(ret) {
305 fail_errno(s);
306 return -1;
307 }
308
309 if(readx(s, &msg.data, sizeof(msg.data)))
310 return -1;
311
312 if(msg.data.id == ID_DONE) {
313 msg.status.id = ID_OKAY;
314 msg.status.msglen = 0;
315 if(writex(s, &msg.status, sizeof(msg.status)))
316 return -1;
317 } else {
318 fail_message(s, "invalid data message: expected ID_DONE");
319 return -1;
320 }
321
322 return 0;
323}
324#endif /* HAVE_SYMLINKS */
325
326static int do_send(int s, char *path, char *buffer)
327{
328 char *tmp;
Liang Cheng155c49a2014-01-02 18:27:51 -0800329 unsigned int mode;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800330 int is_link, ret;
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800331 bool do_unlink;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800332
333 tmp = strrchr(path,',');
334 if(tmp) {
335 *tmp = 0;
336 errno = 0;
337 mode = strtoul(tmp + 1, NULL, 0);
338#ifndef HAVE_SYMLINKS
339 is_link = 0;
340#else
Liang Cheng155c49a2014-01-02 18:27:51 -0800341 is_link = S_ISLNK((mode_t) mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800342#endif
343 mode &= 0777;
344 }
345 if(!tmp || errno) {
346 mode = 0644;
347 is_link = 0;
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800348 do_unlink = true;
JP Abgrall43874fd2013-12-03 14:52:39 -0800349 } else {
350 struct stat st;
351 /* Don't delete files before copying if they are not "regular" */
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800352 do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
353 if (do_unlink) {
JP Abgrall43874fd2013-12-03 14:52:39 -0800354 adb_unlink(path);
355 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800356 }
357
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800358#ifdef HAVE_SYMLINKS
359 if(is_link)
360 ret = handle_send_link(s, path, buffer);
361 else {
362#else
363 {
364#endif
Nick Kralevich29e78132014-01-17 16:16:42 -0800365 uid_t uid = -1;
366 gid_t gid = -1;
Liang Cheng155c49a2014-01-02 18:27:51 -0800367 uint64_t cap = 0;
Liang Cheng155c49a2014-01-02 18:27:51 -0800368
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800369 /* copy user permission bits to "group" and "other" permissions */
370 mode |= ((mode >> 3) & 0070);
371 mode |= ((mode >> 3) & 0007);
372
Liang Cheng155c49a2014-01-02 18:27:51 -0800373 tmp = path;
374 if(*tmp == '/') {
375 tmp++;
376 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700377 if (is_on_system(path) || is_on_vendor(path)) {
Liang Cheng155c49a2014-01-02 18:27:51 -0800378 fs_config(tmp, 0, &uid, &gid, &mode, &cap);
379 }
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800380 ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800381 }
382
383 return ret;
384}
385
386static int do_recv(int s, const char *path, char *buffer)
387{
388 syncmsg msg;
389 int fd, r;
390
Nick Kralevich777523e2014-07-18 20:57:35 -0700391 fd = adb_open(path, O_RDONLY | O_CLOEXEC);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800392 if(fd < 0) {
393 if(fail_errno(s)) return -1;
394 return 0;
395 }
396
397 msg.data.id = ID_DATA;
398 for(;;) {
399 r = adb_read(fd, buffer, SYNC_DATA_MAX);
400 if(r <= 0) {
401 if(r == 0) break;
402 if(errno == EINTR) continue;
403 r = fail_errno(s);
404 adb_close(fd);
405 return r;
406 }
407 msg.data.size = htoll(r);
408 if(writex(s, &msg.data, sizeof(msg.data)) ||
409 writex(s, buffer, r)) {
410 adb_close(fd);
411 return -1;
412 }
413 }
414
415 adb_close(fd);
416
417 msg.data.id = ID_DONE;
418 msg.data.size = 0;
419 if(writex(s, &msg.data, sizeof(msg.data))) {
420 return -1;
421 }
422
423 return 0;
424}
425
426void file_sync_service(int fd, void *cookie)
427{
428 syncmsg msg;
429 char name[1025];
430 unsigned namelen;
431
432 char *buffer = malloc(SYNC_DATA_MAX);
433 if(buffer == 0) goto fail;
434
435 for(;;) {
436 D("sync: waiting for command\n");
437
438 if(readx(fd, &msg.req, sizeof(msg.req))) {
439 fail_message(fd, "command read failure");
440 break;
441 }
442 namelen = ltohl(msg.req.namelen);
443 if(namelen > 1024) {
444 fail_message(fd, "invalid namelen");
445 break;
446 }
447 if(readx(fd, name, namelen)) {
448 fail_message(fd, "filename read failure");
449 break;
450 }
451 name[namelen] = 0;
452
453 msg.req.namelen = 0;
454 D("sync: '%s' '%s'\n", (char*) &msg.req, name);
455
456 switch(msg.req.id) {
457 case ID_STAT:
458 if(do_stat(fd, name)) goto fail;
459 break;
460 case ID_LIST:
461 if(do_list(fd, name)) goto fail;
462 break;
463 case ID_SEND:
464 if(do_send(fd, name, buffer)) goto fail;
465 break;
466 case ID_RECV:
467 if(do_recv(fd, name, buffer)) goto fail;
468 break;
469 case ID_QUIT:
470 goto fail;
471 default:
472 fail_message(fd, "unknown command");
473 goto fail;
474 }
475 }
476
477fail:
478 if(buffer != 0) free(buffer);
479 D("sync: done\n");
480 adb_close(fd);
481}