diff options
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 168 |
1 files changed, 164 insertions, 4 deletions
diff --git a/src/android.c b/src/android.c index 3f6e6f4576b..a51d0518484 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -852,6 +852,26 @@ android_scan_directory_tree (char *file, size_t *limit_return) | |||
| 852 | return NULL; | 852 | return NULL; |
| 853 | } | 853 | } |
| 854 | 854 | ||
| 855 | /* Return whether or not the directory tree entry DIR is a | ||
| 856 | directory. | ||
| 857 | |||
| 858 | DIR should be a value returned by | ||
| 859 | `android_scan_directory_tree'. */ | ||
| 860 | |||
| 861 | static bool | ||
| 862 | android_is_directory (const char *dir) | ||
| 863 | { | ||
| 864 | /* If the directory is the directory tree, then it is a | ||
| 865 | directory. */ | ||
| 866 | if (dir == directory_tree + 5) | ||
| 867 | return true; | ||
| 868 | |||
| 869 | /* Otherwise, look 5 bytes behind. If it is `/', then it is a | ||
| 870 | directory. */ | ||
| 871 | return (dir - 6 >= directory_tree | ||
| 872 | && *(dir - 6) == '/'); | ||
| 873 | } | ||
| 874 | |||
| 855 | 875 | ||
| 856 | 876 | ||
| 857 | /* Intercept USER_FULL_NAME and return something that makes sense if | 877 | /* Intercept USER_FULL_NAME and return something that makes sense if |
| @@ -899,8 +919,15 @@ android_fstat (int fd, struct stat *statb) | |||
| 899 | return fstat (fd, statb); | 919 | return fstat (fd, statb); |
| 900 | } | 920 | } |
| 901 | 921 | ||
| 922 | static int android_lookup_asset_directory_fd (int, | ||
| 923 | const char *restrict *, | ||
| 924 | const char *restrict); | ||
| 925 | |||
| 902 | /* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an | 926 | /* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an |
| 903 | asset, find the information for the corresponding asset. */ | 927 | asset, find the information for the corresponding asset, and if |
| 928 | dirfd is an offset into directory_tree as returned by | ||
| 929 | `android_dirfd', find the information within the corresponding | ||
| 930 | directory tree entry. */ | ||
| 904 | 931 | ||
| 905 | int | 932 | int |
| 906 | android_fstatat (int dirfd, const char *restrict pathname, | 933 | android_fstatat (int dirfd, const char *restrict pathname, |
| @@ -908,11 +935,40 @@ android_fstatat (int dirfd, const char *restrict pathname, | |||
| 908 | { | 935 | { |
| 909 | AAsset *asset_desc; | 936 | AAsset *asset_desc; |
| 910 | const char *asset; | 937 | const char *asset; |
| 938 | const char *asset_dir; | ||
| 939 | |||
| 940 | /* Look up whether or not DIRFD belongs to an open struct | ||
| 941 | android_dir. */ | ||
| 942 | |||
| 943 | if (dirfd != AT_FDCWD) | ||
| 944 | dirfd | ||
| 945 | = android_lookup_asset_directory_fd (dirfd, &pathname, | ||
| 946 | pathname); | ||
| 911 | 947 | ||
| 912 | if (dirfd == AT_FDCWD | 948 | if (dirfd == AT_FDCWD |
| 913 | && asset_manager | 949 | && asset_manager |
| 914 | && (asset = android_get_asset_name (pathname))) | 950 | && (asset = android_get_asset_name (pathname))) |
| 915 | { | 951 | { |
| 952 | /* Look up whether or not PATHNAME happens to be a | ||
| 953 | directory. */ | ||
| 954 | asset_dir = android_scan_directory_tree ((char *) asset, | ||
| 955 | NULL); | ||
| 956 | |||
| 957 | if (!asset_dir) | ||
| 958 | { | ||
| 959 | errno = ENOENT; | ||
| 960 | return -1; | ||
| 961 | } | ||
| 962 | |||
| 963 | if (android_is_directory (asset_dir)) | ||
| 964 | { | ||
| 965 | memset (statbuf, 0, sizeof *statbuf); | ||
| 966 | |||
| 967 | /* Fill in the stat buffer. */ | ||
| 968 | statbuf->st_mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH; | ||
| 969 | return 0; | ||
| 970 | } | ||
| 971 | |||
| 916 | /* AASSET_MODE_STREAMING is fastest here. */ | 972 | /* AASSET_MODE_STREAMING is fastest here. */ |
| 917 | asset_desc = AAssetManager_open (asset_manager, asset, | 973 | asset_desc = AAssetManager_open (asset_manager, asset, |
| 918 | AASSET_MODE_STREAMING); | 974 | AASSET_MODE_STREAMING); |
| @@ -923,7 +979,7 @@ android_fstatat (int dirfd, const char *restrict pathname, | |||
| 923 | memset (statbuf, 0, sizeof *statbuf); | 979 | memset (statbuf, 0, sizeof *statbuf); |
| 924 | 980 | ||
| 925 | /* Fill in the stat buffer. */ | 981 | /* Fill in the stat buffer. */ |
| 926 | statbuf->st_mode = S_IFREG; | 982 | statbuf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; |
| 927 | statbuf->st_size = AAsset_getLength (asset_desc); | 983 | statbuf->st_size = AAsset_getLength (asset_desc); |
| 928 | 984 | ||
| 929 | /* Close the asset. */ | 985 | /* Close the asset. */ |
| @@ -1118,7 +1174,8 @@ android_open (const char *filename, int oflag, int mode) | |||
| 1118 | 1174 | ||
| 1119 | /* Fill in some information that will be reported to | 1175 | /* Fill in some information that will be reported to |
| 1120 | callers of android_fstat, among others. */ | 1176 | callers of android_fstat, among others. */ |
| 1121 | android_table[fd].statb.st_mode = S_IFREG; | 1177 | android_table[fd].statb.st_mode |
| 1178 | = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;; | ||
| 1122 | 1179 | ||
| 1123 | /* Owned by root. */ | 1180 | /* Owned by root. */ |
| 1124 | android_table[fd].statb.st_uid = 0; | 1181 | android_table[fd].statb.st_uid = 0; |
| @@ -4023,8 +4080,21 @@ struct android_dir | |||
| 4023 | 4080 | ||
| 4024 | /* And the end of the files in asset_dir. */ | 4081 | /* And the end of the files in asset_dir. */ |
| 4025 | char *asset_limit; | 4082 | char *asset_limit; |
| 4083 | |||
| 4084 | /* The next struct android_dir. */ | ||
| 4085 | struct android_dir *next; | ||
| 4086 | |||
| 4087 | /* Path to the directory relative to /. */ | ||
| 4088 | char *asset_file; | ||
| 4089 | |||
| 4090 | /* File descriptor used when asset_dir is set. */ | ||
| 4091 | int fd; | ||
| 4026 | }; | 4092 | }; |
| 4027 | 4093 | ||
| 4094 | /* List of all struct android_dir's corresponding to an asset | ||
| 4095 | directory that are currently open. */ | ||
| 4096 | static struct android_dir *android_dirs; | ||
| 4097 | |||
| 4028 | /* Like opendir. However, return an asset directory if NAME points to | 4098 | /* Like opendir. However, return an asset directory if NAME points to |
| 4029 | an asset. */ | 4099 | an asset. */ |
| 4030 | 4100 | ||
| @@ -4034,7 +4104,7 @@ android_opendir (const char *name) | |||
| 4034 | struct android_dir *dir; | 4104 | struct android_dir *dir; |
| 4035 | char *asset_dir; | 4105 | char *asset_dir; |
| 4036 | const char *asset_name; | 4106 | const char *asset_name; |
| 4037 | size_t limit; | 4107 | size_t limit, length; |
| 4038 | 4108 | ||
| 4039 | asset_name = android_get_asset_name (name); | 4109 | asset_name = android_get_asset_name (name); |
| 4040 | 4110 | ||
| @@ -4052,10 +4122,19 @@ android_opendir (const char *name) | |||
| 4052 | return NULL; | 4122 | return NULL; |
| 4053 | } | 4123 | } |
| 4054 | 4124 | ||
| 4125 | length = strlen (name); | ||
| 4126 | |||
| 4055 | dir = xmalloc (sizeof *dir); | 4127 | dir = xmalloc (sizeof *dir); |
| 4056 | dir->dir = NULL; | 4128 | dir->dir = NULL; |
| 4057 | dir->asset_dir = asset_dir; | 4129 | dir->asset_dir = asset_dir; |
| 4058 | dir->asset_limit = (char *) directory_tree + limit; | 4130 | dir->asset_limit = (char *) directory_tree + limit; |
| 4131 | dir->fd = -1; | ||
| 4132 | dir->asset_file = xzalloc (length + 2); | ||
| 4133 | |||
| 4134 | /* Make sure dir->asset_file is terminated with /. */ | ||
| 4135 | strcpy (dir->asset_file, name); | ||
| 4136 | if (dir->asset_file[length - 1] != '/') | ||
| 4137 | dir->asset_file[length] = '/'; | ||
| 4059 | 4138 | ||
| 4060 | /* Make sure dir->asset_limit is within bounds. It is a limit, | 4139 | /* Make sure dir->asset_limit is within bounds. It is a limit, |
| 4061 | and as such can be exactly one byte past directory_tree. */ | 4140 | and as such can be exactly one byte past directory_tree. */ |
| @@ -4069,6 +4148,9 @@ android_opendir (const char *name) | |||
| 4069 | errno = EACCES; | 4148 | errno = EACCES; |
| 4070 | } | 4149 | } |
| 4071 | 4150 | ||
| 4151 | dir->next = android_dirs; | ||
| 4152 | android_dirs = dir; | ||
| 4153 | |||
| 4072 | return dir; | 4154 | return dir; |
| 4073 | } | 4155 | } |
| 4074 | 4156 | ||
| @@ -4086,6 +4168,26 @@ android_opendir (const char *name) | |||
| 4086 | return dir; | 4168 | return dir; |
| 4087 | } | 4169 | } |
| 4088 | 4170 | ||
| 4171 | /* Like dirfd. However, value is not a real directory file descriptor | ||
| 4172 | if DIR is an asset directory. */ | ||
| 4173 | |||
| 4174 | int | ||
| 4175 | android_dirfd (struct android_dir *dirp) | ||
| 4176 | { | ||
| 4177 | int fd; | ||
| 4178 | |||
| 4179 | if (dirp->dir) | ||
| 4180 | return dirfd (dirp->dir); | ||
| 4181 | else if (dirp->fd != -1) | ||
| 4182 | return dirp->fd; | ||
| 4183 | |||
| 4184 | fd = open ("/dev/null", O_RDONLY | O_CLOEXEC); | ||
| 4185 | |||
| 4186 | /* Record this file descriptor in dirp. */ | ||
| 4187 | dirp->fd = fd; | ||
| 4188 | return fd; | ||
| 4189 | } | ||
| 4190 | |||
| 4089 | /* Like readdir, except it understands asset directories. */ | 4191 | /* Like readdir, except it understands asset directories. */ |
| 4090 | 4192 | ||
| 4091 | struct dirent * | 4193 | struct dirent * |
| @@ -4152,8 +4254,29 @@ android_readdir (struct android_dir *dir) | |||
| 4152 | void | 4254 | void |
| 4153 | android_closedir (struct android_dir *dir) | 4255 | android_closedir (struct android_dir *dir) |
| 4154 | { | 4256 | { |
| 4257 | struct android_dir **next, *tem; | ||
| 4258 | |||
| 4155 | if (dir->dir) | 4259 | if (dir->dir) |
| 4156 | closedir (dir->dir); | 4260 | closedir (dir->dir); |
| 4261 | else | ||
| 4262 | { | ||
| 4263 | if (dir->fd != -1) | ||
| 4264 | close (dir->fd); | ||
| 4265 | |||
| 4266 | /* Unlink this directory from the list of all asset manager | ||
| 4267 | directories. */ | ||
| 4268 | |||
| 4269 | for (next = &android_dirs; (tem = *next);) | ||
| 4270 | { | ||
| 4271 | if (tem == dir) | ||
| 4272 | *next = dir->next; | ||
| 4273 | else | ||
| 4274 | next = &(*next)->next; | ||
| 4275 | } | ||
| 4276 | |||
| 4277 | /* Free the asset file name. */ | ||
| 4278 | xfree (dir->asset_file); | ||
| 4279 | } | ||
| 4157 | 4280 | ||
| 4158 | /* There is no need to close anything else, as the directory tree | 4281 | /* There is no need to close anything else, as the directory tree |
| 4159 | lies in statically allocated memory. */ | 4282 | lies in statically allocated memory. */ |
| @@ -4161,6 +4284,43 @@ android_closedir (struct android_dir *dir) | |||
| 4161 | xfree (dir); | 4284 | xfree (dir); |
| 4162 | } | 4285 | } |
| 4163 | 4286 | ||
| 4287 | /* Subroutine used by android_fstatat. If DIRFD belongs to an open | ||
| 4288 | asset directory and FILE is a relative file name, then return | ||
| 4289 | AT_FDCWD and the absolute file name of the directory prepended to | ||
| 4290 | FILE in *PATHNAME. Else, return DIRFD. */ | ||
| 4291 | |||
| 4292 | int | ||
| 4293 | android_lookup_asset_directory_fd (int dirfd, | ||
| 4294 | const char *restrict *pathname, | ||
| 4295 | const char *restrict file) | ||
| 4296 | { | ||
| 4297 | struct android_dir *dir; | ||
| 4298 | static char *name; | ||
| 4299 | |||
| 4300 | if (file[0] == '/') | ||
| 4301 | return dirfd; | ||
| 4302 | |||
| 4303 | for (dir = android_dirs; dir; dir = dir->next) | ||
| 4304 | { | ||
| 4305 | if (dir->fd == dirfd && dirfd != -1) | ||
| 4306 | { | ||
| 4307 | if (name) | ||
| 4308 | xfree (name); | ||
| 4309 | |||
| 4310 | /* dir->asset_file is always separator terminated. */ | ||
| 4311 | name = xzalloc (strlen (dir->asset_file) | ||
| 4312 | + strlen (file) + 1); | ||
| 4313 | strcpy (name, dir->asset_file); | ||
| 4314 | strcpy (name + strlen (dir->asset_file), | ||
| 4315 | file); | ||
| 4316 | *pathname = name; | ||
| 4317 | return AT_FDCWD; | ||
| 4318 | } | ||
| 4319 | } | ||
| 4320 | |||
| 4321 | return dirfd; | ||
| 4322 | } | ||
| 4323 | |||
| 4164 | 4324 | ||
| 4165 | 4325 | ||
| 4166 | /* emacs_abort implementation for Android. This logs a stack | 4326 | /* emacs_abort implementation for Android. This logs a stack |