changeset 13616:acc972b5da60

fcntl-h, etc.: prefer O_SEARCH to O_RDONLY when applicable POSIX 2008 specifies a new 'open' flag O_SEARCH, which can be used when one needs search access to a directory but not read access. On systems where it is available, it works in some cases where O_RDONLY does not, namely on directories that are searchable but not readable, and which need only to be searchable. If O_SEARCH is not available, fall back to the traditional method of using O_RDONLY. * lib/fcntl.in.h (O_SEARCH): #define to O_RDONLY if not defined. * lib/chdir-long.c (cdb_advance_fd): Use O_SEARCH, not O_RDONLY, when opening a directory that needs only to be searchable. * lib/chdir-safer.c (chdir_no_follow): Likewise. * lib/fts.c (diropen, fts_open, fd_ring_check): Likewise. * lib/openat-proc.c (openat_proc_name): Likewise. * lib/openat.c (openat_needs_fchdir): Likewise. * lib/save-cwd.c (save_cwd): Likewise. * lib/savewd.c (savewd_save, savewd_chdir): Likewise.
author Paul Eggert <eggert@cs.ucla.edu>
date Wed, 01 Sep 2010 13:45:53 -0700
parents 48942856d1d0
children 7ec957f3df57
files ChangeLog lib/chdir-long.c lib/chdir-safer.c lib/fcntl.in.h lib/fts.c lib/openat-proc.c lib/openat.c lib/save-cwd.c lib/savewd.c
diffstat 9 files changed, 42 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2010-09-01  Paul Eggert  <eggert@cs.ucla.edu>
+
+	fcntl-h, etc.: prefer O_SEARCH to O_RDONLY when applicable
+
+	POSIX 2008 specifies a new 'open' flag O_SEARCH, which can be used
+	when one needs search access to a directory but not read access.
+	On systems where it is available, it works in some cases where
+	O_RDONLY does not, namely on directories that are searchable but
+	not readable, and which need only to be searchable.  If O_SEARCH
+	is not available, fall back to the traditional method of using
+	O_RDONLY.
+
+	* lib/fcntl.in.h (O_SEARCH): #define to O_RDONLY if not defined.
+	* lib/chdir-long.c (cdb_advance_fd): Use O_SEARCH, not O_RDONLY,
+	when opening a directory that needs only to be searchable.
+	* lib/chdir-safer.c (chdir_no_follow): Likewise.
+	* lib/fts.c (diropen, fts_open, fd_ring_check): Likewise.
+	* lib/openat-proc.c (openat_proc_name): Likewise.
+	* lib/openat.c (openat_needs_fchdir): Likewise.
+	* lib/save-cwd.c (save_cwd): Likewise.
+	* lib/savewd.c (savewd_save, savewd_chdir): Likewise.
+
 2010-08-28  Bruno Haible  <bruno@clisp.org>
 
 	New module 'host-cpu-c-abi'.
--- a/lib/chdir-long.c
+++ b/lib/chdir-long.c
@@ -72,7 +72,7 @@
 cdb_advance_fd (struct cd_buf *cdb, char const *dir)
 {
   int new_fd = openat (cdb->fd, dir,
-                       O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
+                       O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
   if (new_fd < 0)
     return -1;
 
--- a/lib/chdir-safer.c
+++ b/lib/chdir-safer.c
@@ -34,16 +34,19 @@
 #endif
 
 /* Like chdir, but fail if DIR is a symbolic link to a directory (or
-   similar funny business), or if DIR is not readable.  This avoids a
-   minor race condition between when a directory is created or statted
-   and when the process chdirs into it.  */
+   similar funny business).  This avoids a minor race condition
+   between when a directory is created or statted and when the process
+   chdirs into it.
+
+   On older systems lacking full support for O_SEARCH, this function
+   can also fail if DIR is not readable.  */
 int
 chdir_no_follow (char const *dir)
 {
   int result = 0;
   int saved_errno;
   int fd = open (dir,
-                 O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK);
+                 O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK);
   if (fd < 0)
     return -1;
 
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -210,6 +210,10 @@
 # define O_RSYNC 0
 #endif
 
+#ifndef O_SEARCH
+# define O_SEARCH O_RDONLY /* This is often close enough in older systems.  */
+#endif
+
 #ifndef O_SYNC
 # define O_SYNC 0
 #endif
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -347,7 +347,7 @@
 internal_function
 diropen (FTS const *sp, char const *dir)
 {
-  int open_flags = (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+  int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
                     | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
 
   int fd = (ISSET (FTS_CWDFD)
@@ -405,7 +405,7 @@
                early, doing it here saves us the trouble of ensuring
                later (where it'd be messier) that "." can in fact
                be opened.  If not, revert to FTS_NOCHDIR mode.  */
-            int fd = open (".", O_RDONLY);
+            int fd = open (".", O_SEARCH);
             if (fd < 0)
               {
                 /* Even if `.' is unreadable, don't revert to FTS_NOCHDIR mode
@@ -1646,7 +1646,7 @@
       int fd = i_ring_pop (&fd_w);
       if (0 <= fd)
         {
-          int parent_fd = openat (cwd_fd, "..", O_RDONLY);
+          int parent_fd = openat (cwd_fd, "..", O_SEARCH);
           if (parent_fd < 0)
             {
               // Warn?
--- a/lib/openat-proc.c
+++ b/lib/openat-proc.c
@@ -75,7 +75,7 @@
          problem is exhibited on code that built on Solaris 8 and
          running on Solaris 10.  */
 
-      int proc_self_fd = open ("/proc/self/fd", O_RDONLY);
+      int proc_self_fd = open ("/proc/self/fd", O_SEARCH);
       if (proc_self_fd < 0)
         proc_status = -1;
       else
--- a/lib/openat.c
+++ b/lib/openat.c
@@ -244,7 +244,7 @@
 openat_needs_fchdir (void)
 {
   bool needs_fchdir = true;
-  int fd = open ("/", O_RDONLY);
+  int fd = open ("/", O_SEARCH);
 
   if (0 <= fd)
     {
--- a/lib/save-cwd.c
+++ b/lib/save-cwd.c
@@ -76,7 +76,7 @@
 {
   cwd->name = NULL;
 
-  cwd->desc = open (".", O_RDONLY);
+  cwd->desc = open (".", O_SEARCH);
   if (!GNULIB_FCNTL_SAFER)
     cwd->desc = fd_safer (cwd->desc);
   if (cwd->desc < 0)
--- a/lib/savewd.c
+++ b/lib/savewd.c
@@ -45,7 +45,7 @@
     case INITIAL_STATE:
       /* Save the working directory, or prepare to fall back if possible.  */
       {
-        int fd = open_safer (".", O_RDONLY);
+        int fd = open_safer (".", O_SEARCH);
         if (0 <= fd)
           {
             wd->state = FD_STATE;
@@ -105,7 +105,7 @@
       || (options & (HAVE_WORKING_O_NOFOLLOW ? SAVEWD_CHDIR_NOFOLLOW : 0)))
     {
       fd = open (dir,
-                 (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+                 (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
                   | (options & SAVEWD_CHDIR_NOFOLLOW ? O_NOFOLLOW : 0)));
 
       if (open_result)