[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 2effd18c97b: Make some file I/O operations more robust on Android
From: |
Po Lu |
Subject: |
master 2effd18c97b: Make some file I/O operations more robust on Android |
Date: |
Sat, 19 Aug 2023 01:25:57 -0400 (EDT) |
branch: master
commit 2effd18c97bf542e43203c95dd88114159162dd5
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Make some file I/O operations more robust on Android
* src/android.h (android_readlinkat): New prototype.
* src/androidvfs.c (struct android_vops): New function pointer
`readlink'.
(unix_vfs_ops, android_unix_readlink, afs_vfs_ops)
(android_afs_readlink, content_vfs_ops, android_content_mkdir)
(android_content_chmod, authority_vfs_ops)
(android_authority_readlink, saf_root_vfs_ops)
(android_saf_root_readlink, saf_tree_vfs_ops)
(android_saf_tree_readlink, saf_file_vfs_ops, saf_new_vfs_ops)
(android_saf_new_readlink, root_vfs_ops): Implement new
`readlink' vops for each vnode type.
(android_readlinkat): New function.
* src/fileio.c (Fcopy_file): Be more flexible about SELinux
errors under Android.
(emacs_readlinkat): Use `android_readlink' when built as
libemacs.so.
---
src/android.h | 2 +
src/androidvfs.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/fileio.c | 34 ++++++++++++--
3 files changed, 170 insertions(+), 7 deletions(-)
diff --git a/src/android.h b/src/android.h
index a052d3a3b21..e865d7da665 100644
--- a/src/android.h
+++ b/src/android.h
@@ -75,6 +75,8 @@ extern int android_renameat_noreplace (int, const char *,
int, const char *);
extern int android_rename (const char *, const char *);
extern int android_fchmodat (int, const char *, mode_t, int);
+extern ssize_t android_readlinkat (int, const char *restrict, char *restrict,
+ size_t);
diff --git a/src/androidvfs.c b/src/androidvfs.c
index ec33687f34c..d6b832d6caf 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -214,6 +214,10 @@ struct android_vops
AT_SYMLINK_NOFOLLOW. */
int (*chmod) (struct android_vnode *, mode_t, int);
+ /* Return the target of VNODE if it is a symbolic link, or -1.
+ Value and errno are the same as with `readlink'. */
+ ssize_t (*readlink) (struct android_vnode *, char *, size_t);
+
/* Open the specified VNODE as a directory.
Value is a ``directory handle'', or NULL upon failure. */
struct android_vdir *(*opendir) (struct android_vnode *);
@@ -625,6 +629,8 @@ static int android_unix_stat (struct android_vnode *,
struct stat *);
static int android_unix_access (struct android_vnode *, int);
static int android_unix_mkdir (struct android_vnode *, mode_t);
static int android_unix_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_unix_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_unix_opendir (struct android_vnode *);
/* Vector of VFS operations associated with Unix filesystem VFS
@@ -643,6 +649,7 @@ static struct android_vops unix_vfs_ops =
android_unix_access,
android_unix_mkdir,
android_unix_chmod,
+ android_unix_readlink,
android_unix_opendir,
};
@@ -898,6 +905,16 @@ android_unix_chmod (struct android_vnode *vnode, mode_t
mode,
return fchmodat (AT_FDCWD, vp->name, mode, flags);
}
+static ssize_t
+android_unix_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ struct android_unix_vnode *vp;
+
+ vp = (struct android_unix_vnode *) vnode;
+ return readlink (vp->name, buffer, size);
+}
+
static struct dirent *
android_unix_readdir (struct android_vdir *vdir)
{
@@ -1606,6 +1623,8 @@ static int android_afs_stat (struct android_vnode *,
struct stat *);
static int android_afs_access (struct android_vnode *, int);
static int android_afs_mkdir (struct android_vnode *, mode_t);
static int android_afs_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_afs_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_afs_opendir (struct android_vnode *);
/* Vector of VFS operations associated with asset VFS nodes. */
@@ -1623,6 +1642,7 @@ static struct android_vops afs_vfs_ops =
android_afs_access,
android_afs_mkdir,
android_afs_chmod,
+ android_afs_readlink,
android_afs_opendir,
};
@@ -2139,6 +2159,28 @@ android_afs_chmod (struct android_vnode *vnode, mode_t
mode,
return -1;
}
+static ssize_t
+android_afs_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ struct android_afs_vnode *vp;
+ const char *dir;
+
+ vp = (struct android_afs_vnode *) vnode;
+ dir = android_scan_directory_tree (vp->name, NULL);
+
+ /* As there are no symlinks in /assets, just return -1 with errno
+ set to a reasonable value contingent upon whether VP->name
+ actually exists. */
+
+ if (dir)
+ errno = EINVAL;
+ else
+ errno = ENOENT;
+
+ return -1;
+}
+
static struct dirent *
android_afs_readdir (struct android_vdir *vdir)
{
@@ -2379,6 +2421,8 @@ static int android_content_stat (struct android_vnode *,
struct stat *);
static int android_content_access (struct android_vnode *, int);
static int android_content_mkdir (struct android_vnode *, mode_t);
static int android_content_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_content_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_content_opendir (struct android_vnode *);
/* Vector of VFS operations associated with the content VFS node. */
@@ -2396,6 +2440,7 @@ static struct android_vops content_vfs_ops =
android_content_access,
android_content_mkdir,
android_content_chmod,
+ android_content_readlink,
android_content_opendir,
};
@@ -2600,7 +2645,7 @@ static int
android_content_mkdir (struct android_vnode *vnode, mode_t mode)
{
errno = EEXIST;
- return 0;
+ return -1;
}
static int
@@ -2608,7 +2653,15 @@ android_content_chmod (struct android_vnode *vnode,
mode_t mode,
int flags)
{
errno = EACCES;
- return 0;
+ return -1;
+}
+
+static ssize_t
+android_content_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ errno = EINVAL;
+ return -1;
}
static struct dirent *
@@ -2865,6 +2918,8 @@ static int android_authority_stat (struct android_vnode
*, struct stat *);
static int android_authority_access (struct android_vnode *, int);
static int android_authority_mkdir (struct android_vnode *, mode_t);
static int android_authority_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_authority_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_authority_opendir (struct android_vnode *);
/* Vector of VFS operations associated with the content VFS node. */
@@ -2882,6 +2937,7 @@ static struct android_vops authority_vfs_ops =
android_authority_access,
android_authority_mkdir,
android_authority_chmod,
+ android_authority_readlink,
android_authority_opendir,
};
@@ -3176,6 +3232,14 @@ android_authority_chmod (struct android_vnode *vnode,
mode_t mode,
return -1;
}
+static ssize_t
+android_authority_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ errno = EINVAL;
+ return -1;
+}
+
static struct android_vdir *
android_authority_opendir (struct android_vnode *vnode)
{
@@ -3282,6 +3346,8 @@ static int android_saf_root_stat (struct android_vnode *,
struct stat *);
static int android_saf_root_access (struct android_vnode *, int);
static int android_saf_root_mkdir (struct android_vnode *, mode_t);
static int android_saf_root_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_saf_root_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_saf_root_opendir (struct android_vnode *);
/* Vector of VFS operations associated with the SAF root VFS node. */
@@ -3299,6 +3365,7 @@ static struct android_vops saf_root_vfs_ops =
android_saf_root_access,
android_saf_root_mkdir,
android_saf_root_chmod,
+ android_saf_root_readlink,
android_saf_root_opendir,
};
@@ -3585,6 +3652,14 @@ android_saf_root_chmod (struct android_vnode *vnode,
mode_t mode,
return -1;
}
+static ssize_t
+android_saf_root_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ errno = EINVAL;
+ return -1;
+}
+
static struct dirent *
android_saf_root_readdir (struct android_vdir *vdir)
{
@@ -4426,6 +4501,8 @@ static int android_saf_tree_stat (struct android_vnode *,
struct stat *);
static int android_saf_tree_access (struct android_vnode *, int);
static int android_saf_tree_mkdir (struct android_vnode *, mode_t);
static int android_saf_tree_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_saf_tree_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_saf_tree_opendir (struct android_vnode *);
/* Vector of VFS operations associated with SAF tree VFS nodes. */
@@ -4443,6 +4520,7 @@ static struct android_vops saf_tree_vfs_ops =
android_saf_tree_access,
android_saf_tree_mkdir,
android_saf_tree_chmod,
+ android_saf_tree_readlink,
android_saf_tree_opendir,
};
@@ -5138,6 +5216,16 @@ android_saf_tree_chmod (struct android_vnode *vnode,
mode_t mode,
return 0;
}
+static ssize_t
+android_saf_tree_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ /* Return EINVAL. Symlinks aren't exposed to clients by the
+ SAF. */
+ errno = EINVAL;
+ return -1;
+}
+
/* Open a database Cursor containing each directory entry within the
supplied SAF tree vnode VP.
@@ -5562,6 +5650,7 @@ static struct android_vops saf_file_vfs_ops =
android_saf_tree_access,
android_saf_tree_mkdir,
android_saf_tree_chmod,
+ android_saf_tree_readlink,
android_saf_file_opendir,
};
@@ -5842,6 +5931,8 @@ static int android_saf_new_stat (struct android_vnode *,
struct stat *);
static int android_saf_new_access (struct android_vnode *, int);
static int android_saf_new_mkdir (struct android_vnode *, mode_t);
static int android_saf_new_chmod (struct android_vnode *, mode_t, int);
+static ssize_t android_saf_new_readlink (struct android_vnode *, char *,
+ size_t);
static struct android_vdir *android_saf_new_opendir (struct android_vnode *);
/* Vector of VFS operations associated with SAF new VFS nodes. */
@@ -5859,6 +5950,7 @@ static struct android_vops saf_new_vfs_ops =
android_saf_new_access,
android_saf_new_mkdir,
android_saf_new_chmod,
+ android_saf_new_readlink,
android_saf_new_opendir,
};
@@ -6128,6 +6220,14 @@ android_saf_new_chmod (struct android_vnode *vnode,
mode_t mode,
return -1;
}
+static ssize_t
+android_saf_new_readlink (struct android_vnode *vnode, char *buffer,
+ size_t size)
+{
+ errno = ENOENT;
+ return -1;
+}
+
static struct android_vdir *
android_saf_new_opendir (struct android_vnode *vnode)
{
@@ -6229,6 +6329,7 @@ static struct android_vops root_vfs_ops =
android_unix_access,
android_unix_mkdir,
android_unix_chmod,
+ android_unix_readlink,
android_unix_opendir,
};
@@ -6962,6 +7063,42 @@ android_fchmodat (int dirfd, const char *pathname,
mode_t mode,
return rc;
}
+/* Like `android_fstatat', but return the target of any symbolic link
+ at PATHNAME instead of checking file status. */
+
+ssize_t
+android_readlinkat (int dirfd, const char *restrict pathname,
+ char *restrict buf, size_t bufsiz)
+{
+ char buffer[PATH_MAX + 1];
+ struct android_vnode *vp;
+ ssize_t rc;
+
+ if (dirfd == AT_FDCWD || pathname[0] == '/')
+ goto vfs;
+
+ /* Now establish whether DIRFD is a file descriptor corresponding to
+ an open VFS directory stream. */
+
+ if (!android_fstatat_1 (dirfd, pathname, buffer, PATH_MAX + 1))
+ {
+ pathname = buffer;
+ goto vfs;
+ }
+
+ /* Fall back to readlinkat. */
+ return readlinkat (dirfd, pathname, buf, bufsiz);
+
+ vfs:
+ vp = android_name_file (pathname);
+ if (!vp)
+ return -1;
+
+ rc = (*vp->ops->readlink) (vp, buf, bufsiz);
+ (*vp->ops->close) (vp);
+ return rc;
+}
+
/* Like `fdopen', but if FD is a parcel file descriptor, ``detach'' it
from the original.
diff --git a/src/fileio.c b/src/fileio.c
index 869e1ea7e31..9294ea3e7d6 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2331,6 +2331,9 @@ permissions. */)
{
#if HAVE_LIBSELINUX
if (selinux_enabled_p (SSDATA (encoded_file))
+ /* Eschew copying SELinux contexts if they're inapplicable
+ to the destination file. */
+ && selinux_enabled_p (SSDATA (encoded_newname))
&& emacs_fd_to_int (ifd) != -1)
{
conlength = fgetfilecon (emacs_fd_to_int (ifd),
@@ -2494,7 +2497,14 @@ permissions. */)
/* Set the modified context back to the file. */
bool fail = fsetfilecon (ofd, con) != 0;
/* See https://debbugs.gnu.org/11245 for ENOTSUP. */
- if (fail && errno != ENOTSUP)
+ if (fail
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ /* Treat SELinux errors copying files leniently on Android,
+ since the system usually forbids user programs from
+ changing file contexts. */
+ && errno != EACCES
+#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
+ && errno != ENOTSUP)
report_file_error ("Doing fsetfilecon", newname);
freecon (con);
@@ -3090,15 +3100,29 @@ If there is no error, returns nil. */)
/* Relative to directory FD, return the symbolic link value of FILENAME.
On failure, return nil (setting errno). */
+
static Lisp_Object
emacs_readlinkat (int fd, char const *filename)
{
- static struct allocator const emacs_norealloc_allocator =
- { xmalloc, NULL, xfree, memory_full };
+ static struct allocator const emacs_norealloc_allocator = {
+ xmalloc,
+ NULL,
+ xfree,
+ memory_full,
+ };
+
Lisp_Object val;
char readlink_buf[1024];
- char *buf = careadlinkat (fd, filename, readlink_buf, sizeof readlink_buf,
- &emacs_norealloc_allocator, readlinkat);
+ char *buf;
+
+ buf = careadlinkat (fd, filename, readlink_buf, sizeof readlink_buf,
+ &emacs_norealloc_allocator,
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+ android_readlinkat
+#else /* !HAVE_ANDROID || ANDROID_STUBIFY */
+ readlinkat
+#endif /* HAVE_ANDROID && !ANDROID_STUBIFY */
+ );
if (!buf)
return Qnil;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 2effd18c97b: Make some file I/O operations more robust on Android,
Po Lu <=