diff options
Diffstat (limited to 'src/com')
4 files changed, 66 insertions, 16 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java index 0928fdfc..132deb9a 100644 --- a/src/com/android/providers/downloads/DownloadProvider.java +++ b/src/com/android/providers/downloads/DownloadProvider.java @@ -710,14 +710,15 @@ public final class DownloadProvider extends ContentProvider { if (path == null) { throw new IllegalArgumentException("Invalid file URI: " + uri); } - try { - final String canonicalPath = new File(path).getCanonicalPath(); - final String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath(); - if (!canonicalPath.startsWith(externalPath)) { - throw new SecurityException("Destination must be on external storage: " + uri); - } - } catch (IOException e) { - throw new SecurityException("Problem resolving path: " + uri); + + final String phoneStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); + String sdCardStoragePath = null; + if (StorageManager.isSecondStorageSupported()) { + sdCardStoragePath = StorageManager.getExternalStorageDirectory(getContext()); + } + if (!path.startsWith(phoneStoragePath) + && !(sdCardStoragePath != null && path.startsWith(sdCardStoragePath))) { + throw new SecurityException("Destination must be on external storage: " + uri); } } @@ -1209,7 +1210,7 @@ public final class DownloadProvider extends ContentProvider { if (path == null) { throw new FileNotFoundException("No filename found."); } - if (!Helpers.isFilenameValid(path, mDownloadsDataDir)) { + if (!Helpers.isFilenameValid(getContext(), path, mDownloadsDataDir)) { throw new FileNotFoundException("Invalid filename: " + path); } diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index 9d5274c4..88cd9162 100755 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -769,7 +769,7 @@ public class DownloadThread implements Runnable { Log.i(Constants.TAG, "have run thread before for id: " + mInfo.mId + ", and state.mFilename: " + state.mFilename); } - if (!Helpers.isFilenameValid(state.mFilename, + if (!Helpers.isFilenameValid(mContext, state.mFilename, mStorageManager.getDownloadDataDirectory())) { // this should never happen throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR, diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index 3562dac7..d9b38b50 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -375,6 +375,18 @@ public class Helpers { } /** + * Checks whether the filename looks legitimate + */ + static boolean isFilenameValid(Context context, String filename, File downloadsDataDir) { + filename = filename.replaceFirst("/+", "/"); // normalize leading slashes + return filename.startsWith(Environment.getDownloadCacheDirectory().toString()) + || filename.startsWith(downloadsDataDir.toString()) + || filename.startsWith(Environment.getExternalStorageDirectory().toString()) + || (StorageManager.isSecondStorageSupported() && filename.startsWith(StorageManager + .getExternalStorageDirectory(context))); + } + + /** * Checks whether this looks like a legitimate selection parameter */ public static void validateSelection(String selection, Set<String> allowedColumns) { diff --git a/src/com/android/providers/downloads/StorageManager.java b/src/com/android/providers/downloads/StorageManager.java index deb412e7..a0ceae6a 100644 --- a/src/com/android/providers/downloads/StorageManager.java +++ b/src/com/android/providers/downloads/StorageManager.java @@ -19,6 +19,7 @@ package com.android.providers.downloads; import static com.android.providers.downloads.Constants.LOGV; import static com.android.providers.downloads.Constants.TAG; +import android.app.Activity; import android.content.ContentUris; import android.content.Context; import android.content.res.Resources; @@ -27,6 +28,7 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import android.os.Environment; import android.os.StatFs; +import android.os.storage.StorageVolume; import android.provider.Downloads; import android.text.TextUtils; import android.util.Log; @@ -77,6 +79,8 @@ class StorageManager { /** misc members */ private final Context mContext; + private static String sdCardStorageDir; + private static final String LOGTAG = "StorageManager"; public StorageManager(Context context) { mContext = context; @@ -84,6 +88,11 @@ class StorageManager { mExternalStorageDir = Environment.getExternalStorageDirectory(); mSystemCacheDir = Environment.getDownloadCacheDirectory(); startThreadToCleanupDatabaseAndPurgeFileSystem(); + if (isSecondStorageSupported()) { + sdCardStorageDir = getExternalStorageDirectory(context); + } else { + sdCardStorageDir = null; + } } /** How often should database and filesystem be cleaned up to remove spurious files @@ -149,7 +158,9 @@ class StorageManager { dir = mSystemCacheDir; break; case Downloads.Impl.DESTINATION_FILE_URI: - if (path.startsWith(mExternalStorageDir.getPath())) { + if (isSecondStorageSupported() && path.startsWith(sdCardStorageDir)) { + dir = new File(sdCardStorageDir); + } else if (path.startsWith(mExternalStorageDir.getPath())) { dir = mExternalStorageDir; } else if (path.startsWith(mDownloadDataDir.getPath())) { dir = mDownloadDataDir; @@ -175,11 +186,13 @@ class StorageManager { if (targetBytes == 0) { return; } - if (destination == Downloads.Impl.DESTINATION_FILE_URI || - destination == Downloads.Impl.DESTINATION_EXTERNAL) { - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - throw new StopRequestException(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR, - "external media not mounted"); + if (!(isSecondStorageSupported() && root.getPath().startsWith(sdCardStorageDir))) { + if (destination == Downloads.Impl.DESTINATION_FILE_URI || + destination == Downloads.Impl.DESTINATION_EXTERNAL) { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + throw new StopRequestException(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR, + "external media not mounted"); + } } } // is there enough space in the file system of the given param 'root'. @@ -469,4 +482,28 @@ class StorageManager { private synchronized void resetBytesDownloadedSinceLastCheckOnSpace() { mBytesDownloadedSinceLastCheckOnSpace = 0; } + + /** + * Whether support Second Storage + * + * @return boolean true support Second Storage, false will be not + */ + public static boolean isSecondStorageSupported() { + return true; + } + + public static String getExternalStorageDirectory(Context context) { + String sdCardDir = null; + android.os.storage.StorageManager storageManager = + (android.os.storage.StorageManager) context + .getSystemService(Context.STORAGE_SERVICE); + StorageVolume[] volumes = storageManager.getVolumeList(); + for (int i = 0; i < volumes.length; i++) { + if (volumes[i].isRemovable() && volumes[i].allowMassStorage()) { + sdCardDir = volumes[i].getPath(); + break; + } + } + return sdCardDir; + } } |