OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k_old/trunk/rc203soc/sw/uClinux/fs/vfat
    from Rev 1765 to Rev 1782
    Reverse comparison

Rev 1765 → Rev 1782

/vfatfs_syms.c
0,0 → 1,54
/*
* 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_read_super, "vfat", 1, NULL
};
 
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
#define X(sym) EXPORT_SYMBOL(sym);
#define X_PUNCT ;
#else
#define X_PUNCT ,
static struct symbol_table vfat_syms = {
#include <linux/symtab_begin.h>
#endif
X(vfat_create) X_PUNCT
X(vfat_unlink) X_PUNCT
X(vfat_unlink_uvfat) X_PUNCT
X(vfat_mkdir) X_PUNCT
X(vfat_rmdir) X_PUNCT
X(vfat_rename) X_PUNCT
X(vfat_put_super) X_PUNCT
X(vfat_read_super) X_PUNCT
X(vfat_read_inode) X_PUNCT
X(vfat_lookup) X_PUNCT
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
#include <linux/symtab_end.h>
};
#endif
 
int init_vfat_fs(void)
{
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
return register_filesystem(&vfat_fs_type);
#else
int status;
 
if ((status = register_filesystem(&vfat_fs_type)) == 0)
status = register_symtab(&vfat_syms);
return status;
#endif
}
 
/namei.c
0,0 → 1,1689
/*
* linux/fs/vfat/namei.c
*
* Written 1992,1993 by Werner Almesberger
*
* Windows95/Windows NT compatible extended MSDOS filesystem
* by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
* VFAT filesystem to <chaffee@plateau.cs.berkeley.edu>. Specify
* what file operation caused you trouble and if you can duplicate
* the problem, send a script that demonstrates it.
*/
 
#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/malloc.h>
 
#include "../fat/msbuffer.h"
 
#if 0
# define PRINTK(x) printk x
#else
# define PRINTK(x)
#endif
 
#ifndef DEBUG
# define CHECK_STACK
#else
# define CHECK_STACK check_stack(__FILE__, __LINE__)
#endif
 
/*
* XXX: It would be better to use the tolower from linux/ctype.h,
* but _ctype is needed and it is not exported.
*/
#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
 
struct vfat_find_info {
const char *name;
int len;
int new_filename;
int found;
int is_long;
off_t offset;
off_t short_offset;
int long_slots;
ino_t ino;
int posix;
};
 
void vfat_read_inode(struct inode *inode);
 
void vfat_put_super(struct super_block *sb)
{
fat_put_super(sb);
MOD_DEC_USE_COUNT;
}
 
 
static struct super_operations vfat_sops = {
vfat_read_inode,
fat_notify_change,
fat_write_inode,
fat_put_inode,
vfat_put_super,
NULL, /* added in 0.96c */
fat_statfs,
NULL
};
 
static int parse_options(char *options, struct fat_mount_options *opts)
{
char *this_char,*value,save,*savep;
int ret;
 
opts->unicode_xlate = opts->posixfs = 0;
opts->numtail = 1;
opts->utf8 = 0;
 
if (!options) return 1;
save = 0;
savep = NULL;
ret = 1;
for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
if ((value = strchr(this_char,'=')) != NULL) {
save = *value;
savep = value;
*value++ = 0;
}
if (!strcmp(this_char,"utf8")) {
if (value) {
ret = 0;
} else {
opts->utf8 = 1;
}
} else 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 (this_char != options)
*(this_char-1) = ',';
if (value) {
*savep = save;
}
if (ret == 0) {
return 0;
}
}
if (opts->unicode_xlate) {
opts->utf8 = 0;
}
return 1;
}
 
struct super_block *vfat_read_super(struct super_block *sb,void *data,
int silent)
{
struct super_block *res;
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) {
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
 
if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
MOD_DEC_USE_COUNT;
} else {
MSDOS_SB(sb)->options.dotsOK = 0;
}
 
return res;
}
 
#ifdef DEBUG
 
static void
check_stack(const char *fname, int lineno)
{
int stack_level;
char *pg_dir;
 
stack_level = (long)(&pg_dir)-current->kernel_stack_page;
if (stack_level < 0)
printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
fname, lineno, stack_level);
else if (stack_level < 500)
printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
fname, lineno, stack_level);
#if 0
else
printk("------- vfat kstack ok in %s line %d: SL=%d\n",
fname, lineno, stack_level);
#endif
if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
printk("******* vfat stack corruption detected in %s at line %d\n",
fname, lineno);
}
}
 
