• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/fs/hfsplus_journal/
1/*
2 *  linux/fs/hfsplus/ioctl.c
3 *
4 * Copyright (C) 2003
5 * Ethan Benson <erbenson@alaska.net>
6 * partially derived from linux/fs/ext2/ioctl.c
7 * Copyright (C) 1993, 1994, 1995
8 * Remy Card (card@masi.ibp.fr)
9 * Laboratoire MASI - Institut Blaise Pascal
10 * Universite Pierre et Marie Curie (Paris VI)
11 *
12 * hfsplus ioctls
13 */
14
15#include <linux/capability.h>
16#include <linux/fs.h>
17#include <linux/mount.h>
18#include <linux/sched.h>
19#include <linux/xattr.h>
20#include <asm/uaccess.h>
21#include "hfsplus_fs.h"
22
23static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
24{
25	struct inode *inode = file->f_path.dentry->d_inode;
26	unsigned int flags = 0;
27
28	if (inode->i_flags & S_IMMUTABLE)
29		flags |= FS_IMMUTABLE_FL;
30	if (inode->i_flags & S_APPEND)
31		flags |= FS_APPEND_FL;
32	if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
33		flags |= FS_NODUMP_FL;
34
35	return put_user(flags, user_flags);
36}
37
38static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
39{
40	struct inode *inode = file->f_path.dentry->d_inode;
41	unsigned int flags;
42	int err = 0;
43
44	err = mnt_want_write(file->f_path.mnt);
45	if (err)
46		goto out;
47/*
48	if (!inode_owner_or_capable(inode)) {
49		err = -EACCES;
50		goto out_drop_write;
51	}
52*/
53	if (get_user(flags, user_flags)) {
54		err = -EFAULT;
55		goto out_drop_write;
56	}
57
58	mutex_lock(&inode->i_mutex);
59
60	if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
61	    inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
62		if (!capable(CAP_LINUX_IMMUTABLE)) {
63			err = -EPERM;
64			goto out_unlock_inode;
65		}
66	}
67
68	/* don't silently ignore unsupported ext2 flags */
69	if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
70		err = -EOPNOTSUPP;
71		goto out_unlock_inode;
72	}
73
74	if (flags & FS_IMMUTABLE_FL)
75		inode->i_flags |= S_IMMUTABLE;
76	else
77		inode->i_flags &= ~S_IMMUTABLE;
78
79	if (flags & FS_APPEND_FL)
80		inode->i_flags |= S_APPEND;
81	else
82		inode->i_flags &= ~S_APPEND;
83
84	if (flags & FS_NODUMP_FL)
85		HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
86	else
87		HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;
88
89	inode->i_ctime = CURRENT_TIME_SEC;
90	mark_inode_dirty(inode);
91
92out_unlock_inode:
93	mutex_unlock(&inode->i_mutex);
94out_drop_write:
95	mnt_drop_write(file->f_path.mnt);
96out:
97	return err;
98}
99
100long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
101{
102	void __user *argp = (void __user *)arg;
103
104	switch (cmd) {
105	case HFSPLUS_IOC_EXT2_GETFLAGS:
106		return hfsplus_ioctl_getflags(file, argp);
107	case HFSPLUS_IOC_EXT2_SETFLAGS:
108		return hfsplus_ioctl_setflags(file, argp);
109	default:
110		return -ENOTTY;
111	}
112}
113
114int hfsplus_setxattr(struct dentry *dentry, const char *name,
115		     const void *value, size_t size, int flags)
116{
117	struct inode *inode = dentry->d_inode;
118	struct hfs_find_data fd;
119	hfsplus_cat_entry entry;
120	struct hfsplus_cat_file *file;
121	hfsplus_handle_t hfsplus_handle;
122	int res;
123
124	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
125		return -EOPNOTSUPP;
126
127	res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
128	if (res)
129		return res;
130
131	if ((res = hfsplus_journal_start(__FUNCTION__, inode->i_sb, &hfsplus_handle)))
132		return res;
133
134	res = hfsplus_find_cat(&hfsplus_handle, inode->i_sb, inode->i_ino, &fd);
135	if (res)
136		goto out;
137	hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
138			sizeof(struct hfsplus_cat_file));
139	file = &entry.file;
140
141	if (!strcmp(name, "hfs.type")) {
142		if (size == 4)
143			memcpy(&file->user_info.fdType, value, 4);
144		else
145			res = -ERANGE;
146	} else if (!strcmp(name, "hfs.creator")) {
147		if (size == 4)
148			memcpy(&file->user_info.fdCreator, value, 4);
149		else
150			res = -ERANGE;
151	} else
152		res = -EOPNOTSUPP;
153	if (!res)
154		hfs_bnode_write(&hfsplus_handle, fd.bnode, &entry, fd.entryoffset,
155				sizeof(struct hfsplus_cat_file));
156out:
157	hfs_find_exit(&hfsplus_handle, &fd);
158	hfsplus_journal_stop(&hfsplus_handle);
159	return res;
160}
161
162ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
163			 void *value, size_t size)
164{
165	struct inode *inode = dentry->d_inode;
166	struct hfs_find_data fd;
167	hfsplus_cat_entry entry;
168	struct hfsplus_cat_file *file;
169	hfsplus_handle_t hfsplus_handle;
170	ssize_t res = 0;
171	int ret;
172
173	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
174		return -EOPNOTSUPP;
175
176	if (size) {
177		res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
178		if (res)
179			return res;
180
181		if ((ret = hfsplus_journal_start(__FUNCTION__, inode->i_sb, &hfsplus_handle)))
182			return ret;
183
184		res = hfsplus_find_cat(&hfsplus_handle, inode->i_sb, inode->i_ino, &fd);
185		if (res)
186			goto out;
187		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
188				sizeof(struct hfsplus_cat_file));
189	}
190	else {
191		if ((ret = hfsplus_journal_start(__FUNCTION__, inode->i_sb, &hfsplus_handle)))
192			return ret;
193	}
194	file = &entry.file;
195
196	if (!strcmp(name, "hfs.type")) {
197		if (size >= 4) {
198			memcpy(value, &file->user_info.fdType, 4);
199			res = 4;
200		} else
201			res = size ? -ERANGE : 4;
202	} else if (!strcmp(name, "hfs.creator")) {
203		if (size >= 4) {
204			memcpy(value, &file->user_info.fdCreator, 4);
205			res = 4;
206		} else
207			res = size ? -ERANGE : 4;
208	} else
209		res = -EOPNOTSUPP;
210out:
211	if (size)
212		hfs_find_exit(&hfsplus_handle, &fd);
213	hfsplus_journal_stop(&hfsplus_handle);
214	return res;
215}
216
217#define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
218
219ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
220{
221	struct inode *inode = dentry->d_inode;
222
223	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
224		return -EOPNOTSUPP;
225
226	if (!buffer || !size)
227		return HFSPLUS_ATTRLIST_SIZE;
228	if (size < HFSPLUS_ATTRLIST_SIZE)
229		return -ERANGE;
230	strcpy(buffer, "hfs.type");
231	strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
232
233	return HFSPLUS_ATTRLIST_SIZE;
234}
235