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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [msdos/] [namei.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/fs/msdos/namei.c
 *  linux/fs/msdos/namei.c
 *
 *
 *  Written 1992,1993 by Werner Almesberger
 *  Written 1992,1993 by Werner Almesberger
 *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
 *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
 */
 */
 
 
#define __NO_VERSION__
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/module.h>
 
 
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/msdos_fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/stat.h>
 
 
#include <asm/segment.h>
#include <asm/segment.h>
 
 
#include "../fat/msbuffer.h"
#include "../fat/msbuffer.h"
 
 
#define PRINTK(x)
#define PRINTK(x)
 
 
 
 
/* MS-DOS "device special files" */
/* MS-DOS "device special files" */
 
 
static const char *reserved_names[] = {
static const 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 char bad_chars[] = "*?<>|\"";
static char bad_chars[] = "*?<>|\"";
static char bad_if_strict[] = "+=,; ";
static char bad_if_strict[] = "+=,; ";
 
 
 
 
void msdos_put_super(struct super_block *sb)
void msdos_put_super(struct super_block *sb)
{
{
        fat_put_super(sb);
        fat_put_super(sb);
        MOD_DEC_USE_COUNT;
        MOD_DEC_USE_COUNT;
}
}
 
 
struct super_operations msdos_sops = {
struct super_operations msdos_sops = {
        msdos_read_inode,
        msdos_read_inode,
        fat_notify_change,
        fat_notify_change,
        fat_write_inode,
        fat_write_inode,
        fat_put_inode,
        fat_put_inode,
        msdos_put_super,
        msdos_put_super,
        NULL, /* added in 0.96c */
        NULL, /* added in 0.96c */
        fat_statfs,
        fat_statfs,
        NULL
        NULL
};
};
 
 
struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
{
{
        struct super_block *res;
        struct super_block *res;
 
 
        MOD_INC_USE_COUNT;
        MOD_INC_USE_COUNT;
 
 
        MSDOS_SB(sb)->options.isvfat = 0;
        MSDOS_SB(sb)->options.isvfat = 0;
        sb->s_op = &msdos_sops;
        sb->s_op = &msdos_sops;
        res =  fat_read_super(sb, data, silent);
        res =  fat_read_super(sb, data, silent);
        if (res == NULL)
        if (res == NULL)
                MOD_DEC_USE_COUNT;
                MOD_DEC_USE_COUNT;
 
 
        return res;
        return res;
}
}
 
 
 
 
 
 
 
 
 
 
/***** Formats an MS-DOS file name. Rejects invalid names. */
/***** Formats an MS-DOS file name. Rejects invalid names. */
static int msdos_format_name(char conv,const char *name,int len,
static int msdos_format_name(char conv,const char *name,int len,
        char *res,int dot_dirs,char dotsOK)
        char *res,int dot_dirs,char dotsOK)
        /* conv is relaxed/normal/strict, name is proposed name,
        /* conv is relaxed/normal/strict, name is proposed name,
         * len is the length of the proposed name, res is the result name,
         * len is the length of the proposed name, res is the result name,
         * dot_dirs is . and .. are OK, dotsOK is if hidden files get dots.
         * dot_dirs is . and .. are OK, dotsOK is if hidden files get dots.
         */
         */
{
{
        char *walk;
        char *walk;
        const char **reserved;
        const char **reserved;
        unsigned char c;
        unsigned char c;
        int space;
        int space;
 
 
        if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
        if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
                if (!dot_dirs) return -EEXIST;
                if (!dot_dirs) return -EEXIST;
                memset(res+1,' ',10);
                memset(res+1,' ',10);
                while (len--) *res++ = '.';
                while (len--) *res++ = '.';
                return 0;
                return 0;
        }
        }
        if (name[0] == '.') {  /* dotfile because . and .. already done */
        if (name[0] == '.') {  /* dotfile because . and .. already done */
                if (!dotsOK) return -EINVAL;
                if (!dotsOK) return -EINVAL;
                /* Get rid of dot - test for it elsewhere */
                /* Get rid of dot - test for it elsewhere */
                name++; len--;
                name++; len--;
        }
        }
        space = 1; /* disallow names that _really_ start with a dot */
        space = 1; /* disallow names that _really_ start with a dot */
        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 (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
                if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
                if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
                if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
                if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
                if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
                if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
                if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
/*  0xE5 is legal as a first character, but we must substitute 0x05     */
/*  0xE5 is legal as a first character, but we must substitute 0x05     */
/*  because 0xE5 marks deleted files.  Yes, DOS really does this.       */
/*  because 0xE5 marks deleted files.  Yes, DOS really does this.       */
/*  It seems that Microsoft hacked DOS to support non-US characters     */
/*  It seems that Microsoft hacked DOS to support non-US characters     */
/*  after the 0xE5 character was already in use to mark deleted files.  */
/*  after the 0xE5 character was already in use to mark deleted files.  */
                if((res==walk) && (c==0xE5)) c=0x05;
                if((res==walk) && (c==0xE5)) c=0x05;
                if (c == '.') break;
                if (c == '.') break;
                space = (c == ' ');
                space = (c == ' ');
                *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
                *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
        }
        }
        if (space) return -EINVAL;
        if (space) return -EINVAL;
        if (conv == 's' && len && c != '.') {
        if (conv == '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) *walk++ = ' ';
                while (len > 0 && walk-res < MSDOS_NAME) {
                while (len > 0 && walk-res < MSDOS_NAME) {
                        c = *name++;
                        c = *name++;
                        len--;
                        len--;
                        if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
                        if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
                        if (conv == 's' && strchr(bad_if_strict,c))
                        if (conv == 's' && strchr(bad_if_strict,c))
                                return -EINVAL;
                                return -EINVAL;
                        if (c < ' ' || c == ':' || c == '\\' || c == '.')
                        if (c < ' ' || c == ':' || c == '\\' || c == '.')
                                return -EINVAL;
                                return -EINVAL;
                        if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
                        if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
                        space = c == ' ';
                        space = c == ' ';
                        *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
                        *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
                }
                }
                if (space) return -EINVAL;
                if (space) return -EINVAL;
                if (conv == 's' && len) return -EINVAL;
                if (conv == 's' && len) return -EINVAL;
        }
        }
        while (walk-res < MSDOS_NAME) *walk++ = ' ';
        while (walk-res < MSDOS_NAME) *walk++ = ' ';
        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;
}
}
 
 
 
 
/***** Locates a directory entry.  Uses unformatted name. */
/***** Locates a directory entry.  Uses unformatted name. */
static int msdos_find(struct inode *dir,const char *name,int len,
static int msdos_find(struct inode *dir,const char *name,int len,
    struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
    struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
{
{
        char msdos_name[MSDOS_NAME];
        char msdos_name[MSDOS_NAME];
        int res;
        int res;
        char dotsOK;
        char dotsOK;
        char scantype;
        char scantype;
 
 
        dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
        dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
        res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
        res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
                                name,len, msdos_name,1,dotsOK);
                                name,len, msdos_name,1,dotsOK);
        if (res < 0)
        if (res < 0)
                return -ENOENT;
                return -ENOENT;
        if((name[0]=='.') && dotsOK){
        if((name[0]=='.') && dotsOK){
            switch(len){
            switch(len){
                case  0: panic("Empty name in msdos_find!");
                case  0: panic("Empty name in msdos_find!");
                case  1: scantype = SCAN_ANY;                           break;
                case  1: scantype = SCAN_ANY;                           break;
                case  2: scantype = ((name[1]=='.')?SCAN_ANY:SCAN_HID); break;
                case  2: scantype = ((name[1]=='.')?SCAN_ANY:SCAN_HID); break;
                default: scantype = SCAN_HID;
                default: scantype = SCAN_HID;
            }
            }
        } else {
        } else {
            scantype = (dotsOK ? SCAN_NOTHID : SCAN_ANY);
            scantype = (dotsOK ? SCAN_NOTHID : SCAN_ANY);
        }
        }
        return fat_scan(dir,msdos_name,bh,de,ino,scantype);
        return fat_scan(dir,msdos_name,bh,de,ino,scantype);
}
}
 
 
/***** Get inode using directory and name */
/***** Get inode using directory and name */
int msdos_lookup(struct inode *dir,const char *name,int len,
int msdos_lookup(struct inode *dir,const char *name,int len,
    struct inode **result)
    struct inode **result)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        int ino,res;
        int ino,res;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct inode *next;
        struct inode *next;
 
 
        PRINTK (("msdos_lookup\n"));
        PRINTK (("msdos_lookup\n"));
 
 
        *result = NULL;
        *result = NULL;
        if (!dir) return -ENOENT;
        if (!dir) return -ENOENT;
        if (!S_ISDIR(dir->i_mode)) {
        if (!S_ISDIR(dir->i_mode)) {
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        PRINTK (("msdos_lookup 2\n"));
        PRINTK (("msdos_lookup 2\n"));
        if (len == 1 && name[0] == '.') {
        if (len == 1 && name[0] == '.') {
                *result = dir;
                *result = dir;
                return 0;
                return 0;
        }
        }
        if (len == 2 && name[0] == '.' && name[1] == '.') {
        if (len == 2 && name[0] == '.' && name[1] == '.') {
                ino = fat_parent_ino(dir,0);
                ino = fat_parent_ino(dir,0);
                iput(dir);
                iput(dir);
                if (ino < 0) return ino;
                if (ino < 0) return ino;
                if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
                if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
                return 0;
                return 0;
        }
        }
#if 0
#if 0
        if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) {
        if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) {
                iput(dir);
                iput(dir);
                if (!(*result = iget(dir->i_sb, ino)))
                if (!(*result = iget(dir->i_sb, ino)))
                        return -EACCES;
                        return -EACCES;
                return 0;
                return 0;
        }
        }
