Loading media/mtp/MtpDatabase.h +1 −1 Original line number Diff line number Diff line Loading @@ -104,7 +104,7 @@ public: virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0; virtual MtpResponseCode moveObject(MtpObjectHandle handle, MtpObjectHandle newParent, MtpString& newPath) = 0; MtpStorageID newStorage, MtpString& newPath) = 0; virtual void sessionStarted() = 0; Loading media/mtp/MtpServer.cpp +31 −19 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <android-base/logging.h> #include <android-base/properties.h> #include <chrono> #include <dirent.h> Loading Loading @@ -99,16 +100,12 @@ static const MtpEventCode kSupportedEventCodes[] = { }; MtpServer::MtpServer(MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm, const MtpString& deviceInfoManufacturer, const MtpString& deviceInfoModel, const MtpString& deviceInfoDeviceVersion, const MtpString& deviceInfoSerialNumber) : mDatabase(database), mPtp(ptp), mFileGroup(fileGroup), mFilePermission(filePerm), mDirectoryPermission(directoryPerm), mDeviceInfoManufacturer(deviceInfoManufacturer), mDeviceInfoModel(deviceInfoModel), mDeviceInfoDeviceVersion(deviceInfoDeviceVersion), Loading Loading @@ -1002,12 +999,9 @@ MtpResponseCode MtpServer::doSendObjectInfo() { } if (format == MTP_FORMAT_ASSOCIATION) { mode_t mask = umask(0); int ret = mkdir((const char *)path, mDirectoryPermission); umask(mask); if (ret && ret != -EEXIST) int ret = makeFolder((const char *)path); if (ret) return MTP_RESPONSE_GENERAL_ERROR; chown((const char *)path, getuid(), mFileGroup); // SendObject does not get sent for directories, so call endSendObject here instead mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK); Loading Loading @@ -1068,28 +1062,39 @@ MtpResponseCode MtpServer::doMoveObject() { path += "/"; path += info.mName; result = mDatabase->moveObject(objectHandle, parent, path); result = mDatabase->moveObject(objectHandle, parent, storageID, path); if (result != MTP_RESPONSE_OK) return result; if (info.mStorageID == storageID) { ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path); if (rename(fromPath, path)) { ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path); PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path; result = MTP_RESPONSE_GENERAL_ERROR; } } else { ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path); if (format == MTP_FORMAT_ASSOCIATION) { int ret = makeFolder((const char *)path); ret += copyRecursive(fromPath, path); if (ret) { result = MTP_RESPONSE_GENERAL_ERROR; } else { deletePath(fromPath); } } else { if (copyFile(fromPath, path)) { result = MTP_RESPONSE_GENERAL_ERROR; } else { deletePath(fromPath); } } } // If the move failed, undo the database change if (result != MTP_RESPONSE_OK) if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK) if (mDatabase->moveObject(objectHandle, info.mParent, info.mStorageID, fromPath) != MTP_RESPONSE_OK) ALOGE("Couldn't undo failed move"); return result; Loading Loading @@ -1148,9 +1153,16 @@ MtpResponseCode MtpServer::doCopyObject() { } ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path); if (format == MTP_FORMAT_ASSOCIATION) { int ret = makeFolder((const char *)path); if (ret) { result = MTP_RESPONSE_GENERAL_ERROR; } } else { if (copyFile(fromPath, path)) { result = MTP_RESPONSE_GENERAL_ERROR; } } mDatabase->endSendObject(path, handle, format, result); mResponse.setParameter(1, handle); Loading Loading @@ -1188,10 +1200,10 @@ MtpResponseCode MtpServer::doSendObject() { result = MTP_RESPONSE_GENERAL_ERROR; goto done; } fchown(mfr.fd, getuid(), mFileGroup); fchown(mfr.fd, getuid(), FILE_GROUP); // set permissions mask = umask(0); fchmod(mfr.fd, mFilePermission); fchmod(mfr.fd, FILE_PERM); umask(mask); if (initialData > 0) { Loading media/mtp/MtpServer.h +0 −7 Original line number Diff line number Diff line Loading @@ -43,12 +43,6 @@ private: // appear as a PTP device bool mPtp; // group to own new files and folders int mFileGroup; // permissions for new files and directories int mFilePermission; int mDirectoryPermission; // Manufacturer to report in DeviceInfo MtpString mDeviceInfoManufacturer; // Model to report in DeviceInfo Loading Loading @@ -105,7 +99,6 @@ private: public: MtpServer(MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm, const MtpString& deviceInfoManufacturer, const MtpString& deviceInfoModel, const MtpString& deviceInfoDeviceVersion, Loading media/mtp/MtpUtils.cpp +67 −23 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -29,6 +30,8 @@ #include "MtpUtils.h" using namespace std; namespace android { constexpr unsigned long FILE_COPY_SIZE = 262144; Loading Loading @@ -88,6 +91,60 @@ void formatDateTime(time_t seconds, char* buffer, int bufferLength) { 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(); Loading @@ -96,7 +153,7 @@ int copyFile(const char *fromPath, const char *toPath) { 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; Loading @@ -121,23 +178,17 @@ int copyFile(const char *fromPath, const char *toPath) { } 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; } strcpy(pathbuf, path); if (pathbuf[pathLength - 1] != '/') { pathbuf[pathLength++] = '/'; string pathStr(path); if (pathStr[pathStr.size()-1] != '/') { pathStr += '/'; } char* fileSpot = pathbuf + pathLength; int pathRemaining = sizeof(pathbuf) - pathLength - 1; DIR* dir = opendir(path); if (!dir) { Loading @@ -153,19 +204,12 @@ void deleteRecursive(const char* path) { 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); Loading media/mtp/MtpUtils.h +8 −0 Original line number Diff line number Diff line Loading @@ -17,13 +17,21 @@ #ifndef _MTP_UTILS_H #define _MTP_UTILS_H #include "private/android_filesystem_config.h" #include <stdint.h> namespace android { constexpr int FILE_GROUP = AID_MEDIA_RW; constexpr int FILE_PERM = 0664; constexpr int DIR_PERM = 0775; bool parseDateTime(const char* dateTime, time_t& outSeconds); void formatDateTime(time_t seconds, char* buffer, int bufferLength); int makeFolder(const char *path); int copyRecursive(const char *fromPath, const char *toPath); int copyFile(const char *fromPath, const char *toPath); void deleteRecursive(const char* path); void deletePath(const char* path); Loading Loading
media/mtp/MtpDatabase.h +1 −1 Original line number Diff line number Diff line Loading @@ -104,7 +104,7 @@ public: virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0; virtual MtpResponseCode moveObject(MtpObjectHandle handle, MtpObjectHandle newParent, MtpString& newPath) = 0; MtpStorageID newStorage, MtpString& newPath) = 0; virtual void sessionStarted() = 0; Loading
media/mtp/MtpServer.cpp +31 −19 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <android-base/logging.h> #include <android-base/properties.h> #include <chrono> #include <dirent.h> Loading Loading @@ -99,16 +100,12 @@ static const MtpEventCode kSupportedEventCodes[] = { }; MtpServer::MtpServer(MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm, const MtpString& deviceInfoManufacturer, const MtpString& deviceInfoModel, const MtpString& deviceInfoDeviceVersion, const MtpString& deviceInfoSerialNumber) : mDatabase(database), mPtp(ptp), mFileGroup(fileGroup), mFilePermission(filePerm), mDirectoryPermission(directoryPerm), mDeviceInfoManufacturer(deviceInfoManufacturer), mDeviceInfoModel(deviceInfoModel), mDeviceInfoDeviceVersion(deviceInfoDeviceVersion), Loading Loading @@ -1002,12 +999,9 @@ MtpResponseCode MtpServer::doSendObjectInfo() { } if (format == MTP_FORMAT_ASSOCIATION) { mode_t mask = umask(0); int ret = mkdir((const char *)path, mDirectoryPermission); umask(mask); if (ret && ret != -EEXIST) int ret = makeFolder((const char *)path); if (ret) return MTP_RESPONSE_GENERAL_ERROR; chown((const char *)path, getuid(), mFileGroup); // SendObject does not get sent for directories, so call endSendObject here instead mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK); Loading Loading @@ -1068,28 +1062,39 @@ MtpResponseCode MtpServer::doMoveObject() { path += "/"; path += info.mName; result = mDatabase->moveObject(objectHandle, parent, path); result = mDatabase->moveObject(objectHandle, parent, storageID, path); if (result != MTP_RESPONSE_OK) return result; if (info.mStorageID == storageID) { ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path); if (rename(fromPath, path)) { ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path); PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path; result = MTP_RESPONSE_GENERAL_ERROR; } } else { ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path); if (format == MTP_FORMAT_ASSOCIATION) { int ret = makeFolder((const char *)path); ret += copyRecursive(fromPath, path); if (ret) { result = MTP_RESPONSE_GENERAL_ERROR; } else { deletePath(fromPath); } } else { if (copyFile(fromPath, path)) { result = MTP_RESPONSE_GENERAL_ERROR; } else { deletePath(fromPath); } } } // If the move failed, undo the database change if (result != MTP_RESPONSE_OK) if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK) if (mDatabase->moveObject(objectHandle, info.mParent, info.mStorageID, fromPath) != MTP_RESPONSE_OK) ALOGE("Couldn't undo failed move"); return result; Loading Loading @@ -1148,9 +1153,16 @@ MtpResponseCode MtpServer::doCopyObject() { } ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path); if (format == MTP_FORMAT_ASSOCIATION) { int ret = makeFolder((const char *)path); if (ret) { result = MTP_RESPONSE_GENERAL_ERROR; } } else { if (copyFile(fromPath, path)) { result = MTP_RESPONSE_GENERAL_ERROR; } } mDatabase->endSendObject(path, handle, format, result); mResponse.setParameter(1, handle); Loading Loading @@ -1188,10 +1200,10 @@ MtpResponseCode MtpServer::doSendObject() { result = MTP_RESPONSE_GENERAL_ERROR; goto done; } fchown(mfr.fd, getuid(), mFileGroup); fchown(mfr.fd, getuid(), FILE_GROUP); // set permissions mask = umask(0); fchmod(mfr.fd, mFilePermission); fchmod(mfr.fd, FILE_PERM); umask(mask); if (initialData > 0) { Loading
media/mtp/MtpServer.h +0 −7 Original line number Diff line number Diff line Loading @@ -43,12 +43,6 @@ private: // appear as a PTP device bool mPtp; // group to own new files and folders int mFileGroup; // permissions for new files and directories int mFilePermission; int mDirectoryPermission; // Manufacturer to report in DeviceInfo MtpString mDeviceInfoManufacturer; // Model to report in DeviceInfo Loading Loading @@ -105,7 +99,6 @@ private: public: MtpServer(MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm, const MtpString& deviceInfoManufacturer, const MtpString& deviceInfoModel, const MtpString& deviceInfoDeviceVersion, Loading
media/mtp/MtpUtils.cpp +67 −23 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -29,6 +30,8 @@ #include "MtpUtils.h" using namespace std; namespace android { constexpr unsigned long FILE_COPY_SIZE = 262144; Loading Loading @@ -88,6 +91,60 @@ void formatDateTime(time_t seconds, char* buffer, int bufferLength) { 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(); Loading @@ -96,7 +153,7 @@ int copyFile(const char *fromPath, const char *toPath) { 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; Loading @@ -121,23 +178,17 @@ int copyFile(const char *fromPath, const char *toPath) { } 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; } strcpy(pathbuf, path); if (pathbuf[pathLength - 1] != '/') { pathbuf[pathLength++] = '/'; string pathStr(path); if (pathStr[pathStr.size()-1] != '/') { pathStr += '/'; } char* fileSpot = pathbuf + pathLength; int pathRemaining = sizeof(pathbuf) - pathLength - 1; DIR* dir = opendir(path); if (!dir) { Loading @@ -153,19 +204,12 @@ void deleteRecursive(const char* path) { 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); Loading
media/mtp/MtpUtils.h +8 −0 Original line number Diff line number Diff line Loading @@ -17,13 +17,21 @@ #ifndef _MTP_UTILS_H #define _MTP_UTILS_H #include "private/android_filesystem_config.h" #include <stdint.h> namespace android { constexpr int FILE_GROUP = AID_MEDIA_RW; constexpr int FILE_PERM = 0664; constexpr int DIR_PERM = 0775; bool parseDateTime(const char* dateTime, time_t& outSeconds); void formatDateTime(time_t seconds, char* buffer, int bufferLength); int makeFolder(const char *path); int copyRecursive(const char *fromPath, const char *toPath); int copyFile(const char *fromPath, const char *toPath); void deleteRecursive(const char* path); void deletePath(const char* path); Loading