162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hfs/attr.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Export hfs data via xattr
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/fs.h>
1262306a36Sopenharmony_ci#include <linux/xattr.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "hfs_fs.h"
1562306a36Sopenharmony_ci#include "btree.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cienum hfs_xattr_type {
1862306a36Sopenharmony_ci	HFS_TYPE,
1962306a36Sopenharmony_ci	HFS_CREATOR,
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type,
2362306a36Sopenharmony_ci			  const void *value, size_t size, int flags)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct hfs_find_data fd;
2662306a36Sopenharmony_ci	hfs_cat_rec rec;
2762306a36Sopenharmony_ci	struct hfs_cat_file *file;
2862306a36Sopenharmony_ci	int res;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
3162306a36Sopenharmony_ci		return -EOPNOTSUPP;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
3462306a36Sopenharmony_ci	if (res)
3562306a36Sopenharmony_ci		return res;
3662306a36Sopenharmony_ci	fd.search_key->cat = HFS_I(inode)->cat_key;
3762306a36Sopenharmony_ci	res = hfs_brec_find(&fd);
3862306a36Sopenharmony_ci	if (res)
3962306a36Sopenharmony_ci		goto out;
4062306a36Sopenharmony_ci	hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
4162306a36Sopenharmony_ci			sizeof(struct hfs_cat_file));
4262306a36Sopenharmony_ci	file = &rec.file;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	switch (type) {
4562306a36Sopenharmony_ci	case HFS_TYPE:
4662306a36Sopenharmony_ci		if (size == 4)
4762306a36Sopenharmony_ci			memcpy(&file->UsrWds.fdType, value, 4);
4862306a36Sopenharmony_ci		else
4962306a36Sopenharmony_ci			res = -ERANGE;
5062306a36Sopenharmony_ci		break;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	case HFS_CREATOR:
5362306a36Sopenharmony_ci		if (size == 4)
5462306a36Sopenharmony_ci			memcpy(&file->UsrWds.fdCreator, value, 4);
5562306a36Sopenharmony_ci		else
5662306a36Sopenharmony_ci			res = -ERANGE;
5762306a36Sopenharmony_ci		break;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!res)
6162306a36Sopenharmony_ci		hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
6262306a36Sopenharmony_ci				sizeof(struct hfs_cat_file));
6362306a36Sopenharmony_ciout:
6462306a36Sopenharmony_ci	hfs_find_exit(&fd);
6562306a36Sopenharmony_ci	return res;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type,
6962306a36Sopenharmony_ci			      void *value, size_t size)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct hfs_find_data fd;
7262306a36Sopenharmony_ci	hfs_cat_rec rec;
7362306a36Sopenharmony_ci	struct hfs_cat_file *file;
7462306a36Sopenharmony_ci	ssize_t res = 0;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
7762306a36Sopenharmony_ci		return -EOPNOTSUPP;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (size) {
8062306a36Sopenharmony_ci		res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
8162306a36Sopenharmony_ci		if (res)
8262306a36Sopenharmony_ci			return res;
8362306a36Sopenharmony_ci		fd.search_key->cat = HFS_I(inode)->cat_key;
8462306a36Sopenharmony_ci		res = hfs_brec_find(&fd);
8562306a36Sopenharmony_ci		if (res)
8662306a36Sopenharmony_ci			goto out;
8762306a36Sopenharmony_ci		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
8862306a36Sopenharmony_ci				sizeof(struct hfs_cat_file));
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci	file = &rec.file;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	switch (type) {
9362306a36Sopenharmony_ci	case HFS_TYPE:
9462306a36Sopenharmony_ci		if (size >= 4) {
9562306a36Sopenharmony_ci			memcpy(value, &file->UsrWds.fdType, 4);
9662306a36Sopenharmony_ci			res = 4;
9762306a36Sopenharmony_ci		} else
9862306a36Sopenharmony_ci			res = size ? -ERANGE : 4;
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	case HFS_CREATOR:
10262306a36Sopenharmony_ci		if (size >= 4) {
10362306a36Sopenharmony_ci			memcpy(value, &file->UsrWds.fdCreator, 4);
10462306a36Sopenharmony_ci			res = 4;
10562306a36Sopenharmony_ci		} else
10662306a36Sopenharmony_ci			res = size ? -ERANGE : 4;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciout:
11162306a36Sopenharmony_ci	if (size)
11262306a36Sopenharmony_ci		hfs_find_exit(&fd);
11362306a36Sopenharmony_ci	return res;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int hfs_xattr_get(const struct xattr_handler *handler,
11762306a36Sopenharmony_ci			 struct dentry *unused, struct inode *inode,
11862306a36Sopenharmony_ci			 const char *name, void *value, size_t size)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return __hfs_getxattr(inode, handler->flags, value, size);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int hfs_xattr_set(const struct xattr_handler *handler,
12462306a36Sopenharmony_ci			 struct mnt_idmap *idmap,
12562306a36Sopenharmony_ci			 struct dentry *unused, struct inode *inode,
12662306a36Sopenharmony_ci			 const char *name, const void *value, size_t size,
12762306a36Sopenharmony_ci			 int flags)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	if (!value)
13062306a36Sopenharmony_ci		return -EOPNOTSUPP;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return __hfs_setxattr(inode, handler->flags, value, size, flags);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic const struct xattr_handler hfs_creator_handler = {
13662306a36Sopenharmony_ci	.name = "hfs.creator",
13762306a36Sopenharmony_ci	.flags = HFS_CREATOR,
13862306a36Sopenharmony_ci	.get = hfs_xattr_get,
13962306a36Sopenharmony_ci	.set = hfs_xattr_set,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const struct xattr_handler hfs_type_handler = {
14362306a36Sopenharmony_ci	.name = "hfs.type",
14462306a36Sopenharmony_ci	.flags = HFS_TYPE,
14562306a36Sopenharmony_ci	.get = hfs_xattr_get,
14662306a36Sopenharmony_ci	.set = hfs_xattr_set,
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciconst struct xattr_handler *hfs_xattr_handlers[] = {
15062306a36Sopenharmony_ci	&hfs_creator_handler,
15162306a36Sopenharmony_ci	&hfs_type_handler,
15262306a36Sopenharmony_ci	NULL
15362306a36Sopenharmony_ci};
154