Blame view

fs/hfsplus/ioctl.c 5.06 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   *  linux/fs/hfsplus/ioctl.c
   *
   * Copyright (C) 2003
   * Ethan Benson <erbenson@alaska.net>
   * partially derived from linux/fs/ext2/ioctl.c
   * Copyright (C) 1993, 1994, 1995
   * Remy Card (card@masi.ibp.fr)
   * Laboratoire MASI - Institut Blaise Pascal
   * Universite Pierre et Marie Curie (Paris VI)
   *
   * hfsplus ioctls
   */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
14
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/fs.h>
42a74f206   Dave Hansen   [PATCH] r/o bind ...
16
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
  #include <linux/sched.h>
  #include <linux/xattr.h>
  #include <asm/uaccess.h>
  #include "hfsplus_fs.h"
94744567f   Christoph Hellwig   hfsplus: split hf...
21
  static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  {
94744567f   Christoph Hellwig   hfsplus: split hf...
23
  	struct inode *inode = file->f_path.dentry->d_inode;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
24
  	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
94744567f   Christoph Hellwig   hfsplus: split hf...
25
  	unsigned int flags = 0;
722c55d13   Christoph Hellwig   hfsplus: remove s...
26
  	if (inode->i_flags & S_IMMUTABLE)
94744567f   Christoph Hellwig   hfsplus: split hf...
27
  		flags |= FS_IMMUTABLE_FL;
596276c35   Anton Salikhmetov   hfsplus: fix an a...
28
  	if (inode->i_flags & S_APPEND)
94744567f   Christoph Hellwig   hfsplus: split hf...
29
  		flags |= FS_APPEND_FL;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
30
  	if (hip->userflags & HFSPLUS_FLG_NODUMP)
94744567f   Christoph Hellwig   hfsplus: split hf...
31
32
33
34
35
36
37
38
  		flags |= FS_NODUMP_FL;
  
  	return put_user(flags, user_flags);
  }
  
  static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
  {
  	struct inode *inode = file->f_path.dentry->d_inode;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
39
  	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  	unsigned int flags;
94744567f   Christoph Hellwig   hfsplus: split hf...
41
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

a561be710   Al Viro   switch a bunch of...
43
  	err = mnt_want_write_file(file);
94744567f   Christoph Hellwig   hfsplus: split hf...
44
  	if (err)
6333816ad   Christoph Hellwig   hfsplus: protect ...
45
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

2e1496707   Serge E. Hallyn   userns: rename is...
47
  	if (!inode_owner_or_capable(inode)) {
94744567f   Christoph Hellwig   hfsplus: split hf...
48
49
50
  		err = -EACCES;
  		goto out_drop_write;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

94744567f   Christoph Hellwig   hfsplus: split hf...
52
53
54
55
  	if (get_user(flags, user_flags)) {
  		err = -EFAULT;
  		goto out_drop_write;
  	}
6333816ad   Christoph Hellwig   hfsplus: protect ...
56
  	mutex_lock(&inode->i_mutex);
722c55d13   Christoph Hellwig   hfsplus: remove s...
57
58
  	if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
  	    inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
94744567f   Christoph Hellwig   hfsplus: split hf...
59
60
  		if (!capable(CAP_LINUX_IMMUTABLE)) {
  			err = -EPERM;
6333816ad   Christoph Hellwig   hfsplus: protect ...
61
  			goto out_unlock_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  	}
94744567f   Christoph Hellwig   hfsplus: split hf...
64
65
66
67
  
  	/* don't silently ignore unsupported ext2 flags */
  	if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
  		err = -EOPNOTSUPP;
6333816ad   Christoph Hellwig   hfsplus: protect ...
68
  		goto out_unlock_inode;
94744567f   Christoph Hellwig   hfsplus: split hf...
69
  	}
722c55d13   Christoph Hellwig   hfsplus: remove s...
70
71
  
  	if (flags & FS_IMMUTABLE_FL)
94744567f   Christoph Hellwig   hfsplus: split hf...
72
  		inode->i_flags |= S_IMMUTABLE;
722c55d13   Christoph Hellwig   hfsplus: remove s...
73
  	else
94744567f   Christoph Hellwig   hfsplus: split hf...
74
  		inode->i_flags &= ~S_IMMUTABLE;
722c55d13   Christoph Hellwig   hfsplus: remove s...
75
76
  
  	if (flags & FS_APPEND_FL)
94744567f   Christoph Hellwig   hfsplus: split hf...
77
  		inode->i_flags |= S_APPEND;
722c55d13   Christoph Hellwig   hfsplus: remove s...
78
  	else
94744567f   Christoph Hellwig   hfsplus: split hf...
79
  		inode->i_flags &= ~S_APPEND;
722c55d13   Christoph Hellwig   hfsplus: remove s...
80

94744567f   Christoph Hellwig   hfsplus: split hf...
81
  	if (flags & FS_NODUMP_FL)
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
82
  		hip->userflags |= HFSPLUS_FLG_NODUMP;
94744567f   Christoph Hellwig   hfsplus: split hf...
83
  	else
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
84
  		hip->userflags &= ~HFSPLUS_FLG_NODUMP;
94744567f   Christoph Hellwig   hfsplus: split hf...
85
86
87
  
  	inode->i_ctime = CURRENT_TIME_SEC;
  	mark_inode_dirty(inode);
6333816ad   Christoph Hellwig   hfsplus: protect ...
88
  out_unlock_inode:
e50fb58b5   Dan Carpenter   hfsplus: fix doub...
89
  	mutex_unlock(&inode->i_mutex);
94744567f   Christoph Hellwig   hfsplus: split hf...
90
  out_drop_write:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
91
  	mnt_drop_write_file(file);
6333816ad   Christoph Hellwig   hfsplus: protect ...
92
  out:
94744567f   Christoph Hellwig   hfsplus: split hf...
93
94
95
96
97
98
99
100
101
102
103
104
  	return err;
  }
  
  long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
  	void __user *argp = (void __user *)arg;
  
  	switch (cmd) {
  	case HFSPLUS_IOC_EXT2_GETFLAGS:
  		return hfsplus_ioctl_getflags(file, argp);
  	case HFSPLUS_IOC_EXT2_SETFLAGS:
  		return hfsplus_ioctl_setflags(file, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	default:
  		return -ENOTTY;
  	}
  }
  
  int hfsplus_setxattr(struct dentry *dentry, const char *name,
  		     const void *value, size_t size, int flags)
  {
  	struct inode *inode = dentry->d_inode;
  	struct hfs_find_data fd;
  	hfsplus_cat_entry entry;
  	struct hfsplus_cat_file *file;
  	int res;
  
  	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
  		return -EOPNOTSUPP;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
121
  	res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	if (res)
  		return res;
  	res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  	if (res)
  		goto out;
  	hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  			sizeof(struct hfsplus_cat_file));
  	file = &entry.file;
  
  	if (!strcmp(name, "hfs.type")) {
  		if (size == 4)
  			memcpy(&file->user_info.fdType, value, 4);
  		else
  			res = -ERANGE;
  	} else if (!strcmp(name, "hfs.creator")) {
  		if (size == 4)
  			memcpy(&file->user_info.fdCreator, value, 4);
  		else
  			res = -ERANGE;
  	} else
  		res = -EOPNOTSUPP;