#endif
#endif
        PRINTK (("msdos_lookup 3\n"));
        PRINTK (("msdos_lookup 3\n"));
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
                iput(dir);
                iput(dir);
                return res;
                return res;
        }
        }
        PRINTK (("msdos_lookup 4\n"));
        PRINTK (("msdos_lookup 4\n"));
        if (bh)
        if (bh)
                fat_brelse(sb, bh);
                fat_brelse(sb, bh);
        PRINTK (("msdos_lookup 4.5\n"));
        PRINTK (("msdos_lookup 4.5\n"));
        if (!(*result = iget(dir->i_sb,ino))) {
        if (!(*result = iget(dir->i_sb,ino))) {
                iput(dir);
                iput(dir);
                return -EACCES;
                return -EACCES;
        }
        }
        PRINTK (("msdos_lookup 5\n"));
        PRINTK (("msdos_lookup 5\n"));
        if (!(*result)->i_sb ||
        if (!(*result)->i_sb ||
            ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
            ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
                /* crossed a mount point into a non-msdos fs */
                /* crossed a mount point into a non-msdos fs */
                iput(dir);
                iput(dir);
                return 0;
                return 0;
        }
        }
        if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
        if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
                iput(*result);
                iput(*result);
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        PRINTK (("msdos_lookup 6\n"));
        PRINTK (("msdos_lookup 6\n"));
        while (MSDOS_I(*result)->i_old) {
        while (MSDOS_I(*result)->i_old) {
                next = MSDOS_I(*result)->i_old;
                next = MSDOS_I(*result)->i_old;
                iput(*result);
                iput(*result);
                if (!(*result = iget(next->i_sb,next->i_ino))) {
                if (!(*result = iget(next->i_sb,next->i_ino))) {
                        fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
                        fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
                        iput(dir);
                        iput(dir);
                        return -ENOENT;
                        return -ENOENT;
                }
                }
        }
        }
        PRINTK (("msdos_lookup 7\n"));
        PRINTK (("msdos_lookup 7\n"));
        iput(dir);
        iput(dir);
        PRINTK (("msdos_lookup 8\n"));
        PRINTK (("msdos_lookup 8\n"));
        return 0;
        return 0;
}
}
 
 
 
 
/***** Creates a directory entry (name is already formatted). */
/***** Creates a directory entry (name is already formatted). */
static int msdos_create_entry(struct inode *dir, const char *name,int len,
static int msdos_create_entry(struct inode *dir, const char *name,int len,
    int is_dir, int is_hid, struct inode **result)
    int is_dir, int is_hid, struct inode **result)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        int res,ino;
        int res,ino;
 
 
        if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
        if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
                if (res != -ENOENT) return res;
                if (res != -ENOENT) return res;
                if ((dir->i_ino == MSDOS_ROOT_INO) &&
                if ((dir->i_ino == MSDOS_ROOT_INO) &&
                    (MSDOS_SB(sb)->fat_bits != 32))
                    (MSDOS_SB(sb)->fat_bits != 32))
                        return -ENOSPC;
                        return -ENOSPC;
                if ((res = fat_add_cluster(dir)) < 0) return res;
                if ((res = fat_add_cluster(dir)) < 0) return res;
                if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
                if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
        }
        }
        /*
        /*
         * XXX all times should be set by caller upon successful completion.
         * XXX all times should be set by caller upon successful completion.
         */
         */
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_dirt = 1;
        dir->i_dirt = 1;
        memcpy(de->name,name,MSDOS_NAME);
        memcpy(de->name,name,MSDOS_NAME);
        de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
        de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
        de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
        de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
        de->start = 0;
        de->start = 0;
        de->starthi = 0;
        de->starthi = 0;
        fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
        fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
        de->size = 0;
        de->size = 0;
        fat_mark_buffer_dirty(sb, bh, 1);
        fat_mark_buffer_dirty(sb, bh, 1);
        if ((*result = iget(dir->i_sb,ino)) != NULL)
        if ((*result = iget(dir->i_sb,ino)) != NULL)
                msdos_read_inode(*result);
                msdos_read_inode(*result);
        fat_brelse(sb, bh);
        fat_brelse(sb, bh);
        if (!*result) return -EIO;
        if (!*result) return -EIO;
        (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
        (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
            CURRENT_TIME;
            CURRENT_TIME;
        (*result)->i_dirt = 1;
        (*result)->i_dirt = 1;
        dcache_add(dir, name, len, ino);
        dcache_add(dir, name, len, ino);
        return 0;
        return 0;
}
}
 
 
/***** Create a file or directory */
/***** Create a file or directory */
int msdos_create(struct inode *dir,const char *name,int len,int mode,
int msdos_create(struct inode *dir,const char *name,int len,int mode,
        struct inode **result)
        struct inode **result)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        char msdos_name[MSDOS_NAME];
        char msdos_name[MSDOS_NAME];
        int ino,res,is_hid;
        int ino,res,is_hid;
 
 
        if (!dir) return -ENOENT;
        if (!dir) return -ENOENT;
        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
                                     name,len,msdos_name,0,
                                     name,len,msdos_name,0,
                                     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
                                     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
                iput(dir);
                iput(dir);
                return res;
                return res;
        }
        }
        is_hid = (name[0]=='.') && (msdos_name[0]!='.');
        is_hid = (name[0]=='.') && (msdos_name[0]!='.');
        fat_lock_creation();
        fat_lock_creation();
        /* Scan for existing file twice, so that creating a file fails
        /* Scan for existing file twice, so that creating a file fails
         * with -EINVAL if the other (dotfile/nondotfile) exists.
         * with -EINVAL if the other (dotfile/nondotfile) exists.
         * Else SCAN_ANY would do. Maybe use EACCES, EBUSY, ENOSPC, ENFILE?
         * Else SCAN_ANY would do. Maybe use EACCES, EBUSY, ENOSPC, ENFILE?
         */
         */
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
                fat_unlock_creation();
                fat_unlock_creation();
                fat_brelse(sb, bh);
                fat_brelse(sb, bh);
                iput(dir);
                iput(dir);
                return is_hid ? -EEXIST : -EINVAL;
                return is_hid ? -EEXIST : -EINVAL;
        }
        }
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
                fat_unlock_creation();
                fat_unlock_creation();
                fat_brelse(sb, bh);
                fat_brelse(sb, bh);
                iput(dir);
                iput(dir);
                return is_hid ? -EINVAL : -EEXIST;
                return is_hid ? -EINVAL : -EEXIST;
        }
        }
        res = msdos_create_entry(dir,msdos_name,len,S_ISDIR(mode),is_hid,
        res = msdos_create_entry(dir,msdos_name,len,S_ISDIR(mode),is_hid,
                                 result);
                                 result);
        fat_unlock_creation();
        fat_unlock_creation();
        iput(dir);
        iput(dir);
        return res;
        return res;
}
}
 
 
 
 
#ifdef DEBUG
#ifdef DEBUG
 
 
static void dump_fat(struct super_block *sb,int start)
static void dump_fat(struct super_block *sb,int start)
{
{
        printk("[");
        printk("[");
        while (start) {
        while (start) {
                printk("%d ",start);
                printk("%d ",start);
                start = fat_access(sb,start,-1);
                start = fat_access(sb,start,-1);
                if (!start) {
                if (!start) {
                        printk("ERROR");
                        printk("ERROR");
                        break;
                        break;
                }
                }
                if (start == -1) break;
                if (start == -1) break;
        }
        }
        printk("]\n");
        printk("]\n");
}
}
 
 
#endif
#endif
 
 
/***** See if directory is empty */
/***** See if directory is empty */
static int msdos_empty(struct inode *dir)
static int msdos_empty(struct inode *dir)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        loff_t pos;
        loff_t pos;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
 
 
        if (dir->i_count > 1)
        if (dir->i_count > 1)
                return -EBUSY;
                return -EBUSY;
        if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
        if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
                pos = 0;
                pos = 0;
                bh = NULL;
                bh = NULL;
                while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
                while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
                        /* Ignore vfat longname entries */
                        /* Ignore vfat longname entries */
                        if (de->attr == ATTR_EXT)
                        if (de->attr == ATTR_EXT)
                                continue;
                                continue;
                        if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
                        if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
                            MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
                            MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
                            MSDOS_NAME)) {
                            MSDOS_NAME)) {
                                fat_brelse(sb, bh);
                                fat_brelse(sb, bh);
                                return -ENOTEMPTY;
                                return -ENOTEMPTY;
                        }
                        }
                }
                }
                if (bh)
                if (bh)
                        fat_brelse(sb, bh);
                        fat_brelse(sb, bh);
        }
        }
        return 0;
        return 0;
}
}
 
 
/***** Remove a directory */
/***** Remove a directory */
int msdos_rmdir(struct inode *dir,const char *name,int len)
int msdos_rmdir(struct inode *dir,const char *name,int len)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        int res,ino;
        int res,ino;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        struct inode *inode;
        struct inode *inode;
 
 
        bh = NULL;
        bh = NULL;
        inode = NULL;
        inode = NULL;
        res = -EPERM;
        res = -EPERM;
        if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
        if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
                goto rmdir_done;
                goto rmdir_done;
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
        res = -ENOENT;
        res = -ENOENT;
        if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
        if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
        res = -ENOTDIR;
        res = -ENOTDIR;
        if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
        if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
        res = -EBUSY;
        res = -EBUSY;
        if (dir->i_dev != inode->i_dev || dir == inode)
        if (dir->i_dev != inode->i_dev || dir == inode)
          goto rmdir_done;
          goto rmdir_done;
        res = msdos_empty(inode);
        res = msdos_empty(inode);
        if (res)
        if (res)
                goto rmdir_done;
                goto rmdir_done;
        inode->i_nlink = 0;
        inode->i_nlink = 0;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        dir->i_nlink--;
        dir->i_nlink--;
        inode->i_dirt = dir->i_dirt = 1;
        inode->i_dirt = dir->i_dirt = 1;
        de->name[0] = DELETED_FLAG;
        de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, bh, 1);
        fat_mark_buffer_dirty(sb, bh, 1);
        res = 0;
        res = 0;
