}
}
+ /* 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. */
-
- 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);
- }
+ uri = Uri.parse (name);
+ flags = 0;
- mode = "r";
+ if (readable)
+ flags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (writable)
- mode += "w";
-
- try
- {
- fd = resolver.openFileDescriptor (Uri.parse (name), mode);
- fd.close ();
+ flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- 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.
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
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;"
/* 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. */
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;
}
size_t length)
{
struct android_authority_vnode *vp;
- const char *uri_name;
+ char *uri_name;
if (!android_init_gui)
{
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;
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;