static int debug = 0;
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");
}
 
static void dump_de(struct msdos_dir_entry *de)
{
int i;
unsigned char *p = (unsigned char *) de;
printk("[");
 
for (i = 0; i < 32; i++, p++) {
printk("%02x ", *p);
}
printk("]\n");
}
 
#endif
 
/* MS-DOS "device special files" */
 
static const char *reserved_names[] = {
"CON ","PRN ","NUL ","AUX ",
"LPT1 ","LPT2 ","LPT3 ","LPT4 ",
"COM1 ","COM2 ","COM3 ","COM4 ",
NULL };
 
 
/* Characters that are undesirable in an MS-DOS file name */
 
static char bad_chars[] = "*?<>|\":/\\";
static char replace_chars[] = "[];,+=";
 
static int vfat_find(struct inode *dir,const char *name,int len,
int find_long,int new_filename,int is_dir,
struct slot_info *sinfo_out);
 
/* Checks the validity of an long MS-DOS filename */
/* Returns negative number on error, 0 for a normal
* return, and 1 for . or .. */
 
static int vfat_valid_longname(const char *name, int len, int dot_dirs,
int xlate)
{
const char **reserved;
unsigned char c;
int i;
 
if (IS_FREE(name)) return -EINVAL;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
if (!dot_dirs) return -EEXIST;
return 1;
}
 
if (len && name[len-1] == ' ') return -EINVAL;
if (len >= 256) return -EINVAL;
for (i = 0; i < len; i++) {
c = name[i];
if (xlate && c == ':') continue;
if (strchr(bad_chars,c)) {
return -EINVAL;
}
}
if (len == 3 || len == 4) {
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(name,*reserved,8)) return -EINVAL;
}
return 0;
}
 
static int vfat_valid_shortname(const char *name,int len,
int dot_dirs, int utf8)
{
const char *walk, **reserved;
unsigned char c;
int space;
 
if (IS_FREE(name)) return -EINVAL;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
if (!dot_dirs) return -EEXIST;
return 1;
}
 
space = 1; /* disallow names starting with a dot */
c = 0;
for (walk = name; len && walk-name < 8;) {
c = *walk++;
len--;
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 (len && c != '.') {
c = *walk++;
len--;
if (c != '.') return -EINVAL;
}
while (c != '.' && len--) c = *walk++;
if (c == '.') {
if (len >= 4) return -EINVAL;
while (len > 0 && walk-name < (MSDOS_NAME+1)) {
c = *walk++;
len--;
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') return -EINVAL;
space = c == ' ';
}
if (space) return -EINVAL;
if (len) return -EINVAL;
}
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(name,*reserved,8)) return -EINVAL;
 
return 0;
}
 
/* Takes a short filename and converts it to a formatted MS-DOS filename.
* If the short filename is not a valid MS-DOS filename, an error is
* returned. The formatted short filename is returned in 'res'.
*/
 
static int vfat_format_name(const char *name,int len,char *res,
int dot_dirs,int utf8)
{
char *walk;
const char **reserved;
unsigned char c;
int space;
 
if (IS_FREE(name)) return -EINVAL;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
if (!dot_dirs) return -EEXIST;
memset(res+1,' ',10);
while (len--) *res++ = '.';
return 0;
}
 
space = 1; /* disallow names starting with a dot */
c = 0;
for (walk = res; len && walk-res < 8; walk++) {
c = *name++;
len--;
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 (len && c != '.') {
c = *name++;
len--;
if (c != '.') return -EINVAL;
}
while (c != '.' && len--) c = *name++;
if (c == '.') {
while (walk-res < 8) *walk++ = ' ';
while (len > 0 && walk-res < MSDOS_NAME) {
c = *name++;
len--;
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') return -EINVAL;
space = c == ' ';
*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
if (len) return -EINVAL;
}
while (walk-res < MSDOS_NAME) *walk++ = ' ';
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(res,*reserved,8)) return -EINVAL;
 
return 0;
}
 
static char skip_chars[] = ".:\"?<>| ";
 
/* Given a valid longname, create a unique shortname. Make sure the
* shortname does not exist
*/
static int vfat_create_shortname(struct inode *dir, const char *name,
int len, char *name_res, int utf8)
{
const char *ip, *ext_start, *end;
char *p;
int sz, extlen, baselen, totlen;
char msdos_name[13];
char base[9], ext[4];
int i;
int res;
int spaces;
char buf[8];
struct slot_info sinfo;
const char *name_start;
 
PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
sz = 0; /* Make compiler happy */
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. 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 = -EINVAL;
break;
}
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
*p = *ip;
}
}
if (res == 0) {
res = vfat_format_name(msdos_name, len, name_res, 1, utf8);
}
if (res > -1) {
PRINTK(("vfat_create_shortname 1\n"));
res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
PRINTK(("vfat_create_shortname 2\n"));
if (res > -1) return -EEXIST;
return 0;
}
}
 