rmdir_done:
rmdir_done:
        fat_brelse(sb, bh);
        fat_brelse(sb, bh);
        iput(dir);
        iput(dir);
        iput(inode);
        iput(inode);
        return res;
        return res;
}
}
 
 
/***** Make a directory */
/***** Make a directory */
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        struct inode *inode,*dot;
        struct inode *inode,*dot;
        char msdos_name[MSDOS_NAME];
        char msdos_name[MSDOS_NAME];
        int ino,res,is_hid;
        int ino,res,is_hid;
 
 
        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
                                     name,len,msdos_name,0,
                                     name,len,msdos_name,0,
                                     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
                                     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
                iput(dir);
                iput(dir);
                return res;
                return res;
        }
        }
        is_hid = (name[0]=='.') && (msdos_name[0]!='.');
        is_hid = (name[0]=='.') && (msdos_name[0]!='.');
        fat_lock_creation();
        fat_lock_creation();
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) {
        if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) {
                fat_unlock_creation();
                fat_unlock_creation();
                fat_brelse(sb, bh);
                fat_brelse(sb, bh);
                iput(dir);
                iput(dir);
                return -EEXIST;
                return -EEXIST;
        }
        }
        if ((res = msdos_create_entry(dir,msdos_name,len,1,is_hid,
        if ((res = msdos_create_entry(dir,msdos_name,len,1,is_hid,
                                      &inode)) < 0) {
                                      &inode)) < 0) {
                fat_unlock_creation();
                fat_unlock_creation();
                iput(dir);
                iput(dir);
                return res;
                return res;
        }
        }
        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 */
        MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
        MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
        if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error;
        if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error;
        if ((res = msdos_create_entry(inode,MSDOS_DOT,1,1,0,&dot)) < 0)
        if ((res = msdos_create_entry(inode,MSDOS_DOT,1,1,0,&dot)) < 0)
                goto mkdir_error;
                goto mkdir_error;
        dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
        dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
        MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
        MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
        MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
        MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
        dot->i_nlink = inode->i_nlink;
        dot->i_nlink = inode->i_nlink;
        dot->i_dirt = 1;
        dot->i_dirt = 1;
        iput(dot);
        iput(dot);
        if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
        if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
                goto mkdir_error;
                goto mkdir_error;
        fat_unlock_creation();
        fat_unlock_creation();
        dot->i_size = dir->i_size;
        dot->i_size = dir->i_size;
        MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
        MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
        MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
        MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
        dot->i_nlink = dir->i_nlink;
        dot->i_nlink = dir->i_nlink;
        dot->i_dirt = 1;
        dot->i_dirt = 1;
        MSDOS_I(inode)->i_busy = 0;
        MSDOS_I(inode)->i_busy = 0;
        iput(dot);
        iput(dot);
        iput(inode);
        iput(inode);
        iput(dir);
        iput(dir);
        return 0;
        return 0;
