Move adb_dirname and adb_basename to libbase

adb already provides an implementation of dirname and basename that
take and produce std::strings, move it into libbase so it can be
used in the implementation of GetExecutableDirectory.

Test: out/host/linux-x86/nativetest64/adb_test/adb_test
Test: out/host/linux-x86/nativetest64/libbase_test/libbase_test
Test: adb shell /data/nativetest64/libbase_test/libbase_test64
Change-Id: Ideb1627607b14562121316d4ed27fa6fb0930684
This commit is contained in:
Colin Cross 2017-02-23 21:23:05 -08:00
parent 0cde0eae09
commit 58021d15c9
10 changed files with 90 additions and 79 deletions

View file

@ -19,16 +19,15 @@
#include "adb_utils.h"
#include "adb_unique_fd.h"
#include <libgen.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <mutex>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
@ -100,52 +99,6 @@ std::string escape_arg(const std::string& s) {
return result;
}
std::string adb_basename(const std::string& path) {
static std::mutex& basename_lock = *new std::mutex();
// Copy path because basename may modify the string passed in.
std::string result(path);
// Use lock because basename() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
// callers to basename in the process also grab this same lock.
std::lock_guard<std::mutex> lock(basename_lock);
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
// the storage for 'path'.
char* name = basename(&result[0]);
// In case dirname returned a pointer to a process global, copy that string
// before leaving the lock.
result.assign(name);
return result;
}
std::string adb_dirname(const std::string& path) {
static std::mutex& dirname_lock = *new std::mutex();
// Copy path because dirname may modify the string passed in.
std::string result(path);
// Use lock because dirname() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
// callers to dirname in the process also grab this same lock.
std::lock_guard<std::mutex> lock(dirname_lock);
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
// the storage for 'path'.
char* parent = dirname(&result[0]);
// In case dirname returned a pointer to a process global, copy that string
// before leaving the lock.
result.assign(parent);
return result;
}
// Given a relative or absolute filepath, create the directory hierarchy
// as needed. Returns true if the hierarchy is/was setup.
bool mkdirs(const std::string& path) {
@ -171,7 +124,7 @@ bool mkdirs(const std::string& path) {
return true;
}
const std::string parent(adb_dirname(path));
const std::string parent(android::base::Dirname(path));
// If dirname returned the same path as what we passed in, don't go recursive.
// This can happen on Windows when walking up the directory hierarchy and not

View file

@ -28,11 +28,6 @@ void close_stdin();
bool getcwd(std::string* cwd);
bool directory_exists(const std::string& path);
// Like the regular basename and dirname, but thread-safe on all
// platforms and capable of correctly handling exotic Windows paths.
std::string adb_basename(const std::string& path);
std::string adb_dirname(const std::string& path);
// Return the user's home directory.
std::string adb_get_homedir_path();

View file

@ -109,18 +109,6 @@ TEST(adb_utils, escape_arg) {
ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
}
TEST(adb_utils, adb_basename) {
EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
EXPECT_EQ("sh", adb_basename("sh"));
EXPECT_EQ("sh", adb_basename("/system/bin/sh/"));
}
TEST(adb_utils, adb_dirname) {
EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh"));
EXPECT_EQ(".", adb_dirname("sh"));
EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
}
void test_mkdirs(const std::string& basepath) {
// Test creating a directory hierarchy.
ASSERT_TRUE(mkdirs(basepath));

View file

@ -21,6 +21,7 @@
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/strings.h>
#include "sysdeps.h"
@ -113,14 +114,14 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
private:
void SetLineMessage(const std::string& action) {
line_message_ = action + " " + adb_basename(dest_file_);
line_message_ = action + " " + android::base::Basename(dest_file_);
}
void SetSrcFile(const std::string path) {
src_file_ = path;
if (!dest_dir_.empty()) {
// Only uses device-provided name when user passed a directory.
dest_file_ = adb_basename(path);
dest_file_ = android::base::Basename(path);
SetLineMessage("generating");
}
}

View file

@ -2115,7 +2115,8 @@ static int install_multiple_app(TransportType transport, const char* serial, int
std::string cmd = android::base::StringPrintf(
"%s install-write -S %" PRIu64 " %d %d_%s -",
install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
@ -2233,7 +2234,7 @@ static int install_app_legacy(TransportType transport, const char* serial, int a
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
std::string apk_dest = android::base::StringPrintf(
where, adb_basename(argv[last_apk]).c_str());
where, android::base::Basename(argv[last_apk]).c_str());
if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
result = pm_command(transport, serial, argc, argv);

View file

@ -844,7 +844,8 @@ static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_lis
// TODO(b/25566053): Make pushing empty directories work.
// TODO(b/25457350): We don't preserve permissions on directories.
sc.Warning("skipping empty directory '%s'", lpath.c_str());
copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
android::base::Basename(lpath), S_IFDIR);
ci.skip = true;
file_list->push_back(ci);
return true;
@ -977,7 +978,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
if (dst_dir.back() != '/') {
dst_dir.push_back('/');
}
dst_dir.append(adb_basename(src_path));
dst_dir.append(android::base::Basename(src_path));
}
success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false);
@ -995,7 +996,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
if (path_holder.back() != '/') {
path_holder.push_back('/');
}
path_holder += adb_basename(src_path);
path_holder += android::base::Basename(src_path);
dst_path = path_holder.c_str();
}
@ -1015,7 +1016,8 @@ static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_li
std::vector<copyinfo> linklist;
// Add an entry for the current directory to ensure it gets created before pulling its contents.
copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
android::base::Basename(lpath), S_IFDIR);
file_list->push_back(ci);
// Put the files/dirs in rpath on the lists.
@ -1149,7 +1151,7 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
if (srcs.size() == 1 && errno == ENOENT) {
// However, its parent must exist.
struct stat parent_st;
if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
return false;
}
@ -1204,7 +1206,7 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
if (!adb_is_separator(dst_dir.back())) {
dst_dir.push_back(OS_PATH_SEPARATOR);
}
dst_dir.append(adb_basename(src_path));
dst_dir.append(android::base::Basename(src_path));
}
success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
@ -1220,7 +1222,7 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
// 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,
adb_basename(src_path).c_str());
android::base::Basename(src_path).c_str());
dst_path = path_holder.c_str();
}

