Commit ae0caa23 authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Linus Torvalds

[PATCH] fat: Lindent fs/msdos/namei.c

Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 37e06593
...@@ -12,25 +12,28 @@ ...@@ -12,25 +12,28 @@
#include <linux/msdos_fs.h> #include <linux/msdos_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
/* MS-DOS "device special files" */ /* MS-DOS "device special files" */
static const unsigned char *reserved_names[] = { static const unsigned char *reserved_names[] = {
"CON ","PRN ","NUL ","AUX ", "CON ", "PRN ", "NUL ", "AUX ",
"LPT1 ","LPT2 ","LPT3 ","LPT4 ", "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ",
"COM1 ","COM2 ","COM3 ","COM4 ", "COM1 ", "COM2 ", "COM3 ", "COM4 ",
NULL NULL
}; };
/* Characters that are undesirable in an MS-DOS file name */ /* Characters that are undesirable in an MS-DOS file name */
static unsigned char bad_chars[] = "*?<>|\""; static unsigned char bad_chars[] = "*?<>|\"";
static unsigned char bad_if_strict_pc[] = "+=,; "; static unsigned char bad_if_strict_pc[] = "+=,; ";
static unsigned char bad_if_strict_atari[] = " "; /* GEMDOS is less restrictive */ /* GEMDOS is less restrictive */
#define bad_if_strict(opts) ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc) static unsigned char bad_if_strict_atari[] = " ";
#define bad_if_strict(opts) \
((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
/***** Formats an MS-DOS file name. Rejects invalid names. */ /***** Formats an MS-DOS file name. Rejects invalid names. */
static int msdos_format_name(const unsigned char *name, int len, static int msdos_format_name(const unsigned char *name, int len,
unsigned char *res, struct fat_mount_options *opts) unsigned char *res, struct fat_mount_options *opts)
/* name is the proposed name, len is its length, res is /*
* name is the proposed name, len is its length, res is
* the resulting name, opts->name_check is either (r)elaxed, * the resulting name, opts->name_check is either (r)elaxed,
* (n)ormal or (s)trict, opts->dotsOK allows dots at the * (n)ormal or (s)trict, opts->dotsOK allows dots at the
* beginning of name (for hidden files) * beginning of name (for hidden files)
...@@ -41,52 +44,66 @@ static int msdos_format_name(const unsigned char *name, int len, ...@@ -41,52 +44,66 @@ static int msdos_format_name(const unsigned char *name, int len,
unsigned char c; unsigned char c;
int space; int space;
if (name[0] == '.') { /* dotfile because . and .. already done */ if (name[0] == '.') { /* dotfile because . and .. already done */
if (opts->dotsOK) { if (opts->dotsOK) {
/* Get rid of dot - test for it elsewhere */ /* Get rid of dot - test for it elsewhere */
name++; len--; name++;
} len--;
else if (!opts->atari) return -EINVAL; } else if (!opts->atari)
return -EINVAL;
} }
/* disallow names that _really_ start with a dot for MS-DOS, GEMDOS does /*
* not care */ * disallow names that _really_ start with a dot for MS-DOS,
* GEMDOS does not care
*/
space = !opts->atari; space = !opts->atari;
c = 0; c = 0;
for (walk = res; len && walk-res < 8; walk++) { for (walk = res; len && walk - res < 8; walk++) {
c = *name++; c = *name++;
len--; len--;
if (opts->name_check != 'r' && strchr(bad_chars,c)) if (opts->name_check != 'r' && strchr(bad_chars, c))
return -EINVAL; return -EINVAL;
if (opts->name_check == 's' && strchr(bad_if_strict(opts),c)) if (opts->name_check == 's' && strchr(bad_if_strict(opts), c))
return -EINVAL; return -EINVAL;
if (c >= 'A' && c <= 'Z' && opts->name_check == 's') if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
return -EINVAL; return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL; if (c < ' ' || c == ':' || c == '\\')
/* 0xE5 is legal as a first character, but we must substitute 0x05 */ return -EINVAL;
/* because 0xE5 marks deleted files. Yes, DOS really does this. */ /*
/* It seems that Microsoft hacked DOS to support non-US characters */ * 0xE5 is legal as a first character, but we must substitute
/* after the 0xE5 character was already in use to mark deleted files. */ * 0x05 because 0xE5 marks deleted files. Yes, DOS really
if((res==walk) && (c==0xE5)) c=0x05; * does this.
if (c == '.') break; * It seems that Microsoft hacked DOS to support non-US
* characters after the 0xE5 character was already in use to
* mark deleted files.
*/
if ((res == walk) && (c == 0xE5))
c = 0x05;
if (c == '.')
break;
space = (c == ' '); space = (c == ' ');
*walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c; *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
} }
if (space) return -EINVAL; if (space)
return -EINVAL;
if (opts->name_check == 's' && len && c != '.') { if (opts->name_check == 's' && len && c != '.') {
c = *name++; c = *name++;
len--; len--;
if (c != '.') return -EINVAL; if (c != '.')
return -EINVAL;
} }
while (c != '.' && len--) c = *name++; while (c != '.' && len--)
c = *name++;
if (c == '.') { if (c == '.') {
while (walk-res < 8) *walk++ = ' '; while (walk - res < 8)
while (len > 0 && walk-res < MSDOS_NAME) { *walk++ = ' ';
while (len > 0 && walk - res < MSDOS_NAME) {
c = *name++; c = *name++;
len--; len--;
if (opts->name_check != 'r' && strchr(bad_chars,c)) if (opts->name_check != 'r' && strchr(bad_chars, c))
return -EINVAL; return -EINVAL;
if (opts->name_check == 's' && if (opts->name_check == 's' &&
strchr(bad_if_strict(opts),c)) strchr(bad_if_strict(opts), c))
return -EINVAL; return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') if (c < ' ' || c == ':' || c == '\\')
return -EINVAL; return -EINVAL;
...@@ -98,16 +115,23 @@ static int msdos_format_name(const unsigned char *name, int len, ...@@ -98,16 +115,23 @@ static int msdos_format_name(const unsigned char *name, int len,
if (c >= 'A' && c <= 'Z' && opts->name_check == 's') if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
return -EINVAL; return -EINVAL;
space = c == ' '; space = c == ' ';
*walk++ = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c; if (!opts->nocase && c >= 'a' && c <= 'z')
*walk++ = c - 32;
else
*walk++ = c;
} }
if (space) return -EINVAL; if (space)
if (opts->name_check == 's' && len) return -EINVAL; return -EINVAL;
if (opts->name_check == 's' && len)
return -EINVAL;
} }
while (walk-res < MSDOS_NAME) *walk++ = ' '; while (walk - res < MSDOS_NAME)
*walk++ = ' ';
if (!opts->atari) if (!opts->atari)
/* GEMDOS is less stupid and has no reserved names */ /* GEMDOS is less stupid and has no reserved names */
for (reserved = reserved_names; *reserved; reserved++) for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(res,*reserved,8)) return -EINVAL; if (!strncmp(res, *reserved, 8))
return -EINVAL;
return 0; return 0;
} }
...@@ -121,12 +145,13 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len, ...@@ -121,12 +145,13 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
int res; int res;
dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK; dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options); res = msdos_format_name(name, len, msdos_name,
&MSDOS_SB(dir->i_sb)->options);
if (res < 0) if (res < 0)
return -ENOENT; return -ENOENT;
res = fat_scan(dir, msdos_name, bh, de, i_pos); res = fat_scan(dir, msdos_name, bh, de, i_pos);
if (!res && dotsOK) { if (!res && dotsOK) {
if (name[0]=='.') { if (name[0] == '.') {
if (!((*de)->attr & ATTR_HIDDEN)) if (!((*de)->attr & ATTR_HIDDEN))
res = -ENOENT; res = -ENOENT;
} else { } else {
...@@ -145,10 +170,10 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len, ...@@ -145,10 +170,10 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
*/ */
static int msdos_hash(struct dentry *dentry, struct qstr *qstr) static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
{ {
struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options); struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
unsigned char msdos_name[MSDOS_NAME]; unsigned char msdos_name[MSDOS_NAME];
int error; int error;
error = msdos_format_name(qstr->name, qstr->len, msdos_name, options); error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
if (!error) if (!error)
qstr->hash = full_name_hash(msdos_name, MSDOS_NAME); qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
...@@ -161,7 +186,7 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr) ...@@ -161,7 +186,7 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
*/ */
static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
{ {
struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options); struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
int error; int error;
...@@ -182,7 +207,6 @@ static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) ...@@ -182,7 +207,6 @@ static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
goto out; goto out;
} }
static struct dentry_operations msdos_dentry_operations = { static struct dentry_operations msdos_dentry_operations = {
.d_hash = msdos_hash, .d_hash = msdos_hash,
.d_compare = msdos_cmp, .d_compare = msdos_cmp,
...@@ -194,7 +218,7 @@ static struct dentry_operations msdos_dentry_operations = { ...@@ -194,7 +218,7 @@ static struct dentry_operations msdos_dentry_operations = {
/***** Get inode using directory and name */ /***** Get inode using directory and name */
static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd) struct nameidata *nd)
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct inode *inode = NULL; struct inode *inode = NULL;
...@@ -202,7 +226,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, ...@@ -202,7 +226,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
loff_t i_pos; loff_t i_pos;
int res; int res;
dentry->d_op = &msdos_dentry_operations; dentry->d_op = &msdos_dentry_operations;
lock_kernel(); lock_kernel();
...@@ -260,7 +284,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name, ...@@ -260,7 +284,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
/***** Create a file */ /***** Create a file */
static int msdos_create(struct inode *dir, struct dentry *dentry, int mode, static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd) struct nameidata *nd)
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct buffer_head *bh; struct buffer_head *bh;
...@@ -271,19 +295,19 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -271,19 +295,19 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
unsigned char msdos_name[MSDOS_NAME]; unsigned char msdos_name[MSDOS_NAME];
lock_kernel(); lock_kernel();
res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
msdos_name, &MSDOS_SB(sb)->options); msdos_name, &MSDOS_SB(sb)->options);
if (res < 0) { if (res < 0) {
unlock_kernel(); unlock_kernel();
return res; return res;
} }
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* Have to do it due to foo vs. .foo conflicts */ /* Have to do it due to foo vs. .foo conflicts */
if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) { if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
brelse(bh); brelse(bh);
unlock_kernel(); unlock_kernel();
return -EINVAL; return -EINVAL;
} }
inode = NULL; inode = NULL;
res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid); res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
if (res) { if (res) {
...@@ -349,18 +373,18 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -349,18 +373,18 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
struct inode *inode; struct inode *inode;
int res,is_hid; int res, is_hid;
unsigned char msdos_name[MSDOS_NAME]; unsigned char msdos_name[MSDOS_NAME];
loff_t i_pos; loff_t i_pos;
lock_kernel(); lock_kernel();
res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
msdos_name, &MSDOS_SB(sb)->options); msdos_name, &MSDOS_SB(sb)->options);
if (res < 0) { if (res < 0) {
unlock_kernel(); unlock_kernel();
return res; return res;
} }
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* foo vs .foo situation */ /* foo vs .foo situation */
if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
goto out_exist; goto out_exist;
...@@ -376,7 +400,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -376,7 +400,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
res = 0; res = 0;
dir->i_nlink++; dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */ inode->i_nlink = 2; /* no need to mark them dirty */
res = fat_new_dir(inode, dir, 0); res = fat_new_dir(inode, dir, 0);
if (res) if (res)
...@@ -440,14 +464,16 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) ...@@ -440,14 +464,16 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
} }
static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
struct dentry *old_dentry, struct dentry *old_dentry,
struct inode *new_dir, unsigned char *new_name, struct dentry *new_dentry, struct inode *new_dir, unsigned char *new_name,
struct buffer_head *old_bh, struct dentry *new_dentry,
struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid) struct buffer_head *old_bh,
struct msdos_dir_entry *old_de, loff_t old_i_pos,
int is_hid)
{ {
struct buffer_head *new_bh=NULL,*dotdot_bh=NULL; struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
struct msdos_dir_entry *new_de,*dotdot_de; struct msdos_dir_entry *new_de, *dotdot_de;
struct inode *old_inode,*new_inode; struct inode *old_inode, *new_inode;
loff_t new_i_pos, dotdot_i_pos; loff_t new_i_pos, dotdot_i_pos;
int error; int error;
int is_dir; int is_dir;
...@@ -456,8 +482,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, ...@@ -456,8 +482,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
new_inode = new_dentry->d_inode; new_inode = new_dentry->d_inode;
is_dir = S_ISDIR(old_inode->i_mode); is_dir = S_ISDIR(old_inode->i_mode);
if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 &&
&& !new_inode) !new_inode)
goto degenerate_case; goto degenerate_case;
if (is_dir) { if (is_dir) {
if (new_inode) { if (new_inode) {
...@@ -502,7 +528,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, ...@@ -502,7 +528,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
} }
if (dotdot_bh) { if (dotdot_bh) {
dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart); dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
dotdot_de->starthi = cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16); dotdot_de->starthi =
cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
mark_buffer_dirty(dotdot_bh); mark_buffer_dirty(dotdot_bh);
old_dir->i_nlink--; old_dir->i_nlink--;
mark_inode_dirty(old_dir); mark_inode_dirty(old_dir);
...@@ -522,7 +549,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, ...@@ -522,7 +549,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
degenerate_case: degenerate_case:
error = -EINVAL; error = -EINVAL;
if (new_de!=old_de) if (new_de != old_de)
goto out; goto out;
if (is_hid) if (is_hid)
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN; MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
...@@ -537,7 +564,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, ...@@ -537,7 +564,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry) struct inode *new_dir, struct dentry *new_dentry)
{ {
struct buffer_head *old_bh; struct buffer_head *old_bh;
struct msdos_dir_entry *old_de; struct msdos_dir_entry *old_de;
...@@ -547,18 +574,21 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -547,18 +574,21 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
lock_kernel(); lock_kernel();
error = msdos_format_name(old_dentry->d_name.name, error = msdos_format_name(old_dentry->d_name.name,
old_dentry->d_name.len,old_msdos_name, old_dentry->d_name.len, old_msdos_name,
&MSDOS_SB(old_dir->i_sb)->options); &MSDOS_SB(old_dir->i_sb)->options);
if (error < 0) if (error < 0)
goto rename_done; goto rename_done;
error = msdos_format_name(new_dentry->d_name.name, error = msdos_format_name(new_dentry->d_name.name,
new_dentry->d_name.len,new_msdos_name, new_dentry->d_name.len, new_msdos_name,
&MSDOS_SB(new_dir->i_sb)->options); &MSDOS_SB(new_dir->i_sb)->options);
if (error < 0) if (error < 0)
goto rename_done; goto rename_done;
is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.'); is_hid =
old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.'); (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
old_hid =
(old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos); error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
if (error < 0) if (error < 0)
goto rename_done; goto rename_done;
...@@ -583,7 +613,7 @@ static struct inode_operations msdos_dir_inode_operations = { ...@@ -583,7 +613,7 @@ static struct inode_operations msdos_dir_inode_operations = {
.setattr = fat_notify_change, .setattr = fat_notify_change,
}; };
static int msdos_fill_super(struct super_block *sb,void *data, int silent) static int msdos_fill_super(struct super_block *sb, void *data, int silent)
{ {
int res; int res;
...@@ -596,7 +626,8 @@ static int msdos_fill_super(struct super_block *sb,void *data, int silent) ...@@ -596,7 +626,8 @@ static int msdos_fill_super(struct super_block *sb,void *data, int silent)
} }
static struct super_block *msdos_get_sb(struct file_system_type *fs_type, static struct super_block *msdos_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data) int flags, const char *dev_name,
void *data)
{ {
return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super); return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment