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)
\f
/* 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. */
android_unix_mkdir,
android_unix_chmod,
android_unix_readlink,
- android_unix_opendir,
+ android_root_opendir,
};
/* Array of special named vnodes. */
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;
+}
+
\f
/* File system lookup. */
return 0;
}
+ /* /foo... */
+
+ if (root_fd >= 0 && dirfd == root_fd)
+ {
+ snprintf (buffer, size, "/%s", filename);
+ return 0;
+ }
+
return 1;
}