blob: 332276368231379453db6df6cc2740d9ec3f897c [file] [log] [blame]
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Elliott Hughesdde00be2015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030
Josh Gao204d21e2015-11-02 16:45:47 -080031#include <functional>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070032#include <memory>
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070033#include <vector>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070034
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080035#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080036
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080037#include "adb.h"
38#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080039#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040040#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080041#include "file_sync_service.h"
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070042#include "line_printer.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080043
Elliott Hughesdde00be2015-09-27 12:55:37 -070044#include <base/file.h>
Elliott Hughesb628cb12015-08-03 10:38:08 -070045#include <base/strings.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070046#include <base/stringprintf.h>
47
Elliott Hughesb628cb12015-08-03 10:38:08 -070048struct syncsendbuf {
49 unsigned id;
50 unsigned size;
51 char data[SYNC_DATA_MAX];
52};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080053
Elliott Hughesb628cb12015-08-03 10:38:08 -070054class SyncConnection {
55 public:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070056 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesb628cb12015-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 Hughesf5cdc1d2015-10-27 16:03:15 -070062 Error("connect failed: %s", error.c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -070063 }
64 }
65
66 ~SyncConnection() {
67 if (!IsValid()) return;
68
Spencer Lowcc4a4b12015-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 Hughesb628cb12015-08-03 10:38:08 -070078 adb_close(fd);
79 }
80
81 bool IsValid() { return fd >= 0; }
82
Elliott Hughesdde00be2015-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 Hughesf5cdc1d2015-10-27 16:03:15 -070086 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-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 Hughes6c73bfc2015-10-27 13:40:35 -070093 std::vector<char> buf(sizeof(SyncRequest) + path_length);
94 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesdde00be2015-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 Hughes6c73bfc2015-10-27 13:40:35 -0700100 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesdde00be2015-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 Hughesf5cdc1d2015-10-27 16:03:15 -0700106 const char* rpath,
Elliott Hughesdde00be2015-09-27 12:55:37 -0700107 const char* data, size_t data_length,
108 unsigned mtime) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700109 Print(rpath);
110
Elliott Hughesdde00be2015-09-27 12:55:37 -0700111 size_t path_length = strlen(path_and_mode);
112 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700113 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700114 errno = ENAMETOOLONG;
115 return false;
116 }
117
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700118 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughesdde00be2015-09-27 12:55:37 -0700119 sizeof(SyncRequest) + data_length +
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700120 sizeof(SyncRequest));
121 char* p = &buf[0];
Elliott Hughesdde00be2015-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 Hughes6c73bfc2015-10-27 13:40:35 -0700142 if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
Elliott Hughesdde00be2015-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 Hughesf5cdc1d2015-10-27 16:03:15 -0700151 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesdde00be2015-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 Hughesf5cdc1d2015-10-27 16:03:15 -0700158 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700159 return false;
160 }
Elliott Hughese4ed32f2015-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 Hughes6c73bfc2015-10-27 13:40:35 -0700165 std::vector<char> buf(msg.status.msglen + 1);
166 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700167 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
168 from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700169 return false;
170 }
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700171 buf[msg.status.msglen] = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700172 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700173 return false;
174 }
175
Elliott Hughesf5cdc1d2015-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 Gaocbf485f2015-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 Hughesf5cdc1d2015-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
Josh Gaoa544cc62015-11-07 17:18:44 -0800212 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
213 std::string s = "adb: warning: ";
214
215 va_list ap;
216 va_start(ap, fmt);
217 android::base::StringAppendV(&s, fmt, ap);
218 va_end(ap);
219
220 line_printer_.Print(s, LinePrinter::FULL);
221 }
222
Elliott Hughesb628cb12015-08-03 10:38:08 -0700223 uint64_t total_bytes;
224
225 // TODO: add a char[max] buffer here, to replace syncsendbuf...
226 int fd;
227 size_t max;
228
229 private:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700230 uint64_t start_time_ms_;
231
232 LinePrinter line_printer_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700233
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700234 bool SendQuit() {
235 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700236 }
237
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700238 static uint64_t CurrentTimeMs() {
239 struct timeval tv;
240 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
241 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700242 }
243};
244
Josh Gao204d21e2015-11-02 16:45:47 -0800245typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700246
Josh Gao204d21e2015-11-02 16:45:47 -0800247static bool sync_ls(SyncConnection& sc, const char* path,
248 std::function<sync_ls_cb> func) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700249 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700250
251 while (true) {
252 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700253 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700254
255 if (msg.dent.id == ID_DONE) return true;
256 if (msg.dent.id != ID_DENT) return false;
257
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700258 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700259 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800260
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700261 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700262 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800263 buf[len] = 0;
264
Josh Gao204d21e2015-11-02 16:45:47 -0800265 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800266 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800267}
268
Elliott Hughesb628cb12015-08-03 10:38:08 -0700269static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
270 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800271 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700272 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
273 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800274 }
275
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700276 if (timestamp) *timestamp = msg.stat.time;
277 if (mode) *mode = msg.stat.mode;
278 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800279
Elliott Hughesb628cb12015-08-03 10:38:08 -0700280 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800281}
282
Elliott Hughesb628cb12015-08-03 10:38:08 -0700283static bool sync_stat(SyncConnection& sc, const char* path,
284 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700285 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800286}
287
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700288static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
289 const char* lpath, const char* rpath,
290 unsigned mtime) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700291 if (!sc.SendRequest(ID_SEND, path_and_mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700292 sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700293 return false;
294 }
295
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700296 struct stat st;
297 if (stat(lpath, &st) == -1) {
298 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
299 return false;
Spencer Lowc1a31332015-08-28 01:07:30 -0700300 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800301
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700302 uint64_t total_size = st.st_size;
303 uint64_t bytes_copied = 0;
304
305 int lfd = adb_open(lpath, O_RDONLY);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700306 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700307 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700308 return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700309 }
310
Elliott Hughesdde00be2015-09-27 12:55:37 -0700311 syncsendbuf sbuf;
312 sbuf.id = ID_DATA;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700313 while (true) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700314 int ret = adb_read(lfd, sbuf.data, sc.max);
Elliott Hughes0bd85872015-08-25 10:59:45 -0700315 if (ret <= 0) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700316 if (ret < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700317 sc.Error("cannot read '%s': %s", lpath, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700318 adb_close(lfd);
319 return false;
320 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800321 break;
322 }
323
Elliott Hughesdde00be2015-09-27 12:55:37 -0700324 sbuf.size = ret;
325 if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700326 adb_close(lfd);
327 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800328 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700329 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700330
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700331 bytes_copied += ret;
332
333 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
Josh Gaocbf485f2015-11-02 17:15:57 -0800334 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800335 }
336
337 adb_close(lfd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800338
Elliott Hughesb628cb12015-08-03 10:38:08 -0700339 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800340 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700341 msg.data.size = mtime;
Elliott Hughesc5d51622015-09-03 11:06:00 -0700342 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700343 sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700344 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800345 }
346
Elliott Hughesb628cb12015-08-03 10:38:08 -0700347 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800348}
349
Elliott Hughesdde00be2015-09-27 12:55:37 -0700350static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700351 unsigned mtime, mode_t mode)
Elliott Hughesdde00be2015-09-27 12:55:37 -0700352{
353 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
354
355 if (S_ISLNK(mode)) {
356#if !defined(_WIN32)
357 char buf[PATH_MAX];
358 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
359 if (data_length == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700360 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700361 return false;
362 }
363 buf[data_length++] = '\0';
364
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700365 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700366 return sc.CopyDone(lpath, rpath);
367#endif
368 }
369
370 if (!S_ISREG(mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700371 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700372 return false;
373 }
374
375 struct stat st;
376 if (stat(lpath, &st) == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700377 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700378 return false;
379 }
380 if (st.st_size < SYNC_DATA_MAX) {
381 std::string data;
382 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700383 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700384 return false;
385 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700386 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
387 return false;
388 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700389 } else {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700390 if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
391 return false;
392 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700393 }
394 return sc.CopyDone(lpath, rpath);
395}
396
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700397static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
398 sc.Print(rpath);
399
Elliott Hughesb628cb12015-08-03 10:38:08 -0700400 unsigned size = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700401 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700402
Elliott Hughesdde00be2015-09-27 12:55:37 -0700403 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800404
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700405 adb_unlink(lpath);
Josh Gaofe1a6122015-11-04 14:51:23 -0800406 if (!mkdirs(adb_dirname(lpath))) {
407 sc.Error("failed to create parent directory '%s': %s",
408 adb_dirname(lpath).c_str(), strerror(errno));
409 return false;
410 }
411
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700412 int lfd = adb_creat(lpath, 0644);
413 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700414 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700415 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800416 }
417
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700418 uint64_t bytes_copied = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700419 while (true) {
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700420 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700421 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700422 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700423 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700424 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800425 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800426
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700427 if (msg.data.id == ID_DONE) break;
428
429 if (msg.data.id != ID_DATA) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800430 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700431 adb_unlink(lpath);
432 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700433 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800434 }
435
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700436 if (msg.data.size > sc.max) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700437 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800438 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700439 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700440 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800441 }
442
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700443 char buffer[SYNC_DATA_MAX];
444 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800445 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700446 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700447 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800448 }
449
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700450 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700451 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700452 adb_close(lfd);
453 adb_unlink(lpath);
454 return false;
455 }
456
457 sc.total_bytes += msg.data.size;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700458
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700459 bytes_copied += msg.data.size;
460
461 int percentage = static_cast<int>(bytes_copied * 100 / size);
Josh Gaocbf485f2015-11-02 17:15:57 -0800462 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800463 }
464
465 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700466 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800467}
468
Elliott Hughesb628cb12015-08-03 10:38:08 -0700469bool do_sync_ls(const char* path) {
470 SyncConnection sc;
471 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800472
Josh Gao204d21e2015-11-02 16:45:47 -0800473 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
474 const char* name) {
475 printf("%08x %08x %08x %s\n", mode, size, time, name);
476 });
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800477}
478
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800479struct copyinfo
480{
Josh Gao204d21e2015-11-02 16:45:47 -0800481 std::string src;
482 std::string dst;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800483 unsigned int time;
484 unsigned int mode;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700485 uint64_t size;
Josh Gaocb094c62015-11-03 14:44:04 -0800486 bool skip;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800487};
488
Josh Gaod20cf382015-11-03 15:23:03 -0800489static copyinfo mkcopyinfo(const std::string& spath, const std::string& dpath,
Josh Gaoa90563e2015-11-04 14:57:04 -0800490 const std::string& name, unsigned int mode) {
Josh Gao204d21e2015-11-02 16:45:47 -0800491 copyinfo result;
Josh Gaoa90563e2015-11-04 14:57:04 -0800492 result.src = spath;
493 result.dst = dpath;
494 if (result.src.back() != '/') {
495 result.src.push_back('/');
496 }
497 if (result.dst.back() != '/') {
498 result.dst.push_back('/');
499 }
500 result.src.append(name);
501 result.dst.append(name);
502
503 bool isdir = S_ISDIR(mode);
Josh Gaod20cf382015-11-03 15:23:03 -0800504 if (isdir) {
505 result.src.push_back('/');
506 result.dst.push_back('/');
507 }
Josh Gaoa90563e2015-11-04 14:57:04 -0800508
Josh Gao204d21e2015-11-02 16:45:47 -0800509 result.time = 0;
Josh Gaoa90563e2015-11-04 14:57:04 -0800510 result.mode = mode;
Josh Gao204d21e2015-11-02 16:45:47 -0800511 result.size = 0;
Josh Gaocb094c62015-11-03 14:44:04 -0800512 result.skip = false;
Josh Gao204d21e2015-11-02 16:45:47 -0800513 return result;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800514}
515
Elliott Hughesb628cb12015-08-03 10:38:08 -0700516static bool IsDotOrDotDot(const char* name) {
517 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
518}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800519
Josh Gao8efa6462015-11-03 15:26:38 -0800520static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
521 const std::string& lpath,
522 const std::string& rpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800523 std::vector<copyinfo> dirlist;
Josh Gaod20cf382015-11-03 15:23:03 -0800524 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700525 if (!dir) {
Josh Gaod20cf382015-11-03 15:23:03 -0800526 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gao8efa6462015-11-03 15:26:38 -0800527 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800528 }
529
Josh Gaoa90563e2015-11-04 14:57:04 -0800530 bool empty_dir = true;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700531 dirent* de;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700532 while ((de = readdir(dir.get()))) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800533 if (IsDotOrDotDot(de->d_name)) {
534 continue;
535 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700536
Josh Gaoa90563e2015-11-04 14:57:04 -0800537 empty_dir = false;
Josh Gaod20cf382015-11-03 15:23:03 -0800538 std::string stat_path = lpath + de->d_name;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800539
Elliott Hughesb628cb12015-08-03 10:38:08 -0700540 struct stat st;
Josh Gaod20cf382015-11-03 15:23:03 -0800541 if (!lstat(stat_path.c_str(), &st)) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800542 copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700543 if (S_ISDIR(st.st_mode)) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800544 dirlist.push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800545 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700546 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Josh Gaoa544cc62015-11-07 17:18:44 -0800547 sc.Warning("skipping special file '%s'", lpath.c_str());
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700548 } else {
Josh Gao204d21e2015-11-02 16:45:47 -0800549 ci.time = st.st_mtime;
Josh Gao204d21e2015-11-02 16:45:47 -0800550 ci.size = st.st_size;
551 filelist->push_back(ci);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700552 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700554 } else {
Josh Gaod20cf382015-11-03 15:23:03 -0800555 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
556 strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800557 }
558 }
559
Elliott Hughesb628cb12015-08-03 10:38:08 -0700560 // Close this directory and recurse.
561 dir.reset();
Josh Gaoa90563e2015-11-04 14:57:04 -0800562
563 // Add the current directory to the list if it was empty, to ensure that
564 // it gets created.
565 if (empty_dir) {
566 // TODO(b/25566053): Make pushing empty directories work.
567 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa544cc62015-11-07 17:18:44 -0800568 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaoa90563e2015-11-04 14:57:04 -0800569 copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
570 adb_basename(lpath), S_IFDIR);
571 ci.skip = true;
572 filelist->push_back(ci);
573 return true;
574 }
575
Josh Gao204d21e2015-11-02 16:45:47 -0800576 for (const copyinfo& ci : dirlist) {
577 local_build_list(sc, filelist, ci.src.c_str(), ci.dst.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800578 }
579
Josh Gao8efa6462015-11-03 15:26:38 -0800580 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800581}
582
Josh Gaod20cf382015-11-03 15:23:03 -0800583static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
584 std::string rpath, bool check_timestamps,
585 bool list_only) {
586 // Make sure that both directory paths end in a slash.
Josh Gao59409942015-11-06 15:19:53 -0800587 // Both paths are known to exist, so they cannot be empty.
Josh Gaod20cf382015-11-03 15:23:03 -0800588 if (lpath.back() != '/') {
589 lpath.push_back('/');
590 }
591 if (rpath.back() != '/') {
592 rpath.push_back('/');
593 }
594
595 // Recursively build the list of files to copy.
Josh Gao204d21e2015-11-02 16:45:47 -0800596 std::vector<copyinfo> filelist;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800597 int pushed = 0;
598 int skipped = 0;
Josh Gao8efa6462015-11-03 15:26:38 -0800599 if (!local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700600 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800601 }
602
Elliott Hughesb628cb12015-08-03 10:38:08 -0700603 if (check_timestamps) {
Josh Gao204d21e2015-11-02 16:45:47 -0800604 for (const copyinfo& ci : filelist) {
Josh Gaod20cf382015-11-03 15:23:03 -0800605 if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) {
606 return false;
607 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800608 }
Josh Gao204d21e2015-11-02 16:45:47 -0800609 for (copyinfo& ci : filelist) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800610 unsigned int timestamp, mode, size;
Josh Gaod20cf382015-11-03 15:23:03 -0800611 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
612 return false;
613 }
Josh Gao204d21e2015-11-02 16:45:47 -0800614 if (size == ci.size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800615 /* for links, we cannot update the atime/mtime */
Josh Gao204d21e2015-11-02 16:45:47 -0800616 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
617 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaocb094c62015-11-03 14:44:04 -0800618 ci.skip = true;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700619 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800620 }
621 }
622 }
Josh Gao204d21e2015-11-02 16:45:47 -0800623
624 for (const copyinfo& ci : filelist) {
Josh Gaocb094c62015-11-03 14:44:04 -0800625 if (!ci.skip) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700626 if (list_only) {
Josh Gaod20cf382015-11-03 15:23:03 -0800627 sc.Error("would push: %s -> %s", ci.src.c_str(),
628 ci.dst.c_str());
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700629 } else {
Josh Gaod20cf382015-11-03 15:23:03 -0800630 if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time,
631 ci.mode)) {
632 return false;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700633 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800634 }
635 pushed++;
636 } else {
637 skipped++;
638 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800639 }
640
Josh Gaod20cf382015-11-03 15:23:03 -0800641 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
642 pushed, (pushed == 1) ? "" : "s", skipped,
643 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700644 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800645}
646
Josh Gao5d093b22015-10-30 16:57:19 -0700647bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700648 SyncConnection sc;
649 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800650
Josh Gao5d093b22015-10-30 16:57:19 -0700651 bool success = true;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700652 unsigned mode;
Josh Gao5d093b22015-10-30 16:57:19 -0700653 if (!sync_stat(sc, dst, nullptr, &mode, nullptr)) return false;
654 bool dst_isdir = mode != 0 && S_ISDIR(mode);
655
656 if (!dst_isdir) {
657 if (srcs.size() > 1) {
658 sc.Error("target '%s' is not a directory", dst);
659 return false;
660 } else {
661 size_t dst_len = strlen(dst);
662 if (dst[dst_len - 1] == '/') {
663 sc.Error("failed to access '%s': Not a directory", dst);
664 return false;
665 }
666 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700667 }
Josh Gao5d093b22015-10-30 16:57:19 -0700668
669 for (const char* src_path : srcs) {
670 const char* dst_path = dst;
671 struct stat st;
672 if (stat(src_path, &st)) {
673 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
674 success = false;
675 continue;
676 }
677
678 if (S_ISDIR(st.st_mode)) {
679 success &= copy_local_dir_remote(sc, src_path, dst, false, false);
680 continue;
681 }
682
683 std::string path_holder;
684 if (mode != 0 && S_ISDIR(mode)) {
685 // If we're copying a local file to a remote directory,
686 // we really want to copy to remote_dir + "/" + local_filename.
687 path_holder = android::base::StringPrintf(
688 "%s/%s", dst_path, adb_basename(src_path).c_str());
689 dst_path = path_holder.c_str();
690 }
691 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
692 }
693
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700694 sc.Print("\n");
Josh Gao5d093b22015-10-30 16:57:19 -0700695 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800696}
697
Josh Gao204d21e2015-11-02 16:45:47 -0800698static bool remote_build_list(SyncConnection& sc,
699 std::vector<copyinfo>* filelist,
Josh Gaod20cf382015-11-03 15:23:03 -0800700 const std::string& rpath,
701 const std::string& lpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800702 std::vector<copyinfo> dirlist;
Josh Gaoa90563e2015-11-04 14:57:04 -0800703 bool empty_dir = true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800704
Elliott Hughesb628cb12015-08-03 10:38:08 -0700705 // Put the files/dirs in rpath on the lists.
Josh Gao204d21e2015-11-02 16:45:47 -0800706 auto callback = [&](unsigned mode, unsigned size, unsigned time,
707 const char* name) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800708 if (IsDotOrDotDot(name)) {
709 return;
710 }
Josh Gao204d21e2015-11-02 16:45:47 -0800711
Josh Gaoa90563e2015-11-04 14:57:04 -0800712 // We found a child that isn't '.' or '..'.
713 empty_dir = false;
714
715 copyinfo ci = mkcopyinfo(rpath, lpath, name, mode);
716 if (S_ISDIR(mode)) {
717 dirlist.push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800718 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
Josh Gao204d21e2015-11-02 16:45:47 -0800719 ci.time = time;
Josh Gao204d21e2015-11-02 16:45:47 -0800720 ci.size = size;
721 filelist->push_back(ci);
722 } else {
Josh Gaoa544cc62015-11-07 17:18:44 -0800723 sc.Warning("skipping special file '%s'\n", name);
Josh Gao204d21e2015-11-02 16:45:47 -0800724 }
725 };
726
Josh Gaod20cf382015-11-03 15:23:03 -0800727 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700728 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800729 }
730
Josh Gaoa90563e2015-11-04 14:57:04 -0800731 // Add the current directory to the list if it was empty, to ensure that
732 // it gets created.
733 if (empty_dir) {
734 auto rdname = adb_dirname(rpath);
735 auto ldname = adb_dirname(lpath);
736 auto rbasename = adb_basename(rpath);
737 auto lbasename = adb_basename(lpath);
738 filelist->push_back(mkcopyinfo(adb_dirname(rpath), adb_dirname(lpath),
739 adb_basename(rpath), S_IFDIR));
740 return true;
741 }
742
Elliott Hughesb628cb12015-08-03 10:38:08 -0700743 // Recurse into each directory we found.
Josh Gao204d21e2015-11-02 16:45:47 -0800744 while (!dirlist.empty()) {
745 copyinfo current = dirlist.back();
746 dirlist.pop_back();
747 if (!remote_build_list(sc, filelist, current.src.c_str(),
748 current.dst.c_str())) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700749 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800750 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800751 }
752
Elliott Hughesb628cb12015-08-03 10:38:08 -0700753 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800754}
755
Dan Albertf30d73c2015-02-25 17:51:28 -0800756static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700757{
Greg Hackmann8b689142014-05-06 08:48:18 -0700758 struct utimbuf times = { time, time };
759 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700760
761 /* use umask for permissions */
Josh Gao204d21e2015-11-02 16:45:47 -0800762 mode_t mask = umask(0000);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700763 umask(mask);
764 int r2 = chmod(lpath, mode & ~mask);
765
Spencer Low28bc2cb2015-11-07 18:51:54 -0800766 return r1 ? r1 : r2;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700767}
768
Josh Gaod20cf382015-11-03 15:23:03 -0800769static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
770 std::string lpath, bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700771 // Make sure that both directory paths end in a slash.
Josh Gao59409942015-11-06 15:19:53 -0800772 // Both paths are known to exist, so they cannot be empty.
Josh Gaod20cf382015-11-03 15:23:03 -0800773 if (rpath.back() != '/') {
774 rpath.push_back('/');
775 }
776 if (lpath.back() != '/') {
777 lpath.push_back('/');
778 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800779
Elliott Hughesb628cb12015-08-03 10:38:08 -0700780 // Recursively build the list of files to copy.
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700781 sc.Print("pull: building file list...");
Josh Gao204d21e2015-11-02 16:45:47 -0800782 std::vector<copyinfo> filelist;
Josh Gaod20cf382015-11-03 15:23:03 -0800783 if (!remote_build_list(sc, &filelist, rpath.c_str(), lpath.c_str())) {
Josh Gao204d21e2015-11-02 16:45:47 -0800784 return false;
785 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700786
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800787 int pulled = 0;
788 int skipped = 0;
Josh Gao204d21e2015-11-02 16:45:47 -0800789 for (const copyinfo &ci : filelist) {
Josh Gaocb094c62015-11-03 14:44:04 -0800790 if (!ci.skip) {
Josh Gao204d21e2015-11-02 16:45:47 -0800791 sc.Printf("pull: %s -> %s", ci.src.c_str(), ci.dst.c_str());
Josh Gaoa90563e2015-11-04 14:57:04 -0800792
793 if (S_ISDIR(ci.mode)) {
794 // Entry is for an empty directory, create it and continue.
795 // TODO(b/25457350): We don't preserve permissions on directories.
796 if (!mkdirs(ci.dst)) {
797 sc.Error("failed to create directory '%s': %s",
798 ci.dst.c_str(), strerror(errno));
799 return false;
800 }
801 pulled++;
802 continue;
803 }
804
Josh Gao204d21e2015-11-02 16:45:47 -0800805 if (!sync_recv(sc, ci.src.c_str(), ci.dst.c_str())) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700806 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800807 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700808
Josh Gao204d21e2015-11-02 16:45:47 -0800809 if (copy_attrs &&
810 set_time_and_mode(ci.dst.c_str(), ci.time, ci.mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700811 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700812 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800813 pulled++;
814 } else {
815 skipped++;
816 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800817 }
818
Josh Gaod20cf382015-11-03 15:23:03 -0800819 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
820 pulled, (pulled == 1) ? "" : "s", skipped,
821 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700822 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800823}
824
Josh Gao5d093b22015-10-30 16:57:19 -0700825bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
826 bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700827 SyncConnection sc;
828 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800829
Josh Gao5d093b22015-10-30 16:57:19 -0700830 bool success = true;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700831 unsigned mode, time;
Josh Gao5d093b22015-10-30 16:57:19 -0700832 struct stat st;
833 if (stat(dst, &st)) {
834 // If we're only pulling one file, the destination path might point to
835 // a path that doesn't exist yet.
836 if (srcs.size() != 1 || errno != ENOENT) {
837 sc.Error("cannot stat '%s': %s", dst, strerror(errno));
838 return false;
839 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800840 }
841
Josh Gao5d093b22015-10-30 16:57:19 -0700842 bool dst_isdir = S_ISDIR(st.st_mode);
843 if (!dst_isdir) {
844 if (srcs.size() > 1) {
845 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700846 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800847 } else {
Josh Gao5d093b22015-10-30 16:57:19 -0700848 size_t dst_len = strlen(dst);
849 if (dst[dst_len - 1] == '/') {
850 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700851 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700852 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800853 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800854 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700855
Josh Gao5d093b22015-10-30 16:57:19 -0700856 for (const char* src_path : srcs) {
857 const char* dst_path = dst;
858 if (!sync_stat(sc, src_path, &time, &mode, nullptr)) return false;
859 if (mode == 0) {
860 sc.Error("remote object '%s' does not exist", src_path);
861 success = false;
862 continue;
863 }
864
Josh Gao91f03a42015-11-09 15:59:50 -0800865 if (S_ISREG(mode) || S_ISLNK(mode)) {
866 // TODO(b/25601283): symlinks shouldn't be handled as files.
Josh Gao5d093b22015-10-30 16:57:19 -0700867 std::string path_holder;
868 struct stat st;
869 if (stat(dst_path, &st) == 0) {
870 if (S_ISDIR(st.st_mode)) {
871 // If we're copying a remote file to a local directory,
872 // we really want to copy to local_dir + "/" +
873 // basename(remote).
874 path_holder = android::base::StringPrintf(
875 "%s/%s", dst_path, adb_basename(src_path).c_str());
876 dst_path = path_holder.c_str();
877 }
878 }
879 if (!sync_recv(sc, src_path, dst_path)) {
880 success = false;
881 continue;
882 } else {
883 if (copy_attrs && set_time_and_mode(dst_path, time, mode)) {
884 success = false;
885 continue;
886 }
887 }
888 } else if (S_ISDIR(mode)) {
889 success &= copy_remote_dir_local(sc, src_path, dst_path, copy_attrs);
890 continue;
891 } else {
892 sc.Error("remote object '%s' not a file or directory", src_path);
893 success = false;
894 continue;
895 }
896 }
897
898 sc.Print("\n");
899 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800900}
901
Elliott Hughesb628cb12015-08-03 10:38:08 -0700902bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700903 SyncConnection sc;
904 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800905
Josh Gaod20cf382015-11-03 15:23:03 -0800906 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800907}