blob: c37c6dd0e99620804257647020f080a1a3fdba75 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-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 Albert76649012015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low6001c872015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albert76649012015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albert76649012015-02-24 15:51:19 -080027#include <time.h>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070028#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080029
30#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080031
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080032#include "adb.h"
33#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080034#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040035#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include "file_sync_service.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037
Elliott Hughesaa245492015-08-03 10:38:08 -070038#include <base/strings.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070039#include <base/stringprintf.h>
40
Elliott Hughesaa245492015-08-03 10:38:08 -070041struct syncsendbuf {
42 unsigned id;
43 unsigned size;
44 char data[SYNC_DATA_MAX];
45};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080046
Elliott Hughesaa245492015-08-03 10:38:08 -070047static syncsendbuf send_buffer;
48
49static long long NOW() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050 struct timeval tv;
51 gettimeofday(&tv, 0);
Elliott Hughesaa245492015-08-03 10:38:08 -070052 return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080053}
54
Spencer Low6001c872015-05-13 00:02:55 -070055static void print_transfer_progress(uint64_t bytes_current,
56 uint64_t bytes_total) {
Mark Lindner76f2a932014-03-11 17:55:59 -070057 if (bytes_total == 0) return;
58
Spencer Low6001c872015-05-13 00:02:55 -070059 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
60 bytes_current, bytes_total,
Mark Lindner76f2a932014-03-11 17:55:59 -070061 (int) (bytes_current * 100 / bytes_total));
62
63 if (bytes_current == bytes_total) {
64 fputc('\n', stderr);
65 }
66
67 fflush(stderr);
68}
69
Elliott Hughesaa245492015-08-03 10:38:08 -070070static bool SendRequest(int fd, int id, const char* path) {
71 size_t path_length = strlen(path);
72 if (path_length > 1024) {
73 fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
74 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075 }
76
Elliott Hughesaa245492015-08-03 10:38:08 -070077 // Sending header and payload in a single write makes a noticeable
78 // difference to "adb sync" performance.
79 char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
80 SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
81 req->id = id;
82 req->path_length = htoll(path_length);
83 char* data = reinterpret_cast<char*>(req + 1);
84 memcpy(data, path, path_length);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080085
Elliott Hughesaa245492015-08-03 10:38:08 -070086 return WriteFdExactly(fd, buf, sizeof(buf));
87}
88
89class SyncConnection {
90 public:
91 SyncConnection() : total_bytes(0), start_time_(NOW()) {
92 max = SYNC_DATA_MAX; // TODO: decide at runtime.
93
94 std::string error;
95 fd = adb_connect("sync:", &error);
96 if (fd < 0) {
97 fprintf(stderr, "error: %s\n", error.c_str());
98 }
99 }
100
101 ~SyncConnection() {
102 if (!IsValid()) return;
103
104 SendQuit();
105 ShowTransferRate();
106 adb_close(fd);
107 }
108
109 bool IsValid() { return fd >= 0; }
110
111 uint64_t total_bytes;
112
113 // TODO: add a char[max] buffer here, to replace syncsendbuf...
114 int fd;
115 size_t max;
116
117 private:
118 uint64_t start_time_;
119
120 void SendQuit() {
121 SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
122 }
123
124 void ShowTransferRate() {
125 uint64_t t = NOW() - start_time_;
126 if (total_bytes == 0 || t == 0) return;
127
128 fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
129 ((total_bytes * 1000000LL) / t) / 1024LL,
130 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
131 }
132};
133
134typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
135
136static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
137 if (!SendRequest(fd, ID_LIST, path)) return false;
138
139 while (true) {
140 syncmsg msg;
141 if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
142
143 if (msg.dent.id == ID_DONE) return true;
144 if (msg.dent.id != ID_DENT) return false;
145
146 size_t len = ltohl(msg.dent.namelen);
147 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800148
Elliott Hughes5c742702015-07-30 17:42:01 -0700149 char buf[257];
Elliott Hughesaa245492015-08-03 10:38:08 -0700150 if (!ReadFdExactly(fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800151 buf[len] = 0;
152
Elliott Hughes5c742702015-07-30 17:42:01 -0700153 func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800155}
156
Elliott Hughesaa245492015-08-03 10:38:08 -0700157static bool sync_start_stat(SyncConnection& sc, const char* path) {
158 return SendRequest(sc.fd, ID_STAT, path);
159}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800160
Elliott Hughesaa245492015-08-03 10:38:08 -0700161static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
162 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700164 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
165 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800166 }
167
Elliott Hughesaa245492015-08-03 10:38:08 -0700168 if (timestamp) *timestamp = ltohl(msg.stat.time);
169 if (mode) *mode = ltohl(msg.stat.mode);
170 if (size) *size = ltohl(msg.stat.size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800171
Elliott Hughesaa245492015-08-03 10:38:08 -0700172 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800173}
174
Elliott Hughesaa245492015-08-03 10:38:08 -0700175static bool sync_stat(SyncConnection& sc, const char* path,
176 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
177 return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800178}
179
Elliott Hughesaa245492015-08-03 10:38:08 -0700180static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
181 int err = 0;
Mark Lindner76f2a932014-03-11 17:55:59 -0700182 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183
Elliott Hughesaa245492015-08-03 10:38:08 -0700184 int lfd = adb_open(path, O_RDONLY);
185 if (lfd < 0) {
186 fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800187 return -1;
188 }
189
Mark Lindner76f2a932014-03-11 17:55:59 -0700190 if (show_progress) {
191 // Determine local file size.
192 struct stat st;
eric.yana8592192015-02-03 22:16:29 +0800193 if (stat(path, &st)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700194 fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
Mark Lindner76f2a932014-03-11 17:55:59 -0700195 return -1;
196 }
197
198 size = st.st_size;
199 }
200
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800201 sbuf->id = ID_DATA;
Elliott Hughesaa245492015-08-03 10:38:08 -0700202 while (true) {
203 int ret = adb_read(lfd, sbuf->data, sc.max);
204 if (!ret)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800205 break;
206
Elliott Hughesaa245492015-08-03 10:38:08 -0700207 if (ret < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208 if(errno == EINTR)
209 continue;
Elliott Hughesaa245492015-08-03 10:38:08 -0700210 fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211 break;
212 }
213
214 sbuf->size = htoll(ret);
Elliott Hughesaa245492015-08-03 10:38:08 -0700215 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800216 err = -1;
217 break;
218 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700219 sc.total_bytes += ret;
Mark Lindner76f2a932014-03-11 17:55:59 -0700220
221 if (show_progress) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700222 print_transfer_progress(sc.total_bytes, size);
Mark Lindner76f2a932014-03-11 17:55:59 -0700223 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224 }
225
226 adb_close(lfd);
227 return err;
228}
229
Elliott Hughes0a049b12015-01-12 14:26:36 -0800230#if defined(_WIN32)
Elliott Hughesaa245492015-08-03 10:38:08 -0700231extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
Elliott Hughes0a049b12015-01-12 14:26:36 -0800232#else
Elliott Hughesaa245492015-08-03 10:38:08 -0700233static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
234 ssize_t len = readlink(path, sbuf->data, sc.max - 1);
Elliott Hughes5c742702015-07-30 17:42:01 -0700235 if (len < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800236 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
237 return -1;
238 }
239 sbuf->data[len] = '\0';
240
241 sbuf->size = htoll(len + 1);
242 sbuf->id = ID_DATA;
243
Elliott Hughesaa245492015-08-03 10:38:08 -0700244 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800245 return -1;
Elliott Hughes5c742702015-07-30 17:42:01 -0700246 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800247
Elliott Hughesaa245492015-08-03 10:38:08 -0700248 sc.total_bytes += len + 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800249
250 return 0;
251}
252#endif
253
Elliott Hughesaa245492015-08-03 10:38:08 -0700254static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
255 unsigned mtime, mode_t mode, bool show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800256{
Elliott Hughesaa245492015-08-03 10:38:08 -0700257 syncsendbuf* sbuf = &send_buffer;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800258
Elliott Hughesaa245492015-08-03 10:38:08 -0700259 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
260 if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800261
Elliott Hughesaa245492015-08-03 10:38:08 -0700262 if (S_ISREG(mode)) {
263 write_data_file(sc, lpath, sbuf, show_progress);
264 } else if (S_ISLNK(mode)) {
265 write_data_link(sc, lpath, sbuf);
266 } else {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800267 goto fail;
268 }
269
Elliott Hughesaa245492015-08-03 10:38:08 -0700270 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800271 msg.data.id = ID_DONE;
272 msg.data.size = htoll(mtime);
Elliott Hughesaa245492015-08-03 10:38:08 -0700273 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800274
Elliott Hughesaa245492015-08-03 10:38:08 -0700275 if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276
Elliott Hughesaa245492015-08-03 10:38:08 -0700277 if (msg.status.id != ID_OKAY) {
278 if (msg.status.id == ID_FAIL) {
279 size_t len = ltohl(msg.status.msglen);
280 if (len > 256) len = 256;
281 if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282 sbuf->data[len] = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700283 } else {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800284 strcpy(sbuf->data, "unknown reason");
Elliott Hughesaa245492015-08-03 10:38:08 -0700285 }
286 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
287 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288 }
289
Elliott Hughesaa245492015-08-03 10:38:08 -0700290 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800291
292fail:
Elliott Hughesaa245492015-08-03 10:38:08 -0700293 fprintf(stderr, "protocol failure\n");
294 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800295}
296
Elliott Hughesaa245492015-08-03 10:38:08 -0700297static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800298 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800299 int lfd = -1;
300 char *buffer = send_buffer.data;
301 unsigned id;
302
Elliott Hughesaa245492015-08-03 10:38:08 -0700303 size_t len = strlen(rpath);
304 if (len > 1024) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800305
Elliott Hughesaa245492015-08-03 10:38:08 -0700306 unsigned size = 0;
Mark Lindner76f2a932014-03-11 17:55:59 -0700307 if (show_progress) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700308 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
Mark Lindner76f2a932014-03-11 17:55:59 -0700309 }
310
Elliott Hughesaa245492015-08-03 10:38:08 -0700311 if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
312 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800313
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800314 id = msg.data.id;
315
Elliott Hughesaa245492015-08-03 10:38:08 -0700316 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800317 adb_unlink(lpath);
Mark Salyzyn60299df2014-04-30 09:10:31 -0700318 mkdirs(lpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800319 lfd = adb_creat(lpath, 0644);
320 if(lfd < 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700321 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800322 return -1;
323 }
324 goto handle_data;
325 } else {
326 goto remote_error;
327 }
328
Elliott Hughesaa245492015-08-03 10:38:08 -0700329 while (true) {
330 if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800331 return -1;
332 }
333 id = msg.data.id;
334
335 handle_data:
336 len = ltohl(msg.data.size);
Elliott Hughesaa245492015-08-03 10:38:08 -0700337 if (id == ID_DONE) break;
338 if (id != ID_DATA) goto remote_error;
339 if (len > sc.max) {
340 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800341 adb_close(lfd);
342 return -1;
343 }
344
Elliott Hughesaa245492015-08-03 10:38:08 -0700345 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800346 adb_close(lfd);
347 return -1;
348 }
349
Dan Albertcc731cc2015-02-24 21:26:58 -0800350 if(!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700351 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800352 adb_close(lfd);
353 return -1;
354 }
355
Elliott Hughesaa245492015-08-03 10:38:08 -0700356 sc.total_bytes += len;
Mark Lindner76f2a932014-03-11 17:55:59 -0700357
358 if (show_progress) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700359 print_transfer_progress(sc.total_bytes, size);
Mark Lindner76f2a932014-03-11 17:55:59 -0700360 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800361 }
362
363 adb_close(lfd);
364 return 0;
365
366remote_error:
367 adb_close(lfd);
368 adb_unlink(lpath);
369
370 if(id == ID_FAIL) {
371 len = ltohl(msg.data.size);
372 if(len > 256) len = 256;
Elliott Hughesaa245492015-08-03 10:38:08 -0700373 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800374 return -1;
375 }
376 buffer[len] = 0;
377 } else {
378 memcpy(buffer, &id, 4);
379 buffer[4] = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800380 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700381 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800382 return 0;
383}
384
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800385static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesaa245492015-08-03 10:38:08 -0700386 const char* name, void* /*cookie*/) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800387 printf("%08x %08x %08x %s\n", mode, size, time, name);
388}
389
Elliott Hughesaa245492015-08-03 10:38:08 -0700390bool do_sync_ls(const char* path) {
391 SyncConnection sc;
392 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800393
Elliott Hughesaa245492015-08-03 10:38:08 -0700394 return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800395}
396
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800397struct copyinfo
398{
399 copyinfo *next;
400 const char *src;
401 const char *dst;
402 unsigned int time;
403 unsigned int mode;
404 unsigned int size;
405 int flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800406};
407
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700408static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800409 int slen = strlen(spath);
410 int dlen = strlen(dpath);
411 int nlen = strlen(name);
412 int ssize = slen + nlen + 2;
413 int dsize = dlen + nlen + 2;
414
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700415 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416 if(ci == 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700417 fprintf(stderr, "out of memory\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800418 abort();
419 }
420
421 ci->next = 0;
422 ci->time = 0;
423 ci->mode = 0;
424 ci->size = 0;
425 ci->flag = 0;
426 ci->src = (const char*)(ci + 1);
427 ci->dst = ci->src + ssize;
428 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
429 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
430
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800431 return ci;
432}
433
Elliott Hughesaa245492015-08-03 10:38:08 -0700434static bool IsDotOrDotDot(const char* name) {
435 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
436}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800437
Elliott Hughesaa245492015-08-03 10:38:08 -0700438static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800439 copyinfo *dirlist = 0;
440 copyinfo *ci, *next;
441
Elliott Hughesaa245492015-08-03 10:38:08 -0700442 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
443 if (!dir) {
444 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445 return -1;
446 }
447
Elliott Hughesaa245492015-08-03 10:38:08 -0700448 dirent *de;
449 while ((de = readdir(dir.get()))) {
450 if (IsDotOrDotDot(de->d_name)) continue;
451
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800452 char stat_path[PATH_MAX];
Elliott Hughesaa245492015-08-03 10:38:08 -0700453 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
454 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800455 continue;
Elliott Hughesaa245492015-08-03 10:38:08 -0700456 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800457 strcpy(stat_path, lpath);
458 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800459
Elliott Hughesaa245492015-08-03 10:38:08 -0700460 struct stat st;
461 if (!lstat(stat_path, &st)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700462 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700463 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700464 ci->next = dirlist;
465 dirlist = ci;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800466 } else {
Elliott Hughesaa245492015-08-03 10:38:08 -0700467 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
468 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700469 fprintf(stderr, "skipping special file '%s'\n", ci->src);
470 free(ci);
471 } else {
472 ci->time = st.st_mtime;
473 ci->mode = st.st_mode;
474 ci->size = st.st_size;
475 ci->next = *filelist;
476 *filelist = ci;
477 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800478 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700479 } else {
480 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800481 }
482 }
483
Elliott Hughesaa245492015-08-03 10:38:08 -0700484 // Close this directory and recurse.
485 dir.reset();
486 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800487 next = ci->next;
488 local_build_list(filelist, ci->src, ci->dst);
489 free(ci);
490 }
491
492 return 0;
493}
494
Elliott Hughesaa245492015-08-03 10:38:08 -0700495static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
496 bool check_timestamps, bool list_only) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800497 copyinfo *filelist = 0;
498 copyinfo *ci, *next;
499 int pushed = 0;
500 int skipped = 0;
501
Elliott Hughesaa245492015-08-03 10:38:08 -0700502 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
503 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800504 int tmplen = strlen(lpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800505 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700506 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800507 snprintf(tmp, tmplen, "%s/",lpath);
508 lpath = tmp;
509 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700510 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800511 int tmplen = strlen(rpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800512 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700513 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800514 snprintf(tmp, tmplen, "%s/",rpath);
515 rpath = tmp;
516 }
517
Elliott Hughesaa245492015-08-03 10:38:08 -0700518 if (local_build_list(&filelist, lpath, rpath)) {
519 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800520 }
521
Elliott Hughesaa245492015-08-03 10:38:08 -0700522 if (check_timestamps) {
523 for (ci = filelist; ci != 0; ci = ci->next) {
524 if (!sync_start_stat(sc, ci->dst)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800525 }
526 for(ci = filelist; ci != 0; ci = ci->next) {
527 unsigned int timestamp, mode, size;
Elliott Hughesaa245492015-08-03 10:38:08 -0700528 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
529 if (size == ci->size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800530 /* for links, we cannot update the atime/mtime */
Elliott Hughesaa245492015-08-03 10:38:08 -0700531 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
532 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800533 ci->flag = 1;
Elliott Hughesaa245492015-08-03 10:38:08 -0700534 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800535 }
536 }
537 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700538 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800539 next = ci->next;
Elliott Hughesaa245492015-08-03 10:38:08 -0700540 if (ci->flag == 0) {
541 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
542 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
543 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800544 }
545 pushed++;
546 } else {
547 skipped++;
548 }
549 free(ci);
550 }
551
Elliott Hughesaa245492015-08-03 10:38:08 -0700552 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800553 pushed, (pushed == 1) ? "" : "s",
554 skipped, (skipped == 1) ? "" : "s");
555
Elliott Hughesaa245492015-08-03 10:38:08 -0700556 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800557}
558
Elliott Hughesaa245492015-08-03 10:38:08 -0700559bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
560 SyncConnection sc;
561 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800562
Elliott Hughes5c742702015-07-30 17:42:01 -0700563 struct stat st;
564 if (stat(lpath, &st)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700565 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
566 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800567 }
568
Elliott Hughes5c742702015-07-30 17:42:01 -0700569 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700570 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800571 }
572
Elliott Hughesaa245492015-08-03 10:38:08 -0700573 unsigned mode;
574 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
575 std::string path_holder;
576 if (mode != 0 && S_ISDIR(mode)) {
577 // If we're copying a local file to a remote directory,
578 // we really want to copy to remote_dir + "/" + local_filename.
579 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
580 rpath = path_holder.c_str();
581 }
582 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800583}
584
585
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700586struct sync_ls_build_list_cb_args {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800587 copyinfo **filelist;
588 copyinfo **dirlist;
589 const char *rpath;
590 const char *lpath;
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700591};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800592
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700593static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
594 const char* name, void* cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800595{
596 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
597 copyinfo *ci;
598
599 if (S_ISDIR(mode)) {
600 copyinfo **dirlist = args->dirlist;
601
Elliott Hughesaa245492015-08-03 10:38:08 -0700602 // Don't try recursing down "." or "..".
603 if (IsDotOrDotDot(name)) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800604
605 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
606 ci->next = *dirlist;
607 *dirlist = ci;
608 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
609 copyinfo **filelist = args->filelist;
610
611 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
612 ci->time = time;
613 ci->mode = mode;
614 ci->size = size;
615 ci->next = *filelist;
616 *filelist = ci;
617 } else {
618 fprintf(stderr, "skipping special file '%s'\n", name);
619 }
620}
621
Elliott Hughesaa245492015-08-03 10:38:08 -0700622static bool remote_build_list(int syncfd, copyinfo **filelist,
623 const char *rpath, const char *lpath) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800624 copyinfo *dirlist = NULL;
625 sync_ls_build_list_cb_args args;
626
627 args.filelist = filelist;
628 args.dirlist = &dirlist;
629 args.rpath = rpath;
630 args.lpath = lpath;
631
Elliott Hughesaa245492015-08-03 10:38:08 -0700632 // Put the files/dirs in rpath on the lists.
633 if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
634 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800635 }
636
Elliott Hughesaa245492015-08-03 10:38:08 -0700637 // Recurse into each directory we found.
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800638 while (dirlist != NULL) {
639 copyinfo *next = dirlist->next;
Elliott Hughesaa245492015-08-03 10:38:08 -0700640 if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
641 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800642 }
643 free(dirlist);
644 dirlist = next;
645 }
646
Elliott Hughesaa245492015-08-03 10:38:08 -0700647 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800648}
649
Dan Albertbac34742015-02-25 17:51:28 -0800650static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700651{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700652 struct utimbuf times = { time, time };
653 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700654
655 /* use umask for permissions */
656 mode_t mask=umask(0000);
657 umask(mask);
658 int r2 = chmod(lpath, mode & ~mask);
659
660 return r1 ? : r2;
661}
662
Elliott Hughesaa245492015-08-03 10:38:08 -0700663static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
664 int copy_attrs) {
665 // Make sure that both directory paths end in a slash.
666 std::string rpath_clean(rpath);
667 std::string lpath_clean(lpath);
668 if (rpath_clean.empty() || lpath_clean.empty()) return false;
669 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
670 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrews4d04d242014-12-12 13:12:36 -0800671
Elliott Hughesaa245492015-08-03 10:38:08 -0700672 // Recursively build the list of files to copy.
673 fprintf(stderr, "pull: building file list...\n");
674 copyinfo* filelist = nullptr;
675 if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
676
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800677 int pulled = 0;
678 int skipped = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700679 copyinfo* ci = filelist;
680 while (ci) {
681 copyinfo* next = ci->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800682 if (ci->flag == 0) {
683 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700684 if (sync_recv(sc, ci->src, ci->dst, false)) {
685 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800686 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700687
688 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700689 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700690 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800691 pulled++;
692 } else {
693 skipped++;
694 }
695 free(ci);
Elliott Hughesaa245492015-08-03 10:38:08 -0700696 ci = next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800697 }
698
699 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
700 pulled, (pulled == 1) ? "" : "s",
701 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesaa245492015-08-03 10:38:08 -0700702 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800703}
704
Elliott Hughesaa245492015-08-03 10:38:08 -0700705bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
706 SyncConnection sc;
707 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800708
Elliott Hughes5c742702015-07-30 17:42:01 -0700709 unsigned mode, time;
Elliott Hughesaa245492015-08-03 10:38:08 -0700710 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700711 if (mode == 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700712 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
713 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800714 }
715
Elliott Hughes5c742702015-07-30 17:42:01 -0700716 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
717 std::string path_holder;
718 struct stat st;
719 if (stat(lpath, &st) == 0) {
720 if (S_ISDIR(st.st_mode)) {
721 // If we're copying a remote file to a local directory,
722 // we really want to copy to local_dir + "/" + basename(remote).
723 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
724 lpath = path_holder.c_str();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800725 }
726 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700727 if (sync_recv(sc, rpath, lpath, show_progress)) {
728 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800729 } else {
Elliott Hughes5c742702015-07-30 17:42:01 -0700730 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700731 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700732 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800733 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700734 return true;
735 } else if (S_ISDIR(mode)) {
736 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800737 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700738
739 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
740 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800741}
742
Elliott Hughesaa245492015-08-03 10:38:08 -0700743bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesd236d072015-04-21 10:17:07 -0700744 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800745
Elliott Hughesaa245492015-08-03 10:38:08 -0700746 SyncConnection sc;
747 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800748
Elliott Hughesaa245492015-08-03 10:38:08 -0700749 return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800750}