aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-07-28 12:21:47 +0800
committerPo Lu2023-07-28 12:21:47 +0800
commit03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3 (patch)
treea8d55088a6efed2cbe4b0bfad1c1bde61579b54e /src
parent7c0899586471d3649dfb468d2b8f7d6d9685fea1 (diff)
downloademacs-03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3.tar.gz
emacs-03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3.zip
Update Android port
* java/org/gnu/emacs/EmacsDirectoryEntry.java (EmacsDirectoryEntry): Make class final. * java/org/gnu/emacs/EmacsService.java (accessDocument) (openDocumentDirectory, openDocument, createDocument): Throw access and IO error exceptions instead of catching them. (createDirectory, deleteDocument): New functions. * src/android.c (android_init_emacs_service): Add new functions. * src/android.h (struct android_emacs_service): Likewise. * src/androidvfs.c (android_saf_exception_check): New function. Translate between Java exceptions and errno values. (android_saf_stat, android_saf_access, android_saf_delete_document) (struct android_saf_tree_vnode, android_document_id_from_name) (android_saf_tree_name, android_saf_tree_rmdir) (android_saf_tree_opendir_1, android_saf_tree_opendir) (android_saf_file_open, android_saf_file_unlink) (android_saf_new_open, android_saf_new_mkdir): Implement missing VFS operations and derive errno values from the type of any exceptions thrown. (android_vfs_init): Initialize exception classes. (android_mkdir, android_fstat): Remove trailing whitespace.
Diffstat (limited to 'src')
-rw-r--r--src/android.c5
-rw-r--r--src/android.h2
-rw-r--r--src/androidvfs.c316
3 files changed, 291 insertions, 32 deletions
diff --git a/src/android.c b/src/android.c
index 098fa6c383d..687c0b48a2a 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1577,6 +1577,11 @@ android_init_emacs_service (void)
1577 FIND_METHOD (create_document, "createDocument", 1577 FIND_METHOD (create_document, "createDocument",
1578 "(Ljava/lang/String;Ljava/lang/String;" 1578 "(Ljava/lang/String;Ljava/lang/String;"
1579 "Ljava/lang/String;)Ljava/lang/String;"); 1579 "Ljava/lang/String;)Ljava/lang/String;");
1580 FIND_METHOD (create_directory, "createDirectory",
1581 "(Ljava/lang/String;Ljava/lang/String;"
1582 "Ljava/lang/String;)Ljava/lang/String;");
1583 FIND_METHOD (delete_document, "deleteDocument",
1584 "(Ljava/lang/String;Ljava/lang/String;)I");
1580#undef FIND_METHOD 1585#undef FIND_METHOD
1581} 1586}
1582 1587
diff --git a/src/android.h b/src/android.h
index 94a3ad46e74..fd391fa6435 100644
--- a/src/android.h
+++ b/src/android.h
@@ -279,6 +279,8 @@ struct android_emacs_service
279 jmethodID read_directory_entry; 279 jmethodID read_directory_entry;
280 jmethodID open_document; 280 jmethodID open_document;
281 jmethodID create_document; 281 jmethodID create_document;
282 jmethodID create_directory;
283 jmethodID delete_document;
282}; 284};
283 285
284extern JNIEnv *android_java_env; 286extern JNIEnv *android_java_env;
diff --git a/src/androidvfs.c b/src/androidvfs.c
index c174c35f02b..2cd50963e97 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -276,6 +276,10 @@ static struct emacs_directory_entry_class entry_class;
276 class. */ 276 class. */
277static struct android_parcel_file_descriptor_class fd_class; 277static struct android_parcel_file_descriptor_class fd_class;
278 278
279/* Global references to several exception classes. */
280static jclass file_not_found_exception, security_exception;
281static jclass unsupported_operation_exception, out_of_memory_error;
282
279/* Initialize `cursor_class' using the given JNI environment ENV. 283/* Initialize `cursor_class' using the given JNI environment ENV.
280 Calling this function is not necessary on Android 4.4 and 284 Calling this function is not necessary on Android 4.4 and
281 earlier. */ 285 earlier. */
@@ -3688,6 +3692,85 @@ android_saf_root_get_directory (int dirfd)
3688 3692
3689/* Functions common to both SAF directory and file nodes. */ 3693/* Functions common to both SAF directory and file nodes. */
3690 3694
3695/* Check for JNI exceptions, clear them, and set errno accordingly.
3696 Also, free each of the N local references given as arguments if an
3697 exception takes place.
3698
3699 Value is 1 if an exception has taken place, 0 otherwise.
3700
3701 If the exception thrown derives from FileNotFoundException, set
3702 errno to ENOENT.
3703
3704 If the exception thrown derives from SecurityException, set errno
3705 to EACCES.
3706
3707 If the exception thrown derives from UnsupportedOperationException,
3708 set errno to ENOSYS.
3709
3710 If the exception thrown derives from OutOfMemoryException, call
3711 `memory_full'.
3712
3713 If the exception thrown is anything else, set errno to EIO. */
3714
3715static int
3716android_saf_exception_check (int n, ...)
3717{
3718 jthrowable exception;
3719 JNIEnv *env;
3720 va_list ap;
3721
3722 env = android_java_env;
3723 va_start (ap, n);
3724
3725 /* First, check for an exception. */
3726
3727 if (!(*env)->ExceptionCheck (env))
3728 /* No exception has taken place. Return 0. */
3729 return 0;
3730
3731 exception = (*env)->ExceptionOccurred (env);
3732
3733 if (!exception)
3734 /* JNI couldn't return a local reference to the exception. */
3735 memory_full (0);
3736
3737 /* Clear the exception, making it safe to subsequently call other
3738 JNI functions. */
3739 (*env)->ExceptionClear (env);
3740
3741 /* Delete each of the N arguments. */
3742
3743 while (n > 0)
3744 {
3745 ANDROID_DELETE_LOCAL_REF (va_arg (ap, jobject));
3746 n--;
3747 }
3748
3749 /* Now set errno or signal memory_full as required. */
3750
3751 if ((*env)->IsInstanceOf (env, (jobject) exception,
3752 file_not_found_exception))
3753 errno = ENOENT;
3754 else if ((*env)->IsInstanceOf (env, (jobject) exception,
3755 security_exception))
3756 errno = EACCES;
3757 else if ((*env)->IsInstanceOf (env, (jobject) exception,
3758 unsupported_operation_exception))
3759 errno = ENOSYS;
3760 else if ((*env)->IsInstanceOf (env, (jobject) exception,
3761 out_of_memory_error))
3762 {
3763 ANDROID_DELETE_LOCAL_REF ((jobject) exception);
3764 memory_full (0);
3765 }
3766 else
3767 errno = EIO;
3768
3769 /* expression is still a local reference! */
3770 ANDROID_DELETE_LOCAL_REF ((jobject) exception);
3771 return 1;
3772}
3773
3691/* Return file status for the document designated by ID_NAME within 3774/* Return file status for the document designated by ID_NAME within
3692 the document tree identified by URI_NAME. 3775 the document tree identified by URI_NAME.
3693 3776
@@ -3727,11 +3810,13 @@ android_saf_stat (const char *uri_name, const char *id_name,
3727 3810
3728 if (id) 3811 if (id)
3729 { 3812 {
3730 android_exception_check_2 (uri, id); 3813 if (android_saf_exception_check (2, uri, id))
3814 return -1;
3815
3731 ANDROID_DELETE_LOCAL_REF (id); 3816 ANDROID_DELETE_LOCAL_REF (id);
3732 } 3817 }
3733 else 3818 else if (android_saf_exception_check (1, uri))
3734 android_exception_check_1 (uri); 3819 return -1;
3735 3820
3736 ANDROID_DELETE_LOCAL_REF (uri); 3821 ANDROID_DELETE_LOCAL_REF (uri);
3737 3822
@@ -3810,11 +3895,13 @@ android_saf_access (const char *uri_name, const char *id_name,
3810 3895
3811 if (id) 3896 if (id)
3812 { 3897 {
3813 android_exception_check_2 (uri, id); 3898 if (android_saf_exception_check (2, uri, id))
3899 return -1;
3900
3814 ANDROID_DELETE_LOCAL_REF (id); 3901 ANDROID_DELETE_LOCAL_REF (id);
3815 } 3902 }
3816 else 3903 else if (android_saf_exception_check (1, uri))
3817 android_exception_check_1 (uri); 3904 return -1;
3818 3905
3819 ANDROID_DELETE_LOCAL_REF (uri); 3906 ANDROID_DELETE_LOCAL_REF (uri);
3820 3907
@@ -3840,6 +3927,46 @@ android_saf_access (const char *uri_name, const char *id_name,
3840 return 0; 3927 return 0;
3841} 3928}
3842 3929
3930/* Delete the document designated by DOC_ID within the tree identified
3931 through the URI TREE. Return 0 if the document has been deleted,
3932 set errno and return -1 upon failure. */
3933
3934static int
3935android_saf_delete_document (const char *tree, const char *doc_id)
3936{
3937 jobject id, uri;
3938 jmethodID method;
3939 jint rc;
3940
3941 /* Build the strings holding the ID and URI. */
3942 id = (*android_java_env)->NewStringUTF (android_java_env,
3943 doc_id);
3944 android_exception_check ();
3945 uri = (*android_java_env)->NewStringUTF (android_java_env,
3946 tree);
3947 android_exception_check_1 (id);
3948
3949 /* Now, try to delete the document. */
3950 method = service_class.delete_document;
3951 rc = (*android_java_env)->CallIntMethod (android_java_env,
3952 emacs_service,
3953 method, uri, id);
3954
3955 if (android_saf_exception_check (2, id, uri))
3956 return -1;
3957
3958 ANDROID_DELETE_LOCAL_REF (id);
3959 ANDROID_DELETE_LOCAL_REF (uri);
3960
3961 if (rc)
3962 {
3963 errno = EACCES;
3964 return -1;
3965 }
3966
3967 return 0;
3968}
3969
3843 3970
3844 3971
3845/* SAF directory vnode. A file within a SAF directory tree is 3972/* SAF directory vnode. A file within a SAF directory tree is
@@ -3863,7 +3990,9 @@ struct android_saf_tree_vnode
3863 char *tree_id; 3990 char *tree_id;
3864 3991
3865 /* The document ID of the directory represented, or NULL if this is 3992 /* The document ID of the directory represented, or NULL if this is
3866 the root directory of the tree. */ 3993 the root directory of the tree. Since file and new vnodes don't
3994 represent the root directory, this field is always set in
3995 them. */
3867 char *document_id; 3996 char *document_id;
3868 3997
3869 /* The file name of this tree vnode. This is a ``path'' to the 3998 /* The file name of this tree vnode. This is a ``path'' to the
@@ -4004,7 +4133,7 @@ android_verify_jni_string (const char *name)
4004 must name a directory file within TREE_URI. 4133 must name a directory file within TREE_URI.
4005 4134
4006 If NAME is not correct for the Java ``modified UTF-8'' coding 4135 If NAME is not correct for the Java ``modified UTF-8'' coding
4007 system, return -1. 4136 system, return -1 and set errno to ENOENT.
4008 4137
4009 Upon success, return 0 or 1 (contingent upon whether or not the 4138 Upon success, return 0 or 1 (contingent upon whether or not the
4010 last component within NAME is a directory) and place the document 4139 last component within NAME is a directory) and place the document
@@ -4014,7 +4143,8 @@ android_verify_jni_string (const char *name)
4014 within NAME does and is also a directory, return -2 and place the 4143 within NAME does and is also a directory, return -2 and place the
4015 document ID of that directory within *ID. 4144 document ID of that directory within *ID.
4016 4145
4017 If the designated file can't be located, return -1. */ 4146 If the designated file can't be located, return -1 and set errno
4147 accordingly. */
4018 4148
4019static int 4149static int
4020android_document_id_from_name (const char *tree_uri, char *name, 4150android_document_id_from_name (const char *tree_uri, char *name,
@@ -4023,7 +4153,6 @@ android_document_id_from_name (const char *tree_uri, char *name,
4023 jobjectArray result; 4153 jobjectArray result;
4024 jstring uri; 4154 jstring uri;
4025 jbyteArray java_name; 4155 jbyteArray java_name;
4026 size_t length;
4027 jint rc; 4156 jint rc;
4028 jmethodID method; 4157 jmethodID method;
4029 const char *doc_id; 4158 const char *doc_id;
@@ -4055,7 +4184,10 @@ android_document_id_from_name (const char *tree_uri, char *name,
4055 method, 4184 method,
4056 uri, java_name, 4185 uri, java_name,
4057 result); 4186 result);
4058 android_exception_check_3 (result, uri, java_name); 4187
4188 if (android_saf_exception_check (3, result, uri, java_name))
4189 goto finish;
4190
4059 ANDROID_DELETE_LOCAL_REF (uri); 4191 ANDROID_DELETE_LOCAL_REF (uri);
4060 ANDROID_DELETE_LOCAL_REF (java_name); 4192 ANDROID_DELETE_LOCAL_REF (java_name);
4061 4193
@@ -4178,7 +4310,6 @@ android_saf_tree_name (struct android_vnode *vnode, char *name,
4178 4310
4179 /* The document ID can't be found. */ 4311 /* The document ID can't be found. */
4180 xfree (filename); 4312 xfree (filename);
4181 errno = ENOENT;
4182 return NULL; 4313 return NULL;
4183 } 4314 }
4184 4315
@@ -4354,9 +4485,19 @@ android_saf_tree_symlink (const char *target, struct android_vnode *vnode)
4354static int 4485static int
4355android_saf_tree_rmdir (struct android_vnode *vnode) 4486android_saf_tree_rmdir (struct android_vnode *vnode)
4356{ 4487{
4357 /* TODO */ 4488 struct android_saf_tree_vnode *vp;
4358 errno = ENOSYS; 4489
4359 return -1; 4490 vp = (struct android_saf_tree_vnode *) vnode;
4491
4492 /* Don't allow deleting the root directory. */
4493
4494 if (!vp->document_id)
4495 {
4496 errno = EROFS;
4497 return -1;
4498 }
4499
4500 return android_saf_delete_document (vp->tree_uri, vp->document_id);
4360} 4501}
4361 4502
4362static int 4503static int
@@ -4412,8 +4553,8 @@ android_saf_tree_mkdir (struct android_vnode *vnode, mode_t mode)
4412/* Open a database Cursor containing each directory entry within the 4553/* Open a database Cursor containing each directory entry within the
4413 supplied SAF tree vnode VP. 4554 supplied SAF tree vnode VP.
4414 4555
4415 Value is NULL upon failure, a local reference to the Cursor object 4556 Value is NULL upon failure with errno set to a suitable value, a
4416 otherwise. */ 4557 local reference to the Cursor object otherwise. */
4417 4558
4418static jobject 4559static jobject
4419android_saf_tree_opendir_1 (struct android_saf_tree_vnode *vp) 4560android_saf_tree_opendir_1 (struct android_saf_tree_vnode *vp)
@@ -4445,11 +4586,13 @@ android_saf_tree_opendir_1 (struct android_saf_tree_vnode *vp)
4445 4586
4446 if (id) 4587 if (id)
4447 { 4588 {
4448 android_exception_check_2 (id, uri); 4589 if (android_saf_exception_check (2, id, uri))
4590 return NULL;
4591
4449 ANDROID_DELETE_LOCAL_REF (id); 4592 ANDROID_DELETE_LOCAL_REF (id);
4450 } 4593 }
4451 else 4594 else if (android_saf_exception_check (1, uri))
4452 android_exception_check_1 (uri); 4595 return NULL;
4453 4596
4454 ANDROID_DELETE_LOCAL_REF (uri); 4597 ANDROID_DELETE_LOCAL_REF (uri);
4455 4598
@@ -4657,7 +4800,6 @@ android_saf_tree_opendir (struct android_vnode *vnode)
4657 { 4800 {
4658 xfree (dir); 4801 xfree (dir);
4659 xfree (dir->name); 4802 xfree (dir->name);
4660 errno = ENOENT;
4661 return NULL; 4803 return NULL;
4662 } 4804 }
4663 4805
@@ -4880,7 +5022,10 @@ android_saf_file_open (struct android_vnode *vnode, int flags,
4880 service_class.class, 5022 service_class.class,
4881 method, uri, id, 5023 method, uri, id,
4882 write, trunc); 5024 write, trunc);
4883 android_exception_check_2 (uri, id); 5025
5026 if (android_saf_exception_check (2, uri, id))
5027 return -1;
5028
4884 ANDROID_DELETE_LOCAL_REF (uri); 5029 ANDROID_DELETE_LOCAL_REF (uri);
4885 ANDROID_DELETE_LOCAL_REF (id); 5030 ANDROID_DELETE_LOCAL_REF (id);
4886 5031
@@ -4953,9 +5098,10 @@ android_saf_file_open (struct android_vnode *vnode, int flags,
4953static int 5098static int
4954android_saf_file_unlink (struct android_vnode *vnode) 5099android_saf_file_unlink (struct android_vnode *vnode)
4955{ 5100{
4956 /* TODO */ 5101 struct android_saf_file_vnode *vp;
4957 errno = ENOSYS; 5102
4958 return -1; 5103 vp = (struct android_saf_file_vnode *) vnode;
5104 return android_saf_delete_document (vp->tree_uri, vp->document_id);
4959} 5105}
4960 5106
4961static int 5107static int
@@ -5114,7 +5260,7 @@ android_saf_new_open (struct android_vnode *vnode, int flags,
5114 { 5260 {
5115 errno = ENOENT; 5261 errno = ENOENT;
5116 return -1; 5262 return -1;
5117 } 5263 }
5118 5264
5119 /* Otherwise, try to create a new document. First, build strings 5265 /* Otherwise, try to create a new document. First, build strings
5120 for the name, ID and document URI. */ 5266 for the name, ID and document URI. */
@@ -5137,7 +5283,9 @@ android_saf_new_open (struct android_vnode *vnode, int flags,
5137 service_class.class, 5283 service_class.class,
5138 method, uri, id, 5284 method, uri, id,
5139 name); 5285 name);
5140 android_exception_check_3 (name, id, uri); 5286
5287 if (android_saf_exception_check (3, name, id, uri))
5288 return -1;
5141 5289
5142 /* Delete unused local references. */ 5290 /* Delete unused local references. */
5143 ANDROID_DELETE_LOCAL_REF (name); 5291 ANDROID_DELETE_LOCAL_REF (name);
@@ -5225,9 +5373,90 @@ android_saf_new_access (struct android_vnode *vnode, int mode)
5225static int 5373static int
5226android_saf_new_mkdir (struct android_vnode *vnode, mode_t mode) 5374android_saf_new_mkdir (struct android_vnode *vnode, mode_t mode)
5227{ 5375{
5228 /* TODO */ 5376 struct android_saf_new_vnode *vp;
5229 errno = ENOSYS; 5377 jstring name, id, uri, new_id;
5230 return -1; 5378 jmethodID method;
5379 const char *new_doc_id;
5380 char *end;
5381
5382 vp = (struct android_saf_tree_vnode *) vnode;
5383
5384 /* Find the last component of vp->name. */
5385 end = strrchr (vp->name, '/');
5386
5387 /* VP->name must contain at least one directory separator. */
5388 eassert (end);
5389
5390 if (end[1] == '\0')
5391 {
5392 /* There's a trailing directory separator. Search
5393 backwards. */
5394
5395 end--;
5396 while (end != vp->name && *end != '/')
5397 end--;
5398
5399 /* vp->name[0] is always a directory separator. */
5400 eassert (*end == '/');
5401 }
5402
5403 /* Otherwise, try to create a new document. First, build strings
5404 for the name, ID and document URI. */
5405
5406 name = (*android_java_env)->NewStringUTF (android_java_env,
5407 end + 1);
5408 android_exception_check ();
5409 id = (*android_java_env)->NewStringUTF (android_java_env,
5410 vp->document_id);
5411 android_exception_check_1 (name);
5412 uri = (*android_java_env)->NewStringUTF (android_java_env,
5413 vp->tree_uri);
5414 android_exception_check_2 (name, id);
5415
5416 /* Next, try to create a new document and retrieve its ID. */
5417
5418 method = service_class.create_directory;
5419 new_id = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env,
5420 emacs_service,
5421 service_class.class,
5422 method, uri, id,
5423 name);
5424
5425 if (android_saf_exception_check (3, name, id, uri))
5426 return -1;
5427
5428 /* Delete unused local references. */
5429 ANDROID_DELETE_LOCAL_REF (name);
5430 ANDROID_DELETE_LOCAL_REF (id);
5431 ANDROID_DELETE_LOCAL_REF (uri);
5432
5433 if (!new_id)
5434 {
5435 /* The file couldn't be created for some reason. */
5436 errno = EIO;
5437 return -1;
5438 }
5439
5440 /* Now, free VP->document_id and replace it with the service
5441 document ID. */
5442
5443 new_doc_id = (*android_java_env)->GetStringUTFChars (android_java_env,
5444 new_id, NULL);
5445
5446 if (android_saf_exception_check (3, name, id, uri))
5447 return -1;
5448
5449 xfree (vp->document_id);
5450 vp->document_id = xstrdup (new_doc_id);
5451
5452 (*android_java_env)->ReleaseStringUTFChars (android_java_env,
5453 new_id, new_doc_id);
5454 ANDROID_DELETE_LOCAL_REF (new_id);
5455
5456 /* Finally, transform this vnode into a directory vnode. */
5457 vp->vnode.type = ANDROID_VNODE_SAF_TREE;
5458 vp->vnode.ops = &saf_tree_vfs_ops;
5459 return 0;
5231} 5460}
5232 5461
5233static struct android_vdir * 5462static struct android_vdir *
@@ -5449,6 +5678,29 @@ android_vfs_init (JNIEnv *env, jobject manager)
5449 android_init_cursor_class (env); 5678 android_init_cursor_class (env);
5450 android_init_entry_class (env); 5679 android_init_entry_class (env);
5451 android_init_fd_class (env); 5680 android_init_fd_class (env);
5681
5682 /* Initialize each of the exception classes used by
5683 `android_saf_exception_check'. */
5684
5685 old = (*env)->FindClass (env, "java/io/FileNotFoundException");
5686 file_not_found_exception = (*env)->NewGlobalRef (env, old);
5687 (*env)->DeleteLocalRef (env, old);
5688 eassert (file_not_found_exception);
5689
5690 old = (*env)->FindClass (env, "java/lang/SecurityException");
5691 security_exception = (*env)->NewGlobalRef (env, old);
5692 (*env)->DeleteLocalRef (env, old);
5693 eassert (security_exception);
5694
5695 old = (*env)->FindClass (env, "java/lang/UnsupportedOperationException");
5696 unsupported_operation_exception = (*env)->NewGlobalRef (env, old);
5697 (*env)->DeleteLocalRef (env, old);
5698 eassert (unsupported_operation_exception);
5699
5700 old = (*env)->FindClass (env, "java/lang/OutOfMemoryError");
5701 out_of_memory_error = (*env)->NewGlobalRef (env, old);
5702 (*env)->DeleteLocalRef (env, old);
5703 eassert (out_of_memory_error);
5452} 5704}
5453 5705
5454/* The replacement functions that follow have several major 5706/* The replacement functions that follow have several major
@@ -5606,7 +5858,7 @@ android_mkdir (const char *name, mode_t mode)
5606 5858
5607 rc = (*vp->ops->mkdir) (vp, mode); 5859 rc = (*vp->ops->mkdir) (vp, mode);
5608 (*vp->ops->close) (vp); 5860 (*vp->ops->close) (vp);
5609 return rc; 5861 return rc;
5610} 5862}
5611 5863
5612/* Rename the vnode designated by SRC to the vnode designated by DST. 5864/* Rename the vnode designated by SRC to the vnode designated by DST.
@@ -5724,7 +5976,7 @@ android_fstat (int fd, struct stat *statb)
5724 for (tem = afs_file_descriptors; tem; tem = tem->next) 5976 for (tem = afs_file_descriptors; tem; tem = tem->next)
5725 { 5977 {
5726 if (tem->fd == fd) 5978 if (tem->fd == fd)
5727 { 5979 {
5728 memcpy (statb, &tem->statb, sizeof *statb); 5980 memcpy (statb, &tem->statb, sizeof *statb);
5729 return 0; 5981 return 0;
5730 } 5982 }