PRINTK(("vfat_create_shortname 3\n"));
/* Now, we need to create a shortname from the long name */
ext_start = end = &name[len];
while (--ext_start >= name) {
if (*ext_start == '.') {
if (ext_start == end - 1) {
sz = len;
ext_start = NULL;
}
break;
}
}
if (ext_start == name - 1) {
sz = len;
ext_start = NULL;
} else if (ext_start) {
/*
* Names which start with a dot could be just
* an extension eg. "...test". In this case Win95
* uses the extension as the name and sets no extension.
*/
name_start = &name[0];
while (name_start < ext_start)
{
if (!strchr(skip_chars,*name_start)) break;
name_start++;
}
if (name_start != ext_start) {
sz = ext_start - name;
ext_start++;
} else {
sz = len;
ext_start=NULL;
}
}
 
for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
{
if (utf8 && (*ip & 0x80)) {
*p++ = '_';
baselen++;
} else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
*p = *ip;
}
if (strchr(replace_chars, *p)) *p='_';
p++; baselen++;
}
ip++;
}
if (baselen == 0) {
return -EINVAL;
}
spaces = 8 - baselen;
 
if (ext_start) {
extlen = 0;
for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
if (utf8 && (*ip & 0x80)) {
*p++ = '_';
extlen++;
} else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
*p = *ip;
}
if (strchr(replace_chars, *p)) *p='_';
extlen++;
p++;
}
}
} else {
extlen = 0;
}
ext[extlen] = '\0';
base[baselen] = '\0';
 
strcpy(msdos_name, base);
msdos_name[baselen] = '.';
strcpy(&msdos_name[baselen+1], ext);
 
totlen = baselen + extlen + (extlen > 0);
res = 0;
if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
}
i = 0;
while (res > -1) {
/* Create the next shortname to try */
i++;
if (i == 10000000) return -EEXIST;
sprintf(buf, "%d", i);
sz = strlen(buf);
if (sz + 1 > spaces) {
baselen = baselen - (sz + 1 - spaces);
spaces = sz + 1;
}
 
strncpy(msdos_name, base, baselen);
msdos_name[baselen] = '~';
strcpy(&msdos_name[baselen+1], buf);
msdos_name[baselen+sz+1] = '.';
strcpy(&msdos_name[baselen+sz+2], ext);
 
totlen = baselen + sz + 1 + extlen + (extlen > 0);
res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
}
res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
return res;
}
 
static loff_t vfat_find_free_slots(struct inode *dir,int slots)
{
struct super_block *sb = dir->i_sb;
loff_t offset, curr;
struct msdos_dir_entry *de;
struct buffer_head *bh;
struct inode *inode;
int ino;
int row;
int done;
int res;
int added;
 
PRINTK(("vfat_find_free_slots: find %d free slots\n", slots));
offset = curr = 0;
bh = NULL;
row = 0;
ino = fat_get_entry(dir,&curr,&bh,&de);
 
for (added = 0; added < 2; added++) {
while (ino > -1) {
done = IS_FREE(de->name);
if (done) {
inode = iget(sb,ino);
if (inode) {
/* Directory slots of busy deleted files aren't available yet. */
done = !MSDOS_I(inode)->i_busy;
/* PRINTK(("inode %d still busy\n", ino)); */
}
iput(inode);
}
if (done) {
row++;
if (row == slots) {
fat_brelse(sb, bh);
/* printk("----- Free offset at %d\n", offset); */
return offset;
}
} else {
row = 0;
offset = curr;
}
ino = fat_get_entry(dir,&curr,&bh,&de);
}
 
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);
}
return -ENOSPC;
}
 
/* Translate a string, including coded sequences into Unicode */
static int
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;
char *op;
int fill;
unsigned char c1, c2, c3;
 
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 {
for (i = 0, ip = name, op = outname, *outlen = 0;
i < len && *outlen <= 260; i++, *outlen += 1)
{
*op++ = *ip++;
*op++ = 0;
}
}
}
if (*outlen > 260)
return -ENAMETOOLONG;
 
