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.
This commit is contained in:
Po Lu 2024-05-10 09:05:54 +08:00
parent d335f28aa9
commit c900c707e8
2 changed files with 116 additions and 110 deletions

View file

@ -968,7 +968,7 @@ invocation of app_process (through android-emacs) can
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 @@ invocation of app_process (through android-emacs) can
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 ();

View file

@ -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. */