(root)/
attr-2.5.1/
libattr/
libattr.c
       1  /*
       2   * Copyright (c) 2001-2003,2005 Silicon Graphics, Inc.
       3   * All Rights Reserved.
       4   *
       5   * This program is free software: you can redistribute it and/or modify it
       6   * under the terms of the GNU Lesser General Public License as published
       7   * by the Free Software Foundation, either version 2.1 of the License, or
       8   * (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
      13   * GNU Lesser General Public License for more details.
      14   *
      15   * You should have received a copy of the GNU Lesser General Public License
      16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17   */
      18  
      19  #include "config.h"
      20  
      21  #include <errno.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <unistd.h>
      25  #include <sys/types.h>
      26  #include <sys/xattr.h>
      27  
      28  #include <attr/attributes.h>
      29  
      30  #ifndef ENOATTR
      31  # define ENOATTR ENODATA
      32  #endif
      33  
      34  #undef MAXNAMELEN
      35  #define MAXNAMELEN 256
      36  #undef MAXLISTLEN
      37  #define MAXLISTLEN 65536
      38  
      39  #undef roundup
      40  #define roundup(x,y) ((((x)+((y)-1))/(y))*(y))
      41  
      42  static const char *user_name = "user.";
      43  static const char *secure_name = "security.";
      44  static const char *trusted_name = "trusted.";
      45  static const char *xfsroot_name = "xfsroot.";
      46  
      47  /*
      48   * Convert IRIX API components into Linux/XFS API components,
      49   * and vice-versa.
      50   */
      51  static int
      52  api_convert(char *name, const char *irixname, int irixflags, int compat)
      53  {
      54  	if (strlen(irixname) >= MAXNAMELEN) {
      55  		errno = EINVAL;
      56  		return -1;
      57  	}
      58  	if (irixflags & ATTR_ROOT) {
      59  		if (compat)
      60  			strcpy(name, xfsroot_name);
      61  		else
      62  			strcpy(name, trusted_name);
      63  	} else if (irixflags & ATTR_SECURE) {
      64  		strcpy(name, secure_name);
      65  	} else {
      66  		strcpy(name, user_name);
      67  	}
      68  	strcat(name, irixname);
      69  	return 0;
      70  }
      71  
      72  static int
      73  api_unconvert(char *name, const char *linuxname, int irixflags)
      74  {
      75  	int type, length;
      76  
      77  	length = strlen(user_name);
      78  	if (strncmp(linuxname, user_name, length) == 0) {
      79  		type = 0; /*ATTR_USER*/
      80  		goto found;
      81  	}
      82  	length = strlen(secure_name);
      83  	if (strncmp(linuxname, secure_name, length) == 0) {
      84  		type = ATTR_SECURE;
      85  		goto found;
      86  	}
      87  	length = strlen(trusted_name);
      88  	if (strncmp(linuxname, trusted_name, length) == 0) {
      89  		type = ATTR_ROOT;
      90  		goto found;
      91  	}
      92  	length = strlen(xfsroot_name);
      93  	if (strncmp(linuxname, xfsroot_name, length) == 0) {
      94  		type = ATTR_ROOT;
      95  		goto found;
      96  	}
      97  	return 1;
      98  
      99  found:
     100  	if ((irixflags & ATTR_SECURE) != 0 && (type != ATTR_SECURE))
     101  		return 1;
     102  	if ((irixflags & ATTR_ROOT) != 0 && (type != ATTR_ROOT))
     103  		return 1;
     104  	strcpy(name, linuxname + length);
     105  	return 0;
     106  }
     107  
     108  
     109  int
     110  attr_get(const char *path, const char *attrname, char *attrvalue,
     111  	 int *valuelength, int flags)
     112  {
     113  	ssize_t (*get)(const char *, const char *, void *, size_t) =
     114  		flags & ATTR_DONTFOLLOW ? lgetxattr : getxattr;
     115  	int c, compat;
     116  	char name[MAXNAMELEN+16];
     117  
     118  	for (compat = 0; compat < 2; compat++) {
     119  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     120  			return c;
     121  		c = get(path, name, attrvalue, *valuelength);
     122  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     123  			continue;
     124  		break;
     125  	}
     126  	if (c < 0 && errno == ERANGE) {
     127  		int size = get(path, name, NULL, 0);
     128  		if (size >= 0) {
     129  			*valuelength = size;
     130  			errno = E2BIG;
     131  		}
     132  		return c;
     133  	}
     134  	if (c < 0)
     135  		return c;
     136  	*valuelength = c;
     137  	return 0;
     138  }
     139  
     140  int
     141  attr_getf(int fd, const char *attrname, char *attrvalue,
     142  	  int *valuelength, int flags)
     143  {
     144  	int c, compat;
     145  	char name[MAXNAMELEN+16];
     146  
     147  	for (compat = 0; compat < 2; compat++) {
     148  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     149  			return c;
     150  		c = fgetxattr(fd, name, attrvalue, *valuelength);
     151  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     152  			continue;
     153  		break;
     154  	}
     155  	if (c < 0 && errno == ERANGE) {
     156  		int size = fgetxattr(fd, name, NULL, 0);
     157  		if (size >= 0) {
     158  			*valuelength = size;
     159  			errno = E2BIG;
     160  		}
     161  		return c;
     162  	}
     163  	if (c < 0)
     164  		return c;
     165  	*valuelength = c;
     166  	return 0;
     167  }
     168  
     169  int
     170  attr_set(const char *path, const char *attrname, const char *attrvalue,
     171  	 const int valuelength, int flags)
     172  {
     173  	int c, compat, lflags = 0;
     174  	char name[MAXNAMELEN+16];
     175  	void *buffer = (void *)attrvalue;
     176  
     177  	if (flags & ATTR_CREATE)
     178  		lflags = XATTR_CREATE;
     179  	else if (flags & ATTR_REPLACE)
     180  		lflags = XATTR_REPLACE;
     181  
     182  	for (compat = 0; compat < 2; compat++) {
     183  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     184  			return c;
     185  		if (flags & ATTR_DONTFOLLOW)
     186  			c = lsetxattr(path, name, buffer, valuelength, lflags);
     187  		else
     188  			c = setxattr(path, name, buffer, valuelength, lflags);
     189  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     190  			continue;
     191  		break;
     192  	}
     193  	return c;
     194  }
     195  
     196  int
     197  attr_setf(int fd, const char *attrname,
     198  	  const char *attrvalue, const int valuelength, int flags)
     199  {
     200  	int c, compat, lflags = 0;
     201  	char name[MAXNAMELEN+16];
     202  	void *buffer = (void *)attrvalue;
     203  
     204  	if (flags & ATTR_CREATE)
     205  		lflags = XATTR_CREATE;
     206  	else if (flags & ATTR_REPLACE)
     207  		lflags = XATTR_REPLACE;
     208  
     209  	for (compat = 0; compat < 2; compat++) {
     210  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     211  			return c;
     212  		c = fsetxattr(fd, name, buffer, valuelength, lflags);
     213  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     214  			continue;
     215  		break;
     216  	}
     217  	return c;
     218  }
     219  
     220  int
     221  attr_remove(const char *path, const char *attrname, int flags)
     222  {
     223  	int c, compat;
     224  	char name[MAXNAMELEN+16];
     225  
     226  	for (compat = 0; compat < 2; compat++) {
     227  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     228  			return c;
     229  		if (flags & ATTR_DONTFOLLOW)
     230  			c = lremovexattr(path, name);
     231  		else
     232  			c = removexattr(path, name);
     233  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     234  			continue;
     235  		break;
     236  	}
     237  	return c;
     238  }
     239  
     240  int
     241  attr_removef(int fd, const char *attrname, int flags)
     242  {
     243  	int c, compat;
     244  	char name[MAXNAMELEN+16];
     245  
     246  	for (compat = 0; compat < 2; compat++) {
     247  		if ((c = api_convert(name, attrname, flags, compat)) < 0)
     248  			return c;
     249  		c = fremovexattr(fd, name);
     250  		if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
     251  			continue;
     252  		break;
     253  	}
     254  	return c;
     255  }
     256  
     257  
     258  /*
     259   * Helper routine for attr_list functions.
     260   */
     261  
     262  static int
     263  attr_list_pack(const char *name, const int valuelen,
     264  		char *buffer, const int buffersize,
     265  		int *start_offset, int *end_offset)
     266  {
     267  	attrlist_ent_t *aentp;
     268  	attrlist_t *alist = (attrlist_t *)buffer;
     269  	int size = roundup(strlen(name) + 1 + sizeof(aentp->a_valuelen), 8);
     270  
     271  	if ((*end_offset - size) < (*start_offset + sizeof(alist->al_count))) {
     272  		alist->al_more = 1;
     273  		return 1;
     274  	}
     275  
     276  	*end_offset -= size;
     277  	aentp = (attrlist_ent_t *)&buffer[ *end_offset ];
     278  	aentp->a_valuelen = valuelen;
     279  	strncpy(aentp->a_name, name, size - sizeof(aentp->a_valuelen));
     280  
     281  	*start_offset += sizeof(alist->al_offset);
     282  	alist->al_offset[alist->al_count] = *end_offset;
     283  	alist->al_count++;
     284  	return 0;
     285  }
     286  
     287  int
     288  attr_list(const char *path, char *buffer, const int buffersize, int flags,
     289  	  attrlist_cursor_t *cursor)
     290  {
     291  	const char *l;
     292  	int length, vlength, count = 0;
     293  	char lbuf[MAXLISTLEN+1];
     294  	char name[MAXNAMELEN+16];
     295  	int start_offset, end_offset;
     296  
     297  	if (buffersize < sizeof(attrlist_t)) {
     298  		errno = EINVAL;
     299  		return -1;
     300  	}
     301  	memset(buffer, 0, sizeof(attrlist_t));
     302  
     303  	if (flags & ATTR_DONTFOLLOW)
     304  		length = llistxattr(path, lbuf, sizeof(lbuf) - 1);
     305  	else
     306  		length = listxattr(path, lbuf, sizeof(lbuf) - 1);
     307  	if (length <= 0)
     308  		return length;
     309  	lbuf[length] = 0;  /* not supposed to be necessary */
     310  
     311  	start_offset = sizeof(attrlist_t);
     312  	end_offset = buffersize & ~(8-1);	/* 8 byte align */
     313  
     314  	for (l = lbuf; l != lbuf + length; l = strchr(l, '\0') + 1) {
     315  		if (api_unconvert(name, l, flags))
     316  			continue;
     317  		if (flags & ATTR_DONTFOLLOW)
     318  			vlength = lgetxattr(path, l, NULL, 0);
     319  		else
     320  			vlength =  getxattr(path, l, NULL, 0);
     321  		if (vlength < 0 && (errno == ENOATTR || errno == ENOTSUP))
     322  			continue;
     323  		if (count++ < cursor->opaque[0])
     324  			continue;
     325  		if (attr_list_pack(name, vlength, buffer, buffersize,
     326  				   &start_offset, &end_offset)) {
     327  			if (cursor->opaque[0] == count - 1) {
     328  				errno = EINVAL;
     329  				return -1;
     330  			}
     331  			cursor->opaque[0] = count - 1;
     332  			break;
     333  		}
     334  	}
     335  	return 0;
     336  }
     337  
     338  int
     339  attr_listf(int fd, char *buffer, const int buffersize, int flags,
     340  	   attrlist_cursor_t *cursor)
     341  {
     342  	const char *l;
     343  	int length, vlength, count = 0;
     344  	char lbuf[MAXLISTLEN+1];
     345  	char name[MAXNAMELEN+16];
     346  	int start_offset, end_offset;
     347  
     348  	if (buffersize < sizeof(attrlist_t)) {
     349  		errno = EINVAL;
     350  		return -1;
     351  	}
     352  	memset(buffer, 0, sizeof(attrlist_t));
     353  
     354  	length = flistxattr(fd, lbuf, sizeof(lbuf) - 1);
     355  	if (length < 0)
     356  		return length;
     357  	lbuf[length] = 0;  /* not supposed to be necessary */
     358  
     359  	start_offset = sizeof(attrlist_t);
     360  	end_offset = buffersize & ~(8-1);	/* 8 byte align */
     361  
     362  	for (l = lbuf; l != lbuf + length; l = strchr(l, '\0') + 1) {
     363  		if (api_unconvert(name, l, flags))
     364  			continue;
     365  		vlength = fgetxattr(fd, l, NULL, 0);
     366  		if (vlength < 0 && (errno == ENOATTR || errno == ENOTSUP))
     367  			continue;
     368  		if (count++ < cursor->opaque[0])
     369  			continue;
     370  		if (attr_list_pack(name, vlength, buffer, buffersize,
     371  				   &start_offset, &end_offset)) {
     372  			if (cursor->opaque[0] == count - 1) {
     373  				errno = EINVAL;
     374  				return -1;
     375  			}
     376  			cursor->opaque[0] = count - 1;
     377  			break;
     378  		}
     379  	}
     380  	return 0;
     381  }
     382  
     383  
     384  /*
     385   * Helper routines for the attr_multi functions.  In IRIX, the
     386   * multi routines are a single syscall - in Linux, we break em
     387   * apart in userspace and make individual syscalls for each.
     388   */
     389  
     390  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
     391  static int
     392  attr_single(const char *path, attr_multiop_t *op, int flags)
     393  {
     394  	int r = -1;
     395  
     396  	errno = EINVAL;
     397  	flags |= op->am_flags;
     398  	if (op->am_opcode == ATTR_OP_GET)
     399  		r = attr_get(path, op->am_attrname, op->am_attrvalue,
     400  				&op->am_length, flags);
     401  	else if (op->am_opcode == ATTR_OP_SET)
     402  		r = attr_set(path, op->am_attrname, op->am_attrvalue,
     403  				op->am_length, flags);
     404  	else if (op->am_opcode == ATTR_OP_REMOVE)
     405  		r = attr_remove(path, op->am_attrname, flags);
     406  	return r;
     407  }
     408  
     409  static int
     410  attr_singlef(const int fd, attr_multiop_t *op, int flags)
     411  {
     412  	int r = -1;
     413  
     414  	errno = EINVAL;
     415  	flags |= op->am_flags;
     416  	if (op->am_opcode == ATTR_OP_GET)
     417  		r = attr_getf(fd, op->am_attrname, op->am_attrvalue,
     418  				&op->am_length, flags);
     419  	else if (op->am_opcode == ATTR_OP_SET)
     420  		r = attr_setf(fd, op->am_attrname, op->am_attrvalue,
     421  				op->am_length, flags);
     422  	else if (op->am_opcode == ATTR_OP_REMOVE)
     423  		r = attr_removef(fd, op->am_attrname, flags);
     424  	return r;
     425  }
     426  #pragma GCC diagnostic warning "-Wdeprecated-declarations"
     427  
     428  /*
     429   * Operate on multiple attributes of the same object simultaneously
     430   *
     431   * From the manpage: "attr_multi will fail if ... a bit other than
     432   * ATTR_DONTFOLLOW was set in the flag argument." flags must be
     433   * checked here as they are not passed into the kernel.
     434   */
     435  int
     436  attr_multi(const char *path, attr_multiop_t *multiops, int count, int flags)
     437  {
     438  	int i, tmp, r = -1;
     439  
     440  	errno = EINVAL;
     441  	if ((flags & ATTR_DONTFOLLOW) != flags)
     442  		return r;
     443  
     444  	r = errno = 0;
     445  	for (i = 0; i < count; i++) {
     446  		tmp = attr_single(path, &multiops[i], flags);
     447  		if (tmp) r = tmp;
     448  	}
     449  	return r;
     450  }
     451  
     452  int
     453  attr_multif(int fd, attr_multiop_t *multiops, int count, int flags)
     454  {
     455  	int i, tmp, r = -1;
     456  
     457  	errno = EINVAL;
     458  	if ((flags & ATTR_DONTFOLLOW) != flags)
     459  		return r;
     460  
     461  	r = errno = 0;
     462  	for (i = 0; i < count; i++) {
     463  		tmp = attr_singlef(fd, &multiops[i], flags);
     464  		if (tmp) r = tmp;
     465  	}
     466  	return r;
     467  }