e34947056   Christoph Hellwig   hfsplus: optimize...
143
  	if (!res) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
  				sizeof(struct hfsplus_cat_file));
e34947056   Christoph Hellwig   hfsplus: optimize...
146
147
  		hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  out:
  	hfs_find_exit(&fd);
  	return res;
  }
  
  ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
  			 void *value, size_t size)
  {
  	struct inode *inode = dentry->d_inode;
  	struct hfs_find_data fd;
  	hfsplus_cat_entry entry;
  	struct hfsplus_cat_file *file;
  	ssize_t res = 0;
  
  	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
  		return -EOPNOTSUPP;
  
  	if (size) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
166
  		res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  		if (res)
  			return res;
  		res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  		if (res)
  			goto out;
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  				sizeof(struct hfsplus_cat_file));
  	}
  	file = &entry.file;
  
  	if (!strcmp(name, "hfs.type")) {
  		if (size >= 4) {
  			memcpy(value, &file->user_info.fdType, 4);
  			res = 4;
  		} else
  			res = size ? -ERANGE : 4;
  	} else if (!strcmp(name, "hfs.creator")) {
  		if (size >= 4) {
  			memcpy(value, &file->user_info.fdCreator, 4);
  			res = 4;
  		} else
  			res = size ? -ERANGE : 4;
  	} else
46bf36ece   Christoph Hellwig   hfsplus: fix getx...
190
  		res = -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  out:
  	if (size)
  		hfs_find_exit(&fd);
  	return res;
  }
  
  #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
  
  ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
  {
  	struct inode *inode = dentry->d_inode;
  
  	if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
  		return -EOPNOTSUPP;
  
  	if (!buffer || !size)
  		return HFSPLUS_ATTRLIST_SIZE;
  	if (size < HFSPLUS_ATTRLIST_SIZE)
  		return -ERANGE;
  	strcpy(buffer, "hfs.type");
  	strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
  
  	return HFSPLUS_ATTRLIST_SIZE;
  }