Skip to content

Commit

Permalink
[PATCH] hfs: NLS support
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Roman Zippel authored and Linus Torvalds committed Sep 7, 2005
1 parent 717dd80 commit 328b922
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 46 deletions.
35 changes: 18 additions & 17 deletions fs/hfs/catalog.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
*
* Given the ID of the parent and the name build a search key.
*/
void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name)
void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, struct qstr *name)
{
key->cat.reserved = 0;
key->cat.ParID = cpu_to_be32(parent);
if (name) {
hfs_triv2mac(&key->cat.CName, name);
hfs_asc2mac(sb, &key->cat.CName, name);
key->key_len = 6 + key->cat.CName.len;
} else {
memset(&key->cat.CName, 0, sizeof(struct hfs_name));
Expand Down Expand Up @@ -62,13 +62,14 @@ static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
}
}

static int hfs_cat_build_thread(hfs_cat_rec *rec, int type,
static int hfs_cat_build_thread(struct super_block *sb,
hfs_cat_rec *rec, int type,
u32 parentid, struct qstr *name)
{
rec->type = type;
memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
rec->thread.ParID = cpu_to_be32(parentid);
hfs_triv2mac(&rec->thread.CName, name);
hfs_asc2mac(sb, &rec->thread.CName, name);
return sizeof(struct hfs_cat_thread);
}

Expand All @@ -93,8 +94,8 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
sb = dir->i_sb;
hfs_find_init(HFS_SB(sb)->cat_tree, &fd);

hfs_cat_build_key(fd.search_key, cnid, NULL);
entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ?
hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
HFS_CDR_THD : HFS_CDR_FTH,
dir->i_ino, str);
err = hfs_brec_find(&fd);
Expand All @@ -107,7 +108,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
if (err)
goto err2;

hfs_cat_build_key(fd.search_key, dir->i_ino, str);
hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
entry_size = hfs_cat_build_record(&entry, cnid, inode);
err = hfs_brec_find(&fd);
if (err != -ENOENT) {
Expand All @@ -127,7 +128,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
return 0;

err1:
hfs_cat_build_key(fd.search_key, cnid, NULL);
hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
if (!hfs_brec_find(&fd))
hfs_brec_remove(&fd);
err2:
Expand Down Expand Up @@ -176,7 +177,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
hfs_cat_rec rec;
int res, len, type;

hfs_cat_build_key(fd->search_key, cnid, NULL);
hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
res = hfs_brec_read(fd, &rec, sizeof(rec));
if (res)
return res;
Expand Down Expand Up @@ -211,7 +212,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
sb = dir->i_sb;
hfs_find_init(HFS_SB(sb)->cat_tree, &fd);

hfs_cat_build_key(fd.search_key, dir->i_ino, str);
hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
res = hfs_brec_find(&fd);
if (res)
goto out;
Expand Down Expand Up @@ -239,7 +240,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
if (res)
goto out;

hfs_cat_build_key(fd.search_key, cnid, NULL);
hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
res = hfs_brec_find(&fd);
if (!res) {
res = hfs_brec_remove(&fd);
Expand Down Expand Up @@ -280,7 +281,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
dst_fd = src_fd;

/* find the old dir entry and read the data */
hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
Expand All @@ -289,7 +290,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
src_fd.entrylength);

/* create new dir entry with the data from the old entry */
hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
if (!err)
Expand All @@ -305,7 +306,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
mark_inode_dirty(dst_dir);

/* finally remove the old entry */
hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
Expand All @@ -321,7 +322,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
goto out;

/* remove old thread entry */
hfs_cat_build_key(src_fd.search_key, cnid, NULL);
hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL);
err = hfs_brec_find(&src_fd);
if (err)
goto out;
Expand All @@ -330,8 +331,8 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
goto out;

