diff options
author | Sougata Santra <sougata@tuxera.com> | 2014-12-18 19:17:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-18 22:08:10 -0500 |
commit | 89ac9b4d3d1a049ae1054f99b1aed81092cd0a82 (patch) | |
tree | b76f017fbe75cacd124b6ab796d2e4d5ddb9ea76 /fs/hfsplus/dir.c | |
parent | 859f7ef142a956676cb387b90f18e2e71e959c68 (diff) |
hfsplus: fix longname handling
Longname is not correctly handled by hfsplus driver. If an attempt to
create a longname(>255) file/directory is made, it succeeds by creating a
file/directory with HFSPLUS_MAX_STRLEN and incorrect catalog key. Thus
leaving the volume in an inconsistent state. This patch fixes this issue.
Although lookup is always called first to create a negative entry, so just
doing a check in lookup would probably fix this issue. I choose to
propagate error to other iops as well.
Please NOTE: I have factored out hfsplus_cat_build_key_with_cnid from
hfsplus_cat_build_key, to avoid unncessary branching.
Thanks a lot.
TEST:
------
dir="TEST_DIR"
cdir=`pwd`
name255="_123456789_123456789_123456789_123456789_123456789_123456789\
_123456789_123456789_123456789_123456789_123456789_123456789_123456789\
_123456789_123456789_123456789_123456789_123456789_123456789_123456789\
_123456789_123456789_123456789_123456789_123456789_1234"
name256="${name255}5"
mkdir $dir
cd $dir
touch $name255
rm -f $name255
touch $name256
ls -la
cd $cdir
rm -rf $dir
RESULT:
-------
[sougata@ultrabook tmp]$ cdir=`pwd`
[sougata@ultrabook tmp]$
name255="_123456789_123456789_123456789_123456789_123456789_123456789\
> _123456789_123456789_123456789_123456789_123456789_123456789_123456789\
> _123456789_123456789_123456789_123456789_123456789_123456789_123456789\
> _123456789_123456789_123456789_123456789_123456789_1234"
[sougata@ultrabook tmp]$ name256="${name255}5"
[sougata@ultrabook tmp]$
[sougata@ultrabook tmp]$ mkdir $dir
[sougata@ultrabook tmp]$ cd $dir
[sougata@ultrabook TEST_DIR]$ touch $name255
[sougata@ultrabook TEST_DIR]$ rm -f $name255
[sougata@ultrabook TEST_DIR]$ touch $name256
[sougata@ultrabook TEST_DIR]$ ls -la
ls: cannot access
_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234:
No such file or directory
total 0
drwxrwxr-x 1 sougata sougata 3 Feb 20 19:56 .
drwxrwxrwx 1 root root 6 Feb 20 19:56 ..
-????????? ? ? ? ? ?
_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234
[sougata@ultrabook TEST_DIR]$ cd $cdir
[sougata@ultrabook tmp]$ rm -rf $dir
rm: cannot remove `TEST_DIR': Directory not empty
-ENAMETOOLONG returned from hfsplus_asc2uni was not propaged to iops.
This allowed hfsplus to create files/directories with HFSPLUS_MAX_STRLEN
and incorrect keys, leaving the FS in an inconsistent state. This patch
fixes this issue.
Signed-off-by: Sougata Santra <sougata@tuxera.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Vyacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hfsplus/dir.c')
-rw-r--r-- | fs/hfsplus/dir.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 610a3260bef1..435bea231cc6 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -44,7 +44,10 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
44 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 44 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
45 | if (err) | 45 | if (err) |
46 | return ERR_PTR(err); | 46 | return ERR_PTR(err); |
47 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 47 | err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, |
48 | &dentry->d_name); | ||
49 | if (unlikely(err < 0)) | ||
50 | goto fail; | ||
48 | again: | 51 | again: |
49 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); | 52 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); |
50 | if (err) { | 53 | if (err) { |
@@ -97,9 +100,11 @@ again: | |||
97 | be32_to_cpu(entry.file.permissions.dev); | 100 | be32_to_cpu(entry.file.permissions.dev); |
98 | str.len = sprintf(name, "iNode%d", linkid); | 101 | str.len = sprintf(name, "iNode%d", linkid); |
99 | str.name = name; | 102 | str.name = name; |
100 | hfsplus_cat_build_key(sb, fd.search_key, | 103 | err = hfsplus_cat_build_key(sb, fd.search_key, |
101 | HFSPLUS_SB(sb)->hidden_dir->i_ino, | 104 | HFSPLUS_SB(sb)->hidden_dir->i_ino, |
102 | &str); | 105 | &str); |
106 | if (unlikely(err < 0)) | ||
107 | goto fail; | ||
103 | goto again; | 108 | goto again; |
104 | } | 109 | } |
105 | } else if (!dentry->d_fsdata) | 110 | } else if (!dentry->d_fsdata) |
@@ -145,7 +150,7 @@ static int hfsplus_readdir(struct file *file, struct dir_context *ctx) | |||
145 | err = -ENOMEM; | 150 | err = -ENOMEM; |
146 | goto out; | 151 | goto out; |
147 | } | 152 | } |
148 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); | 153 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, inode->i_ino); |
149 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 154 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
150 | if (err) | 155 | if (err) |
151 | goto out; | 156 | goto out; |