(root)/
tar-1.35/
gnu/
lchown.c
       1  /* Provide a stub lchown function for systems that lack it.
       2  
       3     Copyright (C) 1998-1999, 2002, 2004, 2006-2007, 2009-2023 Free Software
       4     Foundation, Inc.
       5  
       6     This file is free software: you can redistribute it and/or modify
       7     it under the terms of the GNU Lesser General Public License as
       8     published by the Free Software Foundation; either version 2.1 of the
       9     License, or (at your option) any later version.
      10  
      11     This file 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 Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public License
      17     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  /* written by Jim Meyering */
      20  
      21  #include <config.h>
      22  
      23  #include <unistd.h>
      24  
      25  #include <errno.h>
      26  #include <string.h>
      27  #include <sys/stat.h>
      28  
      29  #if !HAVE_LCHOWN
      30  
      31  /* If the system chown does not follow symlinks, we don't want it
      32     replaced by gnulib's chown, which does follow symlinks.  */
      33  # if CHOWN_MODIFIES_SYMLINK
      34  #  undef chown
      35  # endif
      36  
      37  /* Work just like chown, except when FILE is a symbolic link.
      38     In that case, set errno to EOPNOTSUPP and return -1.
      39     But if autoconf tests determined that chown modifies
      40     symlinks, then just call chown.  */
      41  
      42  int
      43  lchown (const char *file, uid_t uid, gid_t gid)
      44  {
      45  # if HAVE_CHOWN
      46  #  if ! CHOWN_MODIFIES_SYMLINK
      47    char readlink_buf[1];
      48  
      49    if (0 <= readlink (file, readlink_buf, sizeof readlink_buf))
      50      {
      51        errno = EOPNOTSUPP;
      52        return -1;
      53      }
      54  #  endif
      55  
      56    return chown (file, uid, gid);
      57  
      58  # else /* !HAVE_CHOWN */
      59    errno = ENOSYS;
      60    return -1;
      61  # endif
      62  }
      63  
      64  #else /* HAVE_LCHOWN */
      65  
      66  # undef lchown
      67  
      68  /* Work around trailing slash bugs in lchown.  */
      69  int
      70  rpl_lchown (const char *file, uid_t uid, gid_t gid)
      71  {
      72    bool stat_valid = false;
      73    int result;
      74  
      75  # if CHOWN_CHANGE_TIME_BUG
      76    struct stat st;
      77  
      78    if (gid != (gid_t) -1 || uid != (uid_t) -1)
      79      {
      80        if (lstat (file, &st))
      81          return -1;
      82        stat_valid = true;
      83        if (!S_ISLNK (st.st_mode))
      84          return chown (file, uid, gid);
      85      }
      86  # endif
      87  
      88  # if CHOWN_TRAILING_SLASH_BUG
      89    if (!stat_valid)
      90      {
      91        size_t len = strlen (file);
      92        if (len && file[len - 1] == '/')
      93          return chown (file, uid, gid);
      94      }
      95  # endif
      96  
      97    result = lchown (file, uid, gid);
      98  
      99  # if CHOWN_CHANGE_TIME_BUG && HAVE_LCHMOD
     100    if (result == 0 && stat_valid
     101        && (uid == st.st_uid || uid == (uid_t) -1)
     102        && (gid == st.st_gid || gid == (gid_t) -1))
     103      {
     104        /* No change in ownership, but at least one argument was not -1,
     105           so we are required to update ctime.  Since lchown succeeded,
     106           we assume that lchmod will do likewise.  But if the system
     107           lacks lchmod and lutimes, we are out of luck.  Oh well.  */
     108        result = lchmod (file, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO
     109                                             | S_ISUID | S_ISGID | S_ISVTX));
     110      }
     111  # endif
     112  
     113    return result;
     114  }
     115  
     116  #endif /* HAVE_LCHOWN */