From 6d44d08e044dd2a74c6ac65cedb32a8f7a4f82de Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 3 Aug 2023 14:50:05 +0800 Subject: [PATCH] Isolate fchmodat within the Android VFS layer * src/android.h: Update prototypes. * src/androidvfs.c (unix_vfs_ops, android_unix_chmod, afs_vfs_ops) (android_afs_chmod, content_vfs_ops, android_content_chmod) (authority_vfs_ops, android_authority_chmod, saf_root_vfs_ops) (android_saf_root_chmod, saf_tree_vfs_ops, android_saf_tree_chmod) (saf_file_vfs_ops, saf_new_vfs_ops, android_saf_new_chmod) (root_vfs_ops): Add `chmod' to the list of functions implemented by each vnode. (android_fchmodat): New function. * src/fileio.c (Fset_file_modes): Use `emacs_fchmodat'. * src/lisp.h: * src/sysdep.c (emacs_fchmodat): Delegate to android_fchmodat on Android. --- src/android.h | 1 + src/androidvfs.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ src/fileio.c | 10 +--- src/lisp.h | 1 + src/sysdep.c | 10 ++++ 5 files changed, 139 insertions(+), 9 deletions(-) diff --git a/src/android.h b/src/android.h index 945bd649c18..cecdfab002f 100644 --- a/src/android.h +++ b/src/android.h @@ -74,6 +74,7 @@ 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 int android_fchmodat (int, const char *, mode_t, int); diff --git a/src/androidvfs.c b/src/androidvfs.c index e3b0b895df3..2b467bc444f 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -206,6 +206,12 @@ struct android_vops /* Make a directory designated by VNODE, like Unix `mkdir'. */ int (*mkdir) (struct android_vnode *, mode_t); + /* Change the access mode of the provided VNODE to MODE. Value is + the same as with `chmod'. FLAGS is passed verbatim from the call + to the delegating at-func, and is probably + AT_SYMLINK_NOFOLLOW. */ + int (*chmod) (struct android_vnode *, mode_t, int); + /* Open the specified VNODE as a directory. Value is a ``directory handle'', or NULL upon failure. */ struct android_vdir *(*opendir) (struct android_vnode *); @@ -616,6 +622,7 @@ static int android_unix_rename (struct android_vnode *, 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 struct android_vdir *android_unix_opendir (struct android_vnode *); /* Vector of VFS operations associated with Unix filesystem VFS @@ -633,6 +640,7 @@ static struct android_vops unix_vfs_ops = android_unix_stat, android_unix_access, android_unix_mkdir, + android_unix_chmod, android_unix_opendir, }; @@ -878,6 +886,16 @@ android_unix_mkdir (struct android_vnode *vnode, mode_t mode) return mkdir (vp->name, mode); } +static int +android_unix_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + struct android_unix_vnode *vp; + + vp = (struct android_unix_vnode *) vnode; + return fchmodat (AT_FDCWD, vp->name, mode, flags); +} + static struct dirent * android_unix_readdir (struct android_vdir *vdir) { @@ -1585,6 +1603,7 @@ static int android_afs_rename (struct android_vnode *, 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 struct android_vdir *android_afs_opendir (struct android_vnode *); /* Vector of VFS operations associated with asset VFS nodes. */ @@ -1601,6 +1620,7 @@ static struct android_vops afs_vfs_ops = android_afs_stat, android_afs_access, android_afs_mkdir, + android_afs_chmod, android_afs_opendir, }; @@ -2109,6 +2129,14 @@ android_afs_mkdir (struct android_vnode *vnode, mode_t mode) return -1; } +static int +android_afs_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + errno = EROFS; + return -1; +} + static struct dirent * android_afs_readdir (struct android_vdir *vdir) { @@ -2348,6 +2376,7 @@ static int android_content_rename (struct android_vnode *, 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 struct android_vdir *android_content_opendir (struct android_vnode *); /* Vector of VFS operations associated with the content VFS node. */ @@ -2364,6 +2393,7 @@ static struct android_vops content_vfs_ops = android_content_stat, android_content_access, android_content_mkdir, + android_content_chmod, android_content_opendir, }; @@ -2571,6 +2601,14 @@ android_content_mkdir (struct android_vnode *vnode, mode_t mode) return 0; } +static int +android_content_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + errno = EACCES; + return 0; +} + static struct dirent * android_content_readdir (struct android_vdir *vdir) { @@ -2823,6 +2861,7 @@ static int android_authority_rename (struct android_vnode *, 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 struct android_vdir *android_authority_opendir (struct android_vnode *); /* Vector of VFS operations associated with the content VFS node. */ @@ -2839,6 +2878,7 @@ static struct android_vops authority_vfs_ops = android_authority_stat, android_authority_access, android_authority_mkdir, + android_authority_chmod, android_authority_opendir, }; @@ -3118,6 +3158,14 @@ android_authority_mkdir (struct android_vnode *vnode, mode_t mode) return -1; } +static int +android_authority_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + errno = EACCES; + return -1; +} + static struct android_vdir * android_authority_opendir (struct android_vnode *vnode) { @@ -3223,6 +3271,7 @@ static int android_saf_root_rename (struct android_vnode *, 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 struct android_vdir *android_saf_root_opendir (struct android_vnode *); /* Vector of VFS operations associated with the SAF root VFS node. */ @@ -3239,6 +3288,7 @@ static struct android_vops saf_root_vfs_ops = android_saf_root_stat, android_saf_root_access, android_saf_root_mkdir, + android_saf_root_chmod, android_saf_root_opendir, }; @@ -3520,6 +3570,14 @@ android_saf_root_mkdir (struct android_vnode *vnode, mode_t mode) return -1; } +static int +android_saf_root_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + errno = EACCES; + return -1; +} + static struct dirent * android_saf_root_readdir (struct android_vdir *vdir) { @@ -4347,6 +4405,7 @@ static int android_saf_tree_rename (struct android_vnode *, 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 struct android_vdir *android_saf_tree_opendir (struct android_vnode *); /* Vector of VFS operations associated with SAF tree VFS nodes. */ @@ -4363,6 +4422,7 @@ static struct android_vops saf_tree_vfs_ops = android_saf_tree_stat, android_saf_tree_access, android_saf_tree_mkdir, + android_saf_tree_chmod, android_saf_tree_opendir, }; @@ -5100,6 +5160,24 @@ android_saf_tree_mkdir (struct android_vnode *vnode, mode_t mode) return -1; } +static int +android_saf_tree_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + /* Return EACCESS should MODE contain unusual bits besides S_IFDIR | + S_IRUSR | S_IXUSR. */ + + if (mode & ~(S_IFDIR | S_IRUSR | S_IXUSR)) + { + errno = EACCES; + return -1; + } + + /* Otherwise, no further action is necessary, as SAF nodes already + pretend to be S_IFDIR | S_IRUSR | S_IXUSR. */ + return 0; +} + /* Open a database Cursor containing each directory entry within the supplied SAF tree vnode VP. @@ -5523,6 +5601,7 @@ static struct android_vops saf_file_vfs_ops = android_saf_tree_stat, android_saf_tree_access, android_saf_tree_mkdir, + android_saf_tree_chmod, android_saf_file_opendir, }; @@ -5761,6 +5840,7 @@ static int android_saf_new_rename (struct android_vnode *, 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 struct android_vdir *android_saf_new_opendir (struct android_vnode *); /* Vector of VFS operations associated with SAF new VFS nodes. */ @@ -5777,6 +5857,7 @@ static struct android_vops saf_new_vfs_ops = android_saf_new_stat, android_saf_new_access, android_saf_new_mkdir, + android_saf_new_chmod, android_saf_new_opendir, }; @@ -6038,6 +6119,14 @@ android_saf_new_mkdir (struct android_vnode *vnode, mode_t mode) return 0; } +static int +android_saf_new_chmod (struct android_vnode *vnode, mode_t mode, + int flags) +{ + errno = ENOENT; + return -1; +} + static struct android_vdir * android_saf_new_opendir (struct android_vnode *vnode) { @@ -6125,6 +6214,7 @@ static struct android_vops root_vfs_ops = android_unix_stat, android_unix_access, android_unix_mkdir, + android_unix_chmod, android_unix_opendir, }; @@ -6810,6 +6900,42 @@ android_faccessat (int dirfd, const char *restrict pathname, return rc; } +/* Like `android_fstatat', but set file modes instead of + checking file status and respect FLAGS. */ + +int +android_fchmodat (int dirfd, const char *pathname, mode_t mode, + int flags) +{ + char buffer[PATH_MAX + 1]; + struct android_vnode *vp; + int 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 fchmodat. */ + return fchmodat (dirfd, pathname, mode, flags); + + vfs: + vp = android_name_file (pathname); + if (!vp) + return -1; + + rc = (*vp->ops->chmod) (vp, mode, flags); + (*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 1ccb871ce49..1a7a7152844 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3665,17 +3665,9 @@ command from GNU Coreutils. */) return call4 (handler, Qset_file_modes, absname, mode, flag); encoded = ENCODE_FILE (absname); - - /* Silently ignore attempts to change the access modes of files - within /contents on Android, preventing errors within backup file - creation. */ - - if (check_vfs_filename (encoded, NULL)) - return Qnil; - char *fname = SSDATA (encoded); mode_t imode = XFIXNUM (mode) & 07777; - if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0) + if (emacs_fchmodat (AT_FDCWD, fname, imode, nofollow) != 0) report_file_error ("Doing chmod", absname); return Qnil; diff --git a/src/lisp.h b/src/lisp.h index 5802984a5e7..447912581d7 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -5095,6 +5095,7 @@ 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 int emacs_fchmodat (int, const char *, mode_t, int); 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); diff --git a/src/sysdep.c b/src/sysdep.c index 0a1905c9196..a995bc66741 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2719,6 +2719,16 @@ emacs_rename (const char *src, const char *dst) #endif /* !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) */ } +int +emacs_fchmodat (int fd, const char *path, mode_t mode, int flags) +{ +#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) + return fchmodat (fd, path, mode, flags); +#else /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */ + return android_fchmodat (fd, path, mode, flags); +#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 . -- 2.39.2