X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e18afed7d695edac870ddf55aabc85c0a95a4b5f..47571310770234371eb6e361214056efd1b67137:/src/dired.c diff --git a/src/dired.c b/src/dired.c index 367bcb4031..d3fe5b4943 100644 --- a/src/dired.c +++ b/src/dired.c @@ -1,5 +1,6 @@ /* 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-2014 Free Software + Foundation, Inc. This file is part of GNU Emacs. @@ -22,7 +23,6 @@ along with GNU Emacs. If not, see . */ #include #include #include -#include #ifdef HAVE_PWD_H #include @@ -30,55 +30,27 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include -/* The d_nameln member of a struct dirent includes the '\0' character - on some systems, but not on others. What's worse, you can't tell - at compile-time which one it will be, since it really depends on - the sort of system providing the filesystem you're reading from, - not the system you are running on. Paul Eggert - says this occurs when Emacs is running on a - SunOS 4.1.2 host, reading a directory that is remote-mounted from a - Solaris 2.1 host and is in a native Solaris 2.1 filesystem. - - Since applying strlen to the name always works, we'll just do that. */ -#define NAMLEN(p) strlen (p->d_name) - -#ifdef HAVE_DIRENT_H - #include -#define DIRENTRY struct dirent - -#else /* not HAVE_DIRENT_H */ - -#include -#include - -#define DIRENTRY struct direct - -extern DIR *opendir (char *); -extern struct direct *readdir (DIR *); - -#endif /* HAVE_DIRENT_H */ - #include - -#ifdef MSDOS -#define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0) -#else -#define DIRENTRY_NONEMPTY(p) ((p)->d_ino) -#endif +#include #include "lisp.h" #include "systime.h" +#include "character.h" #include "buffer.h" #include "commands.h" -#include "character.h" #include "charset.h" #include "coding.h" #include "regex.h" #include "blockinput.h" +#ifdef MSDOS +#include "msdos.h" /* for fstatat */ +#endif + static Lisp_Object Qdirectory_files; static Lisp_Object Qdirectory_files_and_attributes; static Lisp_Object Qfile_name_completion; @@ -86,44 +58,94 @@ static Lisp_Object Qfile_name_all_completions; static Lisp_Object Qfile_attributes; static Lisp_Object Qfile_attributes_lessp; -static int scmp (const char *, const char *, int); -static Lisp_Object Ffile_attributes (Lisp_Object, Lisp_Object); +static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); +static Lisp_Object file_attributes (int, char const *, Lisp_Object); +/* Return the number of bytes in DP's name. */ +static ptrdiff_t +dirent_namelen (struct dirent *dp) +{ +#ifdef _D_EXACT_NAMLEN + return _D_EXACT_NAMLEN (dp); +#else + return strlen (dp->d_name); +#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; - BLOCK_INPUT; + DIR *d = dh; + block_input (); closedir (d); - UNBLOCK_INPUT; - return Qnil; + unblock_input (); } /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes. - When ATTRS is zero, return a list of directory filenames; when - non-zero, return a list of directory filenames and their attributes. + If not ATTRS, return a list of directory filenames; + if ATTRS, return a list of directory filenames and their attributes. In the latter case, ID_FORMAT is passed to Ffile_attributes. */ Lisp_Object -directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, int attrs, Lisp_Object id_format) +directory_files_internal (Lisp_Object directory, Lisp_Object full, + Lisp_Object match, Lisp_Object nosort, bool attrs, + Lisp_Object id_format) { DIR *d; - int directory_nbytes; + int fd; + ptrdiff_t directory_nbytes; Lisp_Object list, dirfilename, encoded_directory; struct re_pattern_buffer *bufp = NULL; - int needsep = 0; - int count = SPECPDL_INDEX (); + bool needsep = 0; + ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; - DIRENTRY *dp; + struct dirent *dp; #ifdef WINDOWSNT Lisp_Object w32_save = Qnil; #endif @@ -163,17 +185,14 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object m /* 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) @@ -208,110 +227,92 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object m /* Loop reading blocks until EOF or error. */ for (;;) { + ptrdiff_t len; + bool wanted = 0; + Lisp_Object name, finalname; + struct gcpro gcpro1, gcpro2; + errno = 0; dp = readdir (d); + if (!dp) + { + if (errno == EAGAIN || errno == EINTR) + { + QUIT; + continue; + } + break; + } - if (dp == NULL && (0 -#ifdef EAGAIN - || errno == EAGAIN -#endif -#ifdef EINTR - || errno == EINTR -#endif - )) - { QUIT; continue; } + len = dirent_namelen (dp); + name = finalname = make_unibyte_string (dp->d_name, len); + GCPRO2 (finalname, name); + + /* Note: DECODE_FILE can GC; it should protect its argument, + though. */ + name = DECODE_FILE (name); + len = SBYTES (name); + + /* Now that we have unwind_protect in place, we might as well + allow matching to be interrupted. */ + immediate_quit = 1; + QUIT; + + if (NILP (match) + || re_search (bufp, SSDATA (name), len, 0, len, 0) >= 0) + wanted = 1; - if (dp == NULL) - break; + immediate_quit = 0; - if (DIRENTRY_NONEMPTY (dp)) + if (wanted) { - int len; - int wanted = 0; - Lisp_Object name, finalname; - struct gcpro gcpro1, gcpro2; + if (!NILP (full)) + { + Lisp_Object fullname; + ptrdiff_t nbytes = len + directory_nbytes + needsep; + ptrdiff_t nchars; - len = NAMLEN (dp); - name = finalname = make_unibyte_string (dp->d_name, len); - GCPRO2 (finalname, name); + fullname = make_uninit_multibyte_string (nbytes, nbytes); + memcpy (SDATA (fullname), SDATA (directory), + directory_nbytes); - /* Note: DECODE_FILE can GC; it should protect its argument, - though. */ - name = DECODE_FILE (name); - len = SBYTES (name); + if (needsep) + SSET (fullname, directory_nbytes, DIRECTORY_SEP); - /* Now that we have unwind_protect in place, we might as well - allow matching to be interrupted. */ - immediate_quit = 1; - QUIT; + memcpy (SDATA (fullname) + directory_nbytes + needsep, + SDATA (name), len); - if (NILP (match) - || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0))) - wanted = 1; + nchars = multibyte_chars_in_text (SDATA (fullname), nbytes); - immediate_quit = 0; + /* Some bug somewhere. */ + if (nchars > nbytes) + emacs_abort (); - if (wanted) - { - if (!NILP (full)) - { - Lisp_Object fullname; - int nbytes = len + directory_nbytes + needsep; - int nchars; - - fullname = make_uninit_multibyte_string (nbytes, nbytes); - memcpy (SDATA (fullname), SDATA (directory), - directory_nbytes); - - if (needsep) - SSET (fullname, directory_nbytes, DIRECTORY_SEP); - - memcpy (SDATA (fullname) + directory_nbytes + needsep, - SDATA (name), len); - - nchars = chars_in_text (SDATA (fullname), nbytes); - - /* Some bug somewhere. */ - if (nchars > nbytes) - abort (); - - STRING_SET_CHARS (fullname, nchars); - if (nchars == nbytes) - STRING_SET_UNIBYTE (fullname); - - finalname = fullname; - } - else - finalname = name; - - 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); - - list = Fcons (Fcons (finalname, fileattrs), list); - UNGCPRO; - } - else - list = Fcons (finalname, list); + STRING_SET_CHARS (fullname, nchars); + if (nchars == nbytes) + STRING_SET_UNIBYTE (fullname); + + finalname = fullname; } + else + finalname = name; - UNGCPRO; + if (attrs) + { + Lisp_Object fileattrs + = file_attributes (fd, dp->d_name, id_format); + list = Fcons (Fcons (finalname, fileattrs), list); + } + else + list = Fcons (finalname, list); } + + UNGCPRO; } - BLOCK_INPUT; + block_input (); closedir (d); - UNBLOCK_INPUT; + unblock_input (); #ifdef WINDOWSNT if (attrs) Vw32_get_true_file_attributes = w32_save; @@ -381,9 +382,8 @@ which see. */) } -static Lisp_Object file_name_completion - (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag, - Lisp_Object predicate); +static Lisp_Object file_name_completion (Lisp_Object, Lisp_Object, bool, + Lisp_Object); DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion, 2, 3, 0, @@ -415,7 +415,7 @@ determined by the variable `completion-ignored-extensions', which see. */) if (!NILP (handler)) return call4 (handler, Qfile_name_completion, file, directory, predicate); - return file_name_completion (file, directory, 0, 0, predicate); + return file_name_completion (file, directory, 0, predicate); } DEFUN ("file-name-all-completions", Ffile_name_all_completions, @@ -439,17 +439,19 @@ These are all file names in directory DIRECTORY which begin with FILE. */) if (!NILP (handler)) return call3 (handler, Qfile_name_all_completions, file, directory); - return file_name_completion (file, directory, 1, 0, Qnil); + return file_name_completion (file, directory, 1, Qnil); } -static int file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr); +static int file_name_completion_stat (int, struct dirent *, struct stat *); static Lisp_Object Qdefault_directory; static Lisp_Object -file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag, Lisp_Object predicate) +file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, + Lisp_Object predicate) { DIR *d; - int bestmatchsize = 0; + int fd; + ptrdiff_t bestmatchsize = 0; int matchcount = 0; /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. If ALL_FLAG is 0, BESTMATCH is either nil @@ -458,21 +460,18 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v Lisp_Object encoded_file; Lisp_Object encoded_dir; struct stat st; - int directoryp; - /* If includeall is zero, exclude files in completion-ignored-extensions as + bool directoryp; + /* If not INCLUDEALL, exclude files in completion-ignored-extensions as well as "." and "..". Until shown otherwise, assume we can't exclude anything. */ - int includeall = 1; - int count = SPECPDL_INDEX (); + bool includeall = 1; + ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; elt = Qnil; CHECK_STRING (file); -#ifdef FILE_SYSTEM_CASE - file = FILE_SYSTEM_CASE (file); -#endif bestmatch = Qnil; encoded_file = encoded_dir = Qnil; GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir); @@ -486,59 +485,54 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v 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) */ while (1) { - DIRENTRY *dp; - int len; - int canexclude = 0; + struct dirent *dp; + ptrdiff_t len; + bool canexclude = 0; errno = 0; dp = readdir (d); - if (dp == NULL && (0 -# ifdef EAGAIN - || errno == EAGAIN -# endif -# ifdef EINTR - || errno == EINTR -# endif - )) - { QUIT; continue; } - - if (!dp) break; + if (!dp) + { + if (errno == EAGAIN || errno == EINTR) + { + QUIT; + continue; + } + break; + } - len = NAMLEN (dp); + len = dirent_namelen (dp); QUIT; - if (! DIRENTRY_NONEMPTY (dp) - || len < SCHARS (encoded_file) - || 0 <= scmp (dp->d_name, SSDATA (encoded_file), - SCHARS (encoded_file))) + if (len < 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); + directoryp = S_ISDIR (st.st_mode) != 0; tem = Qnil; /* If all_flag is set, always include all. It would not actually be helpful to the user to ignore any possible completions when making a list of them. */ if (!all_flag) { - int skip; + ptrdiff_t skip; #if 0 /* FIXME: The `scmp' call compares an encoded and a decoded string. */ /* If this entry matches the current bestmatch, the only @@ -568,7 +562,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v for (tem = Vcompletion_ignored_extensions; CONSP (tem); tem = XCDR (tem)) { - int elt_len; + ptrdiff_t elt_len; char *p1; elt = XCAR (tem); @@ -587,7 +581,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v 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; } @@ -609,9 +603,8 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v 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; } @@ -685,7 +678,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v /* Suitably record this match. */ - matchcount++; + matchcount += matchcount <= 1; if (all_flag) bestmatch = Fcons (name, bestmatch); @@ -698,17 +691,14 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v { Lisp_Object zero = make_number (0); /* FIXME: This is a copy of the code in Ftry_completion. */ - int compare = min (bestmatchsize, SCHARS (name)); + ptrdiff_t compare = min (bestmatchsize, SCHARS (name)); Lisp_Object cmp = Fcompare_strings (bestmatch, zero, make_number (compare), name, zero, make_number (compare), completion_ignore_case ? Qt : Qnil); - int 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) { @@ -719,7 +709,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v /* This tests that the current file is an exact match but BESTMATCH is not (it is too long). */ if ((matchsize == SCHARS (name) - && matchsize + !!directoryp < SCHARS (bestmatch)) + && matchsize + directoryp < SCHARS (bestmatch)) || /* If there is no exact match ignoring case, prefer a match that does not change the case @@ -731,7 +721,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v either both or neither are exact. */ (((matchsize == SCHARS (name)) == - (matchsize + !!directoryp == SCHARS (bestmatch))) + (matchsize + directoryp == SCHARS (bestmatch))) && (cmp = Fcompare_strings (name, zero, make_number (SCHARS (file)), file, zero, @@ -784,10 +774,10 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int v Return -1 if strings match, else number of chars that match at the beginning. */ -static int -scmp (const char *s1, const char *s2, int len) +static ptrdiff_t +scmp (const char *s1, const char *s2, ptrdiff_t len) { - register int l = len; + register ptrdiff_t l = len; if (completion_ignore_case) { @@ -808,12 +798,9 @@ scmp (const char *s1, const char *s2, int len) } static int -file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr) +file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr) { - int len = NAMLEN (dp); - int pos = SCHARS (dirname); int value; - char *fullname = (char *) alloca (len + pos + 2); #ifdef MSDOS /* Some fields of struct stat are *very* expensive to compute on MS-DOS, @@ -826,19 +813,12 @@ file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_ad _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 */ @@ -851,7 +831,7 @@ stat_uname (struct stat *st) #ifdef WINDOWSNT return st->st_uname; #else - struct passwd *pw = (struct passwd *) getpwuid (st->st_uid); + struct passwd *pw = getpwuid (st->st_uid); if (pw) return pw->pw_name; @@ -866,7 +846,7 @@ stat_gname (struct stat *st) #ifdef WINDOWSNT return st->st_gname; #else - struct group *gr = (struct group *) getgrgid (st->st_gid); + struct group *gr = getgrgid (st->st_gid); if (gr) return gr->gr_name; @@ -890,8 +870,8 @@ Elements of the attribute list are: 2. File uid as a string or a number. If a string value cannot be looked up, a numeric value, either an integer or a float, is returned. 3. File gid, likewise. - 4. Last access time, as a list of two integers. - First integer has high-order 16 bits of time, second has low 16 bits. + 4. Last access time, as a list of integers (HIGH LOW USEC PSEC) in the + same style as (current-time). (See a note below about access time on FAT-based filesystems.) 5. Last modification time, likewise. This is the time of the last change to the file's contents. @@ -900,7 +880,7 @@ Elements of the attribute list are: 7. Size in bytes. This is a floating point number if the size is too large for an integer. 8. File modes, as a string of ten letters or dashes as in ls -l. - 9. t if file's gid would change if file were deleted and recreated. + 9. An unspecified value, present only for backward compatibility. 10. inode number. If it is larger than what an Emacs integer can hold, this is of the form (HIGH . LOW): first the high bits, then the low 16 bits. If even HIGH is too large for an Emacs integer, this is instead of the form @@ -919,21 +899,8 @@ On some FAT-based filesystems, only the date of last access is recorded, 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; -#ifdef BSD4_2 - Lisp_Object dirname; - struct stat sdir; -#endif /* BSD4_2 */ - - /* 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); @@ -949,36 +916,63 @@ so last access time will always be midnight of that day. */) 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 + it can be very expensive on Windows to get that, and most callers + of 'lstat' don't need that. But here we do want that information + to be accurate. */ + w32_stat_get_owner_group = 1; +#endif + + lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW); + +#ifdef WINDOWSNT + w32_stat_get_owner_group = 0; +#endif - if (lstat (SSDATA (encoded), &s) < 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); if (!(NILP (id_format) || EQ (id_format, Qinteger))) { - BLOCK_INPUT; + block_input (); uname = stat_uname (&s); gname = stat_gname (&s); - UNBLOCK_INPUT; + unblock_input (); } if (uname) - values[2] = DECODE_SYSTEM (build_string (uname)); + values[2] = DECODE_SYSTEM (build_unibyte_string (uname)); else values[2] = make_fixnum_or_float (s.st_uid); if (gname) - values[3] = DECODE_SYSTEM (build_string (gname)); + values[3] = DECODE_SYSTEM (build_unibyte_string (gname)); else values[3] = make_fixnum_or_float (s.st_gid); - values[4] = make_time (s.st_atime); - values[5] = make_time (s.st_mtime); - values[6] = make_time (s.st_ctime); + values[4] = make_lisp_time (get_stat_atime (&s)); + values[5] = make_lisp_time (get_stat_mtime (&s)); + values[6] = make_lisp_time (get_stat_ctime (&s)); /* If the file size is a 4-byte type, assume that files of sizes in the 2-4 GiB range wrap around to negative values, as this is a @@ -990,21 +984,11 @@ so last access time will always be midnight of that day. */) filemodestring (&s, modes); values[8] = make_string (modes, 10); -#ifdef BSD4_2 /* file gid will be dir gid */ - dirname = Ffile_name_directory (filename); - if (! NILP (dirname)) - encoded = ENCODE_FILE (dirname); - if (! NILP (dirname) && stat (SDATA (encoded), &sdir) == 0) - values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil; - else /* if we can't tell, assume worst */ - values[9] = Qt; -#else /* file gid will be egid */ - values[9] = (s.st_gid != getegid ()) ? Qt : Qnil; -#endif /* not BSD4_2 */ + values[9] = Qt; values[10] = INTEGER_TO_CONS (s.st_ino); values[11] = INTEGER_TO_CONS (s.st_dev); - return Flist (sizeof (values) / sizeof (values[0]), values); + return Flist (ARRAYELTS (values), values); } DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, @@ -1033,7 +1017,7 @@ return a list with one element, taken from `user-real-login-name'. */) #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; }