Merge "MTP: Add support for restricting PTP to only certain subdirectories of the storage DO NOT MERGE" into ics-mr1
This commit is contained in:
committed by
Android (Google) Code Review
commit
1a3ece9f87
@ -51,7 +51,15 @@ public class MtpDatabase {
|
|||||||
private final IContentProvider mMediaProvider;
|
private final IContentProvider mMediaProvider;
|
||||||
private final String mVolumeName;
|
private final String mVolumeName;
|
||||||
private final Uri mObjectsUri;
|
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>();
|
private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();
|
||||||
|
|
||||||
// cached property groups for single properties
|
// cached property groups for single properties
|
||||||
@ -112,7 +120,8 @@ public class MtpDatabase {
|
|||||||
System.loadLibrary("media_jni");
|
System.loadLibrary("media_jni");
|
||||||
}
|
}
|
||||||
|
|
||||||
public MtpDatabase(Context context, String volumeName, String storagePath) {
|
public MtpDatabase(Context context, String volumeName, String storagePath,
|
||||||
|
String[] subDirectories) {
|
||||||
native_setup();
|
native_setup();
|
||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@ -122,6 +131,31 @@ public class MtpDatabase {
|
|||||||
mObjectsUri = Files.getMtpObjectsUri(volumeName);
|
mObjectsUri = Files.getMtpObjectsUri(volumeName);
|
||||||
mMediaScanner = new MediaScanner(context);
|
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.
|
// Set locale to MediaScanner.
|
||||||
Locale locale = context.getResources().getConfiguration().locale;
|
Locale locale = context.getResources().getConfiguration().locale;
|
||||||
if (locale != null) {
|
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,
|
private int beginSendObject(String path, int format, int parent,
|
||||||
int storageId, long size, long modified) {
|
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) {
|
if (path != null) {
|
||||||
Cursor c = null;
|
Cursor c = null;
|
||||||
try {
|
try {
|
||||||
@ -269,33 +338,40 @@ public class MtpDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
|
private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
|
||||||
|
String where;
|
||||||
|
String[] whereArgs;
|
||||||
|
|
||||||
if (storageID == 0xFFFFFFFF) {
|
if (storageID == 0xFFFFFFFF) {
|
||||||
// query all stores
|
// query all stores
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
// query all formats
|
// query all formats
|
||||||
if (parent == 0) {
|
if (parent == 0) {
|
||||||
// query all objects
|
// query all objects
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, null, null, null);
|
where = null;
|
||||||
}
|
whereArgs = null;
|
||||||
|
} else {
|
||||||
if (parent == 0xFFFFFFFF) {
|
if (parent == 0xFFFFFFFF) {
|
||||||
// all objects in root of store
|
// all objects in root of store
|
||||||
parent = 0;
|
parent = 0;
|
||||||
}
|
}
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, PARENT_WHERE,
|
where = PARENT_WHERE;
|
||||||
new String[] { Integer.toString(parent) }, null);
|
whereArgs = new String[] { Integer.toString(parent) };
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// query specific format
|
// query specific format
|
||||||
if (parent == 0) {
|
if (parent == 0) {
|
||||||
// query all objects
|
// query all objects
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_WHERE,
|
where = FORMAT_WHERE;
|
||||||
new String[] { Integer.toString(format) }, null);
|
whereArgs = new String[] { Integer.toString(format) };
|
||||||
}
|
} else {
|
||||||
if (parent == 0xFFFFFFFF) {
|
if (parent == 0xFFFFFFFF) {
|
||||||
// all objects in root of store
|
// all objects in root of store
|
||||||
parent = 0;
|
parent = 0;
|
||||||
}
|
}
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_PARENT_WHERE,
|
where = FORMAT_PARENT_WHERE;
|
||||||
new String[] { Integer.toString(format), Integer.toString(parent) }, null);
|
whereArgs = new String[] { Integer.toString(format),
|
||||||
|
Integer.toString(parent) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// query specific store
|
// query specific store
|
||||||
@ -303,37 +379,63 @@ public class MtpDatabase {
|
|||||||
// query all formats
|
// query all formats
|
||||||
if (parent == 0) {
|
if (parent == 0) {
|
||||||
// query all objects
|
// query all objects
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_WHERE,
|
where = STORAGE_WHERE;
|
||||||
new String[] { Integer.toString(storageID) }, null);
|
whereArgs = new String[] { Integer.toString(storageID) };
|
||||||
}
|
} else {
|
||||||
if (parent == 0xFFFFFFFF) {
|
if (parent == 0xFFFFFFFF) {
|
||||||
// all objects in root of store
|
// all objects in root of store
|
||||||
parent = 0;
|
parent = 0;
|
||||||
}
|
}
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_PARENT_WHERE,
|
where = STORAGE_PARENT_WHERE;
|
||||||
new String[] { Integer.toString(storageID), Integer.toString(parent) },
|
whereArgs = new String[] { Integer.toString(storageID),
|
||||||
null);
|
Integer.toString(parent) };
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// query specific format
|
// query specific format
|
||||||
if (parent == 0) {
|
if (parent == 0) {
|
||||||
// query all objects
|
// query all objects
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_WHERE,
|
where = STORAGE_FORMAT_WHERE;
|
||||||
new String[] { Integer.toString(storageID), Integer.toString(format) },
|
whereArgs = new String[] { Integer.toString(storageID),
|
||||||
null);
|
Integer.toString(format) };
|
||||||
}
|
} else {
|
||||||
if (parent == 0xFFFFFFFF) {
|
if (parent == 0xFFFFFFFF) {
|
||||||
// all objects in root of store
|
// all objects in root of store
|
||||||
parent = 0;
|
parent = 0;
|
||||||
}
|
}
|
||||||
return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_PARENT_WHERE,
|
where = STORAGE_FORMAT_PARENT_WHERE;
|
||||||
new String[] { Integer.toString(storageID),
|
whereArgs = new String[] { Integer.toString(storageID),
|
||||||
Integer.toString(format),
|
Integer.toString(format),
|
||||||
Integer.toString(parent) },
|
Integer.toString(parent) };
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
private int[] getObjectList(int storageID, int format, int parent) {
|
||||||
Cursor c = null;
|
Cursor c = null;
|
||||||
try {
|
try {
|
||||||
@ -613,6 +715,11 @@ public class MtpDatabase {
|
|||||||
return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
|
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
|
// now rename the file. make sure this succeeds before updating database
|
||||||
File oldFile = new File(path);
|
File oldFile = new File(path);
|
||||||
int lastSlash = path.lastIndexOf('/');
|
int lastSlash = path.lastIndexOf('/');
|
||||||
@ -794,6 +901,11 @@ public class MtpDatabase {
|
|||||||
return MtpConstants.RESPONSE_GENERAL_ERROR;
|
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) {
|
if (format == MtpConstants.FORMAT_ASSOCIATION) {
|
||||||
// recursive case - delete all children first
|
// recursive case - delete all children first
|
||||||
Uri uri = Files.getMtpObjectsUri(mVolumeName);
|
Uri uri = Files.getMtpObjectsUri(mVolumeName);
|
||||||
|
@ -1053,13 +1053,16 @@ MtpResponseCode MtpServer::doDeleteObject() {
|
|||||||
int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
|
int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
|
||||||
if (result == MTP_RESPONSE_OK) {
|
if (result == MTP_RESPONSE_OK) {
|
||||||
LOGV("deleting %s", (const char *)filePath);
|
LOGV("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);
|
deletePath((const char *)filePath);
|
||||||
return mDatabase->deleteFile(handle);
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MtpResponseCode MtpServer::doGetObjectPropDesc() {
|
MtpResponseCode MtpServer::doGetObjectPropDesc() {
|
||||||
MtpObjectProperty propCode = mRequest.getParameter(1);
|
MtpObjectProperty propCode = mRequest.getParameter(1);
|
||||||
MtpObjectFormat format = mRequest.getParameter(2);
|
MtpObjectFormat format = mRequest.getParameter(2);
|
||||||
|
Reference in New Issue
Block a user