summaryrefslogtreecommitdiff
path: root/setfattr/setfattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'setfattr/setfattr.c')
-rw-r--r--setfattr/setfattr.c425
1 files changed, 425 insertions, 0 deletions
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;
+}
+