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

Commit 73e56d93 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

MTP: Add support for restricting PTP to only certain subdirectories of the storage



Bug: 5527220

Change-Id: If68e7481617ecb62abd24e2d89e6b7dfdf95ba2b
Signed-off-by: default avatarMike Lockwood <lockwood@google.com>
parent 1958dc27
Loading
Loading
Loading
Loading
+150 −38
Original line number Diff line number Diff line
@@ -51,7 +51,15 @@ public class MtpDatabase {
    private final IContentProvider mMediaProvider;
    private final String mVolumeName;
    private final Uri mObjectsUri;
    private final String mMediaStoragePath; // path to primary storage
    // path to primary storage
    private final String mMediaStoragePath;
    // if not null, restrict all queries to these subdirectories
    private final String[] mSubDirectories;
    // where clause for restricting queries to files in mSubDirectories
    private String mSubDirectoriesWhere;
    // where arguments for restricting queries to files in mSubDirectories
    private String[] mSubDirectoriesWhereArgs;

    private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();

    // cached property groups for single properties
@@ -112,7 +120,8 @@ public class MtpDatabase {
        System.loadLibrary("media_jni");
    }

    public MtpDatabase(Context context, String volumeName, String storagePath) {
    public MtpDatabase(Context context, String volumeName, String storagePath,
            String[] subDirectories) {
        native_setup();

        mContext = context;
@@ -122,6 +131,31 @@ public class MtpDatabase {
        mObjectsUri = Files.getMtpObjectsUri(volumeName);
        mMediaScanner = new MediaScanner(context);

        mSubDirectories = subDirectories;
        if (subDirectories != null) {
            // Compute "where" string for restricting queries to subdirectories
            StringBuilder builder = new StringBuilder();
            builder.append("(");
            int count = subDirectories.length;
            for (int i = 0; i < count; i++) {
                builder.append(Files.FileColumns.DATA + "=? OR "
                        + Files.FileColumns.DATA + " LIKE ?");
                if (i != count - 1) {
                    builder.append(" OR ");
                }
            }
            builder.append(")");
            mSubDirectoriesWhere = builder.toString();

            // Compute "where" arguments for restricting queries to subdirectories
            mSubDirectoriesWhereArgs = new String[count * 2];
            for (int i = 0, j = 0; i < count; i++) {
                String path = subDirectories[i];
                mSubDirectoriesWhereArgs[j++] = path;
                mSubDirectoriesWhereArgs[j++] = path + "/%";
            }
        }

        // Set locale to MediaScanner.
        Locale locale = context.getResources().getConfiguration().locale;
        if (locale != null) {
@@ -190,9 +224,44 @@ public class MtpDatabase {
        }
    }

    // check to see if the path is contained in one of our storage subdirectories
    // returns true if we have no special subdirectories
    private boolean inStorageSubDirectory(String path) {
        if (mSubDirectories == null) return true;
        if (path == null) return false;

        boolean allowed = false;
        int pathLength = path.length();
        for (int i = 0; i < mSubDirectories.length && !allowed; i++) {
            String subdir = mSubDirectories[i];
            int subdirLength = subdir.length();
            if (subdirLength < pathLength &&
                    path.charAt(subdirLength) == '/' &&
                    path.startsWith(subdir)) {
                allowed = true;
            }
        }
        return allowed;
    }

    // check to see if the path matches one of our storage subdirectories
    // returns true if we have no special subdirectories
    private boolean isStorageSubDirectory(String path) {
    if (mSubDirectories == null) return false;
        for (int i = 0; i < mSubDirectories.length; i++) {
            if (path.equals(mSubDirectories[i])) {
                return true;
            }
        }
        return false;
    }

    private int beginSendObject(String path, int format, int parent,
                         int storageId, long size, long modified) {
        // first make sure the object does not exist
        // if mSubDirectories is not null, do not allow copying files to any other locations
        if (!inStorageSubDirectory(path)) return -1;

        // make sure the object does not exist
        if (path != null) {
            Cursor c = null;
            try {
@@ -269,33 +338,40 @@ public class MtpDatabase {
    }

    private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
        String where;
        String[] whereArgs;

        if (storageID == 0xFFFFFFFF) {
            // query all stores
            if (format == 0) {
                // query all formats
                if (parent == 0) {
                    // query all objects
                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, null, null, null);
                }
                    where = null;
                    whereArgs = null;
                } else {
                    if (parent == 0xFFFFFFFF) {
                        // all objects in root of store
                        parent = 0;
                    }
                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, PARENT_WHERE,
                        new String[] { Integer.toString(parent) }, null);
                    where = PARENT_WHERE;
                    whereArgs = new String[] { Integer.toString(parent) };
                }
            } else {
                // query specific format
                if (parent == 0) {
                    // query all objects
                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_WHERE,
                            new String[] { Integer.toString(format) }, null);
                }
                    where = FORMAT_WHERE;
                    whereArgs = new String[] { Integer.toString(format) };
                } else {
                    if (parent == 0xFFFFFFFF) {
                        // all objects in root of store
                        parent = 0;
                    }
                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_PARENT_WHERE,
                        new String[] { Integer.toString(format), Integer.toString(parent) }, null);
                    where = FORMAT_PARENT_WHERE;
                    whereArgs = new String[] { Integer.toString(format),
                                               Integer.toString(parent) };
                }
            }
        } else {
            // query specific store
@@ -303,37 +379,63 @@ public class MtpDatabase {
                // query all formats
                if (parent == 0) {
                    // query all objects
                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_WHERE,
                            new String[] { Integer.toString(storageID) }, null);
                }
                    where = STORAGE_WHERE;
                    whereArgs = new String[] { Integer.toString(storageID) };
                } else {
                    if (parent == 0xFFFFFFFF) {
                        // all objects in root of store
                        parent = 0;
                    }
                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_PARENT_WHERE,
                        new String[] { Integer.toString(storageID), Integer.toString(parent) },
                        null);
                    where = STORAGE_PARENT_WHERE;
                    whereArgs = new String[] { Integer.toString(storageID),
                                               Integer.toString(parent) };
                }
            } else {
                // query specific format
                if (parent == 0) {
                    // query all objects
                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_WHERE,
                            new String[] {  Integer.toString(storageID), Integer.toString(format) },
                            null);
                }
                    where = STORAGE_FORMAT_WHERE;
                    whereArgs = new String[] {  Integer.toString(storageID),
                                                Integer.toString(format) };
                } else {
                    if (parent == 0xFFFFFFFF) {
                        // all objects in root of store
                        parent = 0;
                    }
                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_PARENT_WHERE,
                        new String[] { Integer.toString(storageID),
                    where = STORAGE_FORMAT_PARENT_WHERE;
                    whereArgs = new String[] { Integer.toString(storageID),
                                               Integer.toString(format),
                                       Integer.toString(parent) },
                        null);
                                               Integer.toString(parent) };
                }
            }
        }

        // if we are restricting queries to mSubDirectories, we need to add the restriction
        // onto our "where" arguments
        if (mSubDirectoriesWhere != null) {
            if (where == null) {
                where = mSubDirectoriesWhere;
                whereArgs = mSubDirectoriesWhereArgs;
            } else {
                where = where + " AND " + mSubDirectoriesWhere;

                // create new array to hold whereArgs and mSubDirectoriesWhereArgs
                String[] newWhereArgs =
                        new String[whereArgs.length + mSubDirectoriesWhereArgs.length];
                int i, j;
                for (i = 0; i < whereArgs.length; i++) {
                    newWhereArgs[i] = whereArgs[i];
                }
                for (j = 0; j < mSubDirectoriesWhereArgs.length; i++, j++) {
                    newWhereArgs[i] = mSubDirectoriesWhereArgs[j];
                }
                whereArgs = newWhereArgs;
            }
        }

        return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null);
    }

    private int[] getObjectList(int storageID, int format, int parent) {
        Cursor c = null;
        try {
@@ -613,6 +715,11 @@ public class MtpDatabase {
            return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
        }

        // do not allow renaming any of the special subdirectories
        if (isStorageSubDirectory(path)) {
            return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED;
        }

        // now rename the file.  make sure this succeeds before updating database
        File oldFile = new File(path);
        int lastSlash = path.lastIndexOf('/');
@@ -794,6 +901,11 @@ public class MtpDatabase {
                return MtpConstants.RESPONSE_GENERAL_ERROR;
            }

            // do not allow deleting any of the special subdirectories
            if (isStorageSubDirectory(path)) {
                return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED;
            }

            if (format == MtpConstants.FORMAT_ASSOCIATION) {
                // recursive case - delete all children first
                Uri uri = Files.getMtpObjectsUri(mVolumeName);
+7 −4
Original line number Diff line number Diff line
@@ -1053,13 +1053,16 @@ MtpResponseCode MtpServer::doDeleteObject() {
    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
    if (result == MTP_RESPONSE_OK) {
        ALOGV("deleting %s", (const char *)filePath);
        result = mDatabase->deleteFile(handle);
        // Don't delete the actual files unless the database deletion is allowed
        if (result == MTP_RESPONSE_OK) {
            deletePath((const char *)filePath);
        return mDatabase->deleteFile(handle);
    } else {
        return result;
        }
    }

    return result;
}

MtpResponseCode MtpServer::doGetObjectPropDesc() {
    MtpObjectProperty propCode = mRequest.getParameter(1);
    MtpObjectFormat format = mRequest.getParameter(2);