diff options
| -rw-r--r-- | core/java/android/os/RedactingFileDescriptor.java | 26 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java | 80 |
2 files changed, 97 insertions, 9 deletions
diff --git a/core/java/android/os/RedactingFileDescriptor.java b/core/java/android/os/RedactingFileDescriptor.java index 4e5eaac3442f..a1ed2146b38e 100644 --- a/core/java/android/os/RedactingFileDescriptor.java +++ b/core/java/android/os/RedactingFileDescriptor.java @@ -35,7 +35,7 @@ import java.util.Arrays; /** * Variant of {@link FileDescriptor} that allows its creator to specify regions - * that should be redacted (appearing as zeros to the reader). + * that should be redacted. * * @hide */ @@ -44,13 +44,16 @@ public class RedactingFileDescriptor { private static final boolean DEBUG = true; private volatile long[] mRedactRanges; + private volatile long[] mFreeOffsets; private FileDescriptor mInner = null; private ParcelFileDescriptor mOuter = null; - private RedactingFileDescriptor(Context context, File file, int mode, long[] redactRanges) + private RedactingFileDescriptor( + Context context, File file, int mode, long[] redactRanges, long[] freeOffsets) throws IOException { mRedactRanges = checkRangesArgument(redactRanges); + mFreeOffsets = freeOffsets; try { try { @@ -88,13 +91,17 @@ public class RedactingFileDescriptor { * * @param file The underlying file to open. * @param mode The {@link ParcelFileDescriptor} mode to open with. - * @param redactRanges List of file offsets that should be redacted, stored + * @param redactRanges List of file ranges that should be redacted, stored * as {@code [start1, end1, start2, end2, ...]}. Start values are * inclusive and end values are exclusive. + * @param freePositions List of file offsets at which the four byte value 'free' should be + * written instead of zeros within parts of the file covered by {@code redactRanges}. + * Non-redacted bytes will not be modified even if covered by a 'free'. This is + * useful for overwriting boxes in ISOBMFF files with padding data. */ public static ParcelFileDescriptor open(Context context, File file, int mode, - long[] redactRanges) throws IOException { - return new RedactingFileDescriptor(context, file, mode, redactRanges).mOuter; + long[] redactRanges, long[] freePositions) throws IOException { + return new RedactingFileDescriptor(context, file, mode, redactRanges, freePositions).mOuter; } /** @@ -169,6 +176,15 @@ public class RedactingFileDescriptor { for (long j = start; j < end; j++) { data[(int) (j - offset)] = 0; } + // Overwrite data at 'free' offsets within the redaction ranges. + for (long freeOffset : mFreeOffsets) { + final long freeEnd = freeOffset + 4; + final long redactFreeStart = Math.max(freeOffset, start); + final long redactFreeEnd = Math.min(freeEnd, end); + for (long j = redactFreeStart; j < redactFreeEnd; j++) { + data[(int) (j - offset)] = (byte) "free".charAt((int) (j - freeOffset)); + } + } } return n; } diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java index d5163e193510..eff4826040f4 100644 --- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java +++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java @@ -64,7 +64,7 @@ public class RedactingFileDescriptorTest { @Test public void testSingleByte() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 10, 11 }).getFileDescriptor(); + new long[] { 10, 11 }, new long[] {}).getFileDescriptor(); final byte[] buf = new byte[1_000]; assertEquals(buf.length, Os.read(fd, buf, 0, buf.length)); @@ -80,7 +80,7 @@ public class RedactingFileDescriptorTest { @Test public void testRanges() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 100, 200, 300, 400 }).getFileDescriptor(); + new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor(); final byte[] buf = new byte[10]; assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 90)); @@ -102,7 +102,7 @@ public class RedactingFileDescriptorTest { @Test public void testEntireFile() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 0, 5_000_000 }).getFileDescriptor(); + new long[] { 0, 5_000_000 }, new long[] {}).getFileDescriptor(); try (FileInputStream in = new FileInputStream(fd)) { int val; @@ -115,7 +115,7 @@ public class RedactingFileDescriptorTest { @Test public void testReadWrite() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, - new long[] { 100, 200, 300, 400 }).getFileDescriptor(); + new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor(); // Redacted at first final byte[] buf = new byte[10]; @@ -168,4 +168,76 @@ public class RedactingFileDescriptorTest { assertArrayEquals(new long[] { 100, 200 }, removeRange(new long[] { 100, 200 }, 150, 150)); } + + @Test + public void testFreeAtStart() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {1}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAtOffset() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {3}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, 0, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAcrossRedactionStart() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {0}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAcrossRedactionEnd() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 3 }, new long[] {2}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, (byte) 'f', 64, 64, 64, 64, 64, 64, 64 }, + buf); + } + + @Test + public void testFreeOutsideRedaction() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 8 }, new long[] { 8 }).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, 0, 0, 0, 0, 0, 0, 64, 64 }, + buf); + } + + @Test + public void testFreeMultipleRedactions() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 2, 3, 4 }, new long[] { 0 }).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'r', 64, (byte) 'e', 64, 64, 64, 64, 64, 64 }, + buf); + } } |