if (*outlen % 13) {
*op++ = 0;
*op++ = 0;
*outlen += 1;
if (*outlen % 13) {
fill = 13 - (*outlen % 13);
for (i = 0; i < fill; i++) {
*op++ = 0xff;
*op++ = 0xff;
}
*outlen += fill;
}
}
 
return 0;
}
 
static int
vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
char *msdos_name, int *slots,
int uni_xlate, int utf8, struct nls_table *nls)
{
struct msdos_dir_slot *ps;
struct msdos_dir_entry *de;
int res;
int slot;
unsigned char cksum;
char *uniname;
const char *ip;
unsigned long page;
int unilen;
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, utf8, nls);
if (res < 0) {
free_page(page);
return res;
}
 
*slots = unilen / 13;
for (cksum = i = 0; i < 11; i++) {
cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
}
PRINTK(("vfat_fill_long_slots 3: slots=%d\n",*slots));
 
for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
int end, j;
 
PRINTK(("vfat_fill_long_slots 4\n"));
ps->id = slot;
ps->attr = ATTR_EXT;
ps->reserved = 0;
ps->alias_checksum = cksum;
ps->start = 0;
PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
offset = (slot - 1) * 26;
ip = &uniname[offset];
j = offset;
end = 0;
for (i = 0; i < 10; i += 2) {
ps->name0_4[i] = *ip++;
ps->name0_4[i+1] = *ip++;
}
PRINTK(("vfat_fill_long_slots 6\n"));
for (i = 0; i < 12; i += 2) {
ps->name5_10[i] = *ip++;
ps->name5_10[i+1] = *ip++;
}
PRINTK(("vfat_fill_long_slots 7\n"));
for (i = 0; i < 4; i += 2) {
ps->name11_12[i] = *ip++;
ps->name11_12[i+1] = *ip++;
}
}
PRINTK(("vfat_fill_long_slots 8\n"));
ds[0].id |= 0x40;
 
de = (struct msdos_dir_entry *) ps;
PRINTK(("vfat_fill_long_slots 9\n"));
strncpy(de->name, msdos_name, MSDOS_NAME);
 
free_page(page);
return 0;
}
static int vfat_build_slots(struct inode *dir,const char *name,int len,
struct msdos_dir_slot *ds, int *slots, int *is_long)
{
struct msdos_dir_entry *de;
char msdos_name[MSDOS_NAME];
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;
if (len == 1 && name[0] == '.') {
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
} else if (len == 2 && name[0] == '.' && name[1] == '.') {
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
} else {
PRINTK(("vfat_build_slots 4\n"));
res = vfat_valid_shortname(name, len, 1, utf8);
if (res > -1) {
PRINTK(("vfat_build_slots 5a\n"));
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, utf8);
if (res < 0) {
return res;
}
 
res = vfat_valid_longname(name, len, 1, xlate);
if (res < 0) {
return res;
}
 
*is_long = 1;
 
return vfat_fill_long_slots(ds, name, len, msdos_name,
slots, xlate, utf8, nls);
}
}
return 0;
}
 
static int vfat_readdir_cb(
filldir_t filldir,
void * buf,
const char * name,
int name_len,
int is_long,
off_t offset,
off_t short_offset,
int long_slots,
ino_t ino)
{
struct vfat_find_info *vf = (struct vfat_find_info *) buf;
const char *s1, *s2;
int i;
 
#ifdef DEBUG
if (debug) printk("cb: vf.name=%s, len=%d, name=%s, name_len=%d\n",
vf->name, vf->len, name, name_len);
#endif
 
/* Filenames cannot end in '.' or we treat like it has none */
if (vf->len != name_len) {
if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) {
return 0;
}
if (name_len == 2 && name[0] == '.' && name[1] == '.') {
return 0;
}
}
 
s1 = name; s2 = vf->name;
for (i = 0; i < name_len; i++) {
if (vf->new_filename && !vf->posix) {
if (tolower(*s1) != tolower(*s2))
return 0;
} else {
if (*s1 != *s2)
return 0;
}
s1++; s2++;
}
vf->found = 1;
vf->is_long = is_long;
vf->offset = (offset == 2) ? 0 : offset;
vf->short_offset = (short_offset == 2) ? 0 : short_offset;
vf->long_slots = long_slots;
vf->ino = ino;
return -1;
}
 
