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.
This commit is contained in:
parent
de8cae30bc
commit
7f377407b4
2 changed files with 156 additions and 7 deletions
|
@ -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)
|
||||
|
|
127
src/androidvfs.c
127
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue