bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

coreutils patch for files that are writeable but not readable


From: Paul Eggert
Subject: coreutils patch for files that are writeable but not readable
Date: Mon, 09 Aug 2004 16:38:13 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

I installed the following patch to fix some inadequacies of coreutils
in cases where files (particularly, directories) are writeable but
not readable.

fchdir requires only execute (search) access, so it'd be nice if we
could somehow get a search-only file descriptor for a directory (in
particular, the current directory) even if we have only search
permission for that directory.  However, I don't know how to do this,
even on more-advanced systems like GNU/Hurd and solaris.

2004-08-09  Paul Eggert  <address@hidden>

        * lib/chown.c (rpl_chown): Work even if the file is writeable but not
        readable.  This could be improved further but it'd take some work.
        * lib/fts.c (diropen): New function.
        (fts_open, fts_read, fts_children, fts_safe_changedir):
        Use it, so that the code works even if the directory
        is writeable but not readable.  We'd like it to work even if
        the directory is merely executable, but I don't know how to do
        that portably.
        * src/shred.c (wipename): Work even if the directory is writeable
        and not readable.  Prefer write access, since this should work
        better with fdatasync.

Index: lib/chown.c
===================================================================
RCS file: /home/eggert/coreutils/cu/lib/chown.c,v
retrieving revision 1.10
diff -p -u -r1.10 chown.c
--- lib/chown.c 2 Aug 2004 22:41:37 -0000       1.10
+++ lib/chown.c 8 Aug 2004 06:19:30 -0000
@@ -68,10 +68,11 @@ rpl_chown (const char *file, uid_t uid, 
     /* Handle the case in which the system-supplied chown function
        does *not* follow symlinks.  Instead, it changes permissions
        on the symlink itself.  To work around that, we open the
-       file (but this can fail due to lack of read permission) and
+       file (but this can fail due to lack of read or write permission) and
        use fchown on the resulting descriptor.  */
     int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY);
-    if (fd == -1)
+    if (fd < 0
+       && (fd = open (file, O_WRONLY | O_NONBLOCK | O_NOCTTY)) < 0)
       return -1;
     if (fchown (fd, uid, gid))
       {
Index: lib/fts.c
===================================================================
RCS file: /home/eggert/coreutils/cu/lib/fts.c,v
retrieving revision 1.17
diff -p -u -r1.17 fts.c
--- lib/fts.c   4 Aug 2004 21:58:46 -0000       1.17
+++ lib/fts.c   9 Aug 2004 23:29:50 -0000
@@ -297,6 +297,20 @@ leave_dir (FTS *fts, FTSENT *ent)
     }
 }
 
+/* Open the directory DIR if possible, and return a file
+   descriptor.  Return -1 and set errno on failure.  It doesn't matter
+   whether the file descriptor has read or write access.  */
+
+static int
+internal_function
+diropen (char const *dir)
+{
+  int fd = open (dir, O_RDONLY | O_DIRECTORY);
+  if (fd < 0)
+    fd = open (dir, O_WRONLY | O_DIRECTORY);
+  return fd;
+}
+
 FTS *
 fts_open(argv, options, compar)
        char * const *argv;
@@ -416,7 +430,7 @@ fts_open(argv, options, compar)
         * descriptor we run anyway, just more slowly.
         */
        if (!ISSET(FTS_NOCHDIR)
-           && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
+           && (sp->fts_rfd = diropen (".")) < 0)
                SET(FTS_NOCHDIR);
 
        return (sp);
@@ -554,7 +568,7 @@ fts_read(sp)
            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
                p->fts_info = fts_stat(sp, p, true);
                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-                       if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
+                       if ((p->fts_symfd = diropen (".")) < 0) {
                                p->fts_errno = errno;
                                p->fts_info = FTS_ERR;
                        } else
@@ -656,8 +670,7 @@ next:       tmp = p;
                if (p->fts_instr == FTS_FOLLOW) {
                        p->fts_info = fts_stat(sp, p, true);
                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-                               if ((p->fts_symfd =
-                                   open(".", O_RDONLY, 0)) < 0) {
+                               if ((p->fts_symfd = diropen (".")) < 0) {
                                        p->fts_errno = errno;
                                        p->fts_info = FTS_ERR;
                                } else
@@ -802,7 +815,7 @@ fts_children(sp, instr)
            ISSET(FTS_NOCHDIR))
                return (sp->fts_child = fts_build(sp, instr));
 
-       if ((fd = open(".", O_RDONLY, 0)) < 0)
+       if ((fd = diropen (".")) < 0)
                return (sp->fts_child = NULL);
        sp->fts_child = fts_build(sp, instr);
        if (fchdir(fd)) {
@@ -1387,7 +1400,7 @@ fts_maxarglen(argv)
 }
 
 /*
- * Change to dir specified by fd or p->fts_accpath without getting
+ * Change to dir specified by fd or path without getting
  * tricked by someone changing the world out from underneath us.
  * Assumes p->fts_dev and p->fts_ino are filled in.
  */
@@ -1405,7 +1418,7 @@ fts_safe_changedir(sp, p, fd, path)
        newfd = fd;
        if (ISSET(FTS_NOCHDIR))
                return (0);
-       if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
+       if (fd < 0 && (newfd = diropen (path)) < 0)
                return (-1);
        if (fstat(newfd, &sb)) {
                ret = -1;
Index: src/shred.c
===================================================================
RCS file: /home/eggert/coreutils/cu/src/shred.c,v
retrieving revision 1.101
diff -p -u -r1.101 shred.c
--- src/shred.c 3 Aug 2004 19:07:51 -0000       1.101
+++ src/shred.c 9 Aug 2004 23:24:43 -0000
@@ -1434,9 +1434,12 @@ wipename (char *oldname, char const *qol
   size_t len = base_len (base);
   char *dir = dir_name (newname);
   char *qdir = xstrdup (quotearg_colon (dir));
-  int dir_fd = open (dir, O_RDONLY | O_NOCTTY);
   bool first = true;
   bool ok = true;
+
+  int dir_fd = open (dir, O_WRONLY | O_NOCTTY);
+  if (dir_fd < 0)
+    dir_fd = open (dir, O_RDONLY | O_NOCTTY);
 
   if (flags->verbose)
     error (0, 0, _("%s: removing"), qoldname);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]