/* create new thread entry */
hfs_cat_build_key(dst_fd.search_key, cnid, NULL);
entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
dst_dir->i_ino, dst_name);
err = hfs_brec_find(&dst_fd);
if (err != -ENOENT) {
Expand Down
11 changes: 6 additions & 5 deletions fs/hfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_op = &hfs_dentry_operations;

hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
res = hfs_brec_read(&fd, &rec, sizeof(rec));
if (res) {
hfs_find_exit(&fd);
Expand Down Expand Up @@ -56,7 +56,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *inode = filp->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFS_NAMELEN + 1];
char strbuf[HFS_MAX_NAMELEN];
union hfs_cat_rec entry;
struct hfs_find_data fd;
struct hfs_readdir_data *rd;
Expand All @@ -66,7 +66,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
return 0;

hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
hfs_cat_build_key(fd.search_key, inode->i_ino, NULL);
hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
err = hfs_brec_find(&fd);
if (err)
goto out;
Expand Down Expand Up @@ -111,7 +111,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
type = entry.type;
len = hfs_mac2triv(strbuf, &fd.key->cat.CName);
len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
if (type == HFS_CDR_DIR) {
if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
printk("HFS: small dir entry\n");
Expand Down Expand Up @@ -307,7 +307,8 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
old_dir, &old_dentry->d_name,
new_dir, &new_dentry->d_name);
if (!res)
hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
hfs_cat_build_key(old_dir->i_sb,
(btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
new_dir->i_ino, &new_dentry->d_name);
return res;
}
Expand Down
1 change: 1 addition & 0 deletions fs/hfs/hfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define HFS_SECTOR_SIZE 512 /* size of an HFS sector */
#define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */
#define HFS_NAMELEN 31 /* maximum length of an HFS filename */
#define HFS_MAX_NAMELEN 128
#define HFS_MAX_VALENCE 32767U

/* Meanings of the drAtrb field of the MDB,
Expand Down
8 changes: 5 additions & 3 deletions fs/hfs/hfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ struct hfs_sb_info {

int session, part;

struct nls_table *nls_io, *nls_disk;

struct semaphore bitmap_lock;

unsigned long flags;
Expand Down Expand Up @@ -168,7 +170,7 @@ extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *);
extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
extern int hfs_cat_move(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *);
extern void hfs_cat_build_key(btree_key *, u32, struct qstr *);
extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);

/* dir.c */
extern struct file_operations hfs_dir_operations;
Expand Down Expand Up @@ -222,8 +224,8 @@ extern int hfs_strcmp(const unsigned char *, unsigned int,
extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);

/* trans.c */
extern void hfs_triv2mac(struct hfs_name *, struct qstr *);
extern int hfs_mac2triv(char *, const struct hfs_name *);
extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);

extern struct timezone sys_tz;

Expand Down
2 changes: 1 addition & 1 deletion fs/hfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)

init_MUTEX(&HFS_I(inode)->extents_lock);
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
inode->i_ino = HFS_SB(sb)->next_id++;
inode->i_mode = mode;
inode->i_uid = current->fsuid;
Expand Down
6 changes: 6 additions & 0 deletions fs/hfs/mdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/cdrom.h>
#include <linux/genhd.h>
#include <linux/nls.h>

#include "hfs_fs.h"
#include "btree.h"
Expand Down Expand Up @@ -343,6 +344,11 @@ void hfs_mdb_put(struct super_block *sb)
brelse(HFS_SB(sb)->mdb_bh);
brelse(HFS_SB(sb)->alt_mdb_bh);

if (HFS_SB(sb)->nls_io)
unload_nls(HFS_SB(sb)->nls_io);
if (HFS_SB(sb)->nls_disk)
unload_nls(HFS_SB(sb)->nls_disk);

kfree(HFS_SB(sb));
sb->s_fs_info = NULL;
}
43 changes: 43 additions & 0 deletions fs/hfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/blkdev.h>
#include <linux/mount.h>
#include <linux/init.h>
#include <linux/nls.h>
#include <linux/parser.h>
#include <linux/seq_file.h>
#include <linux/vfs.h>
Expand Down Expand Up @@ -130,6 +131,10 @@ static int hfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
seq_printf(seq, ",part=%u", sbi->part);
if (sbi->session >= 0)
seq_printf(seq, ",session=%u", sbi->session);
if (sbi->nls_disk)
seq_printf(seq, ",codepage=%s", sbi->nls_disk->charset);
if (sbi->nls_io)
seq_printf(seq, ",iocharset=%s", sbi->nls_io->charset);
if (sbi->s_quiet)
seq_printf(seq, ",quiet");
return 0;
Expand Down Expand Up @@ -163,6 +168,7 @@ static struct super_operations hfs_super_operations = {
enum {
opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
opt_part, opt_session, opt_type, opt_creator, opt_quiet,
opt_codepage, opt_iocharset,
opt_err
};

Expand All @@ -177,6 +183,8 @@ static match_table_t tokens = {
{ opt_type, "type=%s" },
{ opt_creator, "creator=%s" },
{ opt_quiet, "quiet" },
{ opt_codepage, "codepage=%s" },
{ opt_iocharset, "iocharset=%s" },
{ opt_err, NULL }
};

Expand Down Expand Up @@ -282,11 +290,46 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
case opt_quiet:
hsb->s_quiet = 1;
break;
case opt_codepage:
if (hsb->nls_disk) {
printk("HFS+-fs: unable to change codepage\n");
return 0;
}
p = match_strdup(&args[0]);
hsb->nls_disk = load_nls(p);
if (!hsb->nls_disk) {
printk("HFS+-fs: unable to load codepage \"%s\"\n", p);
kfree(p);
return 0;
}
kfree(p);
break;
case opt_iocharset:
if (hsb->nls_io) {
printk("HFS: unable to change iocharset\n");
return 0;
}
p = match_strdup(&args[0]);
hsb->nls_io = load_nls(p);
if (!hsb->nls_io) {
printk("HFS: unable to load iocharset \"%s\"\n", p);
kfree(p);
return 0;
}
kfree(p);
break;
default:
return 0;
}
}

if (hsb->nls_disk && !hsb->nls_io) {
hsb->nls_io = load_nls_default();
if (!hsb->nls_io) {
printk("HFS: unable to load default iocharset\n");
return 0;
}
}
hsb->s_dir_umask &= 0777;
hsb->s_file_umask &= 0577;

Expand Down
Loading

0 comments on commit 328b922

Please sign in to comment.