--- linux/fs/msdos/namei.c 2018/04/24 18:12:17 1.1 +++ linux/fs/msdos/namei.c 2018/04/24 18:14:16 1.1.1.2 @@ -22,6 +22,12 @@ static char *reserved_names[] = { NULL }; +/* Characters that are undesirable in an MS-DOS file name */ + +static char bad_chars[] = "*?<>|\" "; +static char bad_if_strict[] = "+=,;"; + + /* Formats an MS-DOS file name. Rejects invalid names. */ static int msdos_format_name(char conv,const char *name,int len,char *res) @@ -42,9 +48,10 @@ static int msdos_format_name(char conv,c for (walk = res; len && walk-res < 8; walk++) { c = get_fs_byte(name++); len--; - if (c == ' ' && conv != 'r') return -EINVAL; - if (c >= 'A' && c <= 'Z') { - if (conv != 'r') return -EINVAL; + if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; + if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL; + if (c >= 'A' && c <= 'Z') { + if (conv == 's') return -EINVAL; c += 32; } if (c < ' ' || c == ':' || c == '\\') return -EINVAL; @@ -65,11 +72,13 @@ static int msdos_format_name(char conv,c while (len > 0 && walk-res < MSDOS_NAME) { c = get_fs_byte(name++); len--; - if (c == ' ' && conv != 'r') return -EINVAL; + if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; + if (conv == 's' && strchr(bad_if_strict,c)) + return -EINVAL; if (c < ' ' || c == ':' || c == '\\' || c == '.') return -EINVAL; if (c >= 'A' && c <= 'Z') { - if (conv != 'r') return -EINVAL; + if (conv == 's') return -EINVAL; c += 32; } space = c == ' '; @@ -135,13 +144,13 @@ int msdos_lookup(struct inode *dir,const iput(dir); return -EACCES; } - if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */ + if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */ iput(*result); iput(dir); return -ENOENT; } - while ((*result)->i_data[D_OLD]) { - next = (struct inode *) ((*result)->i_data[D_OLD]); + while (MSDOS_I(*result)->i_old) { + next = MSDOS_I(*result)->i_old; iput(*result); if (!(*result = iget(next->i_dev,next->i_ino))) panic("msdos_lookup: Can't happen"); @@ -209,6 +218,26 @@ int msdos_create(struct inode *dir,const } +#ifdef DEBUG + +static void dump_fat(struct super_block *sb,int start) +{ + printk("["); + while (start) { + printk("%d ",start); + start = fat_access(sb,start,-1); + if (!start) { + printk("ERROR"); + break; + } + if (start == -1) break; + } + printk("]\n"); +} + +#endif + + int msdos_mkdir(struct inode *dir,const char *name,int len,int mode) { struct buffer_head *bh; @@ -234,21 +263,25 @@ int msdos_mkdir(struct inode *dir,const iput(dir); return res; } - inode->i_data[D_BUSY] = 1; /* prevent lookups */ + dir->i_nlink++; + inode->i_nlink = 2; /* no need to mark them dirty */ + MSDOS_I(inode)->i_busy = 1; /* prevent lookups */ if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error; if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0) goto mkdir_error; - dot->i_size = inode->i_size; - dot->i_data[D_START] = inode->i_data[D_START]; + dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */ + MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start; + dot->i_nlink = inode->i_nlink; dot->i_dirt = 1; iput(dot); if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0) goto mkdir_error; unlock_creation(); dot->i_size = dir->i_size; - dot->i_data[D_START] = dir->i_data[D_START]; + MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start; + dot->i_nlink = dir->i_nlink; dot->i_dirt = 1; - inode->i_data[D_BUSY] = 0; + MSDOS_I(inode)->i_busy = 0; iput(dot); iput(inode); iput(dir); @@ -271,7 +304,8 @@ int msdos_rmdir(struct inode *dir,const bh = NULL; inode = NULL; res = -EINVAL; - if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done; + if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 && + get_fs_byte(name+1) == '.'))) goto rmdir_done; if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done; res = -ENOENT; if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done; @@ -280,7 +314,7 @@ int msdos_rmdir(struct inode *dir,const res = -EBUSY; if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done; if (inode->i_count > 1) goto rmdir_done; - if (inode->i_data[D_START]) { /* may be zero in mkdir */ + if (MSDOS_I(inode)->i_start) { /* may be zero in mkdir */ res = -ENOTEMPTY; pos = 0; dbh = NULL; @@ -293,6 +327,7 @@ int msdos_rmdir(struct inode *dir,const } inode->i_nlink = 0; dir->i_mtime = CURRENT_TIME; + dir->i_nlink--; inode->i_dirt = dir->i_dirt = 1; de->name[0] = DELETED_FLAG; bh->b_dirt = 1; @@ -325,7 +360,7 @@ int msdos_unlink(struct inode *dir,const goto unlink_done; } inode->i_nlink = 0; - inode->i_data[D_BUSY] = 1; + MSDOS_I(inode)->i_busy = 1; inode->i_dirt = 1; de->name[0] = DELETED_FLAG; bh->b_dirt = 1; @@ -364,7 +399,7 @@ static int rename_same_dir(struct inode return -EPERM; } new_inode->i_nlink = 0; - new_inode->i_data[D_BUSY] = 1; + MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; new_bh->b_dirt = 1; @@ -432,7 +467,7 @@ static int rename_diff_dir(struct inode return -EPERM; } new_inode->i_nlink = 0; - new_inode->i_data[D_BUSY] = 1; + MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; new_bh->b_dirt = 1; @@ -450,15 +485,16 @@ static int rename_diff_dir(struct inode return -EIO; } msdos_read_inode(free_inode); - old_inode->i_data[D_BUSY] = 1; + MSDOS_I(old_inode)->i_busy = 1; + cache_inval_inode(old_inode); old_inode->i_dirt = 1; old_de->name[0] = DELETED_FLAG; old_bh->b_dirt = 1; free_bh->b_dirt = 1; if (!exists) iput(free_inode); else { - new_inode->i_data[D_DEPEND] = (int) free_inode; - free_inode->i_data[D_OLD] = (int) new_inode; + MSDOS_I(new_inode)->i_depend = free_inode; + MSDOS_I(free_inode)->i_old = new_inode; /* free_inode is put when putting new_inode */ iput(new_inode); brelse(new_bh); @@ -471,12 +507,15 @@ static int rename_diff_dir(struct inode error = -EIO; goto rename_done; } - dotdot_de->start = dotdot_inode->i_data[D_START] = - new_dir->i_data[D_START]; + dotdot_de->start = MSDOS_I(dotdot_inode)->i_start = + MSDOS_I(new_dir)->i_start; dotdot_inode->i_dirt = 1; dotdot_bh->b_dirt = 1; iput(dotdot_inode); brelse(dotdot_bh); + old_dir->i_nlink--; + new_dir->i_nlink++; + /* no need to mark them dirty */ } error = 0; rename_done: