diff options
| author | Po Lu | 2023-08-01 21:06:06 +0800 |
|---|---|---|
| committer | Po Lu | 2023-08-01 21:06:06 +0800 |
| commit | e41349dd93ffec2b1e383cb4c4dfdb59f6e7edac (patch) | |
| tree | 0fcd44202d335331c554ebab0730467329729ad0 /src | |
| parent | b022398b8f0a03f0e1b3ec8df41a439cdbe5bd19 (diff) | |
| download | emacs-e41349dd93ffec2b1e383cb4c4dfdb59f6e7edac.tar.gz emacs-e41349dd93ffec2b1e383cb4c4dfdb59f6e7edac.zip | |
Update Android port
* doc/emacs/android.texi (Android File System): Describe how to
access real files named /assets or /contents if so required.
* java/org/gnu/emacs/EmacsService.java (validAuthority):
* src/android.c (android_init_emacs_service):
* src/android.h: New function.
* src/androidvfs.c (android_saf_valid_authority_p): New
function. Wrap the Java function.
(android_saf_root_stat, android_saf_root_access): Don't return
success if no authority by vp->authority's name exists.
(android_saf_tree_from_name): Check validity of string data
before giving it to JNI.
Diffstat (limited to 'src')
| -rw-r--r-- | src/android.c | 2 | ||||
| -rw-r--r-- | src/android.h | 1 | ||||
| -rw-r--r-- | src/androidvfs.c | 91 |
3 files changed, 87 insertions, 7 deletions
diff --git a/src/android.c b/src/android.c index 2b785319549..c30d7b58979 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -1592,6 +1592,8 @@ android_init_emacs_service (void) | |||
| 1592 | "(Ljava/lang/String;Ljava/lang/String;" | 1592 | "(Ljava/lang/String;Ljava/lang/String;" |
| 1593 | "Ljava/lang/String;Ljava/lang/String;" | 1593 | "Ljava/lang/String;Ljava/lang/String;" |
| 1594 | "Ljava/lang/String;)Ljava/lang/String;"); | 1594 | "Ljava/lang/String;)Ljava/lang/String;"); |
| 1595 | FIND_METHOD (valid_authority, "validAuthority", | ||
| 1596 | "(Ljava/lang/String;)Z"); | ||
| 1595 | #undef FIND_METHOD | 1597 | #undef FIND_METHOD |
| 1596 | } | 1598 | } |
| 1597 | 1599 | ||
diff --git a/src/android.h b/src/android.h index 8440fb9bc75..945bd649c18 100644 --- a/src/android.h +++ b/src/android.h | |||
| @@ -284,6 +284,7 @@ struct android_emacs_service | |||
| 284 | jmethodID delete_document; | 284 | jmethodID delete_document; |
| 285 | jmethodID rename_document; | 285 | jmethodID rename_document; |
| 286 | jmethodID move_document; | 286 | jmethodID move_document; |
| 287 | jmethodID valid_authority; | ||
| 287 | }; | 288 | }; |
| 288 | 289 | ||
| 289 | extern JNIEnv *android_java_env; | 290 | extern JNIEnv *android_java_env; |
diff --git a/src/androidvfs.c b/src/androidvfs.c index eeef5ea5db0..e3b0b895df3 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c | |||
| @@ -3249,6 +3249,43 @@ static struct android_saf_root_vdir *all_saf_root_vdirs; | |||
| 3249 | static struct android_vnode *android_saf_tree_from_name (char *, const char *, | 3249 | static struct android_vnode *android_saf_tree_from_name (char *, const char *, |
| 3250 | const char *); | 3250 | const char *); |
| 3251 | 3251 | ||
| 3252 | /* Forward declaration. */ | ||
| 3253 | static int android_verify_jni_string (const char *); | ||
| 3254 | |||
| 3255 | /* Ascertain and return whether or not AUTHORITY designates a content | ||
| 3256 | provider offering at least one directory tree accessible to | ||
| 3257 | Emacs. */ | ||
| 3258 | |||
| 3259 | static bool | ||
| 3260 | android_saf_valid_authority_p (const char *authority) | ||
| 3261 | { | ||
| 3262 | jobject string; | ||
| 3263 | jboolean valid; | ||
| 3264 | jmethodID method; | ||
| 3265 | |||
| 3266 | /* Make certain AUTHORITY can actually be represented as a Java | ||
| 3267 | string. */ | ||
| 3268 | |||
| 3269 | if (android_verify_jni_string (authority)) | ||
| 3270 | return false; | ||
| 3271 | |||
| 3272 | /* Build a string containing AUTHORITY. */ | ||
| 3273 | |||
| 3274 | string = (*android_java_env)->NewStringUTF (android_java_env, | ||
| 3275 | authority); | ||
| 3276 | android_exception_check (); | ||
| 3277 | |||
| 3278 | method = service_class.valid_authority; | ||
| 3279 | valid | ||
| 3280 | = (*android_java_env)->CallNonvirtualBooleanMethod (android_java_env, | ||
| 3281 | emacs_service, | ||
| 3282 | service_class.class, | ||
| 3283 | method, string); | ||
| 3284 | android_exception_check_1 (string); | ||
| 3285 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 3286 | return valid; | ||
| 3287 | } | ||
| 3288 | |||
| 3252 | static struct android_vnode * | 3289 | static struct android_vnode * |
| 3253 | android_saf_root_name (struct android_vnode *vnode, char *name, | 3290 | android_saf_root_name (struct android_vnode *vnode, char *name, |
| 3254 | size_t length) | 3291 | size_t length) |
| @@ -3311,9 +3348,6 @@ android_saf_root_name (struct android_vnode *vnode, char *name, | |||
| 3311 | return android_saf_tree_from_name (component_end, component, | 3348 | return android_saf_tree_from_name (component_end, component, |
| 3312 | vp->authority); | 3349 | vp->authority); |
| 3313 | 3350 | ||
| 3314 | /* Otherwise, find the first component of NAME and create a vnode | ||
| 3315 | representing it as an authority. */ | ||
| 3316 | |||
| 3317 | /* Create the vnode. */ | 3351 | /* Create the vnode. */ |
| 3318 | vp = xmalloc (sizeof *vp); | 3352 | vp = xmalloc (sizeof *vp); |
| 3319 | vp->vnode.ops = &saf_root_vfs_ops; | 3353 | vp->vnode.ops = &saf_root_vfs_ops; |
| @@ -3414,6 +3448,22 @@ static int | |||
| 3414 | android_saf_root_stat (struct android_vnode *vnode, | 3448 | android_saf_root_stat (struct android_vnode *vnode, |
| 3415 | struct stat *statb) | 3449 | struct stat *statb) |
| 3416 | { | 3450 | { |
| 3451 | struct android_saf_root_vnode *vp; | ||
| 3452 | |||
| 3453 | /* Verify that the authority actually exists and return ENOENT | ||
| 3454 | otherwise, lest `locate-dominating-file' & co call an operation | ||
| 3455 | that doesn't require listing URIs under this authority, such as | ||
| 3456 | access. */ | ||
| 3457 | |||
| 3458 | vp = (struct android_saf_root_vnode *) vnode; | ||
| 3459 | |||
| 3460 | if (vp->authority | ||
| 3461 | && !android_saf_valid_authority_p (vp->authority)) | ||
| 3462 | { | ||
| 3463 | errno = ENOENT; | ||
| 3464 | return -1; | ||
| 3465 | } | ||
| 3466 | |||
| 3417 | /* Make up some imaginary statistics for this vnode. */ | 3467 | /* Make up some imaginary statistics for this vnode. */ |
| 3418 | 3468 | ||
| 3419 | memset (statb, 0, sizeof *statb); | 3469 | memset (statb, 0, sizeof *statb); |
| @@ -3428,6 +3478,8 @@ android_saf_root_stat (struct android_vnode *vnode, | |||
| 3428 | static int | 3478 | static int |
| 3429 | android_saf_root_access (struct android_vnode *vnode, int mode) | 3479 | android_saf_root_access (struct android_vnode *vnode, int mode) |
| 3430 | { | 3480 | { |
| 3481 | struct android_saf_root_vnode *vp; | ||
| 3482 | |||
| 3431 | /* Validate MODE. */ | 3483 | /* Validate MODE. */ |
| 3432 | 3484 | ||
| 3433 | if (mode != F_OK && !(mode & (W_OK | X_OK | R_OK))) | 3485 | if (mode != F_OK && !(mode & (W_OK | X_OK | R_OK))) |
| @@ -3444,6 +3496,20 @@ android_saf_root_access (struct android_vnode *vnode, int mode) | |||
| 3444 | return -1; | 3496 | return -1; |
| 3445 | } | 3497 | } |
| 3446 | 3498 | ||
| 3499 | /* Verify that the authority actually exists and return ENOENT | ||
| 3500 | otherwise, lest `locate-dominating-file' & co call an operation | ||
| 3501 | that doesn't require listing URIs under this authority, such as | ||
| 3502 | access. */ | ||
| 3503 | |||
| 3504 | vp = (struct android_saf_root_vnode *) vnode; | ||
| 3505 | |||
| 3506 | if (vp->authority | ||
| 3507 | && !android_saf_valid_authority_p (vp->authority)) | ||
| 3508 | { | ||
| 3509 | errno = ENOENT; | ||
| 3510 | return -1; | ||
| 3511 | } | ||
| 3512 | |||
| 3447 | return 0; | 3513 | return 0; |
| 3448 | } | 3514 | } |
| 3449 | 3515 | ||
| @@ -5309,9 +5375,9 @@ android_saf_tree_opendir (struct android_vnode *vnode) | |||
| 5309 | AUTHORITY is the name of the content provider authority that is | 5375 | AUTHORITY is the name of the content provider authority that is |
| 5310 | offering TREE. | 5376 | offering TREE. |
| 5311 | 5377 | ||
| 5312 | Value is NULL if no document tree or provider by those names | 5378 | Value is NULL and errno is set if no document tree or provider by |
| 5313 | exists, or some other error takes place (for example, if TREE and | 5379 | those names exists, or some other error takes place (for example, |
| 5314 | AUTHORITY aren't encoded correctly.) */ | 5380 | if TREE and AUTHORITY aren't encoded correctly.) */ |
| 5315 | 5381 | ||
| 5316 | static struct android_vnode * | 5382 | static struct android_vnode * |
| 5317 | android_saf_tree_from_name (char *name, const char *tree, | 5383 | android_saf_tree_from_name (char *name, const char *tree, |
| @@ -5323,7 +5389,18 @@ android_saf_tree_from_name (char *name, const char *tree, | |||
| 5323 | const char *uri; | 5389 | const char *uri; |
| 5324 | struct android_vnode *vp; | 5390 | struct android_vnode *vp; |
| 5325 | 5391 | ||
| 5326 | /* Assume that TREE and NAME are in ``modified UTF-8 format''. */ | 5392 | /* It's not a given that NAME and TREE are actually in the modified |
| 5393 | UTF-8 format used by the JVM to encode strings, and the JVM | ||
| 5394 | aborts when encountering a string that is not. Make sure they | ||
| 5395 | are valid before continuing. */ | ||
| 5396 | |||
| 5397 | if (android_verify_jni_string (name) | ||
| 5398 | || android_verify_jni_string (authority)) | ||
| 5399 | { | ||
| 5400 | errno = ENOENT; | ||
| 5401 | return NULL; | ||
| 5402 | } | ||
| 5403 | |||
| 5327 | tree_string = (*android_java_env)->NewStringUTF (android_java_env, | 5404 | tree_string = (*android_java_env)->NewStringUTF (android_java_env, |
| 5328 | tree); | 5405 | tree); |
| 5329 | android_exception_check (); | 5406 | android_exception_check (); |