patch-2.1.60 linux/fs/fat/dir.c

Next file: linux/fs/fat/fatfs_syms.c
Previous file: linux/fs/fat/cache.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.59/linux/fs/fat/dir.c linux/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 @@
 	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 @@
 	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 @@
  * 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 @@
 	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 @@
 	return (op - ascii);
 }
 
+
+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");
+}
+
 int fat_readdirx(
 	struct inode *inode,
 	struct file *filp,
@@ -115,7 +133,9 @@
 	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 @@
 	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 @@
 
 			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 @@
 					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 @@
 	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 @@
 	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,

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov