diff options
| -rw-r--r-- | core/java/android/os/FileUtils.java | 16 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/os/FileUtilsTest.java | 27 | 
2 files changed, 36 insertions, 7 deletions
| diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 40c658f01e28..a06a8577a56a 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -22,6 +22,8 @@ import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;  import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;  import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;  import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY; +import static android.system.OsConstants.EINVAL; +import static android.system.OsConstants.ENOSYS;  import static android.system.OsConstants.F_OK;  import static android.system.OsConstants.O_ACCMODE;  import static android.system.OsConstants.O_APPEND; @@ -441,7 +443,19 @@ public final class FileUtils {                  final StructStat st_in = Os.fstat(in);                  final StructStat st_out = Os.fstat(out);                  if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) { -                    return copyInternalSendfile(in, out, count, signal, executor, listener); +                    try { +                        return copyInternalSendfile(in, out, count, signal, executor, listener); +                    } catch (ErrnoException e) { +                        if (e.errno == EINVAL || e.errno == ENOSYS) { +                            // sendfile(2) will fail in at least any of the following conditions: +                            // 1. |in| doesn't support mmap(2) +                            // 2. |out| was opened with O_APPEND +                            // We fallback to userspace copy if that fails +                            return copyInternalUserspace(in, out, count, signal, executor, +                                    listener); +                        } +                        throw e; +                    }                  } else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {                      return copyInternalSplice(in, out, count, signal, executor, listener);                  } diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java index 1a86678a30b4..c1e72fe75666 100644 --- a/core/tests/coretests/src/android/os/FileUtilsTest.java +++ b/core/tests/coretests/src/android/os/FileUtilsTest.java @@ -228,6 +228,27 @@ public class FileUtilsTest {      }      @Test +    public void testCopyFileWithAppend() throws Exception { +        final File src = new File(mTarget, "src"); +        final File dest = new File(mTarget, "dest"); + +        byte[] expected = new byte[10]; +        byte[] actual = new byte[10]; +        new Random().nextBytes(expected); +        writeFile(src, expected); + +        try (FileInputStream in = new FileInputStream(src); +                FileOutputStream out = new FileOutputStream(dest, true /* append */)) { +            // sendfile(2) fails if output fd is opened with O_APPEND, but FileUtils#copy should +            // fallback to userspace copy +            FileUtils.copy(in, out); +        } + +        actual = readFile(dest); +        assertArrayEquals(expected, actual); +    } + +    @Test      public void testIsFilenameSafe() throws Exception {          assertTrue(FileUtils.isFilenameSafe(new File("foobar")));          assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23"))); @@ -577,7 +598,6 @@ public class FileUtilsTest {          final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4");          final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg"); -        final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4");          final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4");          final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg"); @@ -589,9 +609,6 @@ public class FileUtilsTest {              FileDescriptor pfdValidImageCameraDir =                      ParcelFileDescriptor.open(validImageCameraDir,                              MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); -            FileDescriptor pfdInvalidVideoCameraDir = -                    ParcelFileDescriptor.open(invalidVideoCameraDir, -                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();              FileDescriptor pfdValidVideoNonCameraDir =                      ParcelFileDescriptor.open(validVideoNonCameraDir, @@ -603,13 +620,11 @@ public class FileUtilsTest {              assertNotNull(convertToModernFd(pfdValidVideoCameraDir));              assertNull(convertToModernFd(pfdValidImageCameraDir)); -            assertNull(convertToModernFd(pfdInvalidVideoCameraDir));              assertNull(convertToModernFd(pfdValidVideoNonCameraDir));              assertNull(convertToModernFd(pfdValidImageNonCameraDir));          } finally {              validVideoCameraDir.delete();              validImageCameraDir.delete(); -            invalidVideoCameraDir.delete();              validVideoNonCameraDir.delete();              validImageNonCameraDir.delete();          } |