Account for folders in copy and move.
Copy and move will use mkdir() if target
is a folder, and copyFile() if target is a file.
Move will recursively copy contents if moving
between different storages. Move will also
change the storageId.
Bug: 67028892
Test: Copy and move folders on win 10
Change-Id: If114ef74b9d8668cf66d45953d9ea8b17bc11ae8
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 036ffe7..3f5648b 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -20,6 +20,7 @@
#include <android-base/unique_fd.h>
#include <dirent.h>
#include <fcntl.h>
+#include <string>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -29,6 +30,8 @@
#include "MtpUtils.h"
+using namespace std;
+
namespace android {
constexpr unsigned long FILE_COPY_SIZE = 262144;
@@ -88,6 +91,60 @@
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
+int makeFolder(const char *path) {
+ mode_t mask = umask(0);
+ int ret = mkdir((const char *)path, DIR_PERM);
+ umask(mask);
+ if (ret && ret != -EEXIST) {
+ PLOG(ERROR) << "Failed to create folder " << path;
+ ret = -1;
+ } else {
+ chown((const char *)path, getuid(), FILE_GROUP);
+ }
+ return ret;
+}
+
+/**
+ * Copies target path and all children to destination path.
+ *
+ * Returns 0 on success or a negative value indicating number of failures
+ */
+int copyRecursive(const char *fromPath, const char *toPath) {
+ int ret = 0;
+ string fromPathStr(fromPath);
+ string toPathStr(toPath);
+
+ DIR* dir = opendir(fromPath);
+ if (!dir) {
+ PLOG(ERROR) << "opendir " << fromPath << " failed";
+ return -1;
+ }
+ if (fromPathStr[fromPathStr.size()-1] != '/')
+ fromPathStr += '/';
+ if (toPathStr[toPathStr.size()-1] != '/')
+ toPathStr += '/';
+
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+ string oldFile = fromPathStr + name;
+ string newFile = toPathStr + name;
+
+ if (entry->d_type == DT_DIR) {
+ ret += makeFolder(newFile.c_str());
+ ret += copyRecursive(oldFile.c_str(), newFile.c_str());
+ } else {
+ ret += copyFile(oldFile.c_str(), newFile.c_str());
+ }
+ }
+ return ret;
+}
+
int copyFile(const char *fromPath, const char *toPath) {
auto start = std::chrono::steady_clock::now();
@@ -96,7 +153,7 @@
PLOG(ERROR) << "Failed to open copy from " << fromPath;
return -1;
}
- android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
+ android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, FILE_PERM));
if (toFd == -1) {
PLOG(ERROR) << "Failed to open copy to " << toPath;
return -1;
@@ -121,23 +178,17 @@
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end - start;
- LOG(INFO) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
+ LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
", Rate: " << ((double) length) / diff.count() << " bytes/s";
+ chown(toPath, getuid(), FILE_GROUP);
return ret == -1 ? -1 : 0;
}
void deleteRecursive(const char* path) {
- char pathbuf[PATH_MAX];
- size_t pathLength = strlen(path);
- if (pathLength >= sizeof(pathbuf) - 1) {
- LOG(ERROR) << "path too long: " << path;
+ string pathStr(path);
+ if (pathStr[pathStr.size()-1] != '/') {
+ pathStr += '/';
}
- strcpy(pathbuf, path);
- if (pathbuf[pathLength - 1] != '/') {
- pathbuf[pathLength++] = '/';
- }
- char* fileSpot = pathbuf + pathLength;
- int pathRemaining = sizeof(pathbuf) - pathLength - 1;
DIR* dir = opendir(path);
if (!dir) {
@@ -153,19 +204,12 @@
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
continue;
}
-
- int nameLength = strlen(name);
- if (nameLength > pathRemaining) {
- LOG(ERROR) << "path " << path << "/" << name << " too long";
- continue;
- }
- strcpy(fileSpot, name);
-
+ pathStr.append(name);
if (entry->d_type == DT_DIR) {
- deleteRecursive(pathbuf);
- rmdir(pathbuf);
+ deleteRecursive(pathStr.c_str());
+ rmdir(pathStr.c_str());
} else {
- unlink(pathbuf);
+ unlink(pathStr.c_str());
}
}
closedir(dir);