Added long name support master
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 20 Jan 2025 01:39:25 +0000 (01:39 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 20 Jan 2025 01:39:25 +0000 (01:39 +0000)
common.c
common.h
mcopy.c
mls.c
mmd.c
msdos.h

index 9077b758f16e0cc11aa9c696767a53ac35dffbd2..66cd0c833150c67f77dc5880e57ca37ca99cad88 100644 (file)
--- a/common.c
+++ b/common.c
@@ -1,6 +1,7 @@
 /******************************************************************************
  * @file            common.c
  *****************************************************************************/
 /******************************************************************************
  * @file            common.c
  *****************************************************************************/
+#include    <ctype.h>
 #include    <errno.h>
 #include    <stdarg.h>
 #include    <stdio.h>
 #include    <errno.h>
 #include    <stdarg.h>
 #include    <stdio.h>
 #endif
 
 #include    "common.h"
 #endif
 
 #include    "common.h"
+#include    "msdos.h"
+
+static const unsigned char cvt[] = {
+
+    0x80,   0x9A,   0x45,   0x41,   0x8E,   0x41,   0x8F,
+    0x80,   0x45,   0x45,   0x45,   0x49,   0x49,   0x49,
+    0x8E,   0x8F,   0x90,   0x92,   0x92,   0x4F,   0x99,
+    0x4F,   0x55,   0x55,   0x59,   0x99,   0x9A,   0x9B,
+    0x9C,   0x9D,   0x9E,   0x9F,   0x41,   0x49,   0x4F,
+    0x55,   0xA5,   0xA5,   0xA6,   0xA7,   0xA8,   0xA9,
+    0xAA,   0xAB,   0xAC,   0xAD,   0xAE,   0xAF,   0xB0,
+    0xB1,   0xB2,   0xB3,   0xB4,   0xB5,   0xB6,   0xB7,
+    0xB8,   0xB9,   0xBA,   0xBB,   0xBC,   0xBD,   0xBE,
+    0xBF,   0xC0,   0xC1,   0xC2,   0xC3,   0xC4,   0xC5,
+    0xC6,   0xC7,   0xC8,   0xC9,   0xCA,   0xCB,   0xCC,
+    0xCD,   0xCE,   0xCF,   0xD0,   0xD1,   0xD2,   0xD3,
+    0xD4,   0xD5,   0xD6,   0xD7,   0xD8,   0xD9,   0xDA,
+    0xDB,   0xDC,   0xDD,   0xDE,   0xDF,   0xE0,   0xE1,
+    0xE2,   0xE3,   0xE4,   0xE5,   0xE6,   0xE7,   0xE8,
+    0xE9,   0xEA,   0xEB,   0xEC,   0xED,   0xEE,   0xEF,
+    0xF0,   0xF1,   0xF2,   0xF3,   0xF4,   0xF5,   0xF6,
+    0xF7,   0xF8,   0xF9,   0xFA,   0xFB,   0xFC,   0xFD,
+    0xFE,   0xFF
+
+};
+
+static const unsigned short uc437[] = {                     /*  CP437(U.S.) to Unicode conversion table */
+
+    0x00C7,     0x00FC,     0x00E9,     0x00E2,     0x00E4,
+    0x00E0,     0x00E5,     0x00E7,     0x00EA,     0x00EB,
+    0x00E8,     0x00EF,     0x00EE,     0x00EC,     0x00C4,
+    0x00C5,     0x00C9,     0x00E6,     0x00C6,     0x00F4,
+    0x00F6,     0x00F2,     0x00FB,     0x00F9,     0x00FF,
+    0x00D6,     0x00DC,     0x00A2,     0x00A3,     0x00A5,
+    0x20A7,     0x0192,     0x00E1,     0x00ED,     0x00F3,
+    0x00FA,     0x00F1,     0x00D1,     0x00AA,     0x00BA,
+    0x00BF,     0x2310,     0x00AC,     0x00BD,     0x00BC,
+    0x00A1,     0x00AB,     0x00BB,     0x2591,     0x2592,
+    0x2593,     0x2502,     0x2524,     0x2561,     0x2562,
+    0x2556,     0x2555,     0x2563,     0x2551,     0x2557,
+    0x255D,     0x255C,     0x255B,     0x2510,     0x2514,
+    0x2534,     0x252C,     0x251C,     0x2500,     0x253C,
+    0x255E,     0x255F,     0x255A,     0x2554,     0x2569,
+    0x2566,     0x2560,     0x2550,     0x256C,     0x2567,
+    0x2568,     0x2564,     0x2565,     0x2559,     0x2558,
+    0x2552,     0x2553,     0x256B,     0x256A,     0x2518,
+    0x250C,     0x2588,     0x2584,     0x258C,     0x2590,
+    0x2580,     0x03B1,     0x00DF,     0x0393,     0x03C0,
+    0x03A3,     0x03C3,     0x00B5,     0x03C4,     0x03A6,
+    0x0398,     0x03A9,     0x03B4,     0x221E,     0x03C6,
+    0x03B5,     0x2229,     0x2261,     0x00B1,     0x2265,
+    0x2264,     0x2320,     0x2321,     0x00F7,     0x2248,
+    0x00B0,     0x2219,     0x00B7,     0x221A,     0x207F,
+    0x00B2,     0x25A0,     0x00A0
+
+};
+
+static unsigned short uni2oem (unsigned int uni, short cp) {
+
+    const unsigned short *p = uc437;
+    unsigned short c = 0;
+    
+    if (uni < 0x80) {
+        c = (unsigned short) uni;
+    } else {
+    
+        (void) cp;
+        
+        if (uni < 0x10000) {
+        
+            for (c = 0; c < 0x80 && uni != p[c]; c++) {
+                ;
+            }
+            
+            c = (c + 0x80) & 0xff;
+        
+        }
+    
+    }
+    
+    return c;
+
+}
+
+static unsigned short oem2uni (unsigned short oem, short cp) {
+
+    const unsigned short *p = uc437;
+    unsigned short c = 0;
+    
+    if (oem < 0x80) {
+        c = oem;
+    } else {
+    
+        (void) cp;
+        
+        if (oem < 0x100) {
+            c = p[oem - 0x80];
+        }
+    
+    }
+    
+    return c;
+
+}
+
+static unsigned int tchar2uni (const char **str) {
+
+    const char *p = *str;
+    unsigned int uc;
+    
+    unsigned short wc = (unsigned char) *p++;
+    
+    if (wc != 0) {
+    
+        if ((wc = oem2uni (wc, 437)) == 0) {
+            return 0xffffffff;
+        }
+    
+    }
+    
+    uc = wc;
+    
+    *str = p;
+    return uc;
+
+};
+
+static int chk_chr (const char *str, int chr) {
+
+    while (*str && *str != chr) {
+        str++;
+    }
+    
+    return *str;
+
+}
+
+int create_name (struct fat_dirent *dp, const char *path) {
+
+    unsigned char b, cf;
+    unsigned short wc;
+    
+    const char *p = path;
+    unsigned int di = 0, uc, i, ni, si;
+    
+    for (;;) {
+    
+        uc = tchar2uni (&p);
+        
+        if (uc == 0xffffffff) {
+            return -1;
+        }
+        
+        if (uc >= 0x10000) {
+            dp->lfn[di++] = (unsigned short) (uc >> 16);
+        }
+        
+        wc = (unsigned short) uc;
+        
+        if (wc < ' ' || wc == '/' || wc == '\\') {
+            break;
+        }
+        
+        if (wc < 0x80 && chk_chr ("\"*:<>\?|\x7F", wc)) {
+            return -1;
+        }
+        
+        if (di >= LFN_MAX) {
+            return -1;
+        }
+        
+        dp->lfn[di++] = wc;
+    
+    }
+    
+    while (*p == '/' || *p == '\\') {
+        p++;
+    }
+    
+    cf = (wc < ' ') ? 4 : 0;
+    
+    while (di) {
+    
+        wc = dp->lfn[di - 1];
+        
+        if (wc != ' ' && wc != '.') {
+            break;
+        }
+        
+        di--;
+    
+    }
+    
+    dp->lfn[di] = 0;
+    
+    if (di == 0) {
+        return -1;
+    }
+    
+    for (si = 0; dp->lfn[si] == ' '; si++) {
+        ;
+    }
+    
+    if (si > 0 || dp->lfn[si] == '.') {
+        cf |= 3;
+    }
+    
+    while (di > 0 && dp->lfn[di - 1] != '.') {
+        di--;
+    }
+    
+    memset (dp->fn, ' ', 11);
+    i = b = 0; ni = 8;
+    
+    for (;;) {
+    
+        wc = dp->lfn[si++];
+        
+        if (wc == 0) {
+            break;
+        }
+        
+        if (wc == ' ' || (wc == '.' && si != di)) {
+        
+            cf |= 3;
+            continue;
+        
+        }
+        
+        if (i >= ni || si == di) {
+        
+            if (ni == 11) {
+            
+                cf |= 3;
+                break;
+            
+            }
+            
+            if (si != di) {
+                cf |= 3;
+            }
+            
+            if (si > di) {
+                break;
+            }
+            
+            si = di;
+            
+            i = 8;
+            ni = 11;
+            
+            b <<= 2;
+            continue;
+        
+        }
+        
+        if (wc >= 0x80) {
+        
+            cf |= 2;
+            
+            if ((wc = uni2oem (wc, 437)) & 0x80) {
+                wc = cvt[wc & 0x7f];
+            }
+        
+        }
+        
+        if (wc >= 0x100) {
+        
+            if (i >= ni - 1) {
+            
+                cf |= 3;
+                
+                i = ni;
+                continue;
+            
+            }
+            
+            dp->fn[i++] = (unsigned char) (wc >> 8);
+        
+        } else {
+        
+            if (wc == 0 || chk_chr ("+,;=[]", wc)) {
+                wc = '_'; cf |= 3;
+            } else {
+            
+                if (isupper ((int) wc)) {
+                    b |= 2;
+                }
+                
+                if (islower ((int) wc)) {
+                    b |= 1; wc -= 0x20;
+                }
+            
+            }
+        
+        }
+        
+        dp->fn[i++] = (unsigned char) wc;
+    
+    }
+    
+    if (dp->fn[0] == 0xe5) {
+        dp->fn[0] = 0x05;
+    }
+    
+    if (ni == 8) {
+        b <<= 2;
+    }
+    
+    if ((b & 0x0c) == 0x0c || (b & 0x03) == 0x03) {
+        cf |= 2;
+    }
+    
+    if (!(cf & 2)) {
+    
+        if (b & 0x01) {
+            cf |= 0x10;
+        }
+        
+        if (b & 0x04) {
+            cf |= 0x08;
+        }
+    
+    }
+    
+    dp->fn[11] = cf;
+    return 0;
+
+}
+
+void gen_numname (unsigned char *dst, const unsigned char *src, const unsigned short *lfn, unsigned int seq) {
+
+    unsigned char ns[8], c;
+    unsigned int i, j;
+    
+    unsigned short wc;
+    unsigned int sr;
+    
+    memcpy (dst, src, 11);
+    
+    if (seq > 5) {
+    
+        sr = seq;
+        
+        while (*lfn) {
+        
+            wc = *lfn++;
+            
+            for (i = 0; i < 16; i++) {
+            
+                sr = (sr << 1) + (wc & 1);
+                wc >>= 1;
+                
+                if (sr & 0x10000) {
+                    sr ^= 0x11021;
+                }
+            
+            }
+        
+        }
+        
+        seq = sr;
+    
+    }
+    
+    i = 7;
+    
+    do {
+    
+        c = ((seq % 16) + '0');
+        
+        if (c > '9') {
+            c += 7;
+        }
+        
+        ns[i--] = c;
+        seq /= 16;
+    
+    } while (seq);
+    
+    ns[i] = '~';
+    
+    for (j = 0; j < i && dst[j] != ' '; j++) {
+    
+        if (j == i - 1) {
+            break;
+        }
+    
+    }
+    
+    do {
+        dst[j++] = (i < 8) ? ns[i++] : ' ';
+    } while (j < 8);
+
+}
+
+
+static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
+
+unsigned int wtoupper (unsigned int uni) {
+
+    static const unsigned short cvt1[] = {                  /* Compressed up conversion table for U+0000 - U+0FFF */
+    
+        /* Basic Latin */
+        0x0061,     0x031A,
+        
+        /* Latin-1 Supplement */
+        0x00E0,     0x0317,     0x00F8,     0x0307,
+        0x00FF,     0x0001,     0x0178,
+        
+        /* Latin Extended-A */
+        0x0100,     0x0130,     0x0132,     0x0106,
+        0x0139,     0x0110,     0x014A,     0x012E,
+        0x0179,     0x0106,
+        
+        /* Latin Extended-B */
+        0x0180,     0x004D,     0x0243,     0x0181,
+        0x0182,     0x0182,     0x0184,     0x0184,
+        0x0186,     0x0187,     0x0187,     0x0189,
+        0x018A,     0x018B,     0x018B,     0x018D,
+        0x018E,     0x018F,     0x0190,     0x0191,
+        0x0191,     0x0193,     0x0194,     0x01F6,
+        0x0196,     0x0197,     0x0198,     0x0198,
+        0x023D,     0x019B,     0x019C,     0x019D,
+        0x0220,     0x019F,     0x01A0,     0x01A0,
+        0x01A2,     0x01A2,     0x01A4,     0x01A4,
+        0x01A6,     0x01A7,     0x01A7,     0x01A9,
+        0x01AA,     0x01AB,     0x01AC,     0x01AC,
+        0x01AE,     0x01AF,     0x01AF,     0x01B1,
+        0x01B2,     0x01B3,     0x01B3,     0x01B5,
+        0x01B5,     0x01B7,     0x01B8,     0x01B8,
+        0x01BA,     0x01BB,     0x01BC,     0x01BC,
+        0x01BE,     0x01F7,     0x01C0,     0x01C1,
+        0x01C2,     0x01C3,     0x01C4,     0x01C5,
+        0x01C4,     0x01C7,     0x01C8,     0x01C7,
+        0x01CA,     0x01CB,     0x01CA,     0x01CD,
+        0x0110,     0x01DD,     0x0001,     0x018E,
+        0x01DE,     0x0112,     0x01F3,     0x0003,
+        0x01F1,     0x01F4,     0x01F4,     0x01F8,
+        0x0128,     0x0222,     0x0112,     0x023A,
+        0x0009,     0x2C65,     0x023B,     0x023B,
+        0x023D,     0x2C66,     0x023F,     0x0240,
+        0x0241,     0x0241,     0x0246,     0x010A,
+        
+        /* IPA Extensions */
+        0x0253,     0x0040,     0x0181,     0x0186,
+        0x0255,     0x0189,     0x018A,     0x0258,
+        0x018F,     0x025A,     0x0190,     0x025C,
+        0x025D,     0x025E,     0x025F,     0x0193,
+        0x0261,     0x0262,     0x0194,     0x0264,
+        0x0265,     0x0266,     0x0267,     0x0197,
+        0x0196,     0x026A,     0x2C62,     0x026C,
+        0x026D,     0x026E,     0x019C,     0x0270,
+        0x0271,     0x019D,     0x0273,     0x0274,
+        0x019F,     0x0276,     0x0277,     0x0278,
+        0x0279,     0x027A,     0x027B,     0x027C,
+        0x2C64,     0x027E,     0x027F,     0x01A6,
+        0x0281,     0x0282,     0x01A9,     0x0284,
+        0x0285,     0x0286,     0x0287,     0x01AE,
+        0x0244,     0x01B1,     0x01B2,     0x0245,
+        0x028D,     0x028E,     0x028F,     0x0290,
+        0x0291,     0x01B7,
+        
+        /* Greek, Coptic */
+        0x037B,     0x0003,     0x03FD,     0x03FE,
+        0x03FF,     0x03AC,     0x0004,     0x0386,
+        0x0388,     0x0389,     0x038A,     0x03B1,
+        0x0311,     0x03C2,     0x0002,     0x03A3,
+        0x03A3,     0x03C4,     0x0308,     0x03CC,
+        0x0003,     0x038C,     0x038E,     0x038F,
+        0x03D8,     0x0118,     0x03F2,     0x000A,
+        0x03F9,     0x03F3,     0x03F4,     0x03F5,
+        0x03F6,     0x03F7,     0x03F7,     0x03F9,
+        0x03FA,     0x03FA,
+        
+        /* Cyrillic */
+        0x0430,     0x0320,     0x0450,     0x0710,
+        0x0460,     0x0122,     0x048A,     0x0136,
+        0x04C1,     0x010E,     0x04CF,     0x0001,
+        0x04C0,     0x04D0,     0x0144,
+        
+        /* Armenian */
+        0x0561,     0x0426,
+        
+        /* EOT */
+        0x0000
+    
+    };
+    
+    static const unsigned short cvt2[] = {                  /* Compressed up conversion table for U+1000 - U+FFFF */
+    
+        /* Phonetic Extensions */
+        0x1D7D,     0x0001,     0x2C63,
+        
+        /* Latin Extended Additional */
+        0x1E00,     0x0196,
+        0x1EA0,     0x015A,
+        
+        /* Greek Extended */
+        0x1F00,     0x0608,     0x1F10,     0x0606,
+        0x1F20,     0x0608,     0x1F30,     0x0608,
+        0x1F40,     0x0606,     0x1F51,     0x0007,
+        0x1F59,     0x1F52,     0x1F5B,     0x1F54,
+        0x1F5D,     0x1F56,     0x1F5F,     0x1F60,
+        0x0608,     0x1F70,     0x000E,     0x1FBA,
+        0x1FBB,     0x1FC8,     0x1FC9,     0x1FCA,
+        0x1FCB,     0x1FDA,     0x1FDB,     0x1FF8,
+        0x1FF9,     0x1FEA,     0x1FEB,     0x1FFA,
+        0x1FFB,     0x1F80,     0x0608,     0x1F90,
+        0x0608,     0x1FA0,     0x0608,     0x1FB0,
+        0x0004,     0x1FB8,     0x1FB9,     0x1FB2,
+        0x1FBC,     0x1FCC,     0x0001,     0x1FC3,
+        0x1FD0,     0x0602,     0x1FE0,     0x0602,
+        0x1FE5,     0x0001,     0x1FEC,     0x1FF3,
+        0x0001,     0x1FFC,
+        
+        /* Letterlike Symbols */
+        0x214E,     0x0001,     0x2132,
+        
+        /* Number forms */
+        0x2170,     0x0210,     0x2184,     0x0001,
+        0x2183,
+        
+        /* Enclosed Alphanumerics */
+        0x24D0,     0x051A,     0x2C30,     0x042F,
+        
+        /* Latin Extended-C */
+        0x2C60,     0x0102,     0x2C67,     0x0106,
+        0x2C75,     0x0102,
+        
+        /* Coptic */
+        0x2C80,     0x0164,
+        
+        /* Georgian Supplement */
+        0x2D00,     0x0826,
+        
+        /* Full-width */
+        0xFF41,     0x031A,
+        
+        /* EOT */
+        0x0000
+    
+    };
+    
+    const unsigned short *p;
+    unsigned short uc, bc, nc, cmd;
+    
+    if (uni < 0x10000) {
+    
+        uc = (unsigned short) uni;
+        p = uc < 0x1000 ? cvt1 : cvt2;
+        
+        for (;;) {
+        
+            bc = *p++;
+            
+            if (bc == 0 || uc < bc) {
+                break;
+            }
+            
+            nc = *p++; cmd = nc >> 8; nc &= 0xFF;
+            
+            if (uc < bc + nc) {
+            
+                switch (cmd) {
+                
+                    case 0:
+                    
+                        uc = p[uc - bc];
+                        break;
+                    
+                    case 1:
+                    
+                        uc -= (uc - bc) & 1;
+                        break;
+                    
+                    case 2:
+                    
+                        uc -= 16;
+                        break;
+                    
+                    case 3:
+                    
+                        uc -= 32;
+                        break;
+                    
+                    case 4:
+                    
+                        uc -= 48;
+                        break;
+                    
+                    case 5:
+                    
+                        uc -= 26;
+                        break;
+                    
+                    case 6:
+                    
+                        uc += 8;
+                        break;
+                    
+                    case 7:
+                    
+                        uc -= 80;
+                        break;
+                    
+                    case 8:
+                    
+                        uc -= 0x1C60;
+                        break;
+                
+                }
+                
+                break;
+            
+            }
+            
+            if (cmd == 0) {
+                p += nc;
+            }
+        
+        }
+        
+        uni = uc;
+    
+    }
+
+    return uni;
+
+}
+
+static unsigned short ld_word (const unsigned char *ptr) {
+    return ((unsigned short) ptr[0]) | (((unsigned short) ptr[1]) << 8);
+}
+
+int cmp_lfn (const unsigned short *lfnbuf, unsigned char *dir) {
+
+    unsigned short wc, uc;
+    unsigned int i, s;
+    
+    if (ld_word (dir + 26) != 0) {
+        return 0;
+    }
+    
+    i = ((*dir & 0x3f) - 1) * 13;
+    
+    for (wc = 1, s = 0; s < 13; s++) {
+    
+        uc = ld_word (dir + lfn_ofs[s]);
+        
+        if (wc != 0) {
+        
+            if (i >= LFN_MAX || wtoupper (uc) != wtoupper (lfnbuf[i++])) {
+                return 0;
+            }
+            
+            wc = uc;
+        
+        } else {
+        
+            if (uc != 0xffff) {
+                return 0;
+            }
+        
+        }
+    
+    }
+    
+    if ((*dir & 0x40) && wc && lfnbuf[i]) {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
+unsigned char sum_sfn (unsigned char *dir) {
+
+    unsigned char sum = 0;
+    unsigned int n = 11;
+    
+    do {
+        sum = (sum >> 1) + (sum << 7) + *dir++;
+    } while (--n);
+    
+    return sum;
+
+}
+
 
 unsigned short generate_datestamp (void) {
 
 
 unsigned short generate_datestamp (void) {
 
index 830c2c3962f2001f45874a1812fb7ae42cec91e1..501db4426833142f98516ccd148ee9bad9e10984 100644 (file)
--- a/common.h
+++ b/common.h
@@ -4,7 +4,22 @@
 #ifndef     _COMMON_H
 #define     _COMMON_H
 
 #ifndef     _COMMON_H
 #define     _COMMON_H
 
-extern unsigned short generate_datestamp (void);
-extern unsigned short generate_timestamp (void);
+#define     LFN_MAX                     255
+
+struct fat_dirent {
+
+    unsigned char fn[12];
+    unsigned short lfn[LFN_MAX];
+
+};
+
+int create_name (struct fat_dirent *dp, const char *path);
+void gen_numname (unsigned char *dst, const unsigned char *src, const unsigned short *lfn, unsigned int seq);
+
+int cmp_lfn (const unsigned short *lfnbuf, unsigned char *dir);
+unsigned char sum_sfn (unsigned char *dir);
+
+unsigned short generate_datestamp (void);
+unsigned short generate_timestamp (void);
 
 #endif      /* _COMMON_H */
 
 #endif      /* _COMMON_H */
diff --git a/mcopy.c b/mcopy.c
index 0c92b040273698ba37cfc98b4a39bf3ead728a2e..8c8bf46a60c31363e24de748bfbd7bd28cc48415 100644 (file)
--- a/mcopy.c
+++ b/mcopy.c
@@ -631,85 +631,117 @@ static int seekto (long offset) {
 }
 
 
 }
 
 
+static int dir_alloc (const char *path, struct dir_info *di, unsigned int nent);
+static int follow_path (const char *target, struct dir_info *di);
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
-static int open_dir (const char *target, struct dir_info *di);
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value);
 
 static unsigned int get_free_fat (unsigned char *scratch);
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value);
 
 static unsigned int get_free_fat (unsigned char *scratch);
+static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
 
 
-static int canonical_to_dir (char *dest, const char *src) {
+static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) {
 
 
-    static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
+    unsigned short wc;
+    unsigned int i, s;
     
     
-    int i, j;
-    int namelen = 0, dots = 0, extlen = 0;
+    memset (de, 0, sizeof (*de));
     
     
-    memset (dest, ' ', 11);
+    de->attr = ATTR_LONG_NAME;
+    de->type = 0;
+    de->csum = sum;
     
     
-    if (*src == '\0' || *src == '.') {
-        return -1;
-    }
+    write721_to_byte_array ((unsigned char *) de + 26, 0);
     
     
-    for (j = i = 0; *src != '\0'; i++) {
+    i = (ord - 1) * 13;
+    s = wc = 0;
     
     
-        int c = (unsigned char) *src++;
-        
-        if (c == '/' || c == '\\') {
-            break;
-        }
-        
-        if (i >= 12) {
-            return -1;
+    do {
+    
+        if (wc != 0xffff) {
+            wc = lfn[i++];
         }
         
         }
         
-        if (i == 0 && c == 0xE5) {
-        
-            /**
-             * 0xE5 in the first character of the name is a marker for delected files,
-             * it needs to be translated to 0x05.
-             */
-            c = 0x05;
-        
-        } else if (c == '.') {
-        
-            if (dots++) {
-                return -1;
-            }
-            
-            j = 8;
-            continue;
+        write721_to_byte_array ((unsigned char *) de + lfn_ofs[s], wc);
         
         
+        if (wc == 0) {
+            wc = 0xffff;
         }
         }
-        
-        if (c <= 0x20 || strchr (invalid_chars, c)) {
-            return -1;
+    
+    } while (++s < 13);
+    
+    if (wc == 0xffff || !lfn[i]) {
+        ord |= 0x40;
+    }
+    
+    de->name[0] = ord;
+
+}
+
+static int dir_find (const char *path, struct dir_info *di, struct fat_dirent *dp) {
+
+    struct msdos_dirent de;
+    unsigned char ord, sum, a, c;
+    
+    if (follow_path (path, di) < 0) {
+        return -1;
+    }
+    
+    ord = sum = 0xff;
+    
+    for (;;) {
+    
+        if (get_next_entry (di, &de) != 0) {
+            break;
         }
         
         }
         
-        if (dots) {
+        a = de.attr & 0x3f;
         
         
-            if (++extlen > 3) {
-                return -1;
-            }
+        if ((c = de.name[0]) == 0) {
+            break;
+        }
         
         
+        if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+            ord = 0xff;
         } else {
         
         } else {
         
-            if (++namelen > 8) {
-                return -1;
+            if (a == 15) {
+            
+                if (!(dp->fn[11] & 0x40)) {
+                
+                    if (c & 0x40) {
+                    
+                        sum = de.csum;
+                        
+                        c &= (unsigned char) ~0x40;
+                        ord = c;
+                    
+                    }
+                    
+                    ord = (c == ord && sum == de.csum && cmp_lfn (dp->lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                
+                }
+            
+            } else {
+            
+                if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                    return 0;    
+                }
+                
+                if (!(dp->fn[11] & 1) && !memcmp (&de, dp->fn, 11)) {
+                    return 0;
+                }
+                
+                ord = 0xff;
+            
             }
         
         }
             }
         
         }
-        
-        if (c >= 'a' && c <= 'z') {
-            c -= 'a' - 'A';
-        }
-        
-        dest[j++] = c;
     
     }
     
     
     }
     
-    return 0;
+    return 1;
 
 }
 
 
 }
 
@@ -968,12 +1000,228 @@ static int copy_file (const char *source, struct file_info *fi, const char *fnam
 
 }
 
 
 }
 
