summaryrefslogtreecommitdiffstats
path: root/fs/vfat
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
commit230e5ab6a084ed50470f101934782dbf54b0d06b (patch)
tree5dd821c8d33f450470588e7a543f74bf74306e9e /fs/vfat
parentc9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff)
Merge with Linux 2.1.67.
Diffstat (limited to 'fs/vfat')
-rw-r--r--fs/vfat/Makefile4
-rw-r--r--fs/vfat/namei.c360
-rw-r--r--fs/vfat/vfatfs_syms.c37
3 files changed, 245 insertions, 156 deletions
diff --git a/fs/vfat/Makefile b/fs/vfat/Makefile
index 354757b9a..df903636f 100644
--- a/fs/vfat/Makefile
+++ b/fs/vfat/Makefile
@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := vfat.o
-O_OBJS :=
-OX_OBJS := namei.o
+O_OBJS := namei.o
+OX_OBJS := vfatfs_syms.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 587291669..c1ff4176c 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -11,21 +11,20 @@
*/
#include <linux/config.h>
+#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/msdos_fs.h>
+#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
+#include <linux/malloc.h>
#include "../fat/msbuffer.h"
-#include "../fat/tables.h"
#if 0
# define PRINTK(x) printk x
@@ -79,13 +78,30 @@ static struct super_operations vfat_sops = {
NULL /* remount */
};
+static int simple_getbool(char *s, int *setval)
+{
+ if (s) {
+ if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
+ *setval = 1;
+ } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
+ *setval = 0;
+ } else {
+ return 0;
+ }
+ } else {
+ *setval = 1;
+ }
+ return 1;
+}
+
static int parse_options(char *options, struct fat_mount_options *opts)
{
char *this_char,*value,save,*savep;
- int ret;
+ int ret, val;
opts->unicode_xlate = opts->posixfs = 0;
opts->numtail = 1;
+ opts->utf8 = 0;
if (!options) return 1;
save = 0;
@@ -97,25 +113,19 @@ static int parse_options(char *options, struct fat_mount_options *opts)
savep = value;
*value++ = 0;
}
- if (!strcmp(this_char,"uni_xlate")) {
- if (value) {
- ret = 0;
- } else {
- opts->unicode_xlate = 1;
- }
- }
- else if (!strcmp(this_char,"posix")) {
- if (value) {
- ret = 0;
- } else {
- opts->posixfs = 1;
- }
- }
- else if (!strcmp(this_char,"nonumtail")) {
- if (value) {
- ret = 0;
- } else {
- opts->numtail = 0;
+ if (!strcmp(this_char,"utf8")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->utf8 = val;
+ } else if (!strcmp(this_char,"uni_xlate")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->unicode_xlate = val;
+ } else if (!strcmp(this_char,"posix")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->posixfs = val;
+ } else if (!strcmp(this_char,"nonumtail")) {
+ ret = simple_getbool(value, &val);
+ if (ret) {
+ opts->numtail = !val;
}
}
if (this_char != options)
@@ -127,6 +137,9 @@ static int parse_options(char *options, struct fat_mount_options *opts)
return 0;
}
}
+ if (opts->unicode_xlate) {
+ opts->utf8 = 0;
+ }
return 1;
}
@@ -137,6 +150,8 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
MOD_INC_USE_COUNT;
+ MSDOS_SB(sb)->options.isvfat = 1;
+
sb->s_op = &vfat_sops;
res = fat_read_super(sb, data, silent);
if (res == NULL) {
@@ -148,7 +163,6 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
MOD_DEC_USE_COUNT;
} else {
- MSDOS_SB(sb)->options.isvfat = 1;
MSDOS_SB(sb)->options.dotsOK = 0;
}
@@ -225,7 +239,6 @@ static const char *reserved_names[] = {
/* Characters that are undesirable in an MS-DOS file name */
static char bad_chars[] = "*?<>|\":/\\";
-static char bad_if_strict[] = "+=,; []";
static char replace_chars[] = "[];,+=";
static int vfat_find(struct inode *dir,struct qstr* name,
@@ -265,8 +278,8 @@ static int vfat_valid_longname(const char *name, int len, int dot_dirs,
return 0;
}
-static int vfat_valid_shortname(char conv,const char *name,int len,
- int dot_dirs)
+static int vfat_valid_shortname(const char *name,int len,
+ int dot_dirs, int utf8)
{
const char *walk, **reserved;
unsigned char c;
@@ -283,17 +296,17 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
for (walk = name; len && walk-name < 8;) {
c = *walk++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
if ((walk == name) && (c == 0xE5)) c = 0x05;
if (c == '.') break;
space = c == ' ';
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len && c != '.') {
+ if (len && c != '.') {
c = *walk++;
len--;
if (c != '.') return -EINVAL;
@@ -304,18 +317,17 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
while (len > 0 && walk-name < (MSDOS_NAME+1)) {
c = *walk++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c))
- return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c))
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
space = c == ' ';
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+ if (len) return -EINVAL;
}
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(name,*reserved,8)) return -EINVAL;
@@ -328,8 +340,8 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
* returned. The formatted short filename is returned in 'res'.
*/
-static int vfat_format_name(char conv,const char *name,int len,char *res,
- int dot_dirs)
+static int vfat_format_name(const char *name,int len,char *res,
+ int dot_dirs,int utf8)
{
char *walk;
const char **reserved;
@@ -349,17 +361,17 @@ static int vfat_format_name(char conv,const char *name,int len,char *res,
for (walk = res; len && walk-res < 8; walk++) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
if (c == '.') break;
space = c == ' ';
*walk = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len && c != '.') {
+ if (len && c != '.') {
c = *name++;
len--;
if (c != '.') return -EINVAL;
@@ -370,19 +382,18 @@ static int vfat_format_name(char conv,const char *name,int len,char *res,
while (len > 0 && walk-res < MSDOS_NAME) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c))
- return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c))
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
space = c == ' ';
*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+ if (len) return -EINVAL;
}
while (walk-res < MSDOS_NAME) *walk++ = ' ';
for (reserved = reserved_names; *reserved; reserved++)
@@ -397,7 +408,7 @@ static char skip_chars[] = ".:\"?<>| ";
* shortname does not exist
*/
static int vfat_create_shortname(struct inode *dir, const char *name,
- int len, char *name_res)
+ int len, char *name_res, int utf8)
{
const char *ip, *ext_start, *end;
char *p;
@@ -417,16 +428,25 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
if (len && name[len-1]==' ') return -EINVAL;
if (len <= 12) {
/* Do a case insensitive search if the name would be a valid
- * shortname if is were all capitalized */
+ * shortname if is were all capitalized. However, do not
+ * allow spaces in short names because Win95 scandisk does
+ * not like that */
+ res = 0;
for (i = 0, p = msdos_name, ip = name; i < len; i++, p++, ip++)
{
+ if (*ip == ' ') {
+ res = -1;
+ break;
+ }
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
*p = *ip;
}
}
- res = vfat_format_name('x', msdos_name, len, name_res, 1);
+ if (res == 0) {
+ res = vfat_format_name(msdos_name, len, name_res, 1, utf8);
+ }
if (res > -1) {
PRINTK(("vfat_create_shortname 1\n"));
qname.name=msdos_name;
@@ -476,7 +496,10 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
{
- if (!strchr(skip_chars, *ip)) {
+ if (utf8 && (*ip & 0x80)) {
+ *p++ = '_';
+ baselen++;
+ } else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
@@ -496,7 +519,10 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
if (ext_start) {
extlen = 0;
for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
- if (!strchr(skip_chars, *ip)) {
+ if (utf8 && (*ip & 0x80)) {
+ *p++ = '_';
+ extlen++;
+ } else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
@@ -547,7 +573,7 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
qname.len=totlen;
res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
}
- res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
+ res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
return res;
}
@@ -596,7 +622,9 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots)
ino = fat_get_entry(dir,&curr,&bh,&de);
}
- if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if ((dir->i_ino == MSDOS_ROOT_INO) &&
+ (MSDOS_SB(sb)->fat_bits != 32))
+ return -ENOSPC;
if ((res = fat_add_cluster(dir)) < 0) return res;
ino = fat_get_entry(dir,&curr,&bh,&de);
}
@@ -605,7 +633,8 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots)
/* Translate a string, including coded sequences into Unicode */
static int
-xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
+xlate_to_uni(const char *name, int len, char *outname, int *outlen,
+ int escape, int utf8, struct nls_table *nls)
{
int i;
const unsigned char *ip;
@@ -613,22 +642,43 @@ xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
int fill;
unsigned char c1, c2, c3;
- op = outname;
- for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260; i++, *outlen += 1)
- {
- if (escape && (i < len - 4) &&
- (*ip == ':') &&
- ((c1 = fat_code2uni[ip[1]]) != 255) &&
- ((c2 = fat_code2uni[ip[2]]) != 255) &&
- ((c3 = fat_code2uni[ip[3]]) != 255)) {
- *op++ = (c1 << 4) + (c2 >> 2);
- *op++ = ((c2 & 0x3) << 6) + c3;
- ip += 4;
+ if (utf8) {
+ *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);
+ if (name[len-1] == '.')
+ *outlen-=2;
+ op = &outname[*outlen * sizeof(__u16)];
+ } else {
+ if (name[len-1] == '.')
+ len--;
+ op = outname;
+ if (nls) {
+ /* XXX: i is incorrectly computed. */
+ for (i = 0, ip = name, op = outname, *outlen = 0;
+ i < len && *outlen <= 260; i++, *outlen += 1)
+ {
+ if (escape && (*ip == ':')) {
+ if (i > len - 4) return -EINVAL;
+ c1 = fat_esc2uni[ip[1]];
+ c2 = fat_esc2uni[ip[2]];
+ c3 = fat_esc2uni[ip[3]];
+ if (c1 == 255 || c2 == 255 || c3 == 255)
+ return -EINVAL;
+ *op++ = (c1 << 4) + (c2 >> 2);
+ *op++ = ((c2 & 0x3) << 6) + c3;
+ ip += 4;
+ } else {
+ *op++ = nls->charset2uni[*ip].uni1;
+ *op++ = nls->charset2uni[*ip].uni2;
+ ip++;
+ }
+ }
} else {
- *op++ = fat_a2uni[*ip].uni1;
- *op++ = fat_a2uni[*ip].uni2;
- ip++;
+ for (i = 0, ip = name, op = outname, *outlen = 0;
+ i < len && *outlen <= 260; i++, *outlen += 1)
+ {
+ *op++ = *ip++;
+ *op++ = 0;
+ }
}
}
if (*outlen > 260)
@@ -653,7 +703,8 @@ xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
static int
vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
- char *msdos_name, int *slots, int uni_xlate)
+ char *msdos_name, int *slots,
+ int uni_xlate, int utf8, struct nls_table *nls)
{
struct msdos_dir_slot *ps;
struct msdos_dir_entry *de;
@@ -667,10 +718,11 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
int i;
loff_t offset;
+ if (name[len-1] == '.') len--;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
uniname = (char *) page;
- res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate);
+ res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls);
if (res < 0) {
free_page(page);
return res;
@@ -690,8 +742,7 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
ps->attr = ATTR_EXT;
ps->reserved = 0;
ps->alias_checksum = cksum;
- ps->start[0] = 0;
- ps->start[1] = 0;
+ ps->start = 0;
PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
offset = (slot - 1) * 26;
ip = &uniname[offset];
@@ -728,11 +779,14 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
{
struct msdos_dir_entry *de;
char msdos_name[MSDOS_NAME];
- int res, xlate;
+ int res, xlate, utf8;
+ struct nls_table *nls;
PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
de = (struct msdos_dir_entry *) ds;
xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
+ utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
+ nls = MSDOS_SB(dir->i_sb)->nls_io;
*slots = 1;
*is_long = 0;
@@ -742,13 +796,13 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
} else {
PRINTK(("vfat_build_slots 4\n"));
- res = vfat_valid_shortname('x', name, len, 1);
+ res = vfat_valid_shortname(name, len, 1, utf8);
if (res > -1) {
PRINTK(("vfat_build_slots 5a\n"));
- res = vfat_format_name('x', name, len, de->name, 1);
+ res = vfat_format_name(name, len, de->name, 1, utf8);
PRINTK(("vfat_build_slots 5b\n"));
} else {
- res = vfat_create_shortname(dir, name, len, msdos_name);
+ res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
if (res < 0) {
return res;
}
@@ -761,7 +815,7 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
*is_long = 1;
return vfat_fill_long_slots(ds, name, len, msdos_name,
- slots, xlate);
+ slots, xlate, utf8, nls);
}
}
return 0;
@@ -787,8 +841,11 @@ static int vfat_readdir_cb(
vf->name, vf->len, name, name_len);
#endif
+ /* Filenames cannot end in '.' or we treat like it has none */
if (vf->len != name_len) {
- return 0;
+ if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) {
+ return 0;
+ }
}
s1 = name; s2 = vf->name;
@@ -821,12 +878,17 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
struct msdos_dir_entry *de;
struct msdos_dir_slot *ps;
loff_t offset;
- struct msdos_dir_slot ds[MSDOS_SLOTS];
+ struct msdos_dir_slot *ds;
int is_long;
int slots, slot;
int res;
PRINTK(("Entering vfat_find\n"));
+
+ ds = (struct msdos_dir_slot *)
+ kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
+ if (ds == NULL) return -ENOMEM;
+
fil.f_pos = 0;
vf.name = qname->name;
vf.len = qname->len;
@@ -835,10 +897,11 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
vf.posix = MSDOS_SB(sb)->options.posixfs;
res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
PRINTK(("vfat_find: Debug 1\n"));
- if (res < 0) return res;
+ if (res < 0) goto cleanup;
if (vf.found) {
if (new_filename) {
- return -EEXIST;
+ res = -EEXIST;
+ goto cleanup;
}
sinfo_out->longname_offset = vf.offset;
sinfo_out->shortname_offset = vf.short_offset;
@@ -848,16 +911,19 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->ino = vf.ino;
PRINTK(("vfat_find: Debug 2\n"));
- return 0;
+ res = 0;
+ goto cleanup;
}
PRINTK(("vfat_find: Debug 3\n"));
- if (!vf.found && !new_filename)
- return -ENOENT;
+ if (!vf.found && !new_filename) {
+ res = -ENOENT;
+ goto cleanup;
+ }
res = vfat_build_slots(dir, qname->name, qname->len, ds,
&slots, &is_long);
- if (res < 0) return res;
+ if (res < 0) goto cleanup;
de = (struct msdos_dir_entry *) ds;
@@ -867,7 +933,8 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
if (is_long) slots++;
offset = vfat_find_free_slots(dir, slots);
if (offset < 0) {
- return offset;
+ res = offset;
+ goto cleanup;
}
PRINTK(("vfat_find: create file 2\n"));
@@ -878,7 +945,8 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
if (sinfo_out->ino < 0) {
PRINTK(("vfat_find: problem\n"));
- return sinfo_out->ino;
+ res = sinfo_out->ino;
+ goto cleanup;
}
memcpy(de, ps, sizeof(struct msdos_dir_slot));
fat_mark_buffer_dirty(sb, bh, 1);
@@ -890,12 +958,12 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
PRINTK(("vfat_find: create file 5\n"));
- memset(de->unused, 0, sizeof(de->unused));
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->ctime_ms = 0;
de->ctime = de->time;
de->adate = de->cdate = de->date;
de->start = 0;
+ de->starthi = 0;
de->size = 0;
de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
de->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
@@ -913,10 +981,15 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->total_slots = slots;
sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
+ res = 0;
return 0;
+ } else {
+ res = -ENOENT;
}
- return -ENOENT;
+cleanup:
+ kfree(ds);
+ return res;
}
int vfat_lookup(struct inode *dir,struct dentry *dentry)
@@ -1040,10 +1113,10 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
memcpy(de->name,name,MSDOS_NAME);
- memset(de->unused, 0, sizeof(de->unused));
de->lcase = 0;
de->attr = ATTR_DIR;
de->start = 0;
+ de->starthi = 0;
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->ctime_ms = 0;
de->ctime = de->time;
@@ -1058,10 +1131,12 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
if (isdot) {
dot->i_size = dir->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
dot->i_nlink = dir->i_nlink;
} else {
dot->i_size = parent->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(parent)->i_logstart;
dot->i_nlink = parent->i_nlink;
}
@@ -1244,10 +1319,8 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
if (res > 0) {
res = 0;
}
- } else {
- printk("Problem in vfat_rmdirx\n");
+ dir->i_version = ++event;
}
- dir->i_version = ++event;
rmdir_done:
fat_brelse(sb, bh);
@@ -1275,19 +1348,15 @@ static int vfat_unlinkx(
struct slot_info sinfo;
bh = NULL;
- if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0)
- goto unlink_done;
+ res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
if (res >= 0 && sinfo.total_slots > 0) {
res = vfat_remove_entry(dir,&sinfo,&bh,dentry,0,nospc);
if (res > 0) {
res = 0;
}
- } else {
- printk("Problem in vfat_unlinkx: res=%d, total_slots=%d\n",res, sinfo.total_slots);
}
-unlink_done:
fat_brelse(sb, bh);
return res;
}
@@ -1329,7 +1398,16 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry)
return res;
}
+/***** Unlink, as called for uvfatfs */
+int vfat_unlink_uvfat(struct inode *dir,struct dentry *dentry)
+{
+ int res;
+ res = vfat_unlinkx (dir,dentry,0);
+ iput(dir);
+ return res;
+}
+
int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
struct inode *new_dir,struct dentry *new_dentry)
{
@@ -1337,8 +1415,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
struct buffer_head *old_bh,*new_bh,*dotdot_bh;
struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
loff_t old_offset,new_offset,old_longname_offset;
- int old_slots,old_ino,new_ino,dotdot_ino,ino;
- struct inode *old_inode, *new_inode, *dotdot_inode, *walk;
+ int old_slots,old_ino,new_ino,dotdot_ino;
+ struct inode *old_inode, *new_inode, *dotdot_inode;
+ struct dentry *walk;
int res, is_dir, i;
int locked = 0;
struct slot_info sinfo;
@@ -1373,25 +1452,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
res = -EINVAL;
goto rename_done;
}
- if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
+ walk = new_dentry;
/* prevent moving directory below itself */
- while (walk->i_ino != MSDOS_ROOT_INO) {
- ino = fat_parent_ino(walk,1);
- iput(walk);
- if (ino < 0) {
- res = ino;
- goto rename_done;
- }
- if (ino == old_ino) {
- res = -EINVAL;
- goto rename_done;
- }
- if (!(walk = iget(new_dir->i_sb,ino))) {
- res = -EIO;
- goto rename_done;
- }
+ for (;;) {
+ if (walk == old_dentry) return -EINVAL;
+ if (walk == walk->d_parent) break;
+ walk = walk->d_parent;
}
- iput(walk);
}
res = vfat_find(new_dir,&new_dentry->d_name,1,0,is_dir,&sinfo);
@@ -1417,10 +1484,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
PRINTK(("vfat_rename 8\n"));
if (res < 0) goto rename_done;
} else {
- PRINTK(("vfat_rename 9\n"));
- res = vfat_unlinkx(new_dir,new_dentry,1);
- PRINTK(("vfat_rename 10\n"));
- if (res < 0) goto rename_done;
+ /* Is this the same file, different case? */
+ if (new_inode != old_inode) {
+ PRINTK(("vfat_rename 9\n"));
+ res = vfat_unlinkx(new_dir,new_dentry,1);
+ PRINTK(("vfat_rename 10\n"));
+ if (res < 0) goto rename_done;
+ }
}
}
@@ -1444,6 +1514,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
new_de->cdate = old_de->cdate;
new_de->adate = old_de->adate;
new_de->start = old_de->start;
+ new_de->starthi = old_de->starthi;
new_de->size = old_de->size;
if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done;
@@ -1492,8 +1563,10 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
res = -EIO;
goto rename_done;
}
- dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
- MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
+ dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
+ dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
mark_inode_dirty(dotdot_inode);
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
@@ -1505,8 +1578,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
}
if (res > 0) res = 0;
- d_instantiate(new_dentry,new_inode);
- d_delete(old_dentry);
+ if (res == 0) {
+ d_move(old_dentry, new_dentry);
+ }
rename_done:
if (locked)
@@ -1547,28 +1621,6 @@ void vfat_read_inode(struct inode *inode)
fat_read_inode(inode, &vfat_dir_inode_operations);
}
-static struct file_system_type vfat_fs_type = {
- "vfat",
- FS_REQUIRES_DEV,
- vfat_read_super,
- NULL
-};
-
-EXPORT_SYMBOL(vfat_create);
-EXPORT_SYMBOL(vfat_unlink);
-EXPORT_SYMBOL(vfat_mkdir);
-EXPORT_SYMBOL(vfat_rmdir);
-EXPORT_SYMBOL(vfat_rename);
-EXPORT_SYMBOL(vfat_put_super);
-EXPORT_SYMBOL(vfat_read_super);
-EXPORT_SYMBOL(vfat_read_inode);
-EXPORT_SYMBOL(vfat_lookup);
-
-__initfunc(int init_vfat_fs(void))
-{
- return register_filesystem(&vfat_fs_type);
-}
-
#ifdef MODULE
int init_module(void)
{
diff --git a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c
new file mode 100644
index 000000000..739d8eae7
--- /dev/null
+++ b/fs/vfat/vfatfs_syms.c
@@ -0,0 +1,37 @@
+/*
+ * linux/fs/msdos/vfatfs_syms.c
+ *
+ * Exported kernel symbols for the VFAT filesystem.
+ * These symbols are used by dmsdos.
+ */
+
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/mm.h>
+#include <linux/msdos_fs.h>
+
+struct file_system_type vfat_fs_type = {
+ "vfat",
+ FS_REQUIRES_DEV,
+ vfat_read_super,
+ NULL
+};
+
+EXPORT_SYMBOL(vfat_create);
+EXPORT_SYMBOL(vfat_unlink);
+EXPORT_SYMBOL(vfat_unlink_uvfat);
+EXPORT_SYMBOL(vfat_mkdir);
+EXPORT_SYMBOL(vfat_rmdir);
+EXPORT_SYMBOL(vfat_rename);
+EXPORT_SYMBOL(vfat_put_super);
+EXPORT_SYMBOL(vfat_read_super);
+EXPORT_SYMBOL(vfat_read_inode);
+EXPORT_SYMBOL(vfat_lookup);
+
+int init_vfat_fs(void)
+{
+ return register_filesystem(&vfat_fs_type);
+}
+