2009-03-04 03:32:55 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2015-02-24 23:51:19 +00:00
|
|
|
#include <dirent.h>
|
2015-05-13 07:02:55 +00:00
|
|
|
#include <inttypes.h>
|
2015-02-24 23:51:19 +00:00
|
|
|
#include <limits.h>
|
2009-03-04 03:32:55 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
2015-02-24 23:51:19 +00:00
|
|
|
#include <time.h>
|
2015-09-27 19:55:37 +00:00
|
|
|
#include <unistd.h>
|
2014-05-06 15:48:18 +00:00
|
|
|
#include <utime.h>
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
#include <chrono>
|
2015-11-03 00:45:47 +00:00
|
|
|
#include <functional>
|
2015-08-24 21:49:43 +00:00
|
|
|
#include <memory>
|
2016-08-04 21:53:17 +00:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
2015-10-27 20:40:35 +00:00
|
|
|
#include <vector>
|
2015-08-24 21:49:43 +00:00
|
|
|
|
2009-03-04 03:32:55 +00:00
|
|
|
#include "sysdeps.h"
|
2015-02-24 23:51:19 +00:00
|
|
|
|
2009-03-04 03:32:55 +00:00
|
|
|
#include "adb.h"
|
|
|
|
#include "adb_client.h"
|
2015-02-25 05:26:58 +00:00
|
|
|
#include "adb_io.h"
|
2015-05-06 21:22:25 +00:00
|
|
|
#include "adb_utils.h"
|
2009-03-04 03:32:55 +00:00
|
|
|
#include "file_sync_service.h"
|
2015-10-27 23:03:15 +00:00
|
|
|
#include "line_printer.h"
|
2016-12-06 01:11:34 +00:00
|
|
|
#include "sysdeps/errno.h"
|
2016-11-18 23:17:07 +00:00
|
|
|
#include "sysdeps/stat.h"
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-12-05 06:00:26 +00:00
|
|
|
#include <android-base/file.h>
|
|
|
|
#include <android-base/strings.h>
|
|
|
|
#include <android-base/stringprintf.h>
|
2015-07-31 00:42:01 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
struct syncsendbuf {
|
|
|
|
unsigned id;
|
|
|
|
unsigned size;
|
|
|
|
char data[SYNC_DATA_MAX];
|
|
|
|
};
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) {
|
|
|
|
if (!adb_is_separator(local_path.back())) {
|
|
|
|
local_path.push_back(OS_PATH_SEPARATOR);
|
|
|
|
}
|
|
|
|
if (remote_path.back() != '/') {
|
|
|
|
remote_path.push_back('/');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-03 00:11:13 +00:00
|
|
|
static bool should_pull_file(mode_t mode) {
|
2016-11-18 23:17:07 +00:00
|
|
|
return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
|
2016-03-03 00:11:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool should_push_file(mode_t mode) {
|
2016-11-18 23:17:07 +00:00
|
|
|
return S_ISREG(mode) || S_ISLNK(mode);
|
2016-03-03 00:11:13 +00:00
|
|
|
}
|
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
struct copyinfo {
|
|
|
|
std::string lpath;
|
|
|
|
std::string rpath;
|
2016-12-06 01:11:34 +00:00
|
|
|
int64_t time = 0;
|
|
|
|
uint32_t mode;
|
2015-12-18 01:05:29 +00:00
|
|
|
uint64_t size = 0;
|
|
|
|
bool skip = false;
|
|
|
|
|
|
|
|
copyinfo(const std::string& local_path,
|
|
|
|
const std::string& remote_path,
|
|
|
|
const std::string& name,
|
|
|
|
unsigned int mode)
|
|
|
|
: lpath(local_path), rpath(remote_path), mode(mode) {
|
|
|
|
ensure_trailing_separators(lpath, rpath);
|
|
|
|
lpath.append(name);
|
|
|
|
rpath.append(name);
|
|
|
|
if (S_ISDIR(mode)) {
|
|
|
|
ensure_trailing_separators(lpath, rpath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
enum class TransferDirection {
|
|
|
|
push,
|
|
|
|
pull,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TransferLedger {
|
|
|
|
std::chrono::steady_clock::time_point start_time;
|
|
|
|
uint64_t files_transferred;
|
|
|
|
uint64_t files_skipped;
|
|
|
|
uint64_t bytes_transferred;
|
|
|
|
uint64_t bytes_expected;
|
|
|
|
bool expect_multiple_files;
|
|
|
|
|
|
|
|
TransferLedger() {
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const TransferLedger& other) const {
|
|
|
|
return files_transferred == other.files_transferred &&
|
|
|
|
files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const TransferLedger& other) const {
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Reset() {
|
|
|
|
start_time = std::chrono::steady_clock::now();
|
|
|
|
files_transferred = 0;
|
|
|
|
files_skipped = 0;
|
|
|
|
bytes_transferred = 0;
|
|
|
|
bytes_expected = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string TransferRate() {
|
|
|
|
if (bytes_transferred == 0) return "";
|
|
|
|
|
|
|
|
std::chrono::duration<double> duration;
|
|
|
|
duration = std::chrono::steady_clock::now() - start_time;
|
|
|
|
|
|
|
|
double s = duration.count();
|
|
|
|
if (s == 0) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
|
|
|
|
return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
|
|
|
|
bytes_transferred, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
|
|
|
|
uint64_t file_total_bytes) {
|
|
|
|
char overall_percentage_str[5] = "?";
|
2016-11-18 00:02:36 +00:00
|
|
|
if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
|
2016-08-04 21:53:17 +00:00
|
|
|
int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
|
|
|
|
// If we're pulling symbolic links, we'll pull the target of the link rather than
|
|
|
|
// just create a local link, and that will cause us to go over 100%.
|
|
|
|
if (overall_percentage <= 100) {
|
|
|
|
snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
|
|
|
|
overall_percentage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string output;
|
|
|
|
if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
|
|
|
|
// This case can happen if we're racing against something that wrote to the file
|
|
|
|
// between our stat and our read, or if we're reading a magic file that lies about
|
|
|
|
// its size. Just show how much we've copied.
|
|
|
|
output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
|
|
|
|
file.c_str(), file_copied_bytes);
|
|
|
|
} else {
|
|
|
|
// If we're transferring multiple files, we want to know how far through the current
|
|
|
|
// file we are, as well as the overall percentage.
|
|
|
|
if (expect_multiple_files) {
|
|
|
|
int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
|
|
|
|
output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
|
|
|
|
file.c_str(), file_percentage);
|
|
|
|
} else {
|
|
|
|
output =
|
|
|
|
android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lp.Print(output, LinePrinter::LineType::INFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
|
|
|
|
const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
|
|
|
|
std::stringstream ss;
|
|
|
|
if (!name.empty()) {
|
|
|
|
ss << name << ": ";
|
|
|
|
}
|
|
|
|
ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
|
|
|
|
<< direction_str << ".";
|
|
|
|
if (files_skipped > 0) {
|
|
|
|
ss << " " << files_skipped << " file" << ((files_skipped == 1) ? "" : "s")
|
|
|
|
<< " skipped.";
|
|
|
|
}
|
|
|
|
ss << TransferRate();
|
|
|
|
|
|
|
|
lp.Print(ss.str(), LinePrinter::LineType::INFO);
|
|
|
|
lp.KeepInfoLine();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
class SyncConnection {
|
|
|
|
public:
|
2016-08-04 21:53:17 +00:00
|
|
|
SyncConnection() : expect_done_(false) {
|
2015-08-03 17:38:08 +00:00
|
|
|
max = SYNC_DATA_MAX; // TODO: decide at runtime.
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
std::string error;
|
2016-12-06 01:11:34 +00:00
|
|
|
FeatureSet features;
|
|
|
|
if (!adb_get_feature_set(&features, &error)) {
|
|
|
|
fd = -1;
|
|
|
|
Error("failed to get feature set: %s", error.c_str());
|
|
|
|
} else {
|
|
|
|
have_stat_v2_ = CanUseFeature(features, kFeatureStat2);
|
|
|
|
fd = adb_connect("sync:", &error);
|
|
|
|
if (fd < 0) {
|
|
|
|
Error("connect failed: %s", error.c_str());
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
~SyncConnection() {
|
|
|
|
if (!IsValid()) return;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
adb: fix adb client running out of sockets on Windows
Background
==========
On Windows, if you run "adb shell exit" in a loop in two windows,
eventually the adb client will be unable to connect to the adb server. I
think connect() is returning WSAEADDRINUSE: "Only one usage of each
socket address (protocol/network address/port) is normally permitted.
(10048)". The Windows System Event Log may also show Event 4227, Tcpip.
Netstat output is filled with:
# for the adb server
TCP 127.0.0.1:5037 127.0.0.1:65523 TIME_WAIT
# for the adb client
TCP 127.0.0.1:65523 127.0.0.1:5037 TIME_WAIT
The error probably means that the client is running out of free
address:port pairs.
The first netstat line is unavoidable, but the second line exists
because the adb client is not waiting for orderly/graceful shutdown of
the socket, and that is apparently required on Windows to get rid of the
second line. For more info, see
https://github.com/CompareAndSwap/SocketCloseTest .
This is exacerbated by the fact that "adb shell exit" makes 4 socket
connections to the adb server: 1) host:version, 2) host:features, 3)
host:version (again), 4) shell:exit. Also exacerbating is the fact that
the adb protocol is length-prefixed so the client typically does not
have to 'read() until zero' which effectively waits for orderly/graceful
shutdown.
The Fix
=======
Introduce a function, ReadOrderlyShutdown(), that should be called in
the adb client to wait for the server to close its socket, before
closing the client socket.
I reviewed all code where the adb client makes a connection to the adb
server and added ReadOrderlyShutdown() when it made sense. I wasn't able
to add it to the following:
* interactive_shell: this doesn't matter because this is interactive and
thus can't be run fast enough to use up ports.
* adb sideload: I couldn't get enough test coverage and I don't think
this is being called frequently enough to be a problem.
* send_shell_command, backup, adb_connect_command, adb shell, adb
exec-out, install_multiple_app, adb_send_emulator_command: These
already wait for server socket shutdown since they already call
recv() until zero.
* restore, adb exec-in: protocol design can't have the server close
first.
* adb start-server: no fd is actually returned
* create_local_service_socket, local_connect_arbitrary_ports,
connect_device: probably called rarely enough not to be a problem.
Also in this change
===================
* Clarify comments in when adb_shutdown() is called before exit().
* add some missing adb_close() in adb sideload.
* Fixup error handling and comments in adb_send_emulator_command().
* Make SyncConnection::SendQuit return a success boolean.
* Add unittest for adb emu kill command. This gets code coverage over
this very careful piece of code.
Change-Id: Iad0b1336f5b74186af2cd35f7ea827d0fa77a17c
Signed-off-by: Spencer Low <CompareAndSwap@gmail.com>
2015-10-15 00:32:44 +00:00
|
|
|
if (SendQuit()) {
|
|
|
|
// We sent a quit command, so the server should be doing orderly
|
|
|
|
// shutdown soon. But if we encountered an error while we were using
|
|
|
|
// the connection, the server might still be sending data (before
|
|
|
|
// doing orderly shutdown), in which case we won't wait for all of
|
|
|
|
// the data nor the coming orderly shutdown. In the common success
|
|
|
|
// case, this will wait for the server to do orderly shutdown.
|
|
|
|
ReadOrderlyShutdown(fd);
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
adb_close(fd);
|
2015-12-09 00:01:15 +00:00
|
|
|
|
|
|
|
line_printer_.KeepInfoLine();
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
bool IsValid() { return fd >= 0; }
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2016-02-19 23:55:55 +00:00
|
|
|
bool ReceivedError(const char* from, const char* to) {
|
|
|
|
adb_pollfd pfd = {.fd = fd, .events = POLLIN};
|
|
|
|
int rc = adb_poll(&pfd, 1, 0);
|
|
|
|
if (rc < 0) {
|
|
|
|
Error("failed to poll: %s", strerror(errno));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return rc != 0;
|
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
void NewTransfer() {
|
|
|
|
current_ledger_.Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecordBytesTransferred(size_t bytes) {
|
|
|
|
current_ledger_.bytes_transferred += bytes;
|
|
|
|
global_ledger_.bytes_transferred += bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecordFilesTransferred(size_t files) {
|
|
|
|
current_ledger_.files_transferred += files;
|
|
|
|
global_ledger_.files_transferred += files;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecordFilesSkipped(size_t files) {
|
|
|
|
current_ledger_.files_skipped += files;
|
|
|
|
global_ledger_.files_skipped += files;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
|
|
|
|
uint64_t file_total_bytes) {
|
|
|
|
current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReportTransferRate(const std::string& file, TransferDirection direction) {
|
|
|
|
current_ledger_.ReportTransferRate(line_printer_, file, direction);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReportOverallTransferRate(TransferDirection direction) {
|
|
|
|
if (current_ledger_ != global_ledger_) {
|
|
|
|
global_ledger_.ReportTransferRate(line_printer_, "", direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-27 19:55:37 +00:00
|
|
|
bool SendRequest(int id, const char* path_and_mode) {
|
|
|
|
size_t path_length = strlen(path_and_mode);
|
|
|
|
if (path_length > 1024) {
|
2015-10-27 23:03:15 +00:00
|
|
|
Error("SendRequest failed: path too long: %zu", path_length);
|
2015-09-27 19:55:37 +00:00
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sending header and payload in a single write makes a noticeable
|
|
|
|
// difference to "adb sync" performance.
|
2015-10-27 20:40:35 +00:00
|
|
|
std::vector<char> buf(sizeof(SyncRequest) + path_length);
|
|
|
|
SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
|
2015-09-27 19:55:37 +00:00
|
|
|
req->id = id;
|
|
|
|
req->path_length = path_length;
|
|
|
|
char* data = reinterpret_cast<char*>(req + 1);
|
|
|
|
memcpy(data, path_and_mode, path_length);
|
|
|
|
|
2015-10-27 20:40:35 +00:00
|
|
|
return WriteFdExactly(fd, &buf[0], buf.size());
|
2015-09-27 19:55:37 +00:00
|
|
|
}
|
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
bool SendStat(const char* path_and_mode) {
|
|
|
|
if (!have_stat_v2_) {
|
|
|
|
errno = ENOTSUP;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return SendRequest(ID_STAT_V2, path_and_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SendLstat(const char* path_and_mode) {
|
|
|
|
if (have_stat_v2_) {
|
|
|
|
return SendRequest(ID_LSTAT_V2, path_and_mode);
|
|
|
|
} else {
|
|
|
|
return SendRequest(ID_LSTAT_V1, path_and_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FinishStat(struct stat* st) {
|
|
|
|
syncmsg msg;
|
|
|
|
|
|
|
|
memset(st, 0, sizeof(*st));
|
|
|
|
if (have_stat_v2_) {
|
|
|
|
if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
|
|
|
|
fatal_errno("protocol fault: failed to read stat response");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
|
|
|
|
fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
|
|
|
|
msg.stat_v2.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.stat_v2.error != 0) {
|
|
|
|
errno = errno_from_wire(msg.stat_v2.error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
st->st_dev = msg.stat_v2.dev;
|
|
|
|
st->st_ino = msg.stat_v2.ino;
|
|
|
|
st->st_mode = msg.stat_v2.mode;
|
|
|
|
st->st_nlink = msg.stat_v2.nlink;
|
|
|
|
st->st_uid = msg.stat_v2.uid;
|
|
|
|
st->st_gid = msg.stat_v2.gid;
|
|
|
|
st->st_size = msg.stat_v2.size;
|
|
|
|
st->st_atime = msg.stat_v2.atime;
|
|
|
|
st->st_mtime = msg.stat_v2.mtime;
|
|
|
|
st->st_ctime = msg.stat_v2.ctime;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
|
|
|
|
fatal_errno("protocol fault: failed to read stat response");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.stat_v1.id != ID_LSTAT_V1) {
|
|
|
|
fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
|
|
|
|
msg.stat_v1.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
|
|
|
|
// There's no way for us to know what the error was.
|
|
|
|
errno = ENOPROTOOPT;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
st->st_mode = msg.stat_v1.mode;
|
|
|
|
st->st_size = msg.stat_v1.size;
|
|
|
|
st->st_ctime = msg.stat_v1.time;
|
|
|
|
st->st_mtime = msg.stat_v1.time;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-27 19:55:37 +00:00
|
|
|
// Sending header, payload, and footer in a single write makes a huge
|
|
|
|
// difference to "adb sync" performance.
|
|
|
|
bool SendSmallFile(const char* path_and_mode,
|
2015-11-21 06:01:06 +00:00
|
|
|
const char* lpath, const char* rpath,
|
2015-11-21 01:35:17 +00:00
|
|
|
unsigned mtime,
|
|
|
|
const char* data, size_t data_length) {
|
2015-09-27 19:55:37 +00:00
|
|
|
size_t path_length = strlen(path_and_mode);
|
|
|
|
if (path_length > 1024) {
|
2015-10-27 23:03:15 +00:00
|
|
|
Error("SendSmallFile failed: path too long: %zu", path_length);
|
2015-09-27 19:55:37 +00:00
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-27 20:40:35 +00:00
|
|
|
std::vector<char> buf(sizeof(SyncRequest) + path_length +
|
2015-11-21 01:35:17 +00:00
|
|
|
sizeof(SyncRequest) + data_length +
|
|
|
|
sizeof(SyncRequest));
|
2015-10-27 20:40:35 +00:00
|
|
|
char* p = &buf[0];
|
2015-09-27 19:55:37 +00:00
|
|
|
|
|
|
|
SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
|
|
|
|
req_send->id = ID_SEND;
|
|
|
|
req_send->path_length = path_length;
|
|
|
|
p += sizeof(SyncRequest);
|
|
|
|
memcpy(p, path_and_mode, path_length);
|
|
|
|
p += path_length;
|
|
|
|
|
|
|
|
SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
|
|
|
|
req_data->id = ID_DATA;
|
|
|
|
req_data->path_length = data_length;
|
|
|
|
p += sizeof(SyncRequest);
|
|
|
|
memcpy(p, data, data_length);
|
|
|
|
p += data_length;
|
|
|
|
|
|
|
|
SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
|
|
|
|
req_done->id = ID_DONE;
|
|
|
|
req_done->path_length = mtime;
|
|
|
|
p += sizeof(SyncRequest);
|
|
|
|
|
2015-11-21 06:01:06 +00:00
|
|
|
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
|
2016-02-19 23:55:55 +00:00
|
|
|
expect_done_ = true;
|
2016-08-04 21:53:17 +00:00
|
|
|
|
|
|
|
// RecordFilesTransferred gets called in CopyDone.
|
|
|
|
RecordBytesTransferred(data_length);
|
2016-03-01 19:46:02 +00:00
|
|
|
ReportProgress(rpath, data_length, data_length);
|
2015-09-27 19:55:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-11-21 01:35:17 +00:00
|
|
|
bool SendLargeFile(const char* path_and_mode,
|
|
|
|
const char* lpath, const char* rpath,
|
|
|
|
unsigned mtime) {
|
|
|
|
if (!SendRequest(ID_SEND, path_and_mode)) {
|
|
|
|
Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
if (stat(lpath, &st) == -1) {
|
|
|
|
Error("cannot stat '%s': %s", lpath, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t total_size = st.st_size;
|
|
|
|
uint64_t bytes_copied = 0;
|
|
|
|
|
|
|
|
int lfd = adb_open(lpath, O_RDONLY);
|
|
|
|
if (lfd < 0) {
|
2015-11-21 06:01:06 +00:00
|
|
|
Error("opening '%s' locally failed: %s", lpath, strerror(errno));
|
2015-11-21 01:35:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
syncsendbuf sbuf;
|
|
|
|
sbuf.id = ID_DATA;
|
|
|
|
while (true) {
|
2017-07-18 21:07:57 +00:00
|
|
|
int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
|
2015-11-21 06:01:06 +00:00
|
|
|
if (bytes_read == -1) {
|
|
|
|
Error("reading '%s' locally failed: %s", lpath, strerror(errno));
|
2015-11-21 01:35:17 +00:00
|
|
|
adb_close(lfd);
|
|
|
|
return false;
|
2015-11-21 06:01:06 +00:00
|
|
|
} else if (bytes_read == 0) {
|
|
|
|
break;
|
2015-11-21 01:35:17 +00:00
|
|
|
}
|
|
|
|
|
2015-11-21 06:01:06 +00:00
|
|
|
sbuf.size = bytes_read;
|
|
|
|
WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
RecordBytesTransferred(bytes_read);
|
2015-11-21 06:01:06 +00:00
|
|
|
bytes_copied += bytes_read;
|
2015-11-21 01:35:17 +00:00
|
|
|
|
2016-02-19 23:55:55 +00:00
|
|
|
// Check to see if we've received an error from the other side.
|
|
|
|
if (ReceivedError(lpath, rpath)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
ReportProgress(rpath, bytes_copied, total_size);
|
2015-11-21 01:35:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
adb_close(lfd);
|
|
|
|
|
|
|
|
syncmsg msg;
|
|
|
|
msg.data.id = ID_DONE;
|
|
|
|
msg.data.size = mtime;
|
2016-02-19 23:55:55 +00:00
|
|
|
expect_done_ = true;
|
2016-08-04 21:53:17 +00:00
|
|
|
|
|
|
|
// RecordFilesTransferred gets called in CopyDone.
|
2015-11-21 06:01:06 +00:00
|
|
|
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
|
2015-11-21 01:35:17 +00:00
|
|
|
}
|
|
|
|
|
2015-09-27 19:55:37 +00:00
|
|
|
bool CopyDone(const char* from, const char* to) {
|
|
|
|
syncmsg msg;
|
|
|
|
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
|
2016-02-19 23:55:55 +00:00
|
|
|
Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (msg.status.id == ID_OKAY) {
|
2016-02-19 23:55:55 +00:00
|
|
|
if (expect_done_) {
|
|
|
|
expect_done_ = false;
|
2016-08-04 21:53:17 +00:00
|
|
|
RecordFilesTransferred(1);
|
2016-02-19 23:55:55 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
Error("failed to copy '%s' to '%s': received premature success", from, to);
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-27 19:55:37 +00:00
|
|
|
}
|
|
|
|
if (msg.status.id != ID_FAIL) {
|
2015-10-27 23:03:15 +00:00
|
|
|
Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-10-24 04:06:11 +00:00
|
|
|
return ReportCopyFailure(from, to, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
|
2015-10-27 20:40:35 +00:00
|
|
|
std::vector<char> buf(msg.status.msglen + 1);
|
|
|
|
if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
|
2015-10-27 23:03:15 +00:00
|
|
|
Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
|
|
|
|
from, to, strerror(errno));
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-10-27 20:40:35 +00:00
|
|
|
buf[msg.status.msglen] = 0;
|
2016-12-06 01:11:34 +00:00
|
|
|
Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-27 23:03:15 +00:00
|
|
|
|
2015-11-03 01:15:57 +00:00
|
|
|
void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
|
|
|
|
std::string s;
|
2015-12-18 01:05:29 +00:00
|
|
|
|
2015-11-03 01:15:57 +00:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
android::base::StringAppendV(&s, fmt, ap);
|
|
|
|
va_end(ap);
|
2015-10-27 23:03:15 +00:00
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
line_printer_.Print(s, LinePrinter::INFO);
|
2015-10-27 23:03:15 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 18:43:00 +00:00
|
|
|
void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
|
2015-11-03 01:15:57 +00:00
|
|
|
std::string s;
|
2015-12-18 01:05:29 +00:00
|
|
|
|
2015-11-03 01:15:57 +00:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
android::base::StringAppendV(&s, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
line_printer_.Print(s, LinePrinter::INFO);
|
2016-08-04 18:43:00 +00:00
|
|
|
line_printer_.KeepInfoLine();
|
2015-11-03 01:15:57 +00:00
|
|
|
}
|
|
|
|
|
2015-10-27 23:03:15 +00:00
|
|
|
void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
|
|
|
|
std::string s = "adb: error: ";
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
android::base::StringAppendV(&s, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2015-12-09 00:01:15 +00:00
|
|
|
line_printer_.Print(s, LinePrinter::ERROR);
|
2015-10-27 23:03:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-08 01:18:44 +00:00
|
|
|
void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
|
|
|
|
std::string s = "adb: warning: ";
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
android::base::StringAppendV(&s, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2015-12-09 00:01:15 +00:00
|
|
|
line_printer_.Print(s, LinePrinter::WARNING);
|
2015-11-08 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
|
2016-08-04 21:53:17 +00:00
|
|
|
current_ledger_.bytes_expected = 0;
|
2015-12-18 01:05:29 +00:00
|
|
|
for (const copyinfo& ci : file_list) {
|
|
|
|
// Unfortunately, this doesn't work for symbolic links, because we'll copy the
|
|
|
|
// target of the link rather than just creating a link. (But ci.size is the link size.)
|
2016-08-04 21:53:17 +00:00
|
|
|
if (!ci.skip) current_ledger_.bytes_expected += ci.size;
|
2015-12-18 01:05:29 +00:00
|
|
|
}
|
2016-08-04 21:53:17 +00:00
|
|
|
current_ledger_.expect_multiple_files = true;
|
2015-12-18 01:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
|
2016-08-04 21:53:17 +00:00
|
|
|
current_ledger_.bytes_expected = expected_total_bytes;
|
|
|
|
current_ledger_.expect_multiple_files = false;
|
2015-12-18 01:05:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// TODO: add a char[max] buffer here, to replace syncsendbuf...
|
|
|
|
int fd;
|
|
|
|
size_t max;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
private:
|
2016-02-19 23:55:55 +00:00
|
|
|
bool expect_done_;
|
2016-12-06 01:11:34 +00:00
|
|
|
bool have_stat_v2_;
|
2015-12-18 01:05:29 +00:00
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
TransferLedger global_ledger_;
|
|
|
|
TransferLedger current_ledger_;
|
2015-10-27 23:03:15 +00:00
|
|
|
LinePrinter line_printer_;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
adb: fix adb client running out of sockets on Windows
Background
==========
On Windows, if you run "adb shell exit" in a loop in two windows,
eventually the adb client will be unable to connect to the adb server. I
think connect() is returning WSAEADDRINUSE: "Only one usage of each
socket address (protocol/network address/port) is normally permitted.
(10048)". The Windows System Event Log may also show Event 4227, Tcpip.
Netstat output is filled with:
# for the adb server
TCP 127.0.0.1:5037 127.0.0.1:65523 TIME_WAIT
# for the adb client
TCP 127.0.0.1:65523 127.0.0.1:5037 TIME_WAIT
The error probably means that the client is running out of free
address:port pairs.
The first netstat line is unavoidable, but the second line exists
because the adb client is not waiting for orderly/graceful shutdown of
the socket, and that is apparently required on Windows to get rid of the
second line. For more info, see
https://github.com/CompareAndSwap/SocketCloseTest .
This is exacerbated by the fact that "adb shell exit" makes 4 socket
connections to the adb server: 1) host:version, 2) host:features, 3)
host:version (again), 4) shell:exit. Also exacerbating is the fact that
the adb protocol is length-prefixed so the client typically does not
have to 'read() until zero' which effectively waits for orderly/graceful
shutdown.
The Fix
=======
Introduce a function, ReadOrderlyShutdown(), that should be called in
the adb client to wait for the server to close its socket, before
closing the client socket.
I reviewed all code where the adb client makes a connection to the adb
server and added ReadOrderlyShutdown() when it made sense. I wasn't able
to add it to the following:
* interactive_shell: this doesn't matter because this is interactive and
thus can't be run fast enough to use up ports.
* adb sideload: I couldn't get enough test coverage and I don't think
this is being called frequently enough to be a problem.
* send_shell_command, backup, adb_connect_command, adb shell, adb
exec-out, install_multiple_app, adb_send_emulator_command: These
already wait for server socket shutdown since they already call
recv() until zero.
* restore, adb exec-in: protocol design can't have the server close
first.
* adb start-server: no fd is actually returned
* create_local_service_socket, local_connect_arbitrary_ports,
connect_device: probably called rarely enough not to be a problem.
Also in this change
===================
* Clarify comments in when adb_shutdown() is called before exit().
* add some missing adb_close() in adb sideload.
* Fixup error handling and comments in adb_send_emulator_command().
* Make SyncConnection::SendQuit return a success boolean.
* Add unittest for adb emu kill command. This gets code coverage over
this very careful piece of code.
Change-Id: Iad0b1336f5b74186af2cd35f7ea827d0fa77a17c
Signed-off-by: Spencer Low <CompareAndSwap@gmail.com>
2015-10-15 00:32:44 +00:00
|
|
|
bool SendQuit() {
|
|
|
|
return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-21 06:01:06 +00:00
|
|
|
bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
|
|
|
|
if (!WriteFdExactly(fd, data, data_length)) {
|
|
|
|
if (errno == ECONNRESET) {
|
|
|
|
// Assume adbd told us why it was closing the connection, and
|
|
|
|
// try to read failure reason from adbd.
|
|
|
|
syncmsg msg;
|
|
|
|
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
|
|
|
|
Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
|
|
|
|
} else if (msg.status.id != ID_FAIL) {
|
|
|
|
Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
|
|
|
|
} else {
|
|
|
|
ReportCopyFailure(from, to, msg);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Error("%zu-byte write failed: %s", data_length, strerror(errno));
|
|
|
|
}
|
|
|
|
_exit(1);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
};
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-11-03 00:45:47 +00:00
|
|
|
typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-11-03 00:45:47 +00:00
|
|
|
static bool sync_ls(SyncConnection& sc, const char* path,
|
2016-07-27 23:25:51 +00:00
|
|
|
const std::function<sync_ls_cb>& func) {
|
2015-09-27 19:55:37 +00:00
|
|
|
if (!sc.SendRequest(ID_LIST, path)) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
while (true) {
|
|
|
|
syncmsg msg;
|
2015-09-27 19:55:37 +00:00
|
|
|
if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
if (msg.dent.id == ID_DONE) return true;
|
|
|
|
if (msg.dent.id != ID_DENT) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-24 21:27:03 +00:00
|
|
|
size_t len = msg.dent.namelen;
|
2015-08-03 17:38:08 +00:00
|
|
|
if (len > 256) return false; // TODO: resize buffer? continue?
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
char buf[257];
|
2015-09-27 19:55:37 +00:00
|
|
|
if (!ReadFdExactly(sc.fd, buf, len)) return false;
|
2015-08-03 17:38:08 +00:00
|
|
|
buf[len] = 0;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-11-03 00:45:47 +00:00
|
|
|
func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
|
2015-08-03 17:38:08 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
|
|
|
|
return sc.SendStat(path) && sc.FinishStat(st);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
|
|
|
|
return sc.SendLstat(path) && sc.FinishStat(st);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
|
|
|
|
if (sync_stat(sc, path, st)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errno != ENOTSUP) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
// Try to emulate the parts we can when talking to older adbds.
|
|
|
|
bool lstat_result = sync_lstat(sc, path, st);
|
|
|
|
if (!lstat_result) {
|
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
if (S_ISLNK(st->st_mode)) {
|
|
|
|
// If the target is a symlink, figure out whether it's a file or a directory.
|
|
|
|
// Also, zero out the st_size field, since no one actually cares what the path length is.
|
|
|
|
st->st_size = 0;
|
|
|
|
std::string dir_path = path;
|
|
|
|
dir_path.push_back('/');
|
|
|
|
struct stat tmp_st;
|
|
|
|
|
|
|
|
st->st_mode &= ~S_IFMT;
|
|
|
|
if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
|
|
|
|
st->st_mode |= S_IFDIR;
|
|
|
|
} else {
|
|
|
|
st->st_mode |= S_IFREG;
|
|
|
|
}
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2017-05-19 05:56:48 +00:00
|
|
|
static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
|
|
|
|
mode_t mode, bool sync) {
|
2015-08-03 17:38:08 +00:00
|
|
|
std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2017-05-19 05:56:48 +00:00
|
|
|
if (sync) {
|
|
|
|
struct stat st;
|
|
|
|
if (sync_lstat(sc, rpath, &st)) {
|
|
|
|
// For links, we cannot update the atime/mtime.
|
|
|
|
if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast<time_t>(mtime)) ||
|
|
|
|
(S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast<time_t>(mtime))) {
|
|
|
|
sc.RecordFilesSkipped(1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-27 19:55:37 +00:00
|
|
|
if (S_ISLNK(mode)) {
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
|
|
|
|
if (data_length == -1) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
buf[data_length++] = '\0';
|
|
|
|
|
2015-11-21 06:01:06 +00:00
|
|
|
if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-27 19:55:37 +00:00
|
|
|
return sc.CopyDone(lpath, rpath);
|
|
|
|
#endif
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-09-27 19:55:37 +00:00
|
|
|
struct stat st;
|
|
|
|
if (stat(lpath, &st) == -1) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
|
2015-09-03 18:06:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-09-27 19:55:37 +00:00
|
|
|
if (st.st_size < SYNC_DATA_MAX) {
|
|
|
|
std::string data;
|
2016-09-14 23:13:50 +00:00
|
|
|
if (!android::base::ReadFileToString(lpath, &data, true)) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
2015-11-21 06:01:06 +00:00
|
|
|
if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
|
|
|
|
data.data(), data.size())) {
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2015-08-03 17:38:08 +00:00
|
|
|
}
|
2015-09-27 19:55:37 +00:00
|
|
|
} else {
|
2015-11-21 01:35:17 +00:00
|
|
|
if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
|
2015-10-27 23:03:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
2015-09-27 19:55:37 +00:00
|
|
|
return sc.CopyDone(lpath, rpath);
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-02 00:43:27 +00:00
|
|
|
static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
|
2016-12-06 22:07:53 +00:00
|
|
|
const char* name, uint64_t expected_size) {
|
2015-09-27 19:55:37 +00:00
|
|
|
if (!sc.SendRequest(ID_RECV, rpath)) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-10-24 04:06:11 +00:00
|
|
|
adb_unlink(lpath);
|
|
|
|
int lfd = adb_creat(lpath, 0644);
|
|
|
|
if (lfd < 0) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("cannot create '%s': %s", lpath, strerror(errno));
|
2015-10-24 04:06:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-10-27 23:03:15 +00:00
|
|
|
uint64_t bytes_copied = 0;
|
2015-10-24 04:06:11 +00:00
|
|
|
while (true) {
|
|
|
|
syncmsg msg;
|
|
|
|
if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
|
|
|
|
adb_close(lfd);
|
|
|
|
adb_unlink(lpath);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-24 04:06:11 +00:00
|
|
|
if (msg.data.id == ID_DONE) break;
|
2015-09-27 19:55:37 +00:00
|
|
|
|
2015-10-24 04:06:11 +00:00
|
|
|
if (msg.data.id != ID_DATA) {
|
2015-08-28 08:07:30 +00:00
|
|
|
adb_close(lfd);
|
2015-10-24 04:06:11 +00:00
|
|
|
adb_unlink(lpath);
|
|
|
|
sc.ReportCopyFailure(rpath, lpath, msg);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
2015-10-24 04:06:11 +00:00
|
|
|
|
|
|
|
if (msg.data.size > sc.max) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
|
2009-03-04 03:32:55 +00:00
|
|
|
adb_close(lfd);
|
2015-10-24 04:06:11 +00:00
|
|
|
adb_unlink(lpath);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-24 04:06:11 +00:00
|
|
|
char buffer[SYNC_DATA_MAX];
|
|
|
|
if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
|
2009-03-04 03:32:55 +00:00
|
|
|
adb_close(lfd);
|
2015-10-24 04:06:11 +00:00
|
|
|
adb_unlink(lpath);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-24 04:06:11 +00:00
|
|
|
if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
|
2015-10-27 23:03:15 +00:00
|
|
|
sc.Error("cannot write '%s': %s", lpath, strerror(errno));
|
2009-03-04 03:32:55 +00:00
|
|
|
adb_close(lfd);
|
2015-10-24 04:06:11 +00:00
|
|
|
adb_unlink(lpath);
|
2015-09-27 19:55:37 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-27 23:03:15 +00:00
|
|
|
bytes_copied += msg.data.size;
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.RecordBytesTransferred(msg.data.size);
|
2016-12-06 22:07:53 +00:00
|
|
|
sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.RecordFilesTransferred(1);
|
2009-03-04 03:32:55 +00:00
|
|
|
adb_close(lfd);
|
2015-09-27 19:55:37 +00:00
|
|
|
return true;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
bool do_sync_ls(const char* path) {
|
|
|
|
SyncConnection sc;
|
|
|
|
if (!sc.IsValid()) return false;
|
2015-07-31 00:42:01 +00:00
|
|
|
|
2015-11-03 00:45:47 +00:00
|
|
|
return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
|
|
|
|
const char* name) {
|
|
|
|
printf("%08x %08x %08x %s\n", mode, size, time, name);
|
|
|
|
});
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
static bool IsDotOrDotDot(const char* name) {
|
|
|
|
return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
|
2015-11-03 23:26:38 +00:00
|
|
|
const std::string& lpath,
|
|
|
|
const std::string& rpath) {
|
2015-11-03 00:45:47 +00:00
|
|
|
std::vector<copyinfo> dirlist;
|
2015-11-03 23:23:03 +00:00
|
|
|
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
|
2015-08-03 17:38:08 +00:00
|
|
|
if (!dir) {
|
2015-11-03 23:23:03 +00:00
|
|
|
sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
|
2015-11-03 23:26:38 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 22:57:04 +00:00
|
|
|
bool empty_dir = true;
|
2015-10-27 23:03:15 +00:00
|
|
|
dirent* de;
|
2015-08-03 17:38:08 +00:00
|
|
|
while ((de = readdir(dir.get()))) {
|
2015-11-04 22:57:04 +00:00
|
|
|
if (IsDotOrDotDot(de->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-11-04 22:57:04 +00:00
|
|
|
empty_dir = false;
|
2015-11-03 23:23:03 +00:00
|
|
|
std::string stat_path = lpath + de->d_name;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
struct stat st;
|
2015-11-07 23:27:26 +00:00
|
|
|
if (lstat(stat_path.c_str(), &st) == -1) {
|
2015-11-03 23:23:03 +00:00
|
|
|
sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
|
|
|
|
strerror(errno));
|
2015-11-07 23:27:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-09 22:03:30 +00:00
|
|
|
copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
|
2015-11-07 23:27:26 +00:00
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
dirlist.push_back(ci);
|
|
|
|
} else {
|
2016-03-03 00:11:13 +00:00
|
|
|
if (!should_push_file(st.st_mode)) {
|
|
|
|
sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
|
2015-11-30 18:21:25 +00:00
|
|
|
ci.skip = true;
|
2015-11-07 23:27:26 +00:00
|
|
|
}
|
2016-03-03 00:11:13 +00:00
|
|
|
ci.time = st.st_mtime;
|
|
|
|
ci.size = st.st_size;
|
2015-12-18 01:05:29 +00:00
|
|
|
file_list->push_back(ci);
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// Close this directory and recurse.
|
|
|
|
dir.reset();
|
2015-11-04 22:57:04 +00:00
|
|
|
|
|
|
|
// Add the current directory to the list if it was empty, to ensure that
|
|
|
|
// it gets created.
|
|
|
|
if (empty_dir) {
|
|
|
|
// TODO(b/25566053): Make pushing empty directories work.
|
|
|
|
// TODO(b/25457350): We don't preserve permissions on directories.
|
2015-11-08 01:18:44 +00:00
|
|
|
sc.Warning("skipping empty directory '%s'", lpath.c_str());
|
2017-02-24 05:23:05 +00:00
|
|
|
copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
|
|
|
|
android::base::Basename(lpath), S_IFDIR);
|
2015-11-04 22:57:04 +00:00
|
|
|
ci.skip = true;
|
2015-12-18 01:05:29 +00:00
|
|
|
file_list->push_back(ci);
|
2015-11-04 22:57:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-11-03 00:45:47 +00:00
|
|
|
for (const copyinfo& ci : dirlist) {
|
2015-12-18 01:05:29 +00:00
|
|
|
local_build_list(sc, file_list, ci.lpath, ci.rpath);
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-03 23:26:38 +00:00
|
|
|
return true;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-03 23:23:03 +00:00
|
|
|
static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
|
|
|
|
std::string rpath, bool check_timestamps,
|
|
|
|
bool list_only) {
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.NewTransfer();
|
|
|
|
|
2015-11-03 23:23:03 +00:00
|
|
|
// Make sure that both directory paths end in a slash.
|
2015-11-09 19:12:14 +00:00
|
|
|
// Both paths are known to be nonempty, so we don't need to check.
|
2015-12-18 01:05:29 +00:00
|
|
|
ensure_trailing_separators(lpath, rpath);
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-11-03 23:23:03 +00:00
|
|
|
// Recursively build the list of files to copy.
|
2015-12-18 01:05:29 +00:00
|
|
|
std::vector<copyinfo> file_list;
|
2015-11-03 23:23:03 +00:00
|
|
|
int skipped = 0;
|
2015-12-18 01:05:29 +00:00
|
|
|
if (!local_build_list(sc, &file_list, lpath, rpath)) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
if (check_timestamps) {
|
2015-12-18 01:05:29 +00:00
|
|
|
for (const copyinfo& ci : file_list) {
|
2016-12-06 01:11:34 +00:00
|
|
|
if (!sc.SendLstat(ci.rpath.c_str())) {
|
|
|
|
sc.Error("failed to send lstat");
|
2015-11-03 23:23:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
2015-12-18 01:05:29 +00:00
|
|
|
for (copyinfo& ci : file_list) {
|
2016-12-06 01:11:34 +00:00
|
|
|
struct stat st;
|
|
|
|
if (sc.FinishStat(&st)) {
|
|
|
|
if (st.st_size == static_cast<off_t>(ci.size)) {
|
|
|
|
// For links, we cannot update the atime/mtime.
|
|
|
|
if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) ||
|
|
|
|
(S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) {
|
|
|
|
ci.skip = true;
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-03 00:45:47 +00:00
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
sc.ComputeExpectedTotalBytes(file_list);
|
|
|
|
|
|
|
|
for (const copyinfo& ci : file_list) {
|
2015-11-03 22:44:04 +00:00
|
|
|
if (!ci.skip) {
|
2015-10-27 23:03:15 +00:00
|
|
|
if (list_only) {
|
2016-08-04 21:55:23 +00:00
|
|
|
sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
|
2015-10-27 23:03:15 +00:00
|
|
|
} else {
|
2017-05-19 05:56:48 +00:00
|
|
|
if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
|
2015-11-03 23:23:03 +00:00
|
|
|
return false;
|
2015-10-27 23:03:15 +00:00
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
skipped++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.RecordFilesSkipped(skipped);
|
|
|
|
sc.ReportTransferRate(lpath, TransferDirection::push);
|
2015-08-03 17:38:08 +00:00
|
|
|
return true;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2017-05-19 05:56:48 +00:00
|
|
|
bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) {
|
2015-08-03 17:38:08 +00:00
|
|
|
SyncConnection sc;
|
|
|
|
if (!sc.IsValid()) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
bool success = true;
|
2016-12-06 01:11:34 +00:00
|
|
|
bool dst_exists;
|
|
|
|
bool dst_isdir;
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
if (sync_stat_fallback(sc, dst, &st)) {
|
|
|
|
dst_exists = true;
|
|
|
|
dst_isdir = S_ISDIR(st.st_mode);
|
|
|
|
} else {
|
|
|
|
if (errno == ENOENT || errno == ENOPROTOOPT) {
|
|
|
|
dst_exists = false;
|
|
|
|
dst_isdir = false;
|
|
|
|
} else {
|
|
|
|
sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-10-30 23:57:19 +00:00
|
|
|
|
2015-11-07 23:38:19 +00:00
|
|
|
if (!dst_isdir) {
|
2015-10-30 23:57:19 +00:00
|
|
|
if (srcs.size() > 1) {
|
|
|
|
sc.Error("target '%s' is not a directory", dst);
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
size_t dst_len = strlen(dst);
|
2015-11-07 23:27:26 +00:00
|
|
|
|
|
|
|
// A path that ends with a slash doesn't have to be a directory if
|
|
|
|
// it doesn't exist yet.
|
|
|
|
if (dst[dst_len - 1] == '/' && dst_exists) {
|
2015-10-30 23:57:19 +00:00
|
|
|
sc.Error("failed to access '%s': Not a directory", dst);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
for (const char* src_path : srcs) {
|
|
|
|
const char* dst_path = dst;
|
|
|
|
struct stat st;
|
2015-11-07 23:27:26 +00:00
|
|
|
if (stat(src_path, &st) == -1) {
|
2015-10-30 23:57:19 +00:00
|
|
|
sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
|
|
|
|
success = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
2015-11-07 23:38:19 +00:00
|
|
|
std::string dst_dir = dst;
|
|
|
|
|
|
|
|
// If the destination path existed originally, the source directory
|
|
|
|
// should be copied as a child of the destination.
|
|
|
|
if (dst_exists) {
|
|
|
|
if (!dst_isdir) {
|
|
|
|
sc.Error("target '%s' is not a directory", dst);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// dst is a POSIX path, so we don't want to use the sysdeps
|
|
|
|
// helpers here.
|
|
|
|
if (dst_dir.back() != '/') {
|
|
|
|
dst_dir.push_back('/');
|
|
|
|
}
|
2017-02-24 05:23:05 +00:00
|
|
|
dst_dir.append(android::base::Basename(src_path));
|
2015-11-07 23:38:19 +00:00
|
|
|
}
|
|
|
|
|
2017-05-19 05:56:48 +00:00
|
|
|
success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false);
|
2015-10-30 23:57:19 +00:00
|
|
|
continue;
|
2016-03-03 00:11:13 +00:00
|
|
|
} else if (!should_push_file(st.st_mode)) {
|
|
|
|
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
|
|
|
|
continue;
|
2015-10-30 23:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string path_holder;
|
2015-11-07 23:38:19 +00:00
|
|
|
if (dst_isdir) {
|
2015-10-30 23:57:19 +00:00
|
|
|
// If we're copying a local file to a remote directory,
|
|
|
|
// we really want to copy to remote_dir + "/" + local_filename.
|
2016-02-03 22:55:24 +00:00
|
|
|
path_holder = dst_path;
|
|
|
|
if (path_holder.back() != '/') {
|
|
|
|
path_holder.push_back('/');
|
|
|
|
}
|
2017-02-24 05:23:05 +00:00
|
|
|
path_holder += android::base::Basename(src_path);
|
2015-10-30 23:57:19 +00:00
|
|
|
dst_path = path_holder.c_str();
|
|
|
|
}
|
2016-08-04 21:53:17 +00:00
|
|
|
|
|
|
|
sc.NewTransfer();
|
2015-12-18 01:05:29 +00:00
|
|
|
sc.SetExpectedTotalBytes(st.st_size);
|
2017-05-19 05:56:48 +00:00
|
|
|
success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync);
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.ReportTransferRate(src_path, TransferDirection::push);
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.ReportOverallTransferRate(TransferDirection::push);
|
2015-10-30 23:57:19 +00:00
|
|
|
return success;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2016-02-26 01:12:45 +00:00
|
|
|
static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
|
|
|
|
const std::string& rpath, const std::string& lpath) {
|
2015-11-03 00:45:47 +00:00
|
|
|
std::vector<copyinfo> dirlist;
|
2015-12-09 22:03:30 +00:00
|
|
|
std::vector<copyinfo> linklist;
|
2016-02-26 01:12:45 +00:00
|
|
|
|
|
|
|
// Add an entry for the current directory to ensure it gets created before pulling its contents.
|
2017-02-24 05:23:05 +00:00
|
|
|
copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
|
|
|
|
android::base::Basename(lpath), S_IFDIR);
|
2016-02-26 01:12:45 +00:00
|
|
|
file_list->push_back(ci);
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// Put the files/dirs in rpath on the lists.
|
2015-11-30 18:21:25 +00:00
|
|
|
auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
|
2015-11-04 22:57:04 +00:00
|
|
|
if (IsDotOrDotDot(name)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-09 22:03:30 +00:00
|
|
|
copyinfo ci(lpath, rpath, name, mode);
|
2015-11-04 22:57:04 +00:00
|
|
|
if (S_ISDIR(mode)) {
|
|
|
|
dirlist.push_back(ci);
|
2015-12-09 22:03:30 +00:00
|
|
|
} else if (S_ISLNK(mode)) {
|
|
|
|
linklist.push_back(ci);
|
2015-11-03 00:45:47 +00:00
|
|
|
} else {
|
2016-03-03 00:11:13 +00:00
|
|
|
if (!should_pull_file(ci.mode)) {
|
|
|
|
sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
|
|
|
|
ci.skip = true;
|
|
|
|
}
|
2015-12-09 22:03:30 +00:00
|
|
|
ci.time = time;
|
|
|
|
ci.size = size;
|
2015-12-18 01:05:29 +00:00
|
|
|
file_list->push_back(ci);
|
2015-11-03 00:45:47 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-11-03 23:23:03 +00:00
|
|
|
if (!sync_ls(sc, rpath.c_str(), callback)) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-12-09 22:03:30 +00:00
|
|
|
// Check each symlink we found to see whether it's a file or directory.
|
|
|
|
for (copyinfo& link_ci : linklist) {
|
2016-12-06 01:11:34 +00:00
|
|
|
struct stat st;
|
|
|
|
if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
|
|
|
|
sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
2015-12-09 22:03:30 +00:00
|
|
|
dirlist.emplace_back(std::move(link_ci));
|
|
|
|
} else {
|
2015-12-18 01:05:29 +00:00
|
|
|
file_list->emplace_back(std::move(link_ci));
|
2015-12-09 22:03:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// Recurse into each directory we found.
|
2015-11-03 00:45:47 +00:00
|
|
|
while (!dirlist.empty()) {
|
|
|
|
copyinfo current = dirlist.back();
|
|
|
|
dirlist.pop_back();
|
2015-12-18 01:05:29 +00:00
|
|
|
if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
return true;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 19:12:14 +00:00
|
|
|
static int set_time_and_mode(const std::string& lpath, time_t time,
|
|
|
|
unsigned int mode) {
|
2014-05-06 15:48:18 +00:00
|
|
|
struct utimbuf times = { time, time };
|
2015-11-09 19:12:14 +00:00
|
|
|
int r1 = utime(lpath.c_str(), ×);
|
2013-04-19 19:41:09 +00:00
|
|
|
|
|
|
|
/* use umask for permissions */
|
2015-11-03 00:45:47 +00:00
|
|
|
mode_t mask = umask(0000);
|
2013-04-19 19:41:09 +00:00
|
|
|
umask(mask);
|
2015-11-09 19:12:14 +00:00
|
|
|
int r2 = chmod(lpath.c_str(), mode & ~mask);
|
2013-04-19 19:41:09 +00:00
|
|
|
|
2015-11-08 02:51:54 +00:00
|
|
|
return r1 ? r1 : r2;
|
2013-04-19 19:41:09 +00:00
|
|
|
}
|
|
|
|
|
2015-11-03 23:23:03 +00:00
|
|
|
static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
|
|
|
|
std::string lpath, bool copy_attrs) {
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.NewTransfer();
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// Make sure that both directory paths end in a slash.
|
2015-11-07 23:27:26 +00:00
|
|
|
// Both paths are known to be nonempty, so we don't need to check.
|
2015-12-18 01:05:29 +00:00
|
|
|
ensure_trailing_separators(lpath, rpath);
|
2014-12-12 21:12:36 +00:00
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
// Recursively build the list of files to copy.
|
2015-12-18 01:05:29 +00:00
|
|
|
sc.Printf("pull: building file list...");
|
|
|
|
std::vector<copyinfo> file_list;
|
|
|
|
if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
|
2015-11-03 00:45:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-12-18 01:05:29 +00:00
|
|
|
sc.ComputeExpectedTotalBytes(file_list);
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
int skipped = 0;
|
2015-12-18 01:05:29 +00:00
|
|
|
for (const copyinfo &ci : file_list) {
|
2015-11-03 22:44:04 +00:00
|
|
|
if (!ci.skip) {
|
2015-11-04 22:57:04 +00:00
|
|
|
if (S_ISDIR(ci.mode)) {
|
|
|
|
// Entry is for an empty directory, create it and continue.
|
|
|
|
// TODO(b/25457350): We don't preserve permissions on directories.
|
2015-11-09 19:12:14 +00:00
|
|
|
if (!mkdirs(ci.lpath)) {
|
2015-11-04 22:57:04 +00:00
|
|
|
sc.Error("failed to create directory '%s': %s",
|
2015-11-09 19:12:14 +00:00
|
|
|
ci.lpath.c_str(), strerror(errno));
|
2015-11-04 22:57:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-06 22:07:53 +00:00
|
|
|
if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size)) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
2013-04-19 19:41:09 +00:00
|
|
|
|
2015-11-09 19:12:14 +00:00
|
|
|
if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2013-04-19 19:41:09 +00:00
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
} else {
|
|
|
|
skipped++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.RecordFilesSkipped(skipped);
|
|
|
|
sc.ReportTransferRate(rpath, TransferDirection::pull);
|
2015-08-03 17:38:08 +00:00
|
|
|
return true;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
|
2016-04-02 00:43:27 +00:00
|
|
|
bool copy_attrs, const char* name) {
|
2015-08-03 17:38:08 +00:00
|
|
|
SyncConnection sc;
|
|
|
|
if (!sc.IsValid()) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
bool success = true;
|
|
|
|
struct stat st;
|
2015-11-07 23:27:26 +00:00
|
|
|
bool dst_exists = true;
|
|
|
|
|
|
|
|
if (stat(dst, &st) == -1) {
|
|
|
|
dst_exists = false;
|
|
|
|
|
|
|
|
// If we're only pulling one path, the destination path might point to
|
2015-10-30 23:57:19 +00:00
|
|
|
// a path that doesn't exist yet.
|
2015-11-07 23:27:26 +00:00
|
|
|
if (srcs.size() == 1 && errno == ENOENT) {
|
|
|
|
// However, its parent must exist.
|
|
|
|
struct stat parent_st;
|
2017-02-24 05:23:05 +00:00
|
|
|
if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
|
2015-11-07 23:27:26 +00:00
|
|
|
sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sc.Error("failed to access '%s': %s", dst, strerror(errno));
|
2015-10-30 23:57:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-07 23:38:19 +00:00
|
|
|
bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
|
|
|
|
if (!dst_isdir) {
|
2015-10-30 23:57:19 +00:00
|
|
|
if (srcs.size() > 1) {
|
|
|
|
sc.Error("target '%s' is not a directory", dst);
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
} else {
|
2015-10-30 23:57:19 +00:00
|
|
|
size_t dst_len = strlen(dst);
|
2015-11-07 23:27:26 +00:00
|
|
|
|
|
|
|
// A path that ends with a slash doesn't have to be a directory if
|
|
|
|
// it doesn't exist yet.
|
2015-11-09 19:12:14 +00:00
|
|
|
if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
|
2015-10-30 23:57:19 +00:00
|
|
|
sc.Error("failed to access '%s': Not a directory", dst);
|
2015-08-03 17:38:08 +00:00
|
|
|
return false;
|
2015-07-31 00:42:01 +00:00
|
|
|
}
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-03 17:38:08 +00:00
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
for (const char* src_path : srcs) {
|
|
|
|
const char* dst_path = dst;
|
2016-12-06 01:11:34 +00:00
|
|
|
struct stat src_st;
|
|
|
|
if (!sync_stat_fallback(sc, src_path, &src_st)) {
|
|
|
|
if (errno == ENOPROTOOPT) {
|
|
|
|
sc.Error("remote object '%s' does not exist", src_path);
|
|
|
|
} else {
|
|
|
|
sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno));
|
|
|
|
}
|
|
|
|
|
2015-10-30 23:57:19 +00:00
|
|
|
success = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
bool src_isdir = S_ISDIR(src_st.st_mode);
|
2015-12-09 22:03:30 +00:00
|
|
|
if (src_isdir) {
|
2015-11-07 23:38:19 +00:00
|
|
|
std::string dst_dir = dst;
|
|
|
|
|
|
|
|
// If the destination path existed originally, the source directory
|
|
|
|
// should be copied as a child of the destination.
|
|
|
|
if (dst_exists) {
|
|
|
|
if (!dst_isdir) {
|
|
|
|
sc.Error("target '%s' is not a directory", dst);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!adb_is_separator(dst_dir.back())) {
|
|
|
|
dst_dir.push_back(OS_PATH_SEPARATOR);
|
|
|
|
}
|
2017-02-24 05:23:05 +00:00
|
|
|
dst_dir.append(android::base::Basename(src_path));
|
2015-11-07 23:38:19 +00:00
|
|
|
}
|
|
|
|
|
2015-12-09 22:03:30 +00:00
|
|
|
success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
|
2015-10-30 23:57:19 +00:00
|
|
|
continue;
|
2016-12-06 01:11:34 +00:00
|
|
|
} else if (!should_pull_file(src_st.st_mode)) {
|
|
|
|
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
|
2016-03-03 00:11:13 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-12-09 22:03:30 +00:00
|
|
|
|
2016-03-03 00:11:13 +00:00
|
|
|
std::string path_holder;
|
|
|
|
if (dst_isdir) {
|
|
|
|
// If we're copying a remote file to a local directory, we
|
|
|
|
// really want to copy to local_dir + OS_PATH_SEPARATOR +
|
|
|
|
// basename(remote).
|
|
|
|
path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
|
2017-02-24 05:23:05 +00:00
|
|
|
android::base::Basename(src_path).c_str());
|
2016-03-03 00:11:13 +00:00
|
|
|
dst_path = path_holder.c_str();
|
|
|
|
}
|
2015-12-09 22:03:30 +00:00
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.NewTransfer();
|
2016-12-06 01:11:34 +00:00
|
|
|
sc.SetExpectedTotalBytes(src_st.st_size);
|
2016-12-06 22:07:53 +00:00
|
|
|
if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size)) {
|
2016-03-03 00:11:13 +00:00
|
|
|
success = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-06 01:11:34 +00:00
|
|
|
if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) {
|
2016-03-03 00:11:13 +00:00
|
|
|
success = false;
|
|
|
|
continue;
|
2015-10-30 23:57:19 +00:00
|
|
|
}
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.ReportTransferRate(src_path, TransferDirection::pull);
|
2015-10-30 23:57:19 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
sc.ReportOverallTransferRate(TransferDirection::pull);
|
2015-10-30 23:57:19 +00:00
|
|
|
return success;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 17:38:08 +00:00
|
|
|
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
|
|
|
|
SyncConnection sc;
|
|
|
|
if (!sc.IsValid()) return false;
|
2009-03-04 03:32:55 +00:00
|
|
|
|
2016-08-04 21:53:17 +00:00
|
|
|
bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
|
|
|
|
if (!list_only) {
|
|
|
|
sc.ReportOverallTransferRate(TransferDirection::push);
|
|
|
|
}
|
|
|
|
return success;
|
2009-03-04 03:32:55 +00:00
|
|
|
}
|