[BACK]Return to attr_copy_action.c CVS log [TXT][DIR] Up to [Development] / xfs-cmds / attr / libattr

File: [Development] / xfs-cmds / attr / libattr / attr_copy_action.c (download)

Revision 1.1, Mon May 19 04:08:04 2008 UTC (9 years, 4 months ago) by bnaujok.longdrop.melbourne.sgi.com
Branch: MAIN
CVS Tags: HEAD

the current attribute copying functions attr_copy_file and
attr_copy_fd is a static list of exceptions for attributes that need special
treatment. The list of those attributes tends to change (slowly) with kernel
versions. We replaced the static list with a config file a while ago; this is
the patch used.
Merge of master-melb:xfs-cmds:31181a by kenmcd.

  Add configurable xattr copy

/* Copyright (C) 2006 Andreas Gruenbacher <agruen@xxxxxxx>, SuSE Linux AG.

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <alloca.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <fnmatch.h>

#include "attr/libattr.h"
#define ERROR_CONTEXT_MACROS
#include "error_context.h"

#define ATTR_CONF "/etc/xattr.conf"

struct attr_action {
	struct attr_action *next;
	char *pattern;
	int action;
};

static struct attr_action *attr_actions;

static void
free_attr_actions(void)
{
	struct attr_action *tmp;

	while (attr_actions) {
		tmp = attr_actions->next;
		free(attr_actions->pattern);
		free(attr_actions);
		attr_actions = tmp;
	}
}

static int
attr_parse_attr_conf(struct error_context *ctx)
{
	char *text, *t;
	size_t size_guess = 4096, len;
	FILE *file;
	char *pattern = NULL;
	struct attr_action *new;
	int action;

	if (attr_actions)
		return 0;

repeat:
	text = malloc(size_guess + 1);
	if (!text)
		goto fail;

	if ((file = fopen(ATTR_CONF, "r")) == NULL) {
		if (errno == ENOENT)
			return 0;
		goto fail;
	}
	len = fread(text, 1, size_guess, file);
	if (ferror(file))
		goto fail;
	if (!feof(file)) {
		fclose(file);
		file = NULL;
		free(text);
		size_guess *= 2;
		goto repeat;
	}
	fclose(file);
	file = NULL;

	text[len] = 0;
	t = text;
	for (;;) {
		t += strspn(t, " \t\n");
		len = strcspn(t, " \t\n#");
		if (t[len] == '#') {
			if (len)
				goto parse_error;
			t += strcspn(t, "\n");
			continue;
		} else if (t[len] == 0)
			break;
		else if (t[len] == '\n')
			goto parse_error;
		pattern = strndup(t, len);
		if (!pattern)
			goto fail;
		t += len;

		t += strspn(t, " \t");
		len = strcspn(t, " \t\n#");
		if (len == 4 && !strncmp(t, "skip", 4))
			action = ATTR_ACTION_SKIP;
		else if (len == 11 && !strncmp(t, "permissions", 11))
			action = ATTR_ACTION_PERMISSIONS;
		else
			goto parse_error;
		t += len;
		t += strspn(t, " \t");
		if (*t != '#' && *t != '\n')
			goto parse_error;

		new = malloc(sizeof(struct attr_action));
		if (!new)
			goto parse_error;
		new->next = attr_actions;
		new->pattern = pattern;
		new->action = action;
		attr_actions = new;

		t += strcspn(t, "\n");
	}
	return 0;

parse_error:
	errno = EINVAL;

fail:
	{
		const char *q = quote (ctx, ATTR_CONF);
		error (ctx, "%s", q);
		quote_free (ctx, q);
	}

	free(pattern);
	if (file)
		fclose(file);
	free(text);
	free_attr_actions();
	return -1;
}

int
attr_copy_action(const char *name, struct error_context *ctx)
{
	struct attr_action *action = attr_actions;

	if (!attr_parse_attr_conf(ctx)) {
		for (action = attr_actions; action; action = action->next) {
			if (!fnmatch(action->pattern, name, 0))
				return action->action;
		}
	}
	return 0;
}