Update Android port
* configure.ac (ANDROID_STUBIFY): Add androidvfs.o when building libemacs.so. * doc/emacs/android.texi (Android): Add `Android Document Providers'. (Android Startup): Update the location of the content identifier directory. (Android File System): Describe access to document provider directories. (Android Document Providers): New node. * doc/emacs/emacs.texi (Top): Update the menu for the Android appendix. * java/Makefile.in (filename, install_temp/assets/build_info): Make directory-tree depend on build_info. * java/org/gnu/emacs/EmacsActivity.java (onActivityResult): New function. When a document tree is accepted, persist access to it. * java/org/gnu/emacs/EmacsDirectoryEntry.java (EmacsDirectoryEntry): New struct. * java/org/gnu/emacs/EmacsOpenActivity.java (checkReadableOrCopy): Use EmacsService.buildContentName. * java/org/gnu/emacs/EmacsService.java (getEmacsView, openContentUri) (checkContentUri): Remove excessive debug logging. (buildContentName, getDocumentAuthorities, requestDirectoryAccess) (getDocumentTrees, decodeFileName, documentIdFromName, getTreeUri) (statDocument, accessDocument, openDocumentDirectory, readDirectoryEntry) (openDocument, createDocument): New functions. * lib-src/asset-directory-tool.c: Improve commentary by illustrating the difference between directory and ordinary files. * src/android.c (ANDROID_THROW, enum android_fd_table_entry_flags) (struct android_emacs_service, android_extract_long) (android_scan_directory_tree, android_is_directory) (android_get_asset_name, android_url_encode, android_content_name_p) (android_get_content_name, android_check_content_access, android_fstat) (android_fstatat, android_file_access_p, android_hack_asset_fd_fallback) (android_detect_ashmem, android_hack_asset_fd, android_close_on_exec) (android_open, android_close, android_fclose, android_create_lib_link) (android_faccessat, struct android_dir, android_opendir, android_dirfd) (android_readdir, android_closedir, android_lookup_asset_directory_fd) (android_exception_check_3, android_get_current_api_level) (android_open_asset, android_close_asset, android_asset_read_quit) (android_asset_read, android_asset_lseek, android_asset_fstat): Move content and asset related functions to androidvfs.c. (android_init_emacs_service): Obtain handles for new JNI functions. (initEmacsParams): Initialize the VFS layer. (android_request_directory_access): New function. (android_display_toast): Remove unused function. * src/android.h (android_get_current_api_level): Assume that this function never returns less than __ANDROID_API__. (struct android_emacs_service): Move `struct android_emacs_service' here. * src/androidfns.c (Fandroid_request_directory_access): New interactive function. (syms_of_androidfns): Register new subr. * src/androidvfs.c (struct android_vdir, struct android_vops) (struct android_vnode, struct android_special_vnode) (enum android_vnode_type, struct android_cursor_class) (struct emacs_directory_entry_class) (struct android_parcel_file_descriptor_class) (android_init_cursor_class, android_init_entry_class) (android_init_fd_class, android_vfs_canonicalize_name) (struct android_unix_vnode, struct android_unix_vdir, unix_vfs_ops) (android_unix_name, android_unix_vnode, android_unix_open) (android_unix_close, android_unix_unlink, android_unix_symlink) (android_unix_rmdir, android_unix_rename, android_unix_stat) (android_unix_access, android_unix_mkdir, android_unix_readdir) (android_unix_closedir, android_unix_dirfd, android_unix_opendir) (android_extract_long, android_scan_directory_tree) (android_is_directory, android_init_assets) (android_hack_asset_fd_fallback, android_detect_ashmem) (android_hack_asset_fd, struct android_afs_vnode) (struct android_afs_vdir, struct android_afs_open_fd, afs_vfs_ops) (android_afs_name, android_afs_initial, android_close_on_exec) (android_afs_open, android_afs_close, android_afs_unlink) (android_afs_symlink, android_afs_rmdir, android_afs_rename) (android_afs_stat, android_afs_access, android_afs_mkdir) (android_afs_readdir, android_afs_closedir, android_afs_dirfd) (android_afs_opendir, android_afs_get_directory_name) (struct android_content_vdir, content_vfs_ops) (content_directory_contents, android_content_name) (android_content_open, android_content_close) (android_content_unlink, android_content_symlink) (android_content_rmdir, android_content_rename) (android_content_stat, android_content_access) (android_content_mkdir, android_content_readdir) (android_content_closedir, android_content_dirfd) (android_content_opendir, android_content_get_directory_name) (android_content_initial, android_get_content_name) (android_check_content_access, struct android_authority_vnode) (authority_vfs_ops, android_authority_name, android_authority_open) (android_authority_close, android_authority_unlink) (android_authority_symlink, android_authority_rmdir) (android_authority_rename, android_authority_stat) (android_authority_access, android_authority_mkdir) (android_authority_opendir, android_authority_initial) (struct android_saf_root_vnode, struct android_saf_root_vdir) (saf_root_vfs_ops, android_saf_root_name, android_saf_root_open) (android_saf_root_close, android_saf_root_unlink) (android_saf_root_symlink, android_saf_root_rmdir) (android_saf_root_rename, android_saf_root_stat) (android_saf_root_access, android_saf_root_mkdir) (android_saf_root_readdir, android_saf_root_closedir) (android_saf_root_dirfd, android_saf_root_opendir) (android_saf_root_initial, android_saf_root_get_directory) (android_saf_stat, android_saf_access) (struct android_saf_tree_vnode, struct android_saf_tree_vdir) (saf_tree_vfs_ops, android_document_id_from_name) (android_saf_tree_name, android_saf_tree_open) (android_saf_tree_close, android_saf_tree_unlink) (android_saf_tree_symlink, android_saf_tree_rmdir) (android_saf_tree_rename, android_saf_tree_stat) (android_saf_tree_access, android_saf_tree_mkdir) (android_saf_tree_opendir_1, android_saf_tree_readdir) (android_saf_tree_closedir, android_saf_tree_dirfd) (android_saf_tree_opendir, android_saf_tree_from_name) (android_saf_tree_get_directory, android_saf_file_vnode) (saf_file_vfs_ops, android_saf_file_name, android_saf_file_open) (android_saf_file_unlink, android_saf_file_rmdir) (android_saf_file_opendir, android_close_parcel_fd) (android_saf_new_vnode, android_saf_new_name, android_saf_new_open) (android_saf_new_unlink, android_saf_new_symlink) (android_saf_new_rmdir, android_saf_new_rename) (android_saf_new_stat, android_saf_new_access) (android_saf_new_mkdir, android_saf_new_opendir, root_vfs_ops) (special_vnodes, android_root_name, android_name_file) (android_vfs_init, android_open, android_unlink, android_symlink) (android_rmdir, android_mkdir, android_renameat_noreplace) (android_rename, android_fstat, android_fstatat_1, android_fstatat) (android_faccessat, android_fdopen, android_close, android_fclose) (android_open_asset, android_close_asset, android_asset_read_quit) (android_asset_read, android_asset_lseek, android_asset_fstat) (android_opendir, android_dirfd, android_readdir) (android_closedir): Move file system emulation routines here. Introduce a new ``VFS'' layer for translating between Emacs-specific file names and the various disparate interfaces for accessing files on Android. * src/callproc.c (delete_temp_file): * src/charset.c (load_charset_map_from_file): * src/dired.c: * src/emacs.c (Fkill_emacs): * src/fileio.c (check_mutable_filename, Fcopy_file) (Fmake_directory_internal, Fdelete_directory_internal) (Fdelete_file, Frename_file, Fadd_name_to_file) (Fmake_symbolic_link, file_accessible_directory_p, Fset_file_modes) (Fset_file_times, write_region): * src/filelock.c (get_boot_time, rename_lock_file) (create_lock_file, current_lock_owner, unlock_file): * src/image.c (slurp_file, png_load_body, jpeg_load_body): * src/keyboard.c (Fopen_dribble_file): * src/lisp.h: * src/lread.c (Fload): * src/process.c (handle_child_signal): * src/sysdep.c (init_standard_fds, emacs_fopen, emacs_fdopen) (emacs_unlink, emacs_symlink, emacs_rmdir, emacs_mkdir) (emacs_renameat_noreplace, emacs_rename): * src/term.c (Fresume_tty, init_tty): Use and add new wrappers for fopen, fdopen, unlink, symlink, rmdir, mkdir, renameat_norepalce and rename.
This commit is contained in:
parent
ce63f592f5
commit
65b58251b1
26 changed files with 7839 additions and 1677 deletions
|
@ -2689,8 +2689,8 @@ for Android, but all API calls need to be stubbed out])
|
|||
# sfntfont-android.o.
|
||||
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
|
||||
|
||||
# Build androidselect.o.
|
||||
ANDROID_OBJ="$ANDROID_OBJ androidselect.o"
|
||||
# Build androidselect.o and androidvfs.o.
|
||||
ANDROID_OBJ="$ANDROID_OBJ androidselect.o androidvfs.o"
|
||||
|
||||
# Check for some functions not always present in the NDK.
|
||||
AC_CHECK_DECLS([android_get_device_api_level])
|
||||
|
|
|
@ -17,6 +17,7 @@ about using such devices with Emacs, @pxref{Other Input Devices}.
|
|||
* What is Android?:: Preamble.
|
||||
* Android Startup:: Starting up Emacs on Android.
|
||||
* Android File System:: The Android file system.
|
||||
* Android Document Providers:: Accessing files from other programs.
|
||||
* Android Environment:: Running Emacs under Android.
|
||||
* Android Windowing:: The Android window system.
|
||||
* Android Fonts:: Font selection under Android.
|
||||
|
@ -142,12 +143,12 @@ it starts Emacs and gives it the file to open as an argument. Note
|
|||
that if that Emacs in turn does not start the Emacs server, subsequent
|
||||
attempts to open the file with the wrapper will fail.
|
||||
|
||||
@cindex /content directory, android
|
||||
@cindex /content/by-authority directory, android
|
||||
Some files are given to Emacs as ``content identifiers'' that the
|
||||
system provides access to outside the normal filesystem APIs. Emacs
|
||||
uses a pseudo-directory named @file{/content} to access those files.
|
||||
Do not make any assumptions about the contents of this directory, or
|
||||
try to open files in it yourself.
|
||||
uses a pseudo-directory named @file{/content/by-authority} to access
|
||||
those files. Do not make any assumptions about the contents of this
|
||||
directory, or try to open files in it yourself.
|
||||
|
||||
This feature is not provided on Android 4.3 and earlier, in which
|
||||
case such files are copied to a temporary directory before being
|
||||
|
@ -180,12 +181,13 @@ that result from such an implementation:
|
|||
@item
|
||||
Subprocesses (such as @command{ls}) can not run from the
|
||||
@file{/assets} directory; if you try to run a subprocess with
|
||||
@code{current-directory} set to @file{/assets} or a subdirectory
|
||||
thereof, it will run from the home directory instead.
|
||||
@code{current-directory} set to @file{/assets},
|
||||
@file{/content/storage} or a subdirectory thereof, it will run from
|
||||
the home directory instead.
|
||||
|
||||
@item
|
||||
There are no @file{.} and @file{..} directories inside the
|
||||
@file{/assets} directory.
|
||||
@file{/assets} or @file{/content} directory.
|
||||
|
||||
@item
|
||||
Files in the @file{/assets} directory are always read only, and may be
|
||||
|
@ -193,7 +195,7 @@ read in to memory more than once each time they are opened.
|
|||
@end itemize
|
||||
|
||||
Aside from the @file{/assets} directory, Android programs normally
|
||||
have access to three other directories. They are:
|
||||
have access to four other directories. They are:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
|
@ -209,6 +211,12 @@ contains utility executables alongside Emacs itself.
|
|||
The @dfn{external storage} directory. This is accessible to Emacs
|
||||
when the user grants the ``Files and Media'' permission to Emacs via
|
||||
system settings.
|
||||
|
||||
@item
|
||||
Directories provided by @dfn{document providers} on Android 5.0 and
|
||||
later. These directories exist outside the normal Unix filesystem,
|
||||
containing files provided by external programs (@pxref{Android
|
||||
Document Providers}.)
|
||||
@end itemize
|
||||
|
||||
The external storage directory is found at @file{/sdcard}. The
|
||||
|
@ -265,6 +273,46 @@ files under @file{/sdcard} as usual.
|
|||
These settings are not present on many proprietary versions of
|
||||
Android.
|
||||
|
||||
@node Android Document Providers
|
||||
@section Accessing files from other programs under Android
|
||||
@cindex document providers, Android
|
||||
@cindex /content/storage directory, Android
|
||||
|
||||
Android 5.0 introduces a new sort of program, the ``document
|
||||
provider'': these programs are small programs that provide access to
|
||||
their own files outside both the asset manager and the Unix
|
||||
filesystem. Emacs supports accessing files and directories they
|
||||
provide, placing their files within the directory
|
||||
@file{/content/storage}.
|
||||
|
||||
@findex android-request-directory-access
|
||||
Before Emacs is granted access to any of these directories, it must
|
||||
first request the right to access it. This is done by running the
|
||||
command (@pxref{M-x}) @code{android-request-directory-access}, which
|
||||
displays a file selection dialog.
|
||||
|
||||
If a directory is selected within this dialog, its contents are
|
||||
subsequently made available within a new directory named
|
||||
@file{/content/storage/@var{authority}/@var{id}}, where
|
||||
@var{authority} is the name of the document provider, and @var{id} is
|
||||
a unique identifier assigned to the directory by the document
|
||||
provider.
|
||||
|
||||
Because these directories do not exist within the Unix file-system,
|
||||
sub-processes cannot be created within them, just as with the
|
||||
@file{/assets} directory (@pxref{Android File System}.) In addition,
|
||||
although Emacs can normally write and create files inside these
|
||||
directories, it cannot create symlinks or hard links.
|
||||
|
||||
@c TODO: fix this!
|
||||
Since document providers are allowed to perform expensive network
|
||||
operations to obtain file contents, a file access operation within one
|
||||
of these directories will possibly take a significant amount of time.
|
||||
Emacs presently does not support quitting out of such file system
|
||||
operations, and the timeouts applied are fully subject to the
|
||||
discretion of the system and the document provider that is responding
|
||||
to these operations.
|
||||
|
||||
@node Android Environment
|
||||
@section Running Emacs under Android
|
||||
|
||||
|
|
|
@ -1267,6 +1267,7 @@ Emacs and Android
|
|||
* What is Android?:: Preamble.
|
||||
* Android Startup:: Starting up Emacs on Android.
|
||||
* Android File System:: The Android file system.
|
||||
* Android Document Providers:: Accessing files from other programs.
|
||||
* Android Environment:: Running Emacs under Android.
|
||||
* Android Windowing:: The Android window system.
|
||||
* Android Fonts:: Font selection under Android.
|
||||
|
|
|
@ -233,7 +233,8 @@ ifneq ($(NDK_BUILD_SHARED),)
|
|||
endif
|
||||
|
||||
install_temp/assets/directory-tree: $(libsrc)/asset-directory-tool \
|
||||
install_temp install_temp/assets/version
|
||||
install_temp install_temp/assets/version \
|
||||
install_temp/assets/build_info
|
||||
$(AM_V_GEN) $(libsrc)/asset-directory-tool install_temp/assets \
|
||||
install_temp/assets/directory-tree
|
||||
|
||||
|
@ -246,9 +247,9 @@ install_temp/assets/version: install_temp
|
|||
install_temp/assets/build_info: install_temp
|
||||
$(AM_V_GEN) { hostname; date +%s; } > $@
|
||||
|
||||
emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
||||
install_temp/assets/version install_temp/assets/build_info \
|
||||
AndroidManifest.xml
|
||||
emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
||||
AndroidManifest.xml install_temp/assets/version \
|
||||
install_temp/assets/build_info
|
||||
# Package everything. Specifying the assets on this command line is
|
||||
# necessary for AAssetManager_getNextFileName to work on old versions
|
||||
# of Android. Make sure not to generate R.java, as it's already been
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
|
@ -33,6 +34,8 @@
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
@ -48,6 +51,9 @@ public class EmacsActivity extends Activity
|
|||
{
|
||||
public static final String TAG = "EmacsActivity";
|
||||
|
||||
/* ID for URIs from a granted document tree. */
|
||||
public static final int ACCEPT_DOCUMENT_TREE = 1;
|
||||
|
||||
/* The currently attached EmacsWindow, or null if none. */
|
||||
private EmacsWindow window;
|
||||
|
||||
|
@ -431,4 +437,36 @@ public class EmacsActivity extends Activity
|
|||
/* Update the window insets. */
|
||||
syncFullscreenWith (window);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onActivityResult (int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
ContentResolver resolver;
|
||||
Uri uri;
|
||||
int flags;
|
||||
|
||||
switch (requestCode)
|
||||
{
|
||||
case ACCEPT_DOCUMENT_TREE:
|
||||
|
||||
/* A document granted through
|
||||
EmacsService.requestDirectoryAccess. */
|
||||
|
||||
if (resultCode == RESULT_OK)
|
||||
{
|
||||
resolver = getContentResolver ();
|
||||
uri = data.getData ();
|
||||
flags = (Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
if (uri != null)
|
||||
resolver.takePersistableUriPermission (uri, flags);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
33
java/org/gnu/emacs/EmacsDirectoryEntry.java
Normal file
33
java/org/gnu/emacs/EmacsDirectoryEntry.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
/* Structure holding a single ``directory entry'' from a document
|
||||
provider. */
|
||||
|
||||
public class EmacsDirectoryEntry
|
||||
{
|
||||
/* The type of this directory entry. 0 means a regular file and 1
|
||||
means a directory. */
|
||||
public int d_type;
|
||||
|
||||
/* The display name of the file represented. */
|
||||
public String d_name;
|
||||
};
|
|
@ -243,18 +243,8 @@ private class EmacsClientThread extends Thread
|
|||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
{
|
||||
content = "/content/" + uri.getEncodedAuthority ();
|
||||
|
||||
for (String segment : uri.getPathSegments ())
|
||||
content += "/" + Uri.encode (segment);
|
||||
|
||||
/* Append the URI query. */
|
||||
|
||||
if (uri.getEncodedQuery () != null)
|
||||
content += "?" + uri.getEncodedQuery ();
|
||||
|
||||
content = EmacsService.buildContentName (uri);
|
||||
Log.d (TAG, "checkReadableOrCopy: " + content);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
the first file or directory, a NULL byte and an unsigned int
|
||||
indicating the offset from the start of the file to the start of
|
||||
the next sibling. Following that is a list of subdirectories or
|
||||
files in the same format. The long is stored LSB first. */
|
||||
files in the same format. The long is stored LSB first.
|
||||
|
||||
Directories can be distinguished from ordinary files through the
|
||||
last bytes of their file names (immediately previous to their
|
||||
terminating NULL bytes), which are set to the directory separator
|
||||
character `/'. */
|
||||
|
||||
|
||||
|
||||
|
|
1801
src/android.c
1801
src/android.c
File diff suppressed because it is too large
Load diff
|
@ -36,26 +36,46 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "androidgui.h"
|
||||
#include "lisp.h"
|
||||
#endif
|
||||
#endif /* ANDROID_STUBIFY */
|
||||
|
||||
extern bool android_init_gui;
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
extern char *android_cache_dir;
|
||||
|
||||
extern int android_emacs_init (int, char **, char *);
|
||||
extern int android_select (int, fd_set *, fd_set *, fd_set *,
|
||||
struct timespec *);
|
||||
extern char *android_user_full_name (struct passwd *);
|
||||
|
||||
|
||||
|
||||
/* File I/O operations. Many of these are defined in
|
||||
androidvfs.c. */
|
||||
|
||||
extern const char *android_is_special_directory (const char *, const char *);
|
||||
extern const char *android_get_home_directory (void);
|
||||
|
||||
extern void android_vfs_init (JNIEnv *, jobject);
|
||||
|
||||
extern int android_open (const char *, int, mode_t);
|
||||
extern char *android_user_full_name (struct passwd *);
|
||||
extern const char *android_is_special_directory (const char *, const char *);
|
||||
extern int android_fstat (int, struct stat *);
|
||||
extern int android_fstatat (int, const char *restrict,
|
||||
struct stat *restrict, int);
|
||||
extern int android_faccessat (int, const char *, int, int);
|
||||
extern int android_close (int);
|
||||
extern FILE *android_fdopen (int, const char *);
|
||||
extern int android_fclose (FILE *);
|
||||
extern const char *android_get_home_directory (void);
|
||||
extern int android_unlink (const char *);
|
||||
extern int android_symlink (const char *, const char *);
|
||||
extern int android_rmdir (const char *);
|
||||
extern int android_mkdir (const char *, mode_t);
|
||||
extern int android_renameat_noreplace (int, const char *,
|
||||
int, const char *);
|
||||
extern int android_rename (const char *, const char *);
|
||||
|
||||
|
||||
|
||||
extern double android_pixel_density_x, android_pixel_density_y;
|
||||
extern double android_scaled_pixel_density;
|
||||
|
@ -89,6 +109,7 @@ extern jstring android_build_jstring (const char *);
|
|||
extern void android_exception_check (void);
|
||||
extern void android_exception_check_1 (jobject);
|
||||
extern void android_exception_check_2 (jobject, jobject);
|
||||
extern void android_exception_check_3 (jobject, jobject, jobject);
|
||||
extern void android_exception_check_nonnull (void *, jobject);
|
||||
extern void android_exception_check_nonnull_1 (void *, jobject, jobject);
|
||||
|
||||
|
@ -96,18 +117,29 @@ extern void android_get_keysym_name (int, char *, size_t);
|
|||
extern void android_wait_event (void);
|
||||
extern void android_toggle_on_screen_keyboard (android_window, bool);
|
||||
extern _Noreturn void android_restart_emacs (void);
|
||||
extern int android_get_current_api_level (void);
|
||||
extern int android_request_directory_access (void);
|
||||
extern int android_get_current_api_level (void)
|
||||
__attribute__ ((pure));
|
||||
|
||||
/* Define `android_get_current_api_level' to a macro that the compiler
|
||||
knows will always return at least __ANDROID_API__. */
|
||||
|
||||
#define android_get_current_api_level() \
|
||||
({ int value; \
|
||||
\
|
||||
value = (android_get_current_api_level) (); \
|
||||
eassume (value >= __ANDROID_API__); value; })
|
||||
|
||||
|
||||
|
||||
/* Directory listing emulation. */
|
||||
|
||||
struct android_dir;
|
||||
struct android_vdir;
|
||||
|
||||
extern struct android_dir *android_opendir (const char *);
|
||||
extern int android_dirfd (struct android_dir *);
|
||||
extern struct dirent *android_readdir (struct android_dir *);
|
||||
extern void android_closedir (struct android_dir *);
|
||||
extern struct android_vdir *android_opendir (const char *);
|
||||
extern int android_dirfd (struct android_vdir *);
|
||||
extern struct dirent *android_readdir (struct android_vdir *);
|
||||
extern void android_closedir (struct android_vdir *);
|
||||
|
||||
|
||||
|
||||
|
@ -211,8 +243,52 @@ extern int android_rewrite_spawn_argv (const char ***);
|
|||
#ifndef ANDROID_STUBIFY
|
||||
#include <jni.h>
|
||||
|
||||
struct android_emacs_service
|
||||
{
|
||||
jclass class;
|
||||
jmethodID fill_rectangle;
|
||||
jmethodID fill_polygon;
|
||||
jmethodID draw_rectangle;
|
||||
jmethodID draw_line;
|
||||
jmethodID draw_point;
|
||||
jmethodID clear_window;
|
||||
jmethodID clear_area;
|
||||
jmethodID ring_bell;
|
||||
jmethodID query_tree;
|
||||
jmethodID get_screen_width;
|
||||
jmethodID get_screen_height;
|
||||
jmethodID detect_mouse;
|
||||
jmethodID name_keysym;
|
||||
jmethodID browse_url;
|
||||
jmethodID restart_emacs;
|
||||
jmethodID update_ic;
|
||||
jmethodID reset_ic;
|
||||
jmethodID open_content_uri;
|
||||
jmethodID check_content_uri;
|
||||
jmethodID query_battery;
|
||||
jmethodID update_extracted_text;
|
||||
jmethodID update_cursor_anchor_info;
|
||||
jmethodID get_document_authorities;
|
||||
jmethodID request_directory_access;
|
||||
jmethodID get_document_trees;
|
||||
jmethodID document_id_from_name;
|
||||
jmethodID get_tree_uri;
|
||||
jmethodID stat_document;
|
||||
jmethodID access_document;
|
||||
jmethodID open_document_directory;
|
||||
jmethodID read_directory_entry;
|
||||
jmethodID open_document;
|
||||
jmethodID create_document;
|
||||
};
|
||||
|
||||
extern JNIEnv *android_java_env;
|
||||
|
||||
/* The EmacsService object. */
|
||||
extern jobject emacs_service;
|
||||
|
||||
/* Various methods associated with the EmacsService. */
|
||||
extern struct android_emacs_service service_class;
|
||||
|
||||
#define ANDROID_DELETE_LOCAL_REF(ref) \
|
||||
((*android_java_env)->DeleteLocalRef (android_java_env, \
|
||||
(ref)))
|
||||
|
|
|
@ -3036,6 +3036,32 @@ for more details about these values. */)
|
|||
|
||||
|
||||
|
||||
/* Directory access requests. */
|
||||
|
||||
DEFUN ("android-request-directory-access", Fandroid_request_directory_access,
|
||||
Sandroid_request_directory_access, 0, 0, "",
|
||||
doc: /* Request access to a directory within external storage.
|
||||
On Android 5.0 and later, prompt for a directory within external or
|
||||
application storage, and grant access to it; some of these directories
|
||||
cannot be accessed through the regular `/sdcard' filesystem.
|
||||
|
||||
If access to the directory is granted, it will eventually appear
|
||||
within the directory `/content/storage'. */)
|
||||
(void)
|
||||
{
|
||||
if (android_get_current_api_level () < 21)
|
||||
error ("Emacs can only access application storage on"
|
||||
" Android 5.0 and later");
|
||||
|
||||
if (!android_init_gui)
|
||||
return Qnil;
|
||||
|
||||
android_request_directory_access ();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Miscellaneous input method related stuff. */
|
||||
|
||||
/* Report X, Y, by the phys cursor width and height as the cursor
|
||||
|
@ -3062,7 +3088,7 @@ android_set_preeditarea (struct window *w, int x, int y)
|
|||
y + w->phys_cursor_height);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* !ANDROID_STUBIFY */
|
||||
|
||||
|
||||
|
||||
|
@ -3220,6 +3246,7 @@ This option has no effect on Android 9 and earlier. */);
|
|||
defsubr (&Sx_server_version);
|
||||
#ifndef ANDROID_STUBIFY
|
||||
defsubr (&Sandroid_query_battery);
|
||||
defsubr (&Sandroid_request_directory_access);
|
||||
|
||||
tip_timer = Qnil;
|
||||
staticpro (&tip_timer);
|
||||
|
@ -3235,5 +3262,5 @@ This option has no effect on Android 9 and earlier. */);
|
|||
staticpro (&tip_dx);
|
||||
tip_dy = Qnil;
|
||||
staticpro (&tip_dy);
|
||||
#endif
|
||||
#endif /* !ANDROID_STUBIFY */
|
||||
}
|
||||
|
|
6137
src/androidvfs.c
Normal file
6137
src/androidvfs.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -214,7 +214,7 @@ record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
|
|||
static void
|
||||
delete_temp_file (Lisp_Object name)
|
||||
{
|
||||
unlink (SSDATA (name));
|
||||
emacs_unlink (SSDATA (name));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -488,7 +488,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
|
|||
specbind (Qfile_name_handler_alist, Qnil);
|
||||
fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, false, false,
|
||||
NULL);
|
||||
fp = fd < 0 ? 0 : fdopen (fd, "r");
|
||||
fp = fd < 0 ? 0 : emacs_fdopen (fd, "r");
|
||||
if (!fp)
|
||||
{
|
||||
int open_errno = errno;
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef DIR emacs_dir;
|
|||
|
||||
/* The Android emulation of dirent stuff is required to be able to
|
||||
list the /assets special directory. */
|
||||
typedef struct android_dir emacs_dir;
|
||||
typedef struct android_vdir emacs_dir;
|
||||
#define emacs_readdir android_readdir
|
||||
#define emacs_closedir android_closedir
|
||||
#endif
|
||||
|
|
|
@ -3012,7 +3012,7 @@ killed. */
|
|||
{
|
||||
Lisp_Object listfile;
|
||||
listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
|
||||
unlink (SSDATA (listfile));
|
||||
emacs_unlink (SSDATA (listfile));
|
||||
}
|
||||
|
||||
#ifdef HAVE_NATIVE_COMP
|
||||
|
|
96
src/fileio.c
96
src/fileio.c
|
@ -182,15 +182,12 @@ static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
|
|||
|
||||
|
||||
|
||||
/* Check that ENCODED does not lie on any special directory whose
|
||||
contents are read only. Signal a `file-error' if it does.
|
||||
|
||||
If WRITE, then don't check that the file lies on `/content' on
|
||||
Android. This special exception allows writing to content
|
||||
provider-supplied files. */
|
||||
/* Establish that ENCODED is not contained within a special directory
|
||||
whose contents are not eligible for Unix VFS operations. Signal a
|
||||
`file-error' with REASON if it does. */
|
||||
|
||||
static void
|
||||
check_mutable_filename (Lisp_Object encoded, bool write)
|
||||
check_vfs_filename (Lisp_Object encoded, const char *reason)
|
||||
{
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
const char *name;
|
||||
|
@ -198,17 +195,10 @@ check_mutable_filename (Lisp_Object encoded, bool write)
|
|||
name = SSDATA (encoded);
|
||||
|
||||
if (android_is_special_directory (name, "/assets"))
|
||||
xsignal2 (Qfile_error,
|
||||
build_string ("File lies on read-only directory"),
|
||||
encoded);
|
||||
|
||||
if (write)
|
||||
return;
|
||||
xsignal2 (Qfile_error, build_string (reason), encoded);
|
||||
|
||||
if (android_is_special_directory (name, "/content"))
|
||||
xsignal2 (Qfile_error,
|
||||
build_string ("File lies on read-only directory"),
|
||||
encoded);
|
||||
xsignal2 (Qfile_error, build_string (reason), encoded);
|
||||
#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
|
||||
}
|
||||
|
||||
|
@ -2287,7 +2277,6 @@ permissions. */)
|
|||
|
||||
encoded_file = ENCODE_FILE (file);
|
||||
encoded_newname = ENCODE_FILE (newname);
|
||||
check_mutable_filename (encoded_newname, true);
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
if (NILP (ok_if_already_exists)
|
||||
|
@ -2553,7 +2542,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
|
|||
|
||||
dir = SSDATA (encoded_dir);
|
||||
|
||||
if (mkdir (dir, 0777 & ~auto_saving_dir_umask) != 0)
|
||||
if (emacs_mkdir (dir, 0777 & ~auto_saving_dir_umask) != 0)
|
||||
report_file_error ("Creating directory", directory);
|
||||
|
||||
return Qnil;
|
||||
|
@ -2572,9 +2561,7 @@ DEFUN ("delete-directory-internal", Fdelete_directory_internal,
|
|||
encoded_dir = ENCODE_FILE (directory);
|
||||
dir = SSDATA (encoded_dir);
|
||||
|
||||
check_mutable_filename (encoded_dir, false);
|
||||
|
||||
if (rmdir (dir) != 0)
|
||||
if (emacs_rmdir (dir) != 0)
|
||||
report_file_error ("Removing directory", directory);
|
||||
|
||||
return Qnil;
|
||||
|
@ -2613,9 +2600,9 @@ With a prefix argument, TRASH is nil. */)
|
|||
return call1 (Qmove_file_to_trash, filename);
|
||||
|
||||
encoded_file = ENCODE_FILE (filename);
|
||||
check_mutable_filename (encoded_file, false);
|
||||
|
||||
if (unlink (SSDATA (encoded_file)) != 0 && errno != ENOENT)
|
||||
if (emacs_unlink (SSDATA (encoded_file)) != 0
|
||||
&& errno != ENOENT)
|
||||
report_file_error ("Removing old name", filename);
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -2771,8 +2758,6 @@ This is what happens in interactive use with M-x. */)
|
|||
|
||||
encoded_file = ENCODE_FILE (file);
|
||||
encoded_newname = ENCODE_FILE (newname);
|
||||
check_mutable_filename (encoded_file, false);
|
||||
check_mutable_filename (encoded_newname, false);
|
||||
|
||||
bool plain_rename = (case_only_rename
|
||||
|| (!NILP (ok_if_already_exists)
|
||||
|
@ -2780,8 +2765,10 @@ This is what happens in interactive use with M-x. */)
|
|||
int rename_errno UNINIT;
|
||||
if (!plain_rename)
|
||||
{
|
||||
if (renameat_noreplace (AT_FDCWD, SSDATA (encoded_file),
|
||||
AT_FDCWD, SSDATA (encoded_newname))
|
||||
if (emacs_renameat_noreplace (AT_FDCWD,
|
||||
SSDATA (encoded_file),
|
||||
AT_FDCWD,
|
||||
SSDATA (encoded_newname))
|
||||
== 0)
|
||||
return Qnil;
|
||||
|
||||
|
@ -2803,7 +2790,8 @@ This is what happens in interactive use with M-x. */)
|
|||
|
||||
if (plain_rename)
|
||||
{
|
||||
if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
||||
if (emacs_rename (SSDATA (encoded_file),
|
||||
SSDATA (encoded_newname)) == 0)
|
||||
return Qnil;
|
||||
rename_errno = errno;
|
||||
/* Don't prompt again. */
|
||||
|
@ -2884,8 +2872,10 @@ This is what happens in interactive use with M-x. */)
|
|||
|
||||
encoded_file = ENCODE_FILE (file);
|
||||
encoded_newname = ENCODE_FILE (newname);
|
||||
check_mutable_filename (encoded_file, false);
|
||||
check_mutable_filename (encoded_newname, false);
|
||||
check_vfs_filename (encoded_file, "Trying to create hard link to "
|
||||
"file within special directory");
|
||||
check_vfs_filename (encoded_newname, "Trying to create hard link"
|
||||
" within special directory");
|
||||
|
||||
if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
||||
return Qnil;
|
||||
|
@ -2896,7 +2886,7 @@ This is what happens in interactive use with M-x. */)
|
|||
|| FIXNUMP (ok_if_already_exists))
|
||||
barf_or_query_if_file_exists (newname, true, "make it a new name",
|
||||
FIXNUMP (ok_if_already_exists), false);
|
||||
unlink (SSDATA (newname));
|
||||
emacs_unlink (SSDATA (newname));
|
||||
if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -2939,10 +2929,9 @@ This happens for interactive use with M-x. */)
|
|||
|
||||
encoded_target = ENCODE_FILE (target);
|
||||
encoded_linkname = ENCODE_FILE (linkname);
|
||||
check_mutable_filename (encoded_target, false);
|
||||
check_mutable_filename (encoded_linkname, false);
|
||||
|
||||
if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0)
|
||||
if (emacs_symlink (SSDATA (encoded_target),
|
||||
SSDATA (encoded_linkname)) == 0)
|
||||
return Qnil;
|
||||
|
||||
if (errno == ENOSYS)
|
||||
|
@ -2955,8 +2944,9 @@ This happens for interactive use with M-x. */)
|
|||
|| FIXNUMP (ok_if_already_exists))
|
||||
barf_or_query_if_file_exists (linkname, true, "make it a link",
|
||||
FIXNUMP (ok_if_already_exists), false);
|
||||
unlink (SSDATA (encoded_linkname));
|
||||
if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0)
|
||||
emacs_unlink (SSDATA (encoded_linkname));
|
||||
if (emacs_symlink (SSDATA (encoded_target),
|
||||
SSDATA (encoded_linkname)) == 0)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
@ -3328,27 +3318,12 @@ file_accessible_directory_p (Lisp_Object file)
|
|||
special cases "/" and "//", and it's a safe optimization
|
||||
here. After appending '.', append another '/' to work around
|
||||
a macOS bug (Bug#30350). */
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
if (!strncmp ("/assets/", data,
|
||||
sizeof "/assets" - 1))
|
||||
{
|
||||
static char const appended[] = "/";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
static char const appended[] = "/./";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
}
|
||||
#endif
|
||||
|
||||
static char const appended[] = "/./";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
}
|
||||
|
||||
ok = file_access_p (dir, F_OK);
|
||||
|
@ -3682,7 +3657,8 @@ command from GNU Coreutils. */)
|
|||
return call4 (handler, Qset_file_modes, absname, mode, flag);
|
||||
|
||||
encoded = ENCODE_FILE (absname);
|
||||
check_mutable_filename (encoded, false);
|
||||
check_vfs_filename (encoded, "Trying to change access modes of file"
|
||||
" within special directory");
|
||||
char *fname = SSDATA (encoded);
|
||||
mode_t imode = XFIXNUM (mode) & 07777;
|
||||
if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
|
||||
|
@ -3755,7 +3731,8 @@ TIMESTAMP is in the format of `current-time'. */)
|
|||
return call4 (handler, Qset_file_times, absname, timestamp, flag);
|
||||
|
||||
Lisp_Object encoded_absname = ENCODE_FILE (absname);
|
||||
check_mutable_filename (encoded_absname, false);
|
||||
check_vfs_filename (encoded_absname, "Trying to set access times of"
|
||||
" file within special directory");
|
||||
|
||||
if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0)
|
||||
{
|
||||
|
@ -5456,7 +5433,6 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
|
|||
}
|
||||
|
||||
encoded_filename = ENCODE_FILE (filename);
|
||||
check_mutable_filename (encoded_filename, false);
|
||||
|
||||
fn = SSDATA (encoded_filename);
|
||||
open_flags = O_WRONLY | O_CREAT;
|
||||
|
|
|
@ -228,7 +228,7 @@ get_boot_time (void)
|
|||
{
|
||||
get_boot_time_1 (SSDATA (filename), 1);
|
||||
if (delete_flag)
|
||||
unlink (SSDATA (filename));
|
||||
emacs_unlink (SSDATA (filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,11 +323,12 @@ rename_lock_file (char const *old, char const *new, bool force)
|
|||
{
|
||||
struct stat st;
|
||||
|
||||
int r = renameat_noreplace (AT_FDCWD, old, AT_FDCWD, new);
|
||||
int r = emacs_renameat_noreplace (AT_FDCWD, old,
|
||||
AT_FDCWD, new);
|
||||
if (! (r < 0 && errno == ENOSYS))
|
||||
return r;
|
||||
if (link (old, new) == 0)
|
||||
return unlink (old) == 0 || errno == ENOENT ? 0 : -1;
|
||||
return emacs_unlink (old) == 0 || errno == ENOENT ? 0 : -1;
|
||||
if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
|
||||
return -1;
|
||||
|
||||
|
@ -347,7 +348,7 @@ rename_lock_file (char const *old, char const *new, bool force)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return rename (old, new);
|
||||
return emacs_rename (old, new);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -365,13 +366,13 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
|
|||
pretending that 'symlink' does not work. */
|
||||
int err = ENOSYS;
|
||||
#else
|
||||
int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||
int err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||
#endif
|
||||
|
||||
if (err == EEXIST && force)
|
||||
{
|
||||
unlink (lfname);
|
||||
err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||
emacs_unlink (lfname);
|
||||
err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||
}
|
||||
|
||||
if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
|
||||
|
@ -409,7 +410,7 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
|
|||
if (!err && rename_lock_file (nonce, lfname, force) != 0)
|
||||
err = errno;
|
||||
if (err)
|
||||
unlink (nonce);
|
||||
emacs_unlink (nonce);
|
||||
}
|
||||
|
||||
SAFE_FREE ();
|
||||
|
@ -622,7 +623,7 @@ current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
|
|||
/* The owner process is dead or has a strange pid, so try to
|
||||
zap the lockfile. */
|
||||
else
|
||||
return unlink (SSDATA (lfname)) < 0 ? errno : 0;
|
||||
return emacs_unlink (SSDATA (lfname)) < 0 ? errno : 0;
|
||||
}
|
||||
else
|
||||
{ /* If we wanted to support the check for stale locks on remote machines,
|
||||
|
@ -770,7 +771,8 @@ unlock_file (Lisp_Object fn)
|
|||
int err = current_lock_owner (0, lfname);
|
||||
if (! (err == 0 || err == ANOTHER_OWNS_IT
|
||||
|| (err == I_OWN_IT
|
||||
&& (unlink (SSDATA (lfname)) == 0 || (err = errno) == ENOENT))))
|
||||
&& (emacs_unlink (SSDATA (lfname)) == 0
|
||||
|| (err = errno) == ENOENT))))
|
||||
report_file_errno ("Unlocking file", fn, err);
|
||||
|
||||
return Qnil;
|
||||
|
|
|
@ -4234,7 +4234,7 @@ static char *
|
|||
slurp_file (image_fd fd, ptrdiff_t *size)
|
||||
{
|
||||
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
|
||||
FILE *fp = fdopen (fd, "rb");
|
||||
FILE *fp = emacs_fdopen (fd, "rb");
|
||||
|
||||
char *buf = NULL;
|
||||
struct stat st;
|
||||
|
@ -8021,7 +8021,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
|
|||
}
|
||||
|
||||
/* Open the image file. */
|
||||
fp = fdopen (fd, "rb");
|
||||
fp = emacs_fdopen (fd, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
image_error ("Cannot open image file `%s'", file);
|
||||
|
@ -8750,7 +8750,7 @@ jpeg_load_body (struct frame *f, struct image *img,
|
|||
return 0;
|
||||
}
|
||||
|
||||
fp = fdopen (fd, "rb");
|
||||
fp = emacs_fdopen (fd, "rb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
image_error ("Cannot open `%s'", file);
|
||||
|
|
|
@ -11740,9 +11740,9 @@ This may include sensitive information such as passwords. */)
|
|||
encfile = ENCODE_FILE (file);
|
||||
fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0 && errno == EEXIST
|
||||
&& (unlink (SSDATA (encfile)) == 0 || errno == ENOENT))
|
||||
&& (emacs_unlink (SSDATA (encfile)) == 0 || errno == ENOENT))
|
||||
fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
dribble = fd < 0 ? 0 : fdopen (fd, "w");
|
||||
dribble = fd < 0 ? 0 : emacs_fdopen (fd, "w");
|
||||
if (dribble == 0)
|
||||
report_file_error ("Opening dribble", file);
|
||||
}
|
||||
|
|
|
@ -5086,7 +5086,15 @@ extern int emacs_open (const char *, int, int);
|
|||
extern int emacs_open_noquit (const char *, int, int);
|
||||
extern int emacs_pipe (int[2]);
|
||||
extern int emacs_close (int);
|
||||
extern FILE *emacs_fdopen (int, const char *);
|
||||
extern int emacs_fclose (FILE *);
|
||||
extern int emacs_unlink (const char *);
|
||||
extern int emacs_symlink (const char *, const char *);
|
||||
extern int emacs_rmdir (const char *);
|
||||
extern int emacs_mkdir (const char *, mode_t);
|
||||
extern int emacs_renameat_noreplace (int, const char *, int,
|
||||
const char *);
|
||||
extern int emacs_rename (const char *, const char *);
|
||||
extern ptrdiff_t emacs_read (int, void *, ptrdiff_t);
|
||||
extern ptrdiff_t emacs_read_quit (int, void *, ptrdiff_t);
|
||||
extern ptrdiff_t emacs_write (int, void const *, ptrdiff_t);
|
||||
|
|
|
@ -1702,7 +1702,7 @@ Return t if the file exists and loads successfully. */)
|
|||
stream = emacs_fopen (SSDATA (efound), fmode);
|
||||
#else
|
||||
#if !defined USE_ANDROID_ASSETS
|
||||
stream = fdopen (fd, fmode);
|
||||
stream = emacs_fdopen (fd, fmode);
|
||||
#else
|
||||
/* Android systems use special file descriptors which can point
|
||||
into compressed data and double as file streams. FMODE is
|
||||
|
|
|
@ -7472,6 +7472,16 @@ handle_child_signal (int sig)
|
|||
{
|
||||
changed = true;
|
||||
if (STRINGP (XCDR (head)))
|
||||
/* handle_child_signal is called in an async signal
|
||||
handler but needs to unlink temporary files which
|
||||
might've been created in an Android content
|
||||
provider.
|
||||
|
||||
emacs_unlink is not async signal safe because
|
||||
deleting files from content providers must proceed
|
||||
through Java code. Consequentially, if XCDR (head)
|
||||
lies on a content provider it will not be removed,
|
||||
which is a bug. */
|
||||
unlink (SSDATA (XCDR (head)));
|
||||
XSETCAR (tail, Qnil);
|
||||
}
|
||||
|
|
82
src/sysdep.c
82
src/sysdep.c
|
@ -260,7 +260,7 @@ init_standard_fds (void)
|
|||
/* Set buferr if possible on platforms defining _PC_PIPE_BUF, as
|
||||
they support the notion of atomic writes to pipes. */
|
||||
#ifdef _PC_PIPE_BUF
|
||||
buferr = fdopen (STDERR_FILENO, "w");
|
||||
buferr = emacs_fdopen (STDERR_FILENO, "w");
|
||||
if (buferr)
|
||||
setvbuf (buferr, NULL, _IOLBF, 0);
|
||||
#endif
|
||||
|
@ -2545,7 +2545,7 @@ emacs_fopen (char const *file, char const *mode)
|
|||
}
|
||||
|
||||
fd = emacs_open (file, omode | oflags | bflag, 0666);
|
||||
return fd < 0 ? 0 : fdopen (fd, mode);
|
||||
return fd < 0 ? 0 : emacs_fdopen (fd, mode);
|
||||
}
|
||||
|
||||
/* Create a pipe for Emacs use. */
|
||||
|
@ -2627,6 +2627,19 @@ emacs_close (int fd)
|
|||
}
|
||||
}
|
||||
|
||||
/* Wrapper around fdopen. On Android, this calls `android_fclose' to
|
||||
clear information associated with FD if necessary. */
|
||||
|
||||
FILE *
|
||||
emacs_fdopen (int fd, const char *mode)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return fdopen (fd, mode);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_fdopen (fd, mode);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
/* Wrapper around fclose. On Android, this calls `android_fclose' to
|
||||
clear information associated with the FILE's file descriptor if
|
||||
necessary. */
|
||||
|
@ -2641,6 +2654,71 @@ emacs_fclose (FILE *stream)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Wrappers around unlink, symlink, rename, renameat_noreplace, and
|
||||
rmdir. These operations handle asset and content directories on
|
||||
Android. */
|
||||
|
||||
int
|
||||
emacs_unlink (const char *name)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return unlink (name);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_unlink (name);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
int
|
||||
emacs_symlink (const char *target, const char *linkname)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return symlink (target, linkname);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_symlink (target, linkname);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
int
|
||||
emacs_rmdir (const char *dirname)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return rmdir (dirname);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_rmdir (dirname);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
int
|
||||
emacs_mkdir (const char *dirname, mode_t mode)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return mkdir (dirname, mode);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_mkdir (dirname, mode);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
int
|
||||
emacs_renameat_noreplace (int srcfd, const char *src,
|
||||
int dstfd, const char *dst)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return renameat_noreplace (srcfd, src, dstfd, dst);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_renameat_noreplace (srcfd, src, dstfd, dst);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
int
|
||||
emacs_rename (const char *src, const char *dst)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return rename (src, dst);
|
||||
#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
return android_rename (src, dst);
|
||||
#endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */
|
||||
}
|
||||
|
||||
/* Maximum number of bytes to read or write in a single system call.
|
||||
This works around a serious bug in Linux kernels before 2.6.16; see
|
||||
<https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
|
||||
|
|
|
@ -2415,7 +2415,7 @@ frame's terminal). */)
|
|||
#else /* !MSDOS */
|
||||
fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
|
||||
t->display_info.tty->input = t->display_info.tty->output
|
||||
= fd < 0 ? 0 : fdopen (fd, "w+");
|
||||
= fd < 0 ? 0 : emacs_fdopen (fd, "w+");
|
||||
|
||||
if (! t->display_info.tty->input)
|
||||
{
|
||||
|
@ -4128,7 +4128,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
|
|||
tty->input = tty->output
|
||||
= ((fd < 0 || ! isatty (fd))
|
||||
? NULL
|
||||
: fdopen (fd, "w+"));
|
||||
: emacs_fdopen (fd, "w+"));
|
||||
|
||||
if (! tty->input)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue