diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 05:20:10 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 05:20:10 -0400 |
commit | 39fe5434cb9de5da40510028b17b96bc4eb312b3 (patch) | |
tree | 7a02a317b9ad57da51ca99887c119e779ccf3f13 /fs/hfsplus | |
parent | 0fc72b81d3111d114ab378935b1cf07680ca1289 (diff) | |
parent | f695baf2df9e0413d3521661070103711545207a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/btree.c | 4 | ||||
-rw-r--r-- | fs/hfsplus/dir.c | 2 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 4 | ||||
-rw-r--r-- | fs/hfsplus/inode.c | 5 | ||||
-rw-r--r-- | fs/hfsplus/ioctl.c | 2 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 6 | ||||
-rw-r--r-- | fs/hfsplus/unicode.c | 230 |
7 files changed, 203 insertions, 50 deletions
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 90ebab753d30..050d29c0a5b5 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
@@ -62,8 +62,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | 62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && |
63 | (head->key_type == HFSPLUS_KEY_BINARY)) | 63 | (head->key_type == HFSPLUS_KEY_BINARY)) |
64 | tree->keycmp = hfsplus_cat_bin_cmp_key; | 64 | tree->keycmp = hfsplus_cat_bin_cmp_key; |
65 | else | 65 | else { |
66 | tree->keycmp = hfsplus_cat_case_cmp_key; | 66 | tree->keycmp = hfsplus_cat_case_cmp_key; |
67 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD; | ||
68 | } | ||
67 | } else { | 69 | } else { |
68 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | 70 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); |
69 | goto fail_page; | 71 | goto fail_page; |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 80b5682a2273..1955ee61251c 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
36 | u16 type; | 36 | u16 type; |
37 | 37 | ||
38 | sb = dir->i_sb; | 38 | sb = dir->i_sb; |
39 | |||
40 | dentry->d_op = &hfsplus_dentry_operations; | ||
39 | dentry->d_fsdata = NULL; | 41 | dentry->d_fsdata = NULL; |
40 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); | 42 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); |
41 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 43 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 3915635b4470..d9f5eda6d039 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -150,6 +150,7 @@ struct hfsplus_sb_info { | |||
150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 | 150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 |
151 | #define HFSPLUS_SB_FORCE 0x0004 | 151 | #define HFSPLUS_SB_FORCE 0x0004 |
152 | #define HFSPLUS_SB_HFSX 0x0008 | 152 | #define HFSPLUS_SB_HFSX 0x0008 |
153 | #define HFSPLUS_SB_CASEFOLD 0x0010 | ||
153 | 154 | ||
154 | 155 | ||
155 | struct hfsplus_inode_info { | 156 | struct hfsplus_inode_info { |
@@ -321,6 +322,7 @@ void hfsplus_file_truncate(struct inode *); | |||
321 | /* inode.c */ | 322 | /* inode.c */ |
322 | extern const struct address_space_operations hfsplus_aops; | 323 | extern const struct address_space_operations hfsplus_aops; |
323 | extern const struct address_space_operations hfsplus_btree_aops; | 324 | extern const struct address_space_operations hfsplus_btree_aops; |
325 | extern struct dentry_operations hfsplus_dentry_operations; | ||
324 | 326 | ||
325 | void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); | 327 | void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); |
326 | void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); | 328 | void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); |
@@ -353,6 +355,8 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unist | |||
353 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 355 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); |
354 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 356 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); |
355 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | 357 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); |
358 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str); | ||
359 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2); | ||
356 | 360 | ||
357 | /* wrapper.c */ | 361 | /* wrapper.c */ |
358 | int hfsplus_read_wrapper(struct super_block *); | 362 | int hfsplus_read_wrapper(struct super_block *); |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 409ce5429c91..6f7c662174db 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -131,6 +131,11 @@ const struct address_space_operations hfsplus_aops = { | |||
131 | .writepages = hfsplus_writepages, | 131 | .writepages = hfsplus_writepages, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | struct dentry_operations hfsplus_dentry_operations = { | ||
135 | .d_hash = hfsplus_hash_dentry, | ||
136 | .d_compare = hfsplus_compare_dentry, | ||
137 | }; | ||
138 | |||
134 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, | 139 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, |
135 | struct nameidata *nd) | 140 | struct nameidata *nd) |
136 | { | 141 | { |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 79fd10402ea3..b60c0affbec5 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
@@ -38,7 +38,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
38 | if (IS_RDONLY(inode)) | 38 | if (IS_RDONLY(inode)) |
39 | return -EROFS; | 39 | return -EROFS; |
40 | 40 | ||
41 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 41 | if (!is_owner_or_cap(inode)) |
42 | return -EACCES; | 42 | return -EACCES; |
43 | 43 | ||
44 | if (get_user(flags, (int __user *)arg)) | 44 | if (get_user(flags, (int __user *)arg)) |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index ebd1b380cbbc..7b0f2e5a44e2 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -283,11 +283,10 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
283 | struct nls_table *nls = NULL; | 283 | struct nls_table *nls = NULL; |
284 | int err = -EINVAL; | 284 | int err = -EINVAL; |
285 | 285 | ||
286 | sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL); | 286 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
287 | if (!sbi) | 287 | if (!sbi) |
288 | return -ENOMEM; | 288 | return -ENOMEM; |
289 | 289 | ||
290 | memset(sbi, 0, sizeof(HFSPLUS_SB(sb))); | ||
291 | sb->s_fs_info = sbi; | 290 | sb->s_fs_info = sbi; |
292 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); | 291 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); |
293 | hfsplus_fill_defaults(sbi); | 292 | hfsplus_fill_defaults(sbi); |
@@ -381,6 +380,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
381 | iput(root); | 380 | iput(root); |
382 | goto cleanup; | 381 | goto cleanup; |
383 | } | 382 | } |
383 | sb->s_root->d_op = &hfsplus_dentry_operations; | ||
384 | 384 | ||
385 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; | 385 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; |
386 | str.name = HFSP_HIDDENDIR_NAME; | 386 | str.name = HFSP_HIDDENDIR_NAME; |
@@ -479,7 +479,7 @@ static int __init init_hfsplus_fs(void) | |||
479 | 479 | ||
480 | hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache", | 480 | hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache", |
481 | HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN, | 481 | HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN, |
482 | hfsplus_init_once, NULL); | 482 | hfsplus_init_once); |
483 | if (!hfsplus_inode_cachep) | 483 | if (!hfsplus_inode_cachep) |
484 | return -ENOMEM; | 484 | return -ENOMEM; |
485 | err = register_filesystem(&hfsplus_fs_type); | 485 | err = register_filesystem(&hfsplus_fs_type); |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 689c8bd721fb..9e10f9444b64 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -239,61 +239,201 @@ out: | |||
239 | return res; | 239 | return res; |
240 | } | 240 | } |
241 | 241 | ||
242 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len) | 242 | /* |
243 | * Convert one or more ASCII characters into a single unicode character. | ||
244 | * Returns the number of ASCII characters corresponding to the unicode char. | ||
245 | */ | ||
246 | static inline int asc2unichar(struct super_block *sb, const char *astr, int len, | ||
247 | wchar_t *uc) | ||
243 | { | 248 | { |
244 | struct nls_table *nls = HFSPLUS_SB(sb).nls; | 249 | int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc); |
245 | int size, off, decompose; | 250 | if (size <= 0) { |
251 | *uc = '?'; | ||
252 | size = 1; | ||
253 | } | ||
254 | switch (*uc) { | ||
255 | case 0x2400: | ||
256 | *uc = 0; | ||
257 | break; | ||
258 | case ':': | ||
259 | *uc = '/'; | ||
260 | break; | ||
261 | } | ||
262 | return size; | ||
263 | } | ||
264 | |||
265 | /* Decomposes a single unicode character. */ | ||
266 | static inline u16 *decompose_unichar(wchar_t uc, int *size) | ||
267 | { | ||
268 | int off; | ||
269 | |||
270 | off = hfsplus_decompose_table[(uc >> 12) & 0xf]; | ||
271 | if (off == 0 || off == 0xffff) | ||
272 | return NULL; | ||
273 | |||
274 | off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)]; | ||
275 | if (!off) | ||
276 | return NULL; | ||
277 | |||
278 | off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)]; | ||
279 | if (!off) | ||
280 | return NULL; | ||
281 | |||
282 | off = hfsplus_decompose_table[off + (uc & 0xf)]; | ||
283 | *size = off & 3; | ||
284 | if (*size == 0) | ||
285 | return NULL; | ||
286 | return hfsplus_decompose_table + (off / 4); | ||
287 | } | ||
288 | |||
289 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | ||
290 | const char *astr, int len) | ||
291 | { | ||
292 | int size, dsize, decompose; | ||
293 | u16 *dstr, outlen = 0; | ||
246 | wchar_t c; | 294 | wchar_t c; |
247 | u16 outlen = 0; | ||
248 | 295 | ||
249 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | 296 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); |
250 | |||
251 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { | 297 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { |
252 | size = nls->char2uni(astr, len, &c); | 298 | size = asc2unichar(sb, astr, len, &c); |
253 | if (size <= 0) { | 299 | |
254 | c = '?'; | 300 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { |
255 | size = 1; | 301 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) |
256 | } | ||
257 | astr += size; | ||
258 | len -= size; | ||
259 | switch (c) { | ||
260 | case 0x2400: | ||
261 | c = 0; | ||
262 | break; | ||
263 | case ':': | ||
264 | c = '/'; | ||
265 | break; | ||
266 | } | ||
267 | if (c >= 0xc0 && decompose) { | ||
268 | off = hfsplus_decompose_table[(c >> 12) & 0xf]; | ||
269 | if (!off) | ||
270 | goto done; | ||
271 | if (off == 0xffff) { | ||
272 | goto done; | ||
273 | } | ||
274 | off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)]; | ||
275 | if (!off) | ||
276 | goto done; | ||
277 | off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)]; | ||
278 | if (!off) | ||
279 | goto done; | ||
280 | off = hfsplus_decompose_table[off + (c & 0xf)]; | ||
281 | size = off & 3; | ||
282 | if (!size) | ||
283 | goto done; | ||
284 | off /= 4; | ||
285 | if (outlen + size > HFSPLUS_MAX_STRLEN) | ||
286 | break; | 302 | break; |
287 | do { | 303 | do { |
288 | ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]); | 304 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); |
289 | } while (--size > 0); | 305 | } while (--dsize > 0); |
290 | continue; | 306 | } else |
291 | } | 307 | ustr->unicode[outlen++] = cpu_to_be16(c); |
292 | done: | 308 | |
293 | ustr->unicode[outlen++] = cpu_to_be16(c); | 309 | astr += size; |
310 | len -= size; | ||
294 | } | 311 | } |
295 | ustr->length = cpu_to_be16(outlen); | 312 | ustr->length = cpu_to_be16(outlen); |
296 | if (len > 0) | 313 | if (len > 0) |
297 | return -ENAMETOOLONG; | 314 | return -ENAMETOOLONG; |
298 | return 0; | 315 | return 0; |
299 | } | 316 | } |
317 | |||
318 | /* | ||
319 | * Hash a string to an integer as appropriate for the HFS+ filesystem. | ||
320 | * Composed unicode characters are decomposed and case-folding is performed | ||
321 | * if the appropriate bits are (un)set on the superblock. | ||
322 | */ | ||
323 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) | ||
324 | { | ||
325 | struct super_block *sb = dentry->d_sb; | ||
326 | const char *astr; | ||
327 | const u16 *dstr; | ||
328 | int casefold, decompose, size, dsize, len; | ||
329 | unsigned long hash; | ||
330 | wchar_t c; | ||
331 | u16 c2; | ||
332 | |||
333 | casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); | ||
334 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | ||
335 | hash = init_name_hash(); | ||
336 | astr = str->name; | ||
337 | len = str->len; | ||
338 | while (len > 0) { | ||
339 | size = asc2unichar(sb, astr, len, &c); | ||
340 | astr += size; | ||
341 | len -= size; | ||
342 | |||
343 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { | ||
344 | do { | ||
345 | c2 = *dstr++; | ||
346 | if (!casefold || (c2 = case_fold(c2))) | ||
347 | hash = partial_name_hash(c2, hash); | ||
348 | } while (--dsize > 0); | ||
349 | } else { | ||
350 | c2 = c; | ||
351 | if (!casefold || (c2 = case_fold(c2))) | ||
352 | hash = partial_name_hash(c2, hash); | ||
353 | } | ||
354 | } | ||
355 | str->hash = end_name_hash(hash); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Compare strings with HFS+ filename ordering. | ||
362 | * Composed unicode characters are decomposed and case-folding is performed | ||
363 | * if the appropriate bits are (un)set on the superblock. | ||
364 | */ | ||
365 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2) | ||
366 | { | ||
367 | struct super_block *sb = dentry->d_sb; | ||
368 | int casefold, decompose, size; | ||
369 | int dsize1, dsize2, len1, len2; | ||
370 | const u16 *dstr1, *dstr2; | ||
371 | const char *astr1, *astr2; | ||
372 | u16 c1, c2; | ||
373 | wchar_t c; | ||
374 | |||
375 | casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); | ||
376 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | ||
377 | astr1 = s1->name; | ||
378 | len1 = s1->len; | ||
379 | astr2 = s2->name; | ||
380 | len2 = s2->len; | ||
381 | dsize1 = dsize2 = 0; | ||
382 | dstr1 = dstr2 = NULL; | ||
383 | |||
384 | while (len1 > 0 && len2 > 0) { | ||
385 | if (!dsize1) { | ||
386 | size = asc2unichar(sb, astr1, len1, &c); | ||
387 | astr1 += size; | ||
388 | len1 -= size; | ||
389 | |||
390 | if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) { | ||
391 | c1 = c; | ||
392 | dstr1 = &c1; | ||
393 | dsize1 = 1; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if (!dsize2) { | ||
398 | size = asc2unichar(sb, astr2, len2, &c); | ||
399 | astr2 += size; | ||
400 | len2 -= size; | ||
401 | |||
402 | if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) { | ||
403 | c2 = c; | ||
404 | dstr2 = &c2; | ||
405 | dsize2 = 1; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | c1 = *dstr1; | ||
410 | c2 = *dstr2; | ||
411 | if (casefold) { | ||
412 | if (!(c1 = case_fold(c1))) { | ||
413 | dstr1++; | ||
414 | dsize1--; | ||
415 | continue; | ||
416 | } | ||
417 | if (!(c2 = case_fold(c2))) { | ||
418 | dstr2++; | ||
419 | dsize2--; | ||
420 | continue; | ||
421 | } | ||
422 | } | ||
423 | if (c1 < c2) | ||
424 | return -1; | ||
425 | else if (c1 > c2) | ||
426 | return 1; | ||
427 | |||
428 | dstr1++; | ||
429 | dsize1--; | ||
430 | dstr2++; | ||
431 | dsize2--; | ||
432 | } | ||
433 | |||
434 | if (len1 < len2) | ||
435 | return -1; | ||
436 | if (len1 > len2) | ||
437 | return 1; | ||
438 | return 0; | ||
439 | } | ||