blob: ab11619fbd1baaf1a0f9049c7ed8103bc487f5a7 [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
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070028#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080029
Elliott Hughes4e7848d2015-08-24 14:49:43 -070030#include <memory>
31
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080032#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080033
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080034#include "adb.h"
35#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080036#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040037#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080038#include "file_sync_service.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080039
Elliott Hughesb628cb12015-08-03 10:38:08 -070040#include <base/strings.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070041#include <base/stringprintf.h>
42
Elliott Hughesb628cb12015-08-03 10:38:08 -070043struct syncsendbuf {
44 unsigned id;
45 unsigned size;
46 char data[SYNC_DATA_MAX];
47};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080048
Elliott Hughesb628cb12015-08-03 10:38:08 -070049static syncsendbuf send_buffer;
50
51static long long NOW() {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080052 struct timeval tv;
53 gettimeofday(&tv, 0);
Elliott Hughesb628cb12015-08-03 10:38:08 -070054 return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080055}
56
Spencer Low803451e2015-05-13 00:02:55 -070057static void print_transfer_progress(uint64_t bytes_current,
58 uint64_t bytes_total) {
Mark Lindner9f9d1452014-03-11 17:55:59 -070059 if (bytes_total == 0) return;
60
Spencer Low803451e2015-05-13 00:02:55 -070061 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
62 bytes_current, bytes_total,
Mark Lindner9f9d1452014-03-11 17:55:59 -070063 (int) (bytes_current * 100 / bytes_total));
64
65 if (bytes_current == bytes_total) {
66 fputc('\n', stderr);
67 }
68
69 fflush(stderr);
70}
71
Elliott Hughesb628cb12015-08-03 10:38:08 -070072static bool SendRequest(int fd, int id, const char* path) {
73 size_t path_length = strlen(path);
74 if (path_length > 1024) {
75 fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
76 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080077 }
78
Elliott Hughesb628cb12015-08-03 10:38:08 -070079 // Sending header and payload in a single write makes a noticeable
80 // difference to "adb sync" performance.
81 char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
82 SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
83 req->id = id;
Elliott Hughes9e8e3552015-08-24 14:27:03 -070084 req->path_length = path_length;
Elliott Hughesb628cb12015-08-03 10:38:08 -070085 char* data = reinterpret_cast<char*>(req + 1);
86 memcpy(data, path, path_length);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080087
Elliott Hughesb628cb12015-08-03 10:38:08 -070088 return WriteFdExactly(fd, buf, sizeof(buf));
89}
90
91class SyncConnection {
92 public:
93 SyncConnection() : total_bytes(0), start_time_(NOW()) {
94 max = SYNC_DATA_MAX; // TODO: decide at runtime.
95
96 std::string error;
97 fd = adb_connect("sync:", &error);
98 if (fd < 0) {
99 fprintf(stderr, "error: %s\n", error.c_str());
100 }
101 }
102
103 ~SyncConnection() {
104 if (!IsValid()) return;
105
106 SendQuit();
107 ShowTransferRate();
108 adb_close(fd);
109 }
110
111 bool IsValid() { return fd >= 0; }
112
113 uint64_t total_bytes;
114
115 // TODO: add a char[max] buffer here, to replace syncsendbuf...
116 int fd;
117 size_t max;
118
119 private:
120 uint64_t start_time_;
121
122 void SendQuit() {
123 SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
124 }
125
126 void ShowTransferRate() {
127 uint64_t t = NOW() - start_time_;
128 if (total_bytes == 0 || t == 0) return;
129
130 fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
131 ((total_bytes * 1000000LL) / t) / 1024LL,
132 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
133 }
134};
135
136typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
137
138static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
139 if (!SendRequest(fd, ID_LIST, path)) return false;
140
141 while (true) {
142 syncmsg msg;
143 if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
144
145 if (msg.dent.id == ID_DONE) return true;
146 if (msg.dent.id != ID_DENT) return false;
147
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700148 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700149 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800150
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700151 char buf[257];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700152 if (!ReadFdExactly(fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800153 buf[len] = 0;
154
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700155 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800156 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800157}
158
Elliott Hughesb628cb12015-08-03 10:38:08 -0700159static bool sync_start_stat(SyncConnection& sc, const char* path) {
160 return SendRequest(sc.fd, ID_STAT, path);
161}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800162
Elliott Hughesb628cb12015-08-03 10:38:08 -0700163static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
164 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800165 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700166 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
167 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800168 }
169
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700170 if (timestamp) *timestamp = msg.stat.time;
171 if (mode) *mode = msg.stat.mode;
172 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800173
Elliott Hughesb628cb12015-08-03 10:38:08 -0700174 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800175}
176
Elliott Hughesb628cb12015-08-03 10:38:08 -0700177static bool sync_stat(SyncConnection& sc, const char* path,
178 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
179 return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800180}
181
Elliott Hughesb628cb12015-08-03 10:38:08 -0700182static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
183 int err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700184 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800185
Elliott Hughesb628cb12015-08-03 10:38:08 -0700186 int lfd = adb_open(path, O_RDONLY);
187 if (lfd < 0) {
188 fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800189 return -1;
190 }
191
Mark Lindner9f9d1452014-03-11 17:55:59 -0700192 if (show_progress) {
193 // Determine local file size.
194 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800195 if (stat(path, &st)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700196 fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
Mark Lindner9f9d1452014-03-11 17:55:59 -0700197 return -1;
198 }
199
200 size = st.st_size;
201 }
202
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800203 sbuf->id = ID_DATA;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700204 while (true) {
205 int ret = adb_read(lfd, sbuf->data, sc.max);
206 if (!ret)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800207 break;
208
Elliott Hughesb628cb12015-08-03 10:38:08 -0700209 if (ret < 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800210 if(errno == EINTR)
211 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700212 fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800213 break;
214 }
215
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700216 sbuf->size = ret;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700217 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800218 err = -1;
219 break;
220 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700221 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700222
223 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700224 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700225 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800226 }
227
228 adb_close(lfd);
229 return err;
230}
231
Elliott Hughes944e1d72015-01-12 14:26:36 -0800232#if defined(_WIN32)
Elliott Hughesb628cb12015-08-03 10:38:08 -0700233extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
Elliott Hughes944e1d72015-01-12 14:26:36 -0800234#else
Elliott Hughesb628cb12015-08-03 10:38:08 -0700235static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
236 ssize_t len = readlink(path, sbuf->data, sc.max - 1);
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700237 if (len < 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800238 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
239 return -1;
240 }
241 sbuf->data[len] = '\0';
242
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700243 sbuf->size = len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800244 sbuf->id = ID_DATA;
245
Elliott Hughesb628cb12015-08-03 10:38:08 -0700246 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800247 return -1;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700248 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800249
Elliott Hughesb628cb12015-08-03 10:38:08 -0700250 sc.total_bytes += len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800251
252 return 0;
253}
254#endif
255
Elliott Hughesb628cb12015-08-03 10:38:08 -0700256static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
257 unsigned mtime, mode_t mode, bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800258{
Elliott Hughesb628cb12015-08-03 10:38:08 -0700259 syncsendbuf* sbuf = &send_buffer;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800260
Elliott Hughesb628cb12015-08-03 10:38:08 -0700261 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
262 if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800263
Elliott Hughesb628cb12015-08-03 10:38:08 -0700264 if (S_ISREG(mode)) {
265 write_data_file(sc, lpath, sbuf, show_progress);
266 } else if (S_ISLNK(mode)) {
267 write_data_link(sc, lpath, sbuf);
268 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800269 goto fail;
270 }
271
Elliott Hughesb628cb12015-08-03 10:38:08 -0700272 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800273 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700274 msg.data.size = mtime;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700275 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800276
Elliott Hughesb628cb12015-08-03 10:38:08 -0700277 if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800278
Elliott Hughesb628cb12015-08-03 10:38:08 -0700279 if (msg.status.id != ID_OKAY) {
280 if (msg.status.id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700281 size_t len = msg.status.msglen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700282 if (len > 256) len = 256;
283 if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800284 sbuf->data[len] = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700285 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800286 strcpy(sbuf->data, "unknown reason");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700287 }
288 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
289 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800290 }
291
Elliott Hughesb628cb12015-08-03 10:38:08 -0700292 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800293
294fail:
Elliott Hughesb628cb12015-08-03 10:38:08 -0700295 fprintf(stderr, "protocol failure\n");
296 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800297}
298
Elliott Hughesb628cb12015-08-03 10:38:08 -0700299static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800300 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800301 int lfd = -1;
302 char *buffer = send_buffer.data;
303 unsigned id;
304
Elliott Hughesb628cb12015-08-03 10:38:08 -0700305 size_t len = strlen(rpath);
306 if (len > 1024) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800307
Elliott Hughesb628cb12015-08-03 10:38:08 -0700308 unsigned size = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700309 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700310 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700311 }
312
Elliott Hughesb628cb12015-08-03 10:38:08 -0700313 if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
314 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800315
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800316 id = msg.data.id;
317
Elliott Hughesb628cb12015-08-03 10:38:08 -0700318 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800319 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700320 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800321 lfd = adb_creat(lpath, 0644);
322 if(lfd < 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700323 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800324 return -1;
325 }
326 goto handle_data;
327 } else {
328 goto remote_error;
329 }
330
Elliott Hughesb628cb12015-08-03 10:38:08 -0700331 while (true) {
332 if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800333 return -1;
334 }
335 id = msg.data.id;
336
337 handle_data:
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700338 len = msg.data.size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700339 if (id == ID_DONE) break;
340 if (id != ID_DATA) goto remote_error;
341 if (len > sc.max) {
342 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800343 adb_close(lfd);
344 return -1;
345 }
346
Elliott Hughesb628cb12015-08-03 10:38:08 -0700347 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800348 adb_close(lfd);
349 return -1;
350 }
351
Dan Albert66a91b02015-02-24 21:26:58 -0800352 if(!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700353 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800354 adb_close(lfd);
355 return -1;
356 }
357
Elliott Hughesb628cb12015-08-03 10:38:08 -0700358 sc.total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700359
360 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700361 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700362 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800363 }
364
365 adb_close(lfd);
366 return 0;
367
368remote_error:
369 adb_close(lfd);
370 adb_unlink(lpath);
371
372 if(id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700373 len = msg.data.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800374 if(len > 256) len = 256;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700375 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800376 return -1;
377 }
378 buffer[len] = 0;
379 } else {
380 memcpy(buffer, &id, 4);
381 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800382 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700383 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800384 return 0;
385}
386
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800387static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700388 const char* name, void* /*cookie*/) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800389 printf("%08x %08x %08x %s\n", mode, size, time, name);
390}
391
Elliott Hughesb628cb12015-08-03 10:38:08 -0700392bool do_sync_ls(const char* path) {
393 SyncConnection sc;
394 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800395
Elliott Hughesb628cb12015-08-03 10:38:08 -0700396 return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800397}
398
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800399struct copyinfo
400{
401 copyinfo *next;
402 const char *src;
403 const char *dst;
404 unsigned int time;
405 unsigned int mode;
406 unsigned int size;
407 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800408};
409
Elliott Hughes712416a2015-05-05 18:26:10 -0700410static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800411 int slen = strlen(spath);
412 int dlen = strlen(dpath);
413 int nlen = strlen(name);
414 int ssize = slen + nlen + 2;
415 int dsize = dlen + nlen + 2;
416
Elliott Hughes712416a2015-05-05 18:26:10 -0700417 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800418 if(ci == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700419 fprintf(stderr, "out of memory\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800420 abort();
421 }
422
423 ci->next = 0;
424 ci->time = 0;
425 ci->mode = 0;
426 ci->size = 0;
427 ci->flag = 0;
428 ci->src = (const char*)(ci + 1);
429 ci->dst = ci->src + ssize;
430 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
431 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
432
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800433 return ci;
434}
435
Elliott Hughesb628cb12015-08-03 10:38:08 -0700436static bool IsDotOrDotDot(const char* name) {
437 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
438}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800439
Elliott Hughesb628cb12015-08-03 10:38:08 -0700440static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800441 copyinfo *dirlist = 0;
442 copyinfo *ci, *next;
443
Elliott Hughesb628cb12015-08-03 10:38:08 -0700444 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
445 if (!dir) {
446 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800447 return -1;
448 }
449
Elliott Hughesb628cb12015-08-03 10:38:08 -0700450 dirent *de;
451 while ((de = readdir(dir.get()))) {
452 if (IsDotOrDotDot(de->d_name)) continue;
453
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454 char stat_path[PATH_MAX];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700455 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
456 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800457 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700458 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800459 strcpy(stat_path, lpath);
460 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800461
Elliott Hughesb628cb12015-08-03 10:38:08 -0700462 struct stat st;
463 if (!lstat(stat_path, &st)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700464 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700465 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700466 ci->next = dirlist;
467 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800468 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700469 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
470 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700471 fprintf(stderr, "skipping special file '%s'\n", ci->src);
472 free(ci);
473 } else {
474 ci->time = st.st_mtime;
475 ci->mode = st.st_mode;
476 ci->size = st.st_size;
477 ci->next = *filelist;
478 *filelist = ci;
479 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800480 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700481 } else {
482 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800483 }
484 }
485
Elliott Hughesb628cb12015-08-03 10:38:08 -0700486 // Close this directory and recurse.
487 dir.reset();
488 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800489 next = ci->next;
490 local_build_list(filelist, ci->src, ci->dst);
491 free(ci);
492 }
493
494 return 0;
495}
496
Elliott Hughesb628cb12015-08-03 10:38:08 -0700497static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
498 bool check_timestamps, bool list_only) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800499 copyinfo *filelist = 0;
500 copyinfo *ci, *next;
501 int pushed = 0;
502 int skipped = 0;
503
Elliott Hughesb628cb12015-08-03 10:38:08 -0700504 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
505 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800506 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800507 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700508 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800509 snprintf(tmp, tmplen, "%s/",lpath);
510 lpath = tmp;
511 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700512 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800513 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800514 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700515 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800516 snprintf(tmp, tmplen, "%s/",rpath);
517 rpath = tmp;
518 }
519
Elliott Hughesb628cb12015-08-03 10:38:08 -0700520 if (local_build_list(&filelist, lpath, rpath)) {
521 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800522 }
523
Elliott Hughesb628cb12015-08-03 10:38:08 -0700524 if (check_timestamps) {
525 for (ci = filelist; ci != 0; ci = ci->next) {
526 if (!sync_start_stat(sc, ci->dst)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800527 }
528 for(ci = filelist; ci != 0; ci = ci->next) {
529 unsigned int timestamp, mode, size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700530 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
531 if (size == ci->size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800532 /* for links, we cannot update the atime/mtime */
Elliott Hughesb628cb12015-08-03 10:38:08 -0700533 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
534 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800535 ci->flag = 1;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700536 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800537 }
538 }
539 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700540 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800541 next = ci->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700542 if (ci->flag == 0) {
543 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
544 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
545 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800546 }
547 pushed++;
548 } else {
549 skipped++;
550 }
551 free(ci);
552 }
553
Elliott Hughesb628cb12015-08-03 10:38:08 -0700554 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800555 pushed, (pushed == 1) ? "" : "s",
556 skipped, (skipped == 1) ? "" : "s");
557
Elliott Hughesb628cb12015-08-03 10:38:08 -0700558 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800559}
560
Elliott Hughesb628cb12015-08-03 10:38:08 -0700561bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
562 SyncConnection sc;
563 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800564
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700565 struct stat st;
566 if (stat(lpath, &st)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700567 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
568 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800569 }
570
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700571 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700572 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800573 }
574
Elliott Hughesb628cb12015-08-03 10:38:08 -0700575 unsigned mode;
576 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
577 std::string path_holder;
578 if (mode != 0 && S_ISDIR(mode)) {
579 // If we're copying a local file to a remote directory,
580 // we really want to copy to remote_dir + "/" + local_filename.
581 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
582 rpath = path_holder.c_str();
583 }
584 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800585}
586
587
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700588struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800589 copyinfo **filelist;
590 copyinfo **dirlist;
591 const char *rpath;
592 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700593};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800594
Elliott Hughes712416a2015-05-05 18:26:10 -0700595static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
596 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800597{
598 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
599 copyinfo *ci;
600
601 if (S_ISDIR(mode)) {
602 copyinfo **dirlist = args->dirlist;
603
Elliott Hughesb628cb12015-08-03 10:38:08 -0700604 // Don't try recursing down "." or "..".
605 if (IsDotOrDotDot(name)) return;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800606
607 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
608 ci->next = *dirlist;
609 *dirlist = ci;
610 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
611 copyinfo **filelist = args->filelist;
612
613 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
614 ci->time = time;
615 ci->mode = mode;
616 ci->size = size;
617 ci->next = *filelist;
618 *filelist = ci;
619 } else {
620 fprintf(stderr, "skipping special file '%s'\n", name);
621 }
622}
623
Elliott Hughesb628cb12015-08-03 10:38:08 -0700624static bool remote_build_list(int syncfd, copyinfo **filelist,
625 const char *rpath, const char *lpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800626 copyinfo *dirlist = NULL;
627 sync_ls_build_list_cb_args args;
628
629 args.filelist = filelist;
630 args.dirlist = &dirlist;
631 args.rpath = rpath;
632 args.lpath = lpath;
633
Elliott Hughesb628cb12015-08-03 10:38:08 -0700634 // Put the files/dirs in rpath on the lists.
635 if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
636 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800637 }
638
Elliott Hughesb628cb12015-08-03 10:38:08 -0700639 // Recurse into each directory we found.
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800640 while (dirlist != NULL) {
641 copyinfo *next = dirlist->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700642 if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
643 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800644 }
645 free(dirlist);
646 dirlist = next;
647 }
648
Elliott Hughesb628cb12015-08-03 10:38:08 -0700649 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800650}
651
Dan Albertf30d73c2015-02-25 17:51:28 -0800652static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700653{
Greg Hackmann8b689142014-05-06 08:48:18 -0700654 struct utimbuf times = { time, time };
655 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700656
657 /* use umask for permissions */
658 mode_t mask=umask(0000);
659 umask(mask);
660 int r2 = chmod(lpath, mode & ~mask);
661
662 return r1 ? : r2;
663}
664
Elliott Hughesb628cb12015-08-03 10:38:08 -0700665static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
666 int copy_attrs) {
667 // Make sure that both directory paths end in a slash.
668 std::string rpath_clean(rpath);
669 std::string lpath_clean(lpath);
670 if (rpath_clean.empty() || lpath_clean.empty()) return false;
671 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
672 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrewsc736a942014-12-12 13:12:36 -0800673
Elliott Hughesb628cb12015-08-03 10:38:08 -0700674 // Recursively build the list of files to copy.
675 fprintf(stderr, "pull: building file list...\n");
676 copyinfo* filelist = nullptr;
677 if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
678
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800679 int pulled = 0;
680 int skipped = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700681 copyinfo* ci = filelist;
682 while (ci) {
683 copyinfo* next = ci->next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800684 if (ci->flag == 0) {
685 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700686 if (sync_recv(sc, ci->src, ci->dst, false)) {
687 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800688 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700689
690 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700691 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700692 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800693 pulled++;
694 } else {
695 skipped++;
696 }
697 free(ci);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700698 ci = next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800699 }
700
701 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
702 pulled, (pulled == 1) ? "" : "s",
703 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700704 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800705}
706
Elliott Hughesb628cb12015-08-03 10:38:08 -0700707bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
708 SyncConnection sc;
709 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800710
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700711 unsigned mode, time;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700712 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700713 if (mode == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700714 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
715 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800716 }
717
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700718 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
719 std::string path_holder;
720 struct stat st;
721 if (stat(lpath, &st) == 0) {
722 if (S_ISDIR(st.st_mode)) {
723 // If we're copying a remote file to a local directory,
724 // we really want to copy to local_dir + "/" + basename(remote).
725 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
726 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800727 }
728 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700729 if (sync_recv(sc, rpath, lpath, show_progress)) {
730 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800731 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700732 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700733 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700734 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800735 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700736 return true;
737 } else if (S_ISDIR(mode)) {
738 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800739 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700740
741 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
742 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800743}
744
Elliott Hughesb628cb12015-08-03 10:38:08 -0700745bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700746 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800747
Elliott Hughesb628cb12015-08-03 10:38:08 -0700748 SyncConnection sc;
749 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800750
Elliott Hughesb628cb12015-08-03 10:38:08 -0700751 return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800752}