static int vfat_find(struct inode *dir,const char *name,int len,
int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
{
struct super_block *sb = dir->i_sb;
struct vfat_find_info vf;
struct file fil;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct msdos_dir_slot *ps;
loff_t offset;
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 = name;
vf.len = len;
vf.new_filename = new_filename;
vf.found = 0;
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) goto cleanup;
if (vf.found) {
if (new_filename) {
res = -EEXIST;
goto cleanup;
}
sinfo_out->longname_offset = vf.offset;
sinfo_out->shortname_offset = vf.short_offset;
sinfo_out->is_long = vf.is_long;
sinfo_out->long_slots = vf.long_slots;
sinfo_out->total_slots = vf.long_slots + 1;
sinfo_out->ino = vf.ino;
 
PRINTK(("vfat_find: Debug 2\n"));
res = 0;
goto cleanup;
}
 
PRINTK(("vfat_find: Debug 3\n"));
if (!vf.found && !new_filename) {
res = -ENOENT;
goto cleanup;
}
res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
if (res < 0) goto cleanup;
 
de = (struct msdos_dir_entry *) ds;
 
bh = NULL;
if (new_filename) {
PRINTK(("vfat_find: create file 1\n"));
if (is_long) slots++;
offset = vfat_find_free_slots(dir, slots);
if (offset < 0) {
res = offset;
goto cleanup;
}
 
PRINTK(("vfat_find: create file 2\n"));
/* Now create the new entry */
bh = NULL;
for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
PRINTK(("vfat_find: create file 3, slot=%d\n",slot));
sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
if (sinfo_out->ino < 0) {
PRINTK(("vfat_find: problem\n"));
res = sinfo_out->ino;
goto cleanup;
}
memcpy(de, ps, sizeof(struct msdos_dir_slot));
fat_mark_buffer_dirty(sb, bh, 1);
}
 
PRINTK(("vfat_find: create file 4\n"));
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
dir->i_dirt = 1;
 
PRINTK(("vfat_find: create file 5\n"));
 
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;
 
 
fat_mark_buffer_dirty(sb, bh, 1);
fat_brelse(sb, bh);
 
sinfo_out->is_long = (slots > 1) ? 1 : 0;
if (sinfo_out->is_long) {
sinfo_out->long_slots = slots - 1;
} else {
sinfo_out->long_slots = 0;
}
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;
} else {
res = -ENOENT;
}
 
cleanup:
kfree(ds);
return res;
}
 
int vfat_lookup(struct inode *dir,const char *name,int len,
struct inode **result)
{
int res, ino;
struct inode *next;
struct slot_info sinfo;
PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len));
 
*result = NULL;
if (!dir) return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
PRINTK (("vfat_lookup 2\n"));
if (len == 1 && name[0] == '.') {
*result = dir;
return 0;
}
if (len == 2 && name[0] == '.' && name[1] == '.') {
ino = fat_parent_ino(dir,0);
iput(dir);
if (ino < 0) return ino;
if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) {
iput(dir);
if (!(*result = iget(dir->i_sb, ino)))
return -EACCES;
return 0;
}
PRINTK (("vfat_lookup 3\n"));
if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
iput(dir);
return res;
}
PRINTK (("vfat_lookup 4.5\n"));
if (!(*result = iget(dir->i_sb,sinfo.ino))) {
iput(dir);
return -EACCES;
}
PRINTK (("vfat_lookup 5\n"));
if (!(*result)->i_sb ||
((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
/* crossed a mount point into a non-msdos fs */
iput(dir);
return 0;
}
if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
iput(*result);
iput(dir);
return -ENOENT;
}
PRINTK (("vfat_lookup 6\n"));
while (MSDOS_I(*result)->i_old) {
next = MSDOS_I(*result)->i_old;
iput(*result);
if (!(*result = iget(next->i_sb,next->i_ino))) {
fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
iput(dir);
return -ENOENT;
}
}
iput(dir);
return 0;
}
 
 
static int vfat_create_entry(struct inode *dir,const char *name,int len,
int is_dir, struct inode **result)
{
struct super_block *sb = dir->i_sb;
int res,ino;
loff_t offset;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct slot_info sinfo;
 
PRINTK(("vfat_create_entry 1\n"));
res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo);
if (res < 0) {
return res;
}
 
offset = sinfo.shortname_offset;
 
PRINTK(("vfat_create_entry 2\n"));
bh = NULL;
ino = fat_get_entry(dir, &offset, &bh, &de);
if (ino < 0) {
PRINTK(("vfat_mkdir problem\n"));
if (bh)
fat_brelse(sb, bh);
return ino;
}
PRINTK(("vfat_create_entry 3\n"));
 
