1/*
2 *  linux/fs/hfs/attr.c
3 *
4 * (C) 2003 Ardis Technologies <roman@ardistech.com>
5 *
6 * Export hfs data via xattr
7 */
8
9
10#include <linux/fs.h>
11#include <linux/xattr.h>
12
13#include "hfs_fs.h"
14#include "btree.h"
15
16int hfs_setxattr(struct dentry *dentry, const char *name,
17		 const void *value, size_t size, int flags)
18{
19	struct inode *inode = d_inode(dentry);
20	struct hfs_find_data fd;
21	hfs_cat_rec rec;
22	struct hfs_cat_file *file;
23	int res;
24
25	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
26		return -EOPNOTSUPP;
27
28	res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
29	if (res)
30		return res;
31	fd.search_key->cat = HFS_I(inode)->cat_key;
32	res = hfs_brec_find(&fd);
33	if (res)
34		goto out;
35	hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
36			sizeof(struct hfs_cat_file));
37	file = &rec.file;
38
39	if (!strcmp(name, "hfs.type")) {
40		if (size == 4)
41			memcpy(&file->UsrWds.fdType, value, 4);
42		else
43			res = -ERANGE;
44	} else if (!strcmp(name, "hfs.creator")) {
45		if (size == 4)
46			memcpy(&file->UsrWds.fdCreator, value, 4);
47		else
48			res = -ERANGE;
49	} else
50		res = -EOPNOTSUPP;
51	if (!res)
52		hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
53				sizeof(struct hfs_cat_file));
54out:
55	hfs_find_exit(&fd);
56	return res;
57}
58
59ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
60			 void *value, size_t size)
61{
62	struct inode *inode = d_inode(dentry);
63	struct hfs_find_data fd;
64	hfs_cat_rec rec;
65	struct hfs_cat_file *file;
66	ssize_t res = 0;
67
68	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
69		return -EOPNOTSUPP;
70
71	if (size) {
72		res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
73		if (res)
74			return res;
75		fd.search_key->cat = HFS_I(inode)->cat_key;
76		res = hfs_brec_find(&fd);
77		if (res)
78			goto out;
79		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
80				sizeof(struct hfs_cat_file));
81	}
82	file = &rec.file;
83
84	if (!strcmp(name, "hfs.type")) {
85		if (size >= 4) {
86			memcpy(value, &file->UsrWds.fdType, 4);
87			res = 4;
88		} else
89			res = size ? -ERANGE : 4;
90	} else if (!strcmp(name, "hfs.creator")) {
91		if (size >= 4) {
92			memcpy(value, &file->UsrWds.fdCreator, 4);
93			res = 4;
94		} else
95			res = size ? -ERANGE : 4;
96	} else
97		res = -ENODATA;
98out:
99	if (size)
100		hfs_find_exit(&fd);
101	return res;
102}
103
104#define HFS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
105
106ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
107{
108	struct inode *inode = d_inode(dentry);
109
110	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
111		return -EOPNOTSUPP;
112
113	if (!buffer || !size)
114		return HFS_ATTRLIST_SIZE;
115	if (size < HFS_ATTRLIST_SIZE)
116		return -ERANGE;
117	strcpy(buffer, "hfs.type");
118	strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
119
120	return HFS_ATTRLIST_SIZE;
121}
122