Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa7b99dd authored by Jerry Zhang's avatar Jerry Zhang Committed by Gerrit Code Review
Browse files

Merge "Account for folders in copy and move."

parents 49d0502f e242f12c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;

+31 −19
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 * limitations under the License.
 */

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <chrono>
#include <dirent.h>
@@ -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),
@@ -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);
@@ -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;
@@ -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);
@@ -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) {
+0 −7
Original line number Diff line number Diff line
@@ -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
@@ -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,
+67 −23
Original line number Diff line number Diff line
@@ -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 @@ 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();

@@ -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;
@@ -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) {
@@ -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);
+8 −0
Original line number Diff line number Diff line
@@ -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);