aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
authorSougata Santra <sougata@tuxera.com>2014-01-23 18:55:25 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 19:37:00 -0500
commitd74a054fa4f5a3fc05eae11b3ff0b653b49dd7cb (patch)
treeb64e48e4e32192d8fc6575d4607330588469f561 /fs/hfsplus
parentd623a9420c9ae2b748ba458c0e9d59084419fce0 (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.c59
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
181static 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);
234out:
235 d_add(dentry, inode);
236 return NULL;
237}
238
239static void hfsplus_get_perms(struct inode *inode, 181static 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
387static const struct inode_operations hfsplus_file_inode_operations = { 329static 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,