aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog31
-rw-r--r--src/conf_post.h4
-rw-r--r--src/dired.c120
-rw-r--r--src/fileio.c40
-rw-r--r--src/filelock.c18
-rw-r--r--src/lisp.h3
-rw-r--r--src/sysdep.c18
-rw-r--r--src/w32.c60
8 files changed, 180 insertions, 114 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 5c13e35306d..2156d7f19c9 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,34 @@
12013-02-01 Paul Eggert <eggert@cs.ucla.edu>
2
3 Use fdopendir, fstatat and readlinkat, for efficiency (Bug#13539).
4 * conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): Remove.
5 * dired.c: Include <fcntl.h>.
6 (open_directory): New function, which uses open and fdopendir
7 rather than opendir. DOS_NT platforms still use opendir, though.
8 (directory_files_internal, file_name_completion): Use it.
9 (file_attributes): New function, with most of the old Ffile_attributes.
10 (directory_files_internal, Ffile_attributes): Use it.
11 (file_attributes, file_name_completion_stat): First arg is now fd,
12 not dir name. All uses changed. Use fstatat rather than lstat +
13 stat.
14 (file_attributes): Use emacs_readlinkat rather than Ffile_symlink_p.
15 * fileio.c: Include <allocator.h>, <careadlinkat.h>.
16 (emacs_readlinkat): New function, with much of the old
17 Ffile_symlink_p, but with an fd argument for speed.
18 It uses readlinkat rather than careadlinkatcwd, so that it
19 need not assume the working directory.
20 (Ffile_symlink_p): Use it.
21 * filelock.c (current_lock_owner): Use emacs_readlinkat
22 rather than emacs_readlink.
23 * lisp.h (emacs_readlinkat): New decl.
24 (READLINK_BUFSIZE, emacs_readlink): Remove.
25 * sysdep.c: Do not include <allocator.h>, <careadlinkat.h>.
26 (emacs_norealloc_allocator, emacs_readlink): Remove.
27 This stuff is moved to fileio.c.
28 * w32.c (fstatat, readlinkat): New functions.
29 (careadlinkat): Don't check that fd == AT_FDCWD.
30 (careadlinkatcwd): Remove; no longer needed.
31
12013-01-31 Glenn Morris <rgm@gnu.org> 322013-01-31 Glenn Morris <rgm@gnu.org>
2 33
3 * fileio.c (choose_write_coding_system): Make it callable from Lisp. 34 * fileio.c (choose_write_coding_system): Make it callable from Lisp.
diff --git a/src/conf_post.h b/src/conf_post.h
index cd1e35bea7a..6c9747a436c 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -182,10 +182,6 @@ extern void _DebPrint (const char *fmt, ...);
182#endif 182#endif
183#endif 183#endif
184 184
185/* Tell gnulib to omit support for openat-related functions having a
186 first argument other than AT_FDCWD. */
187#define GNULIB_SUPPORT_ONLY_AT_FDCWD
188
189#include <string.h> 185#include <string.h>
190#include <stdlib.h> 186#include <stdlib.h>
191 187
diff --git a/src/dired.c b/src/dired.c
index a4c8621e9c0..ed0571fe9fe 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30#include <grp.h> 30#include <grp.h>
31 31
32#include <errno.h> 32#include <errno.h>
33#include <fcntl.h>
33#include <unistd.h> 34#include <unistd.h>
34 35
35#include <dirent.h> 36#include <dirent.h>
@@ -54,6 +55,7 @@ static Lisp_Object Qfile_attributes;
54static Lisp_Object Qfile_attributes_lessp; 55static Lisp_Object Qfile_attributes_lessp;
55 56
56static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); 57static ptrdiff_t scmp (const char *, const char *, ptrdiff_t);
58static Lisp_Object file_attributes (int, char const *, Lisp_Object);
57 59
58/* Return the number of bytes in DP's name. */ 60/* Return the number of bytes in DP's name. */
59static ptrdiff_t 61static ptrdiff_t
@@ -66,6 +68,44 @@ dirent_namelen (struct dirent *dp)
66#endif 68#endif
67} 69}
68 70
71static DIR *
72open_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
69#ifdef WINDOWSNT 109#ifdef WINDOWSNT
70Lisp_Object 110Lisp_Object
71directory_files_internal_w32_unwind (Lisp_Object arg) 111directory_files_internal_w32_unwind (Lisp_Object arg)
@@ -96,6 +136,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
96 Lisp_Object id_format) 136 Lisp_Object id_format)
97{ 137{
98 DIR *d; 138 DIR *d;
139 int fd;
99 ptrdiff_t directory_nbytes; 140 ptrdiff_t directory_nbytes;
100 Lisp_Object list, dirfilename, encoded_directory; 141 Lisp_Object list, dirfilename, encoded_directory;
101 struct re_pattern_buffer *bufp = NULL; 142 struct re_pattern_buffer *bufp = NULL;
@@ -142,9 +183,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
142 /* 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
143 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! */
144 185
145 block_input (); 186 d = open_directory (SSDATA (dirfilename), &fd);
146 d = opendir (SSDATA (dirfilename));
147 unblock_input ();
148 if (d == NULL) 187 if (d == NULL)
149 report_file_error ("Opening directory", Fcons (directory, Qnil)); 188 report_file_error ("Opening directory", Fcons (directory, Qnil));
150 189
@@ -259,20 +298,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
259 298
260 if (attrs) 299 if (attrs)
261 { 300 {
262 /* Construct an expanded filename for the directory entry. 301 Lisp_Object fileattrs
263 Use the decoded names for input to Ffile_attributes. */ 302 = file_attributes (fd, dp->d_name, id_format);
264 Lisp_Object decoded_fullname, fileattrs;
265 struct gcpro gcpro1, gcpro2;
266
267 decoded_fullname = fileattrs = Qnil;
268 GCPRO2 (decoded_fullname, fileattrs);
269
270 /* Both Fexpand_file_name and Ffile_attributes can GC. */
271 decoded_fullname = Fexpand_file_name (name, directory);
272 fileattrs = Ffile_attributes (decoded_fullname, id_format);
273
274 list = Fcons (Fcons (finalname, fileattrs), list); 303 list = Fcons (Fcons (finalname, fileattrs), list);
275 UNGCPRO;
276 } 304 }
277 else 305 else
278 list = Fcons (finalname, list); 306 list = Fcons (finalname, list);
@@ -413,8 +441,7 @@ These are all file names in directory DIRECTORY which begin with FILE. */)
413 return file_name_completion (file, directory, 1, Qnil); 441 return file_name_completion (file, directory, 1, Qnil);
414} 442}
415 443
416static int file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, 444static int file_name_completion_stat (int, struct dirent *, struct stat *);
417 struct stat *st_addr);
418static Lisp_Object Qdefault_directory; 445static Lisp_Object Qdefault_directory;
419 446
420static Lisp_Object 447static Lisp_Object
@@ -422,6 +449,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
422 Lisp_Object predicate) 449 Lisp_Object predicate)
423{ 450{
424 DIR *d; 451 DIR *d;
452 int fd;
425 ptrdiff_t bestmatchsize = 0; 453 ptrdiff_t bestmatchsize = 0;
426 int matchcount = 0; 454 int matchcount = 0;
427 /* 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.
@@ -458,9 +486,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
458 486
459 encoded_dir = ENCODE_FILE (dirname); 487 encoded_dir = ENCODE_FILE (dirname);
460 488
461 block_input (); 489 d = open_directory (SSDATA (Fdirectory_file_name (encoded_dir)), &fd);
462 d = opendir (SSDATA (Fdirectory_file_name (encoded_dir)));
463 unblock_input ();
464 if (!d) 490 if (!d)
465 report_file_error ("Opening directory", Fcons (dirname, Qnil)); 491 report_file_error ("Opening directory", Fcons (dirname, Qnil));
466 492
@@ -495,7 +521,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
495 SCHARS (encoded_file))) 521 SCHARS (encoded_file)))
496 continue; 522 continue;
497 523
498 if (file_name_completion_stat (encoded_dir, dp, &st) < 0) 524 if (file_name_completion_stat (fd, dp, &st) < 0)
499 continue; 525 continue;
500 526
501 directoryp = S_ISDIR (st.st_mode) != 0; 527 directoryp = S_ISDIR (st.st_mode) != 0;
@@ -772,14 +798,9 @@ scmp (const char *s1, const char *s2, ptrdiff_t len)
772} 798}
773 799
774static int 800static int
775file_name_completion_stat (Lisp_Object dirname, struct dirent *dp, 801file_name_completion_stat (int fd, struct dirent *dp, struct stat *st_addr)
776 struct stat *st_addr)
777{ 802{
778 ptrdiff_t len = dirent_namelen (dp);
779 ptrdiff_t pos = SCHARS (dirname);
780 int value; 803 int value;
781 USE_SAFE_ALLOCA;
782 char *fullname = SAFE_ALLOCA (len + pos + 2);
783 804
784#ifdef MSDOS 805#ifdef MSDOS
785 /* Some fields of struct stat are *very* expensive to compute on MS-DOS, 806 /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
@@ -792,23 +813,15 @@ file_name_completion_stat (Lisp_Object dirname, struct dirent *dp,
792 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; 813 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
793#endif /* MSDOS */ 814#endif /* MSDOS */
794 815
795 memcpy (fullname, SDATA (dirname), pos);
796 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
797 fullname[pos++] = DIRECTORY_SEP;
798
799 memcpy (fullname + pos, dp->d_name, len);
800 fullname[pos + len] = 0;
801
802 /* We want to return success if a link points to a nonexistent file, 816 /* We want to return success if a link points to a nonexistent file,
803 but we want to return the status for what the link points to, 817 but we want to return the status for what the link points to,
804 in case it is a directory. */ 818 in case it is a directory. */
805 value = lstat (fullname, st_addr); 819 value = fstatat (fd, dp->d_name, st_addr, AT_SYMLINK_NOFOLLOW);
806 if (value == 0 && S_ISLNK (st_addr->st_mode)) 820 if (value == 0 && S_ISLNK (st_addr->st_mode))
807 stat (fullname, st_addr); 821 fstatat (fd, dp->d_name, st_addr, 0);
808#ifdef MSDOS 822#ifdef MSDOS
809 _djstat_flags = save_djstat_flags; 823 _djstat_flags = save_djstat_flags;
810#endif /* MSDOS */ 824#endif /* MSDOS */
811 SAFE_FREE ();
812 return value; 825 return value;
813} 826}
814 827
@@ -886,18 +899,8 @@ On some FAT-based filesystems, only the date of last access is recorded,
886so last access time will always be midnight of that day. */) 899so last access time will always be midnight of that day. */)
887 (Lisp_Object filename, Lisp_Object id_format) 900 (Lisp_Object filename, Lisp_Object id_format)
888{ 901{
889 Lisp_Object values[12];
890 Lisp_Object encoded; 902 Lisp_Object encoded;
891 struct stat s;
892 int lstat_result;
893
894 /* An array to hold the mode string generated by filemodestring,
895 including its terminating space and null byte. */
896 char modes[sizeof "-rwxr-xr-x "];
897
898 Lisp_Object handler; 903 Lisp_Object handler;
899 struct gcpro gcpro1;
900 char *uname = NULL, *gname = NULL;
901 904
902 filename = Fexpand_file_name (filename, Qnil); 905 filename = Fexpand_file_name (filename, Qnil);
903 906
@@ -913,9 +916,22 @@ so last access time will always be midnight of that day. */)
913 return call3 (handler, Qfile_attributes, filename, id_format); 916 return call3 (handler, Qfile_attributes, filename, id_format);
914 } 917 }
915 918
916 GCPRO1 (filename);
917 encoded = ENCODE_FILE (filename); 919 encoded = ENCODE_FILE (filename);
918 UNGCPRO; 920 return file_attributes (AT_FDCWD, SSDATA (encoded), id_format);
921}
922
923static Lisp_Object
924file_attributes (int fd, char const *name, Lisp_Object id_format)
925{
926 Lisp_Object values[12];
927 struct stat s;
928 int lstat_result;
929
930 /* An array to hold the mode string generated by filemodestring,
931 including its terminating space and null byte. */
932 char modes[sizeof "-rwxr-xr-x "];
933
934 char *uname = NULL, *gname = NULL;
919 935
920#ifdef WINDOWSNT 936#ifdef WINDOWSNT
921 /* We usually don't request accurate owner and group info, because 937 /* We usually don't request accurate owner and group info, because
@@ -925,7 +941,7 @@ so last access time will always be midnight of that day. */)
925 w32_stat_get_owner_group = 1; 941 w32_stat_get_owner_group = 1;
926#endif 942#endif
927 943
928 lstat_result = lstat (SSDATA (encoded), &s); 944 lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW);
929 945
930#ifdef WINDOWSNT 946#ifdef WINDOWSNT
931 w32_stat_get_owner_group = 0; 947 w32_stat_get_owner_group = 0;
@@ -934,7 +950,7 @@ so last access time will always be midnight of that day. */)
934 if (lstat_result < 0) 950 if (lstat_result < 0)
935 return Qnil; 951 return Qnil;
936 952
937 values[0] = (S_ISLNK (s.st_mode) ? Ffile_symlink_p (filename) 953 values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name)
938 : S_ISDIR (s.st_mode) ? Qt : Qnil); 954 : S_ISDIR (s.st_mode) ? Qt : Qnil);
939 values[1] = make_number (s.st_nlink); 955 values[1] = make_number (s.st_nlink);
940 956
diff --git a/src/fileio.c b/src/fileio.c
index cd4bd4fa86e..a8218fcd797 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -82,6 +82,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
82#endif 82#endif
83 83
84#include "systime.h" 84#include "systime.h"
85#include <allocator.h>
86#include <careadlinkat.h>
85#include <stat-time.h> 87#include <stat-time.h>
86 88
87#ifdef HPUX 89#ifdef HPUX
@@ -2759,6 +2761,29 @@ If there is no error, returns nil. */)
2759 return Qnil; 2761 return Qnil;
2760} 2762}
2761 2763
2764/* Relative to directory FD, return the symbolic link value of FILENAME.
2765 On failure, return nil. */
2766Lisp_Object
2767emacs_readlinkat (int fd, char const *filename)
2768{
2769 static struct allocator const emacs_norealloc_allocator =
2770 { xmalloc, NULL, xfree, memory_full };
2771 Lisp_Object val;
2772 char readlink_buf[1024];
2773 char *buf = careadlinkat (fd, filename, readlink_buf, sizeof readlink_buf,
2774 &emacs_norealloc_allocator, readlinkat);
2775 if (!buf)
2776 return Qnil;
2777
2778 val = build_string (buf);
2779 if (buf[0] == '/' && strchr (buf, ':'))
2780 val = concat2 (build_string ("/:"), val);
2781 if (buf != readlink_buf)
2782 xfree (buf);
2783 val = DECODE_FILE (val);
2784 return val;
2785}
2786
2762DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, 2787DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
2763 doc: /* Return non-nil if file FILENAME is the name of a symbolic link. 2788 doc: /* Return non-nil if file FILENAME is the name of a symbolic link.
2764The value is the link target, as a string. 2789The value is the link target, as a string.
@@ -2769,9 +2794,6 @@ points to a nonexistent file. */)
2769 (Lisp_Object filename) 2794 (Lisp_Object filename)
2770{ 2795{
2771 Lisp_Object handler; 2796 Lisp_Object handler;
2772 char *buf;
2773 Lisp_Object val;
2774 char readlink_buf[READLINK_BUFSIZE];
2775 2797
2776 CHECK_STRING (filename); 2798 CHECK_STRING (filename);
2777 filename = Fexpand_file_name (filename, Qnil); 2799 filename = Fexpand_file_name (filename, Qnil);
@@ -2784,17 +2806,7 @@ points to a nonexistent file. */)
2784 2806
2785 filename = ENCODE_FILE (filename); 2807 filename = ENCODE_FILE (filename);
2786 2808
2787 buf = emacs_readlink (SSDATA (filename), readlink_buf); 2809 return emacs_readlinkat (AT_FDCWD, SSDATA (filename));
2788 if (! buf)
2789 return Qnil;
2790
2791 val = build_string (buf);
2792 if (buf[0] == '/' && strchr (buf, ':'))
2793 val = concat2 (build_string ("/:"), val);
2794 if (buf != readlink_buf)
2795 xfree (buf);
2796 val = DECODE_FILE (val);
2797 return val;
2798} 2810}
2799 2811
2800DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, 2812DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
diff --git a/src/filelock.c b/src/filelock.c
index f21240f8340..228fe98e8c7 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -390,12 +390,14 @@ current_lock_owner (lock_info_type *owner, char *lfname)
390 lock_info_type local_owner; 390 lock_info_type local_owner;
391 intmax_t n; 391 intmax_t n;
392 char *at, *dot, *colon; 392 char *at, *dot, *colon;
393 char readlink_buf[READLINK_BUFSIZE]; 393 Lisp_Object lfinfo_object = emacs_readlinkat (AT_FDCWD, lfname);
394 char *lfinfo = emacs_readlink (lfname, readlink_buf); 394 char *lfinfo;
395 struct gcpro gcpro1;
395 396
396 /* If nonexistent lock file, all is well; otherwise, got strange error. */ 397 /* If nonexistent lock file, all is well; otherwise, got strange error. */
397 if (!lfinfo) 398 if (NILP (lfinfo_object))
398 return errno == ENOENT ? 0 : -1; 399 return errno == ENOENT ? 0 : -1;
400 lfinfo = SSDATA (lfinfo_object);
399 401
400 /* Even if the caller doesn't want the owner info, we still have to 402 /* Even if the caller doesn't want the owner info, we still have to
401 read it to determine return value. */ 403 read it to determine return value. */
@@ -407,12 +409,9 @@ current_lock_owner (lock_info_type *owner, char *lfname)
407 at = strrchr (lfinfo, '@'); 409 at = strrchr (lfinfo, '@');
408 dot = strrchr (lfinfo, '.'); 410 dot = strrchr (lfinfo, '.');
409 if (!at || !dot) 411 if (!at || !dot)
410 { 412 return -1;
411 if (lfinfo != readlink_buf)
412 xfree (lfinfo);
413 return -1;
414 }
415 len = at - lfinfo; 413 len = at - lfinfo;
414 GCPRO1 (lfinfo_object);
416 owner->user = xmalloc (len + 1); 415 owner->user = xmalloc (len + 1);
417 memcpy (owner->user, lfinfo, len); 416 memcpy (owner->user, lfinfo, len);
418 owner->user[len] = 0; 417 owner->user[len] = 0;
@@ -445,8 +444,7 @@ current_lock_owner (lock_info_type *owner, char *lfname)
445 owner->host[len] = 0; 444 owner->host[len] = 0;
446 445
447 /* We're done looking at the link info. */ 446 /* We're done looking at the link info. */
448 if (lfinfo != readlink_buf) 447 UNGCPRO;
449 xfree (lfinfo);
450 448
451 /* On current host? */ 449 /* On current host? */
452 if (STRINGP (Fsystem_name ()) 450 if (STRINGP (Fsystem_name ())
diff --git a/src/lisp.h b/src/lisp.h
index 2e9088f1834..251b5e069ec 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3294,6 +3294,7 @@ extern Lisp_Object close_file_unwind (Lisp_Object);
3294extern Lisp_Object restore_point_unwind (Lisp_Object); 3294extern Lisp_Object restore_point_unwind (Lisp_Object);
3295extern _Noreturn void report_file_error (const char *, Lisp_Object); 3295extern _Noreturn void report_file_error (const char *, Lisp_Object);
3296extern bool internal_delete_file (Lisp_Object); 3296extern bool internal_delete_file (Lisp_Object);
3297extern Lisp_Object emacs_readlinkat (int, const char *);
3297extern bool file_directory_p (const char *); 3298extern bool file_directory_p (const char *);
3298extern bool file_accessible_directory_p (const char *); 3299extern bool file_accessible_directory_p (const char *);
3299extern void init_fileio (void); 3300extern void init_fileio (void);
@@ -3566,8 +3567,6 @@ extern int emacs_open (const char *, int, int);
3566extern int emacs_close (int); 3567extern int emacs_close (int);
3567extern ptrdiff_t emacs_read (int, char *, ptrdiff_t); 3568extern ptrdiff_t emacs_read (int, char *, ptrdiff_t);
3568extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t); 3569extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t);
3569enum { READLINK_BUFSIZE = 1024 };
3570extern char *emacs_readlink (const char *, char [READLINK_BUFSIZE]);
3571 3570
3572extern void unlock_all_files (void); 3571extern void unlock_all_files (void);
3573extern void lock_file (Lisp_Object); 3572extern void lock_file (Lisp_Object);
diff --git a/src/sysdep.c b/src/sysdep.c
index 0e9a6826005..57ca8265a65 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -30,9 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30#include <limits.h> 30#include <limits.h>
31#include <unistd.h> 31#include <unistd.h>
32 32
33#include <allocator.h>
34#include <c-ctype.h> 33#include <c-ctype.h>
35#include <careadlinkat.h>
36#include <ignore-value.h> 34#include <ignore-value.h>
37#include <utimens.h> 35#include <utimens.h>
38 36
@@ -2247,22 +2245,6 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
2247 2245
2248 return (bytes_written); 2246 return (bytes_written);
2249} 2247}
2250
2251static struct allocator const emacs_norealloc_allocator =
2252 { xmalloc, NULL, xfree, memory_full };
2253
2254/* Get the symbolic link value of FILENAME. Return a pointer to a
2255 NUL-terminated string. If readlink fails, return NULL and set
2256 errno. If the value fits in INITIAL_BUF, return INITIAL_BUF.
2257 Otherwise, allocate memory and return a pointer to that memory. If
2258 memory allocation fails, diagnose and fail without returning. If
2259 successful, store the length of the symbolic link into *LINKLEN. */
2260char *
2261emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
2262{
2263 return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
2264 &emacs_norealloc_allocator, careadlinkatcwd);
2265}
2266 2248
2267/* Return a struct timeval that is roughly equivalent to T. 2249/* Return a struct timeval that is roughly equivalent to T.
2268 Use the least timeval not less than T. 2250 Use the least timeval not less than T.
diff --git a/src/w32.c b/src/w32.c
index d0af53889e7..64f8a0335ac 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -4274,6 +4274,30 @@ lstat (const char * path, struct stat * buf)
4274 return stat_worker (path, buf, 0); 4274 return stat_worker (path, buf, 0);
4275} 4275}
4276 4276
4277int
4278fstatat (int fd, char const *name, struct stat *st, int flags)
4279{
4280 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4281 This is good enough for the current usage in Emacs, but is fragile.
4282
4283 FIXME: Add proper support for fdopendir, fstatatat, readlinkat.
4284 Gnulib does this and can serve as a model. */
4285 char fullname[MAX_PATH];
4286
4287 if (fd != AT_FDCWD)
4288 {
4289 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4290 < 0)
4291 {
4292 errno = ENAMETOOLONG;
4293 return -1;
4294 }
4295 name = fullname;
4296 }
4297
4298 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
4299}
4300
4277/* Provide fstat and utime as well as stat for consistent handling of 4301/* Provide fstat and utime as well as stat for consistent handling of
4278 file timestamps. */ 4302 file timestamps. */
4279int 4303int
@@ -4816,6 +4840,28 @@ readlink (const char *name, char *buf, size_t buf_size)
4816 return retval; 4840 return retval;
4817} 4841}
4818 4842
4843ssize_t
4844readlinkat (int fd, char const *name, char *buffer,
4845 size_t buffer_size)
4846{
4847 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4848 as in fstatat. FIXME: Add proper support for readlinkat. */
4849 char fullname[MAX_PATH];
4850
4851 if (fd != AT_FDCWD)
4852 {
4853 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4854 < 0)
4855 {
4856 errno = ENAMETOOLONG;
4857 return -1;
4858 }
4859 name = fullname;
4860 }
4861
4862 return readlink (name, buffer, buffer_size);
4863}
4864
4819/* If FILE is a symlink, return its target (stored in a static 4865/* If FILE is a symlink, return its target (stored in a static
4820 buffer); otherwise return FILE. 4866 buffer); otherwise return FILE.
4821 4867
@@ -5168,12 +5214,6 @@ careadlinkat (int fd, char const *filename,
5168 char linkname[MAX_PATH]; 5214 char linkname[MAX_PATH];
5169 ssize_t link_size; 5215 ssize_t link_size;
5170 5216
5171 if (fd != AT_FDCWD)
5172 {
5173 errno = EINVAL;
5174 return NULL;
5175 }
5176
5177 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); 5217 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
5178 5218
5179 if (link_size > 0) 5219 if (link_size > 0)
@@ -5191,14 +5231,6 @@ careadlinkat (int fd, char const *filename,
5191 return NULL; 5231 return NULL;
5192} 5232}
5193 5233
5194ssize_t
5195careadlinkatcwd (int fd, char const *filename, char *buffer,
5196 size_t buffer_size)
5197{
5198 (void) fd;
5199 return readlink (filename, buffer, buffer_size);
5200}
5201
5202 5234
5203/* Support for browsing other processes and their attributes. See 5235/* Support for browsing other processes and their attributes. See
5204 process.c for the Lisp bindings. */ 5236 process.c for the Lisp bindings. */