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

Commit bae12e14 authored by Jerry Zhang's avatar Jerry Zhang Committed by android-build-merger
Browse files

Merge "Account for folders in copy and move."

am: fa7b99dd

Change-Id: I55f333c2237e97ea0ca38d296d6285d09d673197
parents d79a8385 fa7b99dd
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);