if ((*result = iget(dir->i_sb,ino)) != NULL)
vfat_read_inode(*result);
fat_brelse(sb, bh);
if (!*result)
return -EIO;
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
CURRENT_TIME;
(*result)->i_dirt = 1;
(*result)->i_version = ++event;
dir->i_version = event;
dcache_add(dir, name, len, ino);
 
return 0;
}
 
int vfat_create(struct inode *dir,const char *name,int len,int mode,
struct inode **result)
{
int res;
 
if (!dir) return -ENOENT;
 
fat_lock_creation();
res = vfat_create_entry(dir,name,len,0,result);
if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
 
fat_unlock_creation();
iput(dir);
return res;
}
 
static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
struct buffer_head *bh,
struct msdos_dir_entry *de,int ino,const char *name, int isdot)
{
struct super_block *sb = dir->i_sb;
struct inode *dot;
 
PRINTK(("vfat_create_a_dotdir 1\n"));
 
/*
* XXX all times should be set by caller upon successful completion.
*/
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
memcpy(de->name,name,MSDOS_NAME);
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;
de->adate = de->cdate = de->date;
de->size = 0;
fat_mark_buffer_dirty(sb, bh, 1);
if ((dot = iget(dir->i_sb,ino)) != NULL)
vfat_read_inode(dot);
if (!dot) return -EIO;
dot->i_mtime = dot->i_atime = CURRENT_TIME;
dot->i_dirt = 1;
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;
}
 
iput(dot);
 
PRINTK(("vfat_create_a_dotdir 2\n"));
return 0;
}
 
static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
struct msdos_dir_entry *de;
loff_t offset;
 
PRINTK(("vfat_create_dotdirs 1\n"));
if ((res = fat_add_cluster(dir)) < 0) return res;
 
PRINTK(("vfat_create_dotdirs 2\n"));
offset = 0;
bh = NULL;
if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) return res;
PRINTK(("vfat_create_dotdirs 3\n"));
res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOT, 1);
PRINTK(("vfat_create_dotdirs 4\n"));
if (res < 0) {
fat_brelse(sb, bh);
return res;
}
PRINTK(("vfat_create_dotdirs 5\n"));
 
if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) {
fat_brelse(sb, bh);
return res;
}
PRINTK(("vfat_create_dotdirs 6\n"));
 
res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOTDOT, 0);
PRINTK(("vfat_create_dotdirs 7\n"));
fat_brelse(sb, bh);
 
return res;
}
 
/***** See if directory is empty */
static int vfat_empty(struct inode *dir)
{
struct super_block *sb = dir->i_sb;
loff_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
 
if (dir->i_count > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
/* Skip extended filename entries */
if (de->attr == ATTR_EXT) continue;
 
if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
MSDOS_NAME)) {
fat_brelse(sb, bh);
return -ENOTEMPTY;
}
}
if (bh)
fat_brelse(sb, bh);
}
return 0;
}
 
static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
struct msdos_dir_entry *de,int ino)
{
struct super_block *sb = dir->i_sb;
struct inode *inode;
int res;
 
if (ino < 0) return -EINVAL;
if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
if (!S_ISDIR(inode->i_mode)) {
iput(inode);
return -ENOTDIR;
}
if (dir->i_dev != inode->i_dev || dir == inode) {
iput(inode);
return -EBUSY;
}
res = vfat_empty(inode);
if (res) {
iput(inode);
return res;
}
inode->i_nlink = 0;
inode->i_mtime = dir->i_mtime = CURRENT_TIME;
inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_nlink--;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
iput(inode);
 
return 0;
}
 
static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
struct msdos_dir_entry *de,int ino,int nospc)
{
struct super_block *sb = dir->i_sb;
struct inode *inode;
if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) {
iput(inode);
return -EPERM;
}
inode->i_nlink = 0;
inode->i_mtime = dir->i_mtime = CURRENT_TIME;
inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_version = ++event;
MSDOS_I(inode)->i_busy = 1;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
 
iput(inode);
return 0;
}
 
static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
struct buffer_head **bh,struct msdos_dir_entry **de,
int is_dir,int nospc)
{
struct super_block *sb = dir->i_sb;
loff_t offset;
int res, i;
 
/* remove the shortname */
offset = sinfo->shortname_offset;
res = fat_get_entry(dir, &offset, bh, de);
if (res < 0) return res;
if (is_dir) {
res = vfat_rmdir_free_ino(dir,*bh,*de,res);
} else {
res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc);
}
if (res < 0) return res;
/* remove the longname */
offset = sinfo->longname_offset;
for (i = sinfo->long_slots; i > 0; --i) {
res = fat_get_entry(dir, &offset, bh, de);
if (res < 0) {
printk("vfat_remove_entry: problem 1\n");
continue;
}
(*de)->name[0] = DELETED_FLAG;
(*de)->attr = 0;
fat_mark_buffer_dirty(sb, *bh, 1);
}
return 0;
}
 
 
static int vfat_rmdirx(struct inode *dir,const char *name,int len)
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct slot_info sinfo;
 
