Blame lib/lchown.c

Packit Service a2489d
/* Provide a stub lchown function for systems that lack it.
Packit Service a2489d
Packit Service a2489d
   Copyright (C) 1998-1999, 2002, 2004, 2006-2007, 2009-2018 Free Software
Packit Service a2489d
   Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
/* written by Jim Meyering */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
#include <unistd.h>
Packit Service a2489d
Packit Service a2489d
#include <errno.h>
Packit Service a2489d
#include <stdbool.h>
Packit Service a2489d
#include <string.h>
Packit Service a2489d
#include <sys/stat.h>
Packit Service a2489d
Packit Service a2489d
#if !HAVE_LCHOWN
Packit Service a2489d
Packit Service a2489d
/* If the system chown does not follow symlinks, we don't want it
Packit Service a2489d
   replaced by gnulib's chown, which does follow symlinks.  */
Packit Service a2489d
# if CHOWN_MODIFIES_SYMLINK
Packit Service a2489d
#  undef chown
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
/* Work just like chown, except when FILE is a symbolic link.
Packit Service a2489d
   In that case, set errno to EOPNOTSUPP and return -1.
Packit Service a2489d
   But if autoconf tests determined that chown modifies
Packit Service a2489d
   symlinks, then just call chown.  */
Packit Service a2489d
Packit Service a2489d
int
Packit Service a2489d
lchown (const char *file, uid_t uid, gid_t gid)
Packit Service a2489d
{
Packit Service a2489d
# if HAVE_CHOWN
Packit Service a2489d
#  if ! CHOWN_MODIFIES_SYMLINK
Packit Service a2489d
  struct stat stats;
Packit Service a2489d
Packit Service a2489d
  if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
Packit Service a2489d
    {
Packit Service a2489d
      errno = EOPNOTSUPP;
Packit Service a2489d
      return -1;
Packit Service a2489d
    }
Packit Service a2489d
#  endif
Packit Service a2489d
Packit Service a2489d
  return chown (file, uid, gid);
Packit Service a2489d
Packit Service a2489d
# else /* !HAVE_CHOWN */
Packit Service a2489d
  errno = ENOSYS;
Packit Service a2489d
  return -1;
Packit Service a2489d
# endif
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#else /* HAVE_LCHOWN */
Packit Service a2489d
Packit Service a2489d
# undef lchown
Packit Service a2489d
Packit Service a2489d
/* Work around trailing slash bugs in lchown.  */
Packit Service a2489d
int
Packit Service a2489d
rpl_lchown (const char *file, uid_t uid, gid_t gid)
Packit Service a2489d
{
Packit Service a2489d
  bool stat_valid = false;
Packit Service a2489d
  int result;
Packit Service a2489d
Packit Service a2489d
# if CHOWN_CHANGE_TIME_BUG
Packit Service a2489d
  struct stat st;
Packit Service a2489d
Packit Service a2489d
  if (gid != (gid_t) -1 || uid != (uid_t) -1)
Packit Service a2489d
    {
Packit Service a2489d
      if (lstat (file, &st))
Packit Service a2489d
        return -1;
Packit Service a2489d
      stat_valid = true;
Packit Service a2489d
      if (!S_ISLNK (st.st_mode))
Packit Service a2489d
        return chown (file, uid, gid);
Packit Service a2489d
    }
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
# if CHOWN_TRAILING_SLASH_BUG
Packit Service a2489d
  if (!stat_valid)
Packit Service a2489d
    {
Packit Service a2489d
      size_t len = strlen (file);
Packit Service a2489d
      if (len && file[len - 1] == '/')
Packit Service a2489d
        return chown (file, uid, gid);
Packit Service a2489d
    }
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  result = lchown (file, uid, gid);
Packit Service a2489d
Packit Service a2489d
# if CHOWN_CHANGE_TIME_BUG && HAVE_LCHMOD
Packit Service a2489d
  if (result == 0 && stat_valid
Packit Service a2489d
      && (uid == st.st_uid || uid == (uid_t) -1)
Packit Service a2489d
      && (gid == st.st_gid || gid == (gid_t) -1))
Packit Service a2489d
    {
Packit Service a2489d
      /* No change in ownership, but at least one argument was not -1,
Packit Service a2489d
         so we are required to update ctime.  Since lchown succeeded,
Packit Service a2489d
         we assume that lchmod will do likewise.  But if the system
Packit Service a2489d
         lacks lchmod and lutimes, we are out of luck.  Oh well.  */
Packit Service a2489d
      result = lchmod (file, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO
Packit Service a2489d
                                           | S_ISUID | S_ISGID | S_ISVTX));
Packit Service a2489d
    }
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  return result;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#endif /* HAVE_LCHOWN */