/* Lisp functions for making directory listings.
- Copyright (C) 1985-1986, 1993-1994, 1999-2012 Free Software Foundation, Inc.
+ Copyright (C) 1985-1986, 1993-1994, 1999-2013 Free Software
+ Foundation, Inc.
This file is part of GNU Emacs.
#include <grp.h>
#include <errno.h>
+#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
static Lisp_Object Qfile_attributes_lessp;
static ptrdiff_t scmp (const char *, const char *, ptrdiff_t);
+static Lisp_Object file_attributes (int, char const *, Lisp_Object);
\f
/* Return the number of bytes in DP's name. */
static ptrdiff_t
#endif
}
+static DIR *
+open_directory (char const *name, int *fdp)
+{
+ DIR *d;
+ int fd, opendir_errno;
+
+ block_input ();
+
+#ifdef DOS_NT
+ /* Directories cannot be opened. The emulation assumes that any
+ file descriptor other than AT_FDCWD corresponds to the most
+ recently opened directory. This hack is good enough for Emacs. */
+ fd = 0;
+ d = opendir (name);
+ opendir_errno = errno;
+#else
+ fd = emacs_open (name, O_RDONLY | O_DIRECTORY, 0);
+ if (fd < 0)
+ {
+ opendir_errno = errno;
+ d = 0;
+ }
+ else
+ {
+ d = fdopendir (fd);
+ opendir_errno = errno;
+ if (! d)
+ emacs_close (fd);
+ }
+#endif
+
+ unblock_input ();
+
+ *fdp = fd;
+ errno = opendir_errno;
+ return d;
+}
+
#ifdef WINDOWSNT
-Lisp_Object
+void
directory_files_internal_w32_unwind (Lisp_Object arg)
{
Vw32_get_true_file_attributes = arg;
- return Qnil;
}
#endif
-static Lisp_Object
-directory_files_internal_unwind (Lisp_Object dh)
+static void
+directory_files_internal_unwind (void *dh)
{
- DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer;
+ DIR *d = dh;
block_input ();
closedir (d);
unblock_input ();
- return Qnil;
}
/* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
Lisp_Object id_format)
{
DIR *d;
+ int fd;
ptrdiff_t directory_nbytes;
Lisp_Object list, dirfilename, encoded_directory;
struct re_pattern_buffer *bufp = NULL;
/* Now *bufp is the compiled form of MATCH; don't call anything
which might compile a new regexp until we're done with the loop! */
- block_input ();
- d = opendir (SSDATA (dirfilename));
- unblock_input ();
+ d = open_directory (SSDATA (dirfilename), &fd);
if (d == NULL)
- report_file_error ("Opening directory", Fcons (directory, Qnil));
+ report_file_error ("Opening directory", directory);
/* Unfortunately, we can now invoke expand-file-name and
file-attributes on filenames, both of which can throw, so we must
do a proper unwind-protect. */
- record_unwind_protect (directory_files_internal_unwind,
- make_save_value (d, 0));
+ record_unwind_protect_ptr (directory_files_internal_unwind, d);
#ifdef WINDOWSNT
if (attrs)
QUIT;
if (NILP (match)
- || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0)))
+ || re_search (bufp, SSDATA (name), len, 0, len, 0) >= 0)
wanted = 1;
immediate_quit = 0;
memcpy (SDATA (fullname) + directory_nbytes + needsep,
SDATA (name), len);
- nchars = chars_in_text (SDATA (fullname), nbytes);
+ nchars = multibyte_chars_in_text (SDATA (fullname), nbytes);
/* Some bug somewhere. */
if (nchars > nbytes)
if (attrs)
{
- /* Construct an expanded filename for the directory entry.
- Use the decoded names for input to Ffile_attributes. */
- Lisp_Object decoded_fullname, fileattrs;
- struct gcpro gcpro1, gcpro2;
-
- decoded_fullname = fileattrs = Qnil;
- GCPRO2 (decoded_fullname, fileattrs);
-
- /* Both Fexpand_file_name and Ffile_attributes can GC. */
- decoded_fullname = Fexpand_file_name (name, directory);
- fileattrs = Ffile_attributes (decoded_fullname, id_format);
-
+ Lisp_Object fileattrs
+ = file_attributes (fd, dp->d_name, id_format);
list = Fcons (Fcons (finalname, fileattrs), list);
- UNGCPRO;
}
else
list = Fcons (finalname, list);
return file_name_completion (file, directory, 1, Qnil);
}
-static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
- struct stat *st_addr);
+static int file_name_completion_stat (int, struct dirent *, struct stat *);
static Lisp_Object Qdefault_directory;
static Lisp_Object
Lisp_Object predicate)
{
DIR *d;
+ int fd;
ptrdiff_t bestmatchsize = 0;
int matchcount = 0;
/* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded.
on the encoded file name. */
encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file;
- encoded_dir = ENCODE_FILE (dirname);
+ encoded_dir = ENCODE_FILE (Fdirectory_file_name (dirname));
- block_input ();
- d = opendir (SSDATA (Fdirectory_file_name (encoded_dir)));
- unblock_input ();
+ d = open_directory (SSDATA (encoded_dir), &fd);
if (!d)
- report_file_error ("Opening directory", Fcons (dirname, Qnil));
+ report_file_error ("Opening directory", dirname);
- record_unwind_protect (directory_files_internal_unwind,
- make_save_value (d, 0));
+ record_unwind_protect_ptr (directory_files_internal_unwind, d);
/* Loop reading blocks */
/* (att3b compiler bug requires do a null comparison this way) */
QUIT;
if (len < SCHARS (encoded_file)
- || 0 <= scmp (dp->d_name, SSDATA (encoded_file),
- SCHARS (encoded_file)))
+ || (scmp (dp->d_name, SSDATA (encoded_file),
+ SCHARS (encoded_file))
+ >= 0))
continue;
- if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
+ if (file_name_completion_stat (fd, dp, &st) < 0)
continue;
directoryp = S_ISDIR (st.st_mode) != 0;
if (skip < 0)
continue;
- if (0 <= scmp (dp->d_name + skip, p1, elt_len))
+ if (scmp (dp->d_name + skip, p1, elt_len) >= 0)
continue;
break;
}
skip = len - SCHARS (elt);
if (skip < 0) continue;
- if (0 <= scmp (dp->d_name + skip,
- SSDATA (elt),
- SCHARS (elt)))
+ if (scmp (dp->d_name + skip, SSDATA (elt), SCHARS (elt))
+ >= 0)
continue;
break;
}
name, zero,
make_number (compare),
completion_ignore_case ? Qt : Qnil);
- ptrdiff_t matchsize
- = (EQ (cmp, Qt) ? compare
- : XINT (cmp) < 0 ? - XINT (cmp) - 1
- : XINT (cmp) - 1);
+ ptrdiff_t matchsize = EQ (cmp, Qt) ? compare : eabs (XINT (cmp)) - 1;
if (completion_ignore_case)
{
}
static int
-file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
- struct stat *st_addr)
+file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr)
{
- ptrdiff_t len = dirent_namelen (dp);
- ptrdiff_t pos = SCHARS (dirname);
int value;
- USE_SAFE_ALLOCA;
- char *fullname = SAFE_ALLOCA (len + pos + 2);
#ifdef MSDOS
/* Some fields of struct stat are *very* expensive to compute on MS-DOS,
_djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
#endif /* MSDOS */
- memcpy (fullname, SDATA (dirname), pos);
- if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
- fullname[pos++] = DIRECTORY_SEP;
-
- memcpy (fullname + pos, dp->d_name, len);
- fullname[pos + len] = 0;
-
/* We want to return success if a link points to a nonexistent file,
but we want to return the status for what the link points to,
in case it is a directory. */
- value = lstat (fullname, st_addr);
+ value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW);
if (value == 0 && S_ISLNK (st_addr->st_mode))
- stat (fullname, st_addr);
+ fstatat (fd, dp->d_name, st_addr, 0);
#ifdef MSDOS
_djstat_flags = save_djstat_flags;
#endif /* MSDOS */
- SAFE_FREE ();
return value;
}
\f
so last access time will always be midnight of that day. */)
(Lisp_Object filename, Lisp_Object id_format)
{
- Lisp_Object values[12];
Lisp_Object encoded;
- struct stat s;
- int lstat_result;
-
- /* An array to hold the mode string generated by filemodestring,
- including its terminating space and null byte. */
- char modes[sizeof "-rwxr-xr-x "];
-
Lisp_Object handler;
- struct gcpro gcpro1;
- char *uname = NULL, *gname = NULL;
filename = Fexpand_file_name (filename, Qnil);
return call3 (handler, Qfile_attributes, filename, id_format);
}
- GCPRO1 (filename);
encoded = ENCODE_FILE (filename);
- UNGCPRO;
+ return file_attributes (AT_FDCWD, SSDATA (encoded), id_format);
+}
+
+static Lisp_Object
+file_attributes (int fd, char const *name, Lisp_Object id_format)
+{
+ Lisp_Object values[12];
+ struct stat s;
+ int lstat_result;
+
+ /* An array to hold the mode string generated by filemodestring,
+ including its terminating space and null byte. */
+ char modes[sizeof "-rwxr-xr-x "];
+
+ char *uname = NULL, *gname = NULL;
#ifdef WINDOWSNT
/* We usually don't request accurate owner and group info, because
w32_stat_get_owner_group = 1;
#endif
- lstat_result = lstat (SSDATA (encoded), &s);
+ lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW);
#ifdef WINDOWSNT
w32_stat_get_owner_group = 0;
if (lstat_result < 0)
return Qnil;
- values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename)
+ values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name)
: S_ISDIR (s.st_mode) ? Qt : Qnil);
values[1] = make_number (s.st_nlink);
#endif
if (EQ (users, Qnil))
/* At least current user is always known. */
- users = Fcons (Vuser_real_login_name, Qnil);
+ users = list1 (Vuser_real_login_name);
return users;
}