bh = NULL;
res = -EPERM;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
goto rmdir_done;
res = vfat_find(dir,name,len,1,0,0,&sinfo);
 
if (res >= 0 && sinfo.total_slots > 0) {
res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0);
if (res > 0) {
res = 0;
}
dir->i_version = ++event;
}
 
rmdir_done:
fat_brelse(sb, bh);
return res;
}
 
/***** Remove a directory */
int vfat_rmdir(struct inode *dir,const char *name,int len)
{
int res;
 
res = vfat_rmdirx(dir, name, len);
iput(dir);
return res;
}
 
static int vfat_unlinkx(
struct inode *dir,
const char *name,
int len,
int nospc) /* Flag special file ? */
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct slot_info sinfo;
 
bh = NULL;
res = vfat_find(dir,name,len,1,0,0,&sinfo);
 
if (res >= 0 && sinfo.total_slots > 0) {
res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
if (res > 0) {
res = 0;
}
}
 
fat_brelse(sb, bh);
return res;
}
 
 
int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
{
struct inode *inode;
int res;
 
fat_lock_creation();
if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) {
fat_unlock_creation();
iput(dir);
return res;
}
 
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
 
res = vfat_create_dotdirs(inode, dir);
fat_unlock_creation();
MSDOS_I(inode)->i_busy = 0;
iput(inode);
iput(dir);
if (res < 0) {
if (vfat_rmdir(dir,name,len) < 0)
fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
}
return res;
}
 
/***** Unlink, as called for msdosfs */
int vfat_unlink(struct inode *dir,const char *name,int len)
{
int res;
 
res = vfat_unlinkx (dir,name,len,1);
iput(dir);
return res;
}
 
/***** Unlink, as called for uvfatfs */
int vfat_unlink_uvfat(struct inode *dir,const char *name,int len)
{
int res;
 
res = vfat_unlinkx (dir,name,len,0);
iput(dir);
return res;
}
int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
struct inode *new_dir,const char *new_name,int new_len,int must_be_dir)
{
struct super_block *sb = old_dir->i_sb;
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 res, is_dir, i;
int locked = 0;
struct slot_info sinfo;
 
PRINTK(("vfat_rename 1\n"));
if (old_dir == new_dir && old_len == new_len &&
strncmp(old_name, new_name, old_len) == 0)
return 0;
 
old_bh = new_bh = NULL;
old_inode = new_inode = NULL;
res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo);
PRINTK(("vfat_rename 2\n"));
if (res < 0) goto rename_done;
 
old_slots = sinfo.total_slots;
old_longname_offset = sinfo.longname_offset;
old_offset = sinfo.shortname_offset;
old_ino = sinfo.ino;
res = fat_get_entry(old_dir, &old_offset, &old_bh, &old_de);
PRINTK(("vfat_rename 3\n"));
if (res < 0) goto rename_done;
 
res = -ENOENT;
if (!(old_inode = iget(old_dir->i_sb,old_ino)))
goto rename_done;
is_dir = S_ISDIR(old_inode->i_mode);
if (must_be_dir && !is_dir)
goto rename_done;
if (is_dir) {
if ((old_dir->i_dev != new_dir->i_dev) ||
(old_ino == new_dir->i_ino)) {
res = -EINVAL;
goto rename_done;
}
if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
/* 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;
}
}
iput(walk);
}
 
res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo);
 
PRINTK(("vfat_rename 4\n"));
if (res > -1) {
int new_is_dir;
 
PRINTK(("vfat_rename 5\n"));
/* Filename currently exists. Need to delete it */
new_offset = sinfo.shortname_offset;
res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
PRINTK(("vfat_rename 6\n"));
if (res < 0) goto rename_done;
 
if (!(new_inode = iget(new_dir->i_sb,res)))
goto rename_done;
new_is_dir = S_ISDIR(new_inode->i_mode);
iput(new_inode);
if (new_is_dir) {
PRINTK(("vfat_rename 7\n"));
res = vfat_rmdirx(new_dir,new_name,new_len);
PRINTK(("vfat_rename 8\n"));
if (res < 0) goto rename_done;
} else {
/* Is this the same file, different case? */
if (new_inode != old_inode) {
PRINTK(("vfat_rename 9\n"));
res = vfat_unlinkx(new_dir,new_name,new_len,1);
PRINTK(("vfat_rename 10\n"));
if (res < 0) goto rename_done;
}
}
}
 
