aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2005-09-06 18:18:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:50 -0400
commit328b9227865026268261a24a97a578907b280415 (patch)
tree1e0cad4f422252a9c3add879cf847afbb9786cfe
parent717dd80e999cdc84fb611decec5c5054d37c40d2 (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.c35
-rw-r--r--fs/hfs/dir.c11
-rw-r--r--fs/hfs/hfs.h1
-rw-r--r--fs/hfs/hfs_fs.h8
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hfs/mdb.c6
-rw-r--r--fs/hfs/super.c43
-rw-r--r--fs/hfs/trans.c116
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 */
23void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name) 23void 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
65static int hfs_cat_build_thread(hfs_cat_rec *rec, int type, 65static 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
129err1: 130err1:
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);
133err2: 134err2:
@@ -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 *);
168extern int hfs_cat_delete(u32, struct inode *, struct qstr *); 170extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
169extern int hfs_cat_move(u32, struct inode *, struct qstr *, 171extern int hfs_cat_move(u32, struct inode *, struct qstr *,
170 struct inode *, struct qstr *); 172 struct inode *, struct qstr *);
171extern void hfs_cat_build_key(btree_key *, u32, struct qstr *); 173extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
172 174
173/* dir.c */ 175/* dir.c */
174extern struct file_operations hfs_dir_operations; 176extern struct file_operations hfs_dir_operations;
@@ -222,8 +224,8 @@ extern int hfs_strcmp(const unsigned char *, unsigned int,
222extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); 224extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
223 225
224/* trans.c */ 226/* trans.c */
225extern void hfs_triv2mac(struct hfs_name *, struct qstr *); 227extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
226extern int hfs_mac2triv(char *, const struct hfs_name *); 228extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
227 229
228extern struct timezone sys_tz; 230extern 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 = {
163enum { 168enum {
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 */
30int hfs_mac2triv(char *out, const struct hfs_name *in) 33int 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; 79out:
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 */
57void hfs_triv2mac(struct hfs_name *out, struct qstr *in) 95void 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++) 143out:
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}