(root)/
acl-2.3.1/
libacl/
perm_copy_fd.c
       1  /* Copy POSIX 1003.1e draft 17 (abandoned) ACLs between files. */
       2   
       3  /* Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
       4  
       5    This program is free software; you can redistribute it and/or
       6    modify it under the terms of the GNU Lesser General Public
       7    License as published by the Free Software Foundation; either
       8    version 2.1 of the License, or (at your option) any later version.
       9  
      10    This program is distributed in the hope that it will be useful,
      11    but WITHOUT ANY WARRANTY; without even the implied warranty of
      12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13    Lesser General Public License for more details.
      14  
      15    You should have received a copy of the GNU Lesser General Public
      16    License along with this library; if not, write to the Free Software
      17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
      18  */
      19  
      20  #if defined (HAVE_CONFIG_H)
      21  #include "config.h"
      22  #endif
      23  #if defined(HAVE_LIBACL_LIBACL_H)
      24  # include "libacl.h"
      25  #endif
      26  
      27  #include <sys/types.h>
      28  #include <sys/stat.h>
      29  #include <unistd.h>
      30  #include <stdlib.h>
      31  #include <errno.h>
      32  
      33  #if defined(HAVE_SYS_ACL_H)
      34  #include <sys/acl.h>
      35  #endif
      36  
      37  #if defined(HAVE_ACL_LIBACL_H)
      38  #include <acl/libacl.h>
      39  #endif
      40  
      41  #define ERROR_CONTEXT_MACROS
      42  #ifdef HAVE_ATTR_ERROR_CONTEXT_H
      43  #include <attr/error_context.h>
      44  #else
      45  #include "error_context.h"
      46  #endif
      47  
      48  #if !defined(ENOTSUP)
      49  # define ENOTSUP (-1)
      50  #endif
      51  
      52  #if !defined(HAVE_ACL_FREE)
      53  static int
      54  acl_free(void *obj_p)
      55  {
      56  	free (obj_p);
      57  	return 0;
      58  }
      59  #endif
      60  
      61  #if !defined(HAVE_ACL_ENTRIES)
      62  static int
      63  acl_entries(acl_t acl)
      64  {
      65  # if defined(HAVE_ACL_GET_ENTRY)
      66  	/* POSIX 1003.1e draft 17 (abandoned) compatible version.  */
      67  	acl_entry_t entry;
      68  	int entries = 0;
      69  
      70  	int entries = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
      71  	if (entries > 0) {
      72  		while (acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) > 0)
      73  			entries++;
      74  	}
      75  	return entries;
      76  # else
      77  	return -1;
      78  # endif
      79  }
      80  #endif
      81  
      82  #if !defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_FROM_TEXT)
      83  # define HAVE_ACL_FROM_MODE
      84  static acl_t
      85  acl_from_mode(mode_t mode)
      86  {
      87  	char acl_text[] = "u::---,g::---,o::---";
      88  	acl_t acl;
      89  
      90  	if (mode & S_IRUSR) acl_text[ 3] = 'r';
      91  	if (mode & S_IWUSR) acl_text[ 4] = 'w';
      92  	if (mode & S_IXUSR) acl_text[ 5] = 'x';
      93  	if (mode & S_IRGRP) acl_text[10] = 'r';
      94  	if (mode & S_IWGRP) acl_text[11] = 'w';
      95  	if (mode & S_IXGRP) acl_text[12] = 'x';
      96  	if (mode & S_IROTH) acl_text[17] = 'r';
      97  	if (mode & S_IWOTH) acl_text[18] = 'w';
      98  	if (mode & S_IXOTH) acl_text[19] = 'x';
      99  
     100  	return acl_from_text (acl_text);
     101  }
     102  #endif
     103  
     104  /* Set the access control list of path to the permissions defined by mode.  */
     105  static int
     106  set_acl_fd (char const *path, int fd, mode_t mode, struct error_context *ctx)
     107  {
     108  	int ret = 0;
     109  #if defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_SET_FD)
     110  	/* POSIX 1003.1e draft 17 (abandoned) specific version.  */
     111  	acl_t acl = acl_from_mode (mode);
     112  	if (!acl) {
     113  		error (ctx, "");
     114  		return -1;
     115  	}
     116  
     117  	if (acl_set_fd (fd, acl) != 0) {
     118  		ret = -1;
     119  		if (errno == ENOTSUP || errno == ENOSYS) {
     120  			(void) acl_free (acl);
     121  			goto chmod_only;
     122  		} else {
     123  			const char *qpath = quote (ctx, path);
     124  			error (ctx, _("setting permissions for %s"), qpath);
     125  			quote_free (ctx, qpath);
     126  		}
     127  	}
     128  	(void) acl_free (acl);
     129  	return ret;
     130  #endif
     131  
     132  chmod_only:
     133  	ret = fchmod (fd, mode);
     134  	if (ret != 0) {
     135  		const char *qpath = quote (ctx, path);
     136  		error (ctx, _("setting permissions for %s"), qpath);
     137  		quote_free (ctx, qpath);
     138  	}
     139  	return ret;
     140  }
     141  
     142  /* Copy the permissions of src_path to dst_path. This includes the
     143     file mode permission bits and ACLs. File ownership is not copied.
     144   */
     145  int
     146  perm_copy_fd (const char *src_path, int src_fd,
     147  	       const char *dst_path, int dst_fd,
     148  	       struct error_context *ctx)
     149  {
     150  #if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
     151  	acl_t acl;
     152  #endif
     153  	struct stat st;
     154  	int ret = 0;
     155  
     156  	ret = fstat(src_fd, &st);
     157  	if (ret != 0) {
     158  		const char *qpath = quote (ctx, src_path);
     159  		error (ctx, "%s", qpath);
     160  		quote_free (ctx, qpath);
     161  		return -1;
     162  	}
     163  #if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
     164  	/* POSIX 1003.1e draft 17 (abandoned) specific version.  */
     165  	acl = acl_get_fd (src_fd);
     166  	if (acl == NULL) {
     167  		ret = -1;
     168  		if (errno == ENOSYS || errno == ENOTSUP)
     169  			ret = set_acl_fd (dst_path, dst_fd, st.st_mode, ctx);
     170  		else {
     171  			const char *qpath = quote (ctx, src_path);
     172  			error (ctx, "%s", qpath);
     173  			quote_free (ctx, qpath);
     174  		}
     175  		return ret;
     176  	}
     177  
     178  	if (acl_set_fd (dst_fd, acl) != 0) {
     179  		int saved_errno = errno;
     180  		__apply_mask_to_mode(&st.st_mode, acl);
     181  		ret = fchmod (dst_fd, st.st_mode);
     182  		if ((errno != ENOSYS && errno != ENOTSUP) ||
     183  		    acl_entries (acl) != 3) {
     184  			const char *qpath = quote (ctx, dst_path);
     185  			errno = saved_errno;
     186  			error (ctx, _("preserving permissions for %s"), qpath);
     187  			quote_free (ctx, qpath);
     188  			ret = -1;
     189  		}
     190  	}
     191  	(void) acl_free (acl);
     192  	return ret;
     193  #else
     194  	/* POSIX.1 version. */
     195  	ret = fchmod (dst_fd, st.st_mode);
     196  	if (ret != 0) {
     197  		const char *qpath = quote (ctx, dst_path);
     198  		error (ctx, _("setting permissions for %s"), qpath);
     199  		quote_free (ctx, qpath);
     200  	}
     201  	return ret;
     202  #endif
     203  }
     204