mkdir_error:
mkdir_error:
        iput(inode);
        iput(inode);
        if (msdos_rmdir(dir,name,len) < 0)
        if (msdos_rmdir(dir,name,len) < 0)
                fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
                fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
        fat_unlock_creation();
        fat_unlock_creation();
        return res;
        return res;
}
}
 
 
/***** Unlink a file */
/***** Unlink a file */
static int msdos_unlinkx(
static int msdos_unlinkx(
        struct inode *dir,
        struct inode *dir,
        const char *name,
        const char *name,
        int len,
        int len,
        int nospc)      /* Flag special file ? */
        int nospc)      /* Flag special file ? */
{
{
        struct super_block *sb = dir->i_sb;
        struct super_block *sb = dir->i_sb;
        int res,ino;
        int res,ino;
        struct buffer_head *bh;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct msdos_dir_entry *de;
        struct inode *inode;
        struct inode *inode;
 
 
        bh = NULL;
        bh = NULL;
        inode = NULL;
        inode = NULL;
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
                goto unlink_done;
                goto unlink_done;
        if (!(inode = iget(dir->i_sb,ino))) {
        if (!(inode = iget(dir->i_sb,ino))) {
                res = -ENOENT;
                res = -ENOENT;
                goto unlink_done;
                goto unlink_done;
        }
        }
        if (!S_ISREG(inode->i_mode) && nospc){
        if (!S_ISREG(inode->i_mode) && nospc){
                res = -EPERM;
                res = -EPERM;
                goto unlink_done;
                goto unlink_done;
        }
        }
        if (IS_IMMUTABLE(inode)){
        if (IS_IMMUTABLE(inode)){
                res = -EPERM;
                res = -EPERM;
                goto unlink_done;
                goto unlink_done;
        }
        }
        inode->i_nlink = 0;
        inode->i_nlink = 0;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        MSDOS_I(inode)->i_busy = 1;
        MSDOS_I(inode)->i_busy = 1;
        inode->i_dirt = dir->i_dirt = 1;
        inode->i_dirt = dir->i_dirt = 1;
        de->name[0] = DELETED_FLAG;
        de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, bh, 1);
        fat_mark_buffer_dirty(sb, bh, 1);
unlink_done:
unlink_done:
        fat_brelse(sb, bh);
        fat_brelse(sb, bh);
        iput(inode);
        iput(inode);
        iput(dir);
        iput(dir);
        return res;
        return res;
}
}
 
 
/***** Unlink, as called for msdosfs */
/***** Unlink, as called for msdosfs */
int msdos_unlink(struct inode *dir,const char *name,int len)
int msdos_unlink(struct inode *dir,const char *name,int len)
{
{
        return msdos_unlinkx (dir,name,len,1);
        return msdos_unlinkx (dir,name,len,1);
}
}
 
 
/***** Unlink, as called for umsdosfs */
/***** Unlink, as called for umsdosfs */
int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
{
{
        return msdos_unlinkx (dir,name,len,0);
        return msdos_unlinkx (dir,name,len,0);
}
}
 
 
/***** Rename within a directory */
/***** Rename within a directory */
static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
    struct inode *new_dir,char *new_name,int new_len,
    struct inode *new_dir,char *new_name,int new_len,
    struct buffer_head *old_bh,
    struct buffer_head *old_bh,
    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
{
{
        struct super_block *sb = old_dir->i_sb;
        struct super_block *sb = old_dir->i_sb;
        struct buffer_head *new_bh;
        struct buffer_head *new_bh;
        struct msdos_dir_entry *new_de;
        struct msdos_dir_entry *new_de;
        struct inode *new_inode,*old_inode;
        struct inode *new_inode,*old_inode;
        int new_ino,exists,error;
        int new_ino,exists,error;
 
 
        if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid;
        if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid;
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
                if (exists)
                if (exists)
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (exists) {
        if (exists) {
                if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
                if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                        return -EIO;
                        return -EIO;
                }
                }
                error = S_ISDIR(new_inode->i_mode)
                error = S_ISDIR(new_inode->i_mode)
                        ? (old_de->attr & ATTR_DIR)
                        ? (old_de->attr & ATTR_DIR)
                                ? msdos_empty(new_inode)
                                ? msdos_empty(new_inode)
                                : -EPERM
                                : -EPERM
                        : (old_de->attr & ATTR_DIR)
                        : (old_de->attr & ATTR_DIR)
                                ? -EPERM
                                ? -EPERM
                                : 0;
                                : 0;
                if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
                if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
                if (error) {
                if (error) {
                        iput(new_inode);
                        iput(new_inode);
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                        return error;
                        return error;
                }
                }
                if (S_ISDIR(new_inode->i_mode)) {
                if (S_ISDIR(new_inode->i_mode)) {
                        new_dir->i_nlink--;
                        new_dir->i_nlink--;
                        new_dir->i_dirt = 1;
                        new_dir->i_dirt = 1;
                }
                }
                new_inode->i_nlink = 0;
                new_inode->i_nlink = 0;
                MSDOS_I(new_inode)->i_busy = 1;
                MSDOS_I(new_inode)->i_busy = 1;
                new_inode->i_dirt = 1;
                new_inode->i_dirt = 1;
                new_de->name[0] = DELETED_FLAG;
                new_de->name[0] = DELETED_FLAG;
                fat_mark_buffer_dirty(sb, new_bh, 1);
                fat_mark_buffer_dirty(sb, new_bh, 1);
                dcache_add(new_dir, new_name, new_len, new_ino);
                dcache_add(new_dir, new_name, new_len, new_ino);
                iput(new_inode);
                iput(new_inode);
                fat_brelse(sb, new_bh);
                fat_brelse(sb, new_bh);
        }
        }
        memcpy(old_de->name,new_name,MSDOS_NAME);
        memcpy(old_de->name,new_name,MSDOS_NAME);
