blob: e70d550dba60fe5d6e9d0c68c285e3fabf13a4e7 [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);
Elliott Hughes0bd85872015-08-25 10:59:45 -0700206 if (ret <= 0) {
207 if (ret < 0) fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800208 break;
209 }
210
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700211 sbuf->size = ret;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700212 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800213 err = -1;
214 break;
215 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700216 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700217
218 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700219 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700220 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800221 }
222
223 adb_close(lfd);
224 return err;
225}
226
Elliott Hughes944e1d72015-01-12 14:26:36 -0800227#if defined(_WIN32)
Elliott Hughesb628cb12015-08-03 10:38:08 -0700228extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
Elliott Hughes944e1d72015-01-12 14:26:36 -0800229#else
Elliott Hughesb628cb12015-08-03 10:38:08 -0700230static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
231 ssize_t len = readlink(path, sbuf->data, sc.max - 1);
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700232 if (len < 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800233 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
234 return -1;
235 }
236 sbuf->data[len] = '\0';
237
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700238 sbuf->size = len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800239 sbuf->id = ID_DATA;
240
Elliott Hughesb628cb12015-08-03 10:38:08 -0700241 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800242 return -1;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700243 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800244
Elliott Hughesb628cb12015-08-03 10:38:08 -0700245 sc.total_bytes += len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800246
247 return 0;
248}
249#endif
250
Elliott Hughesb628cb12015-08-03 10:38:08 -0700251static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
252 unsigned mtime, mode_t mode, bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800253{
Elliott Hughesb628cb12015-08-03 10:38:08 -0700254 syncsendbuf* sbuf = &send_buffer;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800255
Elliott Hughesb628cb12015-08-03 10:38:08 -0700256 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
257 if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800258
Elliott Hughesb628cb12015-08-03 10:38:08 -0700259 if (S_ISREG(mode)) {
260 write_data_file(sc, lpath, sbuf, show_progress);
261 } else if (S_ISLNK(mode)) {
262 write_data_link(sc, lpath, sbuf);
263 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800264 goto fail;
265 }
266
Elliott Hughesb628cb12015-08-03 10:38:08 -0700267 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800268 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700269 msg.data.size = mtime;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700270 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800271
Elliott Hughesb628cb12015-08-03 10:38:08 -0700272 if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800273
Elliott Hughesb628cb12015-08-03 10:38:08 -0700274 if (msg.status.id != ID_OKAY) {
275 if (msg.status.id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700276 size_t len = msg.status.msglen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700277 if (len > 256) len = 256;
278 if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800279 sbuf->data[len] = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700280 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800281 strcpy(sbuf->data, "unknown reason");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700282 }
283 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
284 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800285 }
286
Elliott Hughesb628cb12015-08-03 10:38:08 -0700287 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800288
289fail:
Elliott Hughesb628cb12015-08-03 10:38:08 -0700290 fprintf(stderr, "protocol failure\n");
291 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800292}
293
Elliott Hughesb628cb12015-08-03 10:38:08 -0700294static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800295 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800296 int lfd = -1;
297 char *buffer = send_buffer.data;
298 unsigned id;
299
Elliott Hughesb628cb12015-08-03 10:38:08 -0700300 size_t len = strlen(rpath);
301 if (len > 1024) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800302
Elliott Hughesb628cb12015-08-03 10:38:08 -0700303 unsigned size = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700304 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700305 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700306 }
307
Elliott Hughesb628cb12015-08-03 10:38:08 -0700308 if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
309 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800310
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800311 id = msg.data.id;
312
Elliott Hughesb628cb12015-08-03 10:38:08 -0700313 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800314 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700315 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800316 lfd = adb_creat(lpath, 0644);
317 if(lfd < 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700318 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800319 return -1;
320 }
321 goto handle_data;
322 } else {
323 goto remote_error;
324 }
325
Elliott Hughesb628cb12015-08-03 10:38:08 -0700326 while (true) {
327 if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800328 return -1;
329 }
330 id = msg.data.id;
331
332 handle_data:
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700333 len = msg.data.size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700334 if (id == ID_DONE) break;
335 if (id != ID_DATA) goto remote_error;
336 if (len > sc.max) {
337 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800338 adb_close(lfd);
339 return -1;
340 }
341
Elliott Hughesb628cb12015-08-03 10:38:08 -0700342 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800343 adb_close(lfd);
344 return -1;
345 }
346
Dan Albert66a91b02015-02-24 21:26:58 -0800347 if(!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700348 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800349 adb_close(lfd);
350 return -1;
351 }
352
Elliott Hughesb628cb12015-08-03 10:38:08 -0700353 sc.total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700354
355 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700356 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700357 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800358 }
359
360 adb_close(lfd);
361 return 0;
362
363remote_error:
364 adb_close(lfd);
365 adb_unlink(lpath);
366
367 if(id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700368 len = msg.data.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800369 if(len > 256) len = 256;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700370 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800371 return -1;
372 }
373 buffer[len] = 0;
374 } else {
375 memcpy(buffer, &id, 4);
376 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800377 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700378 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800379 return 0;
380}
381
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800382static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700383 const char* name, void* /*cookie*/) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800384 printf("%08x %08x %08x %s\n", mode, size, time, name);
385}
386
Elliott Hughesb628cb12015-08-03 10:38:08 -0700387bool do_sync_ls(const char* path) {
388 SyncConnection sc;
389 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800390
Elliott Hughesb628cb12015-08-03 10:38:08 -0700391 return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800392}
393
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800394struct copyinfo
395{
396 copyinfo *next;
397 const char *src;
398 const char *dst;
399 unsigned int time;
400 unsigned int mode;
401 unsigned int size;
402 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800403};
404
Elliott Hughes712416a2015-05-05 18:26:10 -0700405static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800406 int slen = strlen(spath);
407 int dlen = strlen(dpath);
408 int nlen = strlen(name);
409 int ssize = slen + nlen + 2;
410 int dsize = dlen + nlen + 2;
411
Elliott Hughes712416a2015-05-05 18:26:10 -0700412 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800413 if(ci == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700414 fprintf(stderr, "out of memory\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800415 abort();
416 }
417
418 ci->next = 0;
419 ci->time = 0;
420 ci->mode = 0;
421 ci->size = 0;
422 ci->flag = 0;
423 ci->src = (const char*)(ci + 1);
424 ci->dst = ci->src + ssize;
425 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
426 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
427
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800428 return ci;
429}
430
Elliott Hughesb628cb12015-08-03 10:38:08 -0700431static bool IsDotOrDotDot(const char* name) {
432 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
433}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800434
Elliott Hughesb628cb12015-08-03 10:38:08 -0700435static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800436 copyinfo *dirlist = 0;
437 copyinfo *ci, *next;
438
Elliott Hughesb628cb12015-08-03 10:38:08 -0700439 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
440 if (!dir) {
441 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800442 return -1;
443 }
444
Elliott Hughesb628cb12015-08-03 10:38:08 -0700445 dirent *de;
446 while ((de = readdir(dir.get()))) {
447 if (IsDotOrDotDot(de->d_name)) continue;
448
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800449 char stat_path[PATH_MAX];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700450 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
451 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800452 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700453 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454 strcpy(stat_path, lpath);
455 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800456
Elliott Hughesb628cb12015-08-03 10:38:08 -0700457 struct stat st;
458 if (!lstat(stat_path, &st)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700459 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700460 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700461 ci->next = dirlist;
462 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800463 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700464 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
465 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700466 fprintf(stderr, "skipping special file '%s'\n", ci->src);
467 free(ci);
468 } else {
469 ci->time = st.st_mtime;
470 ci->mode = st.st_mode;
471 ci->size = st.st_size;
472 ci->next = *filelist;
473 *filelist = ci;
474 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800475 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700476 } else {
477 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800478 }
479 }
480
Elliott Hughesb628cb12015-08-03 10:38:08 -0700481 // Close this directory and recurse.
482 dir.reset();
483 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800484 next = ci->next;
485 local_build_list(filelist, ci->src, ci->dst);
486 free(ci);
487 }
488
489 return 0;
490}
491
Elliott Hughesb628cb12015-08-03 10:38:08 -0700492static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
493 bool check_timestamps, bool list_only) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800494 copyinfo *filelist = 0;
495 copyinfo *ci, *next;
496 int pushed = 0;
497 int skipped = 0;
498
Elliott Hughesb628cb12015-08-03 10:38:08 -0700499 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
500 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800501 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800502 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700503 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504 snprintf(tmp, tmplen, "%s/",lpath);
505 lpath = tmp;
506 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700507 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800508 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800509 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700510 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800511 snprintf(tmp, tmplen, "%s/",rpath);
512 rpath = tmp;
513 }
514
Elliott Hughesb628cb12015-08-03 10:38:08 -0700515 if (local_build_list(&filelist, lpath, rpath)) {
516 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800517 }
518
Elliott Hughesb628cb12015-08-03 10:38:08 -0700519 if (check_timestamps) {
520 for (ci = filelist; ci != 0; ci = ci->next) {
521 if (!sync_start_stat(sc, ci->dst)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800522 }
523 for(ci = filelist; ci != 0; ci = ci->next) {
524 unsigned int timestamp, mode, size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700525 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
526 if (size == ci->size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800527 /* for links, we cannot update the atime/mtime */
Elliott Hughesb628cb12015-08-03 10:38:08 -0700528 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
529 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800530 ci->flag = 1;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700531 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800532 }
533 }
534 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700535 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800536 next = ci->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700537 if (ci->flag == 0) {
538 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
539 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
540 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800541 }
542 pushed++;
543 } else {
544 skipped++;
545 }
546 free(ci);
547 }
548
Elliott Hughesb628cb12015-08-03 10:38:08 -0700549 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800550 pushed, (pushed == 1) ? "" : "s",
551 skipped, (skipped == 1) ? "" : "s");
552
Elliott Hughesb628cb12015-08-03 10:38:08 -0700553 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800554}
555
Elliott Hughesb628cb12015-08-03 10:38:08 -0700556bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
557 SyncConnection sc;
558 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800559
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700560 struct stat st;
561 if (stat(lpath, &st)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700562 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
563 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800564 }
565
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700566 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700567 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800568 }
569
Elliott Hughesb628cb12015-08-03 10:38:08 -0700570 unsigned mode;
571 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
572 std::string path_holder;
573 if (mode != 0 && S_ISDIR(mode)) {
574 // If we're copying a local file to a remote directory,
575 // we really want to copy to remote_dir + "/" + local_filename.
576 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
577 rpath = path_holder.c_str();
578 }
579 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800580}
581
582
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700583struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800584 copyinfo **filelist;
585 copyinfo **dirlist;
586 const char *rpath;
587 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700588};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800589
Elliott Hughes712416a2015-05-05 18:26:10 -0700590static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
591 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800592{
593 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
594 copyinfo *ci;
595
596 if (S_ISDIR(mode)) {
597 copyinfo **dirlist = args->dirlist;
598
Elliott Hughesb628cb12015-08-03 10:38:08 -0700599 // Don't try recursing down "." or "..".
600 if (IsDotOrDotDot(name)) return;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800601
602 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
603 ci->next = *dirlist;
604 *dirlist = ci;
605 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
606 copyinfo **filelist = args->filelist;
607
608 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
609 ci->time = time;
610 ci->mode = mode;
611 ci->size = size;
612 ci->next = *filelist;
613 *filelist = ci;
614 } else {
615 fprintf(stderr, "skipping special file '%s'\n", name);
616 }
617}
618
Elliott Hughesb628cb12015-08-03 10:38:08 -0700619static bool remote_build_list(int syncfd, copyinfo **filelist,
620 const char *rpath, const char *lpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800621 copyinfo *dirlist = NULL;
622 sync_ls_build_list_cb_args args;
623
624 args.filelist = filelist;
625 args.dirlist = &dirlist;
626 args.rpath = rpath;
627 args.lpath = lpath;
628
Elliott Hughesb628cb12015-08-03 10:38:08 -0700629 // Put the files/dirs in rpath on the lists.
630 if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
631 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800632 }
633
Elliott Hughesb628cb12015-08-03 10:38:08 -0700634 // Recurse into each directory we found.
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800635 while (dirlist != NULL) {
636 copyinfo *next = dirlist->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700637 if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
638 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800639 }
640 free(dirlist);
641 dirlist = next;
642 }
643
Elliott Hughesb628cb12015-08-03 10:38:08 -0700644 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800645}
646
Dan Albertf30d73c2015-02-25 17:51:28 -0800647static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700648{
Greg Hackmann8b689142014-05-06 08:48:18 -0700649 struct utimbuf times = { time, time };
650 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700651
652 /* use umask for permissions */
653 mode_t mask=umask(0000);
654 umask(mask);
655 int r2 = chmod(lpath, mode & ~mask);
656
657 return r1 ? : r2;
658}
659
Elliott Hughesb628cb12015-08-03 10:38:08 -0700660static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
661 int copy_attrs) {
662 // Make sure that both directory paths end in a slash.
663 std::string rpath_clean(rpath);
664 std::string lpath_clean(lpath);
665 if (rpath_clean.empty() || lpath_clean.empty()) return false;
666 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
667 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrewsc736a942014-12-12 13:12:36 -0800668
Elliott Hughesb628cb12015-08-03 10:38:08 -0700669 // Recursively build the list of files to copy.
670 fprintf(stderr, "pull: building file list...\n");
671 copyinfo* filelist = nullptr;
672 if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
673
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800674 int pulled = 0;
675 int skipped = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700676 copyinfo* ci = filelist;
677 while (ci) {
678 copyinfo* next = ci->next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800679 if (ci->flag == 0) {
680 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700681 if (sync_recv(sc, ci->src, ci->dst, false)) {
682 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800683 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700684
685 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700686 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700687 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800688 pulled++;
689 } else {
690 skipped++;
691 }
692 free(ci);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700693 ci = next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800694 }
695
696 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
697 pulled, (pulled == 1) ? "" : "s",
698 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700699 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800700}
701
Elliott Hughesb628cb12015-08-03 10:38:08 -0700702bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
703 SyncConnection sc;
704 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800705
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700706 unsigned mode, time;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700707 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700708 if (mode == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700709 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
710 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800711 }
712
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700713 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
714 std::string path_holder;
715 struct stat st;
716 if (stat(lpath, &st) == 0) {
717 if (S_ISDIR(st.st_mode)) {
718 // If we're copying a remote file to a local directory,
719 // we really want to copy to local_dir + "/" + basename(remote).
720 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
721 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800722 }
723 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700724 if (sync_recv(sc, rpath, lpath, show_progress)) {
725 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800726 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700727 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700728 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700729 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800730 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700731 return true;
732 } else if (S_ISDIR(mode)) {
733 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800734 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700735
736 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
737 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800738}
739
Elliott Hughesb628cb12015-08-03 10:38:08 -0700740bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700741 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800742
Elliott Hughesb628cb12015-08-03 10:38:08 -0700743 SyncConnection sc;
744 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800745
Elliott Hughesb628cb12015-08-03 10:38:08 -0700746 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 -0800747}