From c82edc1013cf28a096cb8f5ba21c28d3e9312227 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 25 Feb 2002 22:10:22 +0000 Subject: 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. --- getfattr/Makefile | 51 +++++++ getfattr/getfattr.c | 422 +++++++++++++++++++++++++++++++++++++++++++++++++++ getfattr/walk_tree.c | 94 ++++++++++++ getfattr/walk_tree.h | 18 +++ 4 files changed, 585 insertions(+) create mode 100644 getfattr/Makefile create mode 100644 getfattr/getfattr.c create mode 100644 getfattr/walk_tree.c create mode 100644 getfattr/walk_tree.h (limited to 'getfattr') 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 + * Changes to use revised EA syscall interface: + * Copyright (C) 2001 by SGI XFS development + */ + +#include +#include +#include +#include +#include +#include +#include "walk_tree.h" + +#include +#include +#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 + * + * TODO: should this be replaced by using nftw(3)? + */ +#include +#include +#include +#include +#include +#include + +#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 + * + * TODO: should this be replaced by using nftw(3)? + */ +#include + +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 *); -- cgit v1.2.3