blob: 9bc634c3d729f6108a109a8d03371eb0d008e0a1 [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
Elliott Hughesa925dba2015-08-24 14:49:43 -070030#include <memory>
31
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080032#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080033
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034#include "adb.h"
35#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080036#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040037#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080038#include "file_sync_service.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039
Elliott Hughesaa245492015-08-03 10:38:08 -070040#include <base/strings.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070041#include <base/stringprintf.h>
42
Elliott Hughesaa245492015-08-03 10:38:08 -070043struct syncsendbuf {
44 unsigned id;
45 unsigned size;
46 char data[SYNC_DATA_MAX];
47};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048
Elliott Hughesaa245492015-08-03 10:38:08 -070049static syncsendbuf send_buffer;
50
51static long long NOW() {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080052 struct timeval tv;
53 gettimeofday(&tv, 0);
Elliott Hughesaa245492015-08-03 10:38:08 -070054 return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080055}
56
Spencer Low6001c872015-05-13 00:02:55 -070057static void print_transfer_progress(uint64_t bytes_current,
58 uint64_t bytes_total) {
Mark Lindner76f2a932014-03-11 17:55:59 -070059 if (bytes_total == 0) return;
60
Spencer Low6001c872015-05-13 00:02:55 -070061 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
62 bytes_current, bytes_total,
Mark Lindner76f2a932014-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 Hughesaa245492015-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);
Elliott Hughes081696d2015-09-03 11:06:00 -070076 errno = ENAMETOOLONG;
Elliott Hughesaa245492015-08-03 10:38:08 -070077 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080078 }
79
Elliott Hughesaa245492015-08-03 10:38:08 -070080 // Sending header and payload in a single write makes a noticeable
81 // difference to "adb sync" performance.
82 char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
83 SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
84 req->id = id;
Elliott Hughesf4465202015-08-24 14:27:03 -070085 req->path_length = path_length;
Elliott Hughesaa245492015-08-03 10:38:08 -070086 char* data = reinterpret_cast<char*>(req + 1);
87 memcpy(data, path, path_length);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088
Elliott Hughesaa245492015-08-03 10:38:08 -070089 return WriteFdExactly(fd, buf, sizeof(buf));
90}
91
92class SyncConnection {
93 public:
94 SyncConnection() : total_bytes(0), start_time_(NOW()) {
95 max = SYNC_DATA_MAX; // TODO: decide at runtime.
96
97 std::string error;
98 fd = adb_connect("sync:", &error);
99 if (fd < 0) {
100 fprintf(stderr, "error: %s\n", error.c_str());
101 }
102 }
103
104 ~SyncConnection() {
105 if (!IsValid()) return;
106
107 SendQuit();
108 ShowTransferRate();
109 adb_close(fd);
110 }
111
112 bool IsValid() { return fd >= 0; }
113
114 uint64_t total_bytes;
115
116 // TODO: add a char[max] buffer here, to replace syncsendbuf...
117 int fd;
118 size_t max;
119
120 private:
121 uint64_t start_time_;
122
123 void SendQuit() {
124 SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
125 }
126
127 void ShowTransferRate() {
128 uint64_t t = NOW() - start_time_;
129 if (total_bytes == 0 || t == 0) return;
130
131 fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
132 ((total_bytes * 1000000LL) / t) / 1024LL,
133 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
134 }
135};
136
137typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
138
139static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
140 if (!SendRequest(fd, ID_LIST, path)) return false;
141
142 while (true) {
143 syncmsg msg;
144 if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
145
146 if (msg.dent.id == ID_DONE) return true;
147 if (msg.dent.id != ID_DENT) return false;
148
Elliott Hughesf4465202015-08-24 14:27:03 -0700149 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700150 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800151
Elliott Hughes5c742702015-07-30 17:42:01 -0700152 char buf[257];
Elliott Hughesaa245492015-08-03 10:38:08 -0700153 if (!ReadFdExactly(fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 buf[len] = 0;
155
Elliott Hughesf4465202015-08-24 14:27:03 -0700156 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800158}
159
Elliott Hughesaa245492015-08-03 10:38:08 -0700160static bool sync_start_stat(SyncConnection& sc, const char* path) {
161 return SendRequest(sc.fd, ID_STAT, path);
162}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163
Elliott Hughesaa245492015-08-03 10:38:08 -0700164static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
165 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800166 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700167 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
168 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800169 }
170
Elliott Hughesf4465202015-08-24 14:27:03 -0700171 if (timestamp) *timestamp = msg.stat.time;
172 if (mode) *mode = msg.stat.mode;
173 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800174
Elliott Hughesaa245492015-08-03 10:38:08 -0700175 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800176}
177
Elliott Hughesaa245492015-08-03 10:38:08 -0700178static bool sync_stat(SyncConnection& sc, const char* path,
179 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
180 return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181}
182
Spencer Lowd8cce182015-08-28 01:07:30 -0700183static bool write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700184 unsigned long long size = 0;
Spencer Lowd8cce182015-08-28 01:07:30 -0700185 if (show_progress) {
186 // Determine local file size.
187 struct stat st;
188 if (stat(path, &st) == -1) {
189 fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
190 return false;
191 }
192
193 size = st.st_size;
194 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800195
Elliott Hughesaa245492015-08-03 10:38:08 -0700196 int lfd = adb_open(path, O_RDONLY);
197 if (lfd < 0) {
198 fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
Spencer Lowd8cce182015-08-28 01:07:30 -0700199 return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700200 }
201
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800202 sbuf->id = ID_DATA;
Elliott Hughesaa245492015-08-03 10:38:08 -0700203 while (true) {
204 int ret = adb_read(lfd, sbuf->data, sc.max);
Elliott Hughes8fcd8bc2015-08-25 10:59:45 -0700205 if (ret <= 0) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700206 if (ret < 0) {
207 fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
208 adb_close(lfd);
209 return false;
210 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211 break;
212 }
213
Elliott Hughesf4465202015-08-24 14:27:03 -0700214 sbuf->size = ret;
Elliott Hughesaa245492015-08-03 10:38:08 -0700215 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700216 adb_close(lfd);
217 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800218 }
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);
Spencer Lowd8cce182015-08-28 01:07:30 -0700227 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800228}
229
Elliott Hughes0a049b12015-01-12 14:26:36 -0800230#if defined(_WIN32)
Spencer Lowd8cce182015-08-28 01:07:30 -0700231extern bool 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
Spencer Lowd8cce182015-08-28 01:07:30 -0700233static bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700234 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));
Spencer Lowd8cce182015-08-28 01:07:30 -0700237 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800238 }
239 sbuf->data[len] = '\0';
240
Elliott Hughesf4465202015-08-24 14:27:03 -0700241 sbuf->size = len + 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242 sbuf->id = ID_DATA;
243
Elliott Hughesaa245492015-08-03 10:38:08 -0700244 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700245 return false;
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
Spencer Lowd8cce182015-08-28 01:07:30 -0700250 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800251}
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);
Elliott Hughes081696d2015-09-03 11:06:00 -0700260 if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) {
261 fprintf(stderr, "failed to send ID_SEND message '%s': %s\n",
262 path_and_mode.c_str(), strerror(errno));
263 return false;
264 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800265
Elliott Hughesaa245492015-08-03 10:38:08 -0700266 if (S_ISREG(mode)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700267 if (!write_data_file(sc, lpath, sbuf, show_progress)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700268 } else if (S_ISLNK(mode)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700269 if (!write_data_link(sc, lpath, sbuf)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700270 } else {
Elliott Hughes081696d2015-09-03 11:06:00 -0700271 fprintf(stderr, "local file '%s' has unsupported mode: 0o%o\n", lpath, mode);
272 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800273 }
274
Elliott Hughesaa245492015-08-03 10:38:08 -0700275 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276 msg.data.id = ID_DONE;
Elliott Hughesf4465202015-08-24 14:27:03 -0700277 msg.data.size = mtime;
Elliott Hughes081696d2015-09-03 11:06:00 -0700278 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
279 fprintf(stderr, "failed to send ID_DONE message for '%s': %s\n", lpath, strerror(errno));
280 return false;
281 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282
Elliott Hughes081696d2015-09-03 11:06:00 -0700283 if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) {
284 fprintf(stderr, "failed to read ID_DONE response for '%s': %s\n", lpath, strerror(errno));
285 return false;
286 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700287 if (msg.status.id != ID_OKAY) {
288 if (msg.status.id == ID_FAIL) {
Elliott Hughesf4465202015-08-24 14:27:03 -0700289 size_t len = msg.status.msglen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700290 if (len > 256) len = 256;
Elliott Hughes081696d2015-09-03 11:06:00 -0700291 if (!ReadFdExactly(sc.fd, sbuf->data, len)) {
292 fprintf(stderr, "failed to read failure reason (!): %s\n", strerror(errno));
293 return false;
294 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800295 sbuf->data[len] = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700296 } else {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800297 strcpy(sbuf->data, "unknown reason");
Elliott Hughesaa245492015-08-03 10:38:08 -0700298 }
299 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
300 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 }
302
Elliott Hughesaa245492015-08-03 10:38:08 -0700303 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800304}
305
Elliott Hughesaa245492015-08-03 10:38:08 -0700306static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800307 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800308 int lfd = -1;
309 char *buffer = send_buffer.data;
310 unsigned id;
311
Elliott Hughesaa245492015-08-03 10:38:08 -0700312 size_t len = strlen(rpath);
313 if (len > 1024) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800314
Elliott Hughesaa245492015-08-03 10:38:08 -0700315 unsigned size = 0;
Mark Lindner76f2a932014-03-11 17:55:59 -0700316 if (show_progress) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700317 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
Mark Lindner76f2a932014-03-11 17:55:59 -0700318 }
319
Elliott Hughesaa245492015-08-03 10:38:08 -0700320 if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
321 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800322
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800323 id = msg.data.id;
324
Elliott Hughesaa245492015-08-03 10:38:08 -0700325 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800326 adb_unlink(lpath);
Mark Salyzyn60299df2014-04-30 09:10:31 -0700327 mkdirs(lpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800328 lfd = adb_creat(lpath, 0644);
329 if(lfd < 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700330 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800331 return -1;
332 }
333 goto handle_data;
334 } else {
335 goto remote_error;
336 }
337
Elliott Hughesaa245492015-08-03 10:38:08 -0700338 while (true) {
339 if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700340 adb_close(lfd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800341 return -1;
342 }
343 id = msg.data.id;
344
345 handle_data:
Elliott Hughesf4465202015-08-24 14:27:03 -0700346 len = msg.data.size;
Elliott Hughesaa245492015-08-03 10:38:08 -0700347 if (id == ID_DONE) break;
348 if (id != ID_DATA) goto remote_error;
349 if (len > sc.max) {
350 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800351 adb_close(lfd);
352 return -1;
353 }
354
Elliott Hughesaa245492015-08-03 10:38:08 -0700355 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800356 adb_close(lfd);
357 return -1;
358 }
359
Dan Albertcc731cc2015-02-24 21:26:58 -0800360 if(!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700361 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800362 adb_close(lfd);
363 return -1;
364 }
365
Elliott Hughesaa245492015-08-03 10:38:08 -0700366 sc.total_bytes += len;
Mark Lindner76f2a932014-03-11 17:55:59 -0700367
368 if (show_progress) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700369 print_transfer_progress(sc.total_bytes, size);
Mark Lindner76f2a932014-03-11 17:55:59 -0700370 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800371 }
372
373 adb_close(lfd);
374 return 0;
375
376remote_error:
377 adb_close(lfd);
378 adb_unlink(lpath);
379
380 if(id == ID_FAIL) {
Elliott Hughesf4465202015-08-24 14:27:03 -0700381 len = msg.data.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800382 if(len > 256) len = 256;
Elliott Hughesaa245492015-08-03 10:38:08 -0700383 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800384 return -1;
385 }
386 buffer[len] = 0;
387 } else {
388 memcpy(buffer, &id, 4);
389 buffer[4] = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800390 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700391 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800392 return 0;
393}
394
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800395static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesaa245492015-08-03 10:38:08 -0700396 const char* name, void* /*cookie*/) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800397 printf("%08x %08x %08x %s\n", mode, size, time, name);
398}
399
Elliott Hughesaa245492015-08-03 10:38:08 -0700400bool do_sync_ls(const char* path) {
401 SyncConnection sc;
402 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800403
Elliott Hughesaa245492015-08-03 10:38:08 -0700404 return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800405}
406
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800407struct copyinfo
408{
409 copyinfo *next;
410 const char *src;
411 const char *dst;
412 unsigned int time;
413 unsigned int mode;
414 unsigned int size;
415 int flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416};
417
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700418static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800419 int slen = strlen(spath);
420 int dlen = strlen(dpath);
421 int nlen = strlen(name);
422 int ssize = slen + nlen + 2;
423 int dsize = dlen + nlen + 2;
424
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700425 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800426 if(ci == 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700427 fprintf(stderr, "out of memory\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800428 abort();
429 }
430
431 ci->next = 0;
432 ci->time = 0;
433 ci->mode = 0;
434 ci->size = 0;
435 ci->flag = 0;
436 ci->src = (const char*)(ci + 1);
437 ci->dst = ci->src + ssize;
438 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
439 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
440
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800441 return ci;
442}
443
Elliott Hughesaa245492015-08-03 10:38:08 -0700444static bool IsDotOrDotDot(const char* name) {
445 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
446}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800447
Elliott Hughesaa245492015-08-03 10:38:08 -0700448static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800449 copyinfo *dirlist = 0;
450 copyinfo *ci, *next;
451
Elliott Hughesaa245492015-08-03 10:38:08 -0700452 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
453 if (!dir) {
454 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800455 return -1;
456 }
457
Elliott Hughesaa245492015-08-03 10:38:08 -0700458 dirent *de;
459 while ((de = readdir(dir.get()))) {
460 if (IsDotOrDotDot(de->d_name)) continue;
461
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800462 char stat_path[PATH_MAX];
Elliott Hughesaa245492015-08-03 10:38:08 -0700463 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
464 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800465 continue;
Elliott Hughesaa245492015-08-03 10:38:08 -0700466 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800467 strcpy(stat_path, lpath);
468 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800469
Elliott Hughesaa245492015-08-03 10:38:08 -0700470 struct stat st;
471 if (!lstat(stat_path, &st)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700472 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700473 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700474 ci->next = dirlist;
475 dirlist = ci;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800476 } else {
Elliott Hughesaa245492015-08-03 10:38:08 -0700477 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
478 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700479 fprintf(stderr, "skipping special file '%s'\n", ci->src);
480 free(ci);
481 } else {
482 ci->time = st.st_mtime;
483 ci->mode = st.st_mode;
484 ci->size = st.st_size;
485 ci->next = *filelist;
486 *filelist = ci;
487 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800488 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700489 } else {
490 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800491 }
492 }
493
Elliott Hughesaa245492015-08-03 10:38:08 -0700494 // Close this directory and recurse.
495 dir.reset();
496 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800497 next = ci->next;
498 local_build_list(filelist, ci->src, ci->dst);
499 free(ci);
500 }
501
502 return 0;
503}
504
Elliott Hughesaa245492015-08-03 10:38:08 -0700505static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
506 bool check_timestamps, bool list_only) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800507 copyinfo *filelist = 0;
508 copyinfo *ci, *next;
509 int pushed = 0;
510 int skipped = 0;
511
Elliott Hughesaa245492015-08-03 10:38:08 -0700512 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
513 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800514 int tmplen = strlen(lpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800515 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700516 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800517 snprintf(tmp, tmplen, "%s/",lpath);
518 lpath = tmp;
519 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700520 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800521 int tmplen = strlen(rpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800522 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700523 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800524 snprintf(tmp, tmplen, "%s/",rpath);
525 rpath = tmp;
526 }
527
Elliott Hughesaa245492015-08-03 10:38:08 -0700528 if (local_build_list(&filelist, lpath, rpath)) {
529 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800530 }
531
Elliott Hughesaa245492015-08-03 10:38:08 -0700532 if (check_timestamps) {
533 for (ci = filelist; ci != 0; ci = ci->next) {
534 if (!sync_start_stat(sc, ci->dst)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800535 }
536 for(ci = filelist; ci != 0; ci = ci->next) {
537 unsigned int timestamp, mode, size;
Elliott Hughesaa245492015-08-03 10:38:08 -0700538 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
539 if (size == ci->size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800540 /* for links, we cannot update the atime/mtime */
Elliott Hughesaa245492015-08-03 10:38:08 -0700541 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
542 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800543 ci->flag = 1;
Elliott Hughesaa245492015-08-03 10:38:08 -0700544 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800545 }
546 }
547 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700548 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800549 next = ci->next;
Elliott Hughesaa245492015-08-03 10:38:08 -0700550 if (ci->flag == 0) {
551 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
552 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
553 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800554 }
555 pushed++;
556 } else {
557 skipped++;
558 }
559 free(ci);
560 }
561
Elliott Hughesaa245492015-08-03 10:38:08 -0700562 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800563 pushed, (pushed == 1) ? "" : "s",
564 skipped, (skipped == 1) ? "" : "s");
565
Elliott Hughesaa245492015-08-03 10:38:08 -0700566 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800567}
568
Elliott Hughesaa245492015-08-03 10:38:08 -0700569bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
570 SyncConnection sc;
571 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800572
Elliott Hughes5c742702015-07-30 17:42:01 -0700573 struct stat st;
574 if (stat(lpath, &st)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700575 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
576 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800577 }
578
Elliott Hughes5c742702015-07-30 17:42:01 -0700579 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700580 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800581 }
582
Elliott Hughesaa245492015-08-03 10:38:08 -0700583 unsigned mode;
584 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
585 std::string path_holder;
586 if (mode != 0 && S_ISDIR(mode)) {
587 // If we're copying a local file to a remote directory,
588 // we really want to copy to remote_dir + "/" + local_filename.
589 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
590 rpath = path_holder.c_str();
591 }
592 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800593}
594
595
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700596struct sync_ls_build_list_cb_args {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800597 copyinfo **filelist;
598 copyinfo **dirlist;
599 const char *rpath;
600 const char *lpath;
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700601};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800602
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700603static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
604 const char* name, void* cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800605{
606 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
607 copyinfo *ci;
608
609 if (S_ISDIR(mode)) {
610 copyinfo **dirlist = args->dirlist;
611
Elliott Hughesaa245492015-08-03 10:38:08 -0700612 // Don't try recursing down "." or "..".
613 if (IsDotOrDotDot(name)) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800614
615 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
616 ci->next = *dirlist;
617 *dirlist = ci;
618 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
619 copyinfo **filelist = args->filelist;
620
621 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
622 ci->time = time;
623 ci->mode = mode;
624 ci->size = size;
625 ci->next = *filelist;
626 *filelist = ci;
627 } else {
628 fprintf(stderr, "skipping special file '%s'\n", name);
629 }
630}
631
Elliott Hughesaa245492015-08-03 10:38:08 -0700632static bool remote_build_list(int syncfd, copyinfo **filelist,
633 const char *rpath, const char *lpath) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800634 copyinfo *dirlist = NULL;
635 sync_ls_build_list_cb_args args;
636
637 args.filelist = filelist;
638 args.dirlist = &dirlist;
639 args.rpath = rpath;
640 args.lpath = lpath;
641
Elliott Hughesaa245492015-08-03 10:38:08 -0700642 // Put the files/dirs in rpath on the lists.
643 if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
644 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800645 }
646
Elliott Hughesaa245492015-08-03 10:38:08 -0700647 // Recurse into each directory we found.
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800648 while (dirlist != NULL) {
649 copyinfo *next = dirlist->next;
Elliott Hughesaa245492015-08-03 10:38:08 -0700650 if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
651 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800652 }
653 free(dirlist);
654 dirlist = next;
655 }
656
Elliott Hughesaa245492015-08-03 10:38:08 -0700657 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658}
659
Dan Albertbac34742015-02-25 17:51:28 -0800660static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700661{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700662 struct utimbuf times = { time, time };
663 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700664
665 /* use umask for permissions */
666 mode_t mask=umask(0000);
667 umask(mask);
668 int r2 = chmod(lpath, mode & ~mask);
669
670 return r1 ? : r2;
671}
672
Elliott Hughesaa245492015-08-03 10:38:08 -0700673static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
674 int copy_attrs) {
675 // Make sure that both directory paths end in a slash.
676 std::string rpath_clean(rpath);
677 std::string lpath_clean(lpath);
678 if (rpath_clean.empty() || lpath_clean.empty()) return false;
679 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
680 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrews4d04d242014-12-12 13:12:36 -0800681
Elliott Hughesaa245492015-08-03 10:38:08 -0700682 // Recursively build the list of files to copy.
683 fprintf(stderr, "pull: building file list...\n");
684 copyinfo* filelist = nullptr;
685 if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
686
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800687 int pulled = 0;
688 int skipped = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700689 copyinfo* ci = filelist;
690 while (ci) {
691 copyinfo* next = ci->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800692 if (ci->flag == 0) {
693 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700694 if (sync_recv(sc, ci->src, ci->dst, false)) {
695 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800696 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700697
698 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700699 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700700 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800701 pulled++;
702 } else {
703 skipped++;
704 }
705 free(ci);
Elliott Hughesaa245492015-08-03 10:38:08 -0700706 ci = next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800707 }
708
709 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
710 pulled, (pulled == 1) ? "" : "s",
711 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesaa245492015-08-03 10:38:08 -0700712 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800713}
714
Elliott Hughesaa245492015-08-03 10:38:08 -0700715bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
716 SyncConnection sc;
717 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800718
Elliott Hughes5c742702015-07-30 17:42:01 -0700719 unsigned mode, time;
Elliott Hughesaa245492015-08-03 10:38:08 -0700720 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700721 if (mode == 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700722 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
723 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800724 }
725
Elliott Hughes5c742702015-07-30 17:42:01 -0700726 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
727 std::string path_holder;
728 struct stat st;
729 if (stat(lpath, &st) == 0) {
730 if (S_ISDIR(st.st_mode)) {
731 // If we're copying a remote file to a local directory,
732 // we really want to copy to local_dir + "/" + basename(remote).
733 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
734 lpath = path_holder.c_str();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800735 }
736 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700737 if (sync_recv(sc, rpath, lpath, show_progress)) {
738 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800739 } else {
Elliott Hughes5c742702015-07-30 17:42:01 -0700740 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700741 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700742 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800743 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700744 return true;
745 } else if (S_ISDIR(mode)) {
746 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800747 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700748
749 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
750 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800751}
752
Elliott Hughesaa245492015-08-03 10:38:08 -0700753bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesd236d072015-04-21 10:17:07 -0700754 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800755
Elliott Hughesaa245492015-08-03 10:38:08 -0700756 SyncConnection sc;
757 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800758
Elliott Hughesaa245492015-08-03 10:38:08 -0700759 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 -0800760}