diff options
Diffstat (limited to 'src/dired.c')
| -rw-r--r-- | src/dired.c | 226 |
1 files changed, 117 insertions, 109 deletions
diff --git a/src/dired.c b/src/dired.c index 3530b74ecb4..ab48488966b 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* Lisp functions for making directory listings. | 1 | /* Lisp functions for making directory listings. |
| 2 | Copyright (C) 1985-1986, 1993-1994, 1999-2012 Free Software Foundation, Inc. | 2 | Copyright (C) 1985-1986, 1993-1994, 1999-2013 Free Software |
| 3 | Foundation, Inc. | ||
| 3 | 4 | ||
| 4 | This file is part of GNU Emacs. | 5 | This file is part of GNU Emacs. |
| 5 | 6 | ||
| @@ -29,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 29 | #include <grp.h> | 30 | #include <grp.h> |
| 30 | 31 | ||
| 31 | #include <errno.h> | 32 | #include <errno.h> |
| 33 | #include <fcntl.h> | ||
| 32 | #include <unistd.h> | 34 | #include <unistd.h> |
| 33 | 35 | ||
| 34 | #include <dirent.h> | 36 | #include <dirent.h> |
| @@ -53,6 +55,7 @@ static Lisp_Object Qfile_attributes; | |||
| 53 | static Lisp_Object Qfile_attributes_lessp; | 55 | static Lisp_Object Qfile_attributes_lessp; |
| 54 | 56 | ||
| 55 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); | 57 | static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); |
| 58 | static Lisp_Object file_attributes (int, char const *, Lisp_Object); | ||
| 56 | 59 | ||
| 57 | /* Return the number of bytes in DP's name. */ | 60 | /* Return the number of bytes in DP's name. */ |
| 58 | static ptrdiff_t | 61 | static ptrdiff_t |
| @@ -65,6 +68,44 @@ dirent_namelen (struct dirent *dp) | |||
| 65 | #endif | 68 | #endif |
| 66 | } | 69 | } |
| 67 | 70 | ||
| 71 | static DIR * | ||
| 72 | open_directory (char const *name, int *fdp) | ||
| 73 | { | ||
| 74 | DIR *d; | ||
| 75 | int fd, opendir_errno; | ||
| 76 | |||
| 77 | block_input (); | ||
| 78 | |||
| 79 | #ifdef DOS_NT | ||
| 80 | /* Directories cannot be opened. The emulation assumes that any | ||
| 81 | file descriptor other than AT_FDCWD corresponds to the most | ||
| 82 | recently opened directory. This hack is good enough for Emacs. */ | ||
| 83 | fd = 0; | ||
| 84 | d = opendir (name); | ||
| 85 | opendir_errno = errno; | ||
| 86 | #else | ||
| 87 | fd = emacs_open (name, O_RDONLY | O_DIRECTORY, 0); | ||
| 88 | if (fd < 0) | ||
| 89 | { | ||
| 90 | opendir_errno = errno; | ||
| 91 | d = 0; | ||
| 92 | } | ||
| 93 | else | ||
| 94 | { | ||
| 95 | d = fdopendir (fd); | ||
| 96 | opendir_errno = errno; | ||
| 97 | if (! d) | ||
| 98 | close (fd); | ||
| 99 | } | ||
| 100 | #endif | ||
| 101 | |||
| 102 | unblock_input (); | ||
| 103 | |||
| 104 | *fdp = fd; | ||
| 105 | errno = opendir_errno; | ||
| 106 | return d; | ||
| 107 | } | ||
| 108 | |||
| 68 | #ifdef WINDOWSNT | 109 | #ifdef WINDOWSNT |
| 69 | Lisp_Object | 110 | Lisp_Object |
| 70 | directory_files_internal_w32_unwind (Lisp_Object arg) | 111 | directory_files_internal_w32_unwind (Lisp_Object arg) |
| @@ -77,7 +118,7 @@ directory_files_internal_w32_unwind (Lisp_Object arg) | |||
| 77 | static Lisp_Object | 118 | static Lisp_Object |
| 78 | directory_files_internal_unwind (Lisp_Object dh) | 119 | directory_files_internal_unwind (Lisp_Object dh) |
| 79 | { | 120 | { |
| 80 | DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer; | 121 | DIR *d = XSAVE_POINTER (dh, 0); |
| 81 | block_input (); | 122 | block_input (); |
| 82 | closedir (d); | 123 | closedir (d); |
| 83 | unblock_input (); | 124 | unblock_input (); |
| @@ -95,6 +136,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 95 | Lisp_Object id_format) | 136 | Lisp_Object id_format) |
| 96 | { | 137 | { |
| 97 | DIR *d; | 138 | DIR *d; |
| 139 | int fd; | ||
| 98 | ptrdiff_t directory_nbytes; | 140 | ptrdiff_t directory_nbytes; |
| 99 | Lisp_Object list, dirfilename, encoded_directory; | 141 | Lisp_Object list, dirfilename, encoded_directory; |
| 100 | struct re_pattern_buffer *bufp = NULL; | 142 | struct re_pattern_buffer *bufp = NULL; |
| @@ -141,9 +183,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 141 | /* Now *bufp is the compiled form of MATCH; don't call anything | 183 | /* Now *bufp is the compiled form of MATCH; don't call anything |
| 142 | which might compile a new regexp until we're done with the loop! */ | 184 | which might compile a new regexp until we're done with the loop! */ |
| 143 | 185 | ||
| 144 | block_input (); | 186 | d = open_directory (SSDATA (dirfilename), &fd); |
| 145 | d = opendir (SSDATA (dirfilename)); | ||
| 146 | unblock_input (); | ||
| 147 | if (d == NULL) | 187 | if (d == NULL) |
| 148 | report_file_error ("Opening directory", Fcons (directory, Qnil)); | 188 | report_file_error ("Opening directory", Fcons (directory, Qnil)); |
| 149 | 189 | ||
| @@ -151,7 +191,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 151 | file-attributes on filenames, both of which can throw, so we must | 191 | file-attributes on filenames, both of which can throw, so we must |
| 152 | do a proper unwind-protect. */ | 192 | do a proper unwind-protect. */ |
| 153 | record_unwind_protect (directory_files_internal_unwind, | 193 | record_unwind_protect (directory_files_internal_unwind, |
| 154 | make_save_value (d, 0)); | 194 | make_save_pointer (d)); |
| 155 | 195 | ||
| 156 | #ifdef WINDOWSNT | 196 | #ifdef WINDOWSNT |
| 157 | if (attrs) | 197 | if (attrs) |
| @@ -193,19 +233,15 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 193 | 233 | ||
| 194 | errno = 0; | 234 | errno = 0; |
| 195 | dp = readdir (d); | 235 | dp = readdir (d); |
| 196 | 236 | if (!dp) | |
| 197 | if (dp == NULL && (0 | 237 | { |
| 198 | #ifdef EAGAIN | 238 | if (errno == EAGAIN || errno == EINTR) |
| 199 | || errno == EAGAIN | 239 | { |
| 200 | #endif | 240 | QUIT; |
| 201 | #ifdef EINTR | 241 | continue; |
| 202 | || errno == EINTR | 242 | } |
| 203 | #endif | 243 | break; |
| 204 | )) | 244 | } |
| 205 | { QUIT; continue; } | ||
| 206 | |||
| 207 | if (dp == NULL) | ||
| 208 | break; | ||
| 209 | 245 | ||
| 210 | len = dirent_namelen (dp); | 246 | len = dirent_namelen (dp); |
| 211 | name = finalname = make_unibyte_string (dp->d_name, len); | 247 | name = finalname = make_unibyte_string (dp->d_name, len); |
| @@ -222,7 +258,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 222 | QUIT; | 258 | QUIT; |
| 223 | 259 | ||
| 224 | if (NILP (match) | 260 | if (NILP (match) |
| 225 | || (0 <= re_search (bufp, SSDATA (name), len, 0, len, 0))) | 261 | || re_search (bufp, SSDATA (name), len, 0, len, 0) >= 0) |
| 226 | wanted = 1; | 262 | wanted = 1; |
| 227 | 263 | ||
| 228 | immediate_quit = 0; | 264 | immediate_quit = 0; |
| @@ -262,20 +298,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, | |||
| 262 | 298 | ||
| 263 | if (attrs) | 299 | if (attrs) |
| 264 | { | 300 | { |
| 265 | /* Construct an expanded filename for the directory entry. | 301 | Lisp_Object fileattrs |
| 266 | Use the decoded names for input to Ffile_attributes. */ | 302 | = file_attributes (fd, dp->d_name, id_format); |
| 267 | Lisp_Object decoded_fullname, fileattrs; | ||
| 268 | struct gcpro gcpro1, gcpro2; | ||
| 269 | |||
| 270 | decoded_fullname = fileattrs = Qnil; | ||
| 271 | GCPRO2 (decoded_fullname, fileattrs); | ||
| 272 | |||
| 273 | /* Both Fexpand_file_name and Ffile_attributes can GC. */ | ||
| 274 | decoded_fullname = Fexpand_file_name (name, directory); | ||
| 275 | fileattrs = Ffile_attributes (decoded_fullname, id_format); | ||
| 276 | |||
| 277 | list = Fcons (Fcons (finalname, fileattrs), list); | 303 | list = Fcons (Fcons (finalname, fileattrs), list); |
| 278 | UNGCPRO; | ||
| 279 | } | 304 | } |
| 280 | else | 305 | else |
| 281 | list = Fcons (finalname, list); | 306 | list = Fcons (finalname, list); |
| @@ -416,8 +441,7 @@ These are all file names in directory DIRECTORY which begin with FILE. */) | |||
| 416 | return file_name_completion (file, directory, 1, Qnil); | 441 | return file_name_completion (file, directory, 1, Qnil); |
| 417 | } | 442 | } |
| 418 | 443 | ||
| 419 | static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | 444 | static int file_name_completion_stat (int, struct dirent *, struct stat *); |
| 420 | struct stat *st_addr); | ||
| 421 | static Lisp_Object Qdefault_directory; | 445 | static Lisp_Object Qdefault_directory; |
| 422 | 446 | ||
| 423 | static Lisp_Object | 447 | static Lisp_Object |
| @@ -425,6 +449,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 425 | Lisp_Object predicate) | 449 | Lisp_Object predicate) |
| 426 | { | 450 | { |
| 427 | DIR *d; | 451 | DIR *d; |
| 452 | int fd; | ||
| 428 | ptrdiff_t bestmatchsize = 0; | 453 | ptrdiff_t bestmatchsize = 0; |
| 429 | int matchcount = 0; | 454 | int matchcount = 0; |
| 430 | /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. | 455 | /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. |
| @@ -459,16 +484,14 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 459 | on the encoded file name. */ | 484 | on the encoded file name. */ |
| 460 | encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file; | 485 | encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file; |
| 461 | 486 | ||
| 462 | encoded_dir = ENCODE_FILE (dirname); | 487 | encoded_dir = ENCODE_FILE (Fdirectory_file_name (dirname)); |
| 463 | 488 | ||
| 464 | block_input (); | 489 | d = open_directory (SSDATA (encoded_dir), &fd); |
| 465 | d = opendir (SSDATA (Fdirectory_file_name (encoded_dir))); | ||
| 466 | unblock_input (); | ||
| 467 | if (!d) | 490 | if (!d) |
| 468 | report_file_error ("Opening directory", Fcons (dirname, Qnil)); | 491 | report_file_error ("Opening directory", Fcons (dirname, Qnil)); |
| 469 | 492 | ||
| 470 | record_unwind_protect (directory_files_internal_unwind, | 493 | record_unwind_protect (directory_files_internal_unwind, |
| 471 | make_save_value (d, 0)); | 494 | make_save_pointer (d)); |
| 472 | 495 | ||
| 473 | /* Loop reading blocks */ | 496 | /* Loop reading blocks */ |
| 474 | /* (att3b compiler bug requires do a null comparison this way) */ | 497 | /* (att3b compiler bug requires do a null comparison this way) */ |
| @@ -480,27 +503,25 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 480 | 503 | ||
| 481 | errno = 0; | 504 | errno = 0; |
| 482 | dp = readdir (d); | 505 | dp = readdir (d); |
| 483 | if (dp == NULL && (0 | 506 | if (!dp) |
| 484 | # ifdef EAGAIN | 507 | { |
| 485 | || errno == EAGAIN | 508 | if (errno == EAGAIN || errno == EINTR) |
| 486 | # endif | 509 | { |
| 487 | # ifdef EINTR | 510 | QUIT; |
| 488 | || errno == EINTR | 511 | continue; |
| 489 | # endif | 512 | } |
| 490 | )) | 513 | break; |
| 491 | { QUIT; continue; } | 514 | } |
| 492 | |||
| 493 | if (!dp) break; | ||
| 494 | 515 | ||
| 495 | len = dirent_namelen (dp); | 516 | len = dirent_namelen (dp); |
| 496 | 517 | ||
| 497 | QUIT; | 518 | QUIT; |
| 498 | if (len < SCHARS (encoded_file) | 519 | if (len < SCHARS (encoded_file) |
| 499 | || 0 <= scmp (dp->d_name, SSDATA (encoded_file), | 520 | || scmp (dp->d_name, SSDATA (encoded_file), |
| 500 | SCHARS (encoded_file))) | 521 | SCHARS (encoded_file)) >= 0) |
| 501 | continue; | 522 | continue; |
| 502 | 523 | ||
| 503 | if (file_name_completion_stat (encoded_dir, dp, &st) < 0) | 524 | if (file_name_completion_stat (fd, dp, &st) < 0) |
| 504 | continue; | 525 | continue; |
| 505 | 526 | ||
| 506 | directoryp = S_ISDIR (st.st_mode) != 0; | 527 | directoryp = S_ISDIR (st.st_mode) != 0; |
| @@ -559,7 +580,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 559 | if (skip < 0) | 580 | if (skip < 0) |
| 560 | continue; | 581 | continue; |
| 561 | 582 | ||
| 562 | if (0 <= scmp (dp->d_name + skip, p1, elt_len)) | 583 | if (scmp (dp->d_name + skip, p1, elt_len) >= 0) |
| 563 | continue; | 584 | continue; |
| 564 | break; | 585 | break; |
| 565 | } | 586 | } |
| @@ -581,9 +602,8 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 581 | skip = len - SCHARS (elt); | 602 | skip = len - SCHARS (elt); |
| 582 | if (skip < 0) continue; | 603 | if (skip < 0) continue; |
| 583 | 604 | ||
| 584 | if (0 <= scmp (dp->d_name + skip, | 605 | if (scmp (dp->d_name + skip, SSDATA (elt), SCHARS (elt)) |
| 585 | SSDATA (elt), | 606 | >= 0) |
| 586 | SCHARS (elt))) | ||
| 587 | continue; | 607 | continue; |
| 588 | break; | 608 | break; |
| 589 | } | 609 | } |
| @@ -677,10 +697,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, | |||
| 677 | name, zero, | 697 | name, zero, |
| 678 | make_number (compare), | 698 | make_number (compare), |
| 679 | completion_ignore_case ? Qt : Qnil); | 699 | completion_ignore_case ? Qt : Qnil); |
| 680 | ptrdiff_t matchsize | 700 | ptrdiff_t matchsize = EQ (cmp, Qt) ? compare : eabs (XINT (cmp)) - 1; |
| 681 | = (EQ (cmp, Qt) ? compare | ||
| 682 | : XINT (cmp) < 0 ? - XINT (cmp) - 1 | ||
| 683 | : XINT (cmp) - 1); | ||
| 684 | 701 | ||
| 685 | if (completion_ignore_case) | 702 | if (completion_ignore_case) |
| 686 | { | 703 | { |
| @@ -780,14 +797,9 @@ scmp (const char *s1, const char *s2, ptrdiff_t len) | |||
| 780 | } | 797 | } |
| 781 | 798 | ||
| 782 | static int | 799 | static int |
| 783 | file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | 800 | file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr) |
| 784 | struct stat *st_addr) | ||
| 785 | { | 801 | { |
| 786 | ptrdiff_t len = dirent_namelen (dp); | ||
| 787 | ptrdiff_t pos = SCHARS (dirname); | ||
| 788 | int value; | 802 | int value; |
| 789 | USE_SAFE_ALLOCA; | ||
| 790 | char *fullname = SAFE_ALLOCA (len + pos + 2); | ||
| 791 | 803 | ||
| 792 | #ifdef MSDOS | 804 | #ifdef MSDOS |
| 793 | /* Some fields of struct stat are *very* expensive to compute on MS-DOS, | 805 | /* Some fields of struct stat are *very* expensive to compute on MS-DOS, |
| @@ -800,23 +812,15 @@ file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, | |||
| 800 | _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; | 812 | _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; |
| 801 | #endif /* MSDOS */ | 813 | #endif /* MSDOS */ |
| 802 | 814 | ||
| 803 | memcpy (fullname, SDATA (dirname), pos); | ||
| 804 | if (!IS_DIRECTORY_SEP (fullname[pos - 1])) | ||
| 805 | fullname[pos++] = DIRECTORY_SEP; | ||
| 806 | |||
| 807 | memcpy (fullname + pos, dp->d_name, len); | ||
| 808 | fullname[pos + len] = 0; | ||
| 809 | |||
| 810 | /* We want to return success if a link points to a nonexistent file, | 815 | /* We want to return success if a link points to a nonexistent file, |
| 811 | but we want to return the status for what the link points to, | 816 | but we want to return the status for what the link points to, |
| 812 | in case it is a directory. */ | 817 | in case it is a directory. */ |
| 813 | value = lstat (fullname, st_addr); | 818 | value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW); |
| 814 | if (value == 0 && S_ISLNK (st_addr->st_mode)) | 819 | if (value == 0 && S_ISLNK (st_addr->st_mode)) |
| 815 | stat (fullname, st_addr); | 820 | fstatat (fd, dp->d_name, st_addr, 0); |
| 816 | #ifdef MSDOS | 821 | #ifdef MSDOS |
| 817 | _djstat_flags = save_djstat_flags; | 822 | _djstat_flags = save_djstat_flags; |
| 818 | #endif /* MSDOS */ | 823 | #endif /* MSDOS */ |
| 819 | SAFE_FREE (); | ||
| 820 | return value; | 824 | return value; |
| 821 | } | 825 | } |
| 822 | 826 | ||
| @@ -826,7 +830,7 @@ stat_uname (struct stat *st) | |||
| 826 | #ifdef WINDOWSNT | 830 | #ifdef WINDOWSNT |
| 827 | return st->st_uname; | 831 | return st->st_uname; |
| 828 | #else | 832 | #else |
| 829 | struct passwd *pw = (struct passwd *) getpwuid (st->st_uid); | 833 | struct passwd *pw = getpwuid (st->st_uid); |
| 830 | 834 | ||
| 831 | if (pw) | 835 | if (pw) |
| 832 | return pw->pw_name; | 836 | return pw->pw_name; |
| @@ -841,7 +845,7 @@ stat_gname (struct stat *st) | |||
| 841 | #ifdef WINDOWSNT | 845 | #ifdef WINDOWSNT |
| 842 | return st->st_gname; | 846 | return st->st_gname; |
| 843 | #else | 847 | #else |
| 844 | struct group *gr = (struct group *) getgrgid (st->st_gid); | 848 | struct group *gr = getgrgid (st->st_gid); |
| 845 | 849 | ||
| 846 | if (gr) | 850 | if (gr) |
| 847 | return gr->gr_name; | 851 | return gr->gr_name; |
| @@ -875,7 +879,7 @@ Elements of the attribute list are: | |||
| 875 | 7. Size in bytes. | 879 | 7. Size in bytes. |
| 876 | This is a floating point number if the size is too large for an integer. | 880 | This is a floating point number if the size is too large for an integer. |
| 877 | 8. File modes, as a string of ten letters or dashes as in ls -l. | 881 | 8. File modes, as a string of ten letters or dashes as in ls -l. |
| 878 | 9. t if file's gid would change if file were deleted and recreated. | 882 | 9. An unspecified value, present only for backward compatibility. |
| 879 | 10. inode number. If it is larger than what an Emacs integer can hold, | 883 | 10. inode number. If it is larger than what an Emacs integer can hold, |
| 880 | this is of the form (HIGH . LOW): first the high bits, then the low 16 bits. | 884 | this is of the form (HIGH . LOW): first the high bits, then the low 16 bits. |
| 881 | If even HIGH is too large for an Emacs integer, this is instead of the form | 885 | If even HIGH is too large for an Emacs integer, this is instead of the form |
| @@ -894,21 +898,8 @@ On some FAT-based filesystems, only the date of last access is recorded, | |||
| 894 | so last access time will always be midnight of that day. */) | 898 | so last access time will always be midnight of that day. */) |
| 895 | (Lisp_Object filename, Lisp_Object id_format) | 899 | (Lisp_Object filename, Lisp_Object id_format) |
| 896 | { | 900 | { |
| 897 | Lisp_Object values[12]; | ||
| 898 | Lisp_Object encoded; | 901 | Lisp_Object encoded; |
| 899 | struct stat s; | ||
| 900 | #ifdef BSD4_2 | ||
| 901 | Lisp_Object dirname; | ||
| 902 | struct stat sdir; | ||
| 903 | #endif /* BSD4_2 */ | ||
| 904 | |||
| 905 | /* An array to hold the mode string generated by filemodestring, | ||
| 906 | including its terminating space and null byte. */ | ||
| 907 | char modes[sizeof "-rwxr-xr-x "]; | ||
| 908 | |||
| 909 | Lisp_Object handler; | 902 | Lisp_Object handler; |
| 910 | struct gcpro gcpro1; | ||
| 911 | char *uname = NULL, *gname = NULL; | ||
| 912 | 903 | ||
| 913 | filename = Fexpand_file_name (filename, Qnil); | 904 | filename = Fexpand_file_name (filename, Qnil); |
| 914 | 905 | ||
| @@ -924,14 +915,41 @@ so last access time will always be midnight of that day. */) | |||
| 924 | return call3 (handler, Qfile_attributes, filename, id_format); | 915 | return call3 (handler, Qfile_attributes, filename, id_format); |
| 925 | } | 916 | } |
| 926 | 917 | ||
| 927 | GCPRO1 (filename); | ||
| 928 | encoded = ENCODE_FILE (filename); | 918 | encoded = ENCODE_FILE (filename); |
| 929 | UNGCPRO; | 919 | return file_attributes (AT_FDCWD, SSDATA (encoded), id_format); |
| 920 | } | ||
| 921 | |||
| 922 | static Lisp_Object | ||
| 923 | file_attributes (int fd, char const *name, Lisp_Object id_format) | ||
| 924 | { | ||
| 925 | Lisp_Object values[12]; | ||
| 926 | struct stat s; | ||
| 927 | int lstat_result; | ||
| 928 | |||
| 929 | /* An array to hold the mode string generated by filemodestring, | ||
| 930 | including its terminating space and null byte. */ | ||
| 931 | char modes[sizeof "-rwxr-xr-x "]; | ||
| 932 | |||
| 933 | char *uname = NULL, *gname = NULL; | ||
| 934 | |||
| 935 | #ifdef WINDOWSNT | ||
| 936 | /* We usually don't request accurate owner and group info, because | ||
| 937 | it can be very expensive on Windows to get that, and most callers | ||
| 938 | of 'lstat' don't need that. But here we do want that information | ||
| 939 | to be accurate. */ | ||
| 940 | w32_stat_get_owner_group = 1; | ||
| 941 | #endif | ||
| 942 | |||
| 943 | lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW); | ||
| 944 | |||
| 945 | #ifdef WINDOWSNT | ||
| 946 | w32_stat_get_owner_group = 0; | ||
| 947 | #endif | ||
| 930 | 948 | ||
| 931 | if (lstat (SSDATA (encoded), &s) < 0) | 949 | if (lstat_result < 0) |
| 932 | return Qnil; | 950 | return Qnil; |
| 933 | 951 | ||
| 934 | values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename) | 952 | values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name) |
| 935 | : S_ISDIR (s.st_mode) ? Qt : Qnil); | 953 | : S_ISDIR (s.st_mode) ? Qt : Qnil); |
| 936 | values[1] = make_number (s.st_nlink); | 954 | values[1] = make_number (s.st_nlink); |
| 937 | 955 | ||
| @@ -965,17 +983,7 @@ so last access time will always be midnight of that day. */) | |||
| 965 | 983 | ||
| 966 | filemodestring (&s, modes); | 984 | filemodestring (&s, modes); |
| 967 | values[8] = make_string (modes, 10); | 985 | values[8] = make_string (modes, 10); |
| 968 | #ifdef BSD4_2 /* file gid will be dir gid */ | 986 | values[9] = Qt; |
| 969 | dirname = Ffile_name_directory (filename); | ||
| 970 | if (! NILP (dirname)) | ||
| 971 | encoded = ENCODE_FILE (dirname); | ||
| 972 | if (! NILP (dirname) && stat (SDATA (encoded), &sdir) == 0) | ||
| 973 | values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil; | ||
| 974 | else /* if we can't tell, assume worst */ | ||
| 975 | values[9] = Qt; | ||
| 976 | #else /* file gid will be egid */ | ||
| 977 | values[9] = (s.st_gid != getegid ()) ? Qt : Qnil; | ||
| 978 | #endif /* not BSD4_2 */ | ||
| 979 | values[10] = INTEGER_TO_CONS (s.st_ino); | 987 | values[10] = INTEGER_TO_CONS (s.st_ino); |
| 980 | values[11] = INTEGER_TO_CONS (s.st_dev); | 988 | values[11] = INTEGER_TO_CONS (s.st_dev); |
| 981 | 989 | ||