Improve efficiency of checking for access to authority documents

* java/org/gnu/emacs/EmacsService.java (checkContentUri): Take a
string instead of a byte array.  Then, use
checkCallingUriPermission, in lieu of opening the file.
* src/android.c (android_check_content_access): Delete unused
function.
(android_init_emacs_service): Adjust for changes to
checkContentUri's signature.
* src/androidvfs.c (android_get_content_name): Return the file
name in a new buffer.
(android_check_content_access): Adjust correspondingly.
(android_authority_name): Verify NAME is a valid JNI string.
This commit is contained in:
Po Lu 2023-08-14 13:15:08 +08:00
parent 3895f88233
commit 9fb00904f9
3 changed files with 51 additions and 89 deletions

View file

@ -960,44 +960,30 @@ invocation of app_process (through android-emacs) can
}
}
/* Return whether Emacs is directly permitted to access the
content:// URI NAME. This is not a suitable test for files which
Emacs can access by virtue of their containing document
trees. */
public boolean
checkContentUri (byte[] string, boolean readable, boolean writable)
checkContentUri (String name, boolean readable, boolean writable)
{
String mode, name;
String mode;
ParcelFileDescriptor fd;
Uri uri;
int rc, flags;
/* Decode this into a URI. */
uri = Uri.parse (name);
flags = 0;
try
{
/* The usual file name encoding question rears its ugly head
again. */
name = new String (string, "UTF-8");
}
catch (UnsupportedEncodingException exception)
{
name = null;
throw new RuntimeException (exception);
}
mode = "r";
if (readable)
flags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (writable)
mode += "w";
flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
try
{
fd = resolver.openFileDescriptor (Uri.parse (name), mode);
fd.close ();
return true;
}
catch (Exception exception)
{
/* Fall through. */
}
return false;
rc = checkCallingUriPermission (uri, flags);
return rc == PackageManager.PERMISSION_GRANTED;
}
/* Build a content file name for URI.

View file

@ -1107,41 +1107,6 @@ android_get_content_name (const char *filename)
return NULL;
}
/* Return whether or not the specified FILENAME is an accessible
content URI. MODE specifies what to check. */
static bool
android_check_content_access (const char *filename, int mode)
{
const char *name;
jobject string;
size_t length;
jboolean rc;
name = android_get_content_name (filename);
length = strlen (name);
string = (*android_java_env)->NewByteArray (android_java_env,
length);
android_exception_check ();
(*android_java_env)->SetByteArrayRegion (android_java_env,
string, 0, length,
(jbyte *) name);
rc = (*android_java_env)->CallBooleanMethod (android_java_env,
emacs_service,
service_class.check_content_uri,
string,
(jboolean) ((mode & R_OK)
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
}
#endif /* 0 */
/* Return the current user's ``home'' directory, which is actually the
@ -1549,7 +1514,7 @@ android_init_emacs_service (void)
FIND_METHOD (open_content_uri, "openContentUri",
"([BZZZ)I");
FIND_METHOD (check_content_uri, "checkContentUri",
"([BZZ)Z");
"(Ljava/lang/String;ZZ)Z");
FIND_METHOD (query_battery, "queryBattery", "()[J");
FIND_METHOD (update_extracted_text, "updateExtractedText",
"(Lorg/gnu/emacs/EmacsWindow;"

View file

@ -2765,14 +2765,13 @@ android_content_initial (char *name, size_t length)
/* Return the content URI corresponding to a `/content/by-authority'
file name, or NULL if it is invalid for some reason. FILENAME
should be relative to /content/by-authority, with no leading
directory separator character.
directory separator character. */
This function is not reentrant. */
static const char *
static char *
android_get_content_name (const char *filename)
{
static char buffer[PATH_MAX + 1], *fill;
char *fill, *buffer;
size_t length;
/* Make sure FILENAME isn't obviously invalid: it must contain an
authority name and a file name component. */
@ -2784,48 +2783,53 @@ android_get_content_name (const char *filename)
return NULL;
}
/* FILENAME must also not be a directory. */
/* FILENAME must also not be a directory. Accessing content
provider directories is not supported by this interface. */
if (filename[strlen (filename)] == '/')
length = strlen (filename);
if (filename[length] == '/')
{
errno = ENOTDIR;
return NULL;
}
snprintf (buffer, PATH_MAX + 1, "content://%s", filename);
/* Prefix FILENAME with content:// and return the buffer containing
that URI. */
buffer = xmalloc (sizeof "content://" + length);
sprintf (buffer, "content://%s", filename);
return buffer;
}
/* Return whether or not the specified URI is an accessible content
URI. MODE specifies what to check. */
URI. MODE specifies what to check.
URI must be a string in the JVM's extended UTF-8 format. */
static bool
android_check_content_access (const char *uri, int mode)
{
jobject string;
size_t length;
jboolean rc;
jboolean rc, read, write;
length = strlen (uri);
string = (*android_java_env)->NewByteArray (android_java_env,
length);
string = (*android_java_env)->NewStringUTF (android_java_env, uri);
android_exception_check ();
(*android_java_env)->SetByteArrayRegion (android_java_env,
string, 0, length,
(jbyte *) uri);
/* Establish what is being checked. Checking for read access is
identical to checking if the file exists. */
read = (bool) (mode & R_OK || (mode == F_OK));
write = (bool) (mode & W_OK);
rc = (*android_java_env)->CallBooleanMethod (android_java_env,
emacs_service,
service_class.check_content_uri,
string,
(jboolean) ((mode & R_OK)
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
string, read, write);
android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
}
@ -2889,7 +2893,7 @@ android_authority_name (struct android_vnode *vnode, char *name,
size_t length)
{
struct android_authority_vnode *vp;
const char *uri_name;
char *uri_name;
if (!android_init_gui)
{
@ -2922,6 +2926,12 @@ android_authority_name (struct android_vnode *vnode, char *name,
if (*name == '/')
name++, length -= 1;
/* NAME must be a valid JNI string, so that it can be encoded
properly. */
if (android_verify_jni_string (name))
goto no_entry;
uri_name = android_get_content_name (name);
if (!uri_name)
goto error;
@ -2931,11 +2941,12 @@ android_authority_name (struct android_vnode *vnode, char *name,
vp->vnode.ops = &authority_vfs_ops;
vp->vnode.type = ANDROID_VNODE_CONTENT_AUTHORITY;
vp->vnode.flags = 0;
vp->uri = xstrdup (uri_name);
vp->uri = uri_name;
return &vp->vnode;
}
/* Content files can't have children. */
no_entry:
errno = ENOENT;
error:
return NULL;