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