@@ -51,7 +51,15 @@ public class MtpDatabase {
5151 private final IContentProvider mMediaProvider ;
5252 private final String mVolumeName ;
5353 private final Uri mObjectsUri ;
54- private final String mMediaStoragePath ; // path to primary storage
54+ // path to primary storage
55+ private final String mMediaStoragePath ;
56+ // if not null, restrict all queries to these subdirectories
57+ private final String [] mSubDirectories ;
58+ // where clause for restricting queries to files in mSubDirectories
59+ private String mSubDirectoriesWhere ;
60+ // where arguments for restricting queries to files in mSubDirectories
61+ private String [] mSubDirectoriesWhereArgs ;
62+
5563 private final HashMap <String , MtpStorage > mStorageMap = new HashMap <String , MtpStorage >();
5664
5765 // cached property groups for single properties
@@ -112,7 +120,8 @@ public class MtpDatabase {
112120 System .loadLibrary ("media_jni" );
113121 }
114122
115- public MtpDatabase (Context context , String volumeName , String storagePath ) {
123+ public MtpDatabase (Context context , String volumeName , String storagePath ,
124+ String [] subDirectories ) {
116125 native_setup ();
117126
118127 mContext = context ;
@@ -122,6 +131,31 @@ public MtpDatabase(Context context, String volumeName, String storagePath) {
122131 mObjectsUri = Files .getMtpObjectsUri (volumeName );
123132 mMediaScanner = new MediaScanner (context );
124133
134+ mSubDirectories = subDirectories ;
135+ if (subDirectories != null ) {
136+ // Compute "where" string for restricting queries to subdirectories
137+ StringBuilder builder = new StringBuilder ();
138+ builder .append ("(" );
139+ int count = subDirectories .length ;
140+ for (int i = 0 ; i < count ; i ++) {
141+ builder .append (Files .FileColumns .DATA + "=? OR "
142+ + Files .FileColumns .DATA + " LIKE ?" );
143+ if (i != count - 1 ) {
144+ builder .append (" OR " );
145+ }
146+ }
147+ builder .append (")" );
148+ mSubDirectoriesWhere = builder .toString ();
149+
150+ // Compute "where" arguments for restricting queries to subdirectories
151+ mSubDirectoriesWhereArgs = new String [count * 2 ];
152+ for (int i = 0 , j = 0 ; i < count ; i ++) {
153+ String path = subDirectories [i ];
154+ mSubDirectoriesWhereArgs [j ++] = path ;
155+ mSubDirectoriesWhereArgs [j ++] = path + "/%" ;
156+ }
157+ }
158+
125159 // Set locale to MediaScanner.
126160 Locale locale = context .getResources ().getConfiguration ().locale ;
127161 if (locale != null ) {
@@ -190,9 +224,44 @@ private void initDeviceProperties(Context context) {
190224 }
191225 }
192226
227+ // check to see if the path is contained in one of our storage subdirectories
228+ // returns true if we have no special subdirectories
229+ private boolean inStorageSubDirectory (String path ) {
230+ if (mSubDirectories == null ) return true ;
231+ if (path == null ) return false ;
232+
233+ boolean allowed = false ;
234+ int pathLength = path .length ();
235+ for (int i = 0 ; i < mSubDirectories .length && !allowed ; i ++) {
236+ String subdir = mSubDirectories [i ];
237+ int subdirLength = subdir .length ();
238+ if (subdirLength < pathLength &&
239+ path .charAt (subdirLength ) == '/' &&
240+ path .startsWith (subdir )) {
241+ allowed = true ;
242+ }
243+ }
244+ return allowed ;
245+ }
246+
247+ // check to see if the path matches one of our storage subdirectories
248+ // returns true if we have no special subdirectories
249+ private boolean isStorageSubDirectory (String path ) {
250+ if (mSubDirectories == null ) return false ;
251+ for (int i = 0 ; i < mSubDirectories .length ; i ++) {
252+ if (path .equals (mSubDirectories [i ])) {
253+ return true ;
254+ }
255+ }
256+ return false ;
257+ }
258+
193259 private int beginSendObject (String path , int format , int parent ,
194260 int storageId , long size , long modified ) {
195- // first make sure the object does not exist
261+ // if mSubDirectories is not null, do not allow copying files to any other locations
262+ if (!inStorageSubDirectory (path )) return -1 ;
263+
264+ // make sure the object does not exist
196265 if (path != null ) {
197266 Cursor c = null ;
198267 try {
@@ -269,69 +338,102 @@ private void endSendObject(String path, int handle, int format, boolean succeede
269338 }
270339
271340 private Cursor createObjectQuery (int storageID , int format , int parent ) throws RemoteException {
341+ String where ;
342+ String [] whereArgs ;
343+
272344 if (storageID == 0xFFFFFFFF ) {
273345 // query all stores
274346 if (format == 0 ) {
275347 // query all formats
276348 if (parent == 0 ) {
277349 // query all objects
278- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , null , null , null );
279- }
280- if (parent == 0xFFFFFFFF ) {
281- // all objects in root of store
282- parent = 0 ;
350+ where = null ;
351+ whereArgs = null ;
352+ } else {
353+ if (parent == 0xFFFFFFFF ) {
354+ // all objects in root of store
355+ parent = 0 ;
356+ }
357+ where = PARENT_WHERE ;
358+ whereArgs = new String [] { Integer .toString (parent ) };
283359 }
284- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , PARENT_WHERE ,
285- new String [] { Integer .toString (parent ) }, null );
286360 } else {
287361 // query specific format
288362 if (parent == 0 ) {
289363 // query all objects
290- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , FORMAT_WHERE ,
291- new String [] { Integer .toString (format ) }, null );
292- }
293- if (parent == 0xFFFFFFFF ) {
294- // all objects in root of store
295- parent = 0 ;
364+ where = FORMAT_WHERE ;
365+ whereArgs = new String [] { Integer .toString (format ) };
366+ } else {
367+ if (parent == 0xFFFFFFFF ) {
368+ // all objects in root of store
369+ parent = 0 ;
370+ }
371+ where = FORMAT_PARENT_WHERE ;
372+ whereArgs = new String [] { Integer .toString (format ),
373+ Integer .toString (parent ) };
296374 }
297- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , FORMAT_PARENT_WHERE ,
298- new String [] { Integer .toString (format ), Integer .toString (parent ) }, null );
299375 }
300376 } else {
301377 // query specific store
302378 if (format == 0 ) {
303379 // query all formats
304380 if (parent == 0 ) {
305381 // query all objects
306- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , STORAGE_WHERE ,
307- new String [] { Integer .toString (storageID ) }, null );
308- }
309- if (parent == 0xFFFFFFFF ) {
310- // all objects in root of store
311- parent = 0 ;
382+ where = STORAGE_WHERE ;
383+ whereArgs = new String [] { Integer .toString (storageID ) };
384+ } else {
385+ if (parent == 0xFFFFFFFF ) {
386+ // all objects in root of store
387+ parent = 0 ;
388+ }
389+ where = STORAGE_PARENT_WHERE ;
390+ whereArgs = new String [] { Integer .toString (storageID ),
391+ Integer .toString (parent ) };
312392 }
313- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , STORAGE_PARENT_WHERE ,
314- new String [] { Integer .toString (storageID ), Integer .toString (parent ) },
315- null );
316393 } else {
317394 // query specific format
318395 if (parent == 0 ) {
319396 // query all objects
320- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , STORAGE_FORMAT_WHERE ,
321- new String [] { Integer .toString (storageID ), Integer .toString (format ) },
322- null );
397+ where = STORAGE_FORMAT_WHERE ;
398+ whereArgs = new String [] { Integer .toString (storageID ),
399+ Integer .toString (format ) };
400+ } else {
401+ if (parent == 0xFFFFFFFF ) {
402+ // all objects in root of store
403+ parent = 0 ;
404+ }
405+ where = STORAGE_FORMAT_PARENT_WHERE ;
406+ whereArgs = new String [] { Integer .toString (storageID ),
407+ Integer .toString (format ),
408+ Integer .toString (parent ) };
323409 }
324- if (parent == 0xFFFFFFFF ) {
325- // all objects in root of store
326- parent = 0 ;
410+ }
411+ }
412+
413+ // if we are restricting queries to mSubDirectories, we need to add the restriction
414+ // onto our "where" arguments
415+ if (mSubDirectoriesWhere != null ) {
416+ if (where == null ) {
417+ where = mSubDirectoriesWhere ;
418+ whereArgs = mSubDirectoriesWhereArgs ;
419+ } else {
420+ where = where + " AND " + mSubDirectoriesWhere ;
421+
422+ // create new array to hold whereArgs and mSubDirectoriesWhereArgs
423+ String [] newWhereArgs =
424+ new String [whereArgs .length + mSubDirectoriesWhereArgs .length ];
425+ int i , j ;
426+ for (i = 0 ; i < whereArgs .length ; i ++) {
427+ newWhereArgs [i ] = whereArgs [i ];
327428 }
328- return mMediaProvider .query (mObjectsUri , ID_PROJECTION , STORAGE_FORMAT_PARENT_WHERE ,
329- new String [] { Integer .toString (storageID ),
330- Integer .toString (format ),
331- Integer .toString (parent ) },
332- null );
429+ for (j = 0 ; j < mSubDirectoriesWhereArgs .length ; i ++, j ++) {
430+ newWhereArgs [i ] = mSubDirectoriesWhereArgs [j ];
431+ }
432+ whereArgs = newWhereArgs ;
333433 }
334434 }
435+
436+ return mMediaProvider .query (mObjectsUri , ID_PROJECTION , where , whereArgs , null );
335437 }
336438
337439 private int [] getObjectList (int storageID , int format , int parent ) {
@@ -613,6 +715,11 @@ private int renameFile(int handle, String newName) {
613715 return MtpConstants .RESPONSE_INVALID_OBJECT_HANDLE ;
614716 }
615717
718+ // do not allow renaming any of the special subdirectories
719+ if (isStorageSubDirectory (path )) {
720+ return MtpConstants .RESPONSE_OBJECT_WRITE_PROTECTED ;
721+ }
722+
616723 // now rename the file. make sure this succeeds before updating database
617724 File oldFile = new File (path );
618725 int lastSlash = path .lastIndexOf ('/' );
@@ -794,6 +901,11 @@ private int deleteFile(int handle) {
794901 return MtpConstants .RESPONSE_GENERAL_ERROR ;
795902 }
796903
904+ // do not allow deleting any of the special subdirectories
905+ if (isStorageSubDirectory (path )) {
906+ return MtpConstants .RESPONSE_OBJECT_WRITE_PROTECTED ;
907+ }
908+
797909 if (format == MtpConstants .FORMAT_ASSOCIATION ) {
798910 // recursive case - delete all children first
799911 Uri uri = Files .getMtpObjectsUri (mVolumeName );
0 commit comments