set_hid:
set_hid:
        old_de->attr = is_hid
        old_de->attr = is_hid
                ? (old_de->attr | ATTR_HIDDEN)
                ? (old_de->attr | ATTR_HIDDEN)
                : (old_de->attr &~ ATTR_HIDDEN);
                : (old_de->attr &~ ATTR_HIDDEN);
        fat_mark_buffer_dirty(sb, old_bh, 1);
        fat_mark_buffer_dirty(sb, old_bh, 1);
        /* update binary info for conversion, i_attrs */
        /* update binary info for conversion, i_attrs */
        if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
        if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
                MSDOS_I(old_inode)->i_attrs = is_hid
                MSDOS_I(old_inode)->i_attrs = is_hid
                        ? (MSDOS_I(old_inode)->i_attrs |  ATTR_HIDDEN)
                        ? (MSDOS_I(old_inode)->i_attrs |  ATTR_HIDDEN)
                        : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
                        : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
                iput(old_inode);
                iput(old_inode);
        }
        }
        return 0;
        return 0;
}
}
 
 
/***** Rename across directories - a nonphysical move */
/***** Rename across directories - a nonphysical move */
static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
    struct inode *new_dir,char *new_name,int new_len,
    struct inode *new_dir,char *new_name,int new_len,
    struct buffer_head *old_bh,
    struct buffer_head *old_bh,
    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
{
{
        struct super_block *sb = old_dir->i_sb;
        struct super_block *sb = old_dir->i_sb;
        struct buffer_head *new_bh,*free_bh,*dotdot_bh;
        struct buffer_head *new_bh,*free_bh,*dotdot_bh;
        struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
        struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
        struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
        struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
        int new_ino,free_ino,dotdot_ino;
        int new_ino,free_ino,dotdot_ino;
        int error,exists,ino;
        int error,exists,ino;
 
 
        if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
        if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
        if (old_ino == new_dir->i_ino) return -EINVAL;
        if (old_ino == new_dir->i_ino) return -EINVAL;
        if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
        if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
        /* prevent moving directory below itself */
        /* prevent moving directory below itself */
        while (walk->i_ino != MSDOS_ROOT_INO) {
        while (walk->i_ino != MSDOS_ROOT_INO) {
                ino = fat_parent_ino(walk,1);
                ino = fat_parent_ino(walk,1);
                iput(walk);
                iput(walk);
                if (ino < 0) return ino;
                if (ino < 0) return ino;
                if (ino == old_ino) return -EINVAL;
                if (ino == old_ino) return -EINVAL;
                if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
                if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
        }
        }
        iput(walk);
        iput(walk);
        /* find free spot */
        /* find free spot */
        while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino,
        while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino,
            SCAN_ANY)) < 0) {
            SCAN_ANY)) < 0) {
                if (error != -ENOENT) return error;
                if (error != -ENOENT) return error;
                error = fat_add_cluster(new_dir);
                error = fat_add_cluster(new_dir);
                if (error) return error;
                if (error) return error;
        }
        }
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
        if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
        if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
                fat_brelse(sb, free_bh);
                fat_brelse(sb, free_bh);
                if (exists)
                if (exists)
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                return -EIO;
                return -EIO;
        }
        }
        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
                iput(old_inode);
                iput(old_inode);
                fat_brelse(sb, free_bh);
                fat_brelse(sb, free_bh);
                if (exists)
                if (exists)
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                return -ENOENT;
                return -ENOENT;
        }
        }
        new_inode = NULL; /* to make GCC happy */
        new_inode = NULL; /* to make GCC happy */
        if (exists) {  /* Trash the old file! */
        if (exists) {  /* Trash the old file! */
                if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
                if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
                        iput(old_inode);
                        iput(old_inode);
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                        return -EIO;
                        return -EIO;
                }
                }
                error = S_ISDIR(new_inode->i_mode)
                error = S_ISDIR(new_inode->i_mode)
                        ? (old_de->attr & ATTR_DIR)
                        ? (old_de->attr & ATTR_DIR)
                                ? msdos_empty(new_inode)
                                ? msdos_empty(new_inode)
                                : -EPERM
                                : -EPERM
                        : (old_de->attr & ATTR_DIR)
                        : (old_de->attr & ATTR_DIR)
                                ? -EPERM
                                ? -EPERM
                                : 0;
                                : 0;
                if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
                if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
                if (error) {
                if (error) {
                        iput(new_inode);
                        iput(new_inode);
                        iput(old_inode);
                        iput(old_inode);
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                        return error;
                        return error;
                }
                }
                new_inode->i_nlink = 0;
                new_inode->i_nlink = 0;
                MSDOS_I(new_inode)->i_busy = 1;
                MSDOS_I(new_inode)->i_busy = 1;
                new_inode->i_dirt = 1;
                new_inode->i_dirt = 1;
                new_de->name[0] = DELETED_FLAG;
                new_de->name[0] = DELETED_FLAG;
                fat_mark_buffer_dirty(sb, new_bh, 1);
                fat_mark_buffer_dirty(sb, new_bh, 1);
        }
        }
        memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
        memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
        memcpy(free_de->name,new_name,MSDOS_NAME);
        memcpy(free_de->name,new_name,MSDOS_NAME);
        free_de->attr = is_hid
        free_de->attr = is_hid
                ? (free_de->attr|ATTR_HIDDEN)
                ? (free_de->attr|ATTR_HIDDEN)
                : (free_de->attr&~ATTR_HIDDEN);
                : (free_de->attr&~ATTR_HIDDEN);
        if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
        if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
                free_de->name[0] = DELETED_FLAG;
                free_de->name[0] = DELETED_FLAG;
/*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
/*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
                fat_brelse(sb, free_bh);
                fat_brelse(sb, free_bh);
                if (exists) {
                if (exists) {
                        iput(new_inode);
                        iput(new_inode);
                        fat_brelse(sb, new_bh);
                        fat_brelse(sb, new_bh);
                }
                }
                return -EIO;
                return -EIO;
        }
        }
        if (exists && S_ISDIR(new_inode->i_mode)) {
        if (exists && S_ISDIR(new_inode->i_mode)) {
                new_dir->i_nlink--;
                new_dir->i_nlink--;
                new_dir->i_dirt = 1;
                new_dir->i_dirt = 1;
        }
        }
        msdos_read_inode(free_inode);
        msdos_read_inode(free_inode);
        MSDOS_I(old_inode)->i_busy = 1;
        MSDOS_I(old_inode)->i_busy = 1;
        MSDOS_I(old_inode)->i_linked = free_inode;
        MSDOS_I(old_inode)->i_linked = free_inode;
        MSDOS_I(free_inode)->i_oldlink = old_inode;
        MSDOS_I(free_inode)->i_oldlink = old_inode;
        fat_cache_inval_inode(old_inode);
        fat_cache_inval_inode(old_inode);
        old_inode->i_dirt = 1;
        old_inode->i_dirt = 1;
        old_de->name[0] = DELETED_FLAG;
        old_de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, old_bh, 1);
        fat_mark_buffer_dirty(sb, old_bh, 1);
        fat_mark_buffer_dirty(sb, free_bh, 1);
        fat_mark_buffer_dirty(sb, free_bh, 1);
        if (exists) {
        if (exists) {
                MSDOS_I(new_inode)->i_depend = free_inode;
                MSDOS_I(new_inode)->i_depend = free_inode;
                MSDOS_I(free_inode)->i_old = new_inode;
                MSDOS_I(free_inode)->i_old = new_inode;
                /* Two references now exist to free_inode so increase count */
                /* Two references now exist to free_inode so increase count */
                free_inode->i_count++;
                free_inode->i_count++;
                /* free_inode is put after putting new_inode and old_inode */
                /* free_inode is put after putting new_inode and old_inode */
                iput(new_inode);
                iput(new_inode);
                dcache_add(new_dir, new_name, new_len, new_ino);
                dcache_add(new_dir, new_name, new_len, new_ino);
                fat_brelse(sb, new_bh);
                fat_brelse(sb, new_bh);
        }
        }
        if (S_ISDIR(old_inode->i_mode)) {
        if (S_ISDIR(old_inode->i_mode)) {
                if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
                if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
                    &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
                    &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
                if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
                if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
                        fat_brelse(sb, dotdot_bh);
                        fat_brelse(sb, dotdot_bh);
                        error = -EIO;
                        error = -EIO;
                        goto rename_done;
                        goto rename_done;
                }
                }
                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;
                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->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
                dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
                dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
                dotdot_inode->i_dirt = 1;
                dotdot_inode->i_dirt = 1;
                fat_mark_buffer_dirty(sb, dotdot_bh, 1);
                fat_mark_buffer_dirty(sb, dotdot_bh, 1);
                old_dir->i_nlink--;
                old_dir->i_nlink--;
                new_dir->i_nlink++;
                new_dir->i_nlink++;
                /* no need to mark them dirty */
                /* no need to mark them dirty */
                dotdot_inode->i_nlink = new_dir->i_nlink;
                dotdot_inode->i_nlink = new_dir->i_nlink;
                iput(dotdot_inode);
                iput(dotdot_inode);
                fat_brelse(sb, dotdot_bh);
                fat_brelse(sb, dotdot_bh);
        }
        }
        error = 0;
        error = 0;