PRINTK(("vfat_rename 11\n"));
fat_lock_creation(); locked = 1;
res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo);
 
PRINTK(("vfat_rename 12\n"));
if (res < 0) goto rename_done;
 
new_offset = sinfo.shortname_offset;
new_ino = sinfo.ino;
res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de);
PRINTK(("vfat_rename 13\n"));
if (res < 0) goto rename_done;
 
new_de->attr = old_de->attr;
new_de->time = old_de->time;
new_de->date = old_de->date;
new_de->ctime_ms = old_de->ctime_ms;
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;
PRINTK(("vfat_rename 14\n"));
 
/* At this point, we have the inodes of the old file and the
* new file. We need to transfer all information from the old
* inode to the new inode and then delete the slots of the old
* entry
*/
 
vfat_read_inode(new_inode);
MSDOS_I(old_inode)->i_busy = 1;
MSDOS_I(old_inode)->i_linked = new_inode;
MSDOS_I(new_inode)->i_oldlink = old_inode;
fat_cache_inval_inode(old_inode);
PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
old_inode->i_dirt = 1;
old_dir->i_version = ++event;
 
/* remove the old entry */
for (i = old_slots; i > 0; --i) {
res = fat_get_entry(old_dir, &old_longname_offset, &old_bh, &old_de);
if (res < 0) {
printk("vfat_unlinkx: problem 1\n");
continue;
}
old_de->name[0] = DELETED_FLAG;
old_de->attr = 0;
fat_mark_buffer_dirty(sb, old_bh, 1);
}
PRINTK(("vfat_rename 15b\n"));
 
fat_mark_buffer_dirty(sb, new_bh, 1);
dcache_add(new_dir, new_name, new_len, new_ino);
 
/* XXX: There is some code in the original MSDOS rename that
* is not duplicated here and it might cause a problem in
* certain circumstances.
*/
if (S_ISDIR(old_inode->i_mode)) {
if ((res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
&dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
fat_brelse(sb, dotdot_bh);
res = -EIO;
goto rename_done;
}
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);
dotdot_inode->i_dirt = 1;
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
new_dir->i_nlink++;
/* no need to mark them dirty */
dotdot_inode->i_nlink = new_dir->i_nlink;
iput(dotdot_inode);
fat_brelse(sb, dotdot_bh);
}
 
if (res > 0) res = 0;
 
rename_done:
if (locked)
fat_unlock_creation();
if (old_bh)
fat_brelse(sb, old_bh);
if (new_bh)
fat_brelse(sb, new_bh);
if (old_inode)
iput(old_inode);
iput(old_dir);
iput(new_dir);
return res;
}
 
 
 
/* Public inode operations for the VFAT fs */
struct inode_operations vfat_dir_inode_operations = {
&fat_dir_operations, /* default directory file-ops */
vfat_create, /* create */
vfat_lookup, /* lookup */
NULL, /* link */
vfat_unlink, /* unlink */
NULL, /* symlink */
vfat_mkdir, /* mkdir */
vfat_rmdir, /* rmdir */
NULL, /* mknod */
vfat_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
 
void vfat_read_inode(struct inode *inode)
{
fat_read_inode(inode, &vfat_dir_inode_operations);
}
 
#ifdef MODULE
int init_module(void)
{
return init_vfat_fs();
}
 
 
void cleanup_module(void)
{
unregister_filesystem(&vfat_fs_type);
}
 
#endif /* ifdef MODULE */
 
 
 
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 8
* c-brace-imaginary-offset: 0
* c-brace-offset: -8
* c-argdecl-indent: 8
* c-label-offset: -8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* End:
*/
/.depend
0,0 → 1,19
namei.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/module.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/msdos_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/nls.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/malloc.h \
../fat/msbuffer.h
vfatfs_syms.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/version.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/module.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/msdos_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_begin.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_end.h
/Makefile
0,0 → 1,15
#
# Makefile for the linux vfat-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
 
O_TARGET := vfat.o
O_OBJS := namei.o
OX_OBJS := vfatfs_syms.o
M_OBJS := $(O_TARGET)
 
include $(TOPDIR)/Rules.make

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.