(root)/
attr-2.5.1/
libattr/
attr_copy_file.c
       1  /*
       2    Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
       3  
       4    This program is free software; you can redistribute it and/or
       5    modify it under the terms of the GNU Lesser General Public
       6    License as published by the Free Software Foundation; either
       7    version 2.1 of the License, or (at your option) any later version.
       8  
       9    This program is distributed in the hope that it will be useful,
      10    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12    Lesser General Public License for more details.
      13  
      14    You should have received a copy of the GNU Lesser General Public License
      15    along with this manual.  If not, see <http://www.gnu.org/licenses/>.
      16  */
      17  
      18  /* Copy extended attributes between files. */
      19  
      20  #if defined (HAVE_CONFIG_H)
      21  #include "config.h"
      22  #endif
      23  
      24  #include <sys/types.h>
      25  # include <sys/xattr.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  #include <errno.h>
      29  
      30  #if defined(HAVE_ALLOCA_H)
      31  # include <alloca.h>
      32  #endif
      33  
      34  #if defined(HAVE_ATTR_LIBATTR_H)
      35  # include "attr/libattr.h"
      36  #endif
      37  
      38  #define ERROR_CONTEXT_MACROS
      39  #include "error_context.h"
      40  #include "nls.h"
      41  
      42  #if !defined(ENOTSUP)
      43  # define ENOTSUP (-1)
      44  #endif
      45  
      46  #if defined(HAVE_ALLOCA)
      47  # define my_alloc(size) alloca (size)
      48  # define my_free(ptr) do { } while(0)
      49  #else
      50  # define my_alloc(size) malloc (size)
      51  # define my_free(ptr) free (ptr)
      52  #endif
      53  
      54  /* Copy extended attributes from src_path to dst_path. If the file
      55     has an extended Access ACL (system.posix_acl_access) and that is
      56     copied successfully, the file mode permission bits are copied as
      57     a side effect. This may not always the case, so the file mode
      58     and/or ownership must be copied separately. */
      59  int
      60  attr_copy_file(const char *src_path, const char *dst_path,
      61  	       int (*check) (const char *, struct error_context *),
      62  	       struct error_context *ctx)
      63  {
      64  #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR) && defined(HAVE_SETXATTR)
      65  	int ret = 0;
      66  	ssize_t size;
      67  	char *names = NULL, *end_names, *name, *value = NULL;
      68  	unsigned int setxattr_ENOTSUP = 0;
      69  
      70  	/* ignore acls by default */
      71  	if (check == NULL)
      72  		check = attr_copy_check_permissions;
      73  
      74  	size = llistxattr (src_path, NULL, 0);
      75  	if (size < 0) {
      76  		if (errno != ENOSYS && errno != ENOTSUP) {
      77  			const char *qpath = quote (ctx, src_path);
      78  			error (ctx, _("listing attributes of %s"), qpath);
      79  			quote_free (ctx, qpath);
      80  			ret = -1;
      81  		}
      82  		goto getout;
      83  	}
      84  	names = (char *) my_alloc (size+1);
      85  	if (names == NULL) {
      86  		error (ctx, "");
      87  		ret = -1;
      88  		goto getout;
      89  	}
      90  	size = llistxattr (src_path, names, size);
      91  	if (size < 0) {
      92  		const char *qpath = quote (ctx, src_path);
      93  		error (ctx, _("listing attributes of %s"), qpath);
      94  		quote_free (ctx, qpath);
      95  		ret = -1;
      96  		goto getout;
      97  	} else {
      98  		names[size] = '\0';
      99  		end_names = names + size;
     100  	}
     101  
     102  	for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
     103  		void *old_value;
     104  
     105  		/* check if this attribute shall be preserved */
     106  		if (!*name || !check(name, ctx))
     107  			continue;
     108  
     109  		size = lgetxattr (src_path, name, NULL, 0);
     110  		if (size < 0) {
     111  			const char *qpath = quote (ctx, src_path);
     112  			const char *qname = quote (ctx, name);
     113  			error (ctx, _("getting attribute %s of %s"),
     114  			       qname, qpath);
     115  			quote_free (ctx, qname);
     116  			quote_free (ctx, qpath);
     117  			ret = -1;
     118  			continue;
     119  		}
     120  		value = (char *) realloc (old_value = value, size);
     121  		if (size != 0 && value == NULL) {
     122  			free(old_value);
     123  			error (ctx, "");
     124  			ret = -1;
     125  		}
     126  		size = lgetxattr (src_path, name, value, size);
     127  		if (size < 0) {
     128  			const char *qpath = quote (ctx, src_path);
     129  			const char *qname = quote (ctx, name);
     130  			error (ctx, _("getting attribute %s of %s"),
     131  			       qname, qpath);
     132  			quote_free (ctx, qname);
     133  			quote_free (ctx, qpath);
     134  			ret = -1;
     135  			continue;
     136  		}
     137  		if (lsetxattr (dst_path, name, value, size, 0) != 0) {
     138  			if (errno == ENOTSUP)
     139  				setxattr_ENOTSUP++;
     140  			else {
     141  				const char *qpath = quote (ctx, dst_path);
     142  				if (errno == ENOSYS) {
     143  					error (ctx, _("setting attributes for "
     144  					       "%s"), qpath);
     145  					ret = -1;
     146  					/* no hope of getting any further */
     147  					break;
     148  				} else {
     149  					const char *qname = quote (ctx, name);
     150  					error (ctx, _("setting attribute %s for "
     151  					       "%s"), qname, qpath);
     152  					quote_free (ctx, qname);
     153  					ret = -1;
     154  				}
     155  				quote_free (ctx, qpath);
     156  			}
     157  		}
     158  	}
     159  	if (setxattr_ENOTSUP) {
     160  		const char *qpath = quote (ctx, dst_path);
     161  		errno = ENOTSUP;
     162  		error (ctx, _("setting attributes for %s"), qpath);
     163  		ret = -1;
     164  		quote_free (ctx, qpath);
     165  	}
     166  getout:
     167  	free (value);
     168  	my_free (names);
     169  	return ret;
     170  #else
     171  	return 0;
     172  #endif
     173  }
     174