]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fat/dir.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 into next
[linux-2.6-omap-h63xx.git] / fs / fat / dir.c
index 72cbcd61bd951268fa49eb18faf42d516606b6dd..34541d06e6263b1817d96ee4d640f2cc8aa35eb7 100644 (file)
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos,
  * but ignore that right now.
  * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
  */
-static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
-                      struct nls_table *nls)
+static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len,
+                      int uni_xlate, struct nls_table *nls)
 {
        wchar_t *ip, ec;
        unsigned char *op, nc;
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
        ip = uni;
        op = ascii;
 
-       while (*ip) {
+       while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
                ec = *ip++;
                if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
                        op += charlen;
+                       len -= charlen;
                } else {
                        if (uni_xlate == 1) {
                                *op = ':';
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
                                        ec >>= 4;
                                }
                                op += 5;
+                               len -= 5;
                        } else {
                                *op++ = '?';
+                               len--;
                        }
                }
-               /* We have some slack there, so it's OK */
-               if (op>ascii+256) {
-                       op = ascii + 256;
-                       break;
-               }
        }
+
+       if (unlikely(*ip)) {
+               printk(KERN_WARNING "FAT: filename was truncated while "
+                      "converting.");
+       }
+
        *op = 0;
        return (op - ascii);
 }
@@ -243,7 +247,7 @@ static int fat_parse_long(struct inode *dir, loff_t *pos,
        unsigned char id, slot, slots, alias_checksum;
 
        if (!*unicode) {
-               *unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
+               *unicode = __getname();
                if (!*unicode) {
                        brelse(*bh);
                        return -ENOMEM;
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
        struct nls_table *nls_io = sbi->nls_io;
        struct nls_table *nls_disk = sbi->nls_disk;
        wchar_t bufuname[14];
-       unsigned char xlate_len, nr_slots;
+       unsigned char nr_slots;
+       int xlate_len;
        wchar_t *unicode = NULL;
-       unsigned char work[MSDOS_NAME], bufname[260];   /* 256 + 4 */
+       unsigned char work[MSDOS_NAME];
+       unsigned char *bufname = NULL;
        int uni_xlate = sbi->options.unicode_xlate;
        int utf8 = sbi->options.utf8;
        int anycase = (sbi->options.name_check != 's');
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
        loff_t cpos = 0;
        int chl, i, j, last_u, err;
 
+       bufname = __getname();
+       if (!bufname)
+               return -ENOMEM;
+
        err = -ENOENT;
        while(1) {
                if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
@@ -386,8 +396,8 @@ parse_record:
 
                bufuname[last_u] = 0x0000;
                xlate_len = utf8
-                       ?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
-                       :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+                       ?utf8_wcstombs(bufname, bufuname, PATH_MAX)
+                       :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io);
                if (xlate_len == name_len)
                        if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
                            (anycase && !nls_strnicmp(nls_io, name, bufname,
@@ -396,8 +406,8 @@ parse_record:
 
                if (nr_slots) {
                        xlate_len = utf8
-                               ?utf8_wcstombs(bufname, unicode, sizeof(bufname))
-                               :uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
+                               ?utf8_wcstombs(bufname, unicode, PATH_MAX)
+                               :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io);
                        if (xlate_len != name_len)
                                continue;
                        if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -416,8 +426,10 @@ Found:
        sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
        err = 0;
 EODir:
+       if (bufname)
+               __putname(bufname);
        if (unicode)
-               free_page((unsigned long)unicode);
+               __putname(unicode);
 
        return err;
 }
@@ -460,7 +472,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
        loff_t cpos;
        int ret = 0;
 
-       lock_kernel();
+       lock_super(sb);
 
        cpos = filp->f_pos;
        /* Fake . and .. for the root directory. */
@@ -598,7 +610,7 @@ parse_record:
        if (isvfat) {
                bufuname[j] = 0x0000;
                i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
-                        : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+                        : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io);
        }
 
        fill_name = bufname;
@@ -607,10 +619,10 @@ parse_record:
                /* convert the unicode long name. 261 is maximum size
                 * of unicode buffer. (13 * slots + nul) */
                void *longname = unicode + 261;
-               int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));
+               int buf_size = PATH_MAX - (261 * sizeof(unicode[0]));
                int long_len = utf8
                        ? utf8_wcstombs(longname, unicode, buf_size)
-                       : uni16_to_x8(longname, unicode, uni_xlate, nls_io);
+                       : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
 
                if (!both) {
                        fill_name = longname;
@@ -640,9 +652,9 @@ EODir:
 FillFailed:
        brelse(bh);
        if (unicode)
-               free_page((unsigned long)unicode);
+               __putname(unicode);
 out:
-       unlock_kernel();
+       unlock_super(sb);
        return ret;
 }