rename_done:
rename_done:
        fat_brelse(sb, free_bh);
        fat_brelse(sb, free_bh);
        iput(old_inode);
        iput(old_inode);
        return error;
        return error;
}
}
 
 
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
        struct inode *new_dir,const char *new_name,int new_len,
        struct inode *new_dir,const char *new_name,int new_len,
        int must_be_dir)
        int must_be_dir)
{
{
        struct super_block *sb = old_dir->i_sb;
        struct super_block *sb = old_dir->i_sb;
        char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
        char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
        struct buffer_head *old_bh;
        struct buffer_head *old_bh;
        struct msdos_dir_entry *old_de;
        struct msdos_dir_entry *old_de;
        int old_ino,error;
        int old_ino,error;
        int is_hid,old_hid; /* if new file and old file are hidden */
        int is_hid,old_hid; /* if new file and old file are hidden */
 
 
        if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check,
        if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check,
                                       old_name,old_len,old_msdos_name,1,
                                       old_name,old_len,old_msdos_name,1,
                                       MSDOS_SB(old_dir->i_sb)->options.dotsOK))
                                       MSDOS_SB(old_dir->i_sb)->options.dotsOK))
            < 0) goto rename_done;
            < 0) goto rename_done;
        if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check,
        if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check,
                                       new_name,new_len,new_msdos_name,0,
                                       new_name,new_len,new_msdos_name,0,
                                       MSDOS_SB(new_dir->i_sb)->options.dotsOK))
                                       MSDOS_SB(new_dir->i_sb)->options.dotsOK))
            < 0) goto rename_done;
            < 0) goto rename_done;
        is_hid = (new_name[0]=='.') && (new_msdos_name[0]!='.');
        is_hid = (new_name[0]=='.') && (new_msdos_name[0]!='.');
        old_hid = (old_name[0]=='.') && (old_msdos_name[0]!='.');
        old_hid = (old_name[0]=='.') && (old_msdos_name[0]!='.');
        if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de,
        if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de,
            &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done;
            &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done;
        fat_lock_creation();
        fat_lock_creation();
        if (old_dir == new_dir)
        if (old_dir == new_dir)
                error = rename_same_dir(old_dir,old_msdos_name,old_len,new_dir,
                error = rename_same_dir(old_dir,old_msdos_name,old_len,new_dir,
                    new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
                    new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
        else error = rename_diff_dir(old_dir,old_msdos_name,old_len,new_dir,
        else error = rename_diff_dir(old_dir,old_msdos_name,old_len,new_dir,
                    new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
                    new_msdos_name,new_len,old_bh,old_de,old_ino,is_hid);
        fat_unlock_creation();
        fat_unlock_creation();
        fat_brelse(sb, old_bh);
        fat_brelse(sb, old_bh);
rename_done:
rename_done:
        iput(old_dir);
        iput(old_dir);
        iput(new_dir);
        iput(new_dir);
        return error;
        return error;
}
}
 
 
 
 
/* The public inode operations for the msdos fs */
/* The public inode operations for the msdos fs */
struct inode_operations msdos_dir_inode_operations = {
struct inode_operations msdos_dir_inode_operations = {
        &fat_dir_operations,    /* default directory file-ops */
        &fat_dir_operations,    /* default directory file-ops */
        msdos_create,           /* create */
        msdos_create,           /* create */
        msdos_lookup,           /* lookup */
        msdos_lookup,           /* lookup */
        NULL,                   /* link */
        NULL,                   /* link */
        msdos_unlink,           /* unlink */
        msdos_unlink,           /* unlink */
        NULL,                   /* symlink */
        NULL,                   /* symlink */
        msdos_mkdir,            /* mkdir */
        msdos_mkdir,            /* mkdir */
        msdos_rmdir,            /* rmdir */
        msdos_rmdir,            /* rmdir */
        NULL,                   /* mknod */
        NULL,                   /* mknod */
        msdos_rename,           /* rename */
        msdos_rename,           /* rename */
        NULL,                   /* readlink */
        NULL,                   /* readlink */
        NULL,                   /* follow_link */
        NULL,                   /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* writepage */
        fat_bmap,               /* bmap */
        fat_bmap,               /* bmap */
        NULL,                   /* truncate */
        NULL,                   /* truncate */
        NULL                    /* permission */
        NULL                    /* permission */
};
};
 
 
 
 
void msdos_read_inode(struct inode *inode)
void msdos_read_inode(struct inode *inode)
{
{
        fat_read_inode(inode, &msdos_dir_inode_operations);
        fat_read_inode(inode, &msdos_dir_inode_operations);
}
}
 
 
 
 
 
 
#ifdef MODULE
#ifdef MODULE
int init_module(void)
int init_module(void)
{
{
        return init_msdos_fs();
        return init_msdos_fs();
}
}
 
 
 
 
void cleanup_module(void)
void cleanup_module(void)
{
{
        unregister_filesystem(&msdos_fs_type);
        unregister_filesystem(&msdos_fs_type);
}
}
 
 
#endif
#endif
 
 
 
 

powered by: WebSVN 2.1.0

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