diff options
author | Sougata Santra <sougata@tuxera.com> | 2014-01-23 18:55:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-23 19:37:00 -0500 |
commit | d74a054fa4f5a3fc05eae11b3ff0b653b49dd7cb (patch) | |
tree | b64e48e4e32192d8fc6575d4607330588469f561 /fs/hfsplus | |
parent | d623a9420c9ae2b748ba458c0e9d59084419fce0 (diff) |
hfsplus: remove hfsplus_file_lookup()
HFS+ resource fork lookup breaks opendir() library function. Since
opendir first calls open() with O_DIRECTORY flag set. O_DIRECTORY means
"refuse to open if not a directory". The open system call in the kernel
does a check for inode->i_op->lookup and returns -ENOTDIR. So if
hfsplus_file_lookup is set it allows opendir() for plain files.
Also resource fork lookup in HFS+ does not work. Since it is never
invoked after VFS permission checking. It will always return with
-EACCES.
When we call opendir() on a file, it does not return NULL. opendir()
library call is based on open with O_DIRECTORY flag passed and then
layered on top of getdents() system call. O_DIRECTORY means "refuse to
open if not a directory".
The open() system call in the kernel does a check for: do_sys_open()
-->..--> can_lookup() i.e it only checks inode->i_op->lookup and returns
ENOTDIR if this function pointer is not set.
In OSX, we can open "file/rsrc" to get the resource fork of "file". This
behavior is emulated inside hfsplus on Linux, which means that to some
degree every file acts like a directory. That is the reason lookup()
inode operations is supported for files, and it is possible to do a lookup
on this specific name. As a result of this open succeeds without
returning ENOTDIR for HFS+
Please see the LKML discussion thread on this issue:
http://marc.info/?l=linux-fsdevel&m=122823343730412&w=2
I tried to test file/rsrc lookup in HFS+ driver and the feature does not
work. From OSX:
$ touch test
$ echo "1234" > test/..namedfork/rsrc
$ ls -l test..namedfork/rsrc
--rw-r--r-- 1 tuxera staff 5 10 dec 12:59 test/..namedfork/rsrc
[sougata@ultrabook tmp]$ id
uid=1000(sougata) gid=1000(sougata) groups=1000(sougata),5(tty),18(dialout),1001(vboxusers)
[sougata@ultrabook tmp]$ mount
/dev/sdb1 on /mnt/tmp type hfsplus (rw,relatime,umask=0,uid=1000,gid=1000,nls=utf8)
[sougata@ultrabook tmp]$ ls -l test/rsrc
ls: cannot access test/rsrc: Permission denied
According to this LKML thread it is expected behavior.
http://marc.info/?t=121139033800008&r=1&w=4
I guess now that permission checking happens in vfs generic_permission() ?
So it turns out that even though the lookup() inode_operation exists for
HFS+ files. It cannot really get invoked ?. So if we can disable this
feature to make opendir() work for HFS+.
Signed-off-by: Sougata Santra <sougata@tuxera.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Cc: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: Anton Altaparmakov <aia21@cam.ac.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/inode.c | 59 |
1 files changed, 0 insertions, 59 deletions
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 37213d075f3c..3ebda928229c 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -178,64 +178,6 @@ const struct dentry_operations hfsplus_dentry_operations = { | |||
178 | .d_compare = hfsplus_compare_dentry, | 178 | .d_compare = hfsplus_compare_dentry, |
179 | }; | 179 | }; |
180 | 180 | ||
181 | static struct dentry *hfsplus_file_lookup(struct inode *dir, | ||
182 | struct dentry *dentry, unsigned int flags) | ||
183 | { | ||
184 | struct hfs_find_data fd; | ||
185 | struct super_block *sb = dir->i_sb; | ||
186 | struct inode *inode = NULL; | ||
187 | struct hfsplus_inode_info *hip; | ||
188 | int err; | ||
189 | |||
190 | if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) | ||
191 | goto out; | ||
192 | |||
193 | inode = HFSPLUS_I(dir)->rsrc_inode; | ||
194 | if (inode) | ||
195 | goto out; | ||
196 | |||
197 | inode = new_inode(sb); | ||
198 | if (!inode) | ||
199 | return ERR_PTR(-ENOMEM); | ||
200 | |||
201 | hip = HFSPLUS_I(inode); | ||
202 | inode->i_ino = dir->i_ino; | ||
203 | INIT_LIST_HEAD(&hip->open_dir_list); | ||
204 | mutex_init(&hip->extents_lock); | ||
205 | hip->extent_state = 0; | ||
206 | hip->flags = 0; | ||
207 | hip->userflags = 0; | ||
208 | set_bit(HFSPLUS_I_RSRC, &hip->flags); | ||
209 | |||
210 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | ||
211 | if (!err) { | ||
212 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); | ||
213 | if (!err) | ||
214 | err = hfsplus_cat_read_inode(inode, &fd); | ||
215 | hfs_find_exit(&fd); | ||
216 | } | ||
217 | if (err) { | ||
218 | iput(inode); | ||
219 | return ERR_PTR(err); | ||
220 | } | ||
221 | hip->rsrc_inode = dir; | ||
222 | HFSPLUS_I(dir)->rsrc_inode = inode; | ||
223 | igrab(dir); | ||
224 | |||
225 | /* | ||
226 | * __mark_inode_dirty expects inodes to be hashed. Since we don't | ||
227 | * want resource fork inodes in the regular inode space, we make them | ||
228 | * appear hashed, but do not put on any lists. hlist_del() | ||
229 | * will work fine and require no locking. | ||
230 | */ | ||
231 | hlist_add_fake(&inode->i_hash); | ||
232 | |||
233 | mark_inode_dirty(inode); | ||
234 | out: | ||
235 | d_add(dentry, inode); | ||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | static void hfsplus_get_perms(struct inode *inode, | 181 | static void hfsplus_get_perms(struct inode *inode, |
240 | struct hfsplus_perm *perms, int dir) | 182 | struct hfsplus_perm *perms, int dir) |
241 | { | 183 | { |
@@ -385,7 +327,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
385 | } | 327 | } |
386 | 328 | ||
387 | static const struct inode_operations hfsplus_file_inode_operations = { | 329 | static const struct inode_operations hfsplus_file_inode_operations = { |
388 | .lookup = hfsplus_file_lookup, | ||
389 | .setattr = hfsplus_setattr, | 330 | .setattr = hfsplus_setattr, |
390 | .setxattr = generic_setxattr, | 331 | .setxattr = generic_setxattr, |
391 | .getxattr = generic_getxattr, | 332 | .getxattr = generic_getxattr, |