mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	[PATCH] hfs: add HFSX support
Add support for HFSX, which allows for case-sensitive filenames. Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
		
							parent
							
								
									7cf3cc3036
								
							
						
					
					
						commit
						2179d372d9
					
				
					 8 changed files with 90 additions and 23 deletions
				
			
		|  | @ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 
 | ||||
| 	init_MUTEX(&tree->tree_lock); | ||||
| 	spin_lock_init(&tree->hash_lock); | ||||
| 	/* Set the correct compare function */ | ||||
| 	tree->sb = sb; | ||||
| 	tree->cnid = id; | ||||
| 	if (id == HFSPLUS_EXT_CNID) { | ||||
| 		tree->keycmp = hfsplus_ext_cmp_key; | ||||
| 	} else if (id == HFSPLUS_CAT_CNID) { | ||||
| 		tree->keycmp = hfsplus_cat_cmp_key; | ||||
| 	} else { | ||||
| 		printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||||
| 		goto free_tree; | ||||
| 	} | ||||
| 	tree->inode = iget(sb, id); | ||||
| 	if (!tree->inode) | ||||
| 		goto free_tree; | ||||
|  | @ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
| 	tree->max_key_len = be16_to_cpu(head->max_key_len); | ||||
| 	tree->depth = be16_to_cpu(head->depth); | ||||
| 
 | ||||
| 	/* Set the correct compare function */ | ||||
| 	if (id == HFSPLUS_EXT_CNID) { | ||||
| 		tree->keycmp = hfsplus_ext_cmp_key; | ||||
| 	} else if (id == HFSPLUS_CAT_CNID) { | ||||
| 		if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | ||||
| 		    (head->key_type == HFSPLUS_KEY_BINARY)) | ||||
| 			tree->keycmp = hfsplus_cat_bin_cmp_key; | ||||
| 		else | ||||
| 			tree->keycmp = hfsplus_cat_case_cmp_key; | ||||
| 	} else { | ||||
| 		printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||||
| 		goto fail_page; | ||||
| 	} | ||||
| 
 | ||||
| 	size = tree->node_size; | ||||
| 	if (!size || size & (size - 1)) | ||||
| 		goto fail_page; | ||||
|  |  | |||
|  | @ -13,7 +13,8 @@ | |||
| #include "hfsplus_fs.h" | ||||
| #include "hfsplus_raw.h" | ||||
| 
 | ||||
| int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | ||||
| int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, | ||||
| 			     const hfsplus_btree_key *k2) | ||||
| { | ||||
| 	__be32 k1p, k2p; | ||||
| 
 | ||||
|  | @ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | |||
| 	if (k1p != k2p) | ||||
| 		return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | ||||
| 
 | ||||
| 	return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name); | ||||
| 	return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); | ||||
| } | ||||
| 
 | ||||
| int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | ||||
| 			    const hfsplus_btree_key *k2) | ||||
| { | ||||
| 	__be32 k1p, k2p; | ||||
| 
 | ||||
| 	k1p = k1->cat.parent; | ||||
| 	k2p = k2->cat.parent; | ||||
| 	if (k1p != k2p) | ||||
| 		return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | ||||
| 
 | ||||
| 	return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); | ||||
| } | ||||
| 
 | ||||
| void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | ||||
|  |  | |||
|  | @ -16,7 +16,8 @@ | |||
| #include "hfsplus_raw.h" | ||||
| 
 | ||||
| /* Compare two extents keys, returns 0 on same, pos/neg for difference */ | ||||
| int hfsplus_ext_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | ||||
| int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, | ||||
| 			const hfsplus_btree_key *k2) | ||||
| { | ||||
| 	__be32 k1id, k2id; | ||||
| 	__be32 k1s, k2s; | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ | |||
| #define HFSPLUS_TYPE_DATA 0x00 | ||||
| #define HFSPLUS_TYPE_RSRC 0xFF | ||||
| 
 | ||||
| typedef int (*btree_keycmp)(hfsplus_btree_key *, hfsplus_btree_key *); | ||||
| typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||||
| 
 | ||||
| #define NODE_HASH_SIZE	256 | ||||
| 
 | ||||
|  | @ -149,6 +149,7 @@ struct hfsplus_sb_info { | |||
| #define HFSPLUS_SB_WRITEBACKUP	0x0001 | ||||
| #define HFSPLUS_SB_NODECOMPOSE	0x0002 | ||||
| #define HFSPLUS_SB_FORCE	0x0004 | ||||
| #define HFSPLUS_SB_HFSX		0x0008 | ||||
| 
 | ||||
| 
 | ||||
| struct hfsplus_inode_info { | ||||
|  | @ -303,7 +304,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); | |||
| int hfs_brec_goto(struct hfs_find_data *, int); | ||||
| 
 | ||||
| /* catalog.c */ | ||||
| int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | ||||
| int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||||
| int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||||
| void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); | ||||
| int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); | ||||
| int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); | ||||
|  | @ -312,7 +314,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, | |||
| 		       struct inode *, struct qstr *); | ||||
| 
 | ||||
| /* extents.c */ | ||||
| int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | ||||
| int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||||
| void hfsplus_ext_write_extent(struct inode *); | ||||
| int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | ||||
| int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); | ||||
|  | @ -350,7 +352,8 @@ extern u16 hfsplus_decompose_table[]; | |||
| extern u16 hfsplus_compose_table[]; | ||||
| 
 | ||||
