diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2005-09-06 18:18:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:50 -0400 |
commit | 328b9227865026268261a24a97a578907b280415 (patch) | |
tree | 1e0cad4f422252a9c3add879cf847afbb9786cfe | |
parent | 717dd80e999cdc84fb611decec5c5054d37c40d2 (diff) |
[PATCH] hfs: NLS support
This adds NLS support to HFS. Using the kernel options iocharset and codepage
it's possible to map the disk encoding to a local mapping. If these options
are not used, it falls back to the old direct mapping.
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>
-rw-r--r-- | fs/hfs/catalog.c | 35 | ||||
-rw-r--r-- | fs/hfs/dir.c | 11 | ||||
-rw-r--r-- | fs/hfs/hfs.h | 1 | ||||
-rw-r--r-- | fs/hfs/hfs_fs.h | 8 | ||||
-rw-r--r-- | fs/hfs/inode.c | 2 | ||||
-rw-r--r-- | fs/hfs/mdb.c | 6 | ||||
-rw-r--r-- | fs/hfs/super.c | 43 | ||||
-rw-r--r-- | fs/hfs/trans.c | 116 |
8 files changed, 176 insertions, 46 deletions
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 65dedefcabfc..2fcd679f0238 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c | |||
@@ -20,12 +20,12 @@ | |||
20 | * | 20 | * |
21 | * Given the ID of the parent and the name build a search key. | 21 | * Given the ID of the parent and the name build a search key. |
22 | */ | 22 | */ |
23 | void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name) | 23 | void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, struct qstr *name) |
24 | { | 24 | { |
25 | key->cat.reserved = 0; | 25 | key->cat.reserved = 0; |
26 | key->cat.ParID = cpu_to_be32(parent); | 26 | key->cat.ParID = cpu_to_be32(parent); |
27 | if (name) { | 27 | if (name) { |
28 | hfs_triv2mac(&key->cat.CName, name); | 28 | hfs_asc2mac(sb, &key->cat.CName, name); |
29 | key->key_len = 6 + key->cat.CName.len; | 29 | key->key_len = 6 + key->cat.CName.len; |
30 | } else { | 30 | } else { |
31 | memset(&key->cat.CName, 0, sizeof(struct hfs_name)); | 31 | memset(&key->cat.CName, 0, sizeof(struct hfs_name)); |
@@ -62,13 +62,14 @@ static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode) | |||
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | static int hfs_cat_build_thread(hfs_cat_rec *rec, int type, | 65 | static int hfs_cat_build_thread(struct super_block *sb, |
66 | hfs_cat_rec *rec, int type, | ||
66 | u32 parentid, struct qstr *name) | 67 | u32 parentid, struct qstr *name) |
67 | { | 68 | { |
68 | rec->type = type; | 69 | rec->type = type; |
69 | memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved)); | 70 | memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved)); |
70 | rec->thread.ParID = cpu_to_be32(parentid); | 71 | rec->thread.ParID = cpu_to_be32(parentid); |
71 | hfs_triv2mac(&rec->thread.CName, name); | 72 | hfs_asc2mac(sb, &rec->thread.CName, name); |
72 | return sizeof(struct hfs_cat_thread); | 73 | return sizeof(struct hfs_cat_thread); |
73 | } | 74 | } |
74 | 75 | ||
@@ -93,8 +94,8 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * | |||
93 | sb = dir->i_sb; | 94 | sb = dir->i_sb; |
94 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); | 95 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); |
95 | 96 | ||
96 | hfs_cat_build_key(fd.search_key, cnid, NULL); | 97 | hfs_cat_build_key(sb, fd.search_key, cnid, NULL); |
97 | entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ? | 98 | entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ? |
98 | HFS_CDR_THD : HFS_CDR_FTH, | 99 | HFS_CDR_THD : HFS_CDR_FTH, |
99 | dir->i_ino, str); | 100 | dir->i_ino, str); |
100 | err = hfs_brec_find(&fd); | 101 | err = hfs_brec_find(&fd); |
@@ -107,7 +108,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * | |||
107 | if (err) | 108 | if (err) |
108 | goto err2; | 109 | goto err2; |
109 | 110 | ||
110 | hfs_cat_build_key(fd.search_key, dir->i_ino, str); | 111 | hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
111 | entry_size = hfs_cat_build_record(&entry, cnid, inode); | 112 | entry_size = hfs_cat_build_record(&entry, cnid, inode); |
112 | err = hfs_brec_find(&fd); | 113 | err = hfs_brec_find(&fd); |
113 | if (err != -ENOENT) { | 114 | if (err != -ENOENT) { |
@@ -127,7 +128,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * | |||
127 | return 0; | 128 | return 0; |
128 | 129 | ||
129 | err1: | 130 | err1: |
130 | hfs_cat_build_key(fd.search_key, cnid, NULL); | 131 | hfs_cat_build_key(sb, fd.search_key, cnid, NULL); |
131 | if (!hfs_brec_find(&fd)) | 132 | if (!hfs_brec_find(&fd)) |
132 | hfs_brec_remove(&fd); | 133 | hfs_brec_remove(&fd); |
133 | err2: | 134 | err2: |
@@ -176,7 +177,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid, | |||
176 | hfs_cat_rec rec; | 177 | hfs_cat_rec rec; |
177 | int res, len, type; | 178 | int res, len, type; |
178 | 179 | ||
179 | hfs_cat_build_key(fd->search_key, cnid, NULL); | 180 | hfs_cat_build_key(sb, fd->search_key, cnid, NULL); |
180 | res = hfs_brec_read(fd, &rec, sizeof(rec)); | 181 | res = hfs_brec_read(fd, &rec, sizeof(rec)); |
181 | if (res) | 182 | if (res) |
182 | return res; | 183 | return res; |
@@ -211,7 +212,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) | |||
211 | sb = dir->i_sb; | 212 | sb = dir->i_sb; |
212 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); | 213 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); |
213 | 214 | ||
214 | hfs_cat_build_key(fd.search_key, dir->i_ino, str); | 215 | hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
215 | res = hfs_brec_find(&fd); | 216 | res = hfs_brec_find(&fd); |
216 | if (res) | 217 | if (res) |
217 | goto out; | 218 | goto out; |
@@ -239,7 +240,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) | |||
239 | if (res) | 240 | if (res) |
240 | goto out; | 241 | goto out; |
241 | 242 | ||
242 | hfs_cat_build_key(fd.search_key, cnid, NULL); | 243 | hfs_cat_build_key(sb, fd.search_key, cnid, NULL); |
243 | res = hfs_brec_find(&fd); | 244 | res = hfs_brec_find(&fd); |
244 | if (!res) { | 245 | if (!res) { |
245 | res = hfs_brec_remove(&fd); | 246 | res = hfs_brec_remove(&fd); |
@@ -280,7 +281,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, | |||
280 | dst_fd = src_fd; | 281 | dst_fd = src_fd; |
281 | 282 | ||
282 | /* find the old dir entry and read the data */ | 283 | /* find the old dir entry and read the data */ |
283 | hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name); | 284 | hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
284 | err = hfs_brec_find(&src_fd); | 285 | err = hfs_brec_find(&src_fd); |
285 | if (err) | 286 | if (err) |
286 | goto out; | 287 | goto out; |
@@ -289,7 +290,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, | |||
289 | src_fd.entrylength); | 290 | src_fd.entrylength); |
290 | 291 | ||
291 | /* create new dir entry with the data from the old entry */ | 292 | /* create new dir entry with the data from the old entry */ |
292 | hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name); | 293 | hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); |
293 | err = hfs_brec_find(&dst_fd); | 294 | err = hfs_brec_find(&dst_fd); |
294 | if (err != -ENOENT) { | 295 | if (err != -ENOENT) { |
295 | if (!err) | 296 | if (!err) |
@@ -305,7 +306,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, | |||
305 | mark_inode_dirty(dst_dir); | 306 | mark_inode_dirty(dst_dir); |
306 | 307 | ||
307 | /* finally remove the old entry */ | 308 | /* finally remove the old entry */ |
308 | hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name); | 309 | hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
309 | err = hfs_brec_find(&src_fd); | 310 | err = hfs_brec_find(&src_fd); |
310 | if (err) | 311 | if (err) |
311 | goto out; | 312 | goto out; |
@@ -321,7 +322,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, | |||
321 | goto out; | 322 | goto out; |
322 | 323 | ||
323 | /* remove old thread entry */ | 324 | /* remove old thread entry */ |
324 | hfs_cat_build_key(src_fd.search_key, cnid, NULL); | 325 | hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL); |
325 | err = hfs_brec_find(&src_fd); | 326 | err = hfs_brec_find(&src_fd); |
326 | if (err) | 327 | if (err) |
327 | goto out; | 328 | goto out; |
@@ -330,8 +331,8 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, | |||
330 | goto out; | 331 | goto out; |
331 | 332 | ||
332 | /* create new thread entry */ | 333 | /* create new thread entry */ |
333 | hfs_cat_build_key(dst_fd.search_key, cnid, NULL); | 334 | hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL); |
334 | entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD, | 335 | entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD, |
335 | dst_dir->i_ino, dst_name); | 336 | dst_dir->i_ino, dst_name); |
336 | err = hfs_brec_find(&dst_fd); | 337 | err = hfs_brec_find(&dst_fd); |
337 | if (err != -ENOENT) { | 338 | if (err != -ENOENT) { |
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index c55998262aed..e1f24befba58 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c | |||
@@ -28,7 +28,7 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, | |||
28 | dentry->d_op = &hfs_dentry_operations; | 28 | dentry->d_op = &hfs_dentry_operations; |
29 | 29 | ||
30 | hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); | 30 | hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); |
31 | hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name); | 31 | hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); |
32 | res = hfs_brec_read(&fd, &rec, sizeof(rec)); | 32 | res = hfs_brec_read(&fd, &rec, sizeof(rec)); |
33 | if (res) { | 33 | if (res) { |
34 | hfs_find_exit(&fd); | 34 | hfs_find_exit(&fd); |
@@ -56,7 +56,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
56 | struct inode *inode = filp->f_dentry->d_inode; | 56 | struct inode *inode = filp->f_dentry->d_inode; |
57 | struct super_block *sb = inode->i_sb; | 57 | struct super_block *sb = inode->i_sb; |
58 | int len, err; | 58 | int len, err; |
59 | char strbuf[HFS_NAMELEN + 1]; | 59 | char strbuf[HFS_MAX_NAMELEN]; |
60 | union hfs_cat_rec entry; | 60 | union hfs_cat_rec entry; |
61 | struct hfs_find_data fd; | 61 | struct hfs_find_data fd; |
62 | struct hfs_readdir_data *rd; | 62 | struct hfs_readdir_data *rd; |
@@ -66,7 +66,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
66 | return 0; | 66 | return 0; |
67 | 67 | ||
68 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); | 68 | hfs_find_init(HFS_SB(sb)->cat_tree, &fd); |
69 | hfs_cat_build_key(fd.search_key, inode->i_ino, NULL); | 69 | hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); |
70 | err = hfs_brec_find(&fd); | 70 | err = hfs_brec_find(&fd); |
71 | if (err) | 71 | if (err) |
72 | goto out; | 72 | goto out; |
@@ -111,7 +111,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
111 | } | 111 | } |
112 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 112 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); |
113 | type = entry.type; | 113 | type = entry.type; |
114 | len = hfs_mac2triv(strbuf, &fd.key->cat.CName); | 114 | len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); |
115 | if (type == HFS_CDR_DIR) { | 115 | if (type == HFS_CDR_DIR) { |
116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { | 116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { |
117 | printk("HFS: small dir entry\n"); | 117 | printk("HFS: small dir entry\n"); |
@@ -307,7 +307,8 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
307 | old_dir, &old_dentry->d_name, | 307 | old_dir, &old_dentry->d_name, |
308 | new_dir, &new_dentry->d_name); | 308 | new_dir, &new_dentry->d_name); |
309 | if (!res) | 309 | if (!res) |
310 | hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, | 310 | hfs_cat_build_key(old_dir->i_sb, |
311 | (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, | ||
311 | new_dir->i_ino, &new_dentry->d_name); | 312 | new_dir->i_ino, &new_dentry->d_name); |
312 | return res; | 313 | return res; |
313 | } | 314 | } |
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index df6b33adee3b..88099ab1a180 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #define HFS_SECTOR_SIZE 512 /* size of an HFS sector */ | 25 | #define HFS_SECTOR_SIZE 512 /* size of an HFS sector */ |
26 | #define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */ | 26 | #define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */ |
27 | #define HFS_NAMELEN 31 /* maximum length of an HFS filename */ | 27 | #define HFS_NAMELEN 31 /* maximum length of an HFS filename */ |
28 | #define HFS_MAX_NAMELEN 128 | ||
28 | #define HFS_MAX_VALENCE 32767U | 29 | #define HFS_MAX_VALENCE 32767U |
29 | 30 | ||
30 | /* Meanings of the drAtrb field of the MDB, | 31 | /* Meanings of the drAtrb field of the MDB, |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index 0dc8ef8e14de..aae019aadf88 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
@@ -141,6 +141,8 @@ struct hfs_sb_info { | |||
141 | 141 | ||
142 | int session, part; | 142 | int session, part; |
143 | 143 | ||
144 | struct nls_table *nls_io, *nls_disk; | ||
145 | |||
144 | struct semaphore bitmap_lock; | 146 | struct semaphore bitmap_lock; |
145 | 147 | ||
146 | unsigned long flags; | 148 | unsigned long flags; |
@@ -168,7 +170,7 @@ extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *); | |||
168 | extern int hfs_cat_delete(u32, struct inode *, struct qstr *); | 170 | extern int hfs_cat_delete(u32, struct inode *, struct qstr *); |
169 | extern int hfs_cat_move(u32, struct inode *, struct qstr *, | 171 | extern int hfs_cat_move(u32, struct inode *, struct qstr *, |
170 | struct inode *, struct qstr *); | 172 | struct inode *, struct qstr *); |
171 | extern void hfs_cat_build_key(btree_key *, u32, struct qstr *); | 173 | extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *); |
172 | 174 | ||
173 | /* dir.c */ | 175 | /* dir.c */ |
174 | extern struct file_operations hfs_dir_operations; | 176 | extern struct file_operations hfs_dir_operations; |
@@ -222,8 +224,8 @@ extern int hfs_strcmp(const unsigned char *, unsigned int, | |||
222 | extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | 224 | extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); |
223 | 225 | ||
224 | /* trans.c */ | 226 | /* trans.c */ |
225 | extern void hfs_triv2mac(struct hfs_name *, struct qstr *); | 227 | extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *); |
226 | extern int hfs_mac2triv(char *, const struct hfs_name *); | 228 | extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *); |
227 | 229 | ||
228 | extern struct timezone sys_tz; | 230 | extern struct timezone sys_tz; |
229 | 231 | ||
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 751912326094..f1570b9f9de3 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
@@ -160,7 +160,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode) | |||
160 | 160 | ||
161 | init_MUTEX(&HFS_I(inode)->extents_lock); | 161 | init_MUTEX(&HFS_I(inode)->extents_lock); |
162 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); | 162 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); |
163 | hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); | 163 | hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); |
164 | inode->i_ino = HFS_SB(sb)->next_id++; | 164 | inode->i_ino = HFS_SB(sb)->next_id++; |
165 | inode->i_mode = mode; | 165 | inode->i_mode = mode; |
166 | inode->i_uid = current->fsuid; | 166 | inode->i_uid = current->fsuid; |
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 217e32f37e0b..0a473f79c89f 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/cdrom.h> | 11 | #include <linux/cdrom.h> |
12 | #include <linux/genhd.h> | 12 | #include <linux/genhd.h> |
13 | #include <linux/nls.h> | ||
13 | 14 | ||
14 | #include "hfs_fs.h" | 15 | #include "hfs_fs.h" |
15 | #include "btree.h" | 16 | #include "btree.h" |
@@ -343,6 +344,11 @@ void hfs_mdb_put(struct super_block *sb) | |||
343 | brelse(HFS_SB(sb)->mdb_bh); | 344 | brelse(HFS_SB(sb)->mdb_bh); |
344 | brelse(HFS_SB(sb)->alt_mdb_bh); | 345 | brelse(HFS_SB(sb)->alt_mdb_bh); |
345 | 346 | ||
347 | if (HFS_SB(sb)->nls_io) | ||
348 | unload_nls(HFS_SB(sb)->nls_io); | ||
349 | if (HFS_SB(sb)->nls_disk) | ||
350 | unload_nls(HFS_SB(sb)->nls_disk); | ||
351 | |||
346 | kfree(HFS_SB(sb)); | 352 | kfree(HFS_SB(sb)); |
347 | sb->s_fs_info = NULL; | 353 | sb->s_fs_info = NULL; |
348 | } | 354 | } |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index fd78414ee7e4..c5074aeafcae 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/blkdev.h> | 17 | #include <linux/blkdev.h> |
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/nls.h> | ||
20 | #include <linux/parser.h> | 21 | #include <linux/parser.h> |
21 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
22 | #include <linux/vfs.h> | 23 | #include <linux/vfs.h> |
@@ -130,6 +131,10 @@ static int hfs_show_options(struct seq_file *seq, struct vfsmount *mnt) | |||
130 | seq_printf(seq, ",part=%u", sbi->part); | 131 | seq_printf(seq, ",part=%u", sbi->part); |
131 | if (sbi->session >= 0) | 132 | if (sbi->session >= 0) |
132 | seq_printf(seq, ",session=%u", sbi->session); | 133 | seq_printf(seq, ",session=%u", sbi->session); |
134 | if (sbi->nls_disk) | ||
135 | seq_printf(seq, ",codepage=%s", sbi->nls_disk->charset); | ||
136 | if (sbi->nls_io) | ||
137 | seq_printf(seq, ",iocharset=%s", sbi->nls_io->charset); | ||
133 | if (sbi->s_quiet) | 138 | if (sbi->s_quiet) |
134 | seq_printf(seq, ",quiet"); | 139 | seq_printf(seq, ",quiet"); |
135 | return 0; | 140 | return 0; |
@@ -163,6 +168,7 @@ static struct super_operations hfs_super_operations = { | |||
163 | enum { | 168 | enum { |
164 | opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask, | 169 | opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask, |
165 | opt_part, opt_session, opt_type, opt_creator, opt_quiet, | 170 | opt_part, opt_session, opt_type, opt_creator, opt_quiet, |
171 | opt_codepage, opt_iocharset, | ||
166 | opt_err | 172 | opt_err |
167 | }; | 173 | }; |
168 | 174 | ||
@@ -177,6 +183,8 @@ static match_table_t tokens = { | |||
177 | { opt_type, "type=%s" }, | 183 | { opt_type, "type=%s" }, |
178 | { opt_creator, "creator=%s" }, | 184 | { opt_creator, "creator=%s" }, |
179 | { opt_quiet, "quiet" }, | 185 | { opt_quiet, "quiet" }, |
186 | { opt_codepage, "codepage=%s" }, | ||
187 | { opt_iocharset, "iocharset=%s" }, | ||
180 | { opt_err, NULL } | 188 | { opt_err, NULL } |
181 | }; | 189 | }; |
182 | 190 | ||
@@ -282,11 +290,46 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
282 | case opt_quiet: | 290 | case opt_quiet: |
283 | hsb->s_quiet = 1; | 291 | hsb->s_quiet = 1; |
284 | break; | 292 | break; |
293 | case opt_codepage: | ||
294 | if (hsb->nls_disk) { | ||
295 | printk("HFS+-fs: unable to change codepage\n"); | ||
296 | return 0; | ||
297 | } | ||
298 | p = match_strdup(&args[0]); | ||
299 | hsb->nls_disk = load_nls(p); | ||
300 | if (!hsb->nls_disk) { | ||
301 | printk("HFS+-fs: unable to load codepage \"%s\"\n", p); | ||
302 | kfree(p); | ||
303 | return 0; | ||
304 | } | ||
305 | kfree(p); | ||
306 | break; | ||
307 | case opt_iocharset: | ||
308 | if (hsb->nls_io) { | ||
309 | printk("HFS: unable to change iocharset\n"); | ||
310 | return 0; | ||
311 | } | ||
312 | p = match_strdup(&args[0]); | ||
313 | hsb->nls_io = load_nls(p); | ||
314 | if (!hsb->nls_io) { | ||
315 | printk("HFS: unable to load iocharset \"%s\"\n", p); | ||
316 | kfree(p); | ||
317 | return 0; | ||
318 | } | ||
319 | kfree(p); | ||
320 | break; | ||
285 | default: | 321 | default: |
286 | return 0; | 322 | return 0; |
287 | } | 323 | } |
288 | } | 324 | } |
289 | 325 | ||
326 | if (hsb->nls_disk && !hsb->nls_io) { | ||
327 | hsb->nls_io = load_nls_default(); | ||
328 | if (!hsb->nls_io) { | ||
329 | printk("HFS: unable to load default iocharset\n"); | ||
330 | return 0; | ||
331 | } | ||
332 | } | ||
290 | hsb->s_dir_umask &= 0777; | 333 | hsb->s_dir_umask &= 0777; |
291 | hsb->s_file_umask &= 0577; | 334 | hsb->s_file_umask &= 0577; |
292 | 335 | ||
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c index fb9720abbadd..e673a88b8ae7 100644 --- a/fs/hfs/trans.c +++ b/fs/hfs/trans.c | |||
@@ -9,12 +9,15 @@ | |||
9 | * with ':' vs. '/' as the path-element separator. | 9 | * with ':' vs. '/' as the path-element separator. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/nls.h> | ||
14 | |||
12 | #include "hfs_fs.h" | 15 | #include "hfs_fs.h" |
13 | 16 | ||
14 | /*================ Global functions ================*/ | 17 | /*================ Global functions ================*/ |
15 | 18 | ||
16 | /* | 19 | /* |
17 | * hfs_mac2triv() | 20 | * hfs_mac2asc() |
18 | * | 21 | * |
19 | * Given a 'Pascal String' (a string preceded by a length byte) in | 22 | * Given a 'Pascal String' (a string preceded by a length byte) in |
20 | * the Macintosh character set produce the corresponding filename using | 23 | * the Macintosh character set produce the corresponding filename using |
@@ -27,23 +30,58 @@ | |||
27 | * by ':' which never appears in HFS filenames. All other characters | 30 | * by ':' which never appears in HFS filenames. All other characters |
28 | * are passed unchanged from input to output. | 31 | * are passed unchanged from input to output. |
29 | */ | 32 | */ |
30 | int hfs_mac2triv(char *out, const struct hfs_name *in) | 33 | int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in) |
31 | { | 34 | { |
32 | const char *p; | 35 | struct nls_table *nls_disk = HFS_SB(sb)->nls_disk; |
33 | char c; | 36 | struct nls_table *nls_io = HFS_SB(sb)->nls_io; |
34 | int i, len; | 37 | const char *src; |
38 | char *dst; | ||
39 | int srclen, dstlen, size; | ||
40 | |||
41 | src = in->name; | ||
42 | srclen = in->len; | ||
43 | dst = out; | ||
44 | dstlen = HFS_MAX_NAMELEN; | ||
45 | if (nls_io) { | ||
46 | wchar_t ch; | ||
35 | 47 | ||
36 | len = in->len; | 48 | while (srclen > 0) { |
37 | p = in->name; | 49 | if (nls_disk) { |
38 | for (i = 0; i < len; i++) { | 50 | size = nls_disk->char2uni(src, srclen, &ch); |
39 | c = *p++; | 51 | if (size <= 0) { |
40 | *out++ = c == '/' ? ':' : c; | 52 | ch = '?'; |
53 | size = 1; | ||
54 | } | ||
55 | src += size; | ||
56 | srclen -= size; | ||
57 | } else { | ||
58 | ch = *src++; | ||
59 | srclen--; | ||
60 | } | ||
61 | if (ch == '/') | ||
62 | ch = ':'; | ||
63 | size = nls_io->uni2char(ch, dst, dstlen); | ||
64 | if (size < 0) { | ||
65 | if (size == -ENAMETOOLONG) | ||
66 | goto out; | ||
67 | *dst = '?'; | ||
68 | size = 1; | ||
69 | } | ||
70 | dst += size; | ||
71 | dstlen -= size; | ||
72 | } | ||
73 | } else { | ||
74 | char ch; | ||
75 | |||
76 | while (--srclen >= 0) | ||
77 | *dst++ = (ch = *src++) == '/' ? ':' : ch; | ||
41 | } | 78 | } |
42 | return i; | 79 | out: |
80 | return dst - out; | ||
43 | } | 81 | } |
44 | 82 | ||
45 | /* | 83 | /* |
46 | * hfs_triv2mac() | 84 | * hfs_asc2mac() |
47 | * | 85 | * |
48 | * Given an ASCII string (not null-terminated) and its length, | 86 | * Given an ASCII string (not null-terminated) and its length, |
49 | * generate the corresponding filename in the Macintosh character set | 87 | * generate the corresponding filename in the Macintosh character set |
@@ -54,19 +92,57 @@ int hfs_mac2triv(char *out, const struct hfs_name *in) | |||
54 | * This routine is a inverse to hfs_mac2triv(). | 92 | * This routine is a inverse to hfs_mac2triv(). |
55 | * A ':' is replaced by a '/'. | 93 | * A ':' is replaced by a '/'. |
56 | */ | 94 | */ |
57 | void hfs_triv2mac(struct hfs_name *out, struct qstr *in) | 95 | void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, struct qstr *in) |
58 | { | 96 | { |
97 | struct nls_table *nls_disk = HFS_SB(sb)->nls_disk; | ||
98 | struct nls_table *nls_io = HFS_SB(sb)->nls_io; | ||
59 | const char *src; | 99 | const char *src; |
60 | char *dst, c; | 100 | char *dst; |
61 | int i, len; | 101 | int srclen, dstlen, size; |
62 | 102 | ||
63 | out->len = len = min((unsigned int)HFS_NAMELEN, in->len); | ||
64 | src = in->name; | 103 | src = in->name; |
104 | srclen = in->len; | ||
65 | dst = out->name; | 105 | dst = out->name; |
66 | for (i = 0; i < len; i++) { | 106 | dstlen = HFS_NAMELEN; |
67 | c = *src++; | 107 | if (nls_io) { |
68 | *dst++ = c == ':' ? '/' : c; | 108 | wchar_t ch; |
109 | |||
110 | while (srclen > 0) { | ||
111 | size = nls_io->char2uni(src, srclen, &ch); | ||
112 | if (size < 0) { | ||
113 | ch = '?'; | ||
114 | size = 1; | ||
115 | } | ||
116 | src += size; | ||
117 | srclen -= size; | ||
118 | if (ch == ':') | ||
119 | ch = '/'; | ||
120 | if (nls_disk) { | ||
121 | size = nls_disk->uni2char(ch, dst, dstlen); | ||
122 | if (size < 0) { | ||
123 | if (size == -ENAMETOOLONG) | ||
124 | goto out; | ||
125 | *dst = '?'; | ||
126 | size = 1; | ||
127 | } | ||
128 | dst += size; | ||
129 | dstlen -= size; | ||
130 | } else { | ||
131 | *dst++ = ch > 0xff ? '?' : ch; | ||
132 | dstlen--; | ||
133 | } | ||
134 | } | ||
135 | } else { | ||
136 | char ch; | ||
137 | |||
138 | if (dstlen > srclen) | ||
139 | dstlen = srclen; | ||
140 | while (--dstlen >= 0) | ||
141 | *dst++ = (ch = *src++) == ':' ? '/' : ch; | ||
69 | } | 142 | } |
70 | for (; i < HFS_NAMELEN; i++) | 143 | out: |
144 | out->len = dst - (char *)out->name; | ||
145 | dstlen = HFS_NAMELEN - out->len; | ||
146 | while (--dstlen >= 0) | ||
71 | *dst++ = 0; | 147 | *dst++ = 0; |
72 | } | 148 | } |