emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 7f377407b4b: List special directories when reading root directory


From: Po Lu
Subject: master 7f377407b4b: List special directories when reading root directory on Android
Date: Sun, 31 Mar 2024 03:41:19 -0400 (EDT)

branch: master
commit 7f377407b4b7d6ac9994ed983d7516bc42139885
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    List special directories when reading root directory on Android
    
    * src/androidvfs.c (root_vfs_ops): Substitute
    android_root_opendir for android_root_opendir.
    (struct android_root_vdir): New structure.
    (root_fd, root_fd_references): New variables.
    (android_root_readdir, android_root_closedir, android_root_dirfd)
    (android_root_opendir): New functions.
    (android_fstatat_1): Test provided fd against root_fd, and if
    they match, prefix FILENAME with the name of the root directory.
    
    * lisp/ls-lisp.el (ls-lisp-insert-directory): If d-f-a-a signals
    an error while retrieving attributes, compile the alist of
    directory contents by hand.
---
 lisp/ls-lisp.el  |  36 ++++++++++++++--
 src/androidvfs.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 156 insertions(+), 7 deletions(-)

diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 89f0238cf74..d09b53b1cc3 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -328,11 +328,39 @@ not contain `d', so that a full listing is expected."
           full-directory-p)
       (let* ((dir (file-name-as-directory file))
             (default-directory dir)    ; so that file-attributes works
+             (id-format (if (memq ?n switches)
+                           'integer
+                         'string))
             (file-alist
-             (directory-files-and-attributes dir nil wildcard-regexp t
-                                             (if (memq ?n switches)
-                                                 'integer
-                                               'string)))
+              (catch 'new-list
+                (handler-bind
+                    ((error
+                      (lambda (error)
+                        ;; `directory-files-and-attributes' signals
+                        ;; failure on Unix systems if even a single
+                        ;; file's attributes cannot be accessed.
+                        ;;
+                        ;; Detect errors signaled while retrieving file
+                        ;; attributes and resolve them by creating the
+                        ;; attribute list manually, ignoring the
+                        ;; attributes of files that cannot be accessed
+                        ;; in this sense.
+                        (when (member (cadr error)
+                                      '("Getting attributes"
+                                        "Reading symbolic link"))
+                          (let ((file-list (directory-files dir nil
+                                                            wildcard-regexp
+                                                            t)))
+                            (throw 'new-list
+                                   (mapcar (lambda (file)
+                                             (cons file
+                                                   (or (ignore-errors
+                                                         (file-attributes
+                                                          file id-format))
+                                                       nil)))
+                                           file-list)))))))
+                  (directory-files-and-attributes
+                   dir nil wildcard-regexp t id-format))))
             (sum 0)
             (max-uid-len 0)
             (max-gid-len 0)
diff --git a/src/androidvfs.c b/src/androidvfs.c
index a9035ae53c6..e8eb9f2d41c 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -6525,11 +6525,33 @@ NATIVE_NAME (ftruncate) (JNIEnv *env, jobject object, 
jint fd)
 
 
 /* Root vnode.  This vnode represents the root inode, and is a regular
-   Unix vnode with modifications to `name' that make it return asset
-   vnodes.  */
+   Unix vnode with modifications to `name' so that it returns asset and
+   content vnodes, and to `opendir', so that asset and content vnodes
+   are read from the root directory, whether or not Emacs holds rights
+   to access the underlying filesystem.  */
+
+struct android_root_vdir
+{
+  /* The directory function table.  */
+  struct android_vdir vdir;
+
+  /* The directory stream, or NULL if it could not be opened.  */
+  DIR *directory;
+
+  /* Index of the next directory to return in `special_vnodes'.  */
+  int index;
+};
+
+/* File descriptor for instances of the foregoing structure when the
+   true root is unavailable.  */
+static int root_fd = -1;
+
+/* Number of open instances referencing this file descriptor.  */
+static ptrdiff_t root_fd_references;
 
 static struct android_vnode *android_root_name (struct android_vnode *,
                                                char *, size_t);
+static struct android_vdir *android_root_opendir (struct android_vnode *);
 
 /* Vector of VFS operations associated with Unix root filesystem VFS
    nodes.  */
@@ -6548,7 +6570,7 @@ static struct android_vops root_vfs_ops =
     android_unix_mkdir,
     android_unix_chmod,
     android_unix_readlink,
-    android_unix_opendir,
+    android_root_opendir,
   };
 
 /* Array of special named vnodes.  */
@@ -6676,6 +6698,97 @@ android_root_name (struct android_vnode *vnode, char 
*name,
   return android_unix_name (vnode, name, length);
 }
 
+static struct dirent *
+android_root_readdir (struct android_vdir *vdir)
+{
+  struct android_root_vdir *dir;
+  static struct dirent dirent, *p;
+
+  dir = (struct android_root_vdir *) vdir;
+  p   = dir->directory ? readdir (dir->directory) : NULL;
+
+  if (p || dir->index >= ARRAYELTS (special_vnodes))
+    return p;
+
+  dirent.d_ino = 0;
+  dirent.d_off = 0;
+  dirent.d_reclen = sizeof dirent;
+  dirent.d_type = DT_DIR;
+
+  /* No element in special_vnode must overflow dirent.d_name.  */
+  strcpy ((char *) &dirent.d_name,
+         special_vnodes[dir->index++].name);
+  return &dirent;
+}
+
+static void
+android_root_closedir (struct android_vdir *vdir)
+{
+  struct android_root_vdir *dir;
+
+  dir = (struct android_root_vdir *) vdir;
+
+  if (dir->directory)
+    closedir (dir->directory);
+  else if (root_fd_references--)
+    ;
+  else
+    {
+      /* Close root_fd, for which no references remain.  */
+      close (root_fd);
+      root_fd = -1;
+    }
+
+  xfree (vdir);
+}
+
+static int
+android_root_dirfd (struct android_vdir *vdir)
+{
+  struct android_unix_vdir *dir;
+
+  dir = (struct android_unix_vdir *) vdir;
+
+  if (dir->directory)
+    return dirfd (dir->directory);
+
+  return root_fd;
+}
+
+static struct android_vdir *
+android_root_opendir (struct android_vnode *vnode)
+{
+  struct android_unix_vnode *vp;
+  struct android_root_vdir *dir;
+  DIR *directory;
+
+  /* Try to opendir the vnode.  */
+  vp = (struct android_unix_vnode *) vnode;
+
+  directory = opendir (vp->name);
+
+  /* Proceed with the remaining code if directory is nil, in which event
+     directory functions will simply forgo listing files inside the real
+     root directory.  */
+
+  dir = xmalloc (sizeof *dir);
+  dir->vdir.readdir = android_root_readdir;
+  dir->vdir.closedir = android_root_closedir;
+  dir->vdir.dirfd = android_root_dirfd;
+  dir->directory = directory;
+  dir->index = 0;
+
+  if (!directory)
+    {
+      /* Allocate a temporary file descriptor for this ersatz root.  */
+      if (root_fd < 0)
+       root_fd = open ("/dev/null", O_RDONLY | O_CLOEXEC);
+      root_fd_references++;
+    }
+
+  return &dir->vdir;
+}
+
 
 
 /* File system lookup.  */
@@ -7223,6 +7336,14 @@ android_fstatat_1 (int dirfd, const char *filename,
       return 0;
     }
 
+  /* /foo... */
+
+  if (root_fd >= 0 && dirfd == root_fd)
+    {
+      snprintf (buffer, size, "/%s", filename);
+      return 0;
+    }
+
   return 1;
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]