| /* unicode.c */ | ||||
| int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||||
| int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||||
| int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||||
| int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | ||||
| int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,8 +22,10 @@ | |||
| #define HFSPLUS_SECTOR_SHIFT         9 | ||||
| #define HFSPLUS_VOLHEAD_SECTOR       2 | ||||
| #define HFSPLUS_VOLHEAD_SIG     0x482b | ||||
| #define HFSPLUS_VOLHEAD_SIGX    0x4858 | ||||
| #define HFSPLUS_SUPER_MAGIC     0x482b | ||||
| #define HFSPLUS_CURRENT_VERSION      4 | ||||
| #define HFSPLUS_MIN_VERSION          4 | ||||
| #define HFSPLUS_CURRENT_VERSION      5 | ||||
| 
 | ||||
| #define HFSP_WRAP_MAGIC         0x4244 | ||||
| #define HFSP_WRAP_ATTRIB_SLOCK  0x8000 | ||||
|  | @ -161,7 +163,7 @@ struct hfs_btree_header_rec { | |||
| 	u16 reserved1; | ||||
| 	__be32 clump_size; | ||||
| 	u8 btree_type; | ||||
| 	u8 reserved2; | ||||
| 	u8 key_type; | ||||
| 	__be32 attributes; | ||||
| 	u32 reserved3[16]; | ||||
| } __packed; | ||||
|  | @ -186,6 +188,10 @@ struct hfs_btree_header_rec { | |||
| #define HFSPLUS_EXCH_CNID		15	/* ExchangeFiles temp id */ | ||||
| #define HFSPLUS_FIRSTUSER_CNID		16	/* first available user id */ | ||||
| 
 | ||||
| /* btree key type */ | ||||
| #define HFSPLUS_KEY_CASEFOLDING		0xCF	/* case-insensitive */ | ||||
| #define HFSPLUS_KEY_BINARY		0xBC	/* case-sensitive */ | ||||
| 
 | ||||
| /* HFS+ catalog entry key */ | ||||
| struct hfsplus_cat_key { | ||||
| 	__be16 key_len; | ||||
|  |  | |||
|  | @ -316,8 +316,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 	vhdr = HFSPLUS_SB(sb).s_vhdr; | ||||
| 
 | ||||
| 	/* Copy parts of the volume header into the superblock */ | ||||
| 	sb->s_magic = be16_to_cpu(vhdr->signature); | ||||
| 	if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { | ||||
| 	sb->s_magic = HFSPLUS_VOLHEAD_SIG; | ||||
| 	if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || | ||||
| 	    be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { | ||||
| 		printk(KERN_ERR "hfs: wrong filesystem version\n"); | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  |  | |||
|  | @ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) | |||
| } | ||||
| 
 | ||||
| /* Compare unicode strings, return values like normal strcmp */ | ||||
| int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unistr *s2) | ||||
| int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, | ||||
| 		       const struct hfsplus_unistr *s2) | ||||
| { | ||||
| 	u16 len1, len2, c1, c2; | ||||
| 	const hfsplus_unichr *p1, *p2; | ||||
|  | @ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Compare names as a sequence of 16-bit unsigned integers */ | ||||
| int hfsplus_strcmp(const struct hfsplus_unistr *s1, | ||||
| 		   const struct hfsplus_unistr *s2) | ||||
| { | ||||
| 	u16 len1, len2, c1, c2; | ||||
| 	const hfsplus_unichr *p1, *p2; | ||||
| 	int len; | ||||
| 
 | ||||
| 	len1 = be16_to_cpu(s1->length); | ||||
| 	len2 = be16_to_cpu(s2->length); | ||||
| 	p1 = s1->unicode; | ||||
| 	p2 = s2->unicode; | ||||
| 
 | ||||
| 	for (len = min(len1, len2); len > 0; len--) { | ||||
| 		c1 = be16_to_cpu(*p1); | ||||
| 		c2 = be16_to_cpu(*p2); | ||||
| 		if (c1 != c2) | ||||
| 			return c1 < c2 ? -1 : 1; | ||||
| 		p1++; | ||||
| 		p2++; | ||||
| 	} | ||||
| 
 | ||||
| 	return len1 < len2 ? -1 : | ||||
| 	       len1 > len2 ? 1 : 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #define Hangul_SBase	0xac00 | ||||
| #define Hangul_LBase	0x1100 | ||||
| #define Hangul_VBase	0x1161 | ||||
|  |  | |||
|  | @ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | |||
| { | ||||
| 	u32 extent; | ||||
| 	u16 attrib; | ||||
| 	__be16 sig; | ||||
| 
 | ||||
| 	if (be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG) | ||||
| 	sig = *(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG); | ||||
| 	if (sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIG) && | ||||
| 	    sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); | ||||
|  | @ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
| 		} | ||||
| 		if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | ||||
| 			break; | ||||
| 		if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { | ||||
| 			HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; | ||||
| 			break; | ||||
| 		} | ||||
| 		brelse(bh); | ||||
| 
 | ||||
| 		/* check for a partition block
 | ||||
|  | @ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
| 		return -EIO; | ||||
| 
 | ||||
| 	/* should still be the same... */ | ||||
| 	if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG) | ||||
| 	if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? | ||||
| 				cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : | ||||
| 				cpu_to_be16(HFSPLUS_VOLHEAD_SIG))) | ||||
| 		goto error; | ||||
| 	HFSPLUS_SB(sb).s_vhbh = bh; | ||||
| 	HFSPLUS_SB(sb).s_vhdr = vhdr; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 David Elliott
						David Elliott