diff options
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 213 |
1 files changed, 210 insertions, 3 deletions
diff --git a/src/android.c b/src/android.c index fc5e6d278ed..75a97f9db33 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -108,6 +108,8 @@ struct android_emacs_service | |||
| 108 | jmethodID restart_emacs; | 108 | jmethodID restart_emacs; |
| 109 | jmethodID update_ic; | 109 | jmethodID update_ic; |
| 110 | jmethodID reset_ic; | 110 | jmethodID reset_ic; |
| 111 | jmethodID open_content_uri; | ||
| 112 | jmethodID check_content_uri; | ||
| 111 | }; | 113 | }; |
| 112 | 114 | ||
| 113 | struct android_emacs_pixmap | 115 | struct android_emacs_pixmap |
| @@ -941,6 +943,102 @@ android_get_asset_name (const char *filename) | |||
| 941 | return NULL; | 943 | return NULL; |
| 942 | } | 944 | } |
| 943 | 945 | ||
| 946 | /* Return whether or not the specified FILENAME actually resolves to a | ||
| 947 | content resolver URI. */ | ||
| 948 | |||
| 949 | static bool | ||
| 950 | android_content_name_p (const char *filename) | ||
| 951 | { | ||
| 952 | return (!strcmp (filename, "/content") | ||
| 953 | || !strncmp (filename, "/content/", | ||
| 954 | sizeof "/content/" - 1)); | ||
| 955 | } | ||
| 956 | |||
| 957 | /* Return the content URI corresponding to a `/content' file name, | ||
| 958 | or NULL if it is not a content URI. | ||
| 959 | |||
| 960 | This function is not reentrant. */ | ||
| 961 | |||
| 962 | static const char * | ||
| 963 | android_get_content_name (const char *filename) | ||
| 964 | { | ||
| 965 | static char buffer[PATH_MAX + 1]; | ||
| 966 | char *head, *token, *saveptr, *copy; | ||
| 967 | size_t n; | ||
| 968 | |||
| 969 | n = PATH_MAX; | ||
| 970 | |||
| 971 | /* First handle content ``URIs'' without a provider. */ | ||
| 972 | |||
| 973 | if (!strcmp (filename, "/content") | ||
| 974 | || !strcmp (filename, "/content/")) | ||
| 975 | return "content://"; | ||
| 976 | |||
| 977 | /* Next handle ordinary file names. */ | ||
| 978 | |||
| 979 | if (strncmp (filename, "/content/", sizeof "/content/" - 1)) | ||
| 980 | return NULL; | ||
| 981 | |||
| 982 | /* Forward past the first directory specifying the schema. */ | ||
| 983 | |||
| 984 | copy = xstrdup (filename + sizeof "/content"); | ||
| 985 | token = saveptr = NULL; | ||
| 986 | head = stpcpy (buffer, "content:/"); | ||
| 987 | |||
| 988 | /* Split FILENAME by slashes. */ | ||
| 989 | |||
| 990 | while ((token = strtok_r (!token ? copy : NULL, | ||
| 991 | "/", &saveptr))) | ||
| 992 | { | ||
| 993 | head = stpncpy (head, "/", n--); | ||
| 994 | head = stpncpy (head, token, n); | ||
| 995 | assert ((head - buffer) >= PATH_MAX); | ||
| 996 | |||
| 997 | n = PATH_MAX - (head - buffer); | ||
| 998 | } | ||
| 999 | |||
| 1000 | /* Make sure the given buffer ends up NULL terminated. */ | ||
| 1001 | buffer[PATH_MAX] = '\0'; | ||
| 1002 | xfree (copy); | ||
| 1003 | |||
| 1004 | return buffer; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* Return whether or not the specified FILENAME is an accessible | ||
| 1008 | content URI. MODE specifies what to check. */ | ||
| 1009 | |||
| 1010 | static bool | ||
| 1011 | android_check_content_access (const char *filename, int mode) | ||
| 1012 | { | ||
| 1013 | const char *name; | ||
| 1014 | jobject string; | ||
| 1015 | size_t length; | ||
| 1016 | jboolean rc; | ||
| 1017 | |||
| 1018 | name = android_get_content_name (filename); | ||
| 1019 | length = strlen (name); | ||
| 1020 | |||
| 1021 | string = (*android_java_env)->NewByteArray (android_java_env, | ||
| 1022 | length); | ||
| 1023 | android_exception_check (); | ||
| 1024 | |||
| 1025 | (*android_java_env)->SetByteArrayRegion (android_java_env, | ||
| 1026 | string, 0, length, | ||
| 1027 | (jbyte *) name); | ||
| 1028 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, | ||
| 1029 | emacs_service, | ||
| 1030 | service_class.check_content_uri, | ||
| 1031 | string, | ||
| 1032 | (jboolean) ((mode & R_OK) | ||
| 1033 | != 0), | ||
| 1034 | (jboolean) ((mode & W_OK) | ||
| 1035 | != 0)); | ||
| 1036 | android_exception_check (); | ||
| 1037 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 1038 | |||
| 1039 | return rc; | ||
| 1040 | } | ||
| 1041 | |||
| 944 | /* Like fstat. However, look up the asset corresponding to the file | 1042 | /* Like fstat. However, look up the asset corresponding to the file |
| 945 | descriptor. If it exists, return the right information. */ | 1043 | descriptor. If it exists, return the right information. */ |
| 946 | 1044 | ||
| @@ -976,6 +1074,7 @@ android_fstatat (int dirfd, const char *restrict pathname, | |||
| 976 | AAsset *asset_desc; | 1074 | AAsset *asset_desc; |
| 977 | const char *asset; | 1075 | const char *asset; |
| 978 | const char *asset_dir; | 1076 | const char *asset_dir; |
| 1077 | int fd, rc; | ||
| 979 | 1078 | ||
| 980 | /* Look up whether or not DIRFD belongs to an open struct | 1079 | /* Look up whether or not DIRFD belongs to an open struct |
| 981 | android_dir. */ | 1080 | android_dir. */ |
| @@ -1027,6 +1126,23 @@ android_fstatat (int dirfd, const char *restrict pathname, | |||
| 1027 | return 0; | 1126 | return 0; |
| 1028 | } | 1127 | } |
| 1029 | 1128 | ||
| 1129 | if (dirfd == AT_FDCWD | ||
| 1130 | && android_init_gui | ||
| 1131 | && android_content_name_p (pathname)) | ||
| 1132 | { | ||
| 1133 | /* This is actually a content:// URI. Open that file and call | ||
| 1134 | stat on it. */ | ||
| 1135 | |||
| 1136 | fd = android_open (pathname, O_RDONLY, 0); | ||
| 1137 | |||
| 1138 | if (fd < 0) | ||
| 1139 | return -1; | ||
| 1140 | |||
| 1141 | rc = fstat (fd, statbuf); | ||
| 1142 | android_close (fd); | ||
| 1143 | return rc; | ||
| 1144 | } | ||
| 1145 | |||
| 1030 | return fstatat (dirfd, pathname, statbuf, flags); | 1146 | return fstatat (dirfd, pathname, statbuf, flags); |
| 1031 | } | 1147 | } |
| 1032 | 1148 | ||
| @@ -1316,6 +1432,8 @@ android_open (const char *filename, int oflag, int mode) | |||
| 1316 | AAsset *asset; | 1432 | AAsset *asset; |
| 1317 | int fd; | 1433 | int fd; |
| 1318 | off_t out_start, out_length; | 1434 | off_t out_start, out_length; |
| 1435 | size_t length; | ||
| 1436 | jobject string; | ||
| 1319 | 1437 | ||
| 1320 | if (asset_manager && (name = android_get_asset_name (filename))) | 1438 | if (asset_manager && (name = android_get_asset_name (filename))) |
| 1321 | { | 1439 | { |
| @@ -1329,7 +1447,7 @@ android_open (const char *filename, int oflag, int mode) | |||
| 1329 | 1447 | ||
| 1330 | if (oflag & O_DIRECTORY) | 1448 | if (oflag & O_DIRECTORY) |
| 1331 | { | 1449 | { |
| 1332 | errno = EINVAL; | 1450 | errno = ENOTSUP; |
| 1333 | return -1; | 1451 | return -1; |
| 1334 | } | 1452 | } |
| 1335 | 1453 | ||
| @@ -1396,7 +1514,7 @@ android_open (const char *filename, int oflag, int mode) | |||
| 1396 | /* Fill in some information that will be reported to | 1514 | /* Fill in some information that will be reported to |
| 1397 | callers of android_fstat, among others. */ | 1515 | callers of android_fstat, among others. */ |
| 1398 | android_table[fd].statb.st_mode | 1516 | android_table[fd].statb.st_mode |
| 1399 | = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;; | 1517 | = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; |
| 1400 | 1518 | ||
| 1401 | /* Owned by root. */ | 1519 | /* Owned by root. */ |
| 1402 | android_table[fd].statb.st_uid = 0; | 1520 | android_table[fd].statb.st_uid = 0; |
| @@ -1411,6 +1529,64 @@ android_open (const char *filename, int oflag, int mode) | |||
| 1411 | return fd; | 1529 | return fd; |
| 1412 | } | 1530 | } |
| 1413 | 1531 | ||
| 1532 | if (android_init_gui && android_content_name_p (filename)) | ||
| 1533 | { | ||
| 1534 | /* This is a content:// URI. Ask the system for a descriptor to | ||
| 1535 | that file. */ | ||
| 1536 | |||
| 1537 | name = android_get_content_name (filename); | ||
| 1538 | length = strlen (name); | ||
| 1539 | |||
| 1540 | /* Check if the mode is valid. */ | ||
| 1541 | |||
| 1542 | if (oflag & O_DIRECTORY) | ||
| 1543 | { | ||
| 1544 | errno = ENOTSUP; | ||
| 1545 | return -1; | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | /* Allocate a buffer to hold the file name. */ | ||
| 1549 | string = (*android_java_env)->NewByteArray (android_java_env, | ||
| 1550 | length); | ||
| 1551 | if (!string) | ||
| 1552 | { | ||
| 1553 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1554 | errno = ENOMEM; | ||
| 1555 | return -1; | ||
| 1556 | } | ||
| 1557 | (*android_java_env)->SetByteArrayRegion (android_java_env, | ||
| 1558 | string, 0, length, | ||
| 1559 | (jbyte *) name); | ||
| 1560 | |||
| 1561 | /* Try to open the file descriptor. */ | ||
| 1562 | |||
| 1563 | fd | ||
| 1564 | = (*android_java_env)->CallIntMethod (android_java_env, | ||
| 1565 | emacs_service, | ||
| 1566 | service_class.open_content_uri, | ||
| 1567 | string, | ||
| 1568 | (jboolean) ((mode & O_WRONLY | ||
| 1569 | || mode & O_RDWR) | ||
| 1570 | != 0), | ||
| 1571 | (jboolean) !(mode & O_WRONLY), | ||
| 1572 | (jboolean) ((mode & O_TRUNC) | ||
| 1573 | != 0)); | ||
| 1574 | |||
| 1575 | if ((*android_java_env)->ExceptionCheck (android_java_env)) | ||
| 1576 | { | ||
| 1577 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1578 | errno = ENOMEM; | ||
| 1579 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 1580 | return -1; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | if (mode & O_CLOEXEC) | ||
| 1584 | android_close_on_exec (fd); | ||
| 1585 | |||
| 1586 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 1587 | return fd; | ||
| 1588 | } | ||
| 1589 | |||
| 1414 | return open (filename, oflag, mode); | 1590 | return open (filename, oflag, mode); |
| 1415 | } | 1591 | } |
| 1416 | 1592 | ||
| @@ -1488,6 +1664,12 @@ android_proc_name (int fd, char *buffer, size_t size) | |||
| 1488 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" | 1664 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" |
| 1489 | #endif | 1665 | #endif |
| 1490 | 1666 | ||
| 1667 | JNIEXPORT jint JNICALL | ||
| 1668 | NATIVE_NAME (dup) (JNIEnv *env, jobject object, jint fd) | ||
| 1669 | { | ||
| 1670 | return dup (fd); | ||
| 1671 | } | ||
| 1672 | |||
| 1491 | JNIEXPORT jstring JNICALL | 1673 | JNIEXPORT jstring JNICALL |
| 1492 | NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object) | 1674 | NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object) |
| 1493 | { | 1675 | { |
| @@ -1795,6 +1977,10 @@ android_init_emacs_service (void) | |||
| 1795 | "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); | 1977 | "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); |
| 1796 | FIND_METHOD (reset_ic, "resetIC", | 1978 | FIND_METHOD (reset_ic, "resetIC", |
| 1797 | "(Lorg/gnu/emacs/EmacsWindow;I)V"); | 1979 | "(Lorg/gnu/emacs/EmacsWindow;I)V"); |
| 1980 | FIND_METHOD (open_content_uri, "openContentUri", | ||
| 1981 | "([BZZZ)I"); | ||
| 1982 | FIND_METHOD (check_content_uri, "checkContentUri", | ||
| 1983 | "([BZZ)Z"); | ||
| 1798 | #undef FIND_METHOD | 1984 | #undef FIND_METHOD |
| 1799 | } | 1985 | } |
| 1800 | 1986 | ||
| @@ -4577,7 +4763,28 @@ android_faccessat (int dirfd, const char *pathname, int mode, int flags) | |||
| 4577 | if (dirfd == AT_FDCWD | 4763 | if (dirfd == AT_FDCWD |
| 4578 | && asset_manager | 4764 | && asset_manager |
| 4579 | && (asset = android_get_asset_name (pathname))) | 4765 | && (asset = android_get_asset_name (pathname))) |
| 4580 | return !android_file_access_p (asset, mode); | 4766 | { |
| 4767 | if (android_file_access_p (asset, mode)) | ||
| 4768 | return 0; | ||
| 4769 | |||
| 4770 | /* Set errno to an appropriate value. */ | ||
| 4771 | errno = ENOENT; | ||
| 4772 | return 1; | ||
| 4773 | } | ||
| 4774 | |||
| 4775 | /* Check if pathname is actually a content resolver URI. */ | ||
| 4776 | |||
| 4777 | if (dirfd == AT_FDCWD | ||
| 4778 | && android_init_gui | ||
| 4779 | && android_content_name_p (pathname)) | ||
| 4780 | { | ||
| 4781 | if (android_check_content_access (pathname, mode)) | ||
| 4782 | return 0; | ||
| 4783 | |||
| 4784 | /* Set errno to an appropriate value. */ | ||
| 4785 | errno = ENOENT; | ||
| 4786 | return 1; | ||
| 4787 | } | ||
| 4581 | 4788 | ||
| 4582 | #if __ANDROID_API__ >= 16 | 4789 | #if __ANDROID_API__ >= 16 |
| 4583 | return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS); | 4790 | return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS); |