blob: 6087c06f23eecf51e3ca9bac9a8ce1735ef1feb4 [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
Josh Gaocda6a2b2015-11-02 16:45:47 -080031#include <functional>
Elliott Hughesa925dba2015-08-24 14:49:43 -070032#include <memory>
Elliott Hughes6d929972015-10-27 13:40:35 -070033#include <vector>
Elliott Hughesa925dba2015-08-24 14:49:43 -070034
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080036
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037#include "adb.h"
38#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080039#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040040#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080041#include "file_sync_service.h"
Elliott Hughesb708d162015-10-27 16:03:15 -070042#include "line_printer.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043
Elliott Hughesae5a6c02015-09-27 12:55:37 -070044#include <base/file.h>
Elliott Hughesaa245492015-08-03 10:38:08 -070045#include <base/strings.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070046#include <base/stringprintf.h>
47
Elliott Hughesaa245492015-08-03 10:38:08 -070048struct syncsendbuf {
49 unsigned id;
50 unsigned size;
51 char data[SYNC_DATA_MAX];
52};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080053
Elliott Hughesaa245492015-08-03 10:38:08 -070054class SyncConnection {
55 public:
Elliott Hughesb708d162015-10-27 16:03:15 -070056 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesaa245492015-08-03 10:38:08 -070057 max = SYNC_DATA_MAX; // TODO: decide at runtime.
58
59 std::string error;
60 fd = adb_connect("sync:", &error);
61 if (fd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -070062 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -070063 }
64 }
65
66 ~SyncConnection() {
67 if (!IsValid()) return;
68
Spencer Low351ecd12015-10-14 17:32:44 -070069 if (SendQuit()) {
70 // We sent a quit command, so the server should be doing orderly
71 // shutdown soon. But if we encountered an error while we were using
72 // the connection, the server might still be sending data (before
73 // doing orderly shutdown), in which case we won't wait for all of
74 // the data nor the coming orderly shutdown. In the common success
75 // case, this will wait for the server to do orderly shutdown.
76 ReadOrderlyShutdown(fd);
77 }
Elliott Hughesaa245492015-08-03 10:38:08 -070078 adb_close(fd);
79 }
80
81 bool IsValid() { return fd >= 0; }
82
Elliott Hughesae5a6c02015-09-27 12:55:37 -070083 bool SendRequest(int id, const char* path_and_mode) {
84 size_t path_length = strlen(path_and_mode);
85 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -070086 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -070087 errno = ENAMETOOLONG;
88 return false;
89 }
90
91 // Sending header and payload in a single write makes a noticeable
92 // difference to "adb sync" performance.
Elliott Hughes6d929972015-10-27 13:40:35 -070093 std::vector<char> buf(sizeof(SyncRequest) + path_length);
94 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -070095 req->id = id;
96 req->path_length = path_length;
97 char* data = reinterpret_cast<char*>(req + 1);
98 memcpy(data, path_and_mode, path_length);
99
Elliott Hughes6d929972015-10-27 13:40:35 -0700100 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700101 }
102
103 // Sending header, payload, and footer in a single write makes a huge
104 // difference to "adb sync" performance.
105 bool SendSmallFile(const char* path_and_mode,
Elliott Hughesb708d162015-10-27 16:03:15 -0700106 const char* rpath,
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700107 const char* data, size_t data_length,
108 unsigned mtime) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700109 Print(rpath);
110
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700111 size_t path_length = strlen(path_and_mode);
112 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700113 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700114 errno = ENAMETOOLONG;
115 return false;
116 }
117
Elliott Hughes6d929972015-10-27 13:40:35 -0700118 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700119 sizeof(SyncRequest) + data_length +
Elliott Hughes6d929972015-10-27 13:40:35 -0700120 sizeof(SyncRequest));
121 char* p = &buf[0];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700122
123 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
124 req_send->id = ID_SEND;
125 req_send->path_length = path_length;
126 p += sizeof(SyncRequest);
127 memcpy(p, path_and_mode, path_length);
128 p += path_length;
129
130 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
131 req_data->id = ID_DATA;
132 req_data->path_length = data_length;
133 p += sizeof(SyncRequest);
134 memcpy(p, data, data_length);
135 p += data_length;
136
137 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
138 req_done->id = ID_DONE;
139 req_done->path_length = mtime;
140 p += sizeof(SyncRequest);
141
Elliott Hughes6d929972015-10-27 13:40:35 -0700142 if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700143
144 total_bytes += data_length;
145 return true;
146 }
147
148 bool CopyDone(const char* from, const char* to) {
149 syncmsg msg;
150 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700151 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700152 return false;
153 }
154 if (msg.status.id == ID_OKAY) {
155 return true;
156 }
157 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700158 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700159 return false;
160 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700161 return ReportCopyFailure(from, to, msg);
162 }
163
164 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700165 std::vector<char> buf(msg.status.msglen + 1);
166 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700167 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
168 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700169 return false;
170 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700171 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700172 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700173 return false;
174 }
175
Elliott Hughesb708d162015-10-27 16:03:15 -0700176 std::string TransferRate() {
177 uint64_t ms = CurrentTimeMs() - start_time_ms_;
178 if (total_bytes == 0 || ms == 0) return "";
179
180 double s = static_cast<double>(ms) / 1000LL;
181 double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
182 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
183 rate, total_bytes, s);
184 }
185
186 void Print(const std::string& s) {
187 // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
188 line_printer_.Print(s, LinePrinter::ELIDE);
189 }
190
Josh Gao983c41c2015-11-02 17:15:57 -0800191 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
192 std::string s;
193 va_list ap;
194 va_start(ap, fmt);
195 android::base::StringAppendV(&s, fmt, ap);
196 va_end(ap);
197
198 Print(s);
199 }
200
Elliott Hughesb708d162015-10-27 16:03:15 -0700201 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
202 std::string s = "adb: error: ";
203
204 va_list ap;
205 va_start(ap, fmt);
206 android::base::StringAppendV(&s, fmt, ap);
207 va_end(ap);
208
209 line_printer_.Print(s, LinePrinter::FULL);
210 }
211
Elliott Hughesaa245492015-08-03 10:38:08 -0700212 uint64_t total_bytes;
213
214 // TODO: add a char[max] buffer here, to replace syncsendbuf...
215 int fd;
216 size_t max;
217
218 private:
Elliott Hughesb708d162015-10-27 16:03:15 -0700219 uint64_t start_time_ms_;
220
221 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700222
Spencer Low351ecd12015-10-14 17:32:44 -0700223 bool SendQuit() {
224 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700225 }
226
Elliott Hughesb708d162015-10-27 16:03:15 -0700227 static uint64_t CurrentTimeMs() {
228 struct timeval tv;
229 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
230 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesaa245492015-08-03 10:38:08 -0700231 }
232};
233
Josh Gaocda6a2b2015-11-02 16:45:47 -0800234typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700235
Josh Gaocda6a2b2015-11-02 16:45:47 -0800236static bool sync_ls(SyncConnection& sc, const char* path,
237 std::function<sync_ls_cb> func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700238 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700239
240 while (true) {
241 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700242 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700243
244 if (msg.dent.id == ID_DONE) return true;
245 if (msg.dent.id != ID_DENT) return false;
246
Elliott Hughesf4465202015-08-24 14:27:03 -0700247 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700248 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800249
Elliott Hughes5c742702015-07-30 17:42:01 -0700250 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700251 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800252 buf[len] = 0;
253
Josh Gaocda6a2b2015-11-02 16:45:47 -0800254 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800255 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800256}
257
Elliott Hughesaa245492015-08-03 10:38:08 -0700258static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
259 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800260 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700261 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
262 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800263 }
264
Elliott Hughesf4465202015-08-24 14:27:03 -0700265 if (timestamp) *timestamp = msg.stat.time;
266 if (mode) *mode = msg.stat.mode;
267 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800268
Elliott Hughesaa245492015-08-03 10:38:08 -0700269 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800270}
271
Elliott Hughesaa245492015-08-03 10:38:08 -0700272static bool sync_stat(SyncConnection& sc, const char* path,
273 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700274 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800275}
276
Elliott Hughesb708d162015-10-27 16:03:15 -0700277static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
278 const char* lpath, const char* rpath,
279 unsigned mtime) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700280 if (!sc.SendRequest(ID_SEND, path_and_mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700281 sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700282 return false;
283 }
284
Elliott Hughesb708d162015-10-27 16:03:15 -0700285 struct stat st;
286 if (stat(lpath, &st) == -1) {
287 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
288 return false;
Spencer Lowd8cce182015-08-28 01:07:30 -0700289 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800290
Elliott Hughesb708d162015-10-27 16:03:15 -0700291 uint64_t total_size = st.st_size;
292 uint64_t bytes_copied = 0;
293
294 int lfd = adb_open(lpath, O_RDONLY);
Elliott Hughesaa245492015-08-03 10:38:08 -0700295 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700296 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
Spencer Lowd8cce182015-08-28 01:07:30 -0700297 return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700298 }
299
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700300 syncsendbuf sbuf;
301 sbuf.id = ID_DATA;
Elliott Hughesaa245492015-08-03 10:38:08 -0700302 while (true) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700303 int ret = adb_read(lfd, sbuf.data, sc.max);
Elliott Hughes8fcd8bc2015-08-25 10:59:45 -0700304 if (ret <= 0) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700305 if (ret < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700306 sc.Error("cannot read '%s': %s", lpath, strerror(errno));
Spencer Lowd8cce182015-08-28 01:07:30 -0700307 adb_close(lfd);
308 return false;
309 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800310 break;
311 }
312
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700313 sbuf.size = ret;
314 if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700315 adb_close(lfd);
316 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800317 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700318 sc.total_bytes += ret;
Mark Lindner76f2a932014-03-11 17:55:59 -0700319
Elliott Hughesb708d162015-10-27 16:03:15 -0700320 bytes_copied += ret;
321
322 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
Josh Gao983c41c2015-11-02 17:15:57 -0800323 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800324 }
325
326 adb_close(lfd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800327
Elliott Hughesaa245492015-08-03 10:38:08 -0700328 syncmsg msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800329 msg.data.id = ID_DONE;
Elliott Hughesf4465202015-08-24 14:27:03 -0700330 msg.data.size = mtime;
Elliott Hughes081696d2015-09-03 11:06:00 -0700331 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700332 sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
Elliott Hughesaa245492015-08-03 10:38:08 -0700333 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800334 }
335
Elliott Hughesaa245492015-08-03 10:38:08 -0700336 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800337}
338
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700339static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700340 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700341{
342 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
343
344 if (S_ISLNK(mode)) {
345#if !defined(_WIN32)
346 char buf[PATH_MAX];
347 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
348 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700349 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700350 return false;
351 }
352 buf[data_length++] = '\0';
353
Elliott Hughesb708d162015-10-27 16:03:15 -0700354 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700355 return sc.CopyDone(lpath, rpath);
356#endif
357 }
358
359 if (!S_ISREG(mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700360 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700361 return false;
362 }
363
364 struct stat st;
365 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700366 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700367 return false;
368 }
369 if (st.st_size < SYNC_DATA_MAX) {
370 std::string data;
371 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700372 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700373 return false;
374 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700375 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
376 return false;
377 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700378 } else {
Elliott Hughesb708d162015-10-27 16:03:15 -0700379 if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
380 return false;
381 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700382 }
383 return sc.CopyDone(lpath, rpath);
384}
385
Elliott Hughesb708d162015-10-27 16:03:15 -0700386static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
387 sc.Print(rpath);
388
Elliott Hughesaa245492015-08-03 10:38:08 -0700389 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700390 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700391
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700392 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800393
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700394 adb_unlink(lpath);
395 mkdirs(lpath);
396 int lfd = adb_creat(lpath, 0644);
397 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700398 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700399 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800400 }
401
Elliott Hughesb708d162015-10-27 16:03:15 -0700402 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700403 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700404 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700405 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700406 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700407 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700408 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800409 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800410
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700411 if (msg.data.id == ID_DONE) break;
412
413 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800414 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700415 adb_unlink(lpath);
416 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700417 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800418 }
419
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700420 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700421 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 -0800422 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700423 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700424 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800425 }
426
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700427 char buffer[SYNC_DATA_MAX];
428 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800429 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700430 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700431 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800432 }
433
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700434 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700435 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700436 adb_close(lfd);
437 adb_unlink(lpath);
438 return false;
439 }
440
441 sc.total_bytes += msg.data.size;
Mark Lindner76f2a932014-03-11 17:55:59 -0700442
Elliott Hughesb708d162015-10-27 16:03:15 -0700443 bytes_copied += msg.data.size;
444
445 int percentage = static_cast<int>(bytes_copied * 100 / size);
Josh Gao983c41c2015-11-02 17:15:57 -0800446 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800447 }
448
449 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700450 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800451}
452
Elliott Hughesaa245492015-08-03 10:38:08 -0700453bool do_sync_ls(const char* path) {
454 SyncConnection sc;
455 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800456
Josh Gaocda6a2b2015-11-02 16:45:47 -0800457 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
458 const char* name) {
459 printf("%08x %08x %08x %s\n", mode, size, time, name);
460 });
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{
Josh Gaocda6a2b2015-11-02 16:45:47 -0800465 std::string src;
466 std::string dst;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800467 unsigned int time;
468 unsigned int mode;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700469 uint64_t size;
Josh Gaofc7c3b62015-11-03 14:44:04 -0800470 bool skip;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471};
472
Josh Gaocda6a2b2015-11-02 16:45:47 -0800473static copyinfo mkcopyinfo(const char* spath, const char* dpath, const char* name, bool isdir) {
474 copyinfo result;
475 result.src = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", spath, name);
476 result.dst = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", dpath, name);
477 result.time = 0;
478 result.mode = 0;
479 result.size = 0;
Josh Gaofc7c3b62015-11-03 14:44:04 -0800480 result.skip = false;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800481 return result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800482}
483
Elliott Hughesaa245492015-08-03 10:38:08 -0700484static bool IsDotOrDotDot(const char* name) {
485 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
486}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800487
Josh Gaocda6a2b2015-11-02 16:45:47 -0800488static int local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
489 const char* lpath, const char* rpath) {
490 std::vector<copyinfo> dirlist;
491 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700492 if (!dir) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700493 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800494 return -1;
495 }
496
Elliott Hughesb708d162015-10-27 16:03:15 -0700497 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700498 while ((de = readdir(dir.get()))) {
499 if (IsDotOrDotDot(de->d_name)) continue;
500
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800501 char stat_path[PATH_MAX];
Elliott Hughesaa245492015-08-03 10:38:08 -0700502 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700503 sc.Error("skipping long path '%s%s'", lpath, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800504 continue;
Elliott Hughesaa245492015-08-03 10:38:08 -0700505 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800506 strcpy(stat_path, lpath);
507 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800508
Elliott Hughesaa245492015-08-03 10:38:08 -0700509 struct stat st;
510 if (!lstat(stat_path, &st)) {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700511 if (S_ISDIR(st.st_mode)) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800512 dirlist.push_back(mkcopyinfo(lpath, rpath, de->d_name, 1));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800513 } else {
Elliott Hughesaa245492015-08-03 10:38:08 -0700514 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800515 sc.Error("skipping special file '%s'", lpath);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700516 } else {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800517 copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
518 ci.time = st.st_mtime;
519 ci.mode = st.st_mode;
520 ci.size = st.st_size;
521 filelist->push_back(ci);
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700522 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800523 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700524 } else {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800525 sc.Error("cannot lstat '%s': %s", stat_path, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800526 }
527 }
528
Elliott Hughesaa245492015-08-03 10:38:08 -0700529 // Close this directory and recurse.
530 dir.reset();
Josh Gaocda6a2b2015-11-02 16:45:47 -0800531 for (const copyinfo& ci : dirlist) {
532 local_build_list(sc, filelist, ci.src.c_str(), ci.dst.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800533 }
534
535 return 0;
536}
537
Elliott Hughesaa245492015-08-03 10:38:08 -0700538static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
539 bool check_timestamps, bool list_only) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800540 std::vector<copyinfo> filelist;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800541 int pushed = 0;
542 int skipped = 0;
543
Elliott Hughesaa245492015-08-03 10:38:08 -0700544 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
545 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800546 int tmplen = strlen(lpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800547 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700548 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800549 snprintf(tmp, tmplen, "%s/",lpath);
550 lpath = tmp;
551 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700552 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800553 int tmplen = strlen(rpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800554 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesaa245492015-08-03 10:38:08 -0700555 if(tmp == 0) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800556 snprintf(tmp, tmplen, "%s/",rpath);
557 rpath = tmp;
558 }
559
Elliott Hughesb708d162015-10-27 16:03:15 -0700560 if (local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700561 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800562 }
563
Elliott Hughesaa245492015-08-03 10:38:08 -0700564 if (check_timestamps) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800565 for (const copyinfo& ci : filelist) {
566 if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800567 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800568 for (copyinfo& ci : filelist) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800569 unsigned int timestamp, mode, size;
Elliott Hughesaa245492015-08-03 10:38:08 -0700570 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800571 if (size == ci.size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800572 /* for links, we cannot update the atime/mtime */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800573 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
574 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800575 ci.skip = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700576 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800577 }
578 }
579 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800580
581 for (const copyinfo& ci : filelist) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800582 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700583 if (list_only) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800584 fprintf(stderr, "would push: %s -> %s\n", ci.src.c_str(),
585 ci.dst.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700586 } else {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800587 if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time, ci.mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700588 return false;
589 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800590 }
591 pushed++;
592 } else {
593 skipped++;
594 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800595 }
596
Josh Gao983c41c2015-11-02 17:15:57 -0800597 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath, pushed,
598 (pushed == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
599 sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700600 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800601}
602
Josh Gao05786772015-10-30 16:57:19 -0700603bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700604 SyncConnection sc;
605 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800606
Josh Gao05786772015-10-30 16:57:19 -0700607 bool success = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700608 unsigned mode;
Josh Gao05786772015-10-30 16:57:19 -0700609 if (!sync_stat(sc, dst, nullptr, &mode, nullptr)) return false;
610 bool dst_isdir = mode != 0 && S_ISDIR(mode);
611
612 if (!dst_isdir) {
613 if (srcs.size() > 1) {
614 sc.Error("target '%s' is not a directory", dst);
615 return false;
616 } else {
617 size_t dst_len = strlen(dst);
618 if (dst[dst_len - 1] == '/') {
619 sc.Error("failed to access '%s': Not a directory", dst);
620 return false;
621 }
622 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700623 }
Josh Gao05786772015-10-30 16:57:19 -0700624
625 for (const char* src_path : srcs) {
626 const char* dst_path = dst;
627 struct stat st;
628 if (stat(src_path, &st)) {
629 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
630 success = false;
631 continue;
632 }
633
634 if (S_ISDIR(st.st_mode)) {
635 success &= copy_local_dir_remote(sc, src_path, dst, false, false);
636 continue;
637 }
638
639 std::string path_holder;
640 if (mode != 0 && S_ISDIR(mode)) {
641 // If we're copying a local file to a remote directory,
642 // we really want to copy to remote_dir + "/" + local_filename.
643 path_holder = android::base::StringPrintf(
644 "%s/%s", dst_path, adb_basename(src_path).c_str());
645 dst_path = path_holder.c_str();
646 }
647 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
648 }
649
Elliott Hughesb708d162015-10-27 16:03:15 -0700650 sc.Print("\n");
Josh Gao05786772015-10-30 16:57:19 -0700651 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800652}
653
Josh Gaocda6a2b2015-11-02 16:45:47 -0800654static bool remote_build_list(SyncConnection& sc,
655 std::vector<copyinfo>* filelist,
656 const char* rpath, const char* lpath) {
657 std::vector<copyinfo> dirlist;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658
Elliott Hughesaa245492015-08-03 10:38:08 -0700659 // Put the files/dirs in rpath on the lists.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800660 auto callback = [&](unsigned mode, unsigned size, unsigned time,
661 const char* name) {
662 if (S_ISDIR(mode)) {
663 // Don't try recursing down "." or "..".
664 if (IsDotOrDotDot(name)) return;
665
666 dirlist.push_back(mkcopyinfo(rpath, lpath, name, 1));
667 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
668 copyinfo ci = mkcopyinfo(rpath, lpath, name, 0);
669 ci.time = time;
670 ci.mode = mode;
671 ci.size = size;
672 filelist->push_back(ci);
673 } else {
674 sc.Print(android::base::StringPrintf("skipping special file '%s'\n",
675 name));
676 }
677 };
678
679 if (!sync_ls(sc, rpath, callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700680 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800681 }
682
Elliott Hughesaa245492015-08-03 10:38:08 -0700683 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800684 while (!dirlist.empty()) {
685 copyinfo current = dirlist.back();
686 dirlist.pop_back();
687 if (!remote_build_list(sc, filelist, current.src.c_str(),
688 current.dst.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700689 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800690 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800691 }
692
Elliott Hughesaa245492015-08-03 10:38:08 -0700693 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800694}
695
Dan Albertbac34742015-02-25 17:51:28 -0800696static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700697{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700698 struct utimbuf times = { time, time };
699 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700700
701 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800702 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700703 umask(mask);
704 int r2 = chmod(lpath, mode & ~mask);
705
706 return r1 ? : r2;
707}
708
Elliott Hughesaa245492015-08-03 10:38:08 -0700709static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
Josh Gao05786772015-10-30 16:57:19 -0700710 bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700711 // Make sure that both directory paths end in a slash.
712 std::string rpath_clean(rpath);
713 std::string lpath_clean(lpath);
714 if (rpath_clean.empty() || lpath_clean.empty()) return false;
715 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
716 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrews4d04d242014-12-12 13:12:36 -0800717
Elliott Hughesaa245492015-08-03 10:38:08 -0700718 // Recursively build the list of files to copy.
Elliott Hughesb708d162015-10-27 16:03:15 -0700719 sc.Print("pull: building file list...");
Josh Gaocda6a2b2015-11-02 16:45:47 -0800720 std::vector<copyinfo> filelist;
721 if (!remote_build_list(sc, &filelist, rpath_clean.c_str(),
722 lpath_clean.c_str())) {
723 return false;
724 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700725
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800726 int pulled = 0;
727 int skipped = 0;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800728 for (const copyinfo &ci : filelist) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800729 if (!ci.skip) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800730 sc.Printf("pull: %s -> %s", ci.src.c_str(), ci.dst.c_str());
731 if (!sync_recv(sc, ci.src.c_str(), ci.dst.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700732 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800733 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700734
Josh Gaocda6a2b2015-11-02 16:45:47 -0800735 if (copy_attrs &&
736 set_time_and_mode(ci.dst.c_str(), ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700737 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700738 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800739 pulled++;
740 } else {
741 skipped++;
742 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800743 }
744
Josh Gao983c41c2015-11-02 17:15:57 -0800745 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath, pulled,
746 (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
747 sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700748 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800749}
750
Josh Gao05786772015-10-30 16:57:19 -0700751bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
752 bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700753 SyncConnection sc;
754 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800755
Josh Gao05786772015-10-30 16:57:19 -0700756 bool success = true;
Elliott Hughes5c742702015-07-30 17:42:01 -0700757 unsigned mode, time;
Josh Gao05786772015-10-30 16:57:19 -0700758 struct stat st;
759 if (stat(dst, &st)) {
760 // If we're only pulling one file, the destination path might point to
761 // a path that doesn't exist yet.
762 if (srcs.size() != 1 || errno != ENOENT) {
763 sc.Error("cannot stat '%s': %s", dst, strerror(errno));
764 return false;
765 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800766 }
767
Josh Gao05786772015-10-30 16:57:19 -0700768 bool dst_isdir = S_ISDIR(st.st_mode);
769 if (!dst_isdir) {
770 if (srcs.size() > 1) {
771 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700772 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800773 } else {
Josh Gao05786772015-10-30 16:57:19 -0700774 size_t dst_len = strlen(dst);
775 if (dst[dst_len - 1] == '/') {
776 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700777 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700778 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800779 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700781
Josh Gao05786772015-10-30 16:57:19 -0700782 for (const char* src_path : srcs) {
783 const char* dst_path = dst;
784 if (!sync_stat(sc, src_path, &time, &mode, nullptr)) return false;
785 if (mode == 0) {
786 sc.Error("remote object '%s' does not exist", src_path);
787 success = false;
788 continue;
789 }
790
791 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
792 std::string path_holder;
793 struct stat st;
794 if (stat(dst_path, &st) == 0) {
795 if (S_ISDIR(st.st_mode)) {
796 // If we're copying a remote file to a local directory,
797 // we really want to copy to local_dir + "/" +
798 // basename(remote).
799 path_holder = android::base::StringPrintf(
800 "%s/%s", dst_path, adb_basename(src_path).c_str());
801 dst_path = path_holder.c_str();
802 }
803 }
804 if (!sync_recv(sc, src_path, dst_path)) {
805 success = false;
806 continue;
807 } else {
808 if (copy_attrs && set_time_and_mode(dst_path, time, mode)) {
809 success = false;
810 continue;
811 }
812 }
813 } else if (S_ISDIR(mode)) {
814 success &= copy_remote_dir_local(sc, src_path, dst_path, copy_attrs);
815 continue;
816 } else {
817 sc.Error("remote object '%s' not a file or directory", src_path);
818 success = false;
819 continue;
820 }
821 }
822
823 sc.Print("\n");
824 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800825}
826
Elliott Hughesaa245492015-08-03 10:38:08 -0700827bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700828 SyncConnection sc;
829 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800830
Elliott Hughesaa245492015-08-03 10:38:08 -0700831 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 -0800832}