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 *);
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
android_unix_access,
android_unix_mkdir,
android_unix_chmod,
+ android_unix_readlink,
android_unix_opendir,
};
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)
{
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. */
android_afs_access,
android_afs_mkdir,
android_afs_chmod,
+ android_afs_readlink,
android_afs_opendir,
};
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)
{
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. */
android_content_access,
android_content_mkdir,
android_content_chmod,
+ android_content_readlink,
android_content_opendir,
};
android_content_mkdir (struct android_vnode *vnode, mode_t mode)
{
errno = EEXIST;
- return 0;
+ return -1;
}
static int
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 *
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. */
android_authority_access,
android_authority_mkdir,
android_authority_chmod,
+ android_authority_readlink,
android_authority_opendir,
};
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)
{
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. */
android_saf_root_access,
android_saf_root_mkdir,
android_saf_root_chmod,
+ android_saf_root_readlink,
android_saf_root_opendir,
};
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)
{
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. */
android_saf_tree_access,
android_saf_tree_mkdir,
android_saf_tree_chmod,
+ android_saf_tree_readlink,
android_saf_tree_opendir,
};
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.
android_saf_tree_access,
android_saf_tree_mkdir,
android_saf_tree_chmod,
+ android_saf_tree_readlink,
android_saf_file_opendir,
};
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. */
android_saf_new_access,
android_saf_new_mkdir,
android_saf_new_chmod,
+ android_saf_new_readlink,
android_saf_new_opendir,
};
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)
{
android_unix_access,
android_unix_mkdir,
android_unix_chmod,
+ android_unix_readlink,
android_unix_opendir,
};
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.
{
#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),
/* 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);
\f
/* 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;