From 9a37e74876af5b935d152bda053a3ead29886c87 Mon Sep 17 00:00:00 2001 From: Raphael Heinz Date: Tue, 10 Oct 2023 22:49:06 +0200 Subject: [PATCH 1/3] Android: Close input and output streams --- .../reactnativefs/ReactNativeFsModule.java | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java index ed1dd279..5be44ab9 100644 --- a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java +++ b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java @@ -137,12 +137,9 @@ public void addListener(String eventName) { @ReactMethod public void appendFile(String filepath, String base64Content, Promise promise) { - try { + try (OutputStream outputStream = getOutputStream(filepath, true)) { byte[] bytes = Base64.decode(base64Content, Base64.DEFAULT); - - OutputStream outputStream = getOutputStream(filepath, true); outputStream.write(bytes); - outputStream.close(); promise.resolve(null); } catch (Exception ex) { @@ -409,6 +406,7 @@ public void getFSInfo(Promise promise) { @ReactMethod public void hash(String filepath, String algorithm, Promise promise) { + FileInputStream inputStream = null; try { Map algorithms = new HashMap<>(); @@ -435,7 +433,7 @@ public void hash(String filepath, String algorithm, Promise promise) { MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm)); - FileInputStream inputStream = new FileInputStream(filepath); + inputStream = new FileInputStream(filepath); byte[] buffer = new byte[1024 * 10]; // 10 KB Buffer int read; @@ -451,6 +449,13 @@ public void hash(String filepath, String algorithm, Promise promise) { } catch (Exception ex) { ex.printStackTrace(); reject(promise, filepath, ex); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ignored) { + } + } } } @@ -539,8 +544,7 @@ public void read( double position, Promise promise ) { - try { - InputStream inputStream = getInputStream(filepath); + try (InputStream inputStream = getInputStream(filepath)) { byte[] buffer = new byte[(int)length]; inputStream.skip((int)position); int bytesRead = inputStream.read(buffer, 0, (int)length); @@ -624,8 +628,7 @@ public void readDirAssets(String directory, Promise promise) { @ReactMethod public void readFile(String filepath, Promise promise) { - try { - InputStream inputStream = getInputStream(filepath); + try (InputStream inputStream = getInputStream(filepath)) { byte[] inputData = getInputStreamBytes(inputStream); String base64Content = Base64.encodeToString(inputData, Base64.NO_WRAP); @@ -899,35 +902,45 @@ public void write( double position, Promise promise ) { + OutputStream outputStream = null; + RandomAccessFile file = null; try { byte[] bytes = Base64.decode(base64Content, Base64.DEFAULT); if (position < 0) { - OutputStream outputStream = getOutputStream(filepath, true); + outputStream = getOutputStream(filepath, true); outputStream.write(bytes); - outputStream.close(); } else { - RandomAccessFile file = new RandomAccessFile(filepath, "rw"); + file = new RandomAccessFile(filepath, "rw"); file.seek((long)position); file.write(bytes); - file.close(); } promise.resolve(null); } catch (Exception ex) { ex.printStackTrace(); reject(promise, filepath, ex); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException ignored) { + } + } + if (file != null) { + try { + file.close(); + } catch (IOException ignored) { + } + } } } @ReactMethod public void writeFile(String filepath, String base64Content, ReadableMap options, Promise promise) { - try { + try (OutputStream outputStream = getOutputStream(filepath, false)) { byte[] bytes = Base64.decode(base64Content, Base64.DEFAULT); - - OutputStream outputStream = getOutputStream(filepath, false); outputStream.write(bytes); - outputStream.close(); promise.resolve(null); } catch (Exception ex) { @@ -938,12 +951,14 @@ public void writeFile(String filepath, String base64Content, ReadableMap options private class CopyFileTask extends AsyncTask { protected Exception doInBackground(String... paths) { + InputStream in = null; + OutputStream out = null; try { String filepath = paths[0]; String destPath = paths[1]; - InputStream in = getInputStream(filepath); - OutputStream out = getOutputStream(destPath, false); + in = getInputStream(filepath); + out = getOutputStream(destPath, false); byte[] buffer = new byte[1024]; int length; @@ -951,11 +966,18 @@ protected Exception doInBackground(String... paths) { out.write(buffer, 0, length); Thread.yield(); } - in.close(); - out.close(); return null; } catch (Exception ex) { return ex; + } finally { + try { + in.close(); + } catch (IOException ignored) { + } + try { + out.close(); + } catch (IOException ignored) { + } } } } @@ -1180,4 +1202,4 @@ private void sendEvent(ReactContext reactContext, String eventName, WritableMap - - private ReactApplicationContext reactContext; - - */ \ No newline at end of file + */ From 1a418ad899c7b11915b0e3bb891ab51ce8aaf2c0 Mon Sep 17 00:00:00 2001 From: Raphael Heinz Date: Tue, 10 Oct 2023 23:18:45 +0200 Subject: [PATCH 2/3] Android: Add missing null check to prevent NullPointerException --- .../reactnativefs/ReactNativeFsModule.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java index 5be44ab9..42876604 100644 --- a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java +++ b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java @@ -970,13 +970,17 @@ protected Exception doInBackground(String... paths) { } catch (Exception ex) { return ex; } finally { - try { - in.close(); - } catch (IOException ignored) { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) { + } } - try { - out.close(); - } catch (IOException ignored) { + if (out != null) { + try { + out.close(); + } catch (IOException ignored) { + } } } } @@ -1151,8 +1155,8 @@ private void sendEvent(ReactContext reactContext, String eventName, WritableMap } /** - * TODO: This is the original module file - * + * TODO: This is the original module file + * - - - From 24ee47647cff204ebdc189b16db7b7de254a5b56 Mon Sep 17 00:00:00 2001 From: "Dr. Sergey Pogodin" Date: Wed, 11 Oct 2023 01:00:42 +0200 Subject: [PATCH 3/3] Minor code clean-up --- .../reactnativefs/ReactNativeFsModule.java | 151 +++--------------- 1 file changed, 25 insertions(+), 126 deletions(-) diff --git a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java index 42876604..081c8b8f 100644 --- a/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java +++ b/android/src/main/java/com/drpogodin/reactnativefs/ReactNativeFsModule.java @@ -37,6 +37,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -63,6 +64,18 @@ public class ReactNativeFsModule extends ReactNativeFsSpec { private ArrayDeque pendingPickFilePromises = new ArrayDeque(); private ActivityResultLauncher pickFileLauncher; + /** + * Attempts to close given object, discarting possible exception. Does nothing + * if given argument is null. + * @param closeable + */ + static private void closeIgnoringException(Closeable closeable) { + if (closeable != null) { + try { closeable.close(); } + catch (Exception e) {} + } + } + ReactNativeFsModule(ReactApplicationContext context) { super(context); @@ -330,19 +343,10 @@ public void existsAssets(String filepath, Promise promise) { } // Attempt to open file (win = exists) - InputStream fileStream = null; - try { - fileStream = assetManager.open(filepath); + try (InputStream fileStream = assetManager.open(filepath)) { promise.resolve(true); } catch (Exception ex) { promise.resolve(false); // don't throw an error, resolve false - } finally { - if (fileStream != null) { - try { - fileStream.close(); - } catch (Exception ignored) { - } - } } } catch (Exception ex) { ex.printStackTrace(); @@ -450,12 +454,7 @@ public void hash(String filepath, String algorithm, Promise promise) { ex.printStackTrace(); reject(promise, filepath, ex); } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(inputStream); } } @@ -659,12 +658,7 @@ public void readFileAssets(String filepath, Promise promise) { ex.printStackTrace(); reject(promise, filepath, ex); } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(stream); } } @@ -687,12 +681,7 @@ public void readFileRes(String filename, Promise promise) { ex.printStackTrace(); reject(promise, filename, ex); } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(stream); } } @@ -797,7 +786,7 @@ public void touch(String filepath, ReadableMap options, Promise promise) { promise.resolve(file.setLastModified((long) mtime)); } catch (Exception ex) { ex.printStackTrace(); - reject(promise, filepath, ex); + reject(promise, filepath, ex); } } @@ -921,18 +910,8 @@ public void write( ex.printStackTrace(); reject(promise, filepath, ex); } finally { - if (outputStream != null) { - try { - outputStream.close(); - } catch (IOException ignored) { - } - } - if (file != null) { - try { - file.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(outputStream); + closeIgnoringException(file); } } @@ -970,18 +949,8 @@ protected Exception doInBackground(String... paths) { } catch (Exception ex) { return ex; } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignored) { - } - } - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(in); + closeIgnoringException(out); } } } @@ -1010,18 +979,8 @@ private void copyInputStream(InputStream in, String source, String destination, } catch (Exception ex) { reject(promise, source, new Exception(String.format("Failed to copy '%s' to %s (%s)", source, destination, ex.getLocalizedMessage()))); } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignored) { - } - } - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { - } - } + closeIgnoringException(in); + closeIgnoringException(out); } } @@ -1064,20 +1023,14 @@ private InputStream getInputStream(String filepath) throws IORejectionException private static byte[] getInputStreamBytes(InputStream inputStream) throws IOException { byte[] bytesResult; - ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; - try { + try (ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream()) { int len; while ((len = inputStream.read(buffer)) != -1) { byteBuffer.write(buffer, 0, len); } bytesResult = byteBuffer.toByteArray(); - } finally { - try { - byteBuffer.close(); - } catch (IOException ignored) { - } } return bytesResult; } @@ -1153,57 +1106,3 @@ private void sendEvent(ReactContext reactContext, String eventName, WritableMap emitter.emit(eventName, params); } } - -/** - * TODO: This is the original module file - * -- -- -- -- -- -- -- -- -- -- -- -- -- --import com.facebook.react.bridge.Promise; --import com.facebook.react.bridge.ReactApplicationContext; -- --import com.facebook.react.bridge.ReactContextBaseJavaModule; --import com.facebook.react.bridge.ReactMethod; -- - -- -- --import com.facebook.react.module.annotations.ReactModule; -- -- -- -- -- --import java.util.HashMap; --import java.util.Map; -- -- private static final String RNFSDocumentDirectoryPath = "RNFSDocumentDirectoryPath"; -- private static final String RNFSExternalDirectoryPath = "RNFSExternalDirectoryPath"; -- private static final String RNFSExternalStorageDirectoryPath = "RNFSExternalStorageDirectoryPath"; -- private static final String RNFSPicturesDirectoryPath = "RNFSPicturesDirectoryPath"; -- private static final String RNFSDownloadDirectoryPath = "RNFSDownloadDirectoryPath"; -- private static final String RNFSTemporaryDirectoryPath = "RNFSTemporaryDirectoryPath"; -- private static final String RNFSCachesDirectoryPath = "RNFSCachesDirectoryPath"; -- private static final String RNFSExternalCachesDirectoryPath = "RNFSExternalCachesDirectoryPath"; -- private static final String RNFSDocumentDirectory = "RNFSDocumentDirectory"; -- -- private static final String RNFSFileTypeRegular = "RNFSFileTypeRegular"; -- private static final String RNFSFileTypeDirectory = "RNFSFileTypeDirectory"; -- -- private SparseArray downloaders = new SparseArray<>(); -- private SparseArray uploaders = new SparseArray<>(); -- -- private ReactApplicationContext reactContext; -- - */