Loading core/java/android/os/FileUtils.java +27 −10 Original line number Diff line number Diff line Loading @@ -605,6 +605,30 @@ public class FileUtils { */ public static File buildUniqueFile(File parent, String mimeType, String displayName) throws FileNotFoundException { final String[] parts = splitFileName(mimeType, displayName); final String name = parts[0]; final String ext = parts[1]; File file = buildFile(parent, name, ext); // If conflicting file, try adding counter suffix int n = 0; while (file.exists()) { if (n++ >= 32) { throw new FileNotFoundException("Failed to create unique file"); } file = buildFile(parent, name + " (" + n + ")", ext); } return file; } /** * Splits file name into base name and extension. * If the display name doesn't have an extension that matches the requested MIME type, the * extension is regarded as a part of filename and default extension for that MIME type is * appended. */ public static String[] splitFileName(String mimeType, String displayName) { String name; String ext; Loading Loading @@ -642,18 +666,11 @@ public class FileUtils { } } File file = buildFile(parent, name, ext); // If conflicting file, try adding counter suffix int n = 0; while (file.exists()) { if (n++ >= 32) { throw new FileNotFoundException("Failed to create unique file"); } file = buildFile(parent, name + " (" + n + ")", ext); if (ext == null) { ext = ""; } return file; return new String[] { name, ext }; } private static File buildFile(File parent, String name, String ext) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java→packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java +5 −2 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ package com.android.mtp.exceptions; package com.android.mtp; import java.io.IOException; /** * Exception thrown when the device is busy and the requested operation cannon be completed. */ public class BusyDeviceException extends IOException { class BusyDeviceException extends IOException { BusyDeviceException() { super("The MTP device is busy."); } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +57 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.mtp.MtpObjectInfo; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUriExposedException; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.storage.StorageManager; import android.provider.DocumentsContract.Document; Loading @@ -41,7 +43,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.mtp.exceptions.BusyDeviceException; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -324,25 +325,61 @@ public class MtpDocumentsProvider extends DocumentsProvider { if (DEBUG) { Log.d(TAG, "createDocument: " + displayName); } final Identifier parentId; final MtpDeviceRecord record; final ParcelFileDescriptor[] pipe; try { final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); parentId = mDatabase.createIdentifier(parentDocumentId); openDevice(parentId.mDeviceId); final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) { throw new UnsupportedOperationException(); throw new UnsupportedOperationException( "Writing operation is not supported by the device."); } final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); pipe = ParcelFileDescriptor.createReliablePipe(); int objectHandle = -1; MtpObjectInfo info = null; try { pipe[0].close(); // 0 bytes for a new document. final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? MtpConstants.FORMAT_ASSOCIATION : MediaFile.getFormatCode(displayName, mimeType); final MtpObjectInfo info = new MtpObjectInfo.Builder() info = new MtpObjectInfo.Builder() .setStorageId(parentId.mStorageId) .setParent(parentId.mObjectHandle) .setFormat(formatCode) .setName(displayName) .build(); final int objectHandle = mMtpManager.createDocument(parentId.mDeviceId, info, pipe[1]); final String[] parts = FileUtils.splitFileName(mimeType, displayName); final String baseName = parts[0]; final String extension = parts[1]; for (int i = 0; i <= 32; i++) { final MtpObjectInfo infoUniqueName; if (i == 0) { infoUniqueName = info; } else { infoUniqueName = new MtpObjectInfo.Builder(info).setName( baseName + " (" + i + ")." + extension).build(); } try { objectHandle = mMtpManager.createDocument( parentId.mDeviceId, infoUniqueName, pipe[1]); break; } catch (SendObjectInfoFailure exp) { // This can be caused when we have an existing file with the same name. continue; } } } finally { pipe[1].close(); } if (objectHandle == -1) { throw new IllegalArgumentException( "The file name \"" + displayName + "\" is conflicted with existing files " + "and the provider failed to find unique name."); } final MtpObjectInfo infoWithHandle = new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build(); final String documentId = mDatabase.putNewDocument( Loading @@ -351,9 +388,12 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDocumentLoader(parentId).clearTask(parentId); notifyChildDocumentsChange(parentDocumentId); return documentId; } catch (FileNotFoundException | RuntimeException error) { Log.e(TAG, "createDocument", error); throw error; } catch (IOException error) { Log.e(TAG, "createDocument", error); throw new FileNotFoundException(error.getMessage()); throw new IllegalStateException(error); } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +1 −2 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.mtp.exceptions.BusyDeviceException; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -190,7 +189,7 @@ class MtpManager { synchronized (device) { final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo); if (sendObjectInfoResult == null) { throw new IOException("Failed to create a document"); throw new SendObjectInfoFailure(); } if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) { if (!device.sendObject(sendObjectInfoResult.getObjectHandle(), Loading packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mtp; import java.io.IOException; /** * Exception thrown when sendObjectInfo failed. */ class SendObjectInfoFailure extends IOException { SendObjectInfoFailure() { super("Failed to MtpDevice#sendObjectInfo."); } } Loading
core/java/android/os/FileUtils.java +27 −10 Original line number Diff line number Diff line Loading @@ -605,6 +605,30 @@ public class FileUtils { */ public static File buildUniqueFile(File parent, String mimeType, String displayName) throws FileNotFoundException { final String[] parts = splitFileName(mimeType, displayName); final String name = parts[0]; final String ext = parts[1]; File file = buildFile(parent, name, ext); // If conflicting file, try adding counter suffix int n = 0; while (file.exists()) { if (n++ >= 32) { throw new FileNotFoundException("Failed to create unique file"); } file = buildFile(parent, name + " (" + n + ")", ext); } return file; } /** * Splits file name into base name and extension. * If the display name doesn't have an extension that matches the requested MIME type, the * extension is regarded as a part of filename and default extension for that MIME type is * appended. */ public static String[] splitFileName(String mimeType, String displayName) { String name; String ext; Loading Loading @@ -642,18 +666,11 @@ public class FileUtils { } } File file = buildFile(parent, name, ext); // If conflicting file, try adding counter suffix int n = 0; while (file.exists()) { if (n++ >= 32) { throw new FileNotFoundException("Failed to create unique file"); } file = buildFile(parent, name + " (" + n + ")", ext); if (ext == null) { ext = ""; } return file; return new String[] { name, ext }; } private static File buildFile(File parent, String name, String ext) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java→packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java +5 −2 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ package com.android.mtp.exceptions; package com.android.mtp; import java.io.IOException; /** * Exception thrown when the device is busy and the requested operation cannon be completed. */ public class BusyDeviceException extends IOException { class BusyDeviceException extends IOException { BusyDeviceException() { super("The MTP device is busy."); } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +57 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.mtp.MtpObjectInfo; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUriExposedException; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.storage.StorageManager; import android.provider.DocumentsContract.Document; Loading @@ -41,7 +43,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.mtp.exceptions.BusyDeviceException; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -324,25 +325,61 @@ public class MtpDocumentsProvider extends DocumentsProvider { if (DEBUG) { Log.d(TAG, "createDocument: " + displayName); } final Identifier parentId; final MtpDeviceRecord record; final ParcelFileDescriptor[] pipe; try { final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); parentId = mDatabase.createIdentifier(parentDocumentId); openDevice(parentId.mDeviceId); final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) { throw new UnsupportedOperationException(); throw new UnsupportedOperationException( "Writing operation is not supported by the device."); } final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); pipe = ParcelFileDescriptor.createReliablePipe(); int objectHandle = -1; MtpObjectInfo info = null; try { pipe[0].close(); // 0 bytes for a new document. final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? MtpConstants.FORMAT_ASSOCIATION : MediaFile.getFormatCode(displayName, mimeType); final MtpObjectInfo info = new MtpObjectInfo.Builder() info = new MtpObjectInfo.Builder() .setStorageId(parentId.mStorageId) .setParent(parentId.mObjectHandle) .setFormat(formatCode) .setName(displayName) .build(); final int objectHandle = mMtpManager.createDocument(parentId.mDeviceId, info, pipe[1]); final String[] parts = FileUtils.splitFileName(mimeType, displayName); final String baseName = parts[0]; final String extension = parts[1]; for (int i = 0; i <= 32; i++) { final MtpObjectInfo infoUniqueName; if (i == 0) { infoUniqueName = info; } else { infoUniqueName = new MtpObjectInfo.Builder(info).setName( baseName + " (" + i + ")." + extension).build(); } try { objectHandle = mMtpManager.createDocument( parentId.mDeviceId, infoUniqueName, pipe[1]); break; } catch (SendObjectInfoFailure exp) { // This can be caused when we have an existing file with the same name. continue; } } } finally { pipe[1].close(); } if (objectHandle == -1) { throw new IllegalArgumentException( "The file name \"" + displayName + "\" is conflicted with existing files " + "and the provider failed to find unique name."); } final MtpObjectInfo infoWithHandle = new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build(); final String documentId = mDatabase.putNewDocument( Loading @@ -351,9 +388,12 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDocumentLoader(parentId).clearTask(parentId); notifyChildDocumentsChange(parentDocumentId); return documentId; } catch (FileNotFoundException | RuntimeException error) { Log.e(TAG, "createDocument", error); throw error; } catch (IOException error) { Log.e(TAG, "createDocument", error); throw new FileNotFoundException(error.getMessage()); throw new IllegalStateException(error); } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +1 −2 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.mtp.exceptions.BusyDeviceException; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -190,7 +189,7 @@ class MtpManager { synchronized (device) { final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo); if (sendObjectInfoResult == null) { throw new IOException("Failed to create a document"); throw new SendObjectInfoFailure(); } if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) { if (!device.sendObject(sendObjectInfoResult.getObjectHandle(), Loading
packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mtp; import java.io.IOException; /** * Exception thrown when sendObjectInfo failed. */ class SendObjectInfoFailure extends IOException { SendObjectInfoFailure() { super("Failed to MtpDevice#sendObjectInfo."); } }