Restore functionality on Android 2.2

* java/Makefile.in (install_temp): Do not compress
directory-tree and generate such files in a special format that
stores file sizes.

* lib-src/asset-directory-tool.c (struct directory_tree): New
field st_size.
(need_file_size): New variable.
(main_1, main_2, main): Write file sizes before sibling offsets
if `--api-8' is specified.

* src/android-asset.h (struct android_asset_manager): New field
open.
(struct android_asset): New field name.
(AAssetManager_fromJava): Load AssetManager#open.
(AAssetManager_open): If a directory tree has already been
loaded, search for a matching asset and load its size thence, to
avoid the requirement of an AssetFileDescriptor.
(AAsset_close): Don't assume asset->fd exists.  Release
asset->name.
(AAsset_getLength): Likewise.
(android_asset_create_stream): If asset->name exists, call
AssetManager#open, in order to open compressed files.

* src/androidvfs.c (OLD_ANDROID_ASSETS): Define to 1 on API 8.
(android_extract_long, android_scan_directory_tree): Mark
arguments as const.  Adjust offsets when OLD_ANDROID_ASSETS.
(android_is_directory, android_init_assets, android_afs_readdir):
Likewise.

* src/lread.c (lread_fstat): Define to sys_fstat, not fstat.
This commit is contained in:
Po Lu 2024-06-12 16:44:21 +08:00
parent f543ec18f4
commit 02e70821b3
5 changed files with 230 additions and 75 deletions

View file

@ -258,7 +258,8 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
{ hostname; date +%s; } > install_temp/assets/build_info { hostname; date +%s; } > install_temp/assets/build_info
# Produce the file index. # Produce the file index.
$(AM_V_SILENT) $(libsrc)/asset-directory-tool \ $(AM_V_SILENT) $(libsrc)/asset-directory-tool \
install_temp/assets install_temp/assets/directory-tree install_temp/assets install_temp/assets/directory-tree\
$(if $(ANDROID_SDK_8_OR_EARLIER),--api-8)
# If the package targets Android 2.2, move compressable and # If the package targets Android 2.2, move compressable and
# non-compressable assets to separate directories. # non-compressable assets to separate directories.
$(AM_V_SILENT) \ $(AM_V_SILENT) \
@ -266,6 +267,7 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
echo "Moving large and gzipped files to separate directories...">&2;\ echo "Moving large and gzipped files to separate directories...">&2;\
mkdir -p install_temp/assets_raw; \ mkdir -p install_temp/assets_raw; \
cd install_temp/assets; \ cd install_temp/assets; \
mv directory-tree ../assets_raw; \
find . \( -size +1536 -o -size 1536 \) \ find . \( -size +1536 -o -size 1536 \) \
\( \! -name '*.gz' \) -type f > files.txt; \ \( \! -name '*.gz' \) -type f > files.txt; \
tar cf ../assets_raw/largefiles.tar -T files.txt; \ tar cf ../assets_raw/largefiles.tar -T files.txt; \

View file

@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h> #include <config.h>
#include <stdio.h> #include <stdio.h>
#include <verify.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <byteswap.h> #include <byteswap.h>
@ -35,17 +36,19 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
application package. application package.
Such a file records the layout of the `assets' directory in the Such a file records the layout of the `assets' directory in the
package. Emacs records this information itself and uses it in the package, and, in packages targeting Android 2.2, the size of each of
Android emulation of readdir, because the system asset manager APIs its members. Emacs records this information itself and uses it in
are routinely buggy, and are often unable to locate directories or the Android emulation of readdir, because the system asset manager
files. APIs are often unable to locate directories or files, or provide
corresponding metadata.
The file is packed, with no data alignment guarantees made. The The file is packed, with no data alignment guarantees made. The file
file starts with the bytes "EMACS", following which is the name of starts with the bytes "EMACS", or EMACS____ on Android 2.2, following
the first file or directory, a NULL byte and an unsigned int which is the name of the first file or directory, a NULL byte, an
indicating the offset from the start of the file to the start of unsigned int holding its size (on Android 2.2), and an unsigned int
the next sibling. Following that is a list of subdirectories or indicating the offset from the start of the file to the start of the
files in the same format. The long is stored LSB first. next sibling. Following that is a list of subdirectories or files in
the same format. The long is stored LSB first.
Directories can be distinguished from ordinary files through the Directories can be distinguished from ordinary files through the
last bytes of their file names (immediately previous to their last bytes of their file names (immediately previous to their
@ -62,10 +65,19 @@ struct directory_tree
/* The name of this directory or file. */ /* The name of this directory or file. */
char *name; char *name;
/* st_size of this entry. */
off_t st_size;
/* Subdirectories and files inside this directory. */ /* Subdirectories and files inside this directory. */
struct directory_tree *children, *next; struct directory_tree *children, *next;
}; };
/* Whether the size of each entry should be prepended to the start
pointer. */
static bool need_file_size;
/* Exit with EXIT_FAILURE, after printing a description of a failing /* Exit with EXIT_FAILURE, after printing a description of a failing
function WHAT along with the details of the error. */ function WHAT along with the details of the error. */
@ -138,11 +150,14 @@ main_1 (DIR *dir, struct directory_tree *parent)
last = &this->next; last = &this->next;
this->name = xmalloc (length + 2); this->name = xmalloc (length + 2);
strcpy (this->name, dirent->d_name); strcpy (this->name, dirent->d_name);
this->st_size = 0;
/* Now record the offset to the end of this directory. This /* Now record the offset to the end of this directory. This
is length + 1, for the file name, and 5 more bytes for is length + 1, for the file name, 5 more bytes for the
the trailing NULL and long. */ trailing NULL and long, and 4 further bytes if a file size
this->offset = parent->offset + length + 6; is required. */
this->offset = (parent->offset
+ length + 6 + (need_file_size ? 4 : 0));
/* Terminate that with a slash and trailing NULL byte. */ /* Terminate that with a slash and trailing NULL byte. */
this->name[length] = '/'; this->name[length] = '/';
@ -175,11 +190,22 @@ main_1 (DIR *dir, struct directory_tree *parent)
*last = this; *last = this;
last = &this->next; last = &this->next;
this->name = xmalloc (length + 1); this->name = xmalloc (length + 1);
this->st_size = statb.st_size;
strcpy (this->name, dirent->d_name); strcpy (this->name, dirent->d_name);
/* This is one byte shorter because there is no trailing if (this->st_size >= 0x1ffffff)
{
fprintf (stderr,
"asset-directory-tool: file size exceeds maximum"
" representable in a directory-tree: %s\n",
dirent->d_name);
exit (EXIT_FAILURE);
}
/* This is one byte the shorter because there is no trailing
slash. */ slash. */
this->offset = parent->offset + length + 5; this->offset = (parent->offset + length + 5
+ (need_file_size ? 4 : 0));
parent->offset = this->offset; parent->offset = this->offset;
} }
} }
@ -194,7 +220,7 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset)
{ {
ssize_t size; ssize_t size;
struct directory_tree *child; struct directory_tree *child;
unsigned int output; unsigned int output[2];
/* Write tree->name with the trailing NULL byte. */ /* Write tree->name with the trailing NULL byte. */
size = strlen (tree->name) + 1; size = strlen (tree->name) + 1;
@ -203,13 +229,26 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset)
/* Write the offset. */ /* Write the offset. */
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
output = bswap_32 (tree->offset); output[1] = bswap_32 (tree->offset);
#else output[0] = bswap_32 ((unsigned int) tree->st_size);
output = tree->offset; #else /* !WORDS_BIGENDIAN */
#endif output[1] = tree->offset;
if (write (fd, &output, 4) < 1) output[0] = (unsigned int) tree->st_size;
croak ("write"); #endif /* !WORDS_BIGENDIAN */
size += 4;
verify (sizeof output == 8 && sizeof output[0] == 4);
if (!need_file_size)
{
if (write (fd, output + 1, 4) < 1)
croak ("write");
size += 4;
}
else
{
if (write (fd, output, 8) < 1)
croak ("write");
size += 8;
}
/* Now update offset. */ /* Now update offset. */
*offset += size; *offset += size;
@ -240,13 +279,16 @@ main (int argc, char **argv)
struct directory_tree tree; struct directory_tree tree;
size_t offset; size_t offset;
if (argc != 3) if (argc != 3 && argc != 4)
{ {
fprintf (stderr, "usage: %s directory output-file\n", fprintf (stderr, "usage: %s directory output-file "
argv[0]); "[--api-8]\n", argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc == 4 && !strcmp (argv[3], "--api-8"))
need_file_size = true;
fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR, fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
@ -272,16 +314,23 @@ main (int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* And a further 4 bytes of padding if need_file_size. */
if (need_file_size && write (fd, "____", 4) < 4)
{
perror ("write");
return EXIT_FAILURE;
}
/* Now iterate through children of INDIR, building the directory /* Now iterate through children of INDIR, building the directory
tree. */ tree. */
tree.offset = 5; tree.offset = 5 + (need_file_size ? 4 : 0);
tree.children = NULL; tree.children = NULL;
main_1 (indir, &tree); main_1 (indir, &tree);
closedir (indir); closedir (indir);
/* Finally, write the directory tree to the output file. */ /* Finally, write the directory tree to the output file. */
offset = 5; offset = 5 + (need_file_size ? 4 : 0);
for (; tree.children; tree.children = tree.children->next) for (; tree.children; tree.children = tree.children->next)
main_2 (fd, tree.children, &offset); main_2 (fd, tree.children, &offset);

View file

@ -19,6 +19,17 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <android/log.h> #include <android/log.h>
/* Forward declarations. */
static const char *directory_tree;
static const char *android_scan_directory_tree (const char *, size_t *);
static unsigned int android_extract_long (const char *);
/* This file contains an emulation of the Android asset manager API /* This file contains an emulation of the Android asset manager API
used on builds for Android 2.2. It is included by android.c used on builds for Android 2.2. It is included by android.c
whenever appropriate. whenever appropriate.
@ -34,6 +45,7 @@ struct android_asset_manager
/* Asset manager class and functions. */ /* Asset manager class and functions. */
jclass class; jclass class;
jmethodID open_fd; jmethodID open_fd;
jmethodID open;
/* Asset file descriptor class and functions. */ /* Asset file descriptor class and functions. */
jclass fd_class; jclass fd_class;
@ -63,6 +75,9 @@ struct android_asset
/* The asset file descriptor and input stream. */ /* The asset file descriptor and input stream. */
jobject fd, stream; jobject fd, stream;
/* Alternatively, the name of the file. */
jstring name;
/* The mode. */ /* The mode. */
int mode; int mode;
}; };
@ -98,6 +113,12 @@ AAssetManager_fromJava (JNIEnv *env, jobject java_manager)
= (*env)->GetMethodID (env, manager->class, "openFd", = (*env)->GetMethodID (env, manager->class, "openFd",
"(Ljava/lang/String;)" "(Ljava/lang/String;)"
"Landroid/content/res/AssetFileDescriptor;"); "Landroid/content/res/AssetFileDescriptor;");
assert (manager->open_fd);
manager->open
= (*env)->GetMethodID (env, manager->class, "open",
"(Ljava/lang/String;)"
"Ljava/io/InputStream;");
assert (manager->open); assert (manager->open);
manager->fd_class manager->fd_class
@ -168,6 +189,8 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
jobject desc; jobject desc;
jstring name; jstring name;
AAsset *asset; AAsset *asset;
const char *asset_dir;
jlong st_size = -1;
/* Push a local frame. */ /* Push a local frame. */
asset = NULL; asset = NULL;
@ -177,53 +200,86 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
if ((*(manager->env))->ExceptionCheck (manager->env)) if ((*(manager->env))->ExceptionCheck (manager->env))
goto fail; goto fail;
/* Encoding issues can be ignored for now as there are only ASCII /* If the directory tree has been initialized, it is possible to avoid
file names in Emacs. */ opening an AssetFileDescriptor and thereby access compressed
assets, without sacrificing the possibility of reading the file
size. */
if (directory_tree)
{
/* Search for a matching asset. */
asset_dir = android_scan_directory_tree (c_name, NULL);
if (!asset_dir)
goto fail;
/* Extract the size of the asset from this directory. */
st_size = android_extract_long (asset_dir - 8);
}
/* Encoding issues can be ignored for the time being as there are only
ASCII file names in Emacs. */
name = (*(manager->env))->NewStringUTF (manager->env, c_name); name = (*(manager->env))->NewStringUTF (manager->env, c_name);
if (!name) if (!name)
goto fail; goto fail;
/* Now try to open an ``AssetFileDescriptor''. */ /* If st_size has been set, it ought to be possible to open an input
desc = (*(manager->env))->CallObjectMethod (manager->env, stream directly upon the first attempt to read from the asset,
manager->asset_manager, sidestepping the intermediate AssetFileDescriptor. */
manager->open_fd,
name);
if (!desc) desc = NULL;
goto fail;
if (st_size < 0)
/* Otherwise attempt to open an ``AssetFileDescriptor''. */
desc = (*(manager->env))->CallObjectMethod (manager->env,
manager->asset_manager,
manager->open_fd,
name);
/* Allocate the asset. */ /* Allocate the asset. */
asset = calloc (1, sizeof *asset); asset = calloc (1, sizeof *asset);
if (!asset) if (!asset)
{
(*(manager->env))->CallVoidMethod (manager->env,
desc,
manager->close);
goto fail;
}
/* Pop the local frame and return desc. */
desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
if (!desc)
goto fail; goto fail;
if (desc)
{
/* Pop the local frame and return desc. */
desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
if (!desc)
goto fail;
/* Will be released by PopLocalFrame. */
name = NULL;
}
else /* if (name) */
{
/* Pop the local frame and return name. */
name = (*(manager->env))->NewGlobalRef (manager->env, name);
if (!name)
goto fail;
}
(*(manager->env))->PopLocalFrame (manager->env, NULL); (*(manager->env))->PopLocalFrame (manager->env, NULL);
asset->manager = manager; asset->manager = manager;
asset->length = -1; asset->length = st_size;
asset->fd = desc; asset->fd = desc;
asset->name = name;
asset->mode = mode; asset->mode = mode;
return asset; return asset;
fail: fail:
if (desc)
(*(manager->env))->CallVoidMethod (manager->env,
desc,
manager->close);
(*(manager->env))->ExceptionClear (manager->env); (*(manager->env))->ExceptionClear (manager->env);
(*(manager->env))->PopLocalFrame (manager->env, NULL); (*(manager->env))->PopLocalFrame (manager->env, NULL);
free (asset); free (asset);
return NULL; return NULL;
} }
@ -234,11 +290,14 @@ AAsset_close (AAsset *asset)
env = asset->manager->env; env = asset->manager->env;
(*env)->CallVoidMethod (asset->manager->env, if (asset->fd)
asset->fd, {
asset->manager->close); (*env)->CallVoidMethod (asset->manager->env,
(*env)->DeleteGlobalRef (asset->manager->env, asset->fd,
asset->fd); asset->manager->close);
(*env)->DeleteGlobalRef (asset->manager->env,
asset->fd);
}
if (asset->stream) if (asset->stream)
{ {
@ -249,6 +308,10 @@ AAsset_close (AAsset *asset)
asset->stream); asset->stream);
} }
if (asset->name)
(*env)->DeleteGlobalRef (asset->manager->env,
asset->name);
free (asset); free (asset);
} }
@ -264,10 +327,17 @@ android_asset_create_stream (AAsset *asset)
jobject stream; jobject stream;
JNIEnv *env; JNIEnv *env;
assert (asset->fd || asset->name);
env = asset->manager->env; env = asset->manager->env;
stream
= (*env)->CallObjectMethod (env, asset->fd, if (asset->name)
asset->manager->create_input_stream); stream = (*env)->CallObjectMethod (env, asset->manager->asset_manager,
asset->manager->open, asset->name);
else
stream
= (*env)->CallObjectMethod (env, asset->fd,
asset->manager->create_input_stream);
if (!stream) if (!stream)
{ {
@ -380,6 +450,8 @@ AAsset_getLength (AAsset *asset)
if (asset->length != -1) if (asset->length != -1)
return asset->length; return asset->length;
if (!asset->fd)
return 0;
env = asset->manager->env; env = asset->manager->env;
asset->length asset->length

View file

@ -46,8 +46,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#if __ANDROID_API__ >= 9 #if __ANDROID_API__ >= 9
#include <android/asset_manager.h> #include <android/asset_manager.h>
#include <android/asset_manager_jni.h> #include <android/asset_manager_jni.h>
#define OLD_ANDROID_ASSETS 0
#else /* __ANDROID_API__ < 9 */ #else /* __ANDROID_API__ < 9 */
#include "android-asset.h" #include "android-asset.h"
#define OLD_ANDROID_ASSETS 1
#endif /* __ANDROID_API__ >= 9 */ #endif /* __ANDROID_API__ >= 9 */
#include <android/log.h> #include <android/log.h>
@ -1001,7 +1003,7 @@ static AAssetManager *asset_manager;
/* Read an unaligned (32-bit) long from the address POINTER. */ /* Read an unaligned (32-bit) long from the address POINTER. */
static unsigned int static unsigned int
android_extract_long (char *pointer) android_extract_long (const char *pointer)
{ {
unsigned int number; unsigned int number;
@ -1022,16 +1024,20 @@ android_extract_long (char *pointer)
directory. */ directory. */
static const char * static const char *
android_scan_directory_tree (char *file, size_t *limit_return) android_scan_directory_tree (const char *file, size_t *limit_return)
{ {
char *token, *saveptr, *copy, *start, *max, *limit; char *token, *saveptr, *copy, *start, *max, *limit;
size_t token_length, ntokens, i, len; size_t token_length, ntokens, i, len;
char *tokens[10]; char *tokens[20];
USE_SAFE_ALLOCA; USE_SAFE_ALLOCA;
/* Skip past the 5 byte header. */ /* Skip past the 5 or 9 byte header. */
#if !OLD_ANDROID_ASSETS
start = (char *) directory_tree + 5; start = (char *) directory_tree + 5;
#else /* OLD_ANDROID_ASSETS */
start = (char *) directory_tree + 9;
#endif /* OLD_ANDROID_ASSETS */
/* Figure out the current limit. */ /* Figure out the current limit. */
limit = (char *) directory_tree + directory_tree_size; limit = (char *) directory_tree + directory_tree_size;
@ -1098,9 +1104,9 @@ android_scan_directory_tree (char *file, size_t *limit_return)
{ {
/* They probably match. Find the NULL byte. It must be /* They probably match. Find the NULL byte. It must be
either one byte past start + token_length, with the last either one byte past start + token_length, with the last
byte a trailing slash (indicating that it is a byte a trailing slash (indicating that it is a directory),
directory), or just start + token_length. Return 4 bytes or just start + token_length. Return 4 or 8 bytes past the
past the next NULL byte. */ next NULL byte. */
max = memchr (start, 0, limit - start); max = memchr (start, 0, limit - start);
@ -1113,13 +1119,14 @@ android_scan_directory_tree (char *file, size_t *limit_return)
last token. Otherwise, set it as start and the limit as last token. Otherwise, set it as start and the limit as
start + the offset and continue the loop. */ start + the offset and continue the loop. */
if (max && max + 5 <= limit) if (max && max + (OLD_ANDROID_ASSETS ? 9 : 5) <= limit)
{ {
if (i < ntokens - 1) if (i < ntokens - 1)
{ {
start = max + 5; start = max + (OLD_ANDROID_ASSETS ? 9 : 5);
limit = ((char *) directory_tree limit = ((char *) directory_tree
+ android_extract_long (max + 1)); + android_extract_long (max + (OLD_ANDROID_ASSETS
? 5 : 1)));
/* Make sure limit is still in range. */ /* Make sure limit is still in range. */
if (limit > directory_tree + directory_tree_size if (limit > directory_tree + directory_tree_size
@ -1137,10 +1144,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
{ {
/* Figure out the limit. */ /* Figure out the limit. */
if (limit_return) if (limit_return)
*limit_return = android_extract_long (max + 1); *limit_return
= android_extract_long (max + (OLD_ANDROID_ASSETS
? 5 : 1));
/* Go to the end of this file. */ /* Go to the end of this file. */
max += 5; max += (OLD_ANDROID_ASSETS ? 9 : 5);
} }
SAFE_FREE (); SAFE_FREE ();
@ -1161,11 +1170,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
start = memchr (start, 0, limit - start); start = memchr (start, 0, limit - start);
if (!start || start + 5 > limit) if (!start || start + (OLD_ANDROID_ASSETS ? 9 : 5) > limit)
goto fail; goto fail;
start = ((char *) directory_tree start = ((char *) directory_tree
+ android_extract_long (start + 1)); + android_extract_long (start
+ (OLD_ANDROID_ASSETS ? 5 : 1)));
/* Make sure start is still in bounds. */ /* Make sure start is still in bounds. */
@ -1192,13 +1202,20 @@ android_is_directory (const char *dir)
{ {
/* If the directory is the directory tree, then it is a /* If the directory is the directory tree, then it is a
directory. */ directory. */
if (dir == directory_tree + 5) if (dir == directory_tree + (OLD_ANDROID_ASSETS ? 9 : 5))
return true; return true;
#if !OLD_ANDROID_ASSETS
/* Otherwise, look 5 bytes behind. If it is `/', then it is a /* Otherwise, look 5 bytes behind. If it is `/', then it is a
directory. */ directory. */
return (dir - 6 >= directory_tree return (dir - 6 >= directory_tree
&& *(dir - 6) == '/'); && *(dir - 6) == '/');
#else /* OLD_ANDROID_ASSETS */
/* Otherwise, look 9 bytes behind. If it is `/', then it is a
directory. */
return (dir - 10 >= directory_tree
&& *(dir - 10) == '/');
#endif /* OLD_ANDROID_ASSETS */
} }
/* Initialize asset retrieval. ENV should be a JNI environment for /* Initialize asset retrieval. ENV should be a JNI environment for
@ -1232,6 +1249,7 @@ android_init_assets (JNIEnv *env, jobject manager)
/* Now figure out how big the directory tree is, and compare the /* Now figure out how big the directory tree is, and compare the
first few bytes. */ first few bytes. */
directory_tree_size = AAsset_getLength (asset); directory_tree_size = AAsset_getLength (asset);
#if !OLD_ANDROID_ASSETS
if (directory_tree_size < 5 if (directory_tree_size < 5
|| memcmp (directory_tree, "EMACS", 5)) || memcmp (directory_tree, "EMACS", 5))
{ {
@ -1239,6 +1257,15 @@ android_init_assets (JNIEnv *env, jobject manager)
"Directory tree has bad magic"); "Directory tree has bad magic");
emacs_abort (); emacs_abort ();
} }
#else /* OLD_ANDROID_ASSETS */
if (directory_tree_size < 9
|| memcmp (directory_tree, "EMACS____", 9))
{
__android_log_print (ANDROID_LOG_FATAL, __func__,
"Directory tree has bad magic");
emacs_abort ();
}
#endif /* OLD_ANDROID_ASSETS */
/* Hold a VM reference to the asset manager to prevent the native /* Hold a VM reference to the asset manager to prevent the native
object from being deleted. */ object from being deleted. */
@ -2287,8 +2314,13 @@ android_afs_readdir (struct android_vdir *vdir)
dirent.d_type = DT_REG; dirent.d_type = DT_REG;
/* Forward dir->asset_dir to the file past last. */ /* Forward dir->asset_dir to the file past last. */
#if !OLD_ANDROID_ASSETS
dir->asset_dir = ((char *) directory_tree dir->asset_dir = ((char *) directory_tree
+ android_extract_long ((char *) last)); + android_extract_long ((char *) last));
#else /* OLD_ANDROID_ASSETS */
dir->asset_dir = ((char *) directory_tree
+ android_extract_long ((char *) last + 4));
#endif /* OLD_ANDROID_ASSETS */
return &dirent; return &dirent;
} }

View file

@ -69,7 +69,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#define lread_fd_cmp(n) (fd == (n)) #define lread_fd_cmp(n) (fd == (n))
#define lread_fd_p (fd >= 0) #define lread_fd_p (fd >= 0)
#define lread_close emacs_close #define lread_close emacs_close
#define lread_fstat fstat #define lread_fstat sys_fstat
#define lread_read_quit emacs_read_quit #define lread_read_quit emacs_read_quit
#define lread_lseek lseek #define lread_lseek lseek