diff --git a/io/src/main/java/com/topjohnwu/superuser/internal/FifoOutputStream.java b/io/src/main/java/com/topjohnwu/superuser/internal/FifoOutputStream.java index b891048..1fc9abc 100644 --- a/io/src/main/java/com/topjohnwu/superuser/internal/FifoOutputStream.java +++ b/io/src/main/java/com/topjohnwu/superuser/internal/FifoOutputStream.java @@ -104,11 +104,6 @@ class FifoOutputStream extends BaseSuOutputStream { } } - @Override - public void write(int b) throws IOException { - out.write(b); - } - @Override public void close() throws IOException { super.close(); diff --git a/io/src/main/java/com/topjohnwu/superuser/io/SuFileInputStream.java b/io/src/main/java/com/topjohnwu/superuser/io/SuFileInputStream.java index 1ced39c..1994c09 100644 --- a/io/src/main/java/com/topjohnwu/superuser/io/SuFileInputStream.java +++ b/io/src/main/java/com/topjohnwu/superuser/io/SuFileInputStream.java @@ -53,13 +53,11 @@ public class SuFileInputStream extends FilterInputStream { * On Android 5.0 and higher (API 21+), internally a named pipe (FIFO) is created * to bridge all I/O operations across process boundary, providing 100% native * {@link FileInputStream} performance. - * A single root command is issued through the main shell. + * A single root command is issued through the main shell at stream construction. *
- * On Android 4.4 and lower, the provided {@code file} will first be copied into - * the application cache folder before opening an InputStream for access. - * The temporary file will be removed when the stream is closed. - *

- * Unlike {@link #openCompat(File)}, the stream is NOT buffered internally. + * On Android 4.4 and lower, the returned stream will do I/O operations using {@code dd} + * commands via the main root shell for each 4MB chunk. Due to excessive internal buffering, + * the performance is on par with native streams. * @see FileInputStream#FileInputStream(File) */ public static InputStream open(File file) throws FileNotFoundException { @@ -77,56 +75,9 @@ public class SuFileInputStream extends FilterInputStream { } } - /** - * {@code SuFileInputStream.openCompat(new File(path))} - */ - public static InputStream openCompat(String path) throws FileNotFoundException { - return openCompat(new File(path)); - } - - /** - * Open an {@link InputStream} with root access (compatibility mode). - *

- * Unless {@code file} is an {@link SuFile}, this method will always try to directly - * open a {@link FileInputStream}, and fallback to using root access when it fails. - *

- * Root Access Streams:
- * On Android 5.0 and higher (API 21+), this is the same as {@link #open(File)}, but - * additionally wrapped with {@link BufferedInputStream} for consistency. - *
- * On Android 4.4 and lower, the returned stream will do every I/O operation with {@code dd} - * commands via the main root shell. This was the implementation in older versions of - * {@code libsu} and is proven to be error prone, but preserved as "compatibility mode". - *

- * The returned stream is already buffered, do not add another - * layer of {@link BufferedInputStream} to add more overhead! - * @see FileInputStream#FileInputStream(File) - */ - public static InputStream openCompat(File file) throws FileNotFoundException { - if (file instanceof SuFile) { - return shell((SuFile) file); - } else { - try { - // Try normal FileInputStream - return new BufferedInputStream(new FileInputStream(file)); - } catch (FileNotFoundException e) { - if (!Shell.rootAccess()) - throw e; - return shell(new SuFile(file)); - } - } - } - private static InputStream root(SuFile file) throws FileNotFoundException { if (Build.VERSION.SDK_INT >= 21) return IOFactory.fifoIn(file); - else - return IOFactory.copyIn(file); - } - - private static InputStream shell(SuFile file) throws FileNotFoundException { - if (Build.VERSION.SDK_INT >= 21) - return new BufferedInputStream(IOFactory.fifoIn(file)); else return IOFactory.shellIn(file); } @@ -134,21 +85,41 @@ public class SuFileInputStream extends FilterInputStream { // Deprecated APIs /** - * Same as {@link #openCompat(String)} + * Same as {@link #open(String)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(String)} */ @Deprecated public SuFileInputStream(String path) throws FileNotFoundException { - super(openCompat(path)); + this(new File(path)); } /** - * Same as {@link #openCompat(File)} + * Same as {@link #open(File)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(File)} */ @Deprecated public SuFileInputStream(File file) throws FileNotFoundException { - super(openCompat(file)); + super(null); + if (file instanceof SuFile) { + in = compat((SuFile) file); + } else { + try { + // Try normal FileInputStream + in = new BufferedInputStream(new FileInputStream(file)); + } catch (FileNotFoundException e) { + if (!Shell.rootAccess()) + throw e; + in = compat(new SuFile(file)); + } + } } + private static InputStream compat(SuFile file) throws FileNotFoundException { + if (Build.VERSION.SDK_INT >= 21) + return new BufferedInputStream(IOFactory.fifoIn(file)); + else + return IOFactory.shellIn(file); + } } diff --git a/io/src/main/java/com/topjohnwu/superuser/io/SuFileOutputStream.java b/io/src/main/java/com/topjohnwu/superuser/io/SuFileOutputStream.java index e2a8c6d..7ba08e6 100644 --- a/io/src/main/java/com/topjohnwu/superuser/io/SuFileOutputStream.java +++ b/io/src/main/java/com/topjohnwu/superuser/io/SuFileOutputStream.java @@ -66,18 +66,17 @@ public class SuFileOutputStream extends BufferedOutputStream { * On Android 5.0 and higher (API 21+), internally a named pipe (FIFO) is created * to bridge all I/O operations across process boundary, providing 100% native * {@link FileOutputStream} performance. - * A single root command is issued through the main shell. + * A single root command is issued through the main shell at stream construction. *
* On Android 4.4 and lower, all write operations will be applied to a temporary file in * the application cache folder. When the stream is closed, the temporary file - * will then be copied over to the provided {@code file} at once then deleted. - *

- * Unlike {@link #openCompat(File, boolean)}, the stream is NOT buffered internally. + * will be copied over to the provided {@code file} by using a single {@code cat} + * command with the main shell, then deleted. * @see FileOutputStream#FileOutputStream(File, boolean) */ public static OutputStream open(File file, boolean append) throws FileNotFoundException { if (file instanceof SuFile) { - return root((SuFile) file, append); + return fifo((SuFile) file, append); } else { try { // Try normal FileInputStream @@ -85,55 +84,49 @@ public class SuFileOutputStream extends BufferedOutputStream { } catch (FileNotFoundException e) { if (!Shell.rootAccess()) throw e; - return root(new SuFile(file), append); + return fifo(new SuFile(file), append); } } } /** - * {@code SuFileOutputStream.openCompat(new File(path), false)} + * {@code SuFileOutputStream.openNoCopy(new File(path), false)} */ - public static OutputStream openCompat(String path) throws FileNotFoundException { - return openCompat(new File(path), false); + public static OutputStream openNoCopy(String path) throws FileNotFoundException { + return openNoCopy(new File(path), false); } /** - * {@code SuFileOutputStream.openCompat(new File(path), append)} + * {@code SuFileOutputStream.openNoCopy(new File(path), append)} */ - public static OutputStream openCompat(String path, boolean append) throws FileNotFoundException { - return openCompat(new File(path), append); + public static OutputStream openNoCopy(String path, boolean append) throws FileNotFoundException { + return openNoCopy(new File(path), append); } /** - * {@code SuFileOutputStream.openCompat(file, false)} + * {@code SuFileOutputStream.openNoCopy(file, false)} */ - public static OutputStream openCompat(File file) throws FileNotFoundException { - return openCompat(file, false); + public static OutputStream openNoCopy(File file) throws FileNotFoundException { + return openNoCopy(file, false); } /** - * Open an {@link OutputStream} with root access (compatibility mode). + * Open an {@link OutputStream} with root access (no internal copying). + *

+ * If your minSdkVersion is 21 or higher, this method is irrelevant. *

* Unless {@code file} is an {@link SuFile}, this method will always try to directly * open a {@link FileOutputStream}, and fallback to using root access when it fails. *

* Root Access Streams:
- * On Android 5.0 and higher (API 21+), this is the same as {@link #open(File, boolean)}, but - * additionally wrapped with {@link BufferedOutputStream} for consistency. + * On Android 5.0 and higher (API 21+), this is equivalent to {@link #open(File, boolean)}. *
- * On Android 4.4 and lower, the returned stream will do every I/O operation with {@code dd} - * commands via the main root shell. This was the implementation in older versions of - * {@code libsu} and is proven to be error prone, but preserved as "compatibility mode". - *

- * The returned stream is already buffered, do not add another - * layer of {@link BufferedOutputStream} to add more overhead! + * On Android 4.4 and lower, the returned stream will do every write operation with a + * {@code dd} command via the main root shell. Writing to files through shell + * commands is proven to be error prone. YOU HAVE BEEN WARNED! * @see FileOutputStream#FileOutputStream(File, boolean) */ - public static OutputStream openCompat(File file, boolean append) throws FileNotFoundException { - return new BufferedOutputStream(compat(file, append)); - } - - private static OutputStream compat(File file, boolean append) throws FileNotFoundException { + public static OutputStream openNoCopy(File file, boolean append) throws FileNotFoundException { if (file instanceof SuFile) { return shell((SuFile) file, append); } else { @@ -148,7 +141,7 @@ public class SuFileOutputStream extends BufferedOutputStream { } } - private static OutputStream root(SuFile file, boolean append) throws FileNotFoundException { + private static OutputStream fifo(SuFile file, boolean append) throws FileNotFoundException { if (Build.VERSION.SDK_INT >= 21) return IOFactory.fifoOut(file, append); else @@ -165,38 +158,42 @@ public class SuFileOutputStream extends BufferedOutputStream { // Deprecated APIs /** - * Same as {@link #openCompat(String)} + * Same as {@link #openNoCopy(String)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(String)} */ @Deprecated public SuFileOutputStream(String path) throws FileNotFoundException { - this(new File(path), false); + super(openNoCopy(path, false)); } /** - * Same as {@link #openCompat(String, boolean)} + * Same as {@link #openNoCopy(String, boolean)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(String, boolean)} */ @Deprecated public SuFileOutputStream(String path, boolean append) throws FileNotFoundException { - this(new File(path), append); + super(openNoCopy(path, append)); } /** - * Same as {@link #openCompat(File)} + * Same as {@link #openNoCopy(File)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(File, boolean)} */ @Deprecated public SuFileOutputStream(File file) throws FileNotFoundException { - this(file, false); + super(openNoCopy(file, false)); } /** - * Same as {@link #openCompat(File, boolean)} + * Same as {@link #openNoCopy(File, boolean)}, but guaranteed to be buffered internally to + * match backwards compatibility behavior. * @deprecated please switch to {@link #open(File, boolean)} */ @Deprecated public SuFileOutputStream(File file, boolean append) throws FileNotFoundException { - super(compat(file, append)); + super(openNoCopy(file, append)); } } diff --git a/io/src/main/java/com/topjohnwu/superuser/io/SuRandomAccessFile.java b/io/src/main/java/com/topjohnwu/superuser/io/SuRandomAccessFile.java index 668de66..fe96536 100644 --- a/io/src/main/java/com/topjohnwu/superuser/io/SuRandomAccessFile.java +++ b/io/src/main/java/com/topjohnwu/superuser/io/SuRandomAccessFile.java @@ -27,10 +27,12 @@ import java.io.IOException; import java.io.RandomAccessFile; /** - * Access files using the global shell instance and mimics {@link RandomAccessFile}. + * Access files using the main shell and mimics {@link RandomAccessFile}. *

- * Usage of this class is strongly NOT recommended. Each I/O operation comes with a large + * Usage of this class is not recommended. Each I/O operation comes with a large * overhead and depends on certain behavior of the command {@code dd}. + * Writing to files through shell commands is proven to be error prone. + * YOU HAVE BEEN WARNED! * Please use {@link SuFileInputStream} and {@link SuFileOutputStream} whenever possible. *

* This class always checks whether using a shell is necessary. If not, it simply opens a new