summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Scott <nathans@sgi.com>2002-02-25 22:10:22 +0000
committerNathan Scott <nathans@sgi.com>2002-02-25 22:10:22 +0000
commitc82edc1013cf28a096cb8f5ba21c28d3e9312227 (patch)
tree5a2c12886725666beddf1aaf8cdf20e474359ebc
parenta87485aca58ea2236b31b0c0b8e438b3d967709b (diff)
downloadattr-c82edc1013cf28a096cb8f5ba21c28d3e9312227.tar.gz
Merge of xfs-cmds-2.4.18:slinx:111138a by nathans.
bump to version 2.0.0 for extended attribute and other interface changes. incorporate new code, docs, etc from ext2/ext3 project.
-rw-r--r--Makefile2
-rw-r--r--README6
-rw-r--r--VERSION6
-rw-r--r--attr/attr.c65
-rw-r--r--build/rpm/attr.spec.in23
-rw-r--r--debian/changelog8
-rw-r--r--debian/control26
-rw-r--r--debian/copyright13
-rw-r--r--doc/CHANGES17
-rw-r--r--doc/COPYING8
-rw-r--r--doc/PORTING2
-rw-r--r--getfattr/Makefile51
-rw-r--r--getfattr/getfattr.c422
-rw-r--r--getfattr/walk_tree.c94
-rw-r--r--getfattr/walk_tree.h18
-rw-r--r--include/Makefile6
-rw-r--r--include/attr_kern.h65
-rw-r--r--include/attributes.h125
-rw-r--r--include/xattr.h76
-rw-r--r--libattr/Makefile15
-rw-r--r--libattr/attr.c319
-rw-r--r--libattr/libattr.c249
-rw-r--r--libattr/syscalls.c167
-rw-r--r--man/Makefile2
-rw-r--r--man/man1/attr.165
-rw-r--r--man/man1/getfattr.1129
-rw-r--r--man/man1/setfattr.171
-rw-r--r--man/man2/attrctl.2350
-rw-r--r--man/man2/getxattr.2123
-rw-r--r--man/man2/listxattr.2137
-rw-r--r--man/man2/removexattr.291
-rw-r--r--man/man2/setxattr.2126
-rw-r--r--man/man3/attr_get.38
-rw-r--r--man/man3/attr_list.3269
-rw-r--r--man/man3/attr_multi.36
-rw-r--r--man/man3/attr_remove.38
-rw-r--r--man/man3/attr_set.38
-rw-r--r--man/man5/Makefile48
-rw-r--r--man/man5/attr.5110
-rw-r--r--setfattr/Makefile50
-rw-r--r--setfattr/setfattr.c425
-rw-r--r--test/Makefile44
-rw-r--r--test/README9
-rw-r--r--test/attr.test78
-rw-r--r--test/run145
45 files changed, 2831 insertions, 1254 deletions
diff --git a/Makefile b/Makefile
index d239aff..7b96fda 100644
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,7 @@ LSRCFILES = configure configure.in Makepkgs install-sh README VERSION
LDIRT = config.log config.status config.cache confdefs.h conftest* \
Logs/* built .census install.* install-dev.* *.gz
-SUBDIRS = include libattr attr man doc debian build
+SUBDIRS = include libattr attr getfattr setfattr test man doc debian build
default: $(CONFIGURE)
ifeq ($(HAVE_BUILDDEFS), no)
diff --git a/README b/README
index c60b176..a07e36b 100644
--- a/README
+++ b/README
@@ -4,9 +4,13 @@ _________________________________
See the file doc/INSTALL for build, installation and post-
install configuration steps.
-Refer to the attr(1) manual page for general extended attribute
+Refer to the attr(5) manual page for general extended attribute
(EA) information and references to other EA manual pages.
+Complete information on the extended attributes project for the
+ext2 and ext3 filesystems, refer to:
+ http://acl.bestbits.at/
+
For more information and details on how to contribute to the
XFS project see the web pages at:
http://oss.sgi.com/projects/xfs/
diff --git a/VERSION b/VERSION
index 0422c97..9467406 100644
--- a/VERSION
+++ b/VERSION
@@ -1,7 +1,7 @@
#
# This file is used by configure to get version information
#
-PKG_MAJOR=1
-PKG_MINOR=1
-PKG_REVISION=4
+PKG_MAJOR=2
+PKG_MINOR=0
+PKG_REVISION=0
PKG_BUILD=0
diff --git a/attr/attr.c b/attr/attr.c
index 9a8d9a6..280ded1 100644
--- a/attr/attr.c
+++ b/attr/attr.c
@@ -30,7 +30,6 @@
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
-
#include <asm/types.h>
#include <sys/types.h>
#include <sys/param.h>
@@ -47,7 +46,6 @@
#define SETOP 1 /* do a SET operation */
#define GETOP 2 /* do a GET operation */
#define REMOVEOP 3 /* do a REMOVE operation */
-#define LISTOP 4 /* do a LIST operation */
static char *progname;
@@ -58,21 +56,17 @@ usage(void)
"Usage: %s [-LRq] -s attrname [-V attrvalue] pathname # set value\n"
" %s [-LRq] -g attrname pathname # get value\n"
" %s [-LRq] -r attrname pathname # remove attr\n"
-" %s [-LRq] -l pathname # list attrs\n"
" -s reads a value from stdin and -g writes a value to stdout\n",
- progname, progname, progname, progname);
+ progname, progname, progname);
exit(1);
}
int
main(int argc, char **argv)
{
- char *attrname, *attrvalue, *filename, *buffer;
+ char *attrname, *attrvalue, *filename;
int attrlength;
- int opflag, ch, error, follow, verbose, rootflag, i;
- attrlist_t *alist;
- attrlist_ent_t *aep;
- attrlist_cursor_t cursor;
+ int opflag, ch, error, follow, verbose, rootflag;
progname = basename(argv[0]);
@@ -82,12 +76,12 @@ main(int argc, char **argv)
verbose = 1;
follow = opflag = rootflag = 0;
attrname = attrvalue = NULL;
- while ((ch = getopt(argc, argv, "s:V:g:r:lqLR")) != EOF) {
+ while ((ch = getopt(argc, argv, "s:V:g:r:qLR")) != EOF) {
switch (ch) {
case 's':
if ((opflag != 0) && (opflag != SETOP)) {
fprintf(stderr,
- "Only one of -s, -g, -r, or -l allowed\n");
+ "Only one of -s, -g, or -r allowed\n");
usage();
}
opflag = SETOP;
@@ -105,7 +99,7 @@ main(int argc, char **argv)
case 'g':
if (opflag) {
fprintf(stderr,
- "Only one of -s, -g, -r, or -l allowed\n");
+ "Only one of -s, -g, or -r allowed\n");
usage();
}
opflag = GETOP;
@@ -114,20 +108,12 @@ main(int argc, char **argv)
case 'r':
if (opflag) {
fprintf(stderr,
- "Only one of -s, -g, -r, or -l allowed\n");
+ "Only one of -s, -g, or -r allowed\n");
usage();
}
opflag = REMOVEOP;
attrname = optarg;
break;
- case 'l':
- if (opflag) {
- fprintf(stderr,
- "Only one of -s, -g, -r, or -l allowed\n");
- usage();
- }
- opflag = LISTOP;
- break;
case 'L':
follow++;
break;
@@ -223,44 +209,9 @@ main(int argc, char **argv)
}
break;
- case LISTOP:
- if ((buffer = malloc(ATTR_MAX_VALUELEN)) == NULL) {
- perror("malloc");
- exit(1);
- }
-
- memset((char *)&cursor, 0, sizeof(cursor));
-
- do {
- error = attr_list(filename, buffer, ATTR_MAX_VALUELEN,
- (!follow ? ATTR_DONTFOLLOW : 0) |
- (rootflag ? ATTR_ROOT : 0),
- &cursor);
- if (error) {
- perror("attr_list");
- fprintf(stderr, "Could not list attributes for %s\n",
- filename);
- exit(1);
- }
-
- alist = (attrlist_t *)buffer;
- for (i = 0; i < alist->al_count; i++) {
- aep = (attrlist_ent_t *)&buffer[ alist->al_offset[i] ];
- if (verbose) {
- printf("Attribute \"%s\" has a %d byte value for %s\n",
- aep->a_name,
- aep->a_valuelen,
- filename);
- } else {
- printf("%s\n", aep->a_name);
- }
- }
- } while (alist->al_more);
- break;
-
default:
fprintf(stderr,
- "At least one of -s, -g, -r, or -l is required\n");
+ "At least one of -s, -g, or -r is required\n");
usage();
break;
}
diff --git a/build/rpm/attr.spec.in b/build/rpm/attr.spec.in
index c9d4990..e14e7cc 100644
--- a/build/rpm/attr.spec.in
+++ b/build/rpm/attr.spec.in
@@ -1,4 +1,4 @@
-Summary: Utility for managing filesystem extended attributes.
+Summary: Utilities for managing filesystem extended attributes.
Name: @pkg_name@
Version: @pkg_version@
Release: @pkg_release@
@@ -6,6 +6,7 @@ Distribution: @pkg_distribution@
Packager: @pkg_builder@
BuildRoot: @build_root@
Prereq: /sbin/ldconfig
+Conflicts: xfsdump < 2.0.0
Source: @pkg_name@-@pkg_version@.src.tar.gz
Copyright: Copyright (C) 2000 Silicon Graphics, Inc.
Vendor: Silicon Graphics, Inc.
@@ -13,23 +14,25 @@ URL: http://oss.sgi.com/projects/xfs/
Group: System Environment/Base
%description
-A utility for manipulating extended attributes on filesystem
-objects, compatible with the SGI IRIX tool of the same name.
+A set of tools for manipulating extended attributes on filesystem
+objects, in particular getfattr(1) and setfattr(1).
+An attr(1) command is also provided which is largely compatible
+with the SGI IRIX tool of the same name.
%package devel
Summary: Extended attribute static libraries and headers.
Group: Development/Libraries
-Requires: @pkg_name@
+Requires: @pkg_name@ >= 2.0.0
%description devel
attr-devel contains the libraries and header files needed to
-develop programs which make use of extended attributes. This
-interface is compatible with the SGI IRIX extended attribute
-interface, and makes use of an unofficial Linux system call.
+develop programs which make use of extended attributes.
+For Linux programs, the documented system call API is the
+recommended interface, but an SGI IRIX compatibility interface
+is also provided.
-Currently only XFS is supported, and the (experimental, unofficial)
-system call interface is likely to change in the future. However,
-the API built above this system call is unlikely to change and is
+Currently only ext2, ext3 and XFS support extended attributes.
+The SGI IRIX compatibility API built above the Linux system calls is
used by programs such as xfsdump(8), xfsrestore(8) and xfs_fsr(8).
You should install attr-devel if you want to develop programs
diff --git a/debian/changelog b/debian/changelog
index e607335..6a93561 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,10 @@
-attr (1.1.4-1) unstable; urgency=low
+attr (2.0.0-1) unstable; urgency=low
- * Bug fix in attr_multi(3), use of "count" parameter was broken
+ * Major new upstream release
+ * Several system call changes - THIS WILL NOT WORK WITH OLD KERNELS!
+ * Uses the new shared ext2/ext3/XFS extended attributes interfaces
- -- Nathan Scott <nathans@debian.org> Fri, 11 Jan 2002 08:43:58 +1100
+ -- Nathan Scott <nathans@debian.org> Thu, 7 Feb 2002 13:25:26 +1100
attr (1.1.3-0) unstable; urgency=low
diff --git a/debian/control b/debian/control
index 09a5e22..b4bb381 100644
--- a/debian/control
+++ b/debian/control
@@ -7,24 +7,26 @@ Standards-Version: 3.5.5
Package: attr
Depends: ${shlibs:Depends}
+Conflicts: xfsdump (<< 2.0.0)
Architecture: any
-Description: Utility for manipulating filesystem extended attributes
- A utility for manipulating extended attributes on filesystem
- objects, compatible with the SGI IRIX tool of the same name.
+Description: Utilities for manipulating filesystem extended attributes
+ A set of tools for manipulating extended attributes on filesystem
+ objects, in particular getfattr(1) and setfattr(1).
+ An attr(1) command is also provided which is largely compatible
+ with the SGI IRIX tool of the same name.
Package: attr-dev
Section: devel
Priority: extra
-Depends: libc6-dev, attr
+Depends: libc6-dev, attr (>= 2.0.0)
+Conflicts: attr (<< 2.0.0)
Architecture: any
-Description: Extended attribute static libraries and headers.
+Description: Extended attribute static libraries and headers
attr-dev contains the libraries and header files needed to develop
- programs which make use of extended attributes.
+ programs which make use of extended attributes. For Linux programs,
+ the documented system call API is the recommended interface, but an
+ SGI IRIX compatibility interface is also provided.
.
- This interface is compatible with the SGI IRIX extended attribute
- interface, and makes use of an unofficial Linux system call.
- .
- Currently only XFS is supported, and the (experimental, unofficial)
- system call interface is likely to change in the future. However,
- the API built above this system call is unlikely to change and is
+ Currently only ext2, ext3 and XFS support extended attributes.
+ The SGI IRIX compatibility API built above the Linux system calls is
used by programs such as xfsdump(8), xfsrestore(8) and xfs_fsr(8).
diff --git a/debian/copyright b/debian/copyright
index d956166..2e88adb 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -5,10 +5,15 @@ It can be downloaded from ftp://oss.sgi.com/projects/xfs/download/
Copyright:
-Copyright (C) 2000 Silicon Graphics, Inc.
+Copyright (C) 2001 Silicon Graphics, Inc.
+Copyright (C) 2001 Andreas Gruenbacher.
-You are free to distribute this software under the terms of
-the GNU General Public License.
+You are free to distribute this software under Version 2.1
+of the GNU Lesser General Public License.
+On Debian systems, refer to /usr/share/common-licenses/LGPL-2.1
+for the complete text of the GNU Lesser General Public License.
+
+Certain components (as annotated in the source) are licensed
+under the terms of the GNU General Public License.
On Debian systems, the complete text of the GNU General Public
License can be found in /usr/share/common-licenses/GPL file.
-
diff --git a/doc/CHANGES b/doc/CHANGES
index 5a5e060..2b1b111 100644
--- a/doc/CHANGES
+++ b/doc/CHANGES
@@ -1,20 +1,23 @@
-attr-1.1.4 (11 Jan 2002)
- - bug fix in attr_multi(3), use of "count" was broken
+attr-2.0.0 (07 February 2002)
+ - initial introduction of the new system call interface
+ - synced up with the ext2 project, incorporated get/set tools
+ - new man pages for system calls, getfattr(1) and setfattr(1)
+ - made the attributes.h interface align properly with IRIX
-attr-1.1.3 (03 Aug 2001)
+attr-1.1.3 (03 August 2001)
- bug fix from Juer Lee, syscall use on non-i386 was broken
- tested on PowerPC and i386; code is simpler and works
- install an additional library symlink for ld, so that the
shared lib is always found before the static lib at link time
-attr-1.1.2 (27 Jul 2001)
+attr-1.1.2 (27 July 2001)
- fixes for (hopefully) the last few nits in libtool usage
-attr-1.1.1 (23 Jul 2001)
+attr-1.1.1 (23 July 2001)
- install static libs and libtool archives into /usr/lib
- shared libraries are unchanged, however
-attr-1.1.0 (16 Jul 2001)
+attr-1.1.0 (16 July 2001)
- reworked Makefiles to use libtool
- rework some of the Debian packaging rules
- install attr command into /usr/bin, not /bin
@@ -22,7 +25,7 @@ attr-1.1.0 (16 Jul 2001)
as it is needed by xfsdump and xfsrestore which must
be available for recovery when only root is mounted
-attr-1.0.4 (02 Jul 2001)
+attr-1.0.4 (02 July 2001)
- work around syscall number collision on recent ia64 kernels
attr-1.0.3 (18 May 2001)
diff --git a/doc/COPYING b/doc/COPYING
index a889ebd..d5d18c3 100644
--- a/doc/COPYING
+++ b/doc/COPYING
@@ -1,8 +1,8 @@
-All the libraries in "attr" are licensed under Version 2.1
-of the GNU Lesser General Public License.
+Most components of the "attr" package are licensed under
+Version 2.1 of the GNU Lesser General Public License.
-All other "attr" components are licensed under Version 2 of
-the GNU General Public License.
+Some components (as annotated in the source) are licensed
+under Version 2 of the GNU General Public License.
----------------------------------------------------------------------
diff --git a/doc/PORTING b/doc/PORTING
index 87bedd4..77829c6 100644
--- a/doc/PORTING
+++ b/doc/PORTING
@@ -42,7 +42,7 @@
example using SUBDIRS : attr/Makefile
example static library: attr/libattr/Makefile
- example command : attr/attr/Makefile
+ example command : attr/getfattr/Makefile
All Makefiles must define TOPDIR as the root of the project. This
allows other stuff to be found relative to $(TOPDIR).
diff --git a/getfattr/Makefile b/getfattr/Makefile
new file mode 100644
index 0000000..d474763
--- /dev/null
+++ b/getfattr/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTCOMMAND = getfattr
+CFILES = walk_tree.c getfattr.c
+HFILES = walk_tree.h
+
+LLDLIBS = $(LIBATTR)
+LTDEPENDENCIES = $(LIBATTR)
+
+default: $(LTCOMMAND)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 -d $(PKG_BIN_DIR)
+ $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
+ $(INSTALL) -S $(LTCOMMAND) $(PKG_BIN_DIR)/aget
+install-dev:
diff --git a/getfattr/getfattr.c b/getfattr/getfattr.c
new file mode 100644
index 0000000..bd642cf
--- /dev/null
+++ b/getfattr/getfattr.c
@@ -0,0 +1,422 @@
+/*
+ * Original getfattr.c:
+ * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+ * Changes to use revised EA syscall interface:
+ * Copyright (C) 2001 by SGI XFS development <linux-xfs@oss.sgi.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <regex.h>
+#include <xattr.h>
+#include "walk_tree.h"
+
+#include <locale.h>
+#include <libintl.h>
+#define _(String) gettext (String)
+
+#define CMD_LINE_OPTIONS "ade:hln:r:svR5LPV"
+#define CMD_LINE_SPEC "[-n name|-d] [-ahsvR5LPV] [-e en] [-r regex] path..."
+
+int opt_dump;
+int opt_symlink;
+char *opt_encoding;
+char opt_value_only;
+int opt_strip_leading_slash = 1;
+
+const char *progname;
+int absolute_warning;
+int header_printed;
+int had_errors;
+regex_t re;
+
+int do_get_all(const char *, struct stat *, void *);
+int do_get_one(const char *, struct stat *, void *);
+int get_one(const char *, const char *);
+const char *encode(const char *value, size_t *size);
+
+
+void help(void)
+{
+ printf(_("%s %s -- get extended attributes\n"),
+ progname, VERSION);
+ printf(_("Usage: %s %s\n"),
+ progname, CMD_LINE_SPEC);
+ printf(_("\t-n name\tdump value of extended attribute `name'\n"
+ "\t-a\tabsolute pathnames - leading '/' not stripped\n"
+ "\t-d\tdump all extended attribute values\n"
+ "\t-e en\tencode values (en = text|hex|base64)\n"
+ "\t-l\tdump extended attribute values of a symlink\n"
+ "\t-s\tdump extended system and user attribute values\n"
+ "\t-v\tprint the attribute value(s) only\n"
+ "\t-R\trecurse into subdirectories (-5 = post-order)\n"
+ "\t-L\tlogical walk, follow symbolic links\n"
+ "\t-P\tphysical walk, do not follow symbolic links\n"
+ "\t-V\tprint version and exit\n"
+ "\t-h\tthis help text\n"));
+}
+
+int main(int argc, char *argv[])
+{
+ char sys_pattern[] = "^system\\.|^user\\.";
+ char usr_pattern[] = "^user\\.";
+ char *pattern = usr_pattern;
+ char *name = NULL;
+
+ progname = basename(argv[0]);
+ setlocale(LC_ALL, "");
+
+ while ((optopt = getopt(argc, argv, CMD_LINE_OPTIONS)) != -1) {
+ switch(optopt) {
+ case 'a': /* absolute names */
+ opt_strip_leading_slash = 0;
+ break;
+
+ case 'd': /* dump attribute values */
+ opt_dump = 1;
+ break;
+
+ case 'e': /* encoding */
+ if (strcmp(optarg, "text") != 0 &&
+ strcmp(optarg, "hex") != 0 &&
+ strcmp(optarg, "base64") != 0)
+ goto synopsis;
+ opt_encoding = optarg;
+ break;
+
+ case 'h':
+ help();
+ return 0;
+
+ case 'l': /* dump attribute(s) of symlink itself */
+ opt_symlink = 1;
+ break;
+
+ case 'n': /* get named attribute */
+ opt_dump = 1;
+ name = optarg;
+ break;
+
+ case 'r':
+ pattern = optarg;
+ break;
+
+ case 's':
+ pattern = sys_pattern;
+ break;
+
+ case 'v': /* get attribute values only */
+ opt_value_only = 1;
+ break;
+
+ case 'H':
+ walk_symlinks = WALK_HALF_LOGICAL;
+ break;
+
+ case 'L':
+ walk_symlinks = WALK_FULL_LOGICAL;
+ break;
+
+ case 'P':
+ walk_symlinks = WALK_PHYSICAL;
+ break;
+
+ case 'R':
+ walk_recurse = 1;
+ walk_postorder = 0;
+ break;
+
+ case '5':
+ walk_recurse = 1;
+ walk_postorder = 1;
+ break;
+
+ case 'V':
+ printf("%s " VERSION "\n", progname);
+ return 0;
+
+ default:
+ goto synopsis;
+ }
+ }
+ if (optind >= argc)
+ goto synopsis;
+
+ if (regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB) != 0) {
+ fprintf(stderr, _("%s: invalid regular expression \"%s\"\n"),
+ progname, pattern);
+ return 1;
+ }
+
+ while (optind < argc) {
+ if (name)
+ had_errors += walk_tree(argv[optind], do_get_one, name);
+ else
+ had_errors += walk_tree(argv[optind], do_get_all, NULL);
+ optind++;
+ }
+
+ return (had_errors ? 1 : 0);
+
+synopsis:
+ fprintf(stderr, _("Usage: %s %s\n"
+ "Try `%s -h' for more information.\n"),
+ progname, CMD_LINE_SPEC, progname);
+ return 2;
+}
+
+int do_getxattr(const char *path, const char *name, void *value, size_t size)
+{
+ if (opt_symlink)
+ return lgetxattr(path, name, value, size);
+ return getxattr(path, name, value, size);
+}
+
+int do_listxattr(const char *path, char *list, size_t size)
+{
+ if (opt_symlink)
+ return llistxattr(path, list, size);
+ return listxattr(path, list, size);
+}
+
+int pstrcmp(const char **a, const char **b)
+{
+ return strcmp(*a, *b);
+}
+
+int do_get_all(const char *path, struct stat *stat, void *dummy)
+{
+ /* nathans TODO - use a high-water-mark allocation here! */
+ char *v;
+ char *list; /* ie. make list & lbufsize "static" & realloc */
+ int n = 0, count = 0;
+ ssize_t listsize, lbufsize;
+ const char **names = NULL;
+
+ lbufsize = do_listxattr(path, NULL, 0);
+ if (lbufsize < 0) {
+ if (errno != ENOATTR && errno != ENOTSUP) {
+ perror(path);
+ had_errors++;
+ return 1;
+ }
+ } else {
+ /* nathans TODO - use a high-water-mark allocation here! */
+ list = malloc(++lbufsize);
+ if (!list) {
+ perror(progname);
+ had_errors++;
+ return 1;
+ }
+ memset(list, 0, lbufsize);
+ listsize = do_listxattr(path, list, lbufsize - 1);
+ if (listsize < 0) {
+ perror(path);
+ had_errors++;
+ return 1;
+ }
+
+ for (v = list; v - list <= listsize; v += strlen(v)+1)
+ if (regexec(&re, v, (size_t) 0, NULL, 0) == 0)
+ count++;
+ if (count) {
+ names = (const char **)malloc(count * sizeof(char *));
+ if (!names) {
+ perror(progname);
+ had_errors++;
+ return 1;
+ }
+ for (v = list; v - list <= listsize; v += strlen(v)+1)
+ if (regexec(&re, v, (size_t) 0, NULL, 0) == 0)
+ names[n++] = v;
+ qsort(names, count, sizeof(char *),
+ (int (*)(const void *,const void *))pstrcmp);
+ }
+ }
+ if (names) {
+ header_printed = 0;
+ for (n = 0; n < count; n++)
+ get_one(path, names[n]);
+ if (header_printed)
+ puts("");
+ }
+ return 0;
+}
+
+int do_get_one(const char *path, struct stat *stat, void *name)
+{
+ int error;
+
+ header_printed = 0;
+ error = get_one(path, (const char *)name);
+ if (header_printed)
+ puts("");
+ return error;
+}
+
+int get_one(const char *path, const char *name)
+{
+ char *value = NULL;
+ size_t size = 0;
+ int error;
+
+ if (opt_dump || opt_value_only) {
+ error = do_getxattr(path, name, NULL, 0);
+ if (error < 0) {
+ const char *strerr;
+syscall_failed:
+ if (!strncmp("system.", name, 7) && errno == ENOATTR)
+ return 0; /* expected */
+ else if (errno == ENOATTR)
+ strerr = _("No such attribute");
+ else
+ strerr = strerror(errno);
+ fprintf(stderr, "%s: %s: %s\n", path, name, strerr);
+ return 1;
+ }
+ /* nathans TODO - high-water-mark allocate here too? */
+ size = error;
+ value = (char *)malloc(size+1);
+ if (!value) {
+ perror(progname);
+ return 1;
+ }
+ error = do_getxattr(path, name, value, size);
+ if (error < 0)
+ goto syscall_failed;
+ value[size] = '\0';
+ size = error;
+ }
+
+ if (opt_strip_leading_slash) {
+ if (*path == '/') {
+ if (!absolute_warning) {
+ fprintf(stderr, _("%s: Removing leading '/' "
+ "from absolute path names\n"),
+ progname);
+ absolute_warning = 1;
+ }
+ while (*path == '/')
+ path++;
+ } else if (*path == '.' && *(path+1) == '/')
+ while (*++path == '/')
+ /* nothing */ ;
+ if (*path == '\0')
+ path = ".";
+ }
+
+ if (!header_printed && !opt_value_only) {
+ printf("# file: %s\n", path);
+ header_printed = 1;
+ }
+ if (opt_value_only)
+ puts(value);
+ else if (size) {
+ const char *e = encode(value, &size);
+
+ if (e)
+ printf("%s=%s\n", name, e);
+ } else
+ puts(name);
+
+ return 0;
+}
+
+const char *encode(const char *value, size_t *size)
+{
+ static char *encoded = NULL, *e;
+
+ if (encoded)
+ free(encoded);
+ if (opt_encoding == NULL || strcmp(opt_encoding, "text") == 0) {
+ int n, extra = 0;
+
+ for (e=(char *)value; e < value + *size; e++) {
+ if (*e < 32 || *e >= 127)
+ extra += 4;
+ else if (*e == '\\' || *e == '"')
+ extra++;
+ }
+ encoded = (char *)malloc(*size + extra + 3);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='"';
+ for (n = 0; n < *size; n++, value++) {
+ if (*value < 32 || *value >= 127) {
+ *e++ = '\\';
+ *e++ = '0' + ((unsigned char)*value >> 6);
+ *e++ = '0' + (((unsigned char)*value & 070) >> 3);
+ *e++ = '0' + ((unsigned char)*value & 07);
+ } else if (*value == '\\' || *value == '"') {
+ *e++ = '\\';
+ *e++ = *value;
+ } else {
+ *e++ = *value;
+ }
+ }
+ *e++ = '"';
+ *e = '\0';
+ *size = (e - encoded);
+ } else if (strcmp(opt_encoding, "hex") == 0) {
+ static const char *digits = "0123456789abcdef";
+ int n;
+
+ encoded = (char *)malloc(*size * 2 + 4);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='0'; *e++ = 'x';
+ for (n = 0; n < *size; n++, value++) {
+ *e++ = digits[((unsigned char)*value >> 4)];
+ *e++ = digits[((unsigned char)*value & 0x0F)];
+ }
+ *e = '\0';
+ *size = (e - encoded);
+ } else if (strcmp(opt_encoding, "base64") == 0) {
+ static const char *digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
+ "ghijklmnopqrstuvwxyz0123456789+/";
+ int n;
+
+ encoded = (char *)malloc((*size + 2) / 3 * 4 + 1);
+ if (!encoded) {
+ perror(progname);
+ had_errors++;
+ return NULL;
+ }
+ e = encoded;
+ *e++='0'; *e++ = 's';
+ for (n=0; n + 2 < *size; n += 3) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[(((unsigned char)value[0] & 0x03) << 4) |
+ (((unsigned char)value[1] & 0xF0) >> 4)];
+ *e++ = digits[(((unsigned char)value[1] & 0x0F) << 2) |
+ ((unsigned char)value[2] >> 6)];
+ *e++ = digits[(unsigned char)value[2] & 0x3F];
+ value += 3;
+ }
+ if (*size - n == 2) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[(((unsigned char)value[0] & 0x03) << 4) |
+ (((unsigned char)value[1] & 0xF0) >> 4)];
+ *e++ = digits[((unsigned char)value[1] & 0x0F) << 2];
+ *e++ = '=';
+ } else if (*size - n == 1) {
+ *e++ = digits[(unsigned char)value[0] >> 2];
+ *e++ = digits[((unsigned char)value[0] & 0x03) << 4];
+ *e++ = '=';
+ *e++ = '=';
+ }
+ *e = '\0';
+ *size = (e - encoded);
+ }
+ return encoded;
+}
diff --git a/getfattr/walk_tree.c b/getfattr/walk_tree.c
new file mode 100644
index 0000000..468fef4
--- /dev/null
+++ b/getfattr/walk_tree.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+ *
+ * TODO: should this be replaced by using nftw(3)?
+ */
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "walk_tree.h"
+
+int walk_recurse = 0;
+int walk_postorder = 0;
+int walk_symlinks = WALK_HALF_LOGICAL;
+
+int walk_tree(const char *path_p, int (*call)(const char *, struct stat *,
+ void *), void *arg)
+{
+ static struct stat st;
+ static int level = 0;
+ int follow;
+ int errors = 0;
+
+ level++;
+ if (lstat(path_p, &st) != 0)
+ goto fail;
+
+ if (S_ISLNK(st.st_mode)) {
+ if (walk_symlinks == WALK_PHYSICAL)
+ follow = 0;
+ else {
+ if (stat(path_p, &st) != 0)
+ goto fail;
+ follow = ((walk_symlinks == WALK_HALF_LOGICAL &&
+ level == 1) ||
+ walk_symlinks == WALK_FULL_LOGICAL);
+ }
+ } else
+ follow = 1;
+
+ if (!follow)
+ goto cleanup;
+
+ if (!walk_postorder)
+ errors += call(path_p, &st, arg);
+
+ if (walk_recurse && S_ISDIR(st.st_mode)) {
+ struct dirent *dirent;
+ DIR *dir;
+
+ char *ipath_p = (char *)path_p;
+ int ipath_length = strlen(ipath_p);
+ if (ipath_p[ipath_length-1] != '/') {
+ ipath_p = (char*)alloca(ipath_length +
+ _POSIX_PATH_MAX + 2);
+ if (ipath_p == NULL)
+ goto fail;
+ strcpy(ipath_p, path_p);
+ strcpy(ipath_p + ipath_length, "/");
+ ipath_length++;
+ }
+
+ dir = opendir(path_p);
+ if (dir == NULL)
+ goto fail;
+ while ((dirent = readdir(dir)) != NULL) {
+ if (!strcmp(dirent->d_name, ".") ||
+ !strcmp(dirent->d_name, ".."))
+ continue;
+ strncpy(ipath_p + ipath_length,
+ dirent->d_name, _POSIX_PATH_MAX);
+ ipath_p[ipath_length + _POSIX_PATH_MAX] = '\0';
+ walk_tree(ipath_p, call, arg); /* recurse */
+ }
+ ipath_p[ipath_length] = '\0';
+ closedir(dir);
+ }
+
+ if (walk_postorder)
+ errors += call(path_p, &st, arg);
+
+cleanup:
+ level--;
+ return errors;
+
+fail:
+ fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno));
+ errors++;
+ goto cleanup;
+}
+
diff --git a/getfattr/walk_tree.h b/getfattr/walk_tree.h
new file mode 100644
index 0000000..c84c742
--- /dev/null
+++ b/getfattr/walk_tree.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+ *
+ * TODO: should this be replaced by using nftw(3)?
+ */
+#include <sys/stat.h>
+
+extern const char *progname;
+
+#define WALK_FULL_LOGICAL 1 /* follow all symlinks */
+#define WALK_HALF_LOGICAL 2 /* follow symlink arguments */
+#define WALK_PHYSICAL 3 /* don't follow symlinks */
+
+extern int walk_recurse; /* recurse into sudirectories */
+extern int walk_postorder; /* walk tree in postorder */
+extern int walk_symlinks; /* follow symbolic links */
+
+int walk_tree(const char *, int (*call)(const char *, struct stat *, void *), void *);
diff --git a/include/Makefile b/include/Makefile
index 677e83e..ef299b7 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
@@ -33,8 +33,8 @@
TOPDIR = ..
include $(TOPDIR)/include/builddefs
-HFILES = attributes.h
-LSRCFILES = builddefs.in buildrules attr_kern.h
+HFILES = attributes.h xattr.h
+LSRCFILES = builddefs.in buildrules
default install :
diff --git a/include/attr_kern.h b/include/attr_kern.h
deleted file mode 100644
index 3be50b9..0000000
--- a/include/attr_kern.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __ATTR_KERN_H__
-#define __ATTR_KERN_H__
-
-/*
- * The (experimental) Linux generic attribute syscall - attrctl(2)
- */
-
-typedef union attr_obj {
- char *path;
- int fd;
- pid_t pid;
-} attr_obj_t;
-
-/*
- * attr_obj_t type identifiers
- */
-#define ATTR_TYPE_FD 1 /* file descriptor */
-#define ATTR_TYPE_PATH 2 /* path - follow symlinks */
-#define ATTR_TYPE_LPATH 3 /* path - don't follow symlinks */
-#define ATTR_TYPE_PID 4 /* process id */
-
-/*
- * Kernel-internal version of the attrlist cursor.
- */
-typedef struct attrlist_cursor_kern {
- __u32 hashval; /* hash value of next entry to add */
- __u32 blkno; /* block containing entry (suggestion)*/
- __u32 offset; /* offset in list of equal-hashvals */
- __u16 pad1; /* padding to match user-level */
- __u8 pad2; /* padding to match user-level */
- __u8 initted; /* T/F: cursor has been initialized */
-} attrlist_cursor_kern_t;
-
-#endif /* __ATTR_KERN_H__ */
diff --git a/include/attributes.h b/include/attributes.h
index f8e42a1..2912cba 100644
--- a/include/attributes.h
+++ b/include/attributes.h
@@ -1,33 +1,33 @@
/*
- * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved.
- *
+ * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2.1 of the GNU Lesser General Public License
* as published by the Free Software Foundation.
- *
+ *
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
+ *
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
* USA.
- *
+ *
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#ifndef __ATTRIBUTES_H__
@@ -38,63 +38,33 @@ extern "C" {
#endif
/*
- * An IRIX-compatible extended attributes API
+ * An almost-IRIX-compatible extended attributes API
+ * (the IRIX attribute "list" operation is missing).
*/
/*
- * Valid command flags, may be used with all API calls.
- * Multiple flags should be bitwise OR'ed together.
- */
-#define ATTR_ROOT 0x0001 /* use attrs in root namespace, not user */
-#define ATTR_CREATE 0x0002 /* pure create: fail if attr already exists */
-#define ATTR_REPLACE 0x0004 /* pure set: fail if attr does not exist */
-#define ATTR_SHIFT 16 /* for supporting extensions */
-
-/*
- * Additional API specific opcodes & flags
+ * The maximum size (into the kernel or returned from the kernel) of an
+ * attribute value or the buffer used for an attr_list() call. Larger
+ * sizes will result in an E2BIG return code.
*/
-#define ATTR_DONTFOLLOW (0x0001 << ATTR_SHIFT) /* do not follow symlinks */
-#define ATTR_TRUST (0x0002 << ATTR_SHIFT)
- /* tell server we are trusted to properly handle extended attributes */
-
-#define ATTR_KERNOTIME (0x0004 << ATTR_SHIFT)
- /* don't update inode timestamps.
- * The DMI needs a way to update attributes without affecting the
- * inode timestamps. Note that this flag is not set-able from user
- * mode - it is kernel internal only, but it must not conflict with
- * the user flags either.
- */
+#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
-/*
- * Generic extended attribute operation structure
- */
-typedef struct attr_op {
- int opcode; /* which operation to perform */
- int error; /* result (an errno) of this operation [out] */
- char *name; /* attribute name */
- char *value; /* attribute value [in/out] */
- int length; /* value length [in/out] */
- int flags; /* bitwise OR of #defines below */
- void *aux; /* optional cmd specific data */
-} attr_op_t;
/*
- * Valid attr_op, attr_multi_op opcodes
+ * Flags that can be used with any of the simple attribute calls.
+ * All desired flags should be bit-wise OR'ed together.
*/
-#define ATTR_OP_GET 1 /* return the indicated attr's value */
-#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
-#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
-#define ATTR_OP_LIST 4 /* list attributes associated with a file */
-
-#define ATTR_OP_EXT 32 /* for supporting extensions */
-#define ATTR_OP_IRIX_LIST (ATTR_OP_EXT + 0) /* IRIX attr_list semantics */
+#define ATTR_DONTFOLLOW 0x0001 /* do not follow symlinks for a pathname */
+#define ATTR_ROOT 0x0002 /* use root-defined attrs in op, not user */
+#define ATTR_TRUST 0x0004 /* tell server we can be trusted to properly
+ handle extended attributes */
/*
- * The maximum size (into the kernel or returned from the kernel) of an
- * attribute value or the buffer used for an attr_list() call. Larger
- * sizes will result in an E2BIG return code.
+ * Additional flags that can be used with the set() attribute call.
+ * All desired flags (from both lists) should be bit-wise OR'ed together.
*/
-#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
+#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
+#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
/*
* Define how lists of attribute names are returned to the user from
@@ -103,9 +73,9 @@ typedef struct attr_op {
* reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
*/
typedef struct attrlist {
- __s32 al_count; /* number of entries in attrlist */
- __s32 al_more; /* T/F: more attrs (do call again) */
- __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
+ int32_t al_count; /* number of entries in attrlist */
+ int32_t al_more; /* T/F: more attrs (do call again) */
+ int32_t al_offset[1]; /* byte offsets of attrs [var-sized] */
} attrlist_t;
/*
@@ -113,8 +83,8 @@ typedef struct attrlist {
* al_offset[i] entry points to.
*/
typedef struct attrlist_ent { /* data from attr_list() */
- __u32 a_valuelen; /* number bytes in value of attr */
- char a_name[1]; /* attr name (NULL terminated) */
+ u_int32_t a_valuelen; /* number bytes in value of attr */
+ char a_name[1]; /* attr name (NULL terminated) */
} attrlist_ent_t;
/*
@@ -125,7 +95,6 @@ typedef struct attrlist_ent { /* data from attr_list() */
((attrlist_ent_t *) \
&((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
-
/*
* Implement a "cursor" for use in successive attr_list() calls.
* It provides a way to find the last attribute that was returned in the
@@ -135,23 +104,30 @@ typedef struct attrlist_ent { /* data from attr_list() */
* operation on a cursor is to bzero() it.
*/
typedef struct attrlist_cursor {
- __u32 opaque[4]; /* an opaque cookie */
+ u_int32_t opaque[4]; /* an opaque cookie */
} attrlist_cursor_t;
/*
* Multi-attribute operation vector.
*/
typedef struct attr_multiop {
- int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */
- int am_error; /* [out arg] result of this sub-op (an errno) */
+ int32_t am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */
+ int32_t am_error; /* [out arg] result of this sub-op (an errno) */
char *am_attrname; /* attribute name to work with */
char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */
- int am_length; /* [in/out arg] length of value */
- int am_flags; /* bitwise OR of attr API flags defined above */
+ int32_t am_length; /* [in/out arg] length of value */
+ int32_t am_flags; /* flags (bit-wise OR of #defines above) */
} attr_multiop_t;
#define ATTR_MAX_MULTIOPS 128 /* max number ops in an oplist array */
/*
+ * Valid values of am_opcode.
+ */
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+
+/*
* Get the value of an attribute.
* Valuelength must be set to the maximum size of the value buffer, it will
* be set to the actual number of bytes used in the value buffer upon return.
@@ -182,19 +158,6 @@ extern int attr_remove (const char *__path, const char *__attrname,
extern int attr_removef (int __fd, const char *__attrname, int __flags);
/*
- * List the names and sizes of the values of all the attributes of an object.
- * "Cursor" must be allocated and zeroed before the first call, it is used
- * to maintain context between system calls if all the attribute names won't
- * fit into the buffer on the first system call.
- * The return value is -1 on error (w/errno set appropriately), 0 on success.
- */
-extern int attr_list (const char *__path, char *__buffer,
- const int __buffersize, int __flags,
- attrlist_cursor_t *__cursor);
-extern int attr_listf (int __fd, char *__buffer, const int __buffersize,
- int __flags, attrlist_cursor_t *__cursor);
-
-/*
* Operate on multiple attributes of the same object simultaneously.
*
* This call will save on system call overhead when many attributes are
diff --git a/include/xattr.h b/include/xattr.h
new file mode 100644
index 0000000..c90be39
--- /dev/null
+++ b/include/xattr.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XATTR_H__
+#define __XATTR_H__
+
+#include <features.h>
+
+#include <errno.h>
+#ifndef ENOATTR
+# define ENOATTR ENODATA /* fallback value until real errno exists */
+#endif
+
+#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
+#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
+
+
+__BEGIN_DECLS
+
+extern int setxattr (const char *__path, const char *__name,
+ void *__value, size_t __size, int __flags) __THROW;
+extern int lsetxattr (const char *__path, const char *__name,
+ void *__value, size_t __size, int __flags) __THROW;
+extern int fsetxattr (int __filedes, const char *__name,
+ void *__value, size_t __size, int __flags) __THROW;
+
+extern ssize_t getxattr (const char *__path, const char *__name,
+ void *__value, size_t __size) __THROW;
+extern ssize_t lgetxattr (const char *__path, const char *__name,
+ void *__value, size_t __size) __THROW;
+extern ssize_t fgetxattr (int __filedes, const char *__name,
+ void *__value, size_t __size) __THROW;
+
+extern ssize_t listxattr (const char *__path, char *__list,
+ size_t __size) __THROW;
+extern ssize_t llistxattr (const char *__path, char *__list,
+ size_t __size) __THROW;
+extern ssize_t flistxattr (int __filedes, char *__list,
+ size_t __size) __THROW;
+
+extern int removexattr (const char *__path, const char *__name) __THROW;
+extern int lremovexattr (const char *__path, const char *__name) __THROW;
+extern int fremovexattr (int __filedes, const char *__name) __THROW;
+
+__END_DECLS
+
+#endif /* __XATTR_H__ */
diff --git a/libattr/Makefile b/libattr/Makefile
index b933e2f..f1b6e58 100644
--- a/libattr/Makefile
+++ b/libattr/Makefile
@@ -2,8 +2,8 @@
# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
-# under the terms of version 2 of the GNU General Public License as
-# published by the Free Software Foundation.
+# under the terms of version 2.1 of the GNU Lesser General Public License
+# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,9 +16,10 @@
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write the Free Software Foundation, Inc., 59
-# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+# USA.
#
# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
# Mountain View, CA 94043, or:
@@ -34,11 +35,11 @@ TOPDIR = ..
include $(TOPDIR)/include/builddefs
LTLIBRARY = libattr.la
-LT_CURRENT = 0
+LT_CURRENT = 1
LT_REVISION = 0
LT_AGE = 0
-CFILES = attr.c
+CFILES = libattr.c syscalls.c
default: $(LTLIBRARY)
diff --git a/libattr/attr.c b/libattr/attr.c
deleted file mode 100644
index f076b67..0000000
--- a/libattr/attr.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <asm/types.h>
-
-#include <attributes.h>
-#include <attr_kern.h>
-
-
-/* Experimental system call interface for Linux */
-static int attrctl(attr_obj_t, int, attr_op_t *, int);
-
-/* Other local function prototypes */
-static int _attr_get(attr_obj_t, int, const char *, char *, int *, int);
-static int _attr_set(attr_obj_t, int, const char *, const char *, const int, int);
-static int _attr_remove(attr_obj_t, int, const char *, int);
-static int _attr_listf(attr_obj_t, int, char *, const int, int,
- attrlist_cursor_t *);
-static int _attr_multif(attr_obj_t, int, attr_multiop_t *, int, int);
-
-
-/*
- * Get the value of an attribute.
- */
-int
-attr_get(const char *path, const char *attrname, char *attrvalue,
- int *valuelength, int flags )
-{
- attr_obj_t obj;
- int follow;
- obj.path = (char *) path;
- follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH;
- return _attr_get(obj, follow, attrname, attrvalue, valuelength, flags);
-}
-
-int
-attr_getf(int fd, const char *attrname, char *attrvalue,
- int *valuelength, int flags )
-{
- attr_obj_t obj;
- obj.fd = fd;
- return _attr_get(obj, ATTR_TYPE_FD, attrname, attrvalue,
- valuelength, flags);
-}
-
-static int
-_attr_get(attr_obj_t obj, int type, const char *attrname, char *attrvalue,
- int *valuelength, int flags)
-{
- attr_op_t op;
- memset(&op, 0, sizeof(attr_op_t));
- op.opcode = ATTR_OP_GET;
- op.name = (char *) attrname;
- op.value = (char *) attrvalue; /* buffer to fill */
- op.length = *valuelength; /* buffer size */
- op.flags = flags;
-
- if (attrctl(obj, type, &op, 1) < 0)
- return -1;
- errno = op.error;
- *valuelength = op.length;
- return (errno ? -1 : 0);
-}
-
-
-/*
- * Set the value of an attribute, creating the attribute if necessary.
- */
-int
-attr_set(const char *path, const char *attrname, const char *attrvalue,
- const int valuelength, int flags)
-{
- attr_obj_t obj;
- int follow;
- obj.path = (char *) path;
- follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH;
- return _attr_set(obj, follow, attrname, attrvalue, valuelength, flags);
-}
-
-int
-attr_setf(int fd, const char *attrname,
- const char *attrvalue, const int valuelength, int flags)
-{
- attr_obj_t obj;
- obj.fd = fd;
- return _attr_set(obj, ATTR_TYPE_FD, attrname, attrvalue,
- valuelength, flags);
-}
-
-static int
-_attr_set(attr_obj_t obj, int type, const char *attrname,
- const char *attrvalue, const int valuelength, int flags)
-{
- attr_op_t op;
- memset(&op, 0, sizeof(attr_op_t));
- op.opcode = ATTR_OP_SET;
- op.name = (char *) attrname;
- op.value = (char *) attrvalue;
- op.length = valuelength;
- op.flags = flags;
-
- if (attrctl(obj, type, &op, 1) < 0)
- return -1;
- errno = op.error;
- return (errno ? -1 : 0);
-}
-
-
-/*
- * Remove an attribute.
- */
-int
-attr_remove(const char *path, const char *attrname, int flags)
-{
- attr_obj_t obj;
- int follow;
- obj.path = (char *) path;
- follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH;
- return _attr_remove(obj, follow, attrname, flags);
-}
-
-int
-attr_removef(int fd, const char *attrname, int flags)
-{
- attr_obj_t obj;
- obj.fd = fd;
- return _attr_remove(obj, ATTR_TYPE_FD, attrname, flags);
-}
-
-static int
-_attr_remove(attr_obj_t obj, int type, const char *attrname, int flags)
-{
- attr_op_t op;
- memset(&op, 0, sizeof(attr_op_t));
- op.opcode = ATTR_OP_REMOVE;
- op.name = (char *) attrname;
- op.flags = flags;
-
- if (attrctl(obj, type, &op, 1) < 0)
- return -1;
- errno = op.error;
- return (errno ? -1 : 0);
-}
-
-
-/*
- * List the names and sizes of the values of all the attributes of an object.
- */
-int
-attr_list(const char *path, char *buffer, const int buffersize,
- int flags, attrlist_cursor_t *cursor)
-{
- attr_obj_t obj;
- int follow;
- obj.path = (char *) path;
- follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH;
- return _attr_listf(obj, follow, buffer, buffersize, flags, cursor);
-}
-
-int
-attr_listf(int fd, char *buffer, const int buffersize,
- int flags, attrlist_cursor_t *cursor)
-{
- attr_obj_t obj;
- obj.fd = fd;
- return _attr_listf(obj, ATTR_TYPE_FD, buffer, buffersize,
- flags, cursor);
-}
-
-static int
-_attr_listf(attr_obj_t obj, int type, char *buffer, const int buffersize,
- int flags, attrlist_cursor_t *cursor)
-{
- attr_op_t op;
- memset(&op, 0, sizeof(attr_op_t));
- op.opcode = ATTR_OP_IRIX_LIST;
- op.value = (char *) buffer;
- op.length = buffersize;
- op.flags = flags;
- op.aux = cursor;
-
- if (attrctl(obj, type, &op, 1) < 0)
- return -1;
- errno = op.error;
- return (errno ? -1 : 0);
-}
-
-/*
- * Operate on multiple attributes of the same object simultaneously
- */
-int
-attr_multi(const char *path, attr_multiop_t *multiops, int count, int flags)
-{
- attr_obj_t obj;
- int follow;
- obj.path = (char *) path;
- follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH;
- return _attr_multif(obj, follow, multiops, count, flags);
-}
-
-int
-attr_multif(int fd, attr_multiop_t *multiops, int count, int flags)
-{
- attr_obj_t obj;
- obj.fd = fd;
- return _attr_multif(obj, ATTR_TYPE_FD, multiops, count, flags);
-}
-
-static int
-_attr_multif(attr_obj_t obj, int type, attr_multiop_t *multiops, int count,
- int flags)
-{
- int i;
- int error = 0;
- attr_op_t *ops;
-
- /* From the manpage: "attr_multi will fail if ... A bit other than */
- /* ATTR_DONTFOLLOW was set in the flag argument." flags must be */
- /* checked here as they are not passed into the kernel. */
- /* All other flags are checked in the kernel (linvfs_attrctl). */
-
- if ((flags & ATTR_DONTFOLLOW) != flags) {
- errno = EINVAL;
- return -1;
- }
-
- if (! (ops = malloc(count * sizeof (attr_op_t)))) {
- errno = ENOMEM;
- return -1;
- }
-
- for (i = 0; i < count; i++) {
- ops[i].opcode = multiops[i].am_opcode;
- ops[i].name = multiops[i].am_attrname;
- ops[i].value = multiops[i].am_attrvalue;
- ops[i].length = multiops[i].am_length;
- ops[i].flags = multiops[i].am_flags;
- }
-
- if (attrctl(obj, type, ops, count) < 0) {
- error = -1;
- goto free_mem;
- }
-
- /* copy return vals */
- for (i = 0; i < count; i++) {
- multiops[i].am_error = ops[i].error;
- if (ops[i].opcode == ATTR_OP_GET)
- multiops[i].am_length = ops[i].length;
- }
-
- free_mem:
- free(ops);
- return error;
-}
-
-
-/*
- * attrctl(2) experimental system call function definition.
- */
-
-#if __i386__
-# define HAVE_ACL_SYSCALL 1
-# ifndef SYS__attrctl
-# define SYS__attrctl 250
-# endif
-#elif __ia64__
-# define HAVE_ACL_SYSCALL 1
-# ifndef SYS__attrctl
-# define SYS__attrctl 1260
-# endif
-#else
-# define HAVE_ACL_SYSCALL 0
-#endif
-
-static int
-attrctl(attr_obj_t obj, int type, attr_op_t *ops, int count)
-{
-#if HAVE_ACL_SYSCALL
- return syscall(SYS__attrctl, obj, type, ops, count);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
diff --git a/libattr/libattr.c b/libattr/libattr.c
new file mode 100644
index 0000000..e820a39
--- /dev/null
+++ b/libattr/libattr.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <asm/types.h>
+
+#include <xattr.h>
+#include <attributes.h>
+
+#undef MAXNAMELEN
+#define MAXNAMELEN 256
+
+static const char *user_name = "user.";
+static const char *root_name = "xfsroot.";
+
+/*
+ * Convert IRIX API components into Linux/XFS API components
+ */
+static int
+api_convert(char *name, const char *irixname, int irixflags)
+{
+ int len = strlen(irixname);
+
+ if (len >= MAXNAMELEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (irixflags & ATTR_ROOT)
+ strcpy(name, root_name);
+ else
+ strcpy(name, user_name);
+ strcat(name, irixname);
+ return 0;
+}
+
+int
+attr_get(const char *path, const char *attrname, char *attrvalue,
+ int *valuelength, int flags)
+{
+ int c;
+ char name[MAXNAMELEN+16];
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ if (flags & ATTR_DONTFOLLOW)
+ c = lgetxattr(path, name, attrvalue, *valuelength);
+ else
+ c = getxattr(path, name, attrvalue, *valuelength);
+ if (c < 0)
+ return c;
+ *valuelength = c;
+ return 0;
+}
+
+int
+attr_getf(int fd, const char *attrname, char *attrvalue,
+ int *valuelength, int flags)
+{
+ int c;
+ char name[MAXNAMELEN+16];
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ c = fgetxattr(fd, name, attrvalue, *valuelength);
+ if (c < 0)
+ return c;
+ *valuelength = c;
+ return 0;
+}
+
+int
+attr_set(const char *path, const char *attrname, const char *attrvalue,
+ const int valuelength, int flags)
+{
+ int c, lflags = 0;
+ char name[MAXNAMELEN+16];
+ void *buffer = (void *)attrvalue;
+
+ if (flags & ATTR_CREATE)
+ lflags = XATTR_CREATE;
+ else if (flags & ATTR_REPLACE)
+ lflags = XATTR_REPLACE;
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ if (flags & ATTR_DONTFOLLOW)
+ return lsetxattr(path, name, buffer, valuelength, lflags);
+ return setxattr(path, name, buffer, valuelength, lflags);
+}
+
+int
+attr_setf(int fd, const char *attrname,
+ const char *attrvalue, const int valuelength, int flags)
+{
+ int c, lflags = 0;
+ char name[MAXNAMELEN+16];
+ void *buffer = (void *)attrvalue;
+
+ if (flags & ATTR_CREATE)
+ lflags = XATTR_CREATE;
+ else if (flags & ATTR_REPLACE)
+ lflags = XATTR_REPLACE;
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ return fsetxattr(fd, name, buffer, valuelength, lflags);
+}
+
+int
+attr_remove(const char *path, const char *attrname, int flags)
+{
+ int c;
+ char name[MAXNAMELEN+16];
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ if (flags & ATTR_DONTFOLLOW)
+ return lremovexattr(path, name);
+ return removexattr(path, name);
+}
+
+int
+attr_removef(int fd, const char *attrname, int flags)
+{
+ int c;
+ char name[MAXNAMELEN+16];
+
+ if ((c = api_convert(name, attrname, flags)) < 0)
+ return c;
+ return fremovexattr(fd, name);
+}
+
+
+/*
+ * Helper routines for the attr_multi functions. In IRIX, the
+ * multi routines are a single syscall - in Linux, we break em
+ * apart in userspace and make individual syscalls for each.
+ */
+
+static int
+attr_single(const char *path, attr_multiop_t *op, int flags)
+{
+ int r = -1;
+
+ errno = -EINVAL;
+ flags |= op->am_flags;
+ if (op->am_opcode & ATTR_OP_GET)
+ r = attr_get(path, op->am_attrname, op->am_attrvalue,
+ &op->am_length, flags);
+ else if (op->am_opcode & ATTR_OP_SET)
+ r = attr_set(path, op->am_attrname, op->am_attrvalue,
+ op->am_length, flags);
+ else if (op->am_opcode & ATTR_OP_REMOVE)
+ r = attr_remove(path, op->am_attrname, flags);
+ return r;
+}
+
+static int
+attr_singlef(const int fd, attr_multiop_t *op, int flags)
+{
+ int r = -1;
+
+ errno = -EINVAL;
+ flags |= op->am_flags;
+ if (op->am_opcode & ATTR_OP_GET)
+ r = attr_getf(fd, op->am_attrname, op->am_attrvalue,
+ &op->am_length, flags);
+ else if (op->am_opcode & ATTR_OP_SET)
+ r = attr_setf(fd, op->am_attrname, op->am_attrvalue,
+ op->am_length, flags);
+ else if (op->am_opcode & ATTR_OP_REMOVE)
+ r = attr_removef(fd, op->am_attrname, flags);
+ return r;
+}
+
+/*
+ * Operate on multiple attributes of the same object simultaneously
+ *
+ * From the manpage: "attr_multi will fail if ... a bit other than
+ * ATTR_DONTFOLLOW was set in the flag argument." flags must be
+ * checked here as they are not passed into the kernel.
+ */
+int
+attr_multi(const char *path, attr_multiop_t *multiops, int count, int flags)
+{
+ int i, tmp, r = -1;
+
+ errno = EINVAL;
+ if ((flags & ATTR_DONTFOLLOW) != flags)
+ return r;
+
+ r = errno = 0;
+ for (i = 0; i < count; i++) {
+ tmp = attr_single(path, &multiops[i], flags);
+ if (tmp) r = tmp;
+ }
+ return r;
+}
+
+int
+attr_multif(int fd, attr_multiop_t *multiops, int count, int flags)
+{
+ int i, tmp, r = -1;
+
+ errno = EINVAL;
+ if ((flags & ATTR_DONTFOLLOW) != flags)
+ return r;
+
+ r = errno = 0;
+ for (i = 0; i < count; i++) {
+ tmp = attr_singlef(fd, &multiops[i], flags);
+ if (tmp) r = tmp;
+ }
+ return r;
+}
diff --git a/libattr/syscalls.c b/libattr/syscalls.c
new file mode 100644
index 0000000..f167540
--- /dev/null
+++ b/libattr/syscalls.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <unistd.h>
+
+#if defined(__i386__)
+# define HAVE_XATTR_SYSCALLS 1
+# define __NR_setxattr 226
+# define __NR_lsetxattr 227
+# define __NR_fsetxattr 228
+# define __NR_getxattr 229
+# define __NR_lgetxattr 230
+# define __NR_fgetxattr 231
+# define __NR_listxattr 232
+# define __NR_llistxattr 233
+# define __NR_flistxattr 234
+# define __NR_removexattr 235
+# define __NR_lremovexattr 236
+# define __NR_fremovexattr 237
+#elif defined (__sparc__)
+# define HAVE_XATTR_SYSCALLS 1
+# define __NR_setxattr 169
+# define __NR_lsetxattr 170
+# define __NR_fsetxattr 171
+# define __NR_getxattr 172
+# define __NR_lgetxattr 173
+# define __NR_fgetxattr 177
+# define __NR_listxattr 178
+# define __NR_llistxattr 179
+# define __NR_flistxattr 180
+# define __NR_removexattr 181
+# define __NR_lremovexattr 182
+# define __NR_fremovexattr 183
+#elif defined (__ia64__)
+# define HAVE_XATTR_SYSCALLS 1
+# define __NR_setxattr 1217
+# define __NR_lsetxattr 1218
+# define __NR_fsetxattr 1219
+# define __NR_getxattr 1220
+# define __NR_lgetxattr 1221
+# define __NR_fgetxattr 1222
+# define __NR_listxattr 1223
+# define __NR_llistxattr 1224
+# define __NR_flistxattr 1225
+# define __NR_removexattr 1226
+# define __NR_lremovexattr 1227
+# define __NR_fremovexattr 1228
+#elif defined (__powerpc__)
+# define HAVE_XATTR_SYSCALLS 1
+# define __NR_setxattr 208
+# define __NR_lsetxattr 209
+# define __NR_fsetxattr 210
+# define __NR_getxattr 211
+# define __NR_lgetxattr 212
+# define __NR_fgetxattr 213
+# define __NR_listxattr 214
+# define __NR_llistxattr 215
+# define __NR_flistxattr 216
+# define __NR_removexattr 217
+# define __NR_lremovexattr 218
+# define __NR_fremovexattr 219
+#else
+# warning "Extended attribute syscalls undefined for this architecture"
+# define HAVE_XATTR_SYSCALLS 0
+#endif
+
+#if HAVE_XATTR_SYSCALLS
+# define SYSCALL(args...) syscall(args)
+#else
+# define SYSCALL(args...) ( errno = ENOSYS, -1 )
+#endif
+
+int setxattr (const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ return SYSCALL(__NR_setxattr, path, name, value, size, flags);
+}
+
+int lsetxattr (const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ return SYSCALL(__NR_lsetxattr, path, name, value, size, flags);
+}
+
+int fsetxattr (int filedes, const char *name,
+ void *value, size_t size, int flags)
+{
+ return SYSCALL(__NR_fsetxattr, filedes, name, value, size, flags);
+}
+
+ssize_t getxattr (const char *path, const char *name,
+ void *value, size_t size)
+{
+ return SYSCALL(__NR_getxattr, path, name, value, size);
+}
+
+ssize_t lgetxattr (const char *path, const char *name,
+ void *value, size_t size)
+{
+ return SYSCALL(__NR_lgetxattr, path, name, value, size);
+}
+
+ssize_t fgetxattr (int filedes, const char *name,
+ void *value, size_t size)
+{
+ return SYSCALL(__NR_fgetxattr, filedes, name, value, size);
+}
+
+ssize_t listxattr (const char *path, char *list, size_t size)
+{
+ return SYSCALL(__NR_listxattr, path, list, size);
+}
+
+ssize_t llistxattr (const char *path, char *list, size_t size)
+{
+ return SYSCALL(__NR_llistxattr, path, list, size);
+}
+
+ssize_t flistxattr (int filedes, char *list, size_t size)
+{
+ return SYSCALL(__NR_flistxattr, filedes, list, size);
+}
+
+int removexattr (const char *path, const char *name)
+{
+ return SYSCALL(__NR_removexattr, path, name);
+}
+
+int lremovexattr (const char *path, const char *name)
+{
+ return SYSCALL(__NR_lremovexattr, path, name);
+}
+
+int fremovexattr (int filedes, const char *name)
+{
+ return SYSCALL(__NR_fremovexattr, filedes, name);
+}
diff --git a/man/Makefile b/man/Makefile
index 057c462..35492a3 100644
--- a/man/Makefile
+++ b/man/Makefile
@@ -33,7 +33,7 @@
TOPDIR = ..
include $(TOPDIR)/include/builddefs
-SUBDIRS = man1 man2 man3
+SUBDIRS = man1 man2 man3 man5
default install install-dev : $(SUBDIRS)
$(SUBDIRS_MAKERULE)
diff --git a/man/man1/attr.1 b/man/man1/attr.1
index bf6cbbe..9c1d905 100644
--- a/man/man1/attr.1
+++ b/man/man1/attr.1
@@ -1,6 +1,6 @@
-.TH attr 1
+.TH ATTR 1 "Extended Attributes" "Dec 2001" "XFS Compatibility API"
.SH NAME
-attr \- manipulate Extended Attributes on filesystem objects
+attr \- extended attributes on XFS filesystem objects
.SH SYNOPSIS
.nf
\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-s attrname\f1 [ \f3\-V attrvalue\f1 ] \c
@@ -10,33 +10,40 @@ attr \- manipulate Extended Attributes on filesystem objects
.sp .8v
\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-r attrname pathname\f1
.sp .8v
-\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-l pathname\f1
-.sp .8v
.fi
.SH OVERVIEW
-Extended Attributes implement the ability for a user to attach
-name/value pairs to objects within the filesystem.
+Extended attributes implement the ability for a user to attach
+name:value pairs to objects within the XFS filesystem.
.P
They could be used to store meta-information about the file.
For example "character-set=kanji" could tell a document browser to
use the Kanji character set when displaying that document
and "thumbnail=..." could provide a reduced resolution overview of a
high resolution graphic image.
+.PP
+This document describes the
+.I attr
+command, which is mostly compatible with the IRIX command of the same name.
+It is thus aimed specifically at users of the XFS filesystem - for
+filesystem independent extended attribute manipulation, consult the
+.IR getfattr (1)
+and
+.IR setfattr (1)
+documentation.
.P
-The
+In the XFS filesystem, the
.I names
can be up to 256 bytes in length, terminated by the first 0 byte.
The intent is that they be printable ASCII (or other character set)
names for the attribute.
-.P
The
.I values
-can be up to 256KB of arbitrary binary data.
+can be up to 64KB of arbitrary binary data.
.P
-Attributes can be attached to all types of inodes:
+Attributes can be attached to all types of XFS inodes:
regular files, directories, symbolic links, device nodes, etc.
.P
-There are 2 disjoint attribute name spaces associated with every
+XFS uses 2 disjoint attribute name spaces associated with every
filesystem object.
They are the
.B root
@@ -58,7 +65,7 @@ the value of attributes on any particular file.
.SH DESCRIPTION
The
.I attr
-utility allows the manipulation of Extended Attributes associated with
+utility allows the manipulation of extended attributes associated with
filesystem objects from within shell scripts.
.PP
There are four main operations that
@@ -77,18 +84,6 @@ With the
flag, \f4stdout\fP will be exactly and only the value of the attribute,
suitable for storage directly into a file or processing via a piped command.
.TP
-.B LIST
-The
-.B \-l
-option tells
-.I attr
-to list the names of all the attributes that are associated with the object,
-and the number of bytes in the value of each of those attributes.
-With the
-.B \-q
-flag, \f4stdout\fP will be a simple list of only the attribute names,
-one per line, suitable for input into a script.
-.TP
.B REMOVE
The
.B \-r attrname
@@ -148,17 +143,21 @@ The standard file interchange/archive programs
.IR tar (1),
and
.IR cpio (1)
-will not archive or restore Extended Attributes,
+will not archive or restore extended attributes,
while the
.IR xfsdump (8)
program will.
+.SH "CAVEATS"
+The list option present in the IRIX version of this command is not supported.
+.I getfattr
+provides a mechanism to retrieve all of the attribute names.
.SH "SEE ALSO"
-attr_get(2), attr_getf(2),
-attr_list(2), attr_listf(2),
-attr_multi(2), attr_multif(2),
-attr_remove(2), attr_removef(2),
-attr_set(2), attr_setf(2),
+getfattr(1),
+setfattr(1),
+attr_get(3),
+attr_set(3),
+attr_multi(3),
+attr_remove(3),
+attr(5),
+and
xfsdump(8).
-.SH BUGS
-The extended attributes system call used by this program is
-experimental and is currently only supported by the XFS filesystem.
diff --git a/man/man1/getfattr.1 b/man/man1/getfattr.1
new file mode 100644
index 0000000..7b3ea66
--- /dev/null
+++ b/man/man1/getfattr.1
@@ -0,0 +1,129 @@
+.TH GETFATTR 1 "Extended Attributes" "Dec 2001" "File Utilities"
+.SH NAME
+getfattr, aget \- get extended attributes of filesystem objects
+.SH SYNOPSIS
+.nf
+\f3getfattr\f1 [\f3\-lvR5LP\f1] \f3\-n name\f1 [\f3\-e en\f1] \c
+\f3pathname\f1...
+\f3getfattr\f1 [\f3\-lvR5LP\f1] \f3\-d\f1 [\f3\-e en\f1] \c
+[\f3\-s\f1 | \f3\-r regex\f1] \f3pathname\f1...
+\f3getfattr\f1 [\f3\-Vh\f1]
+.fi
+.SH DESCRIPTION
+For each file,
+.B getfattr
+displays the file name,
+and the set of extended attribute names (and optionally values) which
+are associated with that file.
+.PP
+.B aget
+is exactly the same as
+.BR getfattr ,
+and is installed for compatibility purposes.
+.PP
+The output format of
+.B "getfattr \-ds"
+is as follows:
+.fam C
+.RS
+.nf
+ 1: # file: somedir/
+ 2: user.name0="value0"
+ 3: system.name0="value1"
+ 4: user.name1="value2"
+ 5: ...
+.fi
+.RE
+.fam T
+.PP
+Line 1 identifies the file name for which the
+following lines are being reported.
+The remaining lines (lines 2 to 4 above) show the
+.I name
+and
+.I value
+pairs associated with the specified file.
+.SS OPTIONS
+.TP 4
+.I \-n name
+Dump the value of the named extended attribute extended attribute.
+.TP
+.I \-a
+Absolute names \- suppress the stripping of leading '/' from an absolute
+.IR pathname .
+.TP
+.I \-d
+Dump the values of all extended attributes associated with
+.IR pathname .
+.TP
+.I \-e en
+Encode values after retrieving them.
+Valid values of
+.I en
+are "text", "hex", and "base64".
+.TP
+.I \-l
+Do not follow symlinks - if
+.I pathname
+is a symbolic link, it is not followed, but is instead itself the
+inode being examined.
+.TP
+.I \-r
+.I regex
+is a regular expression pattern to apply to the set of extended
+attribute names being returned.
+It defaults to "^user\\." if no
+.I \-r
+is specified, which causes
+.B getfattr
+to operate on only extended attributes from the user namespace.
+.TP
+.I \-s
+Dump out both the "user" and "system" namespaces.
+Refer to
+.BR attr (5)
+for a more detailed discussion on namespaces.
+This option is useful for backing up extended attributes in a filesystem
+independent manner.
+It is implemented using a regular expression ("^user\\.|^system\\.")
+and so cannot be used in conjunction with the
+.I \-r
+option described earlier.
+.TP
+.I \-v
+Dump out the extended attribute value(s) only.
+.TP
+.I \-R
+Recurse into subdirectories, dumping extended attributes for each file
+encountered (breadth first).
+.TP
+.I \-5
+Same as \-R, except done in post-order (depth first).
+.TP
+.I \-L
+Refines the \-R or \-5 option - "logical walk" (do follow symbolic links).
+.TP
+.I \-P
+Refines the \-R or \-5 option - "physical walk" (do not follow symbolic links).
+.TP
+.I \-V
+Print the version of
+.B getfattr
+and exit.
+.TP
+.I \-h
+Print help explaining the command line options.
+.TP
+.I \-\-
+End of command line options.
+All remaining parameters are interpreted as file names, even if they
+start with a dash character.
+.SH AUTHOR
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+.P
+Please send your bug reports or comments to these addresses.
+.SH "SEE ALSO"
+setfattr(1), and attr(5).
diff --git a/man/man1/setfattr.1 b/man/man1/setfattr.1
new file mode 100644
index 0000000..6b71d2a
--- /dev/null
+++ b/man/man1/setfattr.1
@@ -0,0 +1,71 @@
+.TH SETFATTR 1 "Extended Attributes" "Dec 2001" "File Utilities"
+.SH NAME
+setfattr, aset \- set extended attributes of filesystem objects
+.SH SYNOPSIS
+.nf
+\f3setfattr\f1 [\f3\-l\f1] \f3\-n name\f1 [\f3\-v value\f1] \f3pathname\f1...
+\f3setfattr\f1 [\f3\-l\f1] \f3\-x name\f1 \f3pathname\f1...
+\f3setfattr\f1 [\f3\-l\f1] \f3\-B file\f1
+\f3setfattr\f1 [\f3\-Vh\f1]
+.fi
+.SH DESCRIPTION
+The
+.B setfattr
+command is used to associate a new
+.I value
+with an extended attribute
+.IR name
+for each specified file.
+.PP
+.B aset
+is exactly the same as
+.BR setfattr ,
+and is installed for compatibility purposes.
+.SS OPTIONS
+.TP 4
+.I \-n name
+Set the value of the named extended attribute extended attribute.
+.TP
+.I \-l
+Do not follow symlinks - if
+.I pathname
+is a symbolic link, it is not followed, but is instead itself the
+inode being modified.
+.TP
+.I \-x
+Remove the named extended attribute entirely.
+.TP
+.I \-v
+Specifies the new value for the named extended attribute.
+.TP
+.I \-B
+Restores extended attributes using values from the specified file.
+The file must be in the format generated by the
+.B getfattr
+command (\-sdlR options).
+The file name
+.I \-
+may be used in conjunction with this option, to specify the
+standard input stream to be used rather than a named file.
+.TP
+.I \-V
+Print the version of
+.B setfattr
+and exit.
+.TP
+.I \-h
+Print help explaining the command line options.
+.TP
+.I \-\-
+End of command line options.
+All remaining parameters are interpreted as file names, even if they
+start with a dash character.
+.SH AUTHOR
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+.P
+Please send your bug reports or comments to these addresses.
+.SH "SEE ALSO"
+getfattr(1), and attr(5).
diff --git a/man/man2/attrctl.2 b/man/man2/attrctl.2
deleted file mode 100644
index b49b0c7..0000000
--- a/man/man2/attrctl.2
+++ /dev/null
@@ -1,350 +0,0 @@
-.TH ATTRCTL 2
-.SH NAME
-attrctl \- manipulate (extended) attributes of system objects
-.SH C SYNOPSIS
-.PP
-.sp
-.nf
-.B #include <attr/attributes.h>
-.sp
-.B "int attrctl (attr_obj_t obj, int type, attr_op_t *ops,"
-.B " int count);"
-.Op
-.SH OVERVIEW
-The
-.I attrctl
-system call allows a user to attach name/value pairs to system
-objects - typically filesystem objects (inodes).
-.P
-This is a first draft proposal which may well *not* be the final
-interface - it has been implemented to address some immediate
-issues with the current XFS implementation and is the first attempt
-at an interface which could allow both XFS and EXT2 extended attributes
-implementations to coexist.
-.P
-Extended attributes can be used to store meta-information about a
-file, for example "character-set=kanji" could tell a document browser
-to use the Kanji character set when displaying that document
-and "thumbnail=..." could provide a reduced resolution overview of a
-high resolution graphic image.
-.P
-The
-.B names
-can be up to MAXNAMELEN bytes in length, terminated by the first \e0 byte.
-The intent is that they be printable ASCII (or other character set)
-names for the attribute.
-.P
-The
-.B values
-can be up to ATTR_MAX_VALUELEN (currently 64KB) of arbitrary binary data.
-.P
-Attributes can be attached to all types of inodes:
-regular files, directories, symbolic links, device nodes, etc.
-.P
-There are 2 disjoint attribute name spaces associated with every
-filesystem object.
-They are the
-.B root
-and
-.B user
-address spaces.
-The
-.B root
-address space is accessible only to the super-user,
-and then only by specifying a flag to the operation request.
-Non-root users will not see or be able to modify attributes in the
-.B root
-address space.
-The
-.B user
-address space is protected by the normal file permissions mechanism,
-so the owner of the file can decide who is able to see and/or modify
-the value of attributes on any particular file. The attribute get/list
-operations require read permission, and attribute set/remove require
-write permission.
-.P
-Attributes are currently supported only in the XFS and EXT2 filesystem
-types. However, this system call has been designed to be generic
-and extensible, such that other filesystems should be able to make
-use of it.
-.SH DESCRIPTION
-The
-.I attrctl
-system call provides a way to access arbitrary extended attributes.
-.P
-.I Obj\^
-indicates the system object whose extended attributes are to be
-manipulated.
-The contents of the \f4attr_obj_t\f1 union are as follows:
-.P
-typedef union {
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-char *path;
-int fd;
-pid_t pid;
-.ft 1
-.fi
-.RE
-} attr_obj_t;
-.PP
-.I type\^
-identifies the type of
-.I obj\^
-- currently only file descriptors and path names are implemented
-(ATTR_TYPE_NAME and ATTR_TYPE_FD), but processes have also been
-proposed (ATTR_TYPE_PID).
-.P
-.I Ops\^
-refers to an array of one or more input/output structures containing
-control information related to attribute operations and those
-operations' results.
-.PP
-The
-.I count
-argument indicates the number of structures in the
-.I ops
-array.
-.PP
-.Op c p a
-The contents of an \f4attr_op_t\fP structure are as follows:
-.P
-typedef struct {
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-int opcode; /* which operation to perform (see below) */
-int error; /* [out arg] result of this sub-op (an errno) */
-char *name; /* attribute name to work with */
-char *value; /* [in/out arg] attribute value (raw bytes) */
-int length; /* [in/out arg] length of value */
-int flags; /* flags (bit-wise OR of #defines below) */
-void *aux; /* optional command-specific data */
-.ft 1
-.fi
-.RE
-} attr_op_t;
-.PP
-The
-.I opcode
-field defines how the remaining fields are to be interpreted
-and can take on one of the following
-.B ATTR_OP
-values.
-.PP
-.B ATTR_OP_GET
-returns the
-.I value
-associated with attribute
-.IR name .
-The size of the user buffer is passed in as
-.IR length ,
-and the size of the attribute value is returned in the same field.
-Valid flags are ATTR_ROOT and ATTR_DONTFOLLOW.
-.P
-.B ATTR_OP_SET
-sets (possibly creating a new attribute) the value of the
-attribute specified by
-.I name
-to
-.IR value .
-The
-.I length
-parameter specifies the size of the new value, and the valid
-.I flags
-are ATTR_ROOT, ATTR_DONTFOLLOW, ATTR_CREATE, and ATTR_REPLACE.
-.P
-.B ATTR_OP_REMOVE
-provides a way to remove previously created attributes.
-If the attribute
-.I name
-exists, the attribute name and its associated value will be
-removed.
-Valid
-.I flags
-are ATTR_ROOT and ATTR_DONTFOLLOW.
-.P
-.B ATTR_OP_LIST
-is used to list the existing attributes associated with an object.
-The
-.I name
-field is ignored \-
-.I value
-and
-.I size
-specify the buffer to be filled with at least a portion of the
-attributes associated with the given object.
-An
-.B attrlist_t
-structure will be written into the
-.I value
-buffer, containing a list of the attributes associated with the
-object, up to a maximum of
-.I size
-bytes.
-The
-.B attrlist_t
-structure contains the following elements:
-.P
-typedef struct {
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-__s32 count; /* number of entries in attribute list */
-__s32 more; /* [in/out arg] more attrs (call again) */
-__s32 offset[1]; /* byte offsets of attrs [var-sized] */
-.ft 1
-.fi
-.RE
-} attrlist_t;
-.PP
-The
-.I count
-field shows the number of attributes represented in this buffer,
-which is also the number of elements in the
-.I offset
-array.
-The
-.I more
-field will be non-zero if another
-.B ATTR_OP_LIST
-call would retrieve more attributes.
-The
-.I offset
-array contains the byte offset within the
-.I value
-buffer of the structure describing each of the attributes, an
-.B attrlist_ent_t
-structure.
-The
-.B "ATTR_ENTRY(buffer, index)"
-macro will help with decoding the list.
-It takes a pointer to the
-.I value
-and an index into the
-.I offset
-array, and returns a pointer to the corresponding
-.I attrlist_ent_t
-structure.
-.P
-typedef struct {
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-__u32 valuelen; /* number of bytes in attribute value */
-char name[]; /* attribute name (NULL terminated) */
-.ft 1
-.fi
-.RE
-} attrlist_ent_t;
-.PP
-The
-.I valuelen
-field shows the size in bytes of the value associated
-with the attribute whose name is stored in the
-.I name
-field.
-.P
-Valid
-.I flags
-for the
-.B ATTR_LIST
-command are ATTR_ROOT and ATTR_DONTFOLLOW.
-The
-.I aux
-pointer is used to reference an opaque cursor (type
-.BR attrlist_cursor_t ),
-which the kernel uses to track the calling process's position
-in the attribute list.
-The only valid operations on this cursor are to pass it into the
-operation or to zero it out (it should be zeroed before the
-first
-.B attrctl
-call.
-Note that multi-threaded applications may keep more than one
-cursor in order to serve multiple contexts (i.e. the
-.B ATTR_LIST
-operation is "thread-safe").
-.P
-All operations will set
-.I error
-to an error code if the operation fails, otherwise it will
-contain zero indicating success. The set of valid
-.I flags
-field values (combined using bitwise OR) is as follows:
-.TP
-.SM
-\%ATTR_ROOT
-Look for attribute
-.I name
-in the
-.B root
-address space, not in the
-.B user
-address space (limited to use by the super-user only).
-.TP
-.SM
-\%ATTR_DONTFOLLOW
-Do not follow symbolic links when resolving a
-.I path
-on an
-.I attr_set
-function call.
-The default is to follow symbolic links.
-.TP
-.SM
-\%ATTR_CREATE
-Set
-.I error
-field (EEXIST) if an attribute of the given name already
-exists on the indicated object.
-This flag is used to implement a pure create operation,
-without this flag
-.B ATTR_SET
-will create the attribute if it does not already exist.
-.TP
-.SM
-\%ATTR_REPLACE
-Set
-.I error
-field (ENOENT) if an attribute of the given name
-does not already exist on the indicated object,
-otherwise replace the existing attribute\'s value with the
-given value.
-This flag is used to implement a pure replacement operation,
-without this flag
-.B ATTR_SET
-will create the attribute if it does not already exist.
-.PP
-The
-.I error
-field will be set (EINVAL) if both ATTR_CREATE and ATTR_REPLACE
-are requested in the same operation.
-.SH DIAGNOSTICS
-.I attrctl
-will return 0 on success, and an error code on any failure.
-Since the
-.I attrctl
-system call is arbitrarily extensible, and the intention is that it
-will always be used through an overlying API, refer to the manual
-pages for overlying API calls for specific error code values.
-.P
-.I attrctl
-will always attempt to perform all operations, and a set of
-operations are not atomic (failure of one operation does not
-necessarily cause prior successful operations to be undone).
-.SH "SEE ALSO"
-attr(1),
-.br
-attr_list(3), attr_listf(3),
-.br
-attr_multi(3), attr_multif(3),
-.br
-attr_remove(3), attr_removef(3),
-.br
-attr_set(3), attr_setf(3).
diff --git a/man/man2/getxattr.2 b/man/man2/getxattr.2
new file mode 100644
index 0000000..813873e
--- /dev/null
+++ b/man/man2/getxattr.2
@@ -0,0 +1,123 @@
+.\"
+.\" Extended attributes system calls manual pages
+.\"
+.\" (C) Andreas Gruenbacher, February 2001
+.\" (C) Silicon Graphics Inc, September 2001
+.\"
+.TH GETXATTR 2 "Extended Attributes" "Dec 2001" "System calls"
+.SH NAME
+getxattr, lgetxattr, fgetxattr \- retrieve an extended attribute value
+.SH SYNOPSIS
+.fam C
+.nf
+.B #include <attr/xattr.h>
+.sp
+.BI "ssize_t getxattr (const char\ *" path ", const char\ *" name ",
+.BI "\t\t\t\t void\ *" value ", size_t " size );
+.BI "ssize_t lgetxattr (const char\ *" path ", const char\ *" name ",
+.BI "\t\t\t\t void\ *" value ", size_t " size );
+.BI "ssize_t fgetxattr (int " filedes ", const char\ *" name ",
+.BI "\t\t\t\t void\ *" value ", size_t " size );
+.fi
+.fam T
+.SH DESCRIPTION
+Extended attributes are
+.IR name :\c
+.I value
+pairs associated with inodes (files, directories, symlinks, etc).
+They are extensions to the normal attributes which are associated
+with all inodes in the system (i.e. the
+.BR stat (2)
+data).
+A complete overview of extended attributes concepts can be found in
+.BR attr (5).
+.PP
+.B getxattr
+retrieves the
+.I value
+of the extended attribute identified by
+.I name
+and associated with the given
+.I path
+in the filesystem.
+The length of the attribute
+.I value
+is returned.
+.PP
+.B lgetxattr
+is identical to
+.BR getxattr ,
+except in the case of a symbolic link, where the link itself is
+interrogated, not the file that it refers to.
+.PP
+.B fgetxattr
+is identical to
+.BR getxattr ,
+only the open file pointed to by
+.I filedes
+(as returned by
+.BR open (2))
+is interrogated in place of
+.IR path .
+.PP
+An extended attribute
+.I name
+is a simple NULL-terminated string.
+The name includes a namespace prefix \- there may be several, disjoint
+namespaces associated with an individual inode.
+The value of an extended attribute is a chunk of arbitrary textual or
+binary data of specified length.
+.PP
+An empty buffer of
+.I size
+zero can be passed into these calls to return the current size of the
+named extended attribute, which can be used to estimate the size of a
+buffer which is sufficiently large to hold the value associated with
+the extended attribute.
+.PP
+The interface is designed to allow guessing of initial buffer
+sizes, and to enlarge buffers when the return value indicates
+that the buffer provided was too small.
+.SH RETURN VALUE
+On success, a positive number is returned indicating the size of the
+extended attribute value.
+On failure, \-1 is returned and
+.I errno
+is set appropriately.
+.PP
+If the named attribute does not exist, or the process has no access to
+this attribute,
+.I errno
+is set to ENOATTR.
+.PP
+If the
+.I size
+of the
+.I value
+buffer is too small to hold the result,
+.I errno
+is set to ERANGE.
+.PP
+If extended attributes are not supported by the filesystem, or are disabled,
+.I errno
+is set to ENOTSUP.
+.PP
+The errors documented for the
+.BR stat (2)
+system call are also applicable here.
+.SH AUTHORS
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+Please send any bug reports or comments to these addresses.
+.SH SEE ALSO
+.BR getfattr (1),
+.BR setfattr (1),
+.BR open (2),
+.BR stat (2),
+.BR setxattr (2),
+.BR listxattr (2),
+.BR removexattr (2),
+and
+.BR attr (5).
diff --git a/man/man2/listxattr.2 b/man/man2/listxattr.2
new file mode 100644
index 0000000..b1bf578
--- /dev/null
+++ b/man/man2/listxattr.2
@@ -0,0 +1,137 @@
+.\"
+.\" Extended attributes system calls manual pages
+.\"
+.\" (C) Andreas Gruenbacher, February 2001
+.\" (C) Silicon Graphics Inc, September 2001
+.\"
+.TH LISTXATTR 2 "Extended Attributes" "Dec 2001" "System calls"
+.SH NAME
+listxattr, llistxattr, flistxattr \- list extended attribute names
+.SH SYNOPSIS
+.fam C
+.nf
+.B #include <attr/xattr.h>
+.sp
+.BI "ssize_t listxattr (const char\ *" path ",
+.BI "\t\t\t\t char\ *" list ", size_t " size );
+.BI "ssize_t llistxattr (const char\ *" path ",
+.BI "\t\t\t\t char\ *" list ", size_t " size );
+.BI "ssize_t flistxattr (int " filedes ",
+.BI "\t\t\t\t char\ *" list ", size_t " size );
+.fi
+.fam T
+.SH DESCRIPTION
+Extended attributes are name:value
+pairs associated with inodes (files, directories, symlinks, etc).
+They are extensions to the normal attributes which are associated
+with all inodes in the system (i.e. the
+.BR stat (2)
+data).
+A complete overview of extended attributes concepts can be found in
+.BR attr (5).
+.PP
+.B listxattr
+retrieves the
+.I list
+of extended attribute names associated with the given
+.I path
+in the filesystem.
+The list is the set of (NULL-terminated) names, one after the other.
+The length of the attribute name
+.I list
+is returned.
+.PP
+.B llistxattr
+is identical to
+.BR listxattr ,
+except in the case of a symbolic link, where the list of names of
+extended attributes associated with the link itself is retrieved,
+not the file that it refers to.
+.PP
+.B flistxattr
+is identical to
+.BR listxattr ,
+only the open file pointed to by
+.I filedes
+(as returned by
+.BR open (2))
+is interrogated in place of
+.IR path .
+.PP
+A single extended attribute
+.I name
+is a simple NULL-terminated string.
+The name includes a namespace prefix \- there may be several, disjoint
+namespaces associated with an individual inode.
+.PP
+An empty buffer of
+.I size
+zero can be passed into these calls to return the current size of the
+list of extended attribute names, which can be used to estimate the
+size of a buffer which is sufficiently large to hold the list of names.
+.PP
+The interface is designed to allow guessing of initial buffer
+sizes, and to enlarge buffers when the return value indicates
+that the buffer provided was too small.
+.SH EXAMPLES
+The
+.I list
+of names is returned as an unordered array of NULL-terminated character
+strings (attribute names are separated by NULL characters), like this:
+.fam C
+.RS
+.nf
+user.name1\\0system.name1\\0user.name2\\0
+.fi
+.RE
+.fam T
+.P
+Filesystems like ext2, ext3 and XFS which implement POSIX ACLs using
+extended attributes, might return a
+.I list
+like this:
+.fam C
+.RS
+.nf
+system.posix_acl_access\\0system.posix_acl_default\\0
+.fi
+.RE
+.fam T
+.SH RETURN VALUE
+On success, a positive number is returned indicating the size of the
+extended attribute name list.
+On failure, \-1 is returned and
+.I errno
+is set appropriately.
+.PP
+If the
+.I size
+of the
+.I list
+buffer is too small to hold the result,
+.I errno
+is set to ERANGE.
+.PP
+If extended attributes are not supported by the filesystem, or are disabled,
+.I errno
+is set to ENOTSUP.
+.PP
+The errors documented for the
+.BR stat (2)
+system call are also applicable here.
+.SH AUTHORS
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+Please send any bug reports or comments to these addresses.
+.SH SEE ALSO
+.BR getfattr (1),
+.BR setfattr (1),
+.BR open (2),
+.BR stat (2),
+.BR getxattr (2),
+.BR setxattr (2),
+.BR removexattr (2),
+and
+.BR attr (5).
diff --git a/man/man2/removexattr.2 b/man/man2/removexattr.2
new file mode 100644
index 0000000..63affc8
--- /dev/null
+++ b/man/man2/removexattr.2
@@ -0,0 +1,91 @@
+.\"
+.\" Extended attributes system calls manual pages
+.\"
+.\" (C) Andreas Gruenbacher, February 2001
+.\" (C) Silicon Graphics Inc, September 2001
+.\"
+.TH REMOVEXATTR 2 "Extended Attributes" "Dec 2001" "System calls"
+.SH NAME
+removexattr, lremovexattr, fremovexattr \- remove an extended attribute
+.SH SYNOPSIS
+.fam C
+.nf
+.B #include <attr/xattr.h>
+.sp
+.BI "int removexattr (const char\ *" path ", const char\ *" name );
+.BI "int lremovexattr (const char\ *" path ", const char\ *" name );
+.BI "int fremovexattr (int " filedes ", const char\ *" name );
+.fi
+.fam T
+.SH DESCRIPTION
+Extended attributes are
+.IR name :\c
+value pairs associated with inodes (files, directories, symlinks, etc).
+They are extensions to the normal attributes which are associated
+with all inodes in the system (i.e. the
+.BR stat (2)
+data).
+A complete overview of extended attributes concepts can be found in
+.BR attr (5).
+.PP
+.B removexattr
+removes the extended attribute identified by
+.I name
+and associated with the given
+.I path
+in the filesystem.
+.PP
+.B lremovexattr
+is identical to
+.BR removexattr ,
+except in the case of a symbolic link, where the extended attribute is
+removed from the link itself, not the file that it refers to.
+.PP
+.B fremovexattr
+is identical to
+.BR removexattr ,
+only the extended attribute is removed from the open file pointed to by
+.I filedes
+(as returned by
+.BR open (2))
+in place of
+.IR path .
+.PP
+An extended attribute name is a simple NULL-terminated string.
+The
+.I name
+includes a namespace prefix \- there may be several, disjoint
+namespaces associated with an individual inode.
+.SH RETURN VALUE
+On success, zero is returned.
+On failure, \-1 is returned and
+.I errno
+is set appropriately.
+.PP
+If the named attribute does not exist,
+.I errno
+is set to ENOATTR.
+.PP
+If extended attributes are not supported by the filesystem, or are disabled,
+.I errno
+is set to ENOTSUP.
+.PP
+The errors documented for the
+.BR stat (2)
+system call are also applicable here.
+.SH AUTHORS
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+Please send any bug reports or comments to these addresses.
+.SH SEE ALSO
+.BR getfattr (1),
+.BR setfattr (1),
+.BR open (2),
+.BR stat (2),
+.BR setxattr (2),
+.BR getxattr (2),
+.BR listxattr (2),
+and
+.BR attr (5).
diff --git a/man/man2/setxattr.2 b/man/man2/setxattr.2
new file mode 100644
index 0000000..5a5f66f
--- /dev/null
+++ b/man/man2/setxattr.2
@@ -0,0 +1,126 @@
+.\"
+.\" Extended attributes system calls manual pages
+.\"
+.\" (C) Andreas Gruenbacher, February 2001
+.\" (C) Silicon Graphics Inc, September 2001
+.\"
+.TH SETXATTR 2 "Extended Attributes" "Dec 2001" "System calls"
+.SH NAME
+setxattr, lsetxattr, fsetxattr \- set an extended attribute value
+.SH SYNOPSIS
+.fam C
+.nf
+.B #include <attr/xattr.h>
+.sp
+.BI "int setxattr (const char\ *" path ", const char\ *" name ",
+.BI "\t\t\t void\ *" value ", size_t " size ", int " flags );
+.BI "int lsetxattr (const char\ *" path ", const char\ *" name ",
+.BI "\t\t\t void\ *" value ", size_t " size ", int " flags );
+.BI "int fsetxattr (int " filedes ", const char\ *" name ",
+.BI "\t\t\t void\ *" value ", size_t " size ", int " flags );
+.fi
+.fam T
+.SH DESCRIPTION
+Extended attributes are
+.IR name :\c
+.I value
+pairs associated with inodes (files, directories, symlinks, etc).
+They are extensions to the normal attributes which are associated
+with all inodes in the system (i.e. the
+.BR stat (2)
+data).
+A complete overview of extended attributes concepts can be found in
+.BR attr (5).
+.PP
+.B setxattr
+sets the
+.I value
+of the extended attribute identified by
+.I name
+and associated with the given
+.I path
+in the filesystem.
+The
+.I size
+of the
+.I value
+must be specified.
+.PP
+.B lsetxattr
+is identical to
+.BR setxattr ,
+except in the case of a symbolic link, where the extended attribute is
+set on the link itself, not the file that it refers to.
+.PP
+.B fsetxattr
+is identical to
+.BR setxattr ,
+only the extended attribute is set on the open file pointed to by
+.I filedes
+(as returned by
+.BR open (2))
+in place of
+.IR path .
+.PP
+An extended attribute name is a simple NULL-terminated string.
+The
+.I name
+includes a namespace prefix \- there may be several, disjoint
+namespaces associated with an individual inode.
+The
+.I value
+of an extended attribute is a chunk of arbitrary textual or
+binary data of specified length.
+.PP
+The
+.I flags
+parameter can be used to refine the semantics of the operation.
+XATTR_CREATE specifies a pure create, which fails if the named
+attribute exists already.
+XATTR_REPLACE specifies a pure replace operation, which fails if the
+named attribute does not already exist.
+By default (no flags), the extended attribute will be created if
+need be, or will simply replace the value if the attribute exists.
+.SH RETURN VALUE
+On success, zero is returned.
+On failure, \-1 is returned and
+.I errno
+is set appropriately.
+.PP
+If XATTR_CREATE is specified, and the attribute exists already,
+.I errno
+is set to EEXIST.
+If XATTR_REPLACE is specified, and the attribute does not exist,
+.I errno
+is set to ENOATTR.
+If XATTR_REMOVE is specified, and the attribute does not exist,
+.I errno
+is set to ENOATTR.
+.PP
+If there is insufficient space remaining to store the extended attribute,
+.I errno
+is set to either ENOSPC, or EDQUOT if quota enforcement was the cause.
+.PP
+If extended attributes are not supported by the filesystem, or are disabled,
+.I errno
+is set to ENOTSUP.
+.PP
+The errors documented for the
+.BR stat (2)
+system call are also applicable here.
+.SH AUTHORS
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+Please send any bug reports or comments to these addresses.
+.SH SEE ALSO
+.BR getfattr (1),
+.BR setfattr (1),
+.BR open (2),
+.BR stat (2),
+.BR getxattr (2),
+.BR listxattr (2),
+.BR removexattr (2),
+and
+.BR attr (5).
diff --git a/man/man3/attr_get.3 b/man/man3/attr_get.3
index 2a49624..bff7c86 100644
--- a/man/man3/attr_get.3
+++ b/man/man3/attr_get.3
@@ -1,4 +1,4 @@
-.TH ATTR_GET 3
+.TH ATTR_GET 3 "Extended Attributes" "Dec 2001" "XFS Compatibility API"
.SH NAME
attr_get, attr_getf \- get the value of a user attribute of a filesystem object
.SH C SYNOPSIS
@@ -174,11 +174,7 @@ does not refer to a valid descriptor.
.SH "SEE ALSO"
attr(1),
.br
-attrctl(2),
-.br
-attr_list(3), attr_listf(3)
-.br
-attr_multi(3), attr_multif(3)
+attr_multi(3), attr_multif(3),
.br
attr_remove(3), attr_removef(3),
.br
diff --git a/man/man3/attr_list.3 b/man/man3/attr_list.3
index cffe16d..e69de29 100644
--- a/man/man3/attr_list.3
+++ b/man/man3/attr_list.3
@@ -1,269 +0,0 @@
-.TH ATTR_LIST 3
-.SH NAME
-attr_list, attr_listf \- list the names of the user attributes of a filesystem object
-.SH C SYNOPSIS
-.PP
-.sp
-.nf
-.B #include <attr/attributes.h>
-.sp
-.B "int attr_list (const char \(**path, char \(**buffer, "
-.B " const int buffersize, int flags,"
-.B " attrlist_cursor_t \(**cursor);"
-.PP
-.B "int attr_listf (int fd, char \(**buffer, "
-.B " const int buffersize, int flags,"
-.B " attrlist_cursor_t \(**cursor);"
-.Op
-.SH DESCRIPTION
-The
-.I attr_list
-and
-.I attr_listf
-functions provide a way to list the existing attributes of a
-filesystem object.
-.P
-.I Path\^
-points to a path name for a filesystem object, and
-.I fd\^
-refers to the file descriptor associated with a file.
-The
-.I buffer
-will be filled with a structure describing at least a portion of the
-attributes associated with the given filesystem object.
-.I Buffer
-will be overwritten with an \f4attrlist_t\fP structure
-containing a list of the attributes associated with
-that filesystem object, up to a maximum of
-.I buffersize
-bytes.
-The
-.I buffer
-must be sufficiently large to hold the appropriate data structures
-plus at least one maximally sized attribute name,
-but cannot be more than ATTR_MAX_VALUELEN (currently 64KB) bytes in length.
-.PP
-.Op c p a
-The contents of an \f4attrlist_t\fP structure include the following members:
-.P
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-__int32_t al_count; /\(** number of entries in attrlist \(**/
-__int32_t al_more; /\(** T/F: more attrs (do syscall again) \(**/
-__int32_t al_offset[1]; /\(** byte offsets of attrs [var-sized] \(**/
-.ft 1
-.fi
-.RE
-.PP
-The
-.I al_count
-field shows the number of attributes represented in this buffer,
-which is also the number of elements in the
-.I al_offset
-array.
-The
-.I al_more
-field will be non-zero if another
-.I attr_list
-call would result in more attributes.
-The
-.I al_offset
-array contains the byte offset within the
-.I buffer
-of the structure describing each of the attributes,
-an \f4attrlist_ent_t\fP structure.
-The \f4ATTR_ENTRY(buffer, index)\fP macro will help with decoding the list.
-It takes a pointer to the
-.I buffer
-and an
-.I index
-into the
-.I al_offset
-array and returns a pointer to the corresponding
-\f4attrlist_ent_t\fP structure.
-.PP
-The contents of an \f4attrlist_ent_t\fP structure
-include the following members:
-.P
-.RS 3
-.nf
-.ft 4
-.ta 9n 22n
-u_int32_t a_valuelen; /\(** number bytes in value of attr \(**/
-char a_name[]; /\(** attr name (NULL terminated) \(**/
-.ft 1
-.fi
-.Op
-.RE
-.PP
-The
-.I a_valuelen
-field shows the size in bytes of the value
-associated with the attribute whose name is stored in the
-.I a_name
-field.
-The name is a NULL terminated string.
-.PP
-Note that the value of the attribute cannot be obtained through
-this interface, the
-.I attr_get
-call should be used to get the value.
-The
-.I attr_list
-interface tells the calling process how large of a buffer
-it must have in order to get the attribute\'s value.
-.PP
-The
-.I flags
-argument can contain the following symbols bitwise OR\'ed together:
-.TP
-.SM
-\%ATTR_ROOT
-List the attributes that are in the
-.B root
-address space, not in the
-.B user
-address space.
-(limited to use by super-user only)
-.TP
-.SM
-\%ATTR_DONTFOLLOW
-Do not follow symbolic links when resolving a
-.I path
-on an
-.I attr_list
-function call.
-The default is to follow symbolic links.
-.PP
-The
-.I cursor
-argument is a pointer to an opaque data structure that the kernel uses
-to track the calling process\'s position in the attribute list.
-The only valid operations on a
-.I cursor
-are to pass it into an
-.I attr_list
-function call or to zero it out.
-It should be zero\'ed out before the first
-.I attr_list
-call.
-Note that multi-threaded applications may keep more than one
-.I cursor
-in order to serve multiple contexts, ie: the
-.I attr_list
-call is "thread-safe".
-.PP
-.I attr_list
-will fail if one or more of the following are true:
-.TP 17
-.SM
-\%[ENOENT]
-The named file does not exist.
-.TP
-.SM
-\%[EPERM]
-The effective user
-.SM ID
-does not match the owner of the file
-and the effective user
-.SM ID
-is not super-user.
-.TP
-.SM
-\%[ENOTDIR]
-A component of the
-path prefix
-is not a directory.
-.TP
-.SM
-\%[EACCES]
-Search permission is denied on a
-component of the
-path prefix.
-.TP
-.SM
-\%[EINVAL]
-A bit was set in the
-.I flag
-argument that is not defined for this system call,
-or the buffer was too small or too large.
-.TP
-.SM
-\%[EFAULT]
-Either
-.I Path
-or
-.I buffer
-points outside the allocated address space of the process, or
-.I buffer
-or
-.I bufsize
-are not 32bit aligned.
-.TP
-.SM
-\%[ELOOP]
-A path name lookup involved too many symbolic links.
-.TP
-.SM
-\%[ENAMETOOLONG]
-The length of
-.I path
-exceeds
-.SM
-.RI { MAXPATHLEN },
-or a pathname component is longer than
-.SM
-.RI { MAXNAMELEN }.
-.TP
-.SM
-\%[ENOATTR]
-.I attribute\^
-does not exist for this file.
-.PP
-.I attr_listf\^
-will fail if:
-.TP 15
-.SM
-\%[EINVAL]
-A bit was set in the
-.I flag
-argument that is not defined for this system call, or
-.I fd\^
-refers to a socket, not a file,
-or the buffer was too small or too large.
-.TP
-.SM
-\%[EFAULT]
-Either
-.I Path
-or
-.I buffer
-points outside the allocated address space of the process, or
-.I buffer
-or
-.I bufsize
-are not 32bit aligned.
-.TP
-.SM
-\%[EBADF]
-.I Fd\^
-does not refer to a valid descriptor.
-.SH "SEE ALSO"
-attr(1),
-.br
-attrctl(2),
-.br
-attr_get(3), attr_getf(3),
-.br
-attr_multi(3), attr_multif(3)
-.br
-attr_remove(3), attr_removef(3),
-.br
-attr_set(3), attr_set(3)
-.SH "DIAGNOSTICS"
-Upon successful completion, a value of 0 is returned.
-Otherwise, a value of \-1 is returned and
-.I errno\^
-is set to indicate the error.
diff --git a/man/man3/attr_multi.3 b/man/man3/attr_multi.3
index 2daab79..699d218 100644
--- a/man/man3/attr_multi.3
+++ b/man/man3/attr_multi.3
@@ -1,4 +1,4 @@
-.TH ATTR_MULTI 3
+.TH ATTR_MULTI 3 "Extended Attributes" "Dec 2001" "XFS Compatibility API"
.SH NAME
attr_multi, attr_multif \- manipulate multiple user attributes on a filesystem object at once
.SH C SYNOPSIS
@@ -253,12 +253,8 @@ does not refer to a valid descriptor.
.SH "SEE ALSO"
attr(1),
.br
-attrctl(2),
-.br
attr_get(3), attr_getf(3),
.br
-attr_list(3), attr_list(3)
-.br
attr_remove(3), attr_removef(3),
.br
attr_set(3), attr_set(3)
diff --git a/man/man3/attr_remove.3 b/man/man3/attr_remove.3
index 1a72d50..4360c5f 100644
--- a/man/man3/attr_remove.3
+++ b/man/man3/attr_remove.3
@@ -1,4 +1,4 @@
-.TH ATTR_REMOVE 3
+.TH ATTR_REMOVE 3 "Extended Attributes" "Dec 2001" "XFS Compatibility API"
.SH NAME
attr_remove, attr_removef \- remove a user attribute of a filesystem object
.SH C SYNOPSIS
@@ -139,13 +139,9 @@ does not refer to a valid descriptor.
.SH "SEE ALSO"
attr(1),
.br
-attrctl(2),
-.br
attr_get(3), attr_getf(3),
.br
-attr_list(3), attr_listf(3)
-.br
-attr_multi(3), attr_multif(3)
+attr_multi(3), attr_multif(3),
.br
attr_set(3), attr_setf(3),
.SH "DIAGNOSTICS"
diff --git a/man/man3/attr_set.3 b/man/man3/attr_set.3
index 01a04ad..79b1e83 100644
--- a/man/man3/attr_set.3
+++ b/man/man3/attr_set.3
@@ -1,4 +1,4 @@
-.TH ATTR_SET 3
+.TH ATTR_SET 3 "Extended Attributes" "Dec 2001" "XFS Compatibility API"
.SH NAME
attr_set, attr_setf \- set the value of a user attribute of a filesystem object
.SH C SYNOPSIS
@@ -199,13 +199,9 @@ does not refer to a valid descriptor.
.SH "SEE ALSO"
attr(1),
.br
-attrctl(2),
-.br
attr_get(3), attr_getf(3),
.br
-attr_list(3), attr_listf(3)
-.br
-attr_multi(3), attr_multif(3)
+attr_multi(3), attr_multif(3),
.br
attr_remove(3), attr_removef(3),
.SH "DIAGNOSTICS"
diff --git a/man/man5/Makefile b/man/man5/Makefile
new file mode 100644
index 0000000..b81e765
--- /dev/null
+++ b/man/man5/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ../..
+include $(TOPDIR)/include/builddefs
+
+MAN_SECTION = 5
+
+MAN_PAGES = $(shell echo *.$(MAN_SECTION))
+MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION)
+LSRCFILES = $(MAN_PAGES)
+
+default install : $(MAN_PAGES)
+
+include $(BUILDRULES)
+
+install-dev : default
+ $(INSTALL) -m 755 -d $(MAN_DEST)
+ $(INSTALL_MAN)
diff --git a/man/man5/attr.5 b/man/man5/attr.5
new file mode 100644
index 0000000..4d82071
--- /dev/null
+++ b/man/man5/attr.5
@@ -0,0 +1,110 @@
+.\"
+.\" Extended attributes manual page
+.\"
+.\" (C) Andreas Gruenbacher, 2000
+.\" (C) Silicon Graphics Inc, 2001
+.\"
+.TH ATTR 5
+.SH NAME
+Extended attributes
+.SH DESCRIPTION
+Extended attributes are name:value pairs associated permanently with
+files and directories, similar to the environment strings associated
+with a process.
+An attribute may be defined or undefined.
+If it is defined, its value may be empty or non-empty.
+.PP
+Extended attributes are extensions to the normal attributes which are
+associated with all inodes in the system (i.e. the
+.BR stat (2)
+data).
+They are often used to provide additional functionality
+to a filesystem \- for example, additional security features such as
+Access Control Lists (ACLs) may be implemented using extended attributes.
+.PP
+Users with search access to a file or directory may retrieve a list of
+attribute names defined for that file or directory.
+.PP
+Extended attributes are accessed as atomic objects.
+Reading retrieves the whole value of an attribute and stores it in a buffer.
+Writing replaces any previous value with the new value.
+.PP
+Currently, support for extended attributes is implemented on Linux by
+the ext2, ext3 and XFS filesystem patches, which can be downloaded from
+.B http://acl.bestbits.at/
+and
+.B http://oss.sgi.com/projects/xfs/
+respectively.
+.SH EXTENDED ATTRIBUTE NAMESPACES
+Attribute names are zero-terminated strings and typically have a short
+(filesystem dependent) length.
+The attribute name is always specified in the full
+.IR namespace.attribute
+form, eg.
+.I user.mime_type
+or
+.IR system.posix_acl_access .
+.PP
+The namespace mechanism is used to define different classes of extended
+attributes.
+These different classes exist for several reasons, e.g. the permissions
+and capabilities required for manipulating extended attributes of one
+namespace may differ to another.
+They have also been used to distinguish filesystem-specific attribute
+names from canonical, filesystem-independent attribute names.
+.PP
+The extended attribute namespace is always specified as the first
+component of the name.
+This greatly simplifies certain operations, and provides a consistent,
+explicit interface for all operations.
+.PP
+Extended
+.I user
+attributes may be assigned to files and directories for storing arbitrary
+additional information such as the mime type, character set or encoding
+of a file.
+User attributes are subject to the same permissions as the contents of a file.
+The file owner can decide who is allowed to read and/or set these attributes.
+.PP
+Extended
+.I system
+attributes are used by the kernel to store system objects such as
+Access Control Lists and Capabilities.
+Read and write access permissions to system attributes
+depend on the policy implemented for each system attribute implemented
+in the kernel.
+.PP
+Additional types of extended attributes with different access permissions,
+such as attributes that are accessible only to processes trusted by the
+kernel, may be added in the future.
+.SH FILESYSTEM DIFFERENCES
+The kernel and the filesystem may place limits on the maximum number
+and size of extended attributes that can be associated with a file.
+.PP
+In the current ext2 and ext3 filesystem implementations, all extended
+attributes must fit on a single filesystem block (1024, 2048 or 4096 bytes,
+depending on the block size specified when the filesystem
+was created). This limit may be removed in a future version.
+Device special files cannot be associated with extended user attributes
+(but they may be associated with extended system attributes). Permissions
+of device special files define access to the devices rather than to the
+device special files.
+.PP
+In the XFS filesystem implementation, there is no practical limit on the
+number of extended attributes associated with a file, and the algorithms
+used to store extended attribute information on disk are scalable (stored
+either inline in the inode, as an extent, or in a B+ tree).
+XFS allows extended attributes to be associated with device inodes.
+.SH ADDITIONAL NOTES
+Since the filesystems on which extended attributes are stored might also
+be used on architectures with a different byte order and machine word
+size, care should be taken to store attribute values in an architecture
+independent format.
+.SH AUTHORS
+Andreas Gruenbacher,
+.RI < a.gruenbacher@computer.org >
+and the SGI XFS development team,
+.RI < linux-xfs@oss.sgi.com >.
+.SH SEE ALSO
+getfattr(1),
+setfattr(1).
diff --git a/setfattr/Makefile b/setfattr/Makefile
new file mode 100644
index 0000000..d3e793b
--- /dev/null
+++ b/setfattr/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTCOMMAND = setfattr
+CFILES = setfattr.c
+
+LLDLIBS = $(LIBATTR)
+LTDEPENDENCIES = $(LIBATTR)
+
+default: $(LTCOMMAND)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 -d $(PKG_BIN_DIR)
+ $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR)
+ $(INSTALL) -S $(LTCOMMAND) $(PKG_BIN_DIR)/aset
+install-dev:
diff --git a/setfattr/setfattr.c b/setfattr/setfattr.c
new file mode 100644
index 0000000..d2a462f
--- /dev/null
+++ b/setfattr/setfattr.c
@@ -0,0 +1,425 @@
+/*
+ * Original setfattr.c:
+ * Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
+ * Changes to use revised EA syscall interface:
+ * Copyright (C) 2001 by SGI XFS development <linux-xfs@oss.sgi.com>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#include <xattr.h>
+
+#include <locale.h>
+#include <libintl.h>
+#define _(String) gettext (String)
+
+#define CMD_LINE_OPTIONS "n:lv:x:B:Vh"
+#define CMD_LINE_SPEC1 "{-n name|-x name} [-v value] [-lVh] file..."
+#define CMD_LINE_SPEC2 "{-B filename} [-lVh] file..."
+
+char *opt_name;
+char *opt_remove;
+char *opt_value;
+int opt_restore;
+int opt_symlink;
+
+int had_errors;
+const char *progname;
+
+int do_set(const char *name, const char *value, const char *path);
+const char *decode(const char *value, size_t *size);
+int restore(FILE *file, const char *filename);
+char *next_line(FILE *file);
+int hex_digit(char c);
+int base64_digit(char c);
+
+int restore(FILE *file, const char *filename)
+{
+ char *path_p = NULL, *l;
+ int line = 0, backup_line, status = 0;
+
+ for(;;) {
+ backup_line = line;
+ while ((l = next_line(file)) != NULL && *l == '\0')
+ line++;
+ if (l == NULL)
+ break;
+ line++;
+ if (strncmp(l, "# file: ", 8) != 0) {
+ if (filename) {
+ fprintf(stderr, _("%s: %s: No filename found "
+ "in line %d, aborting\n"),
+ progname, filename, backup_line);
+ } else {
+ fprintf(stderr, _("%s: No filename found in"
+ "line %d of standard input, "
+ "aborting\n"),
+ progname, backup_line);
+ }
+ status = 1;
+ goto cleanup;
+ } else
+ l += 8;
+ if (path_p)
+ free(path_p);
+ path_p = (char *)malloc(strlen(l) + 1);
+ if (!path_p) {
+ status = 1;
+ goto cleanup;
+ }
+ strcpy(path_p, l);
+
+ while ((l = next_line(file)) != NULL && *l != '\0') {
+ char *name = l, *value = strchr(l, '=');
+ line++;
+ if (value == NULL)
+ value = "";
+ else
+ *value++ = '\0';
+ status = do_set(name, value, path_p);
+ }
+ if (l != NULL)
+ line++;
+ }
+
+cleanup:
+ if (path_p)
+ free(path_p);
+ return status;
+}
+
+void help(void)
+{
+ printf(_("%s %s -- set extended attributes\n"), progname, VERSION);
+ printf(_("Usage: %s %s\n"), progname, CMD_LINE_SPEC1);
+ printf(_(" %s %s\n"), progname, CMD_LINE_SPEC2);
+ printf(_("Options:\n"));
+ printf(_("\t-n name\tset value of extended attribute `name'\n"
+ "\t-l\tset extended attribute values of a symlink\n"
+ "\t-x name\tremove extended attribute `name'\n"
+ "\t-v value\n\t\tvalue for extended attribute `name'\n"
+ "\t-B filename\n\t\trestore extended attributes (inverse of `getfattr -sdlR')\n"
+ "\t-V\tprint version and exit\n"
+ "\t-h\tthis help text\n"));
+}
+
+char *next_line(FILE *file)
+{
+ static char line[_POSIX_PATH_MAX+32], *c;
+ if (!fgets(line, sizeof(line), file))
+ return NULL;
+
+ c = strrchr(line, '\0');
+ while (c > line && (*(c-1) == '\n' ||
+ *(c-1) == '\r')) {
+ c--;
+ *c = '\0';
+ }
+ return line;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *file;
+ int status;
+
+ progname = basename(argv[0]);
+
+ while ((optopt = getopt(argc, argv, CMD_LINE_OPTIONS)) != -1) {
+ switch(optopt) {
+ case 'n': /* attribute name */
+ if (opt_remove)
+ goto synopsis;
+ opt_name = optarg;
+ break;
+
+ case 'l': /* set attribute on symlink itself */
+ opt_symlink = 1;
+ break;
+
+ case 'v': /* attribute value */
+ if (opt_value || opt_remove)
+ goto synopsis;
+ opt_value = optarg;
+ break;
+
+ case 'x': /* remove attribute */
+ if (opt_name)
+ goto synopsis;
+ opt_remove = optarg;
+ break;
+
+ case 'B': /* restore */
+ opt_restore = 1;
+ if (strcmp(optarg, "-") == 0)
+ file = stdin;
+ else {
+ file = fopen(optarg, "r");
+ if (file == NULL) {
+ fprintf(stderr, "%s: %s: %s\n",
+ progname, optarg,
+ strerror(errno));
+ return 1;
+ }
+ }
+ status = restore(file,
+ (file == stdin) ? NULL : optarg);
+ if (file != stdin)
+ fclose(file);
+ if (status != 0)
+ return 1;
+ break;
+
+ case 'V':
+ printf("%s " VERSION "\n", progname);
+ return 0;
+
+ case 'h':
+ help();
+ return 0;
+
+ default:
+ goto synopsis;
+ }
+ }
+ if (((opt_name && opt_remove) || (!opt_name && !opt_remove) ||
+ optind >= argc) && !opt_restore)
+ goto synopsis;
+ if (opt_name) {
+ if (!opt_value)
+ opt_value = "";
+ } else {
+ opt_name = opt_remove;
+ opt_value = NULL;
+ }
+ while (optind < argc) {
+ do_set(opt_name, opt_value, argv[optind]);
+ optind++;
+ }
+
+ return (had_errors ? 1 : 0);
+
+synopsis:
+ fprintf(stderr, _("Usage: %s %s\n"
+ " %s %s\n"
+ "Try `%s -h' for more information.\n"),
+ progname, CMD_LINE_SPEC1, progname, CMD_LINE_SPEC2, progname);
+ return 2;
+}
+
+int do_setxattr(const char *path, const char *name, void *value, size_t size)
+{
+ if (opt_symlink)
+ return lsetxattr(path, name, value, size, 0);
+ return setxattr(path, name, value, size, 0);
+}
+
+int do_removexattr(const char *path, const char *name)
+{
+ if (opt_symlink)
+ return lremovexattr(path, name);
+ return removexattr(path, name);
+}
+
+int do_set(const char *name, const char *value, const char *path)
+{
+ size_t size = 0;
+ int error;
+
+ if (value) {
+ size = strlen(value);
+ value = decode(value, &size);
+ if (!value)
+ return 1;
+ }
+ error = opt_remove? do_removexattr(path, name):
+ do_setxattr(path, name, (void *)value, size);
+ if (error < 0) {
+ perror(path);
+ had_errors++;
+ return 1;
+ }
+ return 0;
+}
+
+const char *decode(const char *value, size_t *size)
+{
+ static char *decoded = NULL;
+
+ if (decoded != NULL) {
+ free(decoded);
+ decoded = NULL;
+ }
+ if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) {
+ const char *v = value+2, *end = value + *size;
+ char *d;
+
+ decoded = d = (char *)malloc(*size / 2);
+ if (!decoded) {
+ perror("");
+ had_errors++;
+ return NULL;
+ }
+ while (v < end) {
+ int d1, d0;
+
+ while (v < end && isspace(*v))
+ v++;
+ if (v == end)
+ break;
+ d1 = hex_digit(*v++);
+ while (v < end && isspace(*v))
+ v++;
+ if (v == end) {
+ bad_hex_encoding:
+ fprintf(stderr, "bad input encoding\n");
+ had_errors++;
+ return NULL;
+ }
+ d0 = hex_digit(*v++);
+ if (d1 < 0 || d0 < 0)
+ goto bad_hex_encoding;
+ *d++ = ((d1 << 4) | d0);
+ }
+ *size = d - decoded;
+ } else if (value[0] == '0' && (value[1] == 's' || value[1] == 'S')) {
+ const char *v = value+2, *end = value + *size;
+ int d0, d1, d2, d3;
+ char *d;
+
+ decoded = d = (char *)malloc(*size / 4 * 3);
+ if (!decoded) {
+ perror("");
+ had_errors++;
+ return NULL;
+ }
+ for(;;) {
+ while (v < end && isspace(*v))
+ v++;
+ if (v == end) {
+ d0 = d1 = d2 = d3 = -2;
+ break;
+ }
+ if (v + 4 > end) {
+ bad_base64_encoding:
+ fprintf(stderr, "bad input encoding\n");
+ had_errors++;
+ return NULL;
+ }
+ d0 = base64_digit(*v++);
+ d1 = base64_digit(*v++);
+ d2 = base64_digit(*v++);
+ d3 = base64_digit(*v++);
+ if (d0 < 0 || d1 < 0 || d2 < 0 || d3 < 0)
+ break;
+
+ *d++ = (char)((d0 << 2) | (d1 >> 4));
+ *d++ = (char)((d1 << 4) | (d2 >> 2));
+ *d++ = (char)((d2 << 6) | d3);
+ }
+ if (d0 == -2) {
+ if (d1 != -2 || d2 != -2 || d3 != -2)
+ goto bad_base64_encoding;
+ goto base64_end;
+ }
+ if (d0 == -1 || d1 < 0 || d2 == -1 || d3 == -1)
+ goto bad_base64_encoding;
+ *d++ = (char)((d0 << 2) | (d1 >> 4));
+ if (d2 != -2)
+ *d++ = (char)((d1 << 4) | (d2 >> 2));
+ else {
+ if (d1 & 0x0F || d3 != -2)
+ goto bad_base64_encoding;
+ goto base64_end;
+ }
+ if (d3 != -2)
+ *d++ = (char)((d2 << 6) | d3);
+ else if (d2 & 0x03)
+ goto bad_base64_encoding;
+ base64_end:
+ while (v < end && isspace(*v))
+ v++;
+ if (v + 4 <= end && *v == '=') {
+ if (*++v != '=' || *++v != '=' || *++v != '=')
+ goto bad_base64_encoding;
+ v++;
+ }
+ while (v < end && isspace(*v))
+ v++;
+ if (v < end)
+ goto bad_base64_encoding;
+ *size = d - decoded;
+ } else {
+ const char *v = value, *end = value + *size;
+ char *d;
+
+ if (end > v+1 && *v == '"' && *(end-1) == '"') {
+ v++;
+ end--;
+ }
+
+ decoded = d = (char *)malloc(*size);
+ if (!decoded) {
+ perror("");
+ had_errors++;
+ return NULL;
+ }
+
+ while (v < end) {
+ if (v[0] == '\\') {
+ if (v[1] == '\\' || v[1] == '"') {
+ *d++ = *++v; v++;
+ } else if (v[1] >= '0' && v[1] <= '7') {
+ int c = 0;
+ v++;
+ c = (*v++ - '0');
+ if (*v >= '0' && *v <= '7')
+ c = (c << 3) + (*v++ - '0');
+ if (*v >= '0' && *v <= '7')
+ c = (c << 3) + (*v++ - '0');
+ *d++ = c;
+ } else
+ *d++ = *v++;
+ } else
+ *d++ = *v++;
+ }
+ *size = d - decoded;
+ }
+ return decoded;
+}
+
+int hex_digit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else
+ return -1;
+}
+
+int base64_digit(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+ else if (c >= 'a' && c <= 'z')
+ return 26 + c - 'a';
+ else if (c >= '0' && c <= '9')
+ return 52 + c - '0';
+ else if (c == '+')
+ return 62;
+ else if (c == '/')
+ return 63;
+ else if (c == '=')
+ return -2;
+ else
+ return -1;
+}
+
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..bc1e326
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+# ensure we pick these up in the source tarball
+LSRCFILES = attr.test run README
+
+default:
+
+include $(BUILDRULES)
+
+install:
+install-dev:
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..ab8f232
--- /dev/null
+++ b/test/README
@@ -0,0 +1,9 @@
+
+Andreas Gruenbacher's tests for the ext2 filesystem extended attributes
+support. Most of these tests should work for any filesystem type, and
+most are actually used as part of the XFS test suite. However, those
+tests relating to the exercising of boundary conditions of attribute
+value lengths, etc, are specific to ext2.
+
+ -- nathans@sgi.com
+
diff --git a/test/attr.test b/test/attr.test
new file mode 100644
index 0000000..b1399e8
--- /dev/null
+++ b/test/attr.test
@@ -0,0 +1,78 @@
+!
+! Tests for getting/setting extended file attributes with ext2/ext3
+! The initial size checks are ext2/ext3 specific, but the remainder
+! should work for any extended attributes filesystem (eg. XFS).
+!
+$ mkdir attr-test
+$ touch attr-test/f
+! Maximum attribute size for 1024 byte blocks = 1024 - (20+20+4) = 980
+$ aset -n user.name -v 968+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ attr-test/f
+! Attribute too big for 1024 byte blocks
+$ aset -n user.name -v 969++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ attr-test/f
+attr-test/f: No space left on device
+$ aset -n user.name attr-test/f
+$ aget -d attr-test/f
+# file: attr-test/f
+user.name
+
+$ aset -n user.name -v 0xbabe attr-test/f
+$ aset -n user.name2 -v 0xdeadbeef attr-test/f
+$ aset -n user.name3 -v 0xdeface attr-test/f
+!
+!
+$ aget -d -e hex attr-test/f
+# file: attr-test/f
+user.name=0xbabe
+user.name2=0xdeadbeef
+user.name3=0xdeface
+
+$ aget -d -e base64 attr-test/f
+# file: attr-test/f
+user.name=0sur4=
+user.name2=0s3q2+7w==
+user.name3=0s3vrO
+
+!
+! shrink value of existing attribute
+!
+$ aset -n user.name2 -v 0xdeaf attr-test/f
+$ aget -d -e hex attr-test/f
+# file: attr-test/f
+user.name=0xbabe
+user.name2=0xdeaf
+user.name3=0xdeface
+
+!
+! grow value of existing attribute
+!
+$ aset -n user.name2 -v 0xdecade attr-test/f
+$ aget -d -e hex attr-test/f
+# file: attr-test/f
+user.name=0xbabe
+user.name2=0xdecade
+user.name3=0xdeface
+
+!
+! empty value
+!
+$ aset -n user.name2 attr-test/f
+$ aget -d -n user.name2 attr-test/f
+# file: attr-test/f
+user.name2
+
+!
+! overwrite empty value
+!
+$ aset -n user.name2 -v 0xcafe attr-test/f
+$ aget -d -e hex -n user.name2 attr-test/f
+# file: attr-test/f
+user.name2=0xcafe
+
+!
+! remove attribute
+!
+$ aset -x user.name2 attr-test/f
+$ aget -d -n user.name2 attr-test/f
+attr-test/f: user.name2: No such attribute
+$ rm attr-test/f
+$ rmdir attr-test
diff --git a/test/run b/test/run
new file mode 100644
index 0000000..b545a53
--- /dev/null
+++ b/test/run
@@ -0,0 +1,145 @@
+#!/usr/bin/perl
+
+use strict;
+use FileHandle;
+use POSIX qw(geteuid getegid isatty);
+
+my $owner = getpwuid(geteuid());
+my $group = getgrgid(getegid());
+
+my ($OK, $FAILED) = ("ok", "failed");
+if (isatty(fileno(STDOUT))) {
+ $OK = "\033[32m" . $OK . "\033[m";
+ $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
+}
+
+my ($prog, $in, $out) = ([], [], []);
+my $line = 0;
+my $prog_line;
+for (;;) {
+ my $script = <>; $line++;
+ $script =~ s/\@OWNER\@/$owner/g;
+ $script =~ s/\@GROUP\@/$group/g;
+ next if (defined($script) && $script =~ /^!/);
+ if (!defined($script) || $script =~ s/^\$ ?//) {
+ if (@$prog) {
+ #print "[$prog_line] \$ ", join(' ', @$prog), " -- ";
+ my $p = [ @$prog ];
+ print "[$prog_line] \$ ", join(' ',
+ map { s/\s/\\$&/g; $_ } @$p), " -- ";
+ my $result = exec_test($prog, $in);
+ my $good = 1;
+ my $nmax = (@$out > @$result) ? @$out : @$result;
+ for (my $n=0; $n < $nmax; $n++) {
+ if (!defined($out->[$n]) || !defined($result->[$n]) ||
+ $out->[$n] ne $result->[$n]) {
+ $good = 0;
+ #chomp $out->[$n];
+ #chomp $result->[$n];
+ #print "$out->[$n] != $result->[$n]";
+ }
+ }
+ print $good ? $OK : $FAILED, "\n";
+ if (!$good) {
+ for (my $n=0; $n < $nmax; $n++) {
+ my $l = defined($out->[$n]) ? $out->[$n] : "~";
+ chomp $l;
+ my $r = defined($result->[$n]) ? $result->[$n] : "~";
+ chomp $r;
+ print sprintf("%-37s | %-39s\n", $l, $r);
+ }
+ }
+ }
+ #$prog = [ split /\s+/, $script ] if $script;
+ $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $script ] if $script;
+ $prog_line = $line;
+ $in = [];
+ $out = [];
+ } elsif ($script =~ s/^> ?//) {
+ push @$in, $script;
+ } else {
+ push @$out, $script;
+ }
+ last unless defined($script);
+}
+
+sub exec_test($$) {
+ my ($prog, $in) = @_;
+ local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+
+ if ($prog->[0] eq "umask") {
+ umask oct $prog->[1];
+ return [];
+ } elsif ($prog->[0] eq "cd") {
+ if (!chdir $prog->[1]) {
+ return [ "chdir: $prog->[1]: $!\n" ];
+ }
+ return [];
+ }
+
+ pipe *IN2, *OUT
+ or die "Can't create pipe for reading: $!";
+ open *IN_DUP, "<&STDIN"
+ or *IN_DUP = undef;
+ open *STDIN, "<&IN2"
+ or die "Can't duplicate pipe for reading: $!";
+ close *IN2;
+
+ open *OUT_DUP, ">&STDOUT"
+ or die "Can't duplicate STDOUT: $!";
+ pipe *IN, *OUT2
+ or die "Can't create pipe for writing: $!";
+ open *STDOUT, ">&OUT2"
+ or die "Can't duplicate pipe for writing: $!";
+ close *OUT2;
+
+ *STDOUT->autoflush();
+ *OUT->autoflush();
+
+ if (fork()) {
+ # Server
+ if (*IN_DUP) {
+ open *STDIN, "<&IN_DUP"
+ or die "Can't duplicate STDIN: $!";
+ close *IN_DUP
+ or die "Can't close STDIN duplicate: $!";
+ }
+ open *STDOUT, ">&OUT_DUP"
+ or die "Can't duplicate STDOUT: $!";
+ close *OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+
+ foreach my $line (@$in) {
+ #print "> $line";
+ print OUT $line;
+ }
+ close *OUT
+ or die "Can't close pipe for writing: $!";
+
+ my $result = [];
+ while (<IN>) {
+ #print "< $_";
+ push @$result, $_;
+ }
+ return $result;
+ } else {
+ # Client
+ close IN
+ or die "Can't close read end for input pipe: $!";
+ close OUT
+ or die "Can't close write end for output pipe: $!";
+ close OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+ local *ERR_DUP;
+ open ERR_DUP, ">&STDERR"
+ or die "Can't duplicate STDERR: $!";
+ open STDERR, ">&STDOUT"
+ or die "Can't join STDOUT and STDERR: $!";
+
+ #print ERR_DUP "<", join(' ', @$prog), ">\n";
+ exec @$prog;
+ print ERR_DUP $prog->[0], ": $!\n";
+ exit;
+ }
+}
+