diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
commit | 230e5ab6a084ed50470f101934782dbf54b0d06b (patch) | |
tree | 5dd821c8d33f450470588e7a543f74bf74306e9e /fs/fat | |
parent | c9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff) |
Merge with Linux 2.1.67.
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/buffer.c | 18 | ||||
-rw-r--r-- | fs/fat/cache.c | 49 | ||||
-rw-r--r-- | fs/fat/dir.c | 69 | ||||
-rw-r--r-- | fs/fat/fatfs_syms.c | 9 | ||||
-rw-r--r-- | fs/fat/file.c | 59 | ||||
-rw-r--r-- | fs/fat/inode.c | 490 | ||||
-rw-r--r-- | fs/fat/misc.c | 81 | ||||
-rw-r--r-- | fs/fat/mmap.c | 7 | ||||
-rw-r--r-- | fs/fat/tables.c | 212 |
9 files changed, 562 insertions, 432 deletions
diff --git a/fs/fat/buffer.c b/fs/fat/buffer.c index 2a6fc6b74..4c827711d 100644 --- a/fs/fat/buffer.c +++ b/fs/fat/buffer.c @@ -10,22 +10,31 @@ #include <linux/fs.h> #include <linux/msdos_fs.h> +#if 0 +# define PRINTK(x) printk x +#else +# define PRINTK(x) +#endif + struct buffer_head *fat_bread ( struct super_block *sb, int block) { struct buffer_head *ret = NULL; - /* Note that the blocksize is 512, 1024 or 2048, but the first read - is always of size 1024 (or 2048). Doing readahead may be counterproductive - or just plain wrong. */ + PRINTK(("fat_bread: block=0x%x\n", block)); + /* + * Note that the blocksize is 512, 1024 or 2048, but the first read + * is always of size 1024 (or 2048). Doing readahead may be + * counterproductive or just plain wrong. + */ if (sb->s_blocksize == 512) { ret = bread (sb->s_dev,block,512); } else { struct buffer_head *real; if (sb->s_blocksize == 1024){ real = bread (sb->s_dev,block>>1,1024); - }else{ + } else { real = bread (sb->s_dev,block>>2,2048); } @@ -82,6 +91,7 @@ struct buffer_head *fat_getblk ( int block) { struct buffer_head *ret = NULL; + PRINTK(("fat_getblk: block=0x%x\n", block)); if (sb->s_blocksize == 512){ ret = getblk (sb->s_dev,block,512); }else{ diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 5fdcb772e..ece255ca1 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -12,6 +12,11 @@ #include "msbuffer.h" +#if 0 +# define PRINTK(x) printk x +#else +# define PRINTK(x) +#endif static struct fat_cache *fat_cache,cache[FAT_CACHE]; @@ -22,11 +27,13 @@ int fat_access(struct super_block *sb,int nr,int new_value) { struct buffer_head *bh,*bh2,*c_bh,*c_bh2; unsigned char *p_first,*p_last; - int first,last,next,copy,b; + int copy,first,last,next,b; if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; - if (MSDOS_SB(sb)->fat_bits == 16) { + if (MSDOS_SB(sb)->fat_bits == 32) { + first = last = nr*4; + } else if (MSDOS_SB(sb)->fat_bits == 16) { first = last = nr*2; } else { first = nr*3/2; @@ -46,13 +53,19 @@ int fat_access(struct super_block *sb,int nr,int new_value) return 0; } } - if (MSDOS_SB(sb)->fat_bits == 16) { + if (MSDOS_SB(sb)->fat_bits == 32) { + p_first = p_last = NULL; /* GCC needs that stuff */ + next = CF_LE_L(((unsigned long *) bh->b_data)[(first & + (SECTOR_SIZE-1)) >> 2]); + if (next >= 0xffffff7) next = -1; + PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%d\n", b, nr, first, next)); + + } else if (MSDOS_SB(sb)->fat_bits == 16) { p_first = p_last = NULL; /* GCC needs that stuff */ next = CF_LE_W(((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >> 1]); if (next >= 0xfff7) next = -1; - } - else { + } else { p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)]; p_last = &((unsigned char *) bh2->b_data)[(first+1) & (SECTOR_SIZE-1)]; @@ -61,10 +74,13 @@ int fat_access(struct super_block *sb,int nr,int new_value) if (next >= 0xff7) next = -1; } if (new_value != -1) { - if (MSDOS_SB(sb)->fat_bits == 16) + if (MSDOS_SB(sb)->fat_bits == 32) { + ((unsigned long *) bh->b_data)[(first & (SECTOR_SIZE-1)) >> + 2] = CT_LE_L(new_value); + } else if (MSDOS_SB(sb)->fat_bits == 16) { ((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >> 1] = CT_LE_W(new_value); - else { + } else { if (nr & 1) { *p_first = (*p_first & 0xf) | (new_value << 4); *p_last = new_value >> 4; @@ -172,7 +188,8 @@ printk("cache add: <%s,%d> %d (%d)\n", kdevname(inode->i_dev), && walk->ino == inode->i_ino && walk->file_cluster == f_clu) { if (walk->disk_cluster != d_clu) { - printk("FAT cache corruption"); + printk("FAT cache corruption inode=%ld\n", + inode->i_ino); fat_cache_inval_inode(inode); return; } @@ -239,16 +256,17 @@ int get_cluster(struct inode *inode,int cluster) return nr; } - int fat_smap(struct inode *inode,int sector) { struct msdos_sb_info *sb; int cluster,offset; sb = MSDOS_SB(inode->i_sb); - if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && - !MSDOS_I(inode)->i_start)) { - if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0; + if ((sb->fat_bits != 32) && + (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && + !MSDOS_I(inode)->i_start))) { + if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) + return 0; return sector+sb->dir_start; } cluster = sector/sb->cluster_size; @@ -279,6 +297,7 @@ int fat_free(struct inode *inode,int skip) fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb)); else { MSDOS_I(inode)->i_start = 0; + MSDOS_I(inode)->i_logstart = 0; mark_inode_dirty(inode); } lock_fat(inode->i_sb); @@ -287,8 +306,12 @@ int fat_free(struct inode *inode,int skip) fat_fs_panic(inode->i_sb,"fat_free: deleting beyond EOF"); break; } - if (MSDOS_SB(inode->i_sb)->free_clusters != -1) + if (MSDOS_SB(inode->i_sb)->free_clusters != -1) { MSDOS_SB(inode->i_sb)->free_clusters++; + if (MSDOS_SB(inode->i_sb)->fat_bits == 32) { + fat_clusters_flush(inode->i_sb); + } + } inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size; } unlock_fat(inode->i_sb); diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 494f7781b..7568f876a 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -11,8 +11,12 @@ * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk> */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) + +#include <linux/version.h> #include <linux/fs.h> #include <linux/msdos_fs.h> +#include <linux/nls.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/stat.h> @@ -24,13 +28,11 @@ #include <asm/uaccess.h> #include "msbuffer.h" -#include "tables.h" - #define PRINTK(X) -static long fat_dir_read(struct inode * inode,struct file * filp, - char * buf, unsigned long count) +static ssize_t fat_dir_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) { return -EISDIR; } @@ -40,7 +42,7 @@ struct file_operations fat_dir_operations = { fat_dir_read, /* read */ NULL, /* write - bad */ fat_readdir, /* readdir */ - NULL, /* poll - default */ + NULL, /* select v2.0.x/poll v2.1.x - default */ fat_dir_ioctl, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -48,7 +50,9 @@ struct file_operations fat_dir_operations = { file_fsync /* fsync */ }; -/* Convert Unicode string to ASCII. If uni_xlate is enabled and we +/* + * Convert Unicode 16 to UTF8, translated unicode, or ascii. + * If uni_xlate is enabled and we * can't get a 1:1 conversion, use a colon as an escape character since * it is normally invalid on the vfat filesystem. The following three * characters are a sort of uuencoded 16 bit Unicode value. This lets @@ -56,10 +60,11 @@ struct file_operations fat_dir_operations = { * into some trouble with long Unicode names, but ignore that right now. */ static int -uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate) +uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate, + struct nls_table *nls) { unsigned char *ip, *op; - unsigned char page, pg_off; + unsigned char ch, cl; unsigned char *uni_page; unsigned short val; @@ -67,21 +72,21 @@ uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate) op = ascii; while (*ip || ip[1]) { - pg_off = *ip++; - page = *ip++; - - uni_page = fat_uni2asc_pg[page]; - if (uni_page && uni_page[pg_off]) { - *op++ = uni_page[pg_off]; + cl = *ip++; + ch = *ip++; + + uni_page = nls->page_uni2charset[ch]; + if (uni_page && uni_page[cl]) { + *op++ = uni_page[cl]; } else { if (uni_xlate == 1) { *op++ = ':'; - val = (pg_off << 8) + page; - op[2] = fat_uni2code[val & 0x3f]; + val = (cl << 8) + ch; + op[2] = fat_uni2esc[val & 0x3f]; val >>= 6; - op[1] = fat_uni2code[val & 0x3f]; + op[1] = fat_uni2esc[val & 0x3f]; val >>= 6; - *op = fat_uni2code[val & 0x3f]; + *op = fat_uni2esc[val & 0x3f]; op += 3; } else { *op++ = '?'; @@ -92,6 +97,19 @@ uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate) return (op - ascii); } +#if 0 +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 int fat_readdirx( struct inode *inode, struct file *filp, @@ -115,7 +133,9 @@ int fat_readdirx( unsigned char alias_checksum = 0; /* Make compiler warning go away */ unsigned char long_slots = 0; int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; + int utf8 = MSDOS_SB(sb)->options.utf8; unsigned char *unicode = NULL; + struct nls_table *nls = MSDOS_SB(sb)->nls_io; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; @@ -138,6 +158,9 @@ int fat_readdirx( is_long = 0; ino = fat_get_entry(inode,&filp->f_pos,&bh,&de); while (ino > -1) { +#if 0 + dump_de(de); +#endif /* Check for long filename entry */ if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) { is_long = 0; @@ -217,7 +240,6 @@ int fat_readdirx( if (is_long) { unsigned char sum; - long_len = uni2ascii(unicode, longname, uni_xlate); for (sum = 0, i = 0; i < 11; i++) { sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; } @@ -226,6 +248,11 @@ int fat_readdirx( PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum)); is_long = 0; } + if (utf8) { + long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname)); + } else { + long_len = uni16_to_x8(longname, unicode, uni_xlate, nls); + } } if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) { @@ -390,7 +417,7 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, switch (cmd) { case VFAT_IOCTL_READDIR_BOTH: { struct dirent *d1 = (struct dirent *)arg; - err = verify_area(VERIFY_WRITE, d1, sizeof (*d1)); + err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); if (err) return err; put_user(0, &d1->d_reclen); @@ -400,7 +427,7 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, case VFAT_IOCTL_READDIR_SHORT: { struct dirent *d1 = (struct dirent *)arg; put_user(0, &d1->d_reclen); - err = verify_area(VERIFY_WRITE, d1, sizeof (*d1)); + err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); if (err) return err; return fat_readdirx(inode,filp,(void *)arg, diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c index c7ec96030..60e71ed98 100644 --- a/fs/fat/fatfs_syms.c +++ b/fs/fat/fatfs_syms.c @@ -4,6 +4,8 @@ * Exported kernel symbols for the low-level FAT-based fs support. * */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#include <linux/version.h> #include <linux/config.h> #include <linux/module.h> @@ -15,16 +17,14 @@ extern struct file_operations fat_dir_operations; -EXPORT_SYMBOL(fat_a2alias); -EXPORT_SYMBOL(fat_a2uni); EXPORT_SYMBOL(fat_add_cluster); EXPORT_SYMBOL(fat_bmap); EXPORT_SYMBOL(fat_brelse); EXPORT_SYMBOL(fat_cache_inval_inode); -EXPORT_SYMBOL(fat_code2uni); EXPORT_SYMBOL(fat_date_unix2dos); EXPORT_SYMBOL(fat_delete_inode); EXPORT_SYMBOL(fat_dir_operations); +EXPORT_SYMBOL(fat_esc2uni); EXPORT_SYMBOL(fat_file_read); EXPORT_SYMBOL(fat_file_write); EXPORT_SYMBOL(fat_fs_panic); @@ -44,8 +44,7 @@ EXPORT_SYMBOL(fat_scan); EXPORT_SYMBOL(fat_smap); EXPORT_SYMBOL(fat_statfs); EXPORT_SYMBOL(fat_truncate); -EXPORT_SYMBOL(fat_uni2asc_pg); -EXPORT_SYMBOL(fat_uni2code); +EXPORT_SYMBOL(fat_uni2esc); EXPORT_SYMBOL(fat_unlock_creation); EXPORT_SYMBOL(fat_write_inode); diff --git a/fs/fat/file.c b/fs/fat/file.c index ca35cc28f..f3a4f6cec 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -6,6 +6,8 @@ * regular file handling primitives for fat-based filesystems */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#include <linux/version.h> #include <linux/sched.h> #include <linux/locks.h> #include <linux/fs.h> @@ -32,7 +34,7 @@ static struct file_operations fat_file_operations = { fat_file_read, /* read */ fat_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* poll - default */ + NULL, /* select v2.0.x/poll v2.1.x - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ @@ -60,6 +62,7 @@ struct inode_operations fat_file_inode_operations = { NULL, /* permission */ NULL /* smap */ }; + /* #Specification: msdos / special devices / mmap Mmapping does work because a special mmap is provide in that case. Note that it is much less efficient than the generic_file_mmap normally @@ -71,7 +74,7 @@ static struct file_operations fat_file_operations_1024 = { fat_file_read, /* read */ fat_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* poll - default */ + NULL, /* select v2.0.x/poll v2.1.x - default */ NULL, /* ioctl - default */ fat_mmap, /* mmap */ NULL, /* no special open is needed */ @@ -152,12 +155,13 @@ static void fat_prefetch ( /* Read a file into user space */ -long fat_file_read( - struct inode *inode, +ssize_t fat_file_read( struct file *filp, char *buf, - unsigned long count) + size_t count, + loff_t *ppos) { + struct inode *inode = filp->f_dentry->d_inode; struct super_block *sb = inode->i_sb; char *start = buf; char *end = buf + count; @@ -175,7 +179,7 @@ long fat_file_read( printk("fat_file_read: mode = %07o\n",inode->i_mode); return -EINVAL; } - if (filp->f_pos >= inode->i_size || count == 0) return 0; + if (*ppos >= inode->i_size || count == 0) return 0; /* Tell the buffer cache which block we expect to read in advance Since we are limited with the stack, we preread only MSDOS_PREFETCH @@ -185,15 +189,15 @@ long fat_file_read( Each time we process one block in bhlist, we replace it by a new prefetch block if needed. */ - PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count)); + PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count)); { /* We must prefetch complete block, so we must take in account the offset in the first block. */ - int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count; + int count_max = (*ppos & (SECTOR_SIZE-1)) + count; int to_reada; /* How many block to read all at once */ - pre.file_sector = filp->f_pos >> SECTOR_BITS; + pre.file_sector = *ppos >> SECTOR_BITS; to_reada = count_max / SECTOR_SIZE; if (count_max & (SECTOR_SIZE-1)) to_reada++; if (filp->f_reada || !MSDOS_I(inode)->i_binary){ @@ -211,7 +215,7 @@ long fat_file_read( } pre.nolist = 0; PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist)); - while ((left_in_file = inode->i_size - filp->f_pos) > 0 + while ((left_in_file = inode->i_size - *ppos) > 0 && buf < end){ struct buffer_head *bh = pre.bhlist[pre.nolist]; char *data; @@ -226,27 +230,27 @@ long fat_file_read( fat_prefetch (inode,&pre,MSDOS_PREFETCH/2); pre.nolist = 0; } - PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count)); + PRINTK (("file_read pos %ld nblist %d %d %d\n",*ppos,pre.nblist,pre.fetched,count)); wait_on_buffer(bh); if (!fat_is_uptodate(sb,bh)){ /* read error ? */ fat_brelse (sb, bh); break; } - offset = filp->f_pos & (SECTOR_SIZE-1); + offset = *ppos & (SECTOR_SIZE-1); data = bh->b_data + offset; size = MIN(SECTOR_SIZE-offset,left_in_file); if (MSDOS_I(inode)->i_binary) { size = MIN(size,end-buf); copy_to_user(buf,data,size); buf += size; - filp->f_pos += size; + *ppos += size; }else{ for (; size && buf < end; size--) { char ch = *data++; - filp->f_pos++; + ++*ppos; if (ch == 26){ - filp->f_pos = inode->i_size; + *ppos = inode->i_size; break; }else if (ch != '\r'){ put_user(ch,buf++); @@ -269,12 +273,13 @@ long fat_file_read( /* Write to a file either from user space */ -long fat_file_write( - struct inode *inode, +ssize_t fat_file_write( struct file *filp, const char *buf, - unsigned long count) + size_t count, + loff_t *ppos) { + struct inode *inode = filp->f_dentry->d_inode; struct super_block *sb = inode->i_sb; int sector,offset,size,left,written; int error,carry; @@ -300,23 +305,23 @@ long fat_file_write( * but so what. That way leads to madness anyway. */ if (filp->f_flags & O_APPEND) - filp->f_pos = inode->i_size; + *ppos = inode->i_size; if (count == 0) return 0; error = carry = 0; for (start = buf; count || carry; count -= size) { - while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS))) + while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS))) if ((error = fat_add_cluster(inode)) < 0) break; if (error) { fat_truncate(inode); break; } - offset = filp->f_pos & (SECTOR_SIZE-1); + offset = *ppos & (SECTOR_SIZE-1); size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); if (binary_mode && offset == 0 && (size == SECTOR_SIZE - || filp->f_pos + size >= inode->i_size)){ + || *ppos + size >= inode->i_size)){ /* No need to read the block first since we will */ /* completely overwrite it */ /* or at least write past the end of file */ @@ -333,7 +338,7 @@ long fat_file_write( buf += size; } else { written = left = SECTOR_SIZE-offset; - to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1)); + to = (char *) bh->b_data+(*ppos & (SECTOR_SIZE-1)); if (carry) { *to++ = '\n'; left--; @@ -353,10 +358,10 @@ long fat_file_write( } written -= left; } - update_vm_cache(inode, filp->f_pos, bh->b_data + (filp->f_pos & (SECTOR_SIZE-1)), written); - filp->f_pos += written; - if (filp->f_pos > inode->i_size) { - inode->i_size = filp->f_pos; + update_vm_cache(inode, *ppos, bh->b_data + (*ppos & (SECTOR_SIZE-1)), written); + *ppos += written; + if (*ppos > inode->i_size) { + inode->i_size = *ppos; mark_inode_dirty(inode); } fat_set_uptodate(sb, bh, 1); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 8ffd91e3d..732d0b9ba 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -5,10 +5,12 @@ * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner */ +#include <linux/version.h> #define __NO_VERSION__ #include <linux/module.h> #include <linux/msdos_fs.h> +#include <linux/nls.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> @@ -18,76 +20,137 @@ #include <linux/fs.h> #include <linux/stat.h> #include <linux/locks.h> +#include <linux/malloc.h> #include "msbuffer.h" -#include "tables.h" #include <asm/uaccess.h> #include <asm/unaligned.h> +/* #define FAT_PARANOIA 1 */ +#ifdef FAT_DEBUG +# define PRINTK(x) printk x +#else +# define PRINTK(x) +#endif - -void fat_put_inode(struct inode *inode) -{ - struct inode *depend, *linked; - struct super_block *sb; - - depend = MSDOS_I(inode)->i_depend; - linked = MSDOS_I(inode)->i_linked; - sb = inode->i_sb; - if (inode->i_nlink) { - if (depend) { - iput(depend); - } - if (linked) { - iput(linked); - MSDOS_I(inode)->i_linked = NULL; - } - if (MSDOS_I(inode)->i_busy) fat_cache_inval_inode(inode); - } -} - -void fat_delete_inode(struct inode *inode) +/* + * Free any dependent inodes at the (effective) last use. + */ +static int fat_free_links(struct inode *inode) { - struct inode *depend, *linked; - struct super_block *sb; + struct inode *depend, *linked, *old_inode; + int success = 0; + /* + * Clear the fields first to avoid races + */ depend = MSDOS_I(inode)->i_depend; + MSDOS_I(inode)->i_depend = NULL; linked = MSDOS_I(inode)->i_linked; - sb = inode->i_sb; + MSDOS_I(inode)->i_linked = NULL; - inode->i_size = 0; - fat_truncate(inode); if (depend) { - if (MSDOS_I(depend)->i_old != inode) { - printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n", - depend, inode, MSDOS_I(depend)->i_old); - fat_fs_panic(sb,"..."); - goto done; +#ifdef FAT_PARANOIA +printk("fat_put_inode: depend inode is %ld, i_count=%d\n", +depend->i_ino, depend->i_count); +#endif + old_inode = MSDOS_I(depend)->i_old; + if (old_inode != inode) { + printk("fat_free_link: Invalid depend for inode %ld: " + "expected 0x%p, got 0x%p\n", + depend->i_ino, inode, old_inode); + goto out; } MSDOS_I(depend)->i_old = NULL; iput(depend); } + if (linked) { - if (MSDOS_I(linked)->i_oldlink != inode) { - printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n", - linked, inode, MSDOS_I(linked)->i_oldlink); - fat_fs_panic(sb,"..."); - goto done; +#ifdef FAT_PARANOIA +printk("fat_put_inode: linked inode is %ld, i_count=%d\n", +linked->i_ino, linked->i_count); +#endif + old_inode = MSDOS_I(linked)->i_oldlink; + if (old_inode != inode) { + printk("fat_free_link: Invalid link for inode %ld: " + "expected 0x%p, got 0x%p\n", + linked->i_ino, inode, old_inode); + goto out; } MSDOS_I(linked)->i_oldlink = NULL; iput(linked); } -done: + success = 1; +out: + return success; +} + +/* + * This is a little tricky, as we may have links and may be linked + * by other inodes. Also, we're subject to race conditions ... + */ +void fat_put_inode(struct inode *inode) +{ + int last_use = 1; + + /* + * Check whether we're a dependent of other inodes ... + */ + if (MSDOS_I(inode)->i_oldlink) + last_use++; + if (MSDOS_I(inode)->i_old) + last_use++; + + if (inode->i_count <= last_use) { +#ifdef FAT_PARANOIA +printk("fat_put_inode: last use for %ld, i_count=%d\n", +inode->i_ino, inode->i_count); +#endif + if (inode->i_nlink) { + if (MSDOS_I(inode)->i_busy) + fat_cache_inval_inode(inode); + fat_free_links(inode); + } + } +} + +void fat_delete_inode(struct inode *inode) +{ + fat_cache_inval_inode(inode); + inode->i_size = 0; + fat_truncate(inode); + if (!fat_free_links(inode)) + fat_fs_panic(inode->i_sb,"..."); /* is this necessary? */ clear_inode(inode); } void fat_put_super(struct super_block *sb) { + lock_super(sb); + if (MSDOS_SB(sb)->fat_bits == 32) { + fat_clusters_flush(sb); + } fat_cache_inval_dev(sb->s_dev); set_blocksize (sb->s_dev,BLOCK_SIZE); - lock_super(sb); + if (MSDOS_SB(sb)->nls_disk) { + unload_nls(MSDOS_SB(sb)->nls_disk); + MSDOS_SB(sb)->nls_disk = NULL; + MSDOS_SB(sb)->options.codepage = 0; + } + if (MSDOS_SB(sb)->nls_io) { + unload_nls(MSDOS_SB(sb)->nls_io); + MSDOS_SB(sb)->nls_io = NULL; + } + /* + * Note: the iocharset option might have been specified + * without enabling nls_io, so check for it here. + */ + if (MSDOS_SB(sb)->options.iocharset) { + kfree(MSDOS_SB(sb)->options.iocharset); + MSDOS_SB(sb)->options.iocharset = NULL; + } sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; @@ -98,35 +161,53 @@ void fat_put_super(struct super_block *sb) static int parse_options(char *options,int *fat, int *blksize, int *debug, struct fat_mount_options *opts) { - char *this_char,*value; + char *this_char,*value,save,*savep; + char *p; + int ret = 1, len; opts->name_check = 'n'; opts->conversion = 'b'; opts->fs_uid = current->uid; opts->fs_gid = current->gid; opts->fs_umask = current->fs->umask; - opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = opts->isvfat = 0; + opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0; + opts->codepage = 0; + opts->utf8 = 0; + opts->iocharset = NULL; *debug = *fat = 0; - if (!options) return 1; - for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { - if ((value = strchr(this_char,'=')) != NULL) + if (!options) + goto out; + save = 0; + savep = NULL; + 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,"check") && value) { if (value[0] && !value[1] && strchr("rns",*value)) opts->name_check = *value; - else if (!strcmp(value,"relaxed")) opts->name_check = 'r'; - else if (!strcmp(value,"normal")) opts->name_check = 'n'; - else if (!strcmp(value,"strict")) opts->name_check = 's'; - else return 0; + else if (!strcmp(value,"relaxed")) + opts->name_check = 'r'; + else if (!strcmp(value,"normal")) + opts->name_check = 'n'; + else if (!strcmp(value,"strict")) + opts->name_check = 's'; + else ret = 0; } else if (!strcmp(this_char,"conv") && value) { if (value[0] && !value[1] && strchr("bta",*value)) opts->conversion = *value; - else if (!strcmp(value,"binary")) opts->conversion = 'b'; - else if (!strcmp(value,"text")) opts->conversion = 't'; - else if (!strcmp(value,"auto")) opts->conversion = 'a'; - else return 0; + else if (!strcmp(value,"binary")) + opts->conversion = 'b'; + else if (!strcmp(value,"text")) + opts->conversion = 't'; + else if (!strcmp(value,"auto")) + opts->conversion = 'a'; + else ret = 0; } else if (!strcmp(this_char,"dots")) { opts->dotsOK = 1; @@ -140,73 +221,110 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug, else if (!strcmp(this_char,"dotsOK") && value) { if (!strcmp(value,"yes")) opts->dotsOK = 1; else if (!strcmp(value,"no")) opts->dotsOK = 0; - else return 0; + else ret = 0; } else if (!strcmp(this_char,"uid")) { - if (!value || !*value) - return 0; - opts->fs_uid = simple_strtoul(value,&value,0); - if (*value) - return 0; + if (!value || !*value) ret = 0; + else { + opts->fs_uid = simple_strtoul(value,&value,0); + if (*value) ret = 0; + } } else if (!strcmp(this_char,"gid")) { - if (!value || !*value) - return 0; - opts->fs_gid = simple_strtoul(value,&value,0); - if (*value) - return 0; + if (!value || !*value) ret= 0; + else { + opts->fs_gid = simple_strtoul(value,&value,0); + if (*value) ret = 0; + } } else if (!strcmp(this_char,"umask")) { - if (!value || !*value) - return 0; - opts->fs_umask = simple_strtoul(value,&value,8); - if (*value) - return 0; + if (!value || !*value) ret = 0; + else { + opts->fs_umask = simple_strtoul(value,&value,8); + if (*value) ret = 0; + } } else if (!strcmp(this_char,"debug")) { - if (value) return 0; - *debug = 1; + if (value) ret = 0; + else *debug = 1; } else if (!strcmp(this_char,"fat")) { - if (!value || !*value) - return 0; - *fat = simple_strtoul(value,&value,0); - if (*value || (*fat != 12 && *fat != 16)) - return 0; + if (!value || !*value) ret = 0; + else { + *fat = simple_strtoul(value,&value,0); + if (*value || (*fat != 12 && *fat != 16 && + *fat != 32)) + ret = 0; + } } else if (!strcmp(this_char,"quiet")) { - if (value) return 0; - opts->quiet = 1; + if (value) ret = 0; + else opts->quiet = 1; } else if (!strcmp(this_char,"blocksize")) { - *blksize = simple_strtoul(value,&value,0); - if (*value) - return 0; - if (*blksize != 512 && *blksize != 1024 && *blksize != 2048){ - printk ("MSDOS FS: Invalid blocksize (512, 1024 or 2048)\n"); + if (*value) ret = 0; + else if (*blksize != 512 && + *blksize != 1024 && + *blksize != 2048) { + printk ("MSDOS FS: Invalid blocksize " + "(512, 1024, or 2048)\n"); } } else if (!strcmp(this_char,"sys_immutable")) { - if (value) - return 0; - opts->sys_immutable = 1; + if (value) ret = 0; + else opts->sys_immutable = 1; + } + else if (!strcmp(this_char,"codepage")) { + opts->codepage = simple_strtoul(value,&value,0); + if (*value) ret = 0; + else printk ("MSDOS FS: Using codepage %d\n", + opts->codepage); } + else if (!strcmp(this_char,"iocharset")) { + p = value; + while (*value && *value != ',') value++; + len = value - p; + if (len) { + char * buffer = kmalloc(len+1, GFP_KERNEL); + if (buffer) { + opts->iocharset = buffer; + memcpy(buffer, p, len); + buffer[len] = 0; + printk("MSDOS FS: IO charset %s\n", + buffer); + } else + ret = 0; + } + } + + if (this_char != options) *(this_char-1) = ','; + if (value) *savep = save; + if (ret == 0) + break; } - return 1; +out: + return ret; } - -/* Read the super block of an MS-DOS FS. */ - -struct super_block *fat_read_super(struct super_block *sb,void *data, int silent) +/* + * Read the super block of an MS-DOS FS. + * + * Note that this may be called from vfat_read_super + * with some fields already initialized. + */ +struct super_block * +fat_read_super(struct super_block *sb, void *data, int silent) { + struct inode *root_inode; struct buffer_head *bh; - struct msdos_boot_sector *b; + struct fat_boot_sector *b; + char *p; int data_sectors,logical_sector_size,sector_mult,fat_clusters=0; - int debug,error,fat; + int debug,error,fat,cp; int blksize = 512; + int fat32; struct fat_mount_options opts; - struct inode *root_inode; + char buf[50]; MOD_INC_USE_COUNT; if (hardsect_size[MAJOR(sb->s_dev)] != NULL){ @@ -215,13 +333,14 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent printk ("MSDOS: Hardware sector size is %d\n",blksize); } } + + opts.isvfat = MSDOS_SB(sb)->options.isvfat; if (!parse_options((char *) data, &fat, &blksize, &debug, &opts) - || (blksize != 512 && blksize != 1024 && blksize != 2048)) - { - sb->s_dev = 0; - MOD_DEC_USE_COUNT; - return NULL; - } + || (blksize != 512 && blksize != 1024 && blksize != 2048)) + goto out_fail; + /* N.B. we should parse directly into the sb structure */ + memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options)); + cache_init(); lock_super(sb); if( blksize > 1024 ) @@ -240,13 +359,10 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent unlock_super(sb); if (bh == NULL || !fat_is_uptodate(sb,bh)) { fat_brelse (sb, bh); - sb->s_dev = 0; - printk("FAT bread failed\n"); - MOD_DEC_USE_COUNT; - return NULL; + goto out_no_bread; } - b = (struct msdos_boot_sector *) bh->b_data; set_blocksize(sb->s_dev, blksize); + /* * The DOS3 partition size limit is *not* 32M as many people think. * Instead, it is 64K sectors (with the usual sector size being @@ -265,15 +381,39 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0) /* don't divide by zero */ + b = (struct fat_boot_sector *) bh->b_data; logical_sector_size = CF_LE_W(get_unaligned((unsigned short *) &b->sector_size)); sector_mult = logical_sector_size >> SECTOR_BITS; MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult; MSDOS_SB(sb)->fats = b->fats; MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult; - MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult; - MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W( - b->fat_length))*sector_mult; + if (!b->fat_length && b->fat32_length) { + struct fat_boot_fsinfo *fsinfo; + + /* Must be FAT32 */ + fat32 = 1; + MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult; + MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster); + MSDOS_SB(sb)->fsinfo_offset = + CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0; + fsinfo = (struct fat_boot_fsinfo *) + &bh->b_data[MSDOS_SB(sb)->fsinfo_offset]; + if (CF_LE_L(fsinfo->signature) != 0x61417272) { + printk("fat_read_super: Did not find valid FSINFO " + "signature. Found 0x%x\n", + CF_LE_L(fsinfo->signature)); + } else { + MSDOS_SB(sb)->free_clusters = CF_LE_L(fsinfo->free_clusters); + } + } else { + fat32 = 0; + MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult; + MSDOS_SB(sb)->root_cluster = 0; + MSDOS_SB(sb)->free_clusters = -1; /* Don't know yet */ + } + MSDOS_SB(sb)->dir_start= CF_LE_W(b->reserved)*sector_mult+ + b->fats*MSDOS_SB(sb)->fat_length; MSDOS_SB(sb)->dir_entries = CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries)); MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE(( @@ -288,8 +428,9 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent if (!error) { MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/ b->cluster_size/sector_mult : 0; - MSDOS_SB(sb)->fat_bits = fat ? fat : MSDOS_SB(sb)->clusters > - MSDOS_FAT12 ? 16 : 12; + MSDOS_SB(sb)->fat_bits = fat32 ? 32 : + (fat ? fat : + (MSDOS_SB(sb)->clusters > MSDOS_FAT12 ? 16 : 12)); fat_clusters = MSDOS_SB(sb)->fat_length*SECTOR_SIZE*8/ MSDOS_SB(sb)->fat_bits; error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries & @@ -315,43 +456,83 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask, MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : ""); printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d," - "se=%d,ts=%d,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size, - MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->fat_length, + "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n", + b->media,MSDOS_SB(sb)->cluster_size, + MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start, + MSDOS_SB(sb)->fat_length, MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries, MSDOS_SB(sb)->data_start, - CF_LE_W(get_unaligned((unsigned short *) &b->sectors)), - CF_LE_L(b->total_sect),logical_sector_size); + CF_LE_W(*(unsigned short *) &b->sectors), + (unsigned long)b->total_sect,logical_sector_size, + MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters); printk ("Transaction block size = %d\n",blksize); } if (MSDOS_SB(sb)->clusters+2 > fat_clusters) MSDOS_SB(sb)->clusters = fat_clusters-2; - if (error) { - if (!silent) - printk("VFS: Can't find a valid MSDOS filesystem on dev " - "%s.\n", kdevname(sb->s_dev)); - sb->s_dev = 0; - MOD_DEC_USE_COUNT; - return NULL; - } + if (error) + goto out_invalid; + sb->s_magic = MSDOS_SUPER_MAGIC; /* set up enough so that it can read an inode */ - MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */ MSDOS_SB(sb)->fat_wait = NULL; MSDOS_SB(sb)->fat_lock = 0; MSDOS_SB(sb)->prev_free = 0; - memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options)); - root_inode = iget(sb,MSDOS_ROOT_INO); - sb->s_root = d_alloc_root(root_inode, NULL); - if (!sb->s_root) { - sb->s_dev = 0; - printk("get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; + cp = opts.codepage ? opts.codepage : 437; + sprintf(buf, "cp%d", cp); + MSDOS_SB(sb)->nls_disk = load_nls(buf); + if (! MSDOS_SB(sb)->nls_disk) { + /* Fail only if explicit charset specified */ + if (opts.codepage != 0) + goto out_fail; + MSDOS_SB(sb)->options.codepage = 0; /* already 0?? */ + MSDOS_SB(sb)->nls_disk = load_nls_default(); + } + + MSDOS_SB(sb)->nls_io = NULL; + if (MSDOS_SB(sb)->options.isvfat && !opts.utf8) { + p = opts.iocharset ? opts.iocharset : "iso8859-1"; + MSDOS_SB(sb)->nls_io = load_nls(p); + if (! MSDOS_SB(sb)->nls_io) { + /* Fail only if explicit charset specified */ + if (opts.iocharset) + goto out_unload_nls; + MSDOS_SB(sb)->nls_io = load_nls_default(); + } } + + root_inode = iget(sb, MSDOS_ROOT_INO); + if (!root_inode) + goto out_no_root; + sb->s_root = d_alloc_root(root_inode, NULL); + if (!sb->s_root) + goto out_no_root; return sb; -} +out_no_root: + printk("get root inode failed\n"); + iput(root_inode); + if (MSDOS_SB(sb)->nls_io) + unload_nls(MSDOS_SB(sb)->nls_io); +out_unload_nls: + unload_nls(MSDOS_SB(sb)->nls_disk); + goto out_fail; +out_invalid: + if (!silent) + printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n", + kdevname(sb->s_dev)); + goto out_fail; +out_no_bread: + printk("FAT bread failed\n"); +out_fail: + if (opts.iocharset) { + printk("VFS: freeing iocharset=%s\n", opts.iocharset); + kfree(opts.iocharset); + } + sb->s_dev = 0; + MOD_DEC_USE_COUNT; + return NULL; +} int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz) { @@ -386,7 +567,7 @@ int fat_bmap(struct inode *inode,int block) int cluster,offset; sb = MSDOS_SB(inode->i_sb); - if (inode->i_ino == MSDOS_ROOT_INO) { + if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) { return sb->dir_start + block; } cluster = block/sb->cluster_size; @@ -412,6 +593,8 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o struct msdos_dir_entry *raw_entry; int nr; + PRINTK(("fat_read_inode: inode=%p, sb->dir_start=0x%x\n", + inode, MSDOS_SB(sb)->dir_start)); MSDOS_I(inode)->i_busy = 0; MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL; MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL; @@ -423,17 +606,33 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR; inode->i_op = fs_dir_inode_ops; - inode->i_nlink = fat_subdirs(inode)+2; - /* subdirs (neither . nor ..) plus . and "self" */ - inode->i_size = MSDOS_SB(sb)->dir_entries* - sizeof(struct msdos_dir_entry); + if (MSDOS_SB(sb)->fat_bits == 32) { + MSDOS_I(inode)->i_start = MSDOS_SB(sb)->root_cluster; + if ((nr = MSDOS_I(inode)->i_start) != 0) { + while (nr != -1) { + inode->i_size += SECTOR_SIZE*MSDOS_SB(sb)->cluster_size; + if (!(nr = fat_access(sb,nr,-1))) { + printk("Directory %ld: bad FAT\n", + inode->i_ino); + break; + } + } + } + } else { + MSDOS_I(inode)->i_start = 0; + inode->i_size = MSDOS_SB(sb)->dir_entries* + sizeof(struct msdos_dir_entry); + } inode->i_blksize = MSDOS_SB(sb)->cluster_size* SECTOR_SIZE; inode->i_blocks = (inode->i_size+inode->i_blksize-1)/ inode->i_blksize*MSDOS_SB(sb)->cluster_size; - MSDOS_I(inode)->i_start = 0; + MSDOS_I(inode)->i_logstart = 0; + MSDOS_I(inode)->i_attrs = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = 0; + inode->i_nlink = fat_subdirs(inode)+2; + /* subdirs (neither . nor ..) plus . and "self" */ return; } if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) { @@ -449,6 +648,11 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o inode->i_op = fs_dir_inode_ops; MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start); + if (MSDOS_SB(sb)->fat_bits == 32) { + MSDOS_I(inode)->i_start |= + (CF_LE_W(raw_entry->starthi) << 16); + } + MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; inode->i_nlink = fat_subdirs(inode); /* includes .., compensating for "self" */ #ifdef DEBUG @@ -458,7 +662,7 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o } #endif inode->i_size = 0; - if ((nr = CF_LE_W(raw_entry->start)) != 0) + if ((nr = MSDOS_I(inode)->i_start) != 0) while (nr != -1) { inode->i_size += SECTOR_SIZE*MSDOS_SB(inode-> i_sb)->cluster_size; @@ -479,6 +683,11 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o ? &fat_file_inode_operations_1024 : &fat_file_inode_operations; MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start); + if (MSDOS_SB(sb)->fat_bits == 32) { + MSDOS_I(inode)->i_start |= + (CF_LE_W(raw_entry->starthi) << 16); + } + MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; inode->i_nlink = 1; inode->i_size = CF_LE_L(raw_entry->size); } @@ -549,7 +758,8 @@ void fat_write_inode(struct inode *inode) } raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | MSDOS_I(inode)->i_attrs; - raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_start); + raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_logstart); + raw_entry->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16); fat_date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date); raw_entry->time = CT_LE_W(raw_entry->time); raw_entry->date = CT_LE_W(raw_entry->date); diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 5b71573b3..0fb7791ec 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -14,7 +14,11 @@ #include "msbuffer.h" -#define PRINTK(x) +#if 0 +# define PRINTK(x) printk x +#else +# define PRINTK(x) +#endif #define Printk(x) printk x /* Well-known binary file extensions - of course there are many more */ @@ -106,6 +110,34 @@ void unlock_fat(struct super_block *sb) wake_up(&MSDOS_SB(sb)->fat_wait); } +/* Flushes the number of free clusters on FAT32 */ +/* XXX: Need to write one per FSINFO block. Currently only writes 1 */ +void fat_clusters_flush(struct super_block *sb) +{ + int offset; + struct buffer_head *bh; + struct fat_boot_fsinfo *fsinfo; + + /* The fat32 boot fs info is at offset 0x3e0 by observation */ + offset = MSDOS_SB(sb)->fsinfo_offset; + bh = fat_bread(sb, (offset >> SECTOR_BITS)); + if (bh == NULL) { + printk("FAT bread failed in fat_clusters_flush\n"); + return; + } + fsinfo = (struct fat_boot_fsinfo *) + &bh->b_data[offset & (SECTOR_SIZE-1)]; + + /* Sanity check */ + if (CF_LE_L(fsinfo->signature) != 0x61417272) { + printk("fat_clusters_flush: Did not find valid FSINFO signature. Found 0x%x. offset=0x%x\n", CF_LE_L(fsinfo->signature), offset); + fat_brelse(sb, bh); + return; + } + fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters); + fat_mark_buffer_dirty(sb, bh, 1); + fat_brelse(sb, bh); +} /* * fat_add_cluster tries to allocate a new cluster and adds it to the file @@ -119,7 +151,9 @@ int fat_add_cluster(struct inode *inode) struct buffer_head *bh; int cluster_size = MSDOS_SB(sb)->cluster_size; - if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC; + if (MSDOS_SB(sb)->fat_bits != 32) { + if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC; + } if (!MSDOS_SB(sb)->free_clusters) return -ENOSPC; lock_fat(sb); limit = MSDOS_SB(sb)->clusters; @@ -141,6 +175,8 @@ printk("free cluster: %d\n",nr); fat_access(sb,nr,EOF_FAT(sb)); if (MSDOS_SB(sb)->free_clusters != -1) MSDOS_SB(sb)->free_clusters--; + if (MSDOS_SB(sb)->fat_bits == 32) + fat_clusters_flush(sb); unlock_fat(sb); #ifdef DEBUG printk("set to %x\n",fat_access(sb,nr,-1)); @@ -177,6 +213,7 @@ printk("last = %d\n",last); if (last) fat_access(sb,last,nr); else { MSDOS_I(inode)->i_start = nr; + MSDOS_I(inode)->i_logstart = nr; mark_inode_dirty(inode); } #ifdef DEBUG @@ -260,6 +297,8 @@ void fat_date_unix2dos(int unix_date,unsigned short *time, unix_date += 3600; } unix_date -= sys_tz.tz_minuteswest*60; + if (sys_tz.tz_dsttime) unix_date += 3600; + *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ (((unix_date/3600) % 24) << 11); day = unix_date/86400-3652; @@ -302,7 +341,7 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, fat_brelse(sb, *bh); PRINTK (("get_entry sector apres brelse\n")); if (!(*bh = fat_bread(sb, sector))) { - printk("Directory sread (sector %d) failed\n",sector); + printk("Directory sread (sector 0x%x) failed\n",sector); continue; } PRINTK (("get_entry apres sread\n")); @@ -344,7 +383,13 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, !(data[entry].attr & ATTR_VOLUME); #define RSS_START /* search for start cluster */ \ - done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number; + done = !IS_FREE(data[entry].name) \ + && ( \ + ( \ + (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \ + ) \ + | CF_LE_W(data[entry].start) \ + ) == *number; #define RSS_FREE /* search for free entry */ \ { \ @@ -397,6 +442,9 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name, if (done) { if (ino) *ino = sector*MSDOS_DPS+entry; start = CF_LE_W(data[entry].start); + if (MSDOS_SB(sb)->fat_bits == 32) { + start |= (CF_LE_W(data[entry].starthi) << 16); + } if (!res_bh) fat_brelse(sb, bh); else { @@ -492,6 +540,7 @@ int fat_parent_ino(struct inode *dir,int locked) static int zero = 0; int error,curr,prev,nr; + PRINTK(("fat_parent_ino: Debug 0\n")); if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i"); if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino; if (!locked) fat_lock_creation(); /* prevent renames */ @@ -500,18 +549,27 @@ int fat_parent_ino(struct inode *dir,int locked) if (!locked) fat_unlock_creation(); return curr; } + PRINTK(("fat_parent_ino: Debug 1 curr=%d\n", curr)); if (!curr) nr = MSDOS_ROOT_INO; else { + PRINTK(("fat_parent_ino: Debug 2\n")); if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL, NULL,NULL,SCAN_ANY)) < 0) { + PRINTK(("fat_parent_ino: Debug 3 prev=%d\n", prev)); if (!locked) fat_unlock_creation(); return prev; } + PRINTK(("fat_parent_ino: Debug 4 prev=%d\n", prev)); + if (prev == 0 && MSDOS_SB(dir->i_sb)->fat_bits == 32) { + prev = MSDOS_SB(dir->i_sb)->root_cluster; + } if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL, NULL,SCAN_ANY)) < 0) { + PRINTK(("fat_parent_ino: Debug 5 error=%d\n", error)); if (!locked) fat_unlock_creation(); return error; } + PRINTK(("fat_parent_ino: Debug 6 nr=%d\n", nr)); } if (!locked) fat_unlock_creation(); return nr; @@ -528,10 +586,12 @@ int fat_subdirs(struct inode *dir) int count; count = 0; - if (dir->i_ino == MSDOS_ROOT_INO) + if ((dir->i_ino == MSDOS_ROOT_INO) && + (MSDOS_SB(dir->i_sb)->fat_bits != 32)) { (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL,SCAN_ANY); - else { - if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */ + } else { + if ((dir->i_ino != MSDOS_ROOT_INO) && + !MSDOS_I(dir)->i_start) return 0; /* in mkdir */ else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start, NULL,&count,NULL,NULL,NULL,SCAN_ANY); } @@ -549,10 +609,7 @@ int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh, { int res; - res = (name) - ? raw_scan(dir->i_sb,MSDOS_I(dir)->i_start, - name, NULL, ino, res_bh, res_de, scantype) - : raw_scan(dir->i_sb,MSDOS_I(dir)->i_start, - NULL, NULL, ino, res_bh, res_de, scantype); + res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start, + name, NULL, ino, res_bh, res_de, scantype); return res<0 ? res : 0; } diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c index fd66e51d1..545874a04 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -7,6 +7,9 @@ * mmap handling for fat-based filesystems */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#include <linux/version.h> + #include <linux/stat.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -59,8 +62,8 @@ static unsigned long fat_file_mmap_nopage( { unsigned long cur_fs = get_fs(); set_fs (KERNEL_DS); - cur_read = fat_file_read (inode,&filp,(char*)page - ,need_read); + cur_read = fat_file_read (&filp, (char*)page, + need_read, &filp.f_pos); set_fs (cur_fs); } if (cur_read != need_read){ diff --git a/fs/fat/tables.c b/fs/fat/tables.c index 3e8379374..c4ad91c3c 100644 --- a/fs/fat/tables.c +++ b/fs/fat/tables.c @@ -1,7 +1,7 @@ /* * linux/fs/fat/tables.c * - * ASCII / Unicode translation tables for VFAT filename handling. + * Unicode escape translation tables for VFAT filename handling. * By Gordon Chaffee. * * Note: This file is used by all fat-based filesystems. @@ -9,10 +9,9 @@ #include <linux/kernel.h> #include <linux/string.h> +#include <linux/msdos_fs.h> -#include "tables.h" - -unsigned char fat_uni2code[64] = { +unsigned char fat_uni2esc[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', @@ -23,7 +22,7 @@ unsigned char fat_uni2code[64] = { 'u', 'v', 'w', 'x', 'y', 'z', '+', '-' }; -unsigned char fat_code2uni[256] = { +unsigned char fat_esc2uni[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -58,209 +57,6 @@ unsigned char fat_code2uni[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; -static unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, /* 0x98-0x9F */ - 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* 0xA0-0xA7 */ - 0xF9, 0xB8, 0x00, 0xAE, 0xAA, 0xF0, 0x00, 0xEE, /* 0xA8-0xAF */ - 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* 0xB0-0xB7 */ - 0xF7, 0xFB, 0x00, 0xAF, 0xAC, 0xAB, 0xF3, 0x00, /* 0xB8-0xBF */ - 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* 0xC0-0xC7 */ - 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* 0xC8-0xCF */ - 0x00, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* 0xD0-0xD7 */ - 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* 0xD8-0xDF */ - 0xA1, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* 0xE0-0xE7 */ - 0x8A, 0x82, 0x88, 0x89, 0x8D, 0x00, 0x8C, 0x8B, /* 0xE8-0xEF */ - 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* 0xF0-0xF7 */ - 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 /* 0xF8-0xFF */ -}; - - -static unsigned char page25[256] = { - 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, /* 0x08-0x0F */ - 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, /* 0x18-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, /* 0x28-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, /* 0x38-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4F */ - 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, /* 0x50-0x57 */ - 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, /* 0x58-0x5F */ - 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, /* 0x60-0x67 */ - 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, /* 0x68-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7F */ - - 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */ - 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9F */ - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xF8-0xFF */ -}; - - -unsigned char *fat_uni2asc_pg[256] = { - page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, page25 -}; - -/* Conversion from ASCII name characters to the shortname character - * should probably just just use XXX - */ -unsigned char fat_a2alias[256] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */ - - 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, /* 0x80-0x87 */ - 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, /* 0x88-0x8F */ - 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, /* 0x90-0x97 */ -/*_~1*/ 0x98, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, /* 0x98-0x9F */ - 0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, /* 0xA0-0xA7 */ - 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, /* 0xA8-0xAF */ - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, /* 0xB0-0xB7 */ - 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, /* 0xB8-0xBF */ - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 0xC0-0xC7 */ - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, /* 0xC8-0xCF */ - 0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0x49, 0xD6, 0xD7, /* 0xD0-0xD7 */ - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, /* 0xD8-0xDF */ - 0xE0, 0xE1, 0xE2, 0xE3, 0x05, 0x05, 0xE6, 0xE8, /* 0xE0-0xE7 */ - 0xE8, 0xE9, 0xEA, 0xEB, 0xED, 0xED, 0xEE, 0xEF, /* 0xE8-0xEF */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 0xF0-0xF7 */ - 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF /* 0xF8-0xFF */ -}; - -struct unicode_value fat_a2uni[256] = { -/* 0x00 */ -{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00}, -{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00}, -{0x08, 0x00}, {0x09, 0x00}, {0x0A, 0x00}, {0x0B, 0x00}, -{0x0C, 0x00}, {0x0D, 0x00}, {0x0E, 0x00}, {0x0F, 0x00}, -/* 0x10 */ -{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, -{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, -{0x18, 0x00}, {0x19, 0x00}, {0x1A, 0x00}, {0x1B, 0x00}, -{0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, {0x1F, 0x00}, -/* 0x20 */ -{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, -{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, -{0x28, 0x00}, {0x29, 0x00}, {0x2A, 0x00}, {0x2B, 0x00}, -{0x2C, 0x00}, {0x2D, 0x00}, {0x2E, 0x00}, {0x2F, 0x00}, -/* 0x30 */ -{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, -{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00}, -{0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x00}, -{0x3C, 0x00}, {0x3D, 0x00}, {0x3E, 0x00}, {0x3F, 0x00}, -/* 0x40 */ -{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, -{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, -{0x48, 0x00}, {0x49, 0x00}, {0x4A, 0x00}, {0x4B, 0x00}, -{0x4C, 0x00}, {0x4D, 0x00}, {0x4E, 0x00}, {0x4F, 0x00}, -/* 0x50 */ -{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00}, -{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, -{0x58, 0x00}, {0x59, 0x00}, {0x5A, 0x00}, {0x5B, 0x00}, -{0x5C, 0x00}, {0x5D, 0x00}, {0x5E, 0x00}, {0x5F, 0x00}, -/* 0x60 */ -{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00}, -{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00}, -{0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00}, -{0x6C, 0x00}, {0x6D, 0x00}, {0x6E, 0x00}, {0x6F, 0x00}, -/* 0x70 */ -{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00}, -{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00}, -{0x78, 0x00}, {0x79, 0x00}, {0x7A, 0x00}, {0x7B, 0x00}, -{0x7C, 0x00}, {0x7D, 0x00}, {0x7E, 0x00}, {0x7F, 0x00}, -/* 0x80 */ -{0xC7, 0x00}, {0xFC, 0x00}, {0xE9, 0x00}, {0xE2, 0x00}, -{0xE4, 0x00}, {0xE0, 0x00}, {0xE5, 0x00}, {0xE7, 0x00}, -{0xEA, 0x00}, {0xEB, 0x00}, {0xE8, 0x00}, {0xEF, 0x00}, -{0xEE, 0x00}, {0xEC, 0x00}, {0xC4, 0x00}, {0xC5, 0x00}, -/* 0x90 */ -{0xC9, 0x00}, {0xE6, 0x00}, {0xC6, 0x00}, {0xF4, 0x00}, -{0xF6, 0x00}, {0xF2, 0x00}, {0xFB, 0x00}, {0xF9, 0x00}, -{0xFF, 0x00}, {0xD6, 0x00}, {0xDC, 0x00}, {0xF8, 0x00}, -{0xA3, 0x00}, {0xD8, 0x00}, {0xD7, 0x00}, {0x92, 0x00}, -/* 0xA0 */ -{0xE1, 0x00}, {0xE0, 0x00}, {0xF3, 0x00}, {0xFA, 0x00}, -{0xF1, 0x00}, {0xD1, 0x00}, {0xAA, 0x00}, {0xBA, 0x00}, -{0xBF, 0x00}, {0xAE, 0x00}, {0xAC, 0x00}, {0xBD, 0x00}, -{0xBC, 0x00}, {0xA1, 0x00}, {0xAB, 0x00}, {0xBB, 0x00}, -/* 0xB0 */ -{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25}, -{0x24, 0x25}, {0xC1, 0x00}, {0xC2, 0x00}, {0xC0, 0x00}, -{0xA9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25}, -{0x5D, 0x25}, {0xA2, 0x00}, {0xA5, 0x00}, {0x10, 0x25}, -/* 0xC0 */ -{0x14, 0x25}, {0x34, 0x25}, {0x2C, 0x25}, {0x1C, 0x25}, -{0x00, 0x25}, {0x3C, 0x25}, {0xE3, 0x00}, {0xC3, 0x00}, -{0x5A, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25}, -{0x60, 0x25}, {0x50, 0x25}, {0x6C, 0x25}, {0xA4, 0x00}, -/* 0xD0 */ -{0xF0, 0x00}, {0xD0, 0x00}, {0xCA, 0x00}, {0xCB, 0x00}, -{0xC8, 0x00}, {0x31, 0x01}, {0xCD, 0x00}, {0xCE, 0x00}, -{0xCF, 0x00}, {0x18, 0x25}, {0x0C, 0x25}, {0x88, 0x25}, -{0x84, 0x25}, {0xA6, 0x00}, {0xCC, 0x00}, {0x80, 0x25}, -/* 0xE0 */ -{0xD3, 0x00}, {0xDF, 0x00}, {0xD4, 0x00}, {0xD2, 0x00}, -{0xF5, 0x00}, {0xD5, 0x00}, {0xB5, 0x00}, {0xFE, 0x00}, -{0xDE, 0x00}, {0xDA, 0x00}, {0xDB, 0x00}, {0xD9, 0x00}, -{0xFD, 0x00}, {0xDD, 0x00}, {0xAF, 0x00}, {0xB4, 0x00}, -/* 0xF0 */ -{0xAD, 0x00}, {0xB1, 0x00}, {0x17, 0x20}, {0xBE, 0x00}, -{0xB6, 0x00}, {0xA7, 0x00}, {0xF7, 0x00}, {0xB8, 0x00}, -{0xB0, 0x00}, {0xA8, 0x00}, {0xB7, 0x00}, {0xB9, 0x00}, -{0xB3, 0x00}, {0xB2, 0x00}, {0xA0, 0x25}, {0xA0, 0x00}}; /* * Overrides for Emacs so that we follow Linus's tabbing style. |