file_sync_service.c revision 4ce2f838e78592d0b93776b73ca4de855a423dde
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#include <unistd.h> 26 27#include <errno.h> 28#include <private/android_filesystem_config.h> 29#include <selinux/android.h> 30#include "sysdeps.h" 31 32#define TRACE_TAG TRACE_SYNC 33#include "adb.h" 34#include "file_sync_service.h" 35 36/* 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 42static int mkdirs(char *name) 43{ 44 int ret; 45 char *x = name + 1; 46 uid_t uid = -1; 47 gid_t gid = -1; 48 unsigned int mode = 0775; 49 uint64_t cap = 0; 50 51 if(name[0] != '/') return -1; 52 53 for(;;) { 54 x = adb_dirstart(x); 55 if(x == 0) return 0; 56 *x = 0; 57 if (is_on_system(name)) { 58 fs_config(name, 1, &uid, &gid, &mode, &cap); 59 } 60 ret = adb_mkdir(name, mode); 61 if((ret < 0) && (errno != EEXIST)) { 62 D("mkdir(\"%s\") -> %s\n", name, strerror(errno)); 63 *x = '/'; 64 return ret; 65 } else if(ret == 0) { 66 ret = chown(name, uid, gid); 67 if (ret < 0) { 68 *x = '/'; 69 return ret; 70 } 71 selinux_android_restorecon(name, 0); 72 } 73 *x++ = '/'; 74 } 75 return 0; 76} 77 78static int do_stat(int s, const char *path) 79{ 80 syncmsg msg; 81 struct stat st; 82 83 msg.stat.id = ID_STAT; 84 85 if(lstat(path, &st)) { 86 msg.stat.mode = 0; 87 msg.stat.size = 0; 88 msg.stat.time = 0; 89 } else { 90 msg.stat.mode = htoll(st.st_mode); 91 msg.stat.size = htoll(st.st_size); 92 msg.stat.time = htoll(st.st_mtime); 93 } 94 95 return writex(s, &msg.stat, sizeof(msg.stat)); 96} 97 98static int do_list(int s, const char *path) 99{ 100 DIR *d; 101 struct dirent *de; 102 struct stat st; 103 syncmsg msg; 104 int len; 105 106 char tmp[1024 + 256 + 1]; 107 char *fname; 108 109 len = strlen(path); 110 memcpy(tmp, path, len); 111 tmp[len] = '/'; 112 fname = tmp + len + 1; 113 114 msg.dent.id = ID_DENT; 115 116 d = opendir(path); 117 if(d == 0) goto done; 118 119 while((de = readdir(d))) { 120 int len = strlen(de->d_name); 121 122 /* not supposed to be possible, but 123 if it does happen, let's not buffer overrun */ 124 if(len > 256) continue; 125 126 strcpy(fname, de->d_name); 127 if(lstat(tmp, &st) == 0) { 128 msg.dent.mode = htoll(st.st_mode); 129 msg.dent.size = htoll(st.st_size); 130 msg.dent.time = htoll(st.st_mtime); 131 msg.dent.namelen = htoll(len); 132 133 if(writex(s, &msg.dent, sizeof(msg.dent)) || 134 writex(s, de->d_name, len)) { 135 closedir(d); 136 return -1; 137 } 138 } 139 } 140 141 closedir(d); 142 143done: 144 msg.dent.id = ID_DONE; 145 msg.dent.mode = 0; 146 msg.dent.size = 0; 147 msg.dent.time = 0; 148 msg.dent.namelen = 0; 149 return writex(s, &msg.dent, sizeof(msg.dent)); 150} 151 152static int fail_message(int s, const char *reason) 153{ 154 syncmsg msg; 155 int len = strlen(reason); 156 157 D("sync: failure: %s\n", reason); 158 159 msg.data.id = ID_FAIL; 160 msg.data.size = htoll(len); 161 if(writex(s, &msg.data, sizeof(msg.data)) || 162 writex(s, reason, len)) { 163 return -1; 164 } else { 165 return 0; 166 } 167} 168 169static int fail_errno(int s) 170{ 171 return fail_message(s, strerror(errno)); 172} 173 174static int handle_send_file(int s, char *path, uid_t uid, 175 gid_t gid, mode_t mode, char *buffer) 176{ 177 syncmsg msg; 178 unsigned int timestamp = 0; 179 int fd; 180 181 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); 182 if(fd < 0 && errno == ENOENT) { 183 if(mkdirs(path) != 0) { 184 if(fail_errno(s)) 185 return -1; 186 fd = -1; 187 } else { 188 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); 189 } 190 } 191 if(fd < 0 && errno == EEXIST) { 192 fd = adb_open_mode(path, O_WRONLY, mode); 193 } 194 if(fd < 0) { 195 if(fail_errno(s)) 196 return -1; 197 fd = -1; 198 } else { 199 if(fchown(fd, uid, gid) != 0) { 200 fail_errno(s); 201 errno = 0; 202 } 203 204 /* 205 * fchown clears the setuid bit - restore it if present. 206 * Ignore the result of calling fchmod. It's not supported 207 * by all filesystems. b/12441485 208 */ 209 fchmod(fd, mode); 210 } 211 212 for(;;) { 213 unsigned int len; 214 215 if(readx(s, &msg.data, sizeof(msg.data))) 216 goto fail; 217 218 if(msg.data.id != ID_DATA) { 219 if(msg.data.id == ID_DONE) { 220 timestamp = ltohl(msg.data.size); 221 break; 222 } 223 fail_message(s, "invalid data message"); 224 goto fail; 225 } 226 len = ltohl(msg.data.size); 227 if(len > SYNC_DATA_MAX) { 228 fail_message(s, "oversize data message"); 229 goto fail; 230 } 231 if(readx(s, buffer, len)) 232 goto fail; 233 234 if(fd < 0) 235 continue; 236 if(writex(fd, buffer, len)) { 237 int saved_errno = errno; 238 adb_close(fd); 239 adb_unlink(path); 240 fd = -1; 241 errno = saved_errno; 242 if(fail_errno(s)) return -1; 243 } 244 } 245 246 if(fd >= 0) { 247 struct utimbuf u; 248 adb_close(fd); 249 selinux_android_restorecon(path, 0); 250 u.actime = timestamp; 251 u.modtime = timestamp; 252 utime(path, &u); 253 254 msg.status.id = ID_OKAY; 255 msg.status.msglen = 0; 256 if(writex(s, &msg.status, sizeof(msg.status))) 257 return -1; 258 } 259 return 0; 260 261fail: 262 if(fd >= 0) 263 adb_close(fd); 264 adb_unlink(path); 265 return -1; 266} 267 268#ifdef HAVE_SYMLINKS 269static int handle_send_link(int s, char *path, char *buffer) 270{ 271 syncmsg msg; 272 unsigned int len; 273 int ret; 274 275 if(readx(s, &msg.data, sizeof(msg.data))) 276 return -1; 277 278 if(msg.data.id != ID_DATA) { 279 fail_message(s, "invalid data message: expected ID_DATA"); 280 return -1; 281 } 282 283 len = ltohl(msg.data.size); 284 if(len > SYNC_DATA_MAX) { 285 fail_message(s, "oversize data message"); 286 return -1; 287 } 288 if(readx(s, buffer, len)) 289 return -1; 290 291 ret = symlink(buffer, path); 292 if(ret && errno == ENOENT) { 293 if(mkdirs(path) != 0) { 294 fail_errno(s); 295 return -1; 296 } 297 ret = symlink(buffer, path); 298 } 299 if(ret) { 300 fail_errno(s); 301 return -1; 302 } 303 304 if(readx(s, &msg.data, sizeof(msg.data))) 305 return -1; 306 307 if(msg.data.id == ID_DONE) { 308 msg.status.id = ID_OKAY; 309 msg.status.msglen = 0; 310 if(writex(s, &msg.status, sizeof(msg.status))) 311 return -1; 312 } else { 313 fail_message(s, "invalid data message: expected ID_DONE"); 314 return -1; 315 } 316 317 return 0; 318} 319#endif /* HAVE_SYMLINKS */ 320 321static int do_send(int s, char *path, char *buffer) 322{ 323 char *tmp; 324 unsigned int mode; 325 int is_link, ret; 326 327 tmp = strrchr(path,','); 328 if(tmp) { 329 *tmp = 0; 330 errno = 0; 331 mode = strtoul(tmp + 1, NULL, 0); 332#ifndef HAVE_SYMLINKS 333 is_link = 0; 334#else 335 is_link = S_ISLNK((mode_t) mode); 336#endif 337 mode &= 0777; 338 } 339 if(!tmp || errno) { 340 mode = 0644; 341 is_link = 0; 342 } else { 343 struct stat st; 344 /* Don't delete files before copying if they are not "regular" */ 345 if(lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 346 adb_unlink(path); 347 } 348 } 349 350#ifdef HAVE_SYMLINKS 351 if(is_link) 352 ret = handle_send_link(s, path, buffer); 353 else { 354#else 355 { 356#endif 357 uid_t uid = -1; 358 gid_t gid = -1; 359 uint64_t cap = 0; 360 361 /* copy user permission bits to "group" and "other" permissions */ 362 mode |= ((mode >> 3) & 0070); 363 mode |= ((mode >> 3) & 0007); 364 365 tmp = path; 366 if(*tmp == '/') { 367 tmp++; 368 } 369 if (is_on_system(path)) { 370 fs_config(tmp, 0, &uid, &gid, &mode, &cap); 371 } 372 ret = handle_send_file(s, path, uid, gid, mode, buffer); 373 } 374 375 return ret; 376} 377 378static int do_recv(int s, const char *path, char *buffer) 379{ 380 syncmsg msg; 381 int fd, r; 382 383 fd = adb_open(path, O_RDONLY); 384 if(fd < 0) { 385 if(fail_errno(s)) return -1; 386 return 0; 387 } 388 389 msg.data.id = ID_DATA; 390 for(;;) { 391 r = adb_read(fd, buffer, SYNC_DATA_MAX); 392 if(r <= 0) { 393 if(r == 0) break; 394 if(errno == EINTR) continue; 395 r = fail_errno(s); 396 adb_close(fd); 397 return r; 398 } 399 msg.data.size = htoll(r); 400 if(writex(s, &msg.data, sizeof(msg.data)) || 401 writex(s, buffer, r)) { 402 adb_close(fd); 403 return -1; 404 } 405 } 406 407 adb_close(fd); 408 409 msg.data.id = ID_DONE; 410 msg.data.size = 0; 411 if(writex(s, &msg.data, sizeof(msg.data))) { 412 return -1; 413 } 414 415 return 0; 416} 417 418void file_sync_service(int fd, void *cookie) 419{ 420 syncmsg msg; 421 char name[1025]; 422 unsigned namelen; 423 424 char *buffer = malloc(SYNC_DATA_MAX); 425 if(buffer == 0) goto fail; 426 427 for(;;) { 428 D("sync: waiting for command\n"); 429 430 if(readx(fd, &msg.req, sizeof(msg.req))) { 431 fail_message(fd, "command read failure"); 432 break; 433 } 434 namelen = ltohl(msg.req.namelen); 435 if(namelen > 1024) { 436 fail_message(fd, "invalid namelen"); 437 break; 438 } 439 if(readx(fd, name, namelen)) { 440 fail_message(fd, "filename read failure"); 441 break; 442 } 443 name[namelen] = 0; 444 445 msg.req.namelen = 0; 446 D("sync: '%s' '%s'\n", (char*) &msg.req, name); 447 448 switch(msg.req.id) { 449 case ID_STAT: 450 if(do_stat(fd, name)) goto fail; 451 break; 452 case ID_LIST: 453 if(do_list(fd, name)) goto fail; 454 break; 455 case ID_SEND: 456 if(do_send(fd, name, buffer)) goto fail; 457 break; 458 case ID_RECV: 459 if(do_recv(fd, name, buffer)) goto fail; 460 break; 461 case ID_QUIT: 462 goto fail; 463 default: 464 fail_message(fd, "unknown command"); 465 goto fail; 466 } 467 } 468 469fail: 470 if(buffer != 0) free(buffer); 471 D("sync: done\n"); 472 adb_close(fd); 473} 474