View file

@ -31,6 +31,7 @@
#include <unistd.h>
#include <utime.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <private/android_filesystem_config.h>
@ -206,7 +207,7 @@ static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if (fd < 0 && errno == ENOENT) {
if (!secure_mkdirs(adb_dirname(path))) {
if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
goto fail;
}
@ -333,7 +334,7 @@ static bool handle_send_link(int s, const std::string& path, std::vector<char>&
ret = symlink(&buffer[0], path.c_str());
if (ret && errno == ENOENT) {
if (!secure_mkdirs(adb_dirname(path))) {
if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
return false;
}

View file

@ -18,11 +18,13 @@
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
@ -236,5 +238,56 @@ std::string GetExecutablePath() {
#endif
}
std::string Basename(const std::string& path) {
// Copy path because basename may modify the string passed in.
std::string result(path);
#if !defined(__BIONIC__)
// Use lock because basename() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
// callers to basename in the process also grab this same lock, but its
// better than nothing. Bionic's basename returns a thread-local buffer.
static std::mutex& basename_lock = *new std::mutex();
std::lock_guard<std::mutex> lock(basename_lock);
#endif
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
// the storage for 'path'.
char* name = basename(&result[0]);
// In case basename returned a pointer to a process global, copy that string
// before leaving the lock.
result.assign(name);
return result;
}
std::string Dirname(const std::string& path) {
// Copy path because dirname may modify the string passed in.
std::string result(path);
#if !defined(__BIONIC__)
// Use lock because dirname() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
// callers to dirname in the process also grab this same lock, but its
// better than nothing. Bionic's dirname returns a thread-local buffer.
static std::mutex& dirname_lock = *new std::mutex();
std::lock_guard<std::mutex> lock(dirname_lock);
#endif
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
// the storage for 'path'.
char* parent = dirname(&result[0]);
// In case dirname returned a pointer to a process global, copy that string
// before leaving the lock.
result.assign(parent);
return result;
}
} // namespace base
} // namespace android

View file

@ -162,3 +162,15 @@ TEST(file, Readlink) {
TEST(file, GetExecutablePath) {
ASSERT_NE("", android::base::GetExecutablePath());
}
TEST(file, Basename) {
EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
EXPECT_EQ("sh", android::base::Basename("sh"));
EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
}
TEST(file, Dirname) {
EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
EXPECT_EQ(".", android::base::Dirname("sh"));
EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
}

View file

@ -52,6 +52,11 @@ bool Readlink(const std::string& path, std::string* result);
std::string GetExecutablePath();
// Like the regular basename and dirname, but thread-safe on all
// platforms and capable of correctly handling exotic Windows paths.
std::string Basename(const std::string& path);
std::string Dirname(const std::string& path);
} // namespace base
} // namespace android