mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-03 19:03:24 +00:00
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.
|
# sfntfont-android.o.
|
||||||
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
|
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
|
||||||
|
|
||||||
# Build androidselect.o.
|
# Build androidselect.o and androidvfs.o.
|
||||||
ANDROID_OBJ="$ANDROID_OBJ androidselect.o"
|
ANDROID_OBJ="$ANDROID_OBJ androidselect.o androidvfs.o"
|
||||||
|
|
||||||
# Check for some functions not always present in the NDK.
|
# Check for some functions not always present in the NDK.
|
||||||
AC_CHECK_DECLS([android_get_device_api_level])
|
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.
|
* What is Android?:: Preamble.
|
||||||
* Android Startup:: Starting up Emacs on Android.
|
* Android Startup:: Starting up Emacs on Android.
|
||||||
* Android File System:: The Android file system.
|
* Android File System:: The Android file system.
|
||||||
|
* Android Document Providers:: Accessing files from other programs.
|
||||||
* Android Environment:: Running Emacs under Android.
|
* Android Environment:: Running Emacs under Android.
|
||||||
* Android Windowing:: The Android window system.
|
* Android Windowing:: The Android window system.
|
||||||
* Android Fonts:: Font selection under Android.
|
* 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
|
that if that Emacs in turn does not start the Emacs server, subsequent
|
||||||
attempts to open the file with the wrapper will fail.
|
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
|
Some files are given to Emacs as ``content identifiers'' that the
|
||||||
system provides access to outside the normal filesystem APIs. Emacs
|
system provides access to outside the normal filesystem APIs. Emacs
|
||||||
uses a pseudo-directory named @file{/content} to access those files.
|
uses a pseudo-directory named @file{/content/by-authority} to access
|
||||||
Do not make any assumptions about the contents of this directory, or
|
those files. Do not make any assumptions about the contents of this
|
||||||
try to open files in it yourself.
|
directory, or try to open files in it yourself.
|
||||||
|
|
||||||
This feature is not provided on Android 4.3 and earlier, in which
|
This feature is not provided on Android 4.3 and earlier, in which
|
||||||
case such files are copied to a temporary directory before being
|
case such files are copied to a temporary directory before being
|
||||||
|
@ -180,12 +181,13 @@ that result from such an implementation:
|
||||||
@item
|
@item
|
||||||
Subprocesses (such as @command{ls}) can not run from the
|
Subprocesses (such as @command{ls}) can not run from the
|
||||||
@file{/assets} directory; if you try to run a subprocess with
|
@file{/assets} directory; if you try to run a subprocess with
|
||||||
@code{current-directory} set to @file{/assets} or a subdirectory
|
@code{current-directory} set to @file{/assets},
|
||||||
thereof, it will run from the home directory instead.
|
@file{/content/storage} or a subdirectory thereof, it will run from
|
||||||
|
the home directory instead.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
There are no @file{.} and @file{..} directories inside the
|
There are no @file{.} and @file{..} directories inside the
|
||||||
@file{/assets} directory.
|
@file{/assets} or @file{/content} directory.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Files in the @file{/assets} directory are always read only, and may be
|
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
|
@end itemize
|
||||||
|
|
||||||
Aside from the @file{/assets} directory, Android programs normally
|
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
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
|
@ -209,6 +211,12 @@ contains utility executables alongside Emacs itself.
|
||||||
The @dfn{external storage} directory. This is accessible to Emacs
|
The @dfn{external storage} directory. This is accessible to Emacs
|
||||||
when the user grants the ``Files and Media'' permission to Emacs via
|
when the user grants the ``Files and Media'' permission to Emacs via
|
||||||
system settings.
|
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
|
@end itemize
|
||||||
|
|
||||||
The external storage directory is found at @file{/sdcard}. The
|
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
|
These settings are not present on many proprietary versions of
|
||||||
Android.
|
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
|
@node Android Environment
|
||||||
@section Running Emacs under Android
|
@section Running Emacs under Android
|
||||||
|
|
||||||
|
|
|
@ -1267,6 +1267,7 @@ Emacs and Android
|
||||||
* What is Android?:: Preamble.
|
* What is Android?:: Preamble.
|
||||||
* Android Startup:: Starting up Emacs on Android.
|
* Android Startup:: Starting up Emacs on Android.
|
||||||
* Android File System:: The Android file system.
|
* Android File System:: The Android file system.
|
||||||
|
* Android Document Providers:: Accessing files from other programs.
|
||||||
* Android Environment:: Running Emacs under Android.
|
* Android Environment:: Running Emacs under Android.
|
||||||
* Android Windowing:: The Android window system.
|
* Android Windowing:: The Android window system.
|
||||||
* Android Fonts:: Font selection under Android.
|
* Android Fonts:: Font selection under Android.
|
||||||
|
|
|
@ -233,7 +233,8 @@ ifneq ($(NDK_BUILD_SHARED),)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install_temp/assets/directory-tree: $(libsrc)/asset-directory-tool \
|
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 \
|
$(AM_V_GEN) $(libsrc)/asset-directory-tool install_temp/assets \
|
||||||
install_temp/assets/directory-tree
|
install_temp/assets/directory-tree
|
||||||
|
|
||||||
|
@ -247,8 +248,8 @@ install_temp/assets/build_info: install_temp
|
||||||
$(AM_V_GEN) { hostname; date +%s; } > $@
|
$(AM_V_GEN) { hostname; date +%s; } > $@
|
||||||
|
|
||||||
emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
||||||
install_temp/assets/version install_temp/assets/build_info \
|
AndroidManifest.xml install_temp/assets/version \
|
||||||
AndroidManifest.xml
|
install_temp/assets/build_info
|
||||||
# Package everything. Specifying the assets on this command line is
|
# Package everything. Specifying the assets on this command line is
|
||||||
# necessary for AAssetManager_getNextFileName to work on old versions
|
# necessary for AAssetManager_getNextFileName to work on old versions
|
||||||
# of Android. Make sure not to generate R.java, as it's already been
|
# of Android. Make sure not to generate R.java, as it's already been
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
|
@ -48,6 +51,9 @@ public class EmacsActivity extends Activity
|
||||||
{
|
{
|
||||||
public static final String TAG = "EmacsActivity";
|
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. */
|
/* The currently attached EmacsWindow, or null if none. */
|
||||||
private EmacsWindow window;
|
private EmacsWindow window;
|
||||||
|
|
||||||
|
@ -431,4 +437,36 @@ public class EmacsActivity extends Activity
|
||||||
/* Update the window insets. */
|
/* Update the window insets. */
|
||||||
syncFullscreenWith (window);
|
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)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||||
{
|
{
|
||||||
content = "/content/" + uri.getEncodedAuthority ();
|
content = EmacsService.buildContentName (uri);
|
||||||
|
|
||||||
for (String segment : uri.getPathSegments ())
|
|
||||||
content += "/" + Uri.encode (segment);
|
|
||||||
|
|
||||||
/* Append the URI query. */
|
|
||||||
|
|
||||||
if (uri.getEncodedQuery () != null)
|
|
||||||
content += "?" + uri.getEncodedQuery ();
|
|
||||||
|
|
||||||
Log.d (TAG, "checkReadableOrCopy: " + content);
|
Log.d (TAG, "checkReadableOrCopy: " + content);
|
||||||
|
|
||||||
return 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
|
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
|
indicating the offset from the start of the file to the start of
|
||||||
the next sibling. Following that is a list of subdirectories or
|
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 `/'. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
1797
src/android.c
1797
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 "androidgui.h"
|
||||||
#include "lisp.h"
|
#include "lisp.h"
|
||||||
#endif
|
#endif /* ANDROID_STUBIFY */
|
||||||
|
|
||||||
extern bool android_init_gui;
|
extern bool android_init_gui;
|
||||||
|
|
||||||
#ifndef ANDROID_STUBIFY
|
#ifndef ANDROID_STUBIFY
|
||||||
|
|
||||||
|
extern char *android_cache_dir;
|
||||||
|
|
||||||
extern int android_emacs_init (int, char **, char *);
|
extern int android_emacs_init (int, char **, char *);
|
||||||
extern int android_select (int, fd_set *, fd_set *, fd_set *,
|
extern int android_select (int, fd_set *, fd_set *, fd_set *,
|
||||||
struct timespec *);
|
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 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_fstat (int, struct stat *);
|
||||||
extern int android_fstatat (int, const char *restrict,
|
extern int android_fstatat (int, const char *restrict,
|
||||||
struct stat *restrict, int);
|
struct stat *restrict, int);
|
||||||
extern int android_faccessat (int, const char *, int, int);
|
extern int android_faccessat (int, const char *, int, int);
|
||||||
extern int android_close (int);
|
extern int android_close (int);
|
||||||
|
extern FILE *android_fdopen (int, const char *);
|
||||||
extern int android_fclose (FILE *);
|
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_pixel_density_x, android_pixel_density_y;
|
||||||
extern double android_scaled_pixel_density;
|
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 (void);
|
||||||
extern void android_exception_check_1 (jobject);
|
extern void android_exception_check_1 (jobject);
|
||||||
extern void android_exception_check_2 (jobject, 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 (void *, jobject);
|
||||||
extern void android_exception_check_nonnull_1 (void *, jobject, 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_wait_event (void);
|
||||||
extern void android_toggle_on_screen_keyboard (android_window, bool);
|
extern void android_toggle_on_screen_keyboard (android_window, bool);
|
||||||
extern _Noreturn void android_restart_emacs (void);
|
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. */
|
/* Directory listing emulation. */
|
||||||
|
|
||||||
struct android_dir;
|
struct android_vdir;
|
||||||
|
|
||||||
extern struct android_dir *android_opendir (const char *);
|
extern struct android_vdir *android_opendir (const char *);
|
||||||
extern int android_dirfd (struct android_dir *);
|
extern int android_dirfd (struct android_vdir *);
|
||||||
extern struct dirent *android_readdir (struct android_dir *);
|
extern struct dirent *android_readdir (struct android_vdir *);
|
||||||
extern void android_closedir (struct android_dir *);
|
extern void android_closedir (struct android_vdir *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,8 +243,52 @@ extern int android_rewrite_spawn_argv (const char ***);
|
||||||
#ifndef ANDROID_STUBIFY
|
#ifndef ANDROID_STUBIFY
|
||||||
#include <jni.h>
|
#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;
|
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) \
|
#define ANDROID_DELETE_LOCAL_REF(ref) \
|
||||||
((*android_java_env)->DeleteLocalRef (android_java_env, \
|
((*android_java_env)->DeleteLocalRef (android_java_env, \
|
||||||
(ref)))
|
(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. */
|
/* Miscellaneous input method related stuff. */
|
||||||
|
|
||||||
/* Report X, Y, by the phys cursor width and height as the cursor
|
/* 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);
|
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);
|
defsubr (&Sx_server_version);
|
||||||
#ifndef ANDROID_STUBIFY
|
#ifndef ANDROID_STUBIFY
|
||||||
defsubr (&Sandroid_query_battery);
|
defsubr (&Sandroid_query_battery);
|
||||||
|
defsubr (&Sandroid_request_directory_access);
|
||||||
|
|
||||||
tip_timer = Qnil;
|
tip_timer = Qnil;
|
||||||
staticpro (&tip_timer);
|
staticpro (&tip_timer);
|
||||||
|
@ -3235,5 +3262,5 @@ This option has no effect on Android 9 and earlier. */);
|
||||||
staticpro (&tip_dx);
|
staticpro (&tip_dx);
|
||||||
tip_dy = Qnil;
|
tip_dy = Qnil;
|
||||||
staticpro (&tip_dy);
|
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
|
static void
|
||||||
delete_temp_file (Lisp_Object name)
|
delete_temp_file (Lisp_Object name)
|
||||||
{
|
{
|
||||||
unlink (SSDATA (name));
|
emacs_unlink (SSDATA (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -488,7 +488,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
|
||||||
specbind (Qfile_name_handler_alist, Qnil);
|
specbind (Qfile_name_handler_alist, Qnil);
|
||||||
fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, false, false,
|
fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, false, false,
|
||||||
NULL);
|
NULL);
|
||||||
fp = fd < 0 ? 0 : fdopen (fd, "r");
|
fp = fd < 0 ? 0 : emacs_fdopen (fd, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
int open_errno = errno;
|
int open_errno = errno;
|
||||||
|
|
|
@ -54,7 +54,7 @@ typedef DIR emacs_dir;
|
||||||
|
|
||||||
/* The Android emulation of dirent stuff is required to be able to
|
/* The Android emulation of dirent stuff is required to be able to
|
||||||
list the /assets special directory. */
|
list the /assets special directory. */
|
||||||
typedef struct android_dir emacs_dir;
|
typedef struct android_vdir emacs_dir;
|
||||||
#define emacs_readdir android_readdir
|
#define emacs_readdir android_readdir
|
||||||
#define emacs_closedir android_closedir
|
#define emacs_closedir android_closedir
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3012,7 +3012,7 @@ killed. */
|
||||||
{
|
{
|
||||||
Lisp_Object listfile;
|
Lisp_Object listfile;
|
||||||
listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
|
listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
|
||||||
unlink (SSDATA (listfile));
|
emacs_unlink (SSDATA (listfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_COMP
|
#ifdef HAVE_NATIVE_COMP
|
||||||
|
|
86
src/fileio.c
86
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
|
/* Establish that ENCODED is not contained within a special directory
|
||||||
contents are read only. Signal a `file-error' if it does.
|
whose contents are not eligible for Unix VFS operations. Signal a
|
||||||
|
`file-error' with REASON 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. */
|
|
||||||
|
|
||||||
static void
|
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
|
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -198,17 +195,10 @@ check_mutable_filename (Lisp_Object encoded, bool write)
|
||||||
name = SSDATA (encoded);
|
name = SSDATA (encoded);
|
||||||
|
|
||||||
if (android_is_special_directory (name, "/assets"))
|
if (android_is_special_directory (name, "/assets"))
|
||||||
xsignal2 (Qfile_error,
|
xsignal2 (Qfile_error, build_string (reason), encoded);
|
||||||
build_string ("File lies on read-only directory"),
|
|
||||||
encoded);
|
|
||||||
|
|
||||||
if (write)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (android_is_special_directory (name, "/content"))
|
if (android_is_special_directory (name, "/content"))
|
||||||
xsignal2 (Qfile_error,
|
xsignal2 (Qfile_error, build_string (reason), encoded);
|
||||||
build_string ("File lies on read-only directory"),
|
|
||||||
encoded);
|
|
||||||
#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
|
#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2287,7 +2277,6 @@ permissions. */)
|
||||||
|
|
||||||
encoded_file = ENCODE_FILE (file);
|
encoded_file = ENCODE_FILE (file);
|
||||||
encoded_newname = ENCODE_FILE (newname);
|
encoded_newname = ENCODE_FILE (newname);
|
||||||
check_mutable_filename (encoded_newname, true);
|
|
||||||
|
|
||||||
#ifdef WINDOWSNT
|
#ifdef WINDOWSNT
|
||||||
if (NILP (ok_if_already_exists)
|
if (NILP (ok_if_already_exists)
|
||||||
|
@ -2553,7 +2542,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
|
||||||
|
|
||||||
dir = SSDATA (encoded_dir);
|
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);
|
report_file_error ("Creating directory", directory);
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
@ -2572,9 +2561,7 @@ DEFUN ("delete-directory-internal", Fdelete_directory_internal,
|
||||||
encoded_dir = ENCODE_FILE (directory);
|
encoded_dir = ENCODE_FILE (directory);
|
||||||
dir = SSDATA (encoded_dir);
|
dir = SSDATA (encoded_dir);
|
||||||
|
|
||||||
check_mutable_filename (encoded_dir, false);
|
if (emacs_rmdir (dir) != 0)
|
||||||
|
|
||||||
if (rmdir (dir) != 0)
|
|
||||||
report_file_error ("Removing directory", directory);
|
report_file_error ("Removing directory", directory);
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
@ -2613,9 +2600,9 @@ With a prefix argument, TRASH is nil. */)
|
||||||
return call1 (Qmove_file_to_trash, filename);
|
return call1 (Qmove_file_to_trash, filename);
|
||||||
|
|
||||||
encoded_file = ENCODE_FILE (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);
|
report_file_error ("Removing old name", filename);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
@ -2771,8 +2758,6 @@ This is what happens in interactive use with M-x. */)
|
||||||
|
|
||||||
encoded_file = ENCODE_FILE (file);
|
encoded_file = ENCODE_FILE (file);
|
||||||
encoded_newname = ENCODE_FILE (newname);
|
encoded_newname = ENCODE_FILE (newname);
|
||||||
check_mutable_filename (encoded_file, false);
|
|
||||||
check_mutable_filename (encoded_newname, false);
|
|
||||||
|
|
||||||
bool plain_rename = (case_only_rename
|
bool plain_rename = (case_only_rename
|
||||||
|| (!NILP (ok_if_already_exists)
|
|| (!NILP (ok_if_already_exists)
|
||||||
|
@ -2780,8 +2765,10 @@ This is what happens in interactive use with M-x. */)
|
||||||
int rename_errno UNINIT;
|
int rename_errno UNINIT;
|
||||||
if (!plain_rename)
|
if (!plain_rename)
|
||||||
{
|
{
|
||||||
if (renameat_noreplace (AT_FDCWD, SSDATA (encoded_file),
|
if (emacs_renameat_noreplace (AT_FDCWD,
|
||||||
AT_FDCWD, SSDATA (encoded_newname))
|
SSDATA (encoded_file),
|
||||||
|
AT_FDCWD,
|
||||||
|
SSDATA (encoded_newname))
|
||||||
== 0)
|
== 0)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
|
||||||
|
@ -2803,7 +2790,8 @@ This is what happens in interactive use with M-x. */)
|
||||||
|
|
||||||
if (plain_rename)
|
if (plain_rename)
|
||||||
{
|
{
|
||||||
if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
if (emacs_rename (SSDATA (encoded_file),
|
||||||
|
SSDATA (encoded_newname)) == 0)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
rename_errno = errno;
|
rename_errno = errno;
|
||||||
/* Don't prompt again. */
|
/* Don't prompt again. */
|
||||||
|
@ -2884,8 +2872,10 @@ This is what happens in interactive use with M-x. */)
|
||||||
|
|
||||||
encoded_file = ENCODE_FILE (file);
|
encoded_file = ENCODE_FILE (file);
|
||||||
encoded_newname = ENCODE_FILE (newname);
|
encoded_newname = ENCODE_FILE (newname);
|
||||||
check_mutable_filename (encoded_file, false);
|
check_vfs_filename (encoded_file, "Trying to create hard link to "
|
||||||
check_mutable_filename (encoded_newname, false);
|
"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)
|
if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
@ -2896,7 +2886,7 @@ This is what happens in interactive use with M-x. */)
|
||||||
|| FIXNUMP (ok_if_already_exists))
|
|| FIXNUMP (ok_if_already_exists))
|
||||||
barf_or_query_if_file_exists (newname, true, "make it a new name",
|
barf_or_query_if_file_exists (newname, true, "make it a new name",
|
||||||
FIXNUMP (ok_if_already_exists), false);
|
FIXNUMP (ok_if_already_exists), false);
|
||||||
unlink (SSDATA (newname));
|
emacs_unlink (SSDATA (newname));
|
||||||
if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
@ -2939,10 +2929,9 @@ This happens for interactive use with M-x. */)
|
||||||
|
|
||||||
encoded_target = ENCODE_FILE (target);
|
encoded_target = ENCODE_FILE (target);
|
||||||
encoded_linkname = ENCODE_FILE (linkname);
|
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;
|
return Qnil;
|
||||||
|
|
||||||
if (errno == ENOSYS)
|
if (errno == ENOSYS)
|
||||||
|
@ -2955,8 +2944,9 @@ This happens for interactive use with M-x. */)
|
||||||
|| FIXNUMP (ok_if_already_exists))
|
|| FIXNUMP (ok_if_already_exists))
|
||||||
barf_or_query_if_file_exists (linkname, true, "make it a link",
|
barf_or_query_if_file_exists (linkname, true, "make it a link",
|
||||||
FIXNUMP (ok_if_already_exists), false);
|
FIXNUMP (ok_if_already_exists), false);
|
||||||
unlink (SSDATA (encoded_linkname));
|
emacs_unlink (SSDATA (encoded_linkname));
|
||||||
if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0)
|
if (emacs_symlink (SSDATA (encoded_target),
|
||||||
|
SSDATA (encoded_linkname)) == 0)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3328,27 +3318,12 @@ file_accessible_directory_p (Lisp_Object file)
|
||||||
special cases "/" and "//", and it's a safe optimization
|
special cases "/" and "//", and it's a safe optimization
|
||||||
here. After appending '.', append another '/' to work around
|
here. After appending '.', append another '/' to work around
|
||||||
a macOS bug (Bug#30350). */
|
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[] = "/./";
|
static char const appended[] = "/./";
|
||||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||||
memcpy (buf, data, len);
|
memcpy (buf, data, len);
|
||||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||||
dir = buf;
|
dir = buf;
|
||||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = file_access_p (dir, F_OK);
|
ok = file_access_p (dir, F_OK);
|
||||||
|
@ -3682,7 +3657,8 @@ command from GNU Coreutils. */)
|
||||||
return call4 (handler, Qset_file_modes, absname, mode, flag);
|
return call4 (handler, Qset_file_modes, absname, mode, flag);
|
||||||
|
|
||||||
encoded = ENCODE_FILE (absname);
|
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);
|
char *fname = SSDATA (encoded);
|
||||||
mode_t imode = XFIXNUM (mode) & 07777;
|
mode_t imode = XFIXNUM (mode) & 07777;
|
||||||
if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
|
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);
|
return call4 (handler, Qset_file_times, absname, timestamp, flag);
|
||||||
|
|
||||||
Lisp_Object encoded_absname = ENCODE_FILE (absname);
|
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)
|
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);
|
encoded_filename = ENCODE_FILE (filename);
|
||||||
check_mutable_filename (encoded_filename, false);
|
|
||||||
|
|
||||||
fn = SSDATA (encoded_filename);
|
fn = SSDATA (encoded_filename);
|
||||||
open_flags = O_WRONLY | O_CREAT;
|
open_flags = O_WRONLY | O_CREAT;
|
||||||
|
|
|
@ -228,7 +228,7 @@ get_boot_time (void)
|
||||||
{
|
{
|
||||||
get_boot_time_1 (SSDATA (filename), 1);
|
get_boot_time_1 (SSDATA (filename), 1);
|
||||||
if (delete_flag)
|
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;
|
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))
|
if (! (r < 0 && errno == ENOSYS))
|
||||||
return r;
|
return r;
|
||||||
if (link (old, new) == 0)
|
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)
|
if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -347,7 +348,7 @@ rename_lock_file (char const *old, char const *new, bool force)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rename (old, new);
|
return emacs_rename (old, new);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,13 +366,13 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
|
||||||
pretending that 'symlink' does not work. */
|
pretending that 'symlink' does not work. */
|
||||||
int err = ENOSYS;
|
int err = ENOSYS;
|
||||||
#else
|
#else
|
||||||
int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
int err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (err == EEXIST && force)
|
if (err == EEXIST && force)
|
||||||
{
|
{
|
||||||
unlink (lfname);
|
emacs_unlink (lfname);
|
||||||
err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
|
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)
|
if (!err && rename_lock_file (nonce, lfname, force) != 0)
|
||||||
err = errno;
|
err = errno;
|
||||||
if (err)
|
if (err)
|
||||||
unlink (nonce);
|
emacs_unlink (nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_FREE ();
|
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
|
/* The owner process is dead or has a strange pid, so try to
|
||||||
zap the lockfile. */
|
zap the lockfile. */
|
||||||
else
|
else
|
||||||
return unlink (SSDATA (lfname)) < 0 ? errno : 0;
|
return emacs_unlink (SSDATA (lfname)) < 0 ? errno : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* If we wanted to support the check for stale locks on remote machines,
|
{ /* 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);
|
int err = current_lock_owner (0, lfname);
|
||||||
if (! (err == 0 || err == ANOTHER_OWNS_IT
|
if (! (err == 0 || err == ANOTHER_OWNS_IT
|
||||||
|| (err == I_OWN_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);
|
report_file_errno ("Unlocking file", fn, err);
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
|
|
@ -4234,7 +4234,7 @@ static char *
|
||||||
slurp_file (image_fd fd, ptrdiff_t *size)
|
slurp_file (image_fd fd, ptrdiff_t *size)
|
||||||
{
|
{
|
||||||
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
|
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
|
||||||
FILE *fp = fdopen (fd, "rb");
|
FILE *fp = emacs_fdopen (fd, "rb");
|
||||||
|
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
struct stat st;
|
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. */
|
/* Open the image file. */
|
||||||
fp = fdopen (fd, "rb");
|
fp = emacs_fdopen (fd, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
image_error ("Cannot open image file `%s'", file);
|
image_error ("Cannot open image file `%s'", file);
|
||||||
|
@ -8750,7 +8750,7 @@ jpeg_load_body (struct frame *f, struct image *img,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fdopen (fd, "rb");
|
fp = emacs_fdopen (fd, "rb");
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
{
|
{
|
||||||
image_error ("Cannot open `%s'", file);
|
image_error ("Cannot open `%s'", file);
|
||||||
|
|
|
@ -11740,9 +11740,9 @@ This may include sensitive information such as passwords. */)
|
||||||
encfile = ENCODE_FILE (file);
|
encfile = ENCODE_FILE (file);
|
||||||
fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
|
fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||||
if (fd < 0 && errno == EEXIST
|
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);
|
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)
|
if (dribble == 0)
|
||||||
report_file_error ("Opening dribble", file);
|
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_open_noquit (const char *, int, int);
|
||||||
extern int emacs_pipe (int[2]);
|
extern int emacs_pipe (int[2]);
|
||||||
extern int emacs_close (int);
|
extern int emacs_close (int);
|
||||||
|
extern FILE *emacs_fdopen (int, const char *);
|
||||||
extern int emacs_fclose (FILE *);
|
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 (int, void *, ptrdiff_t);
|
||||||
extern ptrdiff_t emacs_read_quit (int, void *, ptrdiff_t);
|
extern ptrdiff_t emacs_read_quit (int, void *, ptrdiff_t);
|
||||||
extern ptrdiff_t emacs_write (int, void const *, 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);
|
stream = emacs_fopen (SSDATA (efound), fmode);
|
||||||
#else
|
#else
|
||||||
#if !defined USE_ANDROID_ASSETS
|
#if !defined USE_ANDROID_ASSETS
|
||||||
stream = fdopen (fd, fmode);
|
stream = emacs_fdopen (fd, fmode);
|
||||||
#else
|
#else
|
||||||
/* Android systems use special file descriptors which can point
|
/* Android systems use special file descriptors which can point
|
||||||
into compressed data and double as file streams. FMODE is
|
into compressed data and double as file streams. FMODE is
|
||||||
|
|
|
@ -7472,6 +7472,16 @@ handle_child_signal (int sig)
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
if (STRINGP (XCDR (head)))
|
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)));
|
unlink (SSDATA (XCDR (head)));
|
||||||
XSETCAR (tail, Qnil);
|
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
|
/* Set buferr if possible on platforms defining _PC_PIPE_BUF, as
|
||||||
they support the notion of atomic writes to pipes. */
|
they support the notion of atomic writes to pipes. */
|
||||||
#ifdef _PC_PIPE_BUF
|
#ifdef _PC_PIPE_BUF
|
||||||
buferr = fdopen (STDERR_FILENO, "w");
|
buferr = emacs_fdopen (STDERR_FILENO, "w");
|
||||||
if (buferr)
|
if (buferr)
|
||||||
setvbuf (buferr, NULL, _IOLBF, 0);
|
setvbuf (buferr, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2545,7 +2545,7 @@ emacs_fopen (char const *file, char const *mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = emacs_open (file, omode | oflags | bflag, 0666);
|
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. */
|
/* 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
|
/* Wrapper around fclose. On Android, this calls `android_fclose' to
|
||||||
clear information associated with the FILE's file descriptor if
|
clear information associated with the FILE's file descriptor if
|
||||||
necessary. */
|
necessary. */
|
||||||
|
@ -2641,6 +2654,71 @@ emacs_fclose (FILE *stream)
|
||||||
#endif
|
#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.
|
/* 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
|
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>.
|
<https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
|
||||||
|
|
|
@ -2415,7 +2415,7 @@ frame's terminal). */)
|
||||||
#else /* !MSDOS */
|
#else /* !MSDOS */
|
||||||
fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
|
fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
|
||||||
t->display_info.tty->input = t->display_info.tty->output
|
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)
|
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
|
tty->input = tty->output
|
||||||
= ((fd < 0 || ! isatty (fd))
|
= ((fd < 0 || ! isatty (fd))
|
||||||
? NULL
|
? NULL
|
||||||
: fdopen (fd, "w+"));
|
: emacs_fdopen (fd, "w+"));
|
||||||
|
|
||||||
if (! tty->input)
|
if (! tty->input)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue