(linenum→info "unix/slp.c:2238")

coreutils/6.9/lib/chown.c

    1: /* provide consistent interface to chown for systems that don't interpret
    2:    an ID of -1 as meaning `don't change the corresponding ID'.
    3: 
    4:    Copyright (C) 1997, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    5: 
    6:    This program is free software; you can redistribute it and/or modify
    7:    it under the terms of the GNU General Public License as published by
    8:    the Free Software Foundation; either version 2, or (at your option)
    9:    any later version.
   10: 
   11:    This program is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:    GNU General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU General Public License
   17:    along with this program; if not, write to the Free Software Foundation,
   18:    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
   19: 
   20: /* written by Jim Meyering */
   21: 
   22: #include <config.h>
   23: 
   24: /* Specification.  */
   25: #include <unistd.h>
   26: 
   27: #include <stdbool.h>
   28: #include <sys/types.h>
   29: #include <sys/stat.h>
   30: #include <fcntl.h>
   31: #include <errno.h>
   32: 
   33: /* Below we refer to the system's chown().  */
   34: #undef chown
   35: 
   36: /* The results of open() in this file are not used with fchdir,
   37:    therefore save some unnecessary work in fchdir.c.  */
   38: #undef open
   39: #undef close
   40: 
   41: /* Provide a more-closely POSIX-conforming version of chown on
   42:    systems with one or both of the following problems:
   43:    - chown doesn't treat an ID of -1 as meaning
   44:    `don't change the corresponding ID'.
   45:    - chown doesn't dereference symlinks.  */
   46: 
   47: int
   48: rpl_chown (const char *file, uid_t uid, gid_t gid)
   49: {
   50: #if CHOWN_FAILS_TO_HONOR_ID_OF_NEGATIVE_ONE
   51:   if (gid == (gid_t) -1 || uid == (uid_t) -1)
   52:     {
   53:       struct stat file_stats;
   54: 
   55:       /* Stat file to get id(s) that should remain unchanged.  */
   56:       if (stat (file, &file_stats))
   57:         return -1;
   58: 
   59:       if (gid == (gid_t) -1)
   60:         gid = file_stats.st_gid;
   61: 
   62:       if (uid == (uid_t) -1)
   63:         uid = file_stats.st_uid;
   64:     }
   65: #endif
   66: 
   67: #if CHOWN_MODIFIES_SYMLINK
   68:   {
   69:     /* Handle the case in which the system-supplied chown function
   70:        does *not* follow symlinks.  Instead, it changes permissions
   71:        on the symlink itself.  To work around that, we open the
   72:        file (but this can fail due to lack of read or write permission) and
   73:        use fchown on the resulting descriptor.  */
   74:     int open_flags = O_NONBLOCK | O_NOCTTY;
   75:     int fd = open (file, O_RDONLY | open_flags);
   76:     if (0 <= fd
   77:         || (errno == EACCES
   78:             && 0 <= (fd = open (file, O_WRONLY | open_flags))))
   79:       {
   80:         int result = fchown (fd, uid, gid);
   81:         int saved_errno = errno;
   82: 
   83:         /* POSIX says fchown can fail with errno == EINVAL on sockets,
   84:            so fall back on chown in that case.  */
   85:         struct stat sb;
   86:         bool fchown_socket_failure =
   87:           (result != 0 && saved_errno == EINVAL
   88:            && fstat (fd, &sb) == 0 && S_ISFIFO (sb.st_mode));
   89: 
   90:         close (fd);
   91: 
   92:         if (! fchown_socket_failure)
   93:           {
   94:             errno = saved_errno;
   95:             return result;
   96:           }
   97:       }
   98:     else if (errno != EACCES)
   99:       return -1;
  100:   }
  101: #endif
  102: 
  103:   return chown (file, uid, gid);
  104: }
Syntax (Markdown)