diff options
| author | Po Lu | 2023-07-28 12:21:47 +0800 |
|---|---|---|
| committer | Po Lu | 2023-07-28 12:21:47 +0800 |
| commit | 03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3 (patch) | |
| tree | a8d55088a6efed2cbe4b0bfad1c1bde61579b54e /src | |
| parent | 7c0899586471d3649dfb468d2b8f7d6d9685fea1 (diff) | |
| download | emacs-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.c | 5 | ||||
| -rw-r--r-- | src/android.h | 2 | ||||
| -rw-r--r-- | src/androidvfs.c | 316 |
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 | ||
| 284 | extern JNIEnv *android_java_env; | 286 | extern 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. */ |
| 277 | static struct android_parcel_file_descriptor_class fd_class; | 277 | static struct android_parcel_file_descriptor_class fd_class; |
| 278 | 278 | ||
| 279 | /* Global references to several exception classes. */ | ||
| 280 | static jclass file_not_found_exception, security_exception; | ||
| 281 | static 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 | |||
| 3715 | static int | ||
| 3716 | android_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 | |||
| 3934 | static int | ||
| 3935 | android_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 | ||
| 4019 | static int | 4149 | static int |
| 4020 | android_document_id_from_name (const char *tree_uri, char *name, | 4150 | android_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) | |||
| 4354 | static int | 4485 | static int |
| 4355 | android_saf_tree_rmdir (struct android_vnode *vnode) | 4486 | android_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 | ||
| 4362 | static int | 4503 | static 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 | ||
| 4418 | static jobject | 4559 | static jobject |
| 4419 | android_saf_tree_opendir_1 (struct android_saf_tree_vnode *vp) | 4560 | android_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, | |||
| 4953 | static int | 5098 | static int |
| 4954 | android_saf_file_unlink (struct android_vnode *vnode) | 5099 | android_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 | ||
| 4961 | static int | 5107 | static 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) | |||
| 5225 | static int | 5373 | static int |
| 5226 | android_saf_new_mkdir (struct android_vnode *vnode, mode_t mode) | 5374 | android_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 | ||
| 5233 | static struct android_vdir * | 5462 | static 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 | } |