blob: 3e3bb574029bd8997ca5e409ea9fffccfa0a1db2 [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>
Elliott Hughesae5a6c02015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030
Elliott Hughesa925dba2015-08-24 14:49:43 -070031#include <memory>
Elliott Hughes6d929972015-10-27 13:40:35 -070032#include <vector>
Elliott Hughesa925dba2015-08-24 14:49:43 -070033
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080035
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include "adb.h"
37#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080038#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040039#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040#include "file_sync_service.h"
Elliott Hughesb708d162015-10-27 16:03:15 -070041#include "line_printer.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042
Elliott Hughesae5a6c02015-09-27 12:55:37 -070043#include <base/file.h>
Elliott Hughesaa245492015-08-03 10:38:08 -070044#include <base/strings.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070045#include <base/stringprintf.h>
46
Elliott Hughesaa245492015-08-03 10:38:08 -070047struct syncsendbuf {
48 unsigned id;
49 unsigned size;
50 char data[SYNC_DATA_MAX];
51};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080052
Elliott Hughesaa245492015-08-03 10:38:08 -070053class SyncConnection {
54 public:
Elliott Hughesb708d162015-10-27 16:03:15 -070055 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesaa245492015-08-03 10:38:08 -070056 max = SYNC_DATA_MAX; // TODO: decide at runtime.
57
58 std::string error;
59 fd = adb_connect("sync:", &error);
60 if (fd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -070061 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -070062 }
63 }
64
65 ~SyncConnection() {
66 if (!IsValid()) return;
67
Spencer Low351ecd12015-10-14 17:32:44 -070068 if (SendQuit()) {
69 // We sent a quit command, so the server should be doing orderly
70 // shutdown soon. But if we encountered an error while we were using
71 // the connection, the server might still be sending data (before
72 // doing orderly shutdown), in which case we won't wait for all of
73 // the data nor the coming orderly shutdown. In the common success
74 // case, this will wait for the server to do orderly shutdown.
75 ReadOrderlyShutdown(fd);
76 }
Elliott Hughesaa245492015-08-03 10:38:08 -070077 adb_close(fd);
78 }
79
80 bool IsValid() { return fd >= 0; }
81
Elliott Hughesae5a6c02015-09-27 12:55:37 -070082 bool SendRequest(int id, const char* path_and_mode) {
83 size_t path_length = strlen(path_and_mode);
84 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -070085 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -070086 errno = ENAMETOOLONG;
87 return false;
88 }
89
90 // Sending header and payload in a single write makes a noticeable
91 // difference to "adb sync" performance.
Elliott Hughes6d929972015-10-27 13:40:35 -070092 std::vector<char> buf(sizeof(SyncRequest) + path_length);
93 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -070094 req->id = id;
95 req->path_length = path_length;
96 char* data = reinterpret_cast<char*>(req + 1);
97 memcpy(data, path_and_mode, path_length);
98
Elliott Hughes6d929972015-10-27 13:40:35 -070099 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700100 }
101
102 // Sending header, payload, and footer in a single write makes a huge
103 // difference to "adb sync" performance.
104 bool SendSmallFile(const char* path_and_mode,
Elliott Hughesb708d162015-10-27 16:03:15 -0700105 const char* rpath,
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700106 const char* data, size_t data_length,
107 unsigned mtime) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700108 Print(rpath);
109
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700110 size_t path_length = strlen(path_and_mode);
111 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700112 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700113 errno = ENAMETOOLONG;
114 return false;
115 }
116
Elliott Hughes6d929972015-10-27 13:40:35 -0700117 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700118 sizeof(SyncRequest) + data_length +
Elliott Hughes6d929972015-10-27 13:40:35 -0700119 sizeof(SyncRequest));
120 char* p = &buf[0];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700121
122 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
123 req_send->id = ID_SEND;
124 req_send->path_length = path_length;
125 p += sizeof(SyncRequest);
126 memcpy(p, path_and_mode, path_length);
127 p += path_length;
128
129 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
130 req_data->id = ID_DATA;
131 req_data->path_length = data_length;
132 p += sizeof(SyncRequest);
133 memcpy(p, data, data_length);
134 p += data_length;
135
136 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
137 req_done->id = ID_DONE;
138 req_done->path_length = mtime;
139 p += sizeof(SyncRequest);
140
Elliott Hughes6d929972015-10-27 13:40:35 -0700141 if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700142
143 total_bytes += data_length;
144 return true;
145 }
146
147 bool CopyDone(const char* from, const char* to) {
148 syncmsg msg;
149 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700150 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700151 return false;
152 }
153 if (msg.status.id == ID_OKAY) {
154 return true;
155 }
156 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700157 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700158 return false;
159 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700160 return ReportCopyFailure(from, to, msg);
161 }
162
163 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700164 std::vector<char> buf(msg.status.msglen + 1);
165 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700166 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
167 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700168 return false;
169 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700170 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700171 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700172 return false;
173 }
174
Elliott Hughesb708d162015-10-27 16:03:15 -0700175 std::string TransferRate() {
176 uint64_t ms = CurrentTimeMs() - start_time_ms_;
177 if (total_bytes == 0 || ms == 0) return "";
178
179 double s = static_cast<double>(ms) / 1000LL;
180 double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
181 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
182 rate, total_bytes, s);
183 }
184
185 void Print(const std::string& s) {
186 // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
187 line_printer_.Print(s, LinePrinter::ELIDE);
188 }
189
Josh Gao983c41c2015-11-02 17:15:57 -0800190 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
191 std::string s;
192 va_list ap;
193 va_start(ap, fmt);
194 android::base::StringAppendV(&s, fmt, ap);
195 va_end(ap);
196
197 Print(s);
198 }
199
Elliott Hughesb708d162015-10-27 16:03:15 -0700200 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
201 std::string s = "adb: error: ";
202
203 va_list ap;
204 va_start(ap, fmt);
205 android::base::StringAppendV(&s, fmt, ap);
206 va_end(ap);
207
208 line_printer_.Print(s, LinePrinter::FULL);
209 }
210
Elliott Hughesaa245492015-08-03 10:38:08 -0700211 uint64_t total_bytes;
212
213 // TODO: add a char[max] buffer here, to replace syncsendbuf...
214 int fd;
215 size_t max;
216
217 private:
Elliott Hughesb708d162015-10-27 16:03:15 -0700218 uint64_t start_time_ms_;
219
220 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700221
Spencer Low351ecd12015-10-14 17:32:44 -0700222 bool SendQuit() {
223 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700224 }
225
Elliott Hughesb708d162015-10-27 16:03:15 -0700226 static uint64_t CurrentTimeMs() {
227 struct timeval tv;
228 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
229 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesaa245492015-08-03 10:38:08 -0700230 }
231};
232
233typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
234
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700235static bool sync_ls(SyncConnection& sc, const char* path, sync_ls_cb func, void* cookie) {
236 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700237
238 while (true) {
239 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700240 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700241
242 if (msg.dent.id == ID_DONE) return true;
243 if (msg.dent.id != ID_DENT) return false;
244
Elliott Hughesf4465202015-08-24 14:27:03 -0700245 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700246 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800247
Elliott Hughes5c742702015-07-30 17:42:01 -0700248 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700249 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800250 buf[len] = 0;
251
Elliott Hughesf4465202015-08-24 14:27:03 -0700252 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800253 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800254}
255
Elliott Hughesaa245492015-08-03 10:38:08 -0700256static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
257 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800258 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700259 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
260 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800261 }
262
Elliott Hughesf4465202015-08-24 14:27:03 -0700263 if (timestamp) *timestamp = msg.stat.time;
264 if (mode) *mode = msg.stat.mode;
265 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266
Elliott Hughesaa245492015-08-03 10:38:08 -0700267 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800268}
269
Elliott Hughesaa245492015-08-03 10:38:08 -0700270static bool sync_stat(SyncConnection& sc, const char* path,
271 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700272 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800273}
274
Elliott Hughesb708d162015-10-27 16:03:15 -0700275static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
276 const char* lpath, const char* rpath,
277 unsigned mtime) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700278 if (!sc.SendRequest(ID_SEND, path_and_mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700279 sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700280 return false;
281 }
282
Elliott Hughesb708d162015-10-27 16:03:15 -0700283 struct stat st;
284 if (stat(lpath, &st) == -1) {
285 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
286 return false;
Spencer Lowd8cce182015-08-28 01:07:30 -0700287 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288
Elliott Hughesb708d162015-10-27 16:03:15 -0700289 uint64_t total_size = st.st_size;
290 uint64_t bytes_copied = 0;
291
292 int lfd = adb_open(lpath, O_RDONLY);
Elliott Hughesaa245492015-08-03 10:38:08 -0700293 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700294 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
Spencer Lowd8cce182015-08-28 01:07:30 -0700295 return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700296 }
297
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700298 syncsendbuf sbuf;
299 sbuf.id = ID_DATA;
Elliott Hughesaa245492015-08-03 10:38:08 -0700300 while (true) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700301 int ret = adb_read(lfd, sbuf.data, sc.max);
Elliott Hughes8fcd8bc2015-08-25 10:59:45 -0700302 if (ret <= 0) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700303 if (ret < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700304 sc.Error("cannot read '%s': %s", lpath, strerror(errno));
Spencer Lowd8cce182015-08-28 01:07:30 -0700305 adb_close(lfd);
306 return false;
307 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800308 break;
309 }
310
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700311 sbuf.size = ret;
312 if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700313 adb_close(lfd);
314 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800315 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700316 sc.total_bytes += ret;
Mark Lindner76f2a932014-03-11 17:55:59 -0700317
Elliott Hughesb708d162015-10-27 16:03:15 -0700318 bytes_copied += ret;
319
320 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
Josh Gao983c41c2015-11-02 17:15:57 -0800321 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800322 }
323
324 adb_close(lfd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800325
Elliott Hughesaa245492015-08-03 10:38:08 -0700326 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800327 msg.data.id = ID_DONE;
Elliott Hughesf4465202015-08-24 14:27:03 -0700328 msg.data.size = mtime;
Elliott Hughes081696d2015-09-03 11:06:00 -0700329 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700330 sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
Elliott Hughesaa245492015-08-03 10:38:08 -0700331 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800332 }
333
Elliott Hughesaa245492015-08-03 10:38:08 -0700334 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800335}
336
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700337static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700338 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700339{
340 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
341
342 if (S_ISLNK(mode)) {
343#if !defined(_WIN32)
344 char buf[PATH_MAX];
345 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
346 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700347 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700348 return false;
349 }
350 buf[data_length++] = '\0';
351
Elliott Hughesb708d162015-10-27 16:03:15 -0700352 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700353 return sc.CopyDone(lpath, rpath);
354#endif
355 }
356
357 if (!S_ISREG(mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700358 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700359 return false;
360 }
361
362 struct stat st;
363 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700364 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700365 return false;
366 }
367 if (st.st_size < SYNC_DATA_MAX) {
368 std::string data;
369 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700370 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700371 return false;
372 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700373 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
374 return false;
375 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700376 } else {
Elliott Hughesb708d162015-10-27 16:03:15 -0700377 if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
378 return false;
379 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700380 }
381 return sc.CopyDone(lpath, rpath);
382}
383
Elliott Hughesb708d162015-10-27 16:03:15 -0700384static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
385 sc.Print(rpath);
386
Elliott Hughesaa245492015-08-03 10:38:08 -0700387 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700388 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700389
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700390 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800391
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700392 adb_unlink(lpath);
393 mkdirs(lpath);
394 int lfd = adb_creat(lpath, 0644);
395 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700396 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700397 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800398 }
399
Elliott Hughesb708d162015-10-27 16:03:15 -0700400 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700401 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700402 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700403 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700404 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700405 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700406 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800407 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800408
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700409 if (msg.data.id == ID_DONE) break;
410
411 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800412 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700413 adb_unlink(lpath);
414 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700415 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416 }
417
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700418 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700419 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800420 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700421 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700422 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800423 }
424
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700425 char buffer[SYNC_DATA_MAX];
426 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800427 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700428 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700429 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800430 }
431
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700432 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700433 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700434 adb_close(lfd);
435 adb_unlink(lpath);
436 return false;
437 }
438
439 sc.total_bytes += msg.data.size;
Mark Lindner76f2a932014-03-11 17:55:59 -0700440
Elliott Hughesb708d162015-10-27 16:03:15 -0700441 bytes_copied += msg.data.size;
442
443 int percentage = static_cast<int>(bytes_copied * 100 / size);
Josh Gao983c41c2015-11-02 17:15:57 -0800444 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445 }
446
447 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700448 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800449}
450
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800451static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesaa245492015-08-03 10:38:08 -0700452 const char* name, void* /*cookie*/) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800453 printf("%08x %08x %08x %s\n", mode, size, time, name);
454}
455
Elliott Hughesaa245492015-08-03 10:38:08 -0700456bool do_sync_ls(const char* path) {
457 SyncConnection sc;
458 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800459
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700460 return sync_ls(sc, path, do_sync_ls_cb, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800461}
462
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800463struct copyinfo
464{
465 copyinfo *next;
466 const char *src;
467 const char *dst;
468 unsigned int time;
469 unsigned int mode;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700470 uint64_t size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471 int flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800472};
473
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700474static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800475 int slen = strlen(spath);
476 int dlen = strlen(dpath);
477 int nlen = strlen(name);
478 int ssize = slen + nlen + 2;
479 int dsize = dlen + nlen + 2;
480
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700481 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
Elliott Hughesb708d162015-10-27 16:03:15 -0700482 if (ci == 0) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700483 fprintf(stderr, "out of memory\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800484 abort();
485 }
486
487 ci->next = 0;
488 ci->time = 0;
489 ci->mode = 0;
490 ci->size = 0;
491 ci->flag = 0;
492 ci->src = (const char*)(ci + 1);
493 ci->dst = ci->src + ssize;
494 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
495 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
496
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800497 return ci;
498}
499
Elliott Hughesaa245492015-08-03 10:38:08 -0700500static bool IsDotOrDotDot(const char* name) {
501 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
502}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800503
Elliott Hughesb708d162015-10-27 16:03:15 -0700504static int local_build_list(SyncConnection& sc,
505 copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800506 copyinfo *dirlist = 0;
507 copyinfo *ci, *next;
508
Elliott Hughesaa245492015-08-03 10:38:08 -0700509 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
510 if (!dir) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700511 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800512 return -1;
513 }
514
Elliott Hughesb708d162015-10-27 16:03:15 -0700515 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700516 while ((de = readdir(dir.get()))) {
517 if (IsDotOrDotDot(de->d_name)) continue;
518
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800519 char stat_path[PATH_MAX];
Elliott Hughesaa245492015-08-03 10:38:08 -0700520 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700521 sc.Error("skipping long path '%s%s'", lpath, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800522 continue;
Elliott Hughesaa245492015-08-03 10:38:08 -0700523 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800524 strcpy(stat_path, lpath);
525 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800526
Elliott Hughesaa245492015-08-03 10:38:08 -0700527 struct stat st;
528 if (!lstat(stat_path, &st)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700529 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700530 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700531 ci->next = dirlist;
532 dirlist = ci;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800533 } else {
Elliott Hughesaa245492015-08-03 10:38:08 -0700534 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
535 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700536 sc.Error("skipping special file '%s'", ci->src);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700537 free(ci);
538 } else {
539 ci->time = st.st_mtime;
540 ci->mode = st.st_mode;
541 ci->size = st.st_size;
542 ci->next = *filelist;
543 *filelist = ci;
544 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800545 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700546 } else {
Elliott Hughesb708d162015-10-27 16:03:15 -0700547 sc.Error("cannot lstat '%s': %s",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800548 }
549 }
550
Elliott Hughesaa245492015-08-03 10:38:08 -0700551 // Close this directory and recurse.
552 dir.reset();
553 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800554 next = ci->next;
Elliott Hughesb708d162015-10-27 16:03:15 -0700555 local_build_list(sc, filelist, ci->src, ci->dst);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800556 free(ci);
557 }
558
559 return 0;
560}
561
Elliott Hughesaa245492015-08-03 10:38:08 -0700562static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
563 bool check_timestamps, bool list_only) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800564 copyinfo *filelist = 0;
565 copyinfo *ci, *next;
566 int pushed = 0;
567 int skipped = 0;
568
Elliott Hughesaa245492015-08-03 10:38:08 -0700569 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
570 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800571 int tmplen = strlen(lpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800572 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700573 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800574 snprintf(tmp, tmplen, "%s/",lpath);
575 lpath = tmp;
576 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700577 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800578 int tmplen = strlen(rpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800579 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700580 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800581 snprintf(tmp, tmplen, "%s/",rpath);
582 rpath = tmp;
583 }
584
Elliott Hughesb708d162015-10-27 16:03:15 -0700585 if (local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700586 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800587 }
588
Elliott Hughesaa245492015-08-03 10:38:08 -0700589 if (check_timestamps) {
590 for (ci = filelist; ci != 0; ci = ci->next) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700591 if (!sc.SendRequest(ID_STAT, ci->dst)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800592 }
593 for(ci = filelist; ci != 0; ci = ci->next) {
594 unsigned int timestamp, mode, size;
Elliott Hughesaa245492015-08-03 10:38:08 -0700595 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
596 if (size == ci->size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800597 /* for links, we cannot update the atime/mtime */
Elliott Hughesaa245492015-08-03 10:38:08 -0700598 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
599 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800600 ci->flag = 1;
Elliott Hughesaa245492015-08-03 10:38:08 -0700601 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800602 }
603 }
604 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700605 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800606 next = ci->next;
Elliott Hughesaa245492015-08-03 10:38:08 -0700607 if (ci->flag == 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700608 if (list_only) {
609 fprintf(stderr, "would push: %s -> %s\n", ci->src, ci->dst);
610 } else {
611 if (!sync_send(sc, ci->src, ci->dst, ci->time, ci->mode)) {
612 return false;
613 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800614 }
615 pushed++;
616 } else {
617 skipped++;
618 }
619 free(ci);
620 }
621
Josh Gao983c41c2015-11-02 17:15:57 -0800622 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath, pushed,
623 (pushed == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
624 sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700625 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800626}
627
Elliott Hughesb708d162015-10-27 16:03:15 -0700628bool do_sync_push(const char* lpath, const char* rpath) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700629 SyncConnection sc;
630 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800631
Elliott Hughes5c742702015-07-30 17:42:01 -0700632 struct stat st;
633 if (stat(lpath, &st)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700634 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
Elliott Hughesaa245492015-08-03 10:38:08 -0700635 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800636 }
637
Elliott Hughes5c742702015-07-30 17:42:01 -0700638 if (S_ISDIR(st.st_mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700639 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800640 }
641
Elliott Hughesaa245492015-08-03 10:38:08 -0700642 unsigned mode;
643 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
644 std::string path_holder;
645 if (mode != 0 && S_ISDIR(mode)) {
646 // If we're copying a local file to a remote directory,
647 // we really want to copy to remote_dir + "/" + local_filename.
648 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
649 rpath = path_holder.c_str();
650 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700651 bool result = sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode);
652 sc.Print("\n");
653 return result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800654}
655
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700656struct sync_ls_build_list_cb_args {
Elliott Hughesb708d162015-10-27 16:03:15 -0700657 SyncConnection* sc;
658 copyinfo** filelist;
659 copyinfo** dirlist;
660 const char* rpath;
661 const char* lpath;
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700662};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800663
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700664static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
665 const char* name, void* cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800666{
Elliott Hughesb708d162015-10-27 16:03:15 -0700667 sync_ls_build_list_cb_args* args = static_cast<sync_ls_build_list_cb_args*>(cookie);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800668 copyinfo *ci;
669
670 if (S_ISDIR(mode)) {
671 copyinfo **dirlist = args->dirlist;
672
Elliott Hughesaa245492015-08-03 10:38:08 -0700673 // Don't try recursing down "." or "..".
674 if (IsDotOrDotDot(name)) return;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800675
676 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
677 ci->next = *dirlist;
678 *dirlist = ci;
679 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
680 copyinfo **filelist = args->filelist;
681
682 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
683 ci->time = time;
684 ci->mode = mode;
685 ci->size = size;
686 ci->next = *filelist;
687 *filelist = ci;
688 } else {
Josh Gao983c41c2015-11-02 17:15:57 -0800689 args->sc->Printf("skipping special file '%s'\n", name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800690 }
691}
692
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700693static bool remote_build_list(SyncConnection& sc, copyinfo **filelist,
Elliott Hughesaa245492015-08-03 10:38:08 -0700694 const char *rpath, const char *lpath) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700695 copyinfo* dirlist = nullptr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800696
Elliott Hughesb708d162015-10-27 16:03:15 -0700697 sync_ls_build_list_cb_args args;
698 args.sc = &sc;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800699 args.filelist = filelist;
700 args.dirlist = &dirlist;
701 args.rpath = rpath;
702 args.lpath = lpath;
703
Elliott Hughesaa245492015-08-03 10:38:08 -0700704 // Put the files/dirs in rpath on the lists.
Elliott Hughesb708d162015-10-27 16:03:15 -0700705 if (!sync_ls(sc, rpath, sync_ls_build_list_cb, &args)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700706 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800707 }
708
Elliott Hughesaa245492015-08-03 10:38:08 -0700709 // Recurse into each directory we found.
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800710 while (dirlist != NULL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700711 copyinfo* next = dirlist->next;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700712 if (!remote_build_list(sc, filelist, dirlist->src, dirlist->dst)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700713 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800714 }
715 free(dirlist);
716 dirlist = next;
717 }
718
Elliott Hughesaa245492015-08-03 10:38:08 -0700719 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800720}
721
Dan Albertbac34742015-02-25 17:51:28 -0800722static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700723{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700724 struct utimbuf times = { time, time };
725 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700726
727 /* use umask for permissions */
728 mode_t mask=umask(0000);
729 umask(mask);
730 int r2 = chmod(lpath, mode & ~mask);
731
732 return r1 ? : r2;
733}
734
Elliott Hughesaa245492015-08-03 10:38:08 -0700735static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
736 int copy_attrs) {
737 // Make sure that both directory paths end in a slash.
738 std::string rpath_clean(rpath);
739 std::string lpath_clean(lpath);
740 if (rpath_clean.empty() || lpath_clean.empty()) return false;
741 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
742 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrews4d04d242014-12-12 13:12:36 -0800743
Elliott Hughesaa245492015-08-03 10:38:08 -0700744 // Recursively build the list of files to copy.
Elliott Hughesb708d162015-10-27 16:03:15 -0700745 sc.Print("pull: building file list...");
Elliott Hughesaa245492015-08-03 10:38:08 -0700746 copyinfo* filelist = nullptr;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700747 if (!remote_build_list(sc, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700748
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800749 int pulled = 0;
750 int skipped = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700751 copyinfo* ci = filelist;
752 while (ci) {
753 copyinfo* next = ci->next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800754 if (ci->flag == 0) {
Josh Gao983c41c2015-11-02 17:15:57 -0800755 sc.Printf("pull: %s -> %s", ci->src, ci->dst);
Elliott Hughesb708d162015-10-27 16:03:15 -0700756 if (!sync_recv(sc, ci->src, ci->dst)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700757 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800758 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700759
760 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700761 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700762 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800763 pulled++;
764 } else {
765 skipped++;
766 }
767 free(ci);
Elliott Hughesaa245492015-08-03 10:38:08 -0700768 ci = next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800769 }
770
Josh Gao983c41c2015-11-02 17:15:57 -0800771 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath, pulled,
772 (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
773 sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700774 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800775}
776
Elliott Hughesb708d162015-10-27 16:03:15 -0700777bool do_sync_pull(const char* rpath, const char* lpath, int copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700778 SyncConnection sc;
779 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780
Elliott Hughes5c742702015-07-30 17:42:01 -0700781 unsigned mode, time;
Elliott Hughesaa245492015-08-03 10:38:08 -0700782 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700783 if (mode == 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700784 sc.Error("remote object '%s' does not exist", rpath);
Elliott Hughesaa245492015-08-03 10:38:08 -0700785 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800786 }
787
Elliott Hughes5c742702015-07-30 17:42:01 -0700788 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
789 std::string path_holder;
790 struct stat st;
791 if (stat(lpath, &st) == 0) {
792 if (S_ISDIR(st.st_mode)) {
793 // If we're copying a remote file to a local directory,
794 // we really want to copy to local_dir + "/" + basename(remote).
795 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
796 lpath = path_holder.c_str();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800797 }
798 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700799 if (!sync_recv(sc, rpath, lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700800 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800801 } else {
Elliott Hughes5c742702015-07-30 17:42:01 -0700802 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700803 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700804 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800805 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700806 sc.Print("\n");
Elliott Hughesaa245492015-08-03 10:38:08 -0700807 return true;
808 } else if (S_ISDIR(mode)) {
809 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800810 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700811
Elliott Hughesb708d162015-10-27 16:03:15 -0700812 sc.Error("remote object '%s' not a file or directory", rpath);
Elliott Hughesaa245492015-08-03 10:38:08 -0700813 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800814}
815
Elliott Hughesaa245492015-08-03 10:38:08 -0700816bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700817 SyncConnection sc;
818 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800819
Elliott Hughesaa245492015-08-03 10:38:08 -0700820 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 -0800821}