-static int get_free_dirent (const char *path, struct dir_info *di, struct msdos_dirent *de) {
+static int dir_alloc (const char *path, struct dir_info *di, unsigned int nent) {
 
 
+    struct dir_info temp_di;
+    struct msdos_dirent de;
+    
+    unsigned int n;
     int entry;
     int entry;
+    
+    if (follow_path (path, di) < 0) {
+        return -1;
+    }
+    
+    memcpy (&temp_di, di, sizeof (*di));
+    entry = n = 0;
+    
+    temp_di.flags |= 0x01;
+    di->flags |= 0x01;
+    
+    for (;;) {
+    
+        if ((entry = get_next_entry (&temp_di, &de)) != 0) {
+            return -1;
+        }
+        
+        if (entry == 0 && (!de.name[0] || de.name[0] == 0xe5)) {
+        
+            if (++n == nent) {
+                break;
+            }
+        
+        } else {
+        
+            memcpy (di, &temp_di, sizeof (*di));
+            n = 0;
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int follow_path (const char *target, struct dir_info *di) {
+
+    di->flags = 0;
+    
+    if (!strlen ((char *) target) || (strlen ((char *) target) == 1 && (target[0] == '/' || target[0] == '\\'))) {
+    
+        unsigned long offset;
+        
+        if (size_fat == 32) {
+        
+            di->current_cluster = root_cluster;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
+        
+        } else {
+        
+            di->current_cluster = 0;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) root_dir;
+        
+        }
+        
+        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+    
+    } else {
+    
+        unsigned char *ptr;
+        
+        struct fat_dirent dp;
+        struct msdos_dirent de;
+        
+        unsigned int result;
+        unsigned long offset;
+        
+        unsigned char a, ord, sum, c;
+        
+        if (size_fat == 32) {
+        
+            di->current_cluster = root_cluster;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
+        
+        } else {
+        
+            di->current_cluster = 0;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) root_dir;
+        
+        }
+        
+        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+        
+        ptr = (unsigned char *) target;
+        
+        while ((*ptr == '/' || *ptr == '\\') && *ptr) {
+            ptr++;
+        }
+        
+        while (*ptr) {
+        
+            memset (&dp, 0, sizeof (dp));
+            ord = sum = 0xff;
+            
+            if (create_name (&dp, (char *) ptr) < 0) {
+                return -1;
+            }
+            
+            de.name[0] = 0;
+            
+            for (;;) {
+            
+                if ((result = get_next_entry (di, &de)) != 0) {
+                    return -1;
+                }
+                
+                a = de.attr & 0x3f;
+                c = de.name[0];
+                
+                if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+                    ord = 0xff;
+                } else {
+                
+                    if (a == 15) {
+                    
+                        if (!(dp.fn[11] & 2)) {
+                        
+                            if (c & 0x40) {
+                            
+                                sum = de.csum;
+                                
+                                c &= (unsigned char) ~0x40;
+                                ord = c;
+                            
+                            }
+                            
+                            ord = (c == ord && sum == de.csum && cmp_lfn (dp.lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                            break;
+                        }
+                        
+                        if (!(dp.fn[11] & 1) && !memcmp (&de, dp.fn, 11)) {
+                            break;
+                        }
+                        
+                        ord = 0xff;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if ((de.attr & ATTR_DIR) == ATTR_DIR) {
+            
+                unsigned long offset;
+                
+                di->current_cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
+                di->current_entry = 0;
+                di->current_sector = 0;
+                
+                offset = (unsigned long) (data_area + ((di->current_cluster - 2) * sectors_per_cluster));
+                
+                if (seekto (offset * 512)) {
+                    return -1;
+                }
+                
+                if (fread (di->scratch, 512, 1, ofp) != 1) {
+                    return -1;
+                }
+            
+            } else if (!(de.attr & ATTR_DIR)) {
+                return -1;
+            }
+            
+            while (*ptr != '/' && *ptr != '\\' && *ptr) {
+                ptr++;
+            }
+            
+            if (*ptr == '/' || *ptr == '\\') {
+                ptr++;
+            }
+        
+        }
+        
+        if (!di->current_cluster) {
+            return -1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int get_free_dirent (const char *path, struct dir_info *di) {
+
+    struct msdos_dirent de;
+    int entry;
+    
     unsigned int i, tempclust;
     
     unsigned int i, tempclust;
     
-    if (open_dir (path, di) < 0) {
+    if (follow_path (path, di) < 0) {
         return -1;
     }
     
         return -1;
     }
     
@@ -982,13 +1230,13 @@ static int get_free_dirent (const char *path, struct dir_info *di, struct msdos_
     
     do {
     
     
     do {
     
-        entry = get_next_entry (di, de);
+        entry = get_next_entry (di, &de);
         
         /*if (entry == 0 && (!de->name[0] || de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)) {*/
         
         /*if (entry == 0 && (!de->name[0] || de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)) {*/
-        if (entry == 0 && (!de->name[0] || de->name[0] == 0xE5)) {
+        if (entry == 0 && (!de.name[0] || de.name[0] == 0xE5)) {
         
             /*if (de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) {*/
         
             /*if (de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) {*/
-            if (de->name[0] == 0xE5) {
+            if (de.name[0] == 0xE5) {
                 di->current_entry--;
             }
             
                 di->current_entry--;
             }
             
@@ -1173,144 +1421,26 @@ static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
 }
 
 
 }
 
-static int open_dir (const char *target, struct dir_info *di) {
-
-    di->flags = 0;
-    
-    if (!strlen ((char *) target) || (strlen ((char *) target) == 1 && (target[0] == '/' || target[0] == '\\'))) {
-    
-        unsigned long offset;
-        
-        if (size_fat == 32) {
-        
-            di->current_cluster = root_cluster;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
-        
-        } else {
-        
-            di->current_cluster = 0;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) root_dir;
-        
-        }
-        
-        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
-            return -1;
-        }
-    
-    } else {
-    
-        unsigned char tmpfn[12];
-        unsigned char *ptr;
-        
-        struct msdos_dirent de;
-        unsigned int result;
-        
-        unsigned long offset;
-        
-        if (size_fat == 32) {
-        
-            di->current_cluster = root_cluster;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
-        
-        } else {
-        
-            di->current_cluster = 0;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) root_dir;
-        
-        }
-        
-        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
-            return -1;
-        }
-        
-        ptr = (unsigned char *) target;
-        
-        while ((*ptr == '/' || *ptr == '\\') && *ptr) {
-            ptr++;
-        }
-        
-        while (*ptr) {
-        
-            if (canonical_to_dir ((char *) tmpfn, (char *) ptr) < 0) {
-            
-                fprintf (stderr, "Failed to convert to 8:3\n");
-                return -1;
-            
-            }
-            
-            de.name[0] = 0;
-            
-            do {
-                result = get_next_entry (di, &de);
-            } while (!result && memcmp (de.name, tmpfn, 11));
-            
-            if (!memcmp (de.name, tmpfn, 11) && (de.attr & ATTR_DIR) == ATTR_DIR) {
-            
-                unsigned long offset;
-                
-                di->current_cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
-                di->current_entry = 0;
-                di->current_sector = 0;
-                
-                offset = (unsigned long) (data_area + ((di->current_cluster - 2) * sectors_per_cluster));
-                
-                if (seekto (offset * 512)) {
-                    return -1;
-                }
-                
-                if (fread (di->scratch, 512, 1, ofp) != 1) {
-                    return -1;
-                }
-            
-            } else if (!memcmp (de.name, tmpfn, 11) && !(de.attr & ATTR_DIR)) {
-                return -1;
-            }
-            
-            while (*ptr != '/' && *ptr != '\\' && *ptr) {
-                ptr++;
-            }
-            
-            if (*ptr == '/' || *ptr == '\\') {
-                ptr++;
-            }
-        
-        }
-        
-        if (!di->current_cluster) {
-            return -1;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
 static int open_file (const char *target, unsigned char *scratch, struct file_info *fi) {
 
     unsigned char tmppath[PATH_MAX];
 static int open_file (const char *target, unsigned char *scratch, struct file_info *fi) {
 
     unsigned char tmppath[PATH_MAX];
-    unsigned char filename[12];
     unsigned char *p;
     
     unsigned char *p;
     
+    struct fat_dirent dp;
     struct dir_info di;
     struct msdos_dirent de;
     
     unsigned short date;
     unsigned short xtime;
     
     struct dir_info di;
     struct msdos_dirent de;
     
     unsigned short date;
     unsigned short xtime;
     
+    unsigned char a, ord, sum, c;
+    unsigned int nlen, nent;
+    
+    unsigned char sn[12];
+    unsigned int n;
+    
     unsigned int tempclust;
     unsigned int tempclust;
+    int overwrite = 0;
     
     /* Zero out file structure. */
     memset (fi, 0, sizeof (*fi));
     
     /* Zero out file structure. */
     memset (fi, 0, sizeof (*fi));
@@ -1343,11 +1473,10 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
         p++;
     }
     
         p++;
     }
     
-    if (canonical_to_dir ((char *) filename, (char *) p) < 0) {
+    memset (&dp, 0, sizeof (dp));
     
     
-        fprintf (stderr, "Failed to convert to 8:3\n");
+    if (create_name (&dp, (char *) p) < 0) {
         return -1;
         return -1;
-    
     }
     
     if (p > tmppath) {
     }
     
     if (p > tmppath) {
@@ -1360,111 +1489,214 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
     
     di.scratch = scratch;
     
     
     di.scratch = scratch;
     
-    if (open_dir ((char *) tmppath, &di) < 0) {
+    if (follow_path ((char *) tmppath, &di) < 0) {
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
     
     }
     
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
     
     }
     
-    while (!get_next_entry (&di, &de)) {
+    ord = sum = 0xff;
     
     
-        if (!memcmp (de.name, filename, 11)) {
+    for (;;) {
+    
+        if (get_next_entry (&di, &de) != 0) {
+            break;
+        }
         
         
-            di.current_entry--;
-            
-            if (de.attr & ATTR_DIR) {
-                return -1;
-            }
-            
-            if (!check_overwrite ((char *) target)) {
-                return 0;
-            }
+        a = de.attr & 0x3f;
+        
+        if ((c = de.name[0]) == 0) {
+            break;
+        }
+        
+        if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+            ord = 0xff;
+        } else {
+        
+            if (a == 15) {
             
             
-            fi->cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
+                if (!(dp.fn[11] & 0x40)) {
+                
+                    if (c & 0x40) {
+                    
+                        sum = de.csum;
+                        
+                        c &= (unsigned char) ~0x40;
+                        ord = c;
+                    
+                    }
+                    
+                    ord = (c == ord && sum == de.csum && cmp_lfn (dp.lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                
+                }
             
             
-            for (;;) {
+            } else {
             
             
-                if (size_fat == 12 && fi->cluster >= 0x0FF8) {
-                    break;
-                } else if (size_fat == 16 && fi->cluster >= 0xFFF8) {
-                    break;
-                } else if (size_fat == 32 && fi->cluster >= 0x0FFFFFF8) {
-                    break;
-                }
+                if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
                 
                 
-                tempclust = get_fat_entry (scratch, fi->cluster);
+                    di.current_entry--;
+                    
+                    if (de.attr & ATTR_DIR) {
+                        return -1;
+                    }
+                    
+                    if (!(overwrite = check_overwrite ((char *) target))) {
+                        return 0;
+                    }
+                    
+                    break;
                 
                 
-                if (set_fat_entry (scratch, fi->cluster, 0) < 0) {
-                    return -1;
                 }
                 
                 }
                 
-                fi->cluster = tempclust;
+                if (!(dp.fn[11] & 1) && !memcmp (&de, dp.fn, 11)) {
                 
                 
-                if (!fi->cluster || fi->cluster == 0x0FFFFFFF7) {
+                    di.current_entry--;
+                    
+                    if (de.attr & ATTR_DIR) {
+                        return -1;
+                    }
+                    
+                    if (!(overwrite = check_overwrite ((char *) target))) {
+                        return 0;
+                    }
+                    
                     break;
                     break;
+                
                 }
                 }
+                
+                ord = 0xff;
             
             }
             
             }
+        
+        }
+    
+    }
+    
+    if (overwrite) {
+    
+        fi->cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
+        
+        for (;;) {
+        
+            if (size_fat == 12 && fi->cluster >= 0x0FF8) {
+                break;
+            } else if (size_fat == 16 && fi->cluster >= 0xFFF8) {
+                break;
+            } else if (size_fat == 32 && fi->cluster >= 0x0FFFFFF8) {
+                break;
+            }
             
             
-            fi->cluster = 0;
+            tempclust = get_fat_entry (scratch, fi->cluster);
             
             
-            if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+            if (set_fat_entry (scratch, fi->cluster, 0) < 0) {
                 return -1;
             }
             
                 return -1;
             }
             
-            date = generate_datestamp ();
-            xtime = generate_timestamp ();
-            
-            memset (&de, 0, sizeof (de));
-            memcpy (de.name, filename, 11);
+            fi->cluster = tempclust;
             
             
-            de.attr = ATTR_ARCHIVE;
+            if (!fi->cluster || fi->cluster == 0x0FFFFFFF7) {
+                break;
+            }
+        
+        }
+        
+        fi->cluster = 0;
+        
+        if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+    
+    } else {
+    
+        for (nlen = 0; dp.lfn[nlen]; nlen++) {
+            ;
+        }
+        
+        memcpy (sn, dp.fn, 12);
+        
+        if (sn[11] & 1) {
+        
+            dp.fn[11] = 0x40;
             
             
-            write721_to_byte_array (de.xctime, xtime);
-            write721_to_byte_array (de.cdate, date);
-            write721_to_byte_array (de.adate, date);
-            write721_to_byte_array (de.xtime, xtime);
-            write721_to_byte_array (de.date, date);
+            for (n = 1; n < 100; n++) {
             
             
-            fi->pointer = 0;
+                gen_numname (dp.fn, sn, dp.lfn, n);
+                
+                if (dir_find ((char *) tmppath, &di, &dp) != 0) {
+                    break;
+                }
             
             
-            if (di.current_cluster == 0) {
-                fi->dir_sector = root_dir + di.current_sector;
-            } else {
-                fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster)  + di.current_sector;
             }
             
             }
             
-            /*fi->dir_offset = di.current_entry - 1;*/
-            fi->dir_offset = di.current_entry;
-            
-            if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+            if (n == 100) {
                 return -1;
             }
             
                 return -1;
             }
             
-            memcpy (&(((struct msdos_dirent *) scratch)[fi->dir_offset]), &de, sizeof (de));
+            dp.fn[11] = sn[11];
+        
+        }
+        
+        if (dp.fn[11] & 2) {
+            nent = (nlen + 12) / 13 + 1;
+        } else {
+            nent = 1;
+        }
+        
+        if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
+            return -1;
+        }
+        
+        if (--nent) {
+        
+            sum = sum_sfn (dp.fn);
             
             
-            if (seekto ((unsigned long) fi->dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
-                return -1;
-            }
+            do {
             
             
-            return 0;
+                if (get_free_dirent ((char *) tmppath, &di) < 0) {
+                    return -1;
+                }
+                
+                put_lfn (dp.lfn, nent, sum, &de);
+                
+                if (di.current_cluster == 0) {
+                    fi->dir_sector = root_dir + di.current_sector;
+                } else {
+                    fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster)  + di.current_sector;
+                }
+                
+                /*fi->dir_offset = di.current_entry - 1;*/
+                fi->dir_offset = di.current_entry;
+                
+                if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+                    return -1;
+                }
+                
+                memcpy (&(((struct msdos_dirent *) scratch)[fi->dir_offset]), &de, sizeof (de));
+                
+                if (seekto ((unsigned long) fi->dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
+                    return -1;
+                }
+            
+            } while (--nent);
         
         }
         
         }
+        
+        if (get_free_dirent ((char *) tmppath, &di) < 0) {
+            return -1;
+        }
+        
+        memset (&de, 0, sizeof (de));
+        memcpy (de.name, dp.fn, 11);
+        
+        de.attr = ATTR_ARCHIVE;
     
     }
     
     
     }
     
-    if (get_free_dirent ((char *) tmppath, &di, &de) < 0) {
-        return -1;
-    }
-    
     date = generate_datestamp ();
     xtime = generate_timestamp ();
     
     date = generate_datestamp ();
     xtime = generate_timestamp ();
     
-    memset (&de, 0, sizeof (de));
-    memcpy (de.name, filename, 11);
-    
-    de.attr = ATTR_ARCHIVE;
+    de.type = (dp.fn[11] & 0x18);
     
     write721_to_byte_array (de.xctime, xtime);
     write721_to_byte_array (de.cdate, date);
     
     write721_to_byte_array (de.xctime, xtime);
     write721_to_byte_array (de.cdate, date);
@@ -1480,7 +1712,6 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
         fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster)  + di.current_sector;
     }
     
         fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster)  + di.current_sector;
     }
     
-    /*fi->dir_offset = di.current_entry - 1;*/
     fi->dir_offset = di.current_entry;
     
     if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
     fi->dir_offset = di.current_entry;
     
     if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
@@ -1703,9 +1934,9 @@ static unsigned int get_free_fat (unsigned char *scratch) {
 int get_file (const char *source, unsigned char *scratch, struct file_info *fi) {
 
     unsigned char tmppath[PATH_MAX];
 int get_file (const char *source, unsigned char *scratch, struct file_info *fi) {
 
     unsigned char tmppath[PATH_MAX];
-    unsigned char filename[12];
     unsigned char *p;
     
     unsigned char *p;
     
+    struct fat_dirent dp;
     struct dir_info di;
     struct msdos_dirent de;
     
     struct dir_info di;
     struct msdos_dirent de;
     
@@ -1740,13 +1971,14 @@ int get_file (const char *source, unsigned char *scratch, struct file_info *fi)
         p++;
     }
     
         p++;
     }
     
-    if (canonical_to_dir ((char *) filename, (char *) p) < 0) {
+    memset (&dp, 0, sizeof (dp));
     
     
-        fprintf (stderr, "Failed to convert to 8:3\n");
+    if (create_name (&dp, (char *) p) < 0) {
         return -1;
         return -1;
-    
     }
     
     }
     
+    report_at (program_name, 0, REPORT_WARNING, "get_file: %ls - %.*s", dp.lfn, 11, dp.fn);
+    
     if (p > tmppath) {
         p--;
     }
     if (p > tmppath) {
         p--;
     }
@@ -1757,7 +1989,7 @@ int get_file (const char *source, unsigned char *scratch, struct file_info *fi)
     
     di.scratch = scratch;
     
     
     di.scratch = scratch;
     
-    if (open_dir ((char *) tmppath, &di) < 0) {
+    if (follow_path ((char *) tmppath, &di) < 0) {
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
@@ -1766,7 +1998,7 @@ int get_file (const char *source, unsigned char *scratch, struct file_info *fi)
     
     while (!get_next_entry (&di, &de)) {
     
     
     while (!get_next_entry (&di, &de)) {
     
-        if (!memcmp (de.name, filename, 11)) {
+        if (!memcmp (de.name, dp.fn, 11)) {
         
             di.current_entry--;
             
         
             di.current_entry--;
             
diff --git a/mls.c b/mls.c
index b8e311eb842fe8c07b59ccdeae264afaa188f35b..a53f2c763952a44d10ebed85878fc7ae548a35c8 100644 (file)
--- a/mls.c
+++ b/mls.c
@@ -343,84 +343,10 @@ static int seekto (long offset) {
 }
 
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
 }
 
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
-static int open_dir (const char *target, struct dir_info *di);
+static int follow_path (const char *target, struct dir_info *di);
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 
-static int canonical_to_dir (char *dest, const char *src) {
-
-    static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
-    
-    int i, j;
-    int namelen = 0, dots = 0, extlen = 0;
-    
-    memset (dest, ' ', 11);
-    
-    if (*src == '\0' || *src == '.') {
-        return -1;
-    }
-    
-    for (j = i = 0; *src != '\0'; i++) {
-    
-        int c = (unsigned char) *src++;
-        
-        if (c == '/' || c == '\\') {
-            break;
-        }
-        
-        if (i >= 12) {
-            return -1;
-        }
-        
-        if (i == 0 && c == 0xE5) {
-        
-            /**
-             * 0xE5 in the first character of the name is a marker for delected files,
-             * it needs to be translated to 0x05.
-             */
-            c = 0x05;
-        
-        } else if (c == '.') {
-        
-            if (dots++) {
-                return -1;
-            }
-            
-            j = 8;
-            continue;
-        
-        }
-        
-        if (c <= 0x20 || strchr (invalid_chars, c)) {
-            return -1;
-        }
-        
-        if (dots) {
-        
-            if (++extlen > 3) {
-                return -1;
-            }
-        
-        } else {
-        
-            if (++namelen > 8) {
-                return -1;
-            }
-        
-        }
-        
-        if (c >= 'a' && c <= 'z') {
-            c -= 'a' - 'A';
-        }
-        
-        dest[j++] = c;
-    
-    }
-    
-    return 0;
-
-}
-
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
     unsigned long offset;
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
     unsigned long offset;
@@ -500,7 +426,7 @@ static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
 }
 
 
 }
 
-static int open_dir (const char *target, struct dir_info *di) {
+static int follow_path (const char *target, struct dir_info *di) {
 
     di->flags = 0;
     
 
     di->flags = 0;
     
@@ -532,14 +458,16 @@ static int open_dir (const char *target, struct dir_info *di) {
     
     } else {
     
     
     } else {
     
-        unsigned char tmpfn[12];
         unsigned char *ptr;
         
         unsigned char *ptr;
         
+        struct fat_dirent dp;
         struct msdos_dirent de;
         struct msdos_dirent de;
-        unsigned int result;
         
         
+        unsigned int result;
         unsigned long offset;
         
         unsigned long offset;
         
+        unsigned char a, ord, sum, c;
+        
         if (size_fat == 32) {
         
             di->current_cluster = root_cluster;
         if (size_fat == 32) {
         
             di->current_cluster = root_cluster;
@@ -570,20 +498,67 @@ static int open_dir (const char *target, struct dir_info *di) {
         
         while (*ptr) {
         
         
         while (*ptr) {
         
-            if (canonical_to_dir ((char *) tmpfn, (char *) ptr) < 0) {
+            memset (&dp, 0, sizeof (dp));
+            ord = sum = 0xff;
             
             
-                fprintf (stderr, "Failed to convert to 8:3\n");
+            if (create_name (&dp, (char *) ptr) < 0) {
                 return -1;
                 return -1;
-            
             }
             
             de.name[0] = 0;
             
             }
             
             de.name[0] = 0;
             
-            do {
-                result = get_next_entry (di, &de);
-            } while (!result && memcmp (de.name, tmpfn, 11));
+            for (;;) {
+            
+                if ((result = get_next_entry (di, &de)) != 0) {
+                    return -1;
+                }
+                
+                a = de.attr & 0x3f;
+                
+                if ((c = de.name[0]) == 0) {
+                    return -1;
+                }
+                
+                if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+                    ord = 0xff;
+                } else {
+                
+                    if (a == 15) {
+                    
+                        if (!(dp.fn[11] & 0x40)) {
+                        
+                            if (c & 0x40) {
+                            
+                                sum = de.csum;
+                                
+                                c &= (unsigned char) ~0x40;
+                                ord = c;
+                            
+                            }
+                            
+                            ord = (c == ord && sum == de.csum && cmp_lfn (dp.lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                            break;
+                        }
+                        
+                        if (!(dp.fn[11] & 1) && !memcmp (&de, dp.fn, 11)) {
+                            break;
+                        }
+                        
+                        ord = 0xff;
+                    
+                    }
+                
+                }
+            
+            }
             
             
-            if (!memcmp (de.name, tmpfn, 11) && (de.attr & ATTR_DIR) == ATTR_DIR) {
+            if ((de.attr & ATTR_DIR) == ATTR_DIR) {
             
                 unsigned long offset;
                 
             
                 unsigned long offset;
                 
@@ -601,7 +576,7 @@ static int open_dir (const char *target, struct dir_info *di) {
                     return -1;
                 }
             
                     return -1;
                 }
             
-            } else if (!memcmp (de.name, tmpfn, 11) && !(de.attr & ATTR_DIR)) {
+            } else if (!(de.attr & ATTR_DIR)) {
                 return -1;
             }
             
                 return -1;
             }
             
@@ -966,7 +941,7 @@ int main (int argc, char **argv) {
             target++;
         }
         
             target++;
         }
         
-        if (open_dir ((char *) target, &di) < 0) {
+        if (follow_path ((char *) target, &di) < 0) {
         
             fprintf (stderr, "failed to open directory\n");
             return -1;
         
             fprintf (stderr, "failed to open directory\n");
             return -1;
@@ -990,27 +965,29 @@ int main (int argc, char **argv) {
                 continue;
             }
             
                 continue;
             }
             
-            if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID) {
+            if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID || de.attr == ATTR_LONG_NAME) {
                 continue;
             }
             
             memset (filename, 0, 13);
             
                 continue;
             }
             
             memset (filename, 0, 13);
             
-            for (j = 0, k = 0; j < 11; ++j) {
+            for (j = 0, k = 0; j < 11;) {
             
             
-                if (j < 8 && de.name[j] == ' ') {
+                if (j < 8) {
                 
                 
-                    if ((de.attr & ATTR_DIR) != ATTR_DIR && k > 0 && filename[k - 1] != '.') {
-                        filename[k++] = '.';
+                    if (de.name[j] == ' ') {
+                        j = 8;
+                    } else {
+                        filename[k++] = de.name[j++];
                     }
                 
                 } else {
                 
                     }
                 
                 } else {
                 
-                    if (j == 8 && (de.attr & ATTR_DIR) != ATTR_DIR && filename[k - 1] != '.') {
+                    if (j == 8 && de.name[j] != ' ' && (de.attr & ATTR_DIR) != ATTR_DIR && filename[k - 1] != '.') {
                         filename[k++] = '.';
                     }
                     
                         filename[k++] = '.';
                     }
                     
-                    filename[k++] = de.name[j];
+                    filename[k++] = de.name[j++];
                 
                 }
             
                 
                 }
             
diff --git a/mmd.c b/mmd.c
index e481889f5ee6d69134a4b0889c383433171e2993..edc69fcbf5b8b92015c2aa24759ca508eec5a114 100644 (file)
--- a/mmd.c
+++ b/mmd.c
@@ -334,96 +334,128 @@ static int seekto (long offset) {
 }
 
 
 }
 
 
-static int create_dir (const char *target, unsigned char *scratch);
+static int dir_alloc (const char *path, struct dir_info *di, unsigned int nent);
+static int follow_path (const char *target, struct dir_info *di);
+
+static int get_free_dirent (const char *path, struct dir_info *di);
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de);
-static int get_free_dirent (const char *path, struct dir_info *di, struct msdos_dirent *de);
-static int open_dir (const char *target, struct dir_info *di);
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value);
 
 static unsigned int get_free_fat (unsigned char *scratch);
 
 static unsigned int get_fat_entry (unsigned char *scratch, unsigned int cluster);
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value);
 
 static unsigned int get_free_fat (unsigned char *scratch);
+static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
 
 
-static int canonical_to_dir (char *dest, const char *src) {
+static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) {
 
 
-    static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|";
+    unsigned short wc;
+    unsigned int i, s;
     
     
-    int i, j;
-    int namelen = 0, dots = 0, extlen = 0;
+    memset (de, 0, sizeof (*de));
     
     
-    memset (dest, ' ', 11);
+    de->attr = ATTR_LONG_NAME;
+    de->type = 0;
+    de->csum = sum;
     
     
-    if (*src == '\0' || *src == '.') {
-        return -1;
-    }
+    write721_to_byte_array ((unsigned char *) de + 26, 0);
     
     
-    for (j = i = 0; *src != '\0'; i++) {
+    i = (ord - 1) * 13;
+    s = wc = 0;
     
     
-        int c = (unsigned char) *src++;
-        
-        if (c == '/' || c == '\\') {
-            break;
-        }
-        
-        if (i >= 12) {
-            return -1;
+    do {
+    
+        if (wc != 0xffff) {
+            wc = lfn[i++];
         }
         
         }
         
-        if (i == 0 && c == 0xE5) {
-        
-            /**
-             * 0xE5 in the first character of the name is a marker for delected files,
-             * it needs to be translated to 0x05.
-             */
-            c = 0x05;
-        
-        } else if (c == '.') {
-        
-            if (dots++) {
-                return -1;
-            }
-            
-            j = 8;
-            continue;
+        write721_to_byte_array ((unsigned char *) de + lfn_ofs[s], wc);
         
         
+        if (wc == 0) {
+            wc = 0xffff;
         }
         }
-        
-        if (c <= 0x20 || strchr (invalid_chars, c)) {
-            return -1;
+    
+    } while (++s < 13);
+    
+    if (wc == 0xffff || !lfn[i]) {
+        ord |= 0x40;
+    }
+    
+    de->name[0] = ord;
+
+}
+
+static int dir_find (const char *path, struct dir_info *di, struct fat_dirent *dp) {
+
+    struct msdos_dirent de;
+    unsigned char ord, sum, a, c;
+    
+    if (follow_path (path, di) < 0) {
+        return -1;
+    }
+    
+    ord = sum = 0xff;
+    
+    for (;;) {
+    
+        if (get_next_entry (di, &de) != 0) {
+            break;
         }
         
         }
         
-        if (dots) {
+        a = de.attr & 0x3f;
         
         
-            if (++extlen > 3) {
-                return -1;
-            }
+        if ((c = de.name[0]) == 0) {
+            break;
+        }
         
         
+        if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+            ord = 0xff;
         } else {
         
         } else {
         
-            if (++namelen > 8) {
-                return -1;
+            if (a == 15) {
+            
+                if (!(dp->fn[11] & 0x40)) {
+                
+                    if (c & 0x40) {
+                    
+                        sum = de.csum;
+                        
+                        c &= (unsigned char) ~0x40;
+                        ord = c;
+                    
+                    }
+                    
+                    ord = (c == ord && sum == de.csum && cmp_lfn (dp->lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                
+                }
+            
+            } else {
+            
+                if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                    return 0;    
+                }
+                
+                if (!(dp->fn[11] & 1) && !memcmp (&de, dp->fn, 11)) {
+                    return 0;
+                }
+                
+                ord = 0xff;
+            
             }
         
         }
             }
         
         }
-        
-        if (c >= 'a' && c <= 'z') {
-            c -= 'a' - 'A';
-        }
-        
-        dest[j++] = c;
     
     }
     
     
     }
     
-    return 0;
+    return 1;
 
 }
 
 static int create_dir (const char *target, unsigned char *scratch) {
 
     unsigned char tmppath[PATH_MAX];
 
 }
 
 static int create_dir (const char *target, unsigned char *scratch) {
 
     unsigned char tmppath[PATH_MAX];
-    unsigned char filename[12];
     unsigned char *p;
     
     unsigned char *p;
     
+    struct fat_dirent dp;
     struct dir_info di;
     struct msdos_dirent de;
     
     struct dir_info di;
     struct msdos_dirent de;
     
@@ -434,6 +466,12 @@ static int create_dir (const char *target, unsigned char *scratch) {
     unsigned int dir_sector;
     unsigned int dir_offset;
     
     unsigned int dir_sector;
     unsigned int dir_offset;
     
+    unsigned char a, ord, sum, c;
+    unsigned int nlen, nent;
+    
+    unsigned char sn[12];
+    unsigned int n;
+    
     /* Get a local copy of the target.  If it's larger than PATH_MAX, abort. */
     strncpy ((char *) tmppath, (char *) target, PATH_MAX);
     tmppath[PATH_MAX - 1] = 0;
     /* Get a local copy of the target.  If it's larger than PATH_MAX, abort. */
     strncpy ((char *) tmppath, (char *) target, PATH_MAX);
     tmppath[PATH_MAX - 1] = 0;
@@ -462,11 +500,10 @@ static int create_dir (const char *target, unsigned char *scratch) {
         p++;
     }
     
         p++;
     }
     
-    if (canonical_to_dir ((char *) filename, (char *) p) < 0) {
+    memset (&dp, 0, sizeof (dp));
     
     
-        fprintf (stderr, "Failed to convert to 8:3\n");
+    if (create_name (&dp, (char *) p) < 0) {
         return -1;
         return -1;
-    
     }
     
     if (p > tmppath) {
     }
     
     if (p > tmppath) {
@@ -479,30 +516,146 @@ static int create_dir (const char *target, unsigned char *scratch) {
     
     di.scratch = scratch;
     
     
     di.scratch = scratch;
     
-    if (open_dir ((char *) tmppath, &di) < 0) {
+    if (follow_path ((char *) tmppath, &di) < 0) {
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
     
     }
     
     
         fprintf (stderr, "Failed to open directory\n");
         return -1;
     
     }
     
-    while (!get_next_entry (&di, &de)) {
+    ord = sum = 0xff;
     
     
-        /*if (!de.name[0] || de.name[0] == 0xE5 || (de.attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) {*/
-        if (!de.name[0] || de.name[0] == 0xE5) {
-            continue;
+    for (;;) {
+    
+        if (get_next_entry (&di, &de) != 0) {
+            break;
         }
         
         }
         
-        if (!memcmp (de.name, filename, 11)) {
+        a = de.attr & 0x3f;
         
         
-            fprintf (stderr, "%s already exists.\n", target);
-            return -1;
+        if ((c = de.name[0]) == 0) {
+            break;
+        }
+        
+        if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+            ord = 0xff;
+        } else {
+        
+            if (a == 15) {
+            
+                if (!(dp.fn[11] & 0x40)) {
+                
+                    if (c & 0x40) {
+                    
+                        sum = de.csum;
+                        
+                        c &= (unsigned char) ~0x40;
+                        ord = c;
+                    
+                    }
+                    
+                    ord = (c == ord && sum == de.csum && cmp_lfn (dp.lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                
+                }
+            
+            } else {
+            
+                if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "%s already exists", target);
+                    return -1;
+                
+                }
+                
+                if (!(dp.fn[11] & 1) && !memcmp (&de, dp.fn, 11)) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "%s already exists", target);
+                    return -1;
+                
+                }
+                
+                ord = 0xff;
+            
+            }
         
         }
     
     }
     
         
         }
     
     }
     
-    if (get_free_dirent ((char *) tmppath, &di, &de) < 0) {
+    for (nlen = 0; dp.lfn[nlen]; nlen++) {
+        ;
+    }
+    
+    memcpy (sn, dp.fn, 12);
+    
+    if (sn[11] & 1) {
+    
+        dp.fn[11] = 0x40;
+        
+        for (n = 1; n < 100; n++) {
+        
+            gen_numname (dp.fn, sn, dp.lfn, n);
+            
+            if (dir_find ((char *) tmppath, &di, &dp) != 0) {
+                break;
+            }
+        
+        }
+        
+        if (n == 100) {
+            return -1;
+        }
+        
+        dp.fn[11] = sn[11];
+    
+    }
+    
+    if (dp.fn[11] & 2) {
+        nent = (nlen + 12) / 13 + 1;
+    } else {
+        nent = 1;
+    }
+    
+    if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
+        return -1;
+    }
+    
+    if (--nent) {
+    
+        sum = sum_sfn (dp.fn);
+        
+        do {
+        
+            if (get_free_dirent ((char *) tmppath, &di) < 0) {
+                return -1;
+            }
+            
+            put_lfn (dp.lfn, nent, sum, &de);
+            
+            if (di.current_cluster == 0) {
+                dir_sector = root_dir + di.current_sector;
+            } else {
+                dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector;
+            }
+            
+            /*fi->dir_offset = di.current_entry - 1;*/
+            dir_offset = di.current_entry;
+            
+            if (seekto ((unsigned long) dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+                return -1;
+            }
+            
+            memcpy (&(((struct msdos_dirent *) scratch)[dir_offset]), &de, sizeof (de));
+            
+            if (seekto ((unsigned long) dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
+                return -1;
+            }
+        
+        } while (--nent);
+    
+    }
+    
+    if (get_free_dirent ((char *) tmppath, &di) < 0) {
         return -1;
     }
     
         return -1;
     }
     
@@ -510,7 +663,7 @@ static int create_dir (const char *target, unsigned char *scratch) {
     xtime = generate_timestamp ();
     
     memset (&de, 0, sizeof (de));
     xtime = generate_timestamp ();
     
     memset (&de, 0, sizeof (de));
-    memcpy (de.name, filename, 11);
+    memcpy (de.name, dp.fn, 11);
     
     cluster = get_free_fat (scratch);
     
     
     cluster = get_free_fat (scratch);
     
@@ -522,6 +675,7 @@ static int create_dir (const char *target, unsigned char *scratch) {
     write721_to_byte_array (de.starthi, cluster >> 16);
     
     de.attr = ATTR_DIR;
     write721_to_byte_array (de.starthi, cluster >> 16);
     
     de.attr = ATTR_DIR;
+    de.type = (dp.fn[11] & 0x18);
     
     write721_to_byte_array (de.xctime, xtime);
     write721_to_byte_array (de.cdate, date);
     
     write721_to_byte_array (de.xctime, xtime);
     write721_to_byte_array (de.cdate, date);
@@ -627,12 +781,234 @@ static int create_dir (const char *target, unsigned char *scratch) {
 
 }
 
 
 }
 
-static int get_free_dirent (const char *path, struct dir_info *di, struct msdos_dirent *de) {
+static int dir_alloc (const char *path, struct dir_info *di, unsigned int nent) {
 
 
+    struct dir_info temp_di;
+    struct msdos_dirent de;
+    
+    unsigned int n;
     int entry;
     int entry;
+    
+    if (follow_path (path, di) < 0) {
+        return -1;
+    }
+    
+    memcpy (&temp_di, di, sizeof (*di));
+    entry = n = 0;
+    
+    temp_di.flags |= 0x01;
+    di->flags |= 0x01;
+    
+    for (;;) {
+    
+        if ((entry = get_next_entry (&temp_di, &de)) != 0) {
+            return -1;
+        }
+        
+        if (entry == 0 && (!de.name[0] || de.name[0] == 0xe5)) {
+        
+            if (++n == nent) {
+                break;
+            }
+        
+        } else {
+        
+            memcpy (di, &temp_di, sizeof (*di));
+            n = 0;
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int follow_path (const char *target, struct dir_info *di) {
+
+    di->flags = 0;
+    
+    if (!strlen ((char *) target) || (strlen ((char *) target) == 1 && (target[0] == '/' || target[0] == '\\'))) {
+    
+        unsigned long offset;
+        
+        if (size_fat == 32) {
+        
+            di->current_cluster = root_cluster;
+            di->root_cluster = root_cluster;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
+        
+        } else {
+        
+            di->current_cluster = 0;
+            di->root_cluster = 0;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) root_dir;
+        
+        }
+        
+        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+    
+    } else {
+    
+        unsigned char *ptr;
+        
+        struct fat_dirent dp;
+        struct msdos_dirent de;
+        
+        unsigned int result;
+        unsigned long offset;
+        
+        unsigned char a, ord, sum, c;
+        
+        if (size_fat == 32) {
+        
+            di->current_cluster = root_cluster;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
+        
+        } else {
+        
+            di->current_cluster = 0;
+            di->current_entry = 0;
+            di->current_sector = 0;
+            
+            offset = (unsigned long) root_dir;
+        
+        }
+        
+        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+        
+        ptr = (unsigned char *) target;
+        
+        while ((*ptr == '/' || *ptr == '\\') && *ptr) {
+            ptr++;
+        }
+        
+        while (*ptr) {
+        
+            memset (&dp, 0, sizeof (dp));
+            ord = sum = 0xff;
+            
+            if (create_name (&dp, (char *) ptr) < 0) {
+                return -1;
+            }
+            
+            de.name[0] = 0;
+            
+            for (;;) {
+            
+                if ((result = get_next_entry (di, &de)) != 0) {
+                    return -1;
+                }
+                
+                a = de.attr & 0x3f;
+                
+                if ((c = de.name[0]) == 0) {
+                    return -1;
+                }
+                
+                if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+                    ord = 0xff;
+                } else {
+                
+                    if (a == 15) {
+                    
+                        if (!(dp.fn[11] & 0x40)) {
+                        
+                            if (c & 0x40) {
+                            
+                                sum = de.csum;
+                                
+                                c &= (unsigned char) ~0x40;
+                                ord = c;
+                            
+                            }
+                            
+                            ord = (c == ord && sum == de.csum && cmp_lfn (dp.lfn, (unsigned char *) &de)) ? ord - 1 : 0xff;
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (ord == 0 && sum == sum_sfn ((unsigned char *) &de)) {
+                            break;
+                        }
+                        
+                        if (!(dp.fn[11] & 1) && !memcmp (&de, dp.fn, 11)) {
+                            break;
+                        }
+                        
+                        ord = 0xff;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if ((de.attr & ATTR_DIR) == ATTR_DIR) {
+            
+                unsigned long offset;
+                
+                di->current_cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
+                di->root_cluster = di->current_cluster;
+                di->current_entry = 0;
+                di->current_sector = 0;
+                
+                offset = (unsigned long) (data_area + ((di->current_cluster - 2) * sectors_per_cluster));
+                
+                if (seekto (offset * 512)) {
+                    return -1;
+                }
+                
+                if (fread (di->scratch, 512, 1, ofp) != 1) {
+                    return -1;
+                }
+            
+            } else if (!(de.attr & ATTR_DIR)) {
+                return -1;
+            }
+            
+            while (*ptr != '/' && *ptr != '\\' && *ptr) {
+                ptr++;
+            }
+            
+            if (*ptr == '/' || *ptr == '\\') {
+                ptr++;
+            }
+        
+        }
+        
+        if (!di->current_cluster) {
+            return -1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int get_free_dirent (const char *path, struct dir_info *di) {
+
+    struct msdos_dirent de;
+    int entry;
+    
     unsigned int i, tempclust;
     
     unsigned int i, tempclust;
     
-    if (open_dir (path, di) < 0) {
+    if (follow_path (path, di) < 0) {
         return -1;
     }
     
         return -1;
     }
     
@@ -641,13 +1017,11 @@ static int get_free_dirent (const char *path, struct dir_info *di, struct msdos_
     
     do {
     
     
     do {
     
-        entry = get_next_entry (di, de);
+        entry = get_next_entry (di, &de);
         
         
-        /*if (entry == 0 && (!de->name[0] || de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)) {*/
-        if (entry == 0 && (!de->name[0] || de->name[0] == 0xE5)) {
+        if (entry == 0 && (!de.name[0] || de.name[0] == 0xE5)) {
         
         
-            /*if (de->name[0] == 0xE5 || (de->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) {*/
-            if (de->name[0] == 0xE5) {
+            if (de.name[0] == 0xE5) {
                 di->current_entry--;
             }
             
                 di->current_entry--;
             }
             
@@ -811,134 +1185,6 @@ static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
 }
 
 
 }
 
-static int open_dir (const char *target, struct dir_info *di) {
-
-    di->flags = 0;
-    
-    if (!strlen ((char *) target) || (strlen ((char *) target) == 1 && (target[0] == '/' || target[0] == '\\'))) {
-    
-        unsigned long offset;
-        
-        if (size_fat == 32) {
-        
-            di->current_cluster = root_cluster;
-            di->root_cluster = root_cluster;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
-        
-        } else {
-        
-            di->current_cluster = 0;
-            di->root_cluster = 0;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) root_dir;
-        
-        }
-        
-        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
-            return -1;
-        }
-    
-    } else {
-    
-        unsigned char tmpfn[12];
-        unsigned char *ptr;
-        
-        struct msdos_dirent de;
-        unsigned int result;
-        
-        unsigned long offset;
-        
-        if (size_fat == 32) {
-        
-            di->current_cluster = root_cluster;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster);
-        
-        } else {
-        
-            di->current_cluster = 0;
-            di->current_entry = 0;
-            di->current_sector = 0;
-            
-            offset = (unsigned long) root_dir;
-        
-        }
-        
-        if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
-            return -1;
-        }
-        
-        ptr = (unsigned char *) target;
-        
-        while ((*ptr == '/' || *ptr == '\\') && *ptr) {
-            ptr++;
-        }
-        
-        while (*ptr) {
-        
-            if (canonical_to_dir ((char *) tmpfn, (char *) ptr) < 0) {
-            
-                fprintf (stderr, "Failed to convert to 8:3\n");
-                return -1;
-            
-            }
-            
-            de.name[0] = 0;
-            
-            do {
-                result = get_next_entry (di, &de);
-            } while (!result && memcmp (de.name, tmpfn, 11));
-            
-            if (!memcmp (de.name, tmpfn, 11) && (de.attr & ATTR_DIR) == ATTR_DIR) {
-            
-                unsigned long offset;
-                
-                di->current_cluster = (unsigned int) de.startlo[0] | ((unsigned int) de.startlo[1]) << 8 | ((unsigned int) de.starthi[0]) << 16 | ((unsigned int) de.starthi[1]) << 24;
-                di->root_cluster = di->current_cluster;
-                di->current_entry = 0;
-                di->current_sector = 0;
-                
-                offset = (unsigned long) (data_area + ((di->current_cluster - 2) * sectors_per_cluster));
-                
-                if (seekto (offset * 512)) {
-                    return -1;
-                }
-                
-                if (fread (di->scratch, 512, 1, ofp) != 1) {
-                    return -1;
-                }
-            
-            } else if (!memcmp (de.name, tmpfn, 11) && !(de.attr & ATTR_DIR)) {
-                return -1;
-            }
-            
-            while (*ptr != '/' && *ptr != '\\' && *ptr) {
-                ptr++;
-            }
-            
-            if (*ptr == '/' || *ptr == '\\') {
-                ptr++;
-            }
-        
-        }
-        
-        if (!di->current_cluster) {
-            return -1;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value) {
 
     unsigned int i, offset, sector;
 static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned int value) {
 
     unsigned int i, offset, sector;
diff --git a/msdos.h b/msdos.h
index a4b4e4f13d4b311dc524ef3f613ebb5a0bfd6da0..b104ea3c7dab2847dbf0b7e885f5696b3855ccbf 100644 (file)
--- a/msdos.h
+++ b/msdos.h
@@ -39,7 +39,7 @@
 #define     ATTR_VOLUME_ID              0x08
 #define     ATTR_DIR                    0x10
 #define     ATTR_ARCHIVE                0x20
 #define     ATTR_VOLUME_ID              0x08
 #define     ATTR_DIR                    0x10
 #define     ATTR_ARCHIVE                0x20
-/*#define     ATTR_LONG_NAME              (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)*/
+#define     ATTR_LONG_NAME              (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
 
 struct msdos_volume_info {
 
 
 struct msdos_volume_info {
 
@@ -115,8 +115,8 @@ struct msdos_dirent {
 
     unsigned char name[11];
     unsigned char attr;
 
     unsigned char name[11];
     unsigned char attr;
-    unsigned char lcase;
-    unsigned char ctime_cs;
+    unsigned char type;
+    unsigned char csum;
     unsigned char xctime[2];
     unsigned char cdate[2];
     unsigned char adate[2];
     unsigned char xctime[2];
     unsigned char cdate[2];
     unsigned char adate[2];