• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "client/file_sync_client.h"
18 
19 #include <dirent.h>
20 #include <inttypes.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <utime.h>
30 
31 #include <chrono>
32 #include <deque>
33 #include <functional>
34 #include <memory>
35 #include <sstream>
36 #include <string>
37 #include <variant>
38 #include <vector>
39 
40 #include "sysdeps.h"
41 
42 #include "adb.h"
43 #include "adb_client.h"
44 #include "adb_io.h"
45 #include "adb_utils.h"
46 #include "compression_utils.h"
47 #include "file_sync_protocol.h"
48 #include "line_printer.h"
49 #include "sysdeps/errno.h"
50 #include "sysdeps/stat.h"
51 
52 #include "client/commandline.h"
53 
54 #include <android-base/file.h>
55 #include <android-base/strings.h>
56 #include <android-base/stringprintf.h>
57 
58 using namespace std::literals;
59 
60 typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name);
61 
62 struct syncsendbuf {
63     unsigned id;
64     unsigned size;
65     char data[SYNC_DATA_MAX];
66 };
67 
ensure_trailing_separators(std::string & local_path,std::string & remote_path)68 static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) {
69     if (!adb_is_separator(local_path.back())) {
70         local_path.push_back(OS_PATH_SEPARATOR);
71     }
72     if (remote_path.back() != '/') {
73         remote_path.push_back('/');
74     }
75 }
76 
should_pull_file(mode_t mode)77 static bool should_pull_file(mode_t mode) {
78     return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
79 }
80 
should_push_file(mode_t mode)81 static bool should_push_file(mode_t mode) {
82     return S_ISREG(mode) || S_ISLNK(mode);
83 }
84 
85 struct copyinfo {
86     std::string lpath;
87     std::string rpath;
88     int64_t time = 0;
89     uint32_t mode;
90     uint64_t size = 0;
91     bool skip = false;
92 
copyinfocopyinfo93     copyinfo(const std::string& local_path,
94              const std::string& remote_path,
95              const std::string& name,
96              unsigned int mode)
97             : lpath(local_path), rpath(remote_path), mode(mode) {
98         ensure_trailing_separators(lpath, rpath);
99         lpath.append(name);
100         rpath.append(name);
101         if (S_ISDIR(mode)) {
102             ensure_trailing_separators(lpath, rpath);
103         }
104     }
105 };
106 
107 enum class TransferDirection {
108     push,
109     pull,
110 };
111 
112 struct TransferLedger {
113     std::chrono::steady_clock::time_point start_time;
114     uint64_t files_transferred;
115     uint64_t files_skipped;
116     uint64_t bytes_transferred;
117     uint64_t bytes_expected;
118     bool expect_multiple_files;
119 
120   private:
121     std::string last_progress_str;
122     std::chrono::steady_clock::time_point last_progress_time;
123 
124   public:
TransferLedgerTransferLedger125     TransferLedger() {
126         Reset();
127     }
128 
operator ==TransferLedger129     bool operator==(const TransferLedger& other) const {
130         return files_transferred == other.files_transferred &&
131                files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
132     }
133 
operator !=TransferLedger134     bool operator!=(const TransferLedger& other) const {
135         return !(*this == other);
136     }
137 
ResetTransferLedger138     void Reset() {
139         start_time = std::chrono::steady_clock::now();
140         files_transferred = 0;
141         files_skipped = 0;
142         bytes_transferred = 0;
143         bytes_expected = 0;
144         last_progress_str.clear();
145         last_progress_time = {};
146     }
147 
TransferRateTransferLedger148     std::string TransferRate() {
149         if (bytes_transferred == 0) return "";
150 
151         std::chrono::duration<double> duration;
152         duration = std::chrono::steady_clock::now() - start_time;
153 
154         double s = duration.count();
155         if (s == 0) {
156             return "";
157         }
158         double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
159         return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
160                                            bytes_transferred, s);
161     }
162 
ReportProgressTransferLedger163     void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
164                         uint64_t file_total_bytes) {
165         static constexpr auto kProgressReportInterval = 100ms;
166 
167         auto now = std::chrono::steady_clock::now();
168         if (now < last_progress_time + kProgressReportInterval) {
169             return;
170         }
171         char overall_percentage_str[5] = "?";
172         if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
173             int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
174             // If we're pulling symbolic links, we'll pull the target of the link rather than
175             // just create a local link, and that will cause us to go over 100%.
176             if (overall_percentage <= 100) {
177                 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
178                          overall_percentage);
179             }
180         }
181 
182         std::string output;
183         if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
184             // This case can happen if we're racing against something that wrote to the file
185             // between our stat and our read, or if we're reading a magic file that lies about
186             // its size. Just show how much we've copied.
187             output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
188                                                  file.c_str(), file_copied_bytes);
189         } else {
190             // If we're transferring multiple files, we want to know how far through the current
191             // file we are, as well as the overall percentage.
192             if (expect_multiple_files) {
193                 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
194                 output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
195                                                      file.c_str(), file_percentage);
196             } else {
197                 output =
198                     android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
199             }
200         }
201         if (output != last_progress_str) {
202             lp.Print(output, LinePrinter::LineType::INFO);
203             last_progress_str = std::move(output);
204             last_progress_time = now;
205         }
206     }
207 
ReportTransferRateTransferLedger208     void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
209         const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
210         std::stringstream ss;
211         if (!name.empty()) {
212             std::string_view display_name(name);
213             char* out = getenv("ANDROID_PRODUCT_OUT");
214             if (out) android::base::ConsumePrefix(&display_name, out);
215             ss << display_name << ": ";
216         }
217         ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
218            << direction_str << ", " << files_skipped << " skipped.";
219         ss << TransferRate();
220 
221         lp.Print(ss.str(), LinePrinter::LineType::INFO);
222         lp.KeepInfoLine();
223     }
224 };
225 
226 class SyncConnection {
227   public:
SyncConnection()228     SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) {
229         acknowledgement_buffer_.resize(0);
230         max = SYNC_DATA_MAX; // TODO: decide at runtime.
231 
232         std::string error;
233         auto&& features = adb_get_feature_set(&error);
234         if (!features) {
235             Error("failed to get feature set: %s", error.c_str());
236         } else {
237             features_ = &*features;
238             have_stat_v2_ = CanUseFeature(*features, kFeatureStat2);
239             have_ls_v2_ = CanUseFeature(*features, kFeatureLs2);
240             have_sendrecv_v2_ = CanUseFeature(*features, kFeatureSendRecv2);
241             have_sendrecv_v2_brotli_ = CanUseFeature(*features, kFeatureSendRecv2Brotli);
242             have_sendrecv_v2_lz4_ = CanUseFeature(*features, kFeatureSendRecv2LZ4);
243             have_sendrecv_v2_zstd_ = CanUseFeature(*features, kFeatureSendRecv2Zstd);
244             have_sendrecv_v2_dry_run_send_ = CanUseFeature(*features, kFeatureSendRecv2DryRunSend);
245             std::string error;
246             fd.reset(adb_connect("sync:", &error));
247             if (fd < 0) {
248                 Error("connect failed: %s", error.c_str());
249             }
250         }
251     }
252 
~SyncConnection()253     ~SyncConnection() {
254         if (!IsValid()) return;
255 
256         if (SendQuit()) {
257             // We sent a quit command, so the server should be doing orderly
258             // shutdown soon. But if we encountered an error while we were using
259             // the connection, the server might still be sending data (before
260             // doing orderly shutdown), in which case we won't wait for all of
261             // the data nor the coming orderly shutdown. In the common success
262             // case, this will wait for the server to do orderly shutdown.
263             ReadOrderlyShutdown(fd);
264         }
265 
266         line_printer_.KeepInfoLine();
267     }
268 
HaveSendRecv2() const269     bool HaveSendRecv2() const { return have_sendrecv_v2_; }
HaveSendRecv2Brotli() const270     bool HaveSendRecv2Brotli() const { return have_sendrecv_v2_brotli_; }
HaveSendRecv2LZ4() const271     bool HaveSendRecv2LZ4() const { return have_sendrecv_v2_lz4_; }
HaveSendRecv2Zstd() const272     bool HaveSendRecv2Zstd() const { return have_sendrecv_v2_zstd_; }
HaveSendRecv2DryRunSend() const273     bool HaveSendRecv2DryRunSend() const { return have_sendrecv_v2_dry_run_send_; }
274 
275     // Resolve a compression type which might be CompressionType::Any to a specific compression
276     // algorithm.
ResolveCompressionType(CompressionType compression) const277     CompressionType ResolveCompressionType(CompressionType compression) const {
278         if (compression == CompressionType::Any) {
279             if (HaveSendRecv2Zstd()) {
280                 return CompressionType::Zstd;
281             } else if (HaveSendRecv2LZ4()) {
282                 return CompressionType::LZ4;
283             } else if (HaveSendRecv2Brotli()) {
284                 return CompressionType::Brotli;
285             }
286             return CompressionType::None;
287         }
288         return compression;
289     }
290 
Features() const291     const FeatureSet& Features() const { return *features_; }
292 
IsValid()293     bool IsValid() { return fd >= 0; }
294 
NewTransfer()295     void NewTransfer() {
296         current_ledger_.Reset();
297     }
298 
RecordBytesTransferred(size_t bytes)299     void RecordBytesTransferred(size_t bytes) {
300         current_ledger_.bytes_transferred += bytes;
301         global_ledger_.bytes_transferred += bytes;
302     }
303 
RecordFileSent(std::string from,std::string to)304     void RecordFileSent(std::string from, std::string to) {
305         RecordFilesTransferred(1);
306         deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
307     }
308 
RecordFilesTransferred(size_t files)309     void RecordFilesTransferred(size_t files) {
310         current_ledger_.files_transferred += files;
311         global_ledger_.files_transferred += files;
312     }
313 
RecordFilesSkipped(size_t files)314     void RecordFilesSkipped(size_t files) {
315         current_ledger_.files_skipped += files;
316         global_ledger_.files_skipped += files;
317     }
318 
ReportProgress(const std::string & file,uint64_t file_copied_bytes,uint64_t file_total_bytes)319     void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
320                         uint64_t file_total_bytes) {
321         current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
322     }
323 
ReportTransferRate(const std::string & file,TransferDirection direction)324     void ReportTransferRate(const std::string& file, TransferDirection direction) {
325         current_ledger_.ReportTransferRate(line_printer_, file, direction);
326     }
327 
ReportOverallTransferRate(TransferDirection direction)328     void ReportOverallTransferRate(TransferDirection direction) {
329         if (current_ledger_ != global_ledger_) {
330             global_ledger_.ReportTransferRate(line_printer_, "", direction);
331         }
332     }
333 
SendRequest(int id,const std::string & path)334     bool SendRequest(int id, const std::string& path) {
335         if (path.length() > 1024) {
336             Error("SendRequest failed: path too long: %zu", path.length());
337             errno = ENAMETOOLONG;
338             return false;
339         }
340 
341         // Sending header and payload in a single write makes a noticeable
342         // difference to "adb sync" performance.
343         std::vector<char> buf(sizeof(SyncRequest) + path.length());
344         SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
345         req->id = id;
346         req->path_length = path.length();
347         char* data = reinterpret_cast<char*>(req + 1);
348         memcpy(data, path.data(), path.length());
349         return WriteFdExactly(fd, buf.data(), buf.size());
350     }
351 
SendSend2(std::string_view path,mode_t mode,CompressionType compression,bool dry_run)352     bool SendSend2(std::string_view path, mode_t mode, CompressionType compression, bool dry_run) {
353         if (path.length() > 1024) {
354             Error("SendRequest failed: path too long: %zu", path.length());
355             errno = ENAMETOOLONG;
356             return false;
357         }
358 
359         Block buf;
360 
361         SyncRequest req;
362         req.id = ID_SEND_V2;
363         req.path_length = path.length();
364 
365         syncmsg msg;
366         msg.send_v2_setup.id = ID_SEND_V2;
367         msg.send_v2_setup.mode = mode;
368         msg.send_v2_setup.flags = 0;
369         switch (compression) {
370             case CompressionType::None:
371                 break;
372 
373             case CompressionType::Brotli:
374                 msg.send_v2_setup.flags = kSyncFlagBrotli;
375                 break;
376 
377             case CompressionType::LZ4:
378                 msg.send_v2_setup.flags = kSyncFlagLZ4;
379                 break;
380 
381             case CompressionType::Zstd:
382                 msg.send_v2_setup.flags = kSyncFlagZstd;
383                 break;
384 
385             case CompressionType::Any:
386                 LOG(FATAL) << "unexpected CompressionType::Any";
387         }
388 
389         if (dry_run) {
390             msg.send_v2_setup.flags |= kSyncFlagDryRun;
391         }
392 
393         buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.send_v2_setup));
394 
395         void* p = buf.data();
396 
397         p = mempcpy(p, &req, sizeof(SyncRequest));
398         p = mempcpy(p, path.data(), path.length());
399         p = mempcpy(p, &msg.send_v2_setup, sizeof(msg.send_v2_setup));
400 
401         return WriteFdExactly(fd, buf.data(), buf.size());
402     }
403 
SendRecv2(const std::string & path,CompressionType compression)404     bool SendRecv2(const std::string& path, CompressionType compression) {
405         if (path.length() > 1024) {
406             Error("SendRequest failed: path too long: %zu", path.length());
407             errno = ENAMETOOLONG;
408             return false;
409         }
410 
411         Block buf;
412 
413         SyncRequest req;
414         req.id = ID_RECV_V2;
415         req.path_length = path.length();
416 
417         syncmsg msg;
418         msg.recv_v2_setup.id = ID_RECV_V2;
419         msg.recv_v2_setup.flags = 0;
420         switch (compression) {
421             case CompressionType::None:
422                 break;
423 
424             case CompressionType::Brotli:
425                 msg.recv_v2_setup.flags |= kSyncFlagBrotli;
426                 break;
427 
428             case CompressionType::LZ4:
429                 msg.recv_v2_setup.flags |= kSyncFlagLZ4;
430                 break;
431 
432             case CompressionType::Zstd:
433                 msg.recv_v2_setup.flags |= kSyncFlagZstd;
434                 break;
435 
436             case CompressionType::Any:
437                 LOG(FATAL) << "unexpected CompressionType::Any";
438         }
439 
440         buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.recv_v2_setup));
441 
442         void* p = buf.data();
443 
444         p = mempcpy(p, &req, sizeof(SyncRequest));
445         p = mempcpy(p, path.data(), path.length());
446         p = mempcpy(p, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup));
447 
448         return WriteFdExactly(fd, buf.data(), buf.size());
449     }
450 
SendStat(const std::string & path)451     bool SendStat(const std::string& path) {
452         if (!have_stat_v2_) {
453             errno = ENOTSUP;
454             return false;
455         }
456         return SendRequest(ID_STAT_V2, path);
457     }
458 
SendLstat(const std::string & path)459     bool SendLstat(const std::string& path) {
460         if (have_stat_v2_) {
461             return SendRequest(ID_LSTAT_V2, path);
462         } else {
463             return SendRequest(ID_LSTAT_V1, path);
464         }
465     }
466 
FinishStat(struct stat * st)467     bool FinishStat(struct stat* st) {
468         syncmsg msg;
469 
470         memset(st, 0, sizeof(*st));
471         if (have_stat_v2_) {
472             if (!ReadFdExactly(fd.get(), &msg.stat_v2, sizeof(msg.stat_v2))) {
473                 PLOG(FATAL) << "protocol fault: failed to read stat response";
474             }
475 
476             if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
477                 PLOG(FATAL) << "protocol fault: stat response has wrong message id: "
478                             << msg.stat_v2.id;
479             }
480 
481             if (msg.stat_v2.error != 0) {
482                 errno = errno_from_wire(msg.stat_v2.error);
483                 return false;
484             }
485 
486             st->st_dev = msg.stat_v2.dev;
487             st->st_ino = msg.stat_v2.ino;
488             st->st_mode = msg.stat_v2.mode;
489             st->st_nlink = msg.stat_v2.nlink;
490             st->st_uid = msg.stat_v2.uid;
491             st->st_gid = msg.stat_v2.gid;
492             st->st_size = msg.stat_v2.size;
493             st->st_atime = msg.stat_v2.atime;
494             st->st_mtime = msg.stat_v2.mtime;
495             st->st_ctime = msg.stat_v2.ctime;
496             return true;
497         } else {
498             if (!ReadFdExactly(fd.get(), &msg.stat_v1, sizeof(msg.stat_v1))) {
499                 PLOG(FATAL) << "protocol fault: failed to read stat response";
500             }
501 
502             if (msg.stat_v1.id != ID_LSTAT_V1) {
503                 LOG(FATAL) << "protocol fault: stat response has wrong message id: "
504                            << msg.stat_v1.id;
505             }
506 
507             if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
508                 // There's no way for us to know what the error was.
509                 errno = ENOPROTOOPT;
510                 return false;
511             }
512 
513             st->st_mode = msg.stat_v1.mode;
514             st->st_size = msg.stat_v1.size;
515             st->st_ctime = msg.stat_v1.mtime;
516             st->st_mtime = msg.stat_v1.mtime;
517         }
518 
519         return true;
520     }
521 
SendLs(const std::string & path)522     bool SendLs(const std::string& path) {
523         return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
524     }
525 
526   private:
527     template <bool v2>
FinishLsImpl(borrowed_fd fd,const std::function<sync_ls_cb> & callback)528     static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) {
529         using dent_type =
530                 std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
531 
532         while (true) {
533             dent_type dent;
534             if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false;
535 
536             uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1;
537             if (dent.id == ID_DONE) return true;
538             if (dent.id != expected_id) return false;
539 
540             // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255.
541             char buf[256];
542             size_t len = dent.namelen;
543             if (len > 255) return false;
544 
545             if (!ReadFdExactly(fd, buf, len)) return false;
546             buf[len] = 0;
547             // Address the unlikely scenario wherein a
548             // compromised device/service might be able to
549             // traverse across directories on the host. Let's
550             // shut that door!
551             if (strchr(buf, '/')
552 #if defined(_WIN32)
553                 || strchr(buf, '\\')
554 #endif
555             ) {
556                 return false;
557             }
558             callback(dent.mode, dent.size, dent.mtime, buf);
559         }
560     }
561 
562   public:
FinishLs(const std::function<sync_ls_cb> & callback)563     bool FinishLs(const std::function<sync_ls_cb>& callback) {
564         if (have_ls_v2_) {
565             return FinishLsImpl<true>(this->fd, callback);
566         } else {
567             return FinishLsImpl<false>(this->fd, callback);
568         }
569     }
570 
571     // Sending header, payload, and footer in a single write makes a huge
572     // difference to "adb sync" performance.
SendSmallFile(const std::string & path,mode_t mode,const std::string & lpath,const std::string & rpath,unsigned mtime,const char * data,size_t data_length,bool dry_run)573     bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
574                        const std::string& rpath, unsigned mtime, const char* data,
575                        size_t data_length, bool dry_run) {
576         if (dry_run) {
577             // We need to use send v2 for dry run.
578             return SendLargeFile(path, mode, lpath, rpath, mtime, CompressionType::None, dry_run);
579         }
580 
581         std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
582         if (path_and_mode.length() > 1024) {
583             Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
584             errno = ENAMETOOLONG;
585             return false;
586         }
587 
588         std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
589                               data_length + sizeof(SyncRequest));
590         char* p = &buf[0];
591 
592         SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
593         req_send->id = ID_SEND_V1;
594         req_send->path_length = path_and_mode.length();
595         p += sizeof(SyncRequest);
596         memcpy(p, path_and_mode.data(), path_and_mode.size());
597         p += path_and_mode.length();
598 
599         SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
600         req_data->id = ID_DATA;
601         req_data->path_length = data_length;
602         p += sizeof(SyncRequest);
603         memcpy(p, data, data_length);
604         p += data_length;
605 
606         SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
607         req_done->id = ID_DONE;
608         req_done->path_length = mtime;
609         p += sizeof(SyncRequest);
610 
611         WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
612 
613         RecordFileSent(lpath, rpath);
614         RecordBytesTransferred(data_length);
615         ReportProgress(rpath, data_length, data_length);
616         return true;
617     }
618 
SendLargeFile(const std::string & path,mode_t mode,const std::string & lpath,const std::string & rpath,unsigned mtime,CompressionType compression,bool dry_run)619     bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
620                        const std::string& rpath, unsigned mtime, CompressionType compression,
621                        bool dry_run) {
622         if (dry_run && !HaveSendRecv2DryRunSend()) {
623             Error("dry-run not supported by the device");
624             return false;
625         }
626 
627         if (!HaveSendRecv2()) {
628             return SendLargeFileLegacy(path, mode, lpath, rpath, mtime);
629         }
630 
631         compression = ResolveCompressionType(compression);
632 
633         if (!SendSend2(path, mode, compression, dry_run)) {
634             Error("failed to send ID_SEND_V2 message '%s': %s", path.c_str(), strerror(errno));
635             return false;
636         }
637 
638         struct stat st;
639         if (stat(lpath.c_str(), &st) == -1) {
640             Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
641             return false;
642         }
643 
644         uint64_t total_size = st.st_size;
645         uint64_t bytes_copied = 0;
646 
647         unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
648         if (lfd < 0) {
649             Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
650             return false;
651         }
652 
653         syncsendbuf sbuf;
654         sbuf.id = ID_DATA;
655 
656         std::variant<std::monostate, NullEncoder, BrotliEncoder, LZ4Encoder, ZstdEncoder>
657                 encoder_storage;
658         Encoder* encoder = nullptr;
659         switch (compression) {
660             case CompressionType::None:
661                 encoder = &encoder_storage.emplace<NullEncoder>(SYNC_DATA_MAX);
662                 break;
663 
664             case CompressionType::Brotli:
665                 encoder = &encoder_storage.emplace<BrotliEncoder>(SYNC_DATA_MAX);
666                 break;
667 
668             case CompressionType::LZ4:
669                 encoder = &encoder_storage.emplace<LZ4Encoder>(SYNC_DATA_MAX);
670                 break;
671 
672             case CompressionType::Zstd:
673                 encoder = &encoder_storage.emplace<ZstdEncoder>(SYNC_DATA_MAX);
674                 break;
675 
676             case CompressionType::Any:
677                 LOG(FATAL) << "unexpected CompressionType::Any";
678         }
679 
680         bool sending = true;
681         while (sending) {
682             Block input(SYNC_DATA_MAX);
683             int r = adb_read(lfd.get(), input.data(), input.size());
684             if (r < 0) {
685                 Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
686                 return false;
687             }
688 
689             if (r == 0) {
690                 encoder->Finish();
691             } else {
692                 input.resize(r);
693                 encoder->Append(std::move(input));
694                 RecordBytesTransferred(r);
695                 bytes_copied += r;
696                 ReportProgress(rpath, bytes_copied, total_size);
697             }
698 
699             while (true) {
700                 Block output;
701                 EncodeResult result = encoder->Encode(&output);
702                 if (result == EncodeResult::Error) {
703                     Error("compressing '%s' locally failed", lpath.c_str());
704                     return false;
705                 }
706 
707                 if (!output.empty()) {
708                     sbuf.size = output.size();
709                     memcpy(sbuf.data, output.data(), output.size());
710                     WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + output.size());
711                 }
712 
713                 if (result == EncodeResult::Done) {
714                     sending = false;
715                     break;
716                 } else if (result == EncodeResult::NeedInput) {
717                     break;
718                 } else if (result == EncodeResult::MoreOutput) {
719                     continue;
720                 }
721             }
722         }
723 
724         syncmsg msg;
725         msg.data.id = ID_DONE;
726         msg.data.size = mtime;
727         RecordFileSent(lpath, rpath);
728         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
729     }
730 
SendLargeFileLegacy(const std::string & path,mode_t mode,const std::string & lpath,const std::string & rpath,unsigned mtime)731     bool SendLargeFileLegacy(const std::string& path, mode_t mode, const std::string& lpath,
732                              const std::string& rpath, unsigned mtime) {
733         std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
734         if (!SendRequest(ID_SEND_V1, path_and_mode)) {
735             Error("failed to send ID_SEND_V1 message '%s': %s", path_and_mode.c_str(),
736                   strerror(errno));
737             return false;
738         }
739 
740         struct stat st;
741         if (stat(lpath.c_str(), &st) == -1) {
742             Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
743             return false;
744         }
745 
746         uint64_t total_size = st.st_size;
747         uint64_t bytes_copied = 0;
748 
749         unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
750         if (lfd < 0) {
751             Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
752             return false;
753         }
754 
755         syncsendbuf sbuf;
756         sbuf.id = ID_DATA;
757 
758         while (true) {
759             int bytes_read = adb_read(lfd, sbuf.data, max);
760             if (bytes_read == -1) {
761                 Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
762                 return false;
763             } else if (bytes_read == 0) {
764                 break;
765             }
766 
767             sbuf.size = bytes_read;
768             WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
769 
770             RecordBytesTransferred(bytes_read);
771             bytes_copied += bytes_read;
772             ReportProgress(rpath, bytes_copied, total_size);
773         }
774 
775         syncmsg msg;
776         msg.data.id = ID_DONE;
777         msg.data.size = mtime;
778         RecordFileSent(lpath, rpath);
779         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
780     }
781 
ReportCopyFailure(const std::string & from,const std::string & to,const syncmsg & msg)782     bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
783         std::vector<char> buf(msg.status.msglen + 1);
784         if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
785             Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(),
786                   to.c_str(), strerror(errno));
787             return false;
788         }
789         buf[msg.status.msglen] = 0;
790         Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]);
791         return false;
792     }
793 
CopyDone()794     void CopyDone() { deferred_acknowledgements_.pop_front(); }
795 
ReportDeferredCopyFailure(const std::string & msg)796     void ReportDeferredCopyFailure(const std::string& msg) {
797         auto& [from, to] = deferred_acknowledgements_.front();
798         Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), msg.c_str());
799         deferred_acknowledgements_.pop_front();
800     }
801 
ReadAcknowledgements(bool read_all=false)802     bool ReadAcknowledgements(bool read_all = false) {
803         // We need to read enough such that adbd's intermediate socket's write buffer can't be
804         // full. The default buffer on Linux is 212992 bytes, but there's 576 bytes of bookkeeping
805         // overhead per write. The worst case scenario is a continuous string of failures, since
806         // each logical packet is divided into two writes. If our packet size if conservatively 512
807         // bytes long, this leaves us with space for 128 responses.
808         constexpr size_t max_deferred_acks = 128;
809         auto& buf = acknowledgement_buffer_;
810         adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
811         while (!deferred_acknowledgements_.empty()) {
812             bool should_block = read_all || deferred_acknowledgements_.size() >= max_deferred_acks;
813 
814             enum class ReadStatus {
815                 Success,
816                 Failure,
817                 TryLater,
818             };
819 
820             // Read until the acknowledgement buffer has at least `amount` bytes in it (or there is
821             // an I/O error, or the socket has no data ready to read).
822             auto read_until_amount = [&](size_t amount) -> ReadStatus {
823                 while (buf.size() < amount) {
824                     // The fd is blocking, so if we want to avoid blocking in this function, we must
825                     // poll first to verify that some data is available before trying to read it.
826                     if (!should_block) {
827                         ssize_t rc = adb_poll(&pfd, 1, 0);
828                         if (rc == 0) {
829                             return ReadStatus::TryLater;
830                         }
831                     }
832                     const ssize_t bytes_left = amount - buf.size();
833                     ssize_t rc = adb_read(fd, buf.end(), bytes_left);
834                     if (rc <= 0) {
835                         Error("failed to read copy response");
836                         return ReadStatus::Failure;
837                     }
838                     buf.resize(buf.size() + rc);
839                     if (!should_block && buf.size() < amount) {
840                         return ReadStatus::TryLater;
841                     }
842                 }
843                 return ReadStatus::Success;
844             };
845 
846             switch (read_until_amount(sizeof(sync_status))) {
847                 case ReadStatus::TryLater:
848                     return true;
849                 case ReadStatus::Failure:
850                     return false;
851                 case ReadStatus::Success:
852                     break;
853             }
854 
855             auto* hdr = reinterpret_cast<sync_status*>(buf.data());
856             if (hdr->id == ID_OKAY) {
857                 buf.resize(0);
858                 if (hdr->msglen != 0) {
859                     Error("received ID_OKAY with msg_len (%" PRIu32 " != 0", hdr->msglen);
860                     return false;
861                 }
862                 CopyDone();
863                 continue;
864             } else if (hdr->id != ID_FAIL) {
865                 Error("unexpected response from daemon: id = %#" PRIx32, hdr->id);
866                 return false;
867             } else if (hdr->msglen > SYNC_DATA_MAX) {
868                 Error("too-long message length from daemon: msglen = %" PRIu32, hdr->msglen);
869                 return false;
870             }
871 
872             switch (read_until_amount(sizeof(sync_status) + hdr->msglen)) {
873                 case ReadStatus::TryLater:
874                     return true;
875                 case ReadStatus::Failure:
876                     return false;
877                 case ReadStatus::Success:
878                     break;
879             }
880 
881             std::string msg(buf.begin() + sizeof(sync_status), buf.end());
882             ReportDeferredCopyFailure(msg);
883             buf.resize(0);
884             return false;
885         }
886 
887         return true;
888     }
889 
Printf(const char * fmt,...)890     void Printf(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
891         std::string s;
892 
893         va_list ap;
894         va_start(ap, fmt);
895         android::base::StringAppendV(&s, fmt, ap);
896         va_end(ap);
897 
898         line_printer_.Print(s, LinePrinter::INFO);
899     }
900 
Println(const char * fmt,...)901     void Println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
902         std::string s;
903 
904         va_list ap;
905         va_start(ap, fmt);
906         android::base::StringAppendV(&s, fmt, ap);
907         va_end(ap);
908 
909         line_printer_.Print(s, LinePrinter::INFO);
910         line_printer_.KeepInfoLine();
911     }
912 
Error(const char * fmt,...)913     void Error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
914         std::string s = "adb: error: ";
915 
916         va_list ap;
917         va_start(ap, fmt);
918         android::base::StringAppendV(&s, fmt, ap);
919         va_end(ap);
920 
921         line_printer_.Print(s, LinePrinter::ERROR);
922     }
923 
Warning(const char * fmt,...)924     void Warning(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
925         std::string s = "adb: warning: ";
926 
927         va_list ap;
928         va_start(ap, fmt);
929         android::base::StringAppendV(&s, fmt, ap);
930         va_end(ap);
931 
932         line_printer_.Print(s, LinePrinter::WARNING);
933     }
934 
ComputeExpectedTotalBytes(const std::vector<copyinfo> & file_list)935     void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
936         current_ledger_.bytes_expected = 0;
937         for (const copyinfo& ci : file_list) {
938             // Unfortunately, this doesn't work for symbolic links, because we'll copy the
939             // target of the link rather than just creating a link. (But ci.size is the link size.)
940             if (!ci.skip) current_ledger_.bytes_expected += ci.size;
941         }
942         current_ledger_.expect_multiple_files = true;
943     }
944 
SetExpectedTotalBytes(uint64_t expected_total_bytes)945     void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
946         current_ledger_.bytes_expected = expected_total_bytes;
947         current_ledger_.expect_multiple_files = false;
948     }
949 
950     // TODO: add a char[max] buffer here, to replace syncsendbuf...
951     unique_fd fd;
952     size_t max;
953 
954   private:
955     std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
956     Block acknowledgement_buffer_;
957     const FeatureSet* features_ = nullptr;
958     bool have_stat_v2_;
959     bool have_ls_v2_;
960     bool have_sendrecv_v2_;
961     bool have_sendrecv_v2_brotli_;
962     bool have_sendrecv_v2_lz4_;
963     bool have_sendrecv_v2_zstd_;
964     bool have_sendrecv_v2_dry_run_send_;
965 
966     TransferLedger global_ledger_;
967     TransferLedger current_ledger_;
968     LinePrinter line_printer_;
969 
SendQuit()970     bool SendQuit() {
971         return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
972     }
973 
WriteOrDie(const std::string & from,const std::string & to,const void * data,size_t data_length)974     bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
975                     size_t data_length) {
976         if (!WriteFdExactly(fd, data, data_length)) {
977             if (errno == ECONNRESET) {
978                 // Assume adbd told us why it was closing the connection, and
979                 // try to read failure reason from adbd.
980                 syncmsg msg;
981                 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
982                     Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
983                           strerror(errno));
984                 } else if (msg.status.id != ID_FAIL) {
985                     Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
986                           msg.status.id);
987                 } else {
988                     ReportCopyFailure(from, to, msg);
989                 }
990             } else {
991                 Error("%zu-byte write failed: %s", data_length, strerror(errno));
992             }
993             _exit(1);
994         }
995         return true;
996     }
997 };
998 
sync_ls(SyncConnection & sc,const std::string & path,const std::function<sync_ls_cb> & func)999 static bool sync_ls(SyncConnection& sc, const std::string& path,
1000                     const std::function<sync_ls_cb>& func) {
1001     return sc.SendLs(path) && sc.FinishLs(func);
1002 }
1003 
sync_stat(SyncConnection & sc,const std::string & path,struct stat * st)1004 static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
1005     return sc.SendStat(path) && sc.FinishStat(st);
1006 }
1007 
sync_lstat(SyncConnection & sc,const std::string & path,struct stat * st)1008 static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
1009     return sc.SendLstat(path) && sc.FinishStat(st);
1010 }
1011 
sync_stat_fallback(SyncConnection & sc,const std::string & path,struct stat * st)1012 static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
1013     if (sync_stat(sc, path, st)) {
1014         return true;
1015     }
1016 
1017     if (errno != ENOTSUP) {
1018         return false;
1019     }
1020 
1021     // Try to emulate the parts we can when talking to older adbds.
1022     bool lstat_result = sync_lstat(sc, path, st);
1023     if (!lstat_result) {
1024         return false;
1025     }
1026 
1027     if (S_ISLNK(st->st_mode)) {
1028         // If the target is a symlink, figure out whether it's a file or a directory.
1029         // Also, zero out the st_size field, since no one actually cares what the path length is.
1030         st->st_size = 0;
1031         std::string dir_path = path;
1032         dir_path.push_back('/');
1033         struct stat tmp_st;
1034 
1035         st->st_mode &= ~S_IFMT;
1036         if (sync_lstat(sc, dir_path, &tmp_st)) {
1037             st->st_mode |= S_IFDIR;
1038         } else {
1039             st->st_mode |= S_IFREG;
1040         }
1041     }
1042     return true;
1043 }
1044 
sync_send(SyncConnection & sc,const std::string & lpath,const std::string & rpath,unsigned mtime,mode_t mode,bool sync,CompressionType compression,bool dry_run)1045 static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
1046                       unsigned mtime, mode_t mode, bool sync, CompressionType compression,
1047                       bool dry_run) {
1048     if (sync) {
1049         struct stat st;
1050         if (sync_lstat(sc, rpath, &st)) {
1051             if (st.st_mtime == static_cast<time_t>(mtime)) {
1052                 sc.RecordFilesSkipped(1);
1053                 return true;
1054             }
1055         }
1056     }
1057 
1058     if (S_ISLNK(mode)) {
1059 #if !defined(_WIN32)
1060         char buf[PATH_MAX];
1061         ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
1062         if (data_length == -1) {
1063             sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
1064             return false;
1065         }
1066         buf[data_length++] = '\0';
1067 
1068         if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length, dry_run)) {
1069             return false;
1070         }
1071         return sc.ReadAcknowledgements(sync);
1072 #endif
1073     }
1074 
1075     struct stat st;
1076     if (stat(lpath.c_str(), &st) == -1) {
1077         sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
1078         return false;
1079     }
1080     if (st.st_size < SYNC_DATA_MAX) {
1081         std::string data;
1082         if (!android::base::ReadFileToString(lpath, &data, true)) {
1083             sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
1084             return false;
1085         }
1086         if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size(),
1087                               dry_run)) {
1088             return false;
1089         }
1090     } else {
1091         if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime, compression, dry_run)) {
1092             return false;
1093         }
1094     }
1095     return sc.ReadAcknowledgements(sync);
1096 }
1097 
sync_recv_v1(SyncConnection & sc,const char * rpath,const char * lpath,const char * name,uint64_t expected_size)1098 static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
1099                          uint64_t expected_size) {
1100     if (!sc.SendRequest(ID_RECV_V1, rpath)) return false;
1101 
1102     adb_unlink(lpath);
1103     unique_fd lfd(adb_creat(lpath, 0644));
1104     if (lfd < 0) {
1105         sc.Error("cannot create '%s': %s", lpath, strerror(errno));
1106         return false;
1107     }
1108 
1109     uint64_t bytes_copied = 0;
1110     while (true) {
1111         syncmsg msg;
1112         if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
1113             adb_unlink(lpath);
1114             return false;
1115         }
1116 
1117         if (msg.data.id == ID_DONE) break;
1118 
1119         if (msg.data.id != ID_DATA) {
1120             adb_unlink(lpath);
1121             sc.ReportCopyFailure(rpath, lpath, msg);
1122             return false;
1123         }
1124 
1125         if (msg.data.size > sc.max) {
1126             sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
1127             adb_unlink(lpath);
1128             return false;
1129         }
1130 
1131         char buffer[SYNC_DATA_MAX];
1132         if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
1133             adb_unlink(lpath);
1134             return false;
1135         }
1136 
1137         if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
1138             sc.Error("cannot write '%s': %s", lpath, strerror(errno));
1139             adb_unlink(lpath);
1140             return false;
1141         }
1142 
1143         bytes_copied += msg.data.size;
1144 
1145         sc.RecordBytesTransferred(msg.data.size);
1146         sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
1147     }
1148 
1149     sc.RecordFilesTransferred(1);
1150     return true;
1151 }
1152 
sync_recv_v2(SyncConnection & sc,const char * rpath,const char * lpath,const char * name,uint64_t expected_size,CompressionType compression)1153 static bool sync_recv_v2(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
1154                          uint64_t expected_size, CompressionType compression) {
1155     compression = sc.ResolveCompressionType(compression);
1156 
1157     if (!sc.SendRecv2(rpath, compression)) return false;
1158 
1159     adb_unlink(lpath);
1160     unique_fd lfd(adb_creat(lpath, 0644));
1161     if (lfd < 0) {
1162         sc.Error("cannot create '%s': %s", lpath, strerror(errno));
1163         return false;
1164     }
1165 
1166     uint64_t bytes_copied = 0;
1167 
1168     Block buffer(SYNC_DATA_MAX);
1169     std::variant<std::monostate, NullDecoder, BrotliDecoder, LZ4Decoder, ZstdDecoder>
1170             decoder_storage;
1171     Decoder* decoder = nullptr;
1172 
1173     std::span buffer_span(buffer.data(), buffer.size());
1174     switch (compression) {
1175         case CompressionType::None:
1176             decoder = &decoder_storage.emplace<NullDecoder>(buffer_span);
1177             break;
1178 
1179         case CompressionType::Brotli:
1180             decoder = &decoder_storage.emplace<BrotliDecoder>(buffer_span);
1181             break;
1182 
1183         case CompressionType::LZ4:
1184             decoder = &decoder_storage.emplace<LZ4Decoder>(buffer_span);
1185             break;
1186 
1187         case CompressionType::Zstd:
1188             decoder = &decoder_storage.emplace<ZstdDecoder>(buffer_span);
1189             break;
1190 
1191         case CompressionType::Any:
1192             LOG(FATAL) << "unexpected CompressionType::Any";
1193     }
1194 
1195     while (true) {
1196         syncmsg msg;
1197         if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
1198             adb_unlink(lpath);
1199             return false;
1200         }
1201 
1202         if (msg.data.id == ID_DONE) {
1203             if (!decoder->Finish()) {
1204                 sc.Error("unexpected ID_DONE");
1205                 return false;
1206             }
1207         } else if (msg.data.id != ID_DATA) {
1208             adb_unlink(lpath);
1209             sc.ReportCopyFailure(rpath, lpath, msg);
1210             return false;
1211         } else {
1212             if (msg.data.size > sc.max) {
1213                 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
1214                 adb_unlink(lpath);
1215                 return false;
1216             }
1217 
1218             Block block(msg.data.size);
1219             if (!ReadFdExactly(sc.fd, block.data(), msg.data.size)) {
1220                 adb_unlink(lpath);
1221                 return false;
1222             }
1223             decoder->Append(std::move(block));
1224         }
1225 
1226         while (true) {
1227             std::span<char> output;
1228             DecodeResult result = decoder->Decode(&output);
1229 
1230             if (result == DecodeResult::Error) {
1231                 sc.Error("decompress failed");
1232                 adb_unlink(lpath);
1233                 return false;
1234             }
1235 
1236             if (!output.empty()) {
1237                 if (!WriteFdExactly(lfd, output.data(), output.size())) {
1238                     sc.Error("cannot write '%s': %s", lpath, strerror(errno));
1239                     adb_unlink(lpath);
1240                     return false;
1241                 }
1242             }
1243 
1244             bytes_copied += output.size();
1245             sc.RecordBytesTransferred(output.size());
1246             sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
1247 
1248             if (result == DecodeResult::NeedInput) {
1249                 break;
1250             } else if (result == DecodeResult::MoreOutput) {
1251                 continue;
1252             } else if (result == DecodeResult::Done) {
1253                 sc.RecordFilesTransferred(1);
1254                 return true;
1255             } else {
1256                 LOG(FATAL) << "invalid DecodeResult: " << static_cast<int>(result);
1257             }
1258         }
1259     }
1260 }
1261 
sync_recv(SyncConnection & sc,const char * rpath,const char * lpath,const char * name,uint64_t expected_size,CompressionType compression)1262 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
1263                       uint64_t expected_size, CompressionType compression) {
1264     if (sc.HaveSendRecv2()) {
1265         return sync_recv_v2(sc, rpath, lpath, name, expected_size, compression);
1266     } else {
1267         return sync_recv_v1(sc, rpath, lpath, name, expected_size);
1268     }
1269 }
1270 
do_sync_ls(const char * path)1271 bool do_sync_ls(const char* path) {
1272     SyncConnection sc;
1273     if (!sc.IsValid()) return false;
1274 
1275     return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) {
1276         printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name);
1277     });
1278 }
1279 
IsDotOrDotDot(const char * name)1280 static bool IsDotOrDotDot(const char* name) {
1281     return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
1282 }
1283 
local_build_list(SyncConnection & sc,std::vector<copyinfo> * file_list,std::vector<std::string> * directory_list,const std::string & lpath,const std::string & rpath)1284 static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
1285                              std::vector<std::string>* directory_list, const std::string& lpath,
1286                              const std::string& rpath) {
1287     std::vector<copyinfo> dirlist;
1288     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
1289     if (!dir) {
1290         sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
1291         return false;
1292     }
1293 
1294     dirent* de;
1295     while ((de = readdir(dir.get()))) {
1296         if (IsDotOrDotDot(de->d_name)) {
1297             continue;
1298         }
1299 
1300         std::string stat_path = lpath + de->d_name;
1301 
1302         struct stat st;
1303         if (lstat(stat_path.c_str(), &st) == -1) {
1304             sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
1305                      strerror(errno));
1306             continue;
1307         }
1308 
1309         copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
1310         if (S_ISDIR(st.st_mode)) {
1311             dirlist.push_back(ci);
1312         } else {
1313             if (!should_push_file(st.st_mode)) {
1314                 sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
1315                 ci.skip = true;
1316             }
1317             ci.time = st.st_mtime;
1318             ci.size = st.st_size;
1319             file_list->push_back(ci);
1320         }
1321     }
1322 
1323     // Close this directory and recurse.
1324     dir.reset();
1325 
1326     for (const copyinfo& ci : dirlist) {
1327         directory_list->push_back(ci.rpath);
1328         local_build_list(sc, file_list, directory_list, ci.lpath, ci.rpath);
1329     }
1330 
1331     return true;
1332 }
1333 
1334 // dirname("//foo") returns "//", so we can't do the obvious `path == "/"`.
is_root_dir(std::string_view path)1335 static bool is_root_dir(std::string_view path) {
1336     for (char c : path) {
1337         if (c != '/') {
1338             return false;
1339         }
1340     }
1341     return true;
1342 }
1343 
copy_local_dir_remote(SyncConnection & sc,std::string lpath,std::string rpath,bool check_timestamps,bool list_only,CompressionType compression,bool dry_run)1344 static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, std::string rpath,
1345                                   bool check_timestamps, bool list_only,
1346                                   CompressionType compression, bool dry_run) {
1347     sc.NewTransfer();
1348 
1349     // Make sure that both directory paths end in a slash.
1350     // Both paths are known to be nonempty, so we don't need to check.
1351     ensure_trailing_separators(lpath, rpath);
1352 
1353     // Recursively build the list of files to copy.
1354     std::vector<copyinfo> file_list;
1355     std::vector<std::string> directory_list;
1356 
1357     for (std::string path = rpath; !is_root_dir(path); path = android::base::Dirname(path)) {
1358         directory_list.push_back(path);
1359     }
1360     std::reverse(directory_list.begin(), directory_list.end());
1361 
1362     int skipped = 0;
1363     if (!local_build_list(sc, &file_list, &directory_list, lpath, rpath)) {
1364         return false;
1365     }
1366 
1367     // b/110953234:
1368     // P shipped with a bug that causes directory creation as a side-effect of a push to fail.
1369     // Work around this by explicitly doing a mkdir via shell.
1370     //
1371     // Devices that don't support shell_v2 are unhappy if we try to send a too-long packet to them,
1372     // but they're not affected by this bug, so only apply the workaround if we have shell_v2.
1373     //
1374     // TODO(b/25457350): We don't preserve permissions on directories.
1375     // TODO: Find all of the leaves and `mkdir -p` them instead?
1376     if (!CanUseFeature(sc.Features(), kFeatureFixedPushMkdir) &&
1377         CanUseFeature(sc.Features(), kFeatureShell2)) {
1378         SilentStandardStreamsCallbackInterface cb;
1379         std::string cmd = "mkdir";
1380         for (const auto& dir : directory_list) {
1381             std::string escaped_path = escape_arg(dir);
1382             if (escaped_path.size() > 16384) {
1383                 // Somewhat arbitrarily limit that probably won't ever happen.
1384                 sc.Error("path too long: %s", escaped_path.c_str());
1385                 return false;
1386             }
1387 
1388             // The maximum should be 64kiB, but that's not including other stuff that gets tacked
1389             // onto the command line, so let's be a bit conservative.
1390             if (cmd.size() + escaped_path.size() > 32768) {
1391                 // Dispatch the command, ignoring failure (since the directory might already exist).
1392                 send_shell_command(cmd, false, &cb);
1393                 cmd = "mkdir";
1394             }
1395             cmd += " ";
1396             cmd += escaped_path;
1397         }
1398 
1399         if (cmd != "mkdir") {
1400             send_shell_command(cmd, false, &cb);
1401         }
1402     }
1403 
1404     if (check_timestamps) {
1405         for (const copyinfo& ci : file_list) {
1406             if (!sc.SendLstat(ci.rpath)) {
1407                 sc.Error("failed to send lstat");
1408                 return false;
1409             }
1410         }
1411         for (copyinfo& ci : file_list) {
1412             struct stat st;
1413             if (sc.FinishStat(&st)) {
1414                 if (st.st_size == static_cast<off_t>(ci.size) && st.st_mtime == ci.time) {
1415                     ci.skip = true;
1416                 }
1417             }
1418         }
1419     }
1420 
1421     sc.ComputeExpectedTotalBytes(file_list);
1422 
1423     for (const copyinfo& ci : file_list) {
1424         if (!ci.skip) {
1425             if (list_only) {
1426                 sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
1427             } else {
1428                 if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false, compression,
1429                                dry_run)) {
1430                     return false;
1431                 }
1432             }
1433         } else {
1434             skipped++;
1435         }
1436     }
1437 
1438     sc.RecordFilesSkipped(skipped);
1439     bool success = sc.ReadAcknowledgements(true);
1440     sc.ReportTransferRate(lpath, TransferDirection::push);
1441     return success;
1442 }
1443 
do_sync_push(const std::vector<const char * > & srcs,const char * dst,bool sync,CompressionType compression,bool dry_run)1444 bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync,
1445                   CompressionType compression, bool dry_run) {
1446     SyncConnection sc;
1447     if (!sc.IsValid()) return false;
1448 
1449     bool success = true;
1450     bool dst_exists;
1451     bool dst_isdir;
1452 
1453     struct stat st;
1454     if (sync_stat_fallback(sc, dst, &st)) {
1455         dst_exists = true;
1456         dst_isdir = S_ISDIR(st.st_mode);
1457     } else {
1458         if (errno == ENOENT || errno == ENOPROTOOPT) {
1459             dst_exists = false;
1460             dst_isdir = false;
1461         } else {
1462             sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno));
1463             return false;
1464         }
1465     }
1466 
1467     if (!dst_isdir) {
1468         if (srcs.size() > 1) {
1469             sc.Error("target '%s' is not a directory", dst);
1470             return false;
1471         } else {
1472             size_t dst_len = strlen(dst);
1473 
1474             // A path that ends with a slash doesn't have to be a directory if
1475             // it doesn't exist yet.
1476             if (dst[dst_len - 1] == '/' && dst_exists) {
1477                 sc.Error("failed to access '%s': Not a directory", dst);
1478                 return false;
1479             }
1480         }
1481     }
1482 
1483     for (const char* src_path : srcs) {
1484         const char* dst_path = dst;
1485         struct stat st;
1486         if (stat(src_path, &st) == -1) {
1487             sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
1488             success = false;
1489             continue;
1490         }
1491 
1492         if (S_ISDIR(st.st_mode)) {
1493             std::string dst_dir = dst;
1494 
1495             // If the destination path existed originally, the source directory
1496             // should be copied as a child of the destination.
1497             if (dst_exists) {
1498                 if (!dst_isdir) {
1499                     sc.Error("target '%s' is not a directory", dst);
1500                     return false;
1501                 }
1502                 // dst is a POSIX path, so we don't want to use the sysdeps
1503                 // helpers here.
1504                 if (dst_dir.back() != '/') {
1505                     dst_dir.push_back('/');
1506                 }
1507                 dst_dir.append(android::base::Basename(src_path));
1508             }
1509 
1510             success &=
1511                     copy_local_dir_remote(sc, src_path, dst_dir, sync, false, compression, dry_run);
1512             continue;
1513         } else if (!should_push_file(st.st_mode)) {
1514             sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
1515             continue;
1516         }
1517 
1518         std::string path_holder;
1519         if (dst_isdir) {
1520             // If we're copying a local file to a remote directory,
1521             // we really want to copy to remote_dir + "/" + local_filename.
1522             path_holder = dst_path;
1523             if (path_holder.back() != '/') {
1524                 path_holder.push_back('/');
1525             }
1526             path_holder += android::base::Basename(src_path);
1527             dst_path = path_holder.c_str();
1528         }
1529 
1530         sc.NewTransfer();
1531         sc.SetExpectedTotalBytes(st.st_size);
1532         success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync, compression,
1533                              dry_run);
1534         sc.ReportTransferRate(src_path, TransferDirection::push);
1535     }
1536 
1537     success &= sc.ReadAcknowledgements(true);
1538     sc.ReportOverallTransferRate(TransferDirection::push);
1539     return success;
1540 }
1541 
remote_build_list(SyncConnection & sc,std::vector<copyinfo> * file_list,const std::string & rpath,const std::string & lpath)1542 static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
1543                               const std::string& rpath, const std::string& lpath) {
1544     std::vector<copyinfo> dirlist;
1545     std::vector<copyinfo> linklist;
1546 
1547     // Add an entry for the current directory to ensure it gets created before pulling its contents.
1548     copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
1549                 android::base::Basename(lpath), S_IFDIR);
1550     file_list->push_back(ci);
1551 
1552     // Put the files/dirs in rpath on the lists.
1553     auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) {
1554         if (IsDotOrDotDot(name)) {
1555             return;
1556         }
1557 
1558         copyinfo ci(lpath, rpath, name, mode);
1559         if (S_ISDIR(mode)) {
1560             dirlist.push_back(ci);
1561         } else if (S_ISLNK(mode)) {
1562             linklist.push_back(ci);
1563         } else {
1564             if (!should_pull_file(ci.mode)) {
1565                 sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
1566                 ci.skip = true;
1567             }
1568             ci.time = time;
1569             ci.size = size;
1570             file_list->push_back(ci);
1571         }
1572     };
1573 
1574     if (!sync_ls(sc, rpath, callback)) {
1575         return false;
1576     }
1577 
1578     // Check each symlink we found to see whether it's a file or directory.
1579     for (copyinfo& link_ci : linklist) {
1580         struct stat st;
1581         if (!sync_stat_fallback(sc, link_ci.rpath, &st)) {
1582             sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
1583             continue;
1584         }
1585 
1586         if (S_ISDIR(st.st_mode)) {
1587             dirlist.emplace_back(std::move(link_ci));
1588         } else {
1589             file_list->emplace_back(std::move(link_ci));
1590         }
1591     }
1592 
1593     // Recurse into each directory we found.
1594     while (!dirlist.empty()) {
1595         copyinfo current = dirlist.back();
1596         dirlist.pop_back();
1597         if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
1598             return false;
1599         }
1600     }
1601 
1602     return true;
1603 }
1604 
set_time_and_mode(const std::string & lpath,time_t time,unsigned int mode)1605 static int set_time_and_mode(const std::string& lpath, time_t time,
1606                              unsigned int mode) {
1607     struct utimbuf times = { time, time };
1608     int r1 = utime(lpath.c_str(), &times);
1609 
1610     /* use umask for permissions */
1611     mode_t mask = umask(0000);
1612     umask(mask);
1613     int r2 = chmod(lpath.c_str(), mode & ~mask);
1614 
1615     return r1 ? r1 : r2;
1616 }
1617 
copy_remote_dir_local(SyncConnection & sc,std::string rpath,std::string lpath,bool copy_attrs,CompressionType compression)1618 static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath, std::string lpath,
1619                                   bool copy_attrs, CompressionType compression) {
1620     sc.NewTransfer();
1621 
1622     // Make sure that both directory paths end in a slash.
1623     // Both paths are known to be nonempty, so we don't need to check.
1624     ensure_trailing_separators(lpath, rpath);
1625 
1626     // Recursively build the list of files to copy.
1627     sc.Printf("pull: building file list...");
1628     std::vector<copyinfo> file_list;
1629     if (!remote_build_list(sc, &file_list, rpath, lpath)) {
1630         return false;
1631     }
1632 
1633     sc.ComputeExpectedTotalBytes(file_list);
1634 
1635     int skipped = 0;
1636     for (const copyinfo &ci : file_list) {
1637         if (!ci.skip) {
1638             if (S_ISDIR(ci.mode)) {
1639                 // Entry is for an empty directory, create it and continue.
1640                 // TODO(b/25457350): We don't preserve permissions on directories.
1641                 if (!mkdirs(ci.lpath))  {
1642                     sc.Error("failed to create directory '%s': %s",
1643                              ci.lpath.c_str(), strerror(errno));
1644                     return false;
1645                 }
1646                 continue;
1647             }
1648 
1649             if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size, compression)) {
1650                 return false;
1651             }
1652 
1653             if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
1654                 return false;
1655             }
1656         } else {
1657             skipped++;
1658         }
1659     }
1660 
1661     sc.RecordFilesSkipped(skipped);
1662     sc.ReportTransferRate(rpath, TransferDirection::pull);
1663     return true;
1664 }
1665 
do_sync_pull(const std::vector<const char * > & srcs,const char * dst,bool copy_attrs,CompressionType compression,const char * name)1666 bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
1667                   CompressionType compression, const char* name) {
1668     SyncConnection sc;
1669     if (!sc.IsValid()) return false;
1670 
1671     bool success = true;
1672     struct stat st;
1673     bool dst_exists = true;
1674 
1675     if (stat(dst, &st) == -1) {
1676         dst_exists = false;
1677 
1678         // If we're only pulling one path, the destination path might point to
1679         // a path that doesn't exist yet.
1680         if (srcs.size() == 1 && errno == ENOENT) {
1681             // However, its parent must exist.
1682             struct stat parent_st;
1683             if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
1684                 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
1685                 return false;
1686             }
1687         } else {
1688             sc.Error("failed to access '%s': %s", dst, strerror(errno));
1689             return false;
1690         }
1691     }
1692 
1693     bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
1694     if (!dst_isdir) {
1695         if (srcs.size() > 1) {
1696             sc.Error("target '%s' is not a directory", dst);
1697             return false;
1698         } else {
1699             size_t dst_len = strlen(dst);
1700 
1701             // A path that ends with a slash doesn't have to be a directory if
1702             // it doesn't exist yet.
1703             if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
1704                 sc.Error("failed to access '%s': Not a directory", dst);
1705                 return false;
1706             }
1707         }
1708     }
1709 
1710     for (const char* src_path : srcs) {
1711         const char* dst_path = dst;
1712         struct stat src_st;
1713         if (!sync_stat_fallback(sc, src_path, &src_st)) {
1714             if (errno == ENOPROTOOPT) {
1715                 sc.Error("remote object '%s' does not exist", src_path);
1716             } else {
1717                 sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno));
1718             }
1719 
1720             success = false;
1721             continue;
1722         }
1723 
1724         bool src_isdir = S_ISDIR(src_st.st_mode);
1725         if (src_isdir) {
1726             std::string dst_dir = dst;
1727 
1728             // If the destination path existed originally, the source directory
1729             // should be copied as a child of the destination.
1730             if (dst_exists) {
1731                 if (!dst_isdir) {
1732                     sc.Error("target '%s' is not a directory", dst);
1733                     return false;
1734                 }
1735                 if (!adb_is_separator(dst_dir.back())) {
1736                     dst_dir.push_back(OS_PATH_SEPARATOR);
1737                 }
1738                 dst_dir.append(android::base::Basename(src_path));
1739             }
1740 
1741             success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs, compression);
1742             continue;
1743         } else if (!should_pull_file(src_st.st_mode)) {
1744             sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
1745             continue;
1746         }
1747 
1748         std::string path_holder;
1749         if (dst_isdir) {
1750             // If we're copying a remote file to a local directory, we
1751             // really want to copy to local_dir + OS_PATH_SEPARATOR +
1752             // basename(remote).
1753             path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
1754                                                       android::base::Basename(src_path).c_str());
1755             dst_path = path_holder.c_str();
1756         }
1757 
1758         sc.NewTransfer();
1759         sc.SetExpectedTotalBytes(src_st.st_size);
1760         if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size, compression)) {
1761             success = false;
1762             continue;
1763         }
1764 
1765         if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) {
1766             success = false;
1767             continue;
1768         }
1769         sc.ReportTransferRate(src_path, TransferDirection::pull);
1770     }
1771 
1772     sc.ReportOverallTransferRate(TransferDirection::pull);
1773     return success;
1774 }
1775 
do_sync_sync(const std::string & lpath,const std::string & rpath,bool list_only,CompressionType compression,bool dry_run)1776 bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only,
1777                   CompressionType compression, bool dry_run) {
1778     SyncConnection sc;
1779     if (!sc.IsValid()) return false;
1780 
1781     bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only, compression, dry_run);
1782     if (!list_only) {
1783         sc.ReportOverallTransferRate(TransferDirection::push);
1784     }
1785     return success;
1786 }
1787