From 93828987c38f3125d57e9c22f71a03483b8d6bca Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 10 May 2024 09:05:54 +0800 Subject: [PATCH] Fix earlier change to content URI resolution on Android * java/org/gnu/emacs/EmacsService.java (openContentUri): Return -1 if fd be NULL. * src/androidvfs.c (android_authority_open): Detect SecurityException and suchlike. (android_vfs_init): Initialize exception classes on Android 4.4. (cherry picked from commit c900c707e8f3075dfe57c39a8a6363ba4575035f) --- java/org/gnu/emacs/EmacsService.java | 5 +- src/androidvfs.c | 221 ++++++++++++++------------- 2 files changed, 116 insertions(+), 110 deletions(-) diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 5548748ddfa..1e5f72eed37 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -968,7 +968,7 @@ public final class EmacsService extends Service string; make it writable if WRITABLE, and readable if READABLE. Truncate the file if TRUNCATE. - Value is the resulting file descriptor or an exception will be + Value is the resulting file descriptor, -1, or an exception will be raised. */ public int @@ -999,6 +999,9 @@ public final class EmacsService extends Service minimum requirement for access to /content/by-authority. */ fd = resolver.openFileDescriptor (Uri.parse (uri), mode); + if (fd == null) + return -1; + i = fd.detachFd (); fd.close (); diff --git a/src/androidvfs.c b/src/androidvfs.c index c326896d4c3..284b1370549 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -3023,6 +3023,104 @@ android_check_content_access (const char *uri, int mode) +/* Functions shared by authority and SAF nodes. */ + +/* Check for JNI exceptions, clear them, and set errno accordingly. + Also, free each of the N local references given as arguments if an + exception takes place. + + Value is 1 if an exception has taken place, 0 otherwise. + + If the exception thrown derives from FileNotFoundException, set + errno to ENOENT. + + If the exception thrown derives from SecurityException, set errno + to EACCES. + + If the exception thrown derives from OperationCanceledException, + set errno to EINTR. + + If the exception thrown derives from UnsupportedOperationException, + set errno to ENOSYS. + + If the exception thrown derives from OutOfMemoryException, call + `memory_full'. + + If the exception thrown is anything else, set errno to EIO. */ + +static int +android_saf_exception_check (int n, ...) +{ + jthrowable exception; + JNIEnv *env; + va_list ap; + int new_errno; + + env = android_java_env; + va_start (ap, n); + + /* First, check for an exception. */ + + if (!(*env)->ExceptionCheck (env)) + { + /* No exception has taken place. Return 0. */ + va_end (ap); + return 0; + } + + /* Print the exception. */ + (*env)->ExceptionDescribe (env); + + exception = (*env)->ExceptionOccurred (env); + + if (!exception) + /* JNI couldn't return a local reference to the exception. */ + memory_full (0); + + /* Clear the exception, making it safe to subsequently call other + JNI functions. */ + (*env)->ExceptionClear (env); + + /* Delete each of the N arguments. */ + + while (n > 0) + { + ANDROID_DELETE_LOCAL_REF (va_arg (ap, jobject)); + n--; + } + + /* Now set errno or signal memory_full as required. */ + + if ((*env)->IsInstanceOf (env, (jobject) exception, + file_not_found_exception)) + new_errno = ENOENT; + else if ((*env)->IsInstanceOf (env, (jobject) exception, + security_exception)) + new_errno = EACCES; + else if ((*env)->IsInstanceOf (env, (jobject) exception, + operation_canceled_exception)) + new_errno = EINTR; + else if ((*env)->IsInstanceOf (env, (jobject) exception, + unsupported_operation_exception)) + new_errno = ENOSYS; + else if ((*env)->IsInstanceOf (env, (jobject) exception, + out_of_memory_error)) + { + ANDROID_DELETE_LOCAL_REF ((jobject) exception); + memory_full (0); + } + else + new_errno = EIO; + + /* expression is still a local reference! */ + ANDROID_DELETE_LOCAL_REF ((jobject) exception); + errno = new_errno; + va_end (ap); + return 1; +} + + + /* Content authority-based vnode implementation. /content/by-authority is a simple vnode implementation that converts @@ -3201,7 +3299,9 @@ android_authority_open (struct android_vnode *vnode, int flags, (jboolean) !(mode & O_WRONLY), (jboolean) ((mode & O_TRUNC) != 0)); - android_exception_check_1 (string); + if (android_saf_exception_check (1, string)) + return -1; + ANDROID_DELETE_LOCAL_REF (string); /* If fd is -1, just assume that the file does not exist, and return -1 with errno set to ENOENT. */ @@ -3209,18 +3309,12 @@ android_authority_open (struct android_vnode *vnode, int flags, if (fd == -1) { errno = ENOENT; - goto skip; + return -1; } if (mode & O_CLOEXEC) android_close_on_exec (fd); - skip: - ANDROID_DELETE_LOCAL_REF (string); - - if (fd == -1) - return -1; - *fd_return = fd; return 0; } @@ -4089,100 +4183,6 @@ android_saf_root_get_directory (int dirfd) thread. */ static bool inside_saf_critical_section; -/* Check for JNI exceptions, clear them, and set errno accordingly. - Also, free each of the N local references given as arguments if an - exception takes place. - - Value is 1 if an exception has taken place, 0 otherwise. - - If the exception thrown derives from FileNotFoundException, set - errno to ENOENT. - - If the exception thrown derives from SecurityException, set errno - to EACCES. - - If the exception thrown derives from OperationCanceledException, - set errno to EINTR. - - If the exception thrown derives from UnsupportedOperationException, - set errno to ENOSYS. - - If the exception thrown derives from OutOfMemoryException, call - `memory_full'. - - If the exception thrown is anything else, set errno to EIO. */ - -static int -android_saf_exception_check (int n, ...) -{ - jthrowable exception; - JNIEnv *env; - va_list ap; - int new_errno; - - env = android_java_env; - va_start (ap, n); - - /* First, check for an exception. */ - - if (!(*env)->ExceptionCheck (env)) - { - /* No exception has taken place. Return 0. */ - va_end (ap); - return 0; - } - - /* Print the exception. */ - (*env)->ExceptionDescribe (env); - - exception = (*env)->ExceptionOccurred (env); - - if (!exception) - /* JNI couldn't return a local reference to the exception. */ - memory_full (0); - - /* Clear the exception, making it safe to subsequently call other - JNI functions. */ - (*env)->ExceptionClear (env); - - /* Delete each of the N arguments. */ - - while (n > 0) - { - ANDROID_DELETE_LOCAL_REF (va_arg (ap, jobject)); - n--; - } - - /* Now set errno or signal memory_full as required. */ - - if ((*env)->IsInstanceOf (env, (jobject) exception, - file_not_found_exception)) - new_errno = ENOENT; - else if ((*env)->IsInstanceOf (env, (jobject) exception, - security_exception)) - new_errno = EACCES; - else if ((*env)->IsInstanceOf (env, (jobject) exception, - operation_canceled_exception)) - new_errno = EINTR; - else if ((*env)->IsInstanceOf (env, (jobject) exception, - unsupported_operation_exception)) - new_errno = ENOSYS; - else if ((*env)->IsInstanceOf (env, (jobject) exception, - out_of_memory_error)) - { - ANDROID_DELETE_LOCAL_REF ((jobject) exception); - memory_full (0); - } - else - new_errno = EIO; - - /* expression is still a local reference! */ - ANDROID_DELETE_LOCAL_REF ((jobject) exception); - errno = new_errno; - va_end (ap); - return 1; -} - /* Return file status for the document designated by ID_NAME within the document tree identified by URI_NAME. @@ -6883,15 +6883,9 @@ android_vfs_init (JNIEnv *env, jobject manager) eassert (java_string_class); (*env)->DeleteLocalRef (env, old); - /* And initialize those used on Android 5.0 and later. */ - - if (android_get_current_api_level () < 21) + if (android_get_current_api_level () < 19) return; - android_init_cursor_class (env); - android_init_entry_class (env); - android_init_fd_class (env); - /* Initialize each of the exception classes used by `android_saf_exception_check'. */ @@ -6920,6 +6914,15 @@ android_vfs_init (JNIEnv *env, jobject manager) (*env)->DeleteLocalRef (env, old); eassert (out_of_memory_error); + /* And initialize those used on Android 5.0 and later. */ + + if (android_get_current_api_level () < 21) + return; + + android_init_cursor_class (env); + android_init_entry_class (env); + android_init_fd_class (env); + /* Initialize the semaphore used to wait for SAF operations to complete. */ -- 2.39.5