diff options
author | Josh Gao <jmgao@google.com> | 2015-11-07 15:38:19 -0800 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2015-11-11 14:01:45 -0800 |
commit | 07db1196e7bd5856b5e2ebe4ea6791d2ae8c9e76 (patch) | |
tree | 5dc4d77d44aa55feec1f5492b435dd4a06dfe77f /adb/file_sync_client.cpp | |
parent | 12a2ae9a0c21edaf8e80984519108631bdf3c9e6 (diff) |
adb: don't explode directories when pushing/pulling.
Previously, `adb pull /data/local/tmp` would spew all of the contents of
/data/local/tmp into the current directory. This patch makes push/pull
keep directories intact.
Bug: http://b/25394682
Change-Id: I2304ae9e61745a2b9536f58a6012640bf8ff422a
Diffstat (limited to 'adb/file_sync_client.cpp')
-rw-r--r-- | adb/file_sync_client.cpp | 62 |
1 files changed, 47 insertions, 15 deletions
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp index 90bf456561..736411cc68 100644 --- a/adb/file_sync_client.cpp +++ b/adb/file_sync_client.cpp @@ -657,8 +657,9 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { unsigned dst_mode; if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false; bool dst_exists = (dst_mode != 0); + bool dst_isdir = S_ISDIR(dst_mode); - if (!S_ISDIR(dst_mode)) { + if (!dst_isdir) { if (srcs.size() > 1) { sc.Error("target '%s' is not a directory", dst); return false; @@ -684,12 +685,30 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { } if (S_ISDIR(st.st_mode)) { - success &= copy_local_dir_remote(sc, src_path, dst, false, false); + 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('/'); + } + dst_dir.append(adb_basename(src_path)); + } + + success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), + false, false); continue; } std::string path_holder; - if (S_ISDIR(dst_mode)) { + if (dst_isdir) { // If we're copying a local file to a remote directory, // we really want to copy to remote_dir + "/" + local_filename. path_holder = android::base::StringPrintf( @@ -859,7 +878,8 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, } } - if (dst_exists && !S_ISDIR(st.st_mode)) { + bool dst_isdir = dst_exists && S_ISDIR(st.st_mode); + if (!dst_isdir) { if (srcs.size() > 1) { sc.Error("target '%s' is not a directory", dst); return false; @@ -890,16 +910,12 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, if (S_ISREG(src_mode) || S_ISLNK(src_mode)) { // TODO(b/25601283): symlinks shouldn't be handled as files. std::string path_holder; - struct stat st; - if (stat(dst_path, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - // If we're copying a remote file to a local directory, - // we really want to copy to local_dir + "/" + - // basename(remote). - path_holder = android::base::StringPrintf( - "%s/%s", dst_path, adb_basename(src_path).c_str()); - dst_path = path_holder.c_str(); - } + if (dst_isdir) { + // If we're copying a remote file to a local directory, we + // really want to copy to local_dir + "/" + basename(remote). + path_holder = android::base::StringPrintf( + "%s/%s", dst_path, adb_basename(src_path).c_str()); + dst_path = path_holder.c_str(); } if (!sync_recv(sc, src_path, dst_path)) { success = false; @@ -912,7 +928,23 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, } } } else if (S_ISDIR(src_mode)) { - success &= copy_remote_dir_local(sc, src_path, dst_path, copy_attrs); + 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); + } + dst_dir.append(adb_basename(src_path)); + } + + success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), + copy_attrs); continue; } else { sc.Error("remote object '%s' not a file or directory", src_path); |