blob: 7de82b7e8d7ee2dec98ea6e70d80a6aee30ccfb0 [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
Elliott Hughes944e1d72015-01-12 14:26:36 -0800273#if defined(_WIN32)
274extern int handle_send_link(int s, char *path, char *buffer) __attribute__((error("no symlinks on Windows")));
275#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800276static int handle_send_link(int s, char *path, char *buffer)
277{
278 syncmsg msg;
279 unsigned int len;
280 int ret;
281
282 if(readx(s, &msg.data, sizeof(msg.data)))
283 return -1;
284
285 if(msg.data.id != ID_DATA) {
286 fail_message(s, "invalid data message: expected ID_DATA");
287 return -1;
288 }
289
290 len = ltohl(msg.data.size);
291 if(len > SYNC_DATA_MAX) {
292 fail_message(s, "oversize data message");
293 return -1;
294 }
295 if(readx(s, buffer, len))
296 return -1;
297
298 ret = symlink(buffer, path);
299 if(ret && errno == ENOENT) {
Liang Cheng155c49a2014-01-02 18:27:51 -0800300 if(mkdirs(path) != 0) {
301 fail_errno(s);
302 return -1;
303 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800304 ret = symlink(buffer, path);
305 }
306 if(ret) {
307 fail_errno(s);
308 return -1;
309 }
310
311 if(readx(s, &msg.data, sizeof(msg.data)))
312 return -1;
313
314 if(msg.data.id == ID_DONE) {
315 msg.status.id = ID_OKAY;
316 msg.status.msglen = 0;
317 if(writex(s, &msg.status, sizeof(msg.status)))
318 return -1;
319 } else {
320 fail_message(s, "invalid data message: expected ID_DONE");
321 return -1;
322 }
323
324 return 0;
325}
Elliott Hughes944e1d72015-01-12 14:26:36 -0800326#endif
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800327
328static int do_send(int s, char *path, char *buffer)
329{
Liang Cheng155c49a2014-01-02 18:27:51 -0800330 unsigned int mode;
Elliott Hughes944e1d72015-01-12 14:26:36 -0800331 bool is_link = false;
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800332 bool do_unlink;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800333
Elliott Hughes944e1d72015-01-12 14:26:36 -0800334 char* tmp = strrchr(path,',');
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800335 if(tmp) {
336 *tmp = 0;
337 errno = 0;
338 mode = strtoul(tmp + 1, NULL, 0);
Liang Cheng155c49a2014-01-02 18:27:51 -0800339 is_link = S_ISLNK((mode_t) mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800340 mode &= 0777;
341 }
342 if(!tmp || errno) {
343 mode = 0644;
344 is_link = 0;
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800345 do_unlink = true;
JP Abgrall43874fd2013-12-03 14:52:39 -0800346 } else {
347 struct stat st;
348 /* Don't delete files before copying if they are not "regular" */
JP Abgrallbb5f0d22014-03-07 17:31:25 -0800349 do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
350 if (do_unlink) {
JP Abgrall43874fd2013-12-03 14:52:39 -0800351 adb_unlink(path);
352 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800353 }
354
Elliott Hughes944e1d72015-01-12 14:26:36 -0800355 if (is_link) {
356 return handle_send_link(s, path, buffer);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800357 }
358
Elliott Hughes944e1d72015-01-12 14:26:36 -0800359 uid_t uid = -1;
360 gid_t gid = -1;
361 uint64_t cap = 0;
362
363 /* copy user permission bits to "group" and "other" permissions */
364 mode |= ((mode >> 3) & 0070);
365 mode |= ((mode >> 3) & 0007);
366
367 tmp = path;
368 if(*tmp == '/') {
369 tmp++;
370 }
371 if (is_on_system(path) || is_on_vendor(path)) {
372 fs_config(tmp, 0, &uid, &gid, &mode, &cap);
373 }
374 return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800375}
376
377static int do_recv(int s, const char *path, char *buffer)
378{
379 syncmsg msg;
380 int fd, r;
381
Nick Kralevich777523e2014-07-18 20:57:35 -0700382 fd = adb_open(path, O_RDONLY | O_CLOEXEC);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800383 if(fd < 0) {
384 if(fail_errno(s)) return -1;
385 return 0;
386 }
387
388 msg.data.id = ID_DATA;
389 for(;;) {
390 r = adb_read(fd, buffer, SYNC_DATA_MAX);
391 if(r <= 0) {
392 if(r == 0) break;
393 if(errno == EINTR) continue;
394 r = fail_errno(s);
395 adb_close(fd);
396 return r;
397 }
398 msg.data.size = htoll(r);
399 if(writex(s, &msg.data, sizeof(msg.data)) ||
400 writex(s, buffer, r)) {
401 adb_close(fd);
402 return -1;
403 }
404 }
405
406 adb_close(fd);
407
408 msg.data.id = ID_DONE;
409 msg.data.size = 0;
410 if(writex(s, &msg.data, sizeof(msg.data))) {
411 return -1;
412 }
413
414 return 0;
415}
416
417void file_sync_service(int fd, void *cookie)
418{
419 syncmsg msg;
420 char name[1025];
421 unsigned namelen;
422
423 char *buffer = malloc(SYNC_DATA_MAX);
424 if(buffer == 0) goto fail;
425
426 for(;;) {
427 D("sync: waiting for command\n");
428
429 if(readx(fd, &msg.req, sizeof(msg.req))) {
430 fail_message(fd, "command read failure");
431 break;
432 }
433 namelen = ltohl(msg.req.namelen);
434 if(namelen > 1024) {
435 fail_message(fd, "invalid namelen");
436 break;
437 }
438 if(readx(fd, name, namelen)) {
439 fail_message(fd, "filename read failure");
440 break;
441 }
442 name[namelen] = 0;
443
444 msg.req.namelen = 0;
445 D("sync: '%s' '%s'\n", (char*) &msg.req, name);
446
447 switch(msg.req.id) {
448 case ID_STAT:
449 if(do_stat(fd, name)) goto fail;
450 break;
451 case ID_LIST:
452 if(do_list(fd, name)) goto fail;
453 break;
454 case ID_SEND:
455 if(do_send(fd, name, buffer)) goto fail;
456 break;
457 case ID_RECV:
458 if(do_recv(fd, name, buffer)) goto fail;
459 break;
460 case ID_QUIT:
461 goto fail;
462 default:
463 fail_message(fd, "unknown command");
464 goto fail;
465 }
466 }
467
468fail:
469 if(buffer != 0) free(buffer);
470 D("sync: done\n");
471 adb_close(fd);
472}