[BACK]Return to msdosfs_conv.c CVS log [TXT][DIR] Up to [local] / sys / msdosfs

Annotation of sys/msdosfs/msdosfs_conv.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: msdosfs_conv.c,v 1.13 2004/05/14 04:05:05 tedu Exp $  */
                      2: /*     $NetBSD: msdosfs_conv.c,v 1.24 1997/10/17 11:23:54 ws Exp $     */
                      3:
                      4: /*-
                      5:  * Copyright (C) 1995, 1997 Wolfgang Solfrank.
                      6:  * Copyright (C) 1995, 1997 TooLs GmbH.
                      7:  * All rights reserved.
                      8:  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by TooLs GmbH.
                     21:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
                     22:  *    derived from this software without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
                     25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     27:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     28:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     29:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     30:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     31:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     32:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     33:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: /*
                     36:  * Written by Paul Popelka (paulp@uts.amdahl.com)
                     37:  *
                     38:  * You can do anything you want with this software, just don't say you wrote
                     39:  * it, and don't remove this notice.
                     40:  *
                     41:  * This software is provided "as is".
                     42:  *
                     43:  * The author supplies this software to be publicly redistributed on the
                     44:  * understanding that the author is not responsible for the correct
                     45:  * functioning of this software in any circumstances and is not liable for
                     46:  * any damages caused by this software.
                     47:  *
                     48:  * October 1992
                     49:  */
                     50:
                     51: /*
                     52:  * System include files.
                     53:  */
                     54: #include <sys/param.h>
                     55: #include <sys/systm.h>
                     56: #include <sys/time.h>
                     57: #include <sys/kernel.h>                /* defines tz */
                     58: #include <sys/dirent.h>
                     59: #include <sys/vnode.h>
                     60:
                     61: /*
                     62:  * MSDOSFS include files.
                     63:  */
                     64: #include <msdosfs/direntry.h>
                     65: #include <msdosfs/denode.h>
                     66:
                     67: /*
                     68:  * Days in each month in a regular year.
                     69:  */
                     70: const u_short regyear[] = {
                     71:        31, 28, 31, 30, 31, 30,
                     72:        31, 31, 30, 31, 30, 31
                     73: };
                     74:
                     75: /*
                     76:  * Days in each month in a leap year.
                     77:  */
                     78: const u_short leapyear[] = {
                     79:        31, 29, 31, 30, 31, 30,
                     80:        31, 31, 30, 31, 30, 31
                     81: };
                     82:
                     83: /*
                     84:  * Variables used to remember parts of the last time conversion.  Maybe we
                     85:  * can avoid a full conversion.
                     86:  */
                     87: uint32_t lasttime;
                     88: uint32_t lastday;
                     89: u_short lastddate;
                     90: u_short lastdtime;
                     91:
                     92: /*
                     93:  * Convert the unix version of time to dos's idea of time to be used in
                     94:  * file timestamps. The passed in unix time is assumed to be in GMT.
                     95:  */
                     96: void
                     97: unix2dostime(tsp, ddp, dtp, dhp)
                     98:        struct timespec *tsp;
                     99:        u_int16_t *ddp;
                    100:        u_int16_t *dtp;
                    101:        u_int8_t *dhp;
                    102: {
                    103:        uint32_t t;
                    104:        uint32_t days;
                    105:        uint32_t inc;
                    106:        uint32_t year;
                    107:        uint32_t month;
                    108:        const u_short *months;
                    109:
                    110:        /*
                    111:         * If the time from the last conversion is the same as now, then
                    112:         * skip the computations and use the saved result.
                    113:         */
                    114:        t = tsp->tv_sec - (tz.tz_minuteswest * 60)
                    115:             /* +- daylight saving time correction */ ;
                    116:        t &= ~1;
                    117:        if (lasttime != t) {
                    118:                lasttime = t;
                    119:                lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
                    120:                    + (((t / 60) % 60) << DT_MINUTES_SHIFT)
                    121:                    + (((t / 3600) % 24) << DT_HOURS_SHIFT);
                    122:
                    123:                /*
                    124:                 * If the number of days since 1970 is the same as the last
                    125:                 * time we did the computation then skip all this leap year
                    126:                 * and month stuff.
                    127:                 */
                    128:                days = t / (24 * 60 * 60);
                    129:                if (days != lastday) {
                    130:                        lastday = days;
                    131:                        for (year = 1970;; year++) {
                    132:                                inc = year & 0x03 ? 365 : 366;
                    133:                                if (days < inc)
                    134:                                        break;
                    135:                                days -= inc;
                    136:                        }
                    137:                        months = year & 0x03 ? regyear : leapyear;
                    138:                        for (month = 0; month < 12; month++) {
                    139:                                if (days < months[month])
                    140:                                        break;
                    141:                                days -= months[month];
                    142:                        }
                    143:                        lastddate = ((days + 1) << DD_DAY_SHIFT)
                    144:                            + ((month + 1) << DD_MONTH_SHIFT);
                    145:                        /*
                    146:                         * Remember dos's idea of time is relative to 1980.
                    147:                         * unix's is relative to 1970.  If somehow we get a
                    148:                         * time before 1980 then don't give totally crazy
                    149:                         * results.
                    150:                         */
                    151:                        if (year > 1980)
                    152:                                lastddate += (year - 1980) << DD_YEAR_SHIFT;
                    153:                }
                    154:        }
                    155:
                    156:        if (dtp != NULL)
                    157:                *dtp = lastdtime;
                    158:        if (dhp != NULL)
                    159:                *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
                    160:
                    161:        *ddp = lastddate;
                    162: }
                    163:
                    164: /*
                    165:  * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
                    166:  * interval there were 8 regular years and 2 leap years.
                    167:  */
                    168: #define        SECONDSTO1980   (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
                    169:
                    170: u_short lastdosdate;
                    171: uint32_t lastseconds;
                    172:
                    173: /*
                    174:  * Convert from dos' idea of time to unix'. This will probably only be
                    175:  * called from the stat(), and fstat() system calls and so probably need
                    176:  * not be too efficient.
                    177:  */
                    178: void
                    179: dos2unixtime(dd, dt, dh, tsp)
                    180:        u_int dd;
                    181:        u_int dt;
                    182:        u_int dh;
                    183:        struct timespec *tsp;
                    184: {
                    185:        uint32_t seconds;
                    186:        uint32_t m, month;
                    187:        uint32_t y, year;
                    188:        uint32_t days;
                    189:        const u_short *months;
                    190:
                    191:        if (dd == 0) {
                    192:                /*
                    193:                 * Uninitialized field, return the epoch.
                    194:                 */
                    195:                tsp->tv_sec = 0;
                    196:                tsp->tv_nsec = 0;
                    197:                return;
                    198:        }
                    199:        seconds = ((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) * 2
                    200:            + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
                    201:            + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
                    202:            + dh / 100;
                    203:        /*
                    204:         * If the year, month, and day from the last conversion are the
                    205:         * same then use the saved value.
                    206:         */
                    207:        if (lastdosdate != dd) {
                    208:                lastdosdate = dd;
                    209:                days = 0;
                    210:                year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
                    211:                for (y = 0; y < year; y++)
                    212:                        days += y & 0x03 ? 365 : 366;
                    213:                months = year & 0x03 ? regyear : leapyear;
                    214:                /*
                    215:                 * Prevent going from 0 to 0xffffffff in the following
                    216:                 * loop.
                    217:                 */
                    218:                month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
                    219:                if (month == 0) {
                    220:                        printf("dos2unixtime(): month value out of range (%ld)\n",
                    221:                            month);
                    222:                        month = 1;
                    223:                }
                    224:                for (m = 0; m < month - 1; m++)
                    225:                        days += months[m];
                    226:                days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
                    227:                lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
                    228:        }
                    229:        tsp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
                    230:             /* -+ daylight saving time correction */ ;
                    231:        tsp->tv_nsec = (dh % 100) * 10000000;
                    232: }
                    233:
                    234: static const u_char
                    235: unix2dos[256] = {
                    236:        0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
                    237:        0,    0,    0,    0,    0,    0,    0,    0,    /* 08-0f */
                    238:        0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
                    239:        0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
                    240:        0,    0x21, 0,    0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
                    241:        0x28, 0x29, 0,    0,    0,    0x2d, 0,    0,    /* 28-2f */
                    242:        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
                    243:        0x38, 0x39, 0,    0,    0,    0,    0,    0,    /* 38-3f */
                    244:        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
                    245:        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
                    246:        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
                    247:        0x58, 0x59, 0x5a, 0,    0,    0,    0x5e, 0x5f, /* 58-5f */
                    248:        0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */
                    249:        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 68-6f */
                    250:        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */
                    251:        0x58, 0x59, 0x5a, 0x7b, 0,    0x7d, 0x7e, 0,    /* 78-7f */
                    252:        0,    0,    0,    0,    0,    0,    0,    0,    /* 80-87 */
                    253:        0,    0,    0,    0,    0,    0,    0,    0,    /* 88-8f */
                    254:        0,    0,    0,    0,    0,    0,    0,    0,    /* 90-97 */
                    255:        0,    0,    0,    0,    0,    0,    0,    0,    /* 98-9f */
                    256:        0,    0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
                    257:        0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
                    258:        0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
                    259:        0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
                    260:        0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
                    261:        0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
                    262:        0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
                    263:        0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
                    264:        0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
                    265:        0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
                    266:        0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
                    267:        0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
                    268: };
                    269:
                    270: static const u_char
                    271: dos2unix[256] = {
                    272:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 00-07 */
                    273:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 08-0f */
                    274:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 10-17 */
                    275:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 18-1f */
                    276:        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
                    277:        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
                    278:        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
                    279:        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
                    280:        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
                    281:        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
                    282:        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
                    283:        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
                    284:        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
                    285:        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
                    286:        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
                    287:        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
                    288:        0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7, /* 80-87 */
                    289:        0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5, /* 88-8f */
                    290:        0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9, /* 90-97 */
                    291:        0xff, 0xd6, 0xdc, 0xf8, 0xa3, 0xd8, 0xd7, 0x3f, /* 98-9f */
                    292:        0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba, /* a0-a7 */
                    293:        0xbf, 0xae, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb, /* a8-af */
                    294:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xc1, 0xc2, 0xc0, /* b0-b7 */
                    295:        0xa9, 0x3f, 0x3f, 0x3f, 0x3f, 0xa2, 0xa5, 0x3f, /* b8-bf */
                    296:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xe3, 0xc3, /* c0-c7 */
                    297:        0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xa4, /* c8-cf */
                    298:        0xf0, 0xd0, 0xca, 0xcb, 0xc8, 0x3f, 0xcd, 0xce, /* d0-d7 */
                    299:        0xcf, 0x3f, 0x3f, 0x3f, 0x3f, 0xa6, 0xcc, 0x3f, /* d8-df */
                    300:        0xd3, 0xdf, 0xd4, 0xd2, 0xf5, 0xd5, 0xb5, 0xfe, /* e0-e7 */
                    301:        0xde, 0xda, 0xdb, 0xd9, 0xfd, 0xdd, 0xaf, 0x3f, /* e8-ef */
                    302:        0xad, 0xb1, 0x3f, 0xbe, 0xb6, 0xa7, 0xf7, 0xb8, /* f0-f7 */
                    303:        0xb0, 0xa8, 0xb7, 0xb9, 0xb3, 0xb2, 0x3f, 0x3f, /* f8-ff */
                    304: };
                    305:
                    306: static const u_char
                    307: u2l[256] = {
                    308:        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
                    309:        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
                    310:        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
                    311:        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */
                    312:        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
                    313:        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
                    314:        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
                    315:        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
                    316:        0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */
                    317:        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */
                    318:        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */
                    319:        0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
                    320:        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
                    321:        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
                    322:        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
                    323:        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
                    324:        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
                    325:        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
                    326:        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
                    327:        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
                    328:        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
                    329:        0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
                    330:        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
                    331:        0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
                    332:        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */
                    333:        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */
                    334:        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */
                    335:        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */
                    336:        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
                    337:        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
                    338:        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
                    339:        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */
                    340: };
                    341:
                    342: /*
                    343:  * DOS filenames are made of 2 parts, the name part and the extension part.
                    344:  * The name part is 8 characters long and the extension part is 3
                    345:  * characters long.  They may contain trailing blanks if the name or
                    346:  * extension are not long enough to fill their respective fields.
                    347:  */
                    348:
                    349: /*
                    350:  * Convert a DOS filename to a unix filename. And, return the number of
                    351:  * characters in the resulting unix filename excluding the terminating
                    352:  * null.
                    353:  */
                    354: int
                    355: dos2unixfn(dn, un, lower)
                    356:        u_char dn[11];
                    357:        u_char *un;
                    358:        int lower;
                    359: {
                    360:        int i;
                    361:        int thislong = 1;
                    362:        u_char c;
                    363:
                    364:        /*
                    365:         * If first char of the filename is SLOT_E5 (0x05), then the real
                    366:         * first char of the filename should be 0xe5. But, they couldn't
                    367:         * just have a 0xe5 mean 0xe5 because that is used to mean a freed
                    368:         * directory slot. Another dos quirk.
                    369:         */
                    370:        if (*dn == SLOT_E5)
                    371:                c = dos2unix[0xe5];
                    372:        else
                    373:                c = dos2unix[*dn];
                    374:        *un++ = lower ? u2l[c] : c;
                    375:        dn++;
                    376:
                    377:        /*
                    378:         * Copy the name portion into the unix filename string.
                    379:         */
                    380:        for (i = 1; i < 8 && *dn != ' '; i++) {
                    381:                c = dos2unix[*dn++];
                    382:                *un++ = lower ? u2l[c] : c;
                    383:                thislong++;
                    384:        }
                    385:        dn += 8 - i;
                    386:
                    387:        /*
                    388:         * Now, if there is an extension then put in a period and copy in
                    389:         * the extension.
                    390:         */
                    391:        if (*dn != ' ') {
                    392:                *un++ = '.';
                    393:                thislong++;
                    394:                for (i = 0; i < 3 && *dn != ' '; i++) {
                    395:                        c = dos2unix[*dn++];
                    396:                        *un++ = lower ? u2l[c] : c;
                    397:                        thislong++;
                    398:                }
                    399:        }
                    400:        *un++ = 0;
                    401:
                    402:        return (thislong);
                    403: }
                    404:
                    405: /*
                    406:  * Convert a unix filename to a DOS filename according to Win95 rules.
                    407:  * If applicable and gen is not 0, it is inserted into the converted
                    408:  * filename as a generation number.
                    409:  * Returns
                    410:  *     0 if name couldn't be converted
                    411:  *     1 if the converted name is the same as the original
                    412:  *       (no long filename entry necessary for Win95)
                    413:  *     2 if conversion was successful
                    414:  *     3 if conversion was successful and generation number was inserted
                    415:  */
                    416: int
                    417: unix2dosfn(un, dn, unlen, gen)
                    418:        u_char *un;
                    419:        u_char dn[12];
                    420:        int unlen;
                    421:        u_int gen;
                    422: {
                    423:        int i, j, l;
                    424:        int conv = 1;
                    425:        u_char *cp, *dp, *dp1;
                    426:        u_char gentext[6];
                    427:
                    428:        /*
                    429:         * Fill the dos filename string with blanks. These are DOS's pad
                    430:         * characters.
                    431:         */
                    432:        for (i = 0; i < 11; i++)
                    433:                dn[i] = ' ';
                    434:        dn[11] = 0;
                    435:
                    436:        /*
                    437:         * The filenames "." and ".." are handled specially, since they
                    438:         * don't follow dos filename rules.
                    439:         */
                    440:        if (un[0] == '.' && unlen == 1) {
                    441:                dn[0] = '.';
                    442:                return gen <= 1;
                    443:        }
                    444:        if (un[0] == '.' && un[1] == '.' && unlen == 2) {
                    445:                dn[0] = '.';
                    446:                dn[1] = '.';
                    447:                return gen <= 1;
                    448:        }
                    449:
                    450:        /*
                    451:         * Filenames with only blanks and dots are not allowed!
                    452:         */
                    453:        for (cp = un, i = unlen; --i >= 0; cp++)
                    454:                if (*cp != ' ' && *cp != '.')
                    455:                        break;
                    456:        if (i < 0)
                    457:                return 0;
                    458:
                    459:        /*
                    460:         * Now find the extension
                    461:         * Note: dot as first char doesn't start extension
                    462:         *       and trailing dots and blanks are ignored
                    463:         */
                    464:        dp = dp1 = 0;
                    465:        for (cp = un + 1, i = unlen - 1; --i >= 0;) {
                    466:                switch (*cp++) {
                    467:                case '.':
                    468:                        if (!dp1)
                    469:                                dp1 = cp;
                    470:                        break;
                    471:                case ' ':
                    472:                        break;
                    473:                default:
                    474:                        if (dp1)
                    475:                                dp = dp1;
                    476:                        dp1 = 0;
                    477:                        break;
                    478:                }
                    479:        }
                    480:
                    481:        /*
                    482:         * Now convert it
                    483:         */
                    484:        if (dp) {
                    485:                if (dp1)
                    486:                        l = dp1 - dp;
                    487:                else
                    488:                        l = unlen - (dp - un);
                    489:                for (i = 0, j = 8; i < l && j < 11; i++, j++) {
                    490:                        if (dp[i] != (dn[j] = unix2dos[dp[i]])
                    491:                            && conv != 3)
                    492:                                conv = 2;
                    493:                        if (!dn[j]) {
                    494:                                conv = 3;
                    495:                                dn[j--] = ' ';
                    496:                        }
                    497:                }
                    498:                if (i < l)
                    499:                        conv = 3;
                    500:                dp--;
                    501:        } else {
                    502:                for (dp = cp; *--dp == ' ' || *dp == '.';);
                    503:                dp++;
                    504:        }
                    505:
                    506:        /*
                    507:         * Now convert the rest of the name
                    508:         */
                    509:        for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
                    510:                if (*un != (dn[j] = unix2dos[*un])
                    511:                    && conv != 3)
                    512:                        conv = 2;
                    513:                if (!dn[j]) {
                    514:                        conv = 3;
                    515:                        dn[j--] = ' ';
                    516:                }
                    517:        }
                    518:        if (un < dp)
                    519:                conv = 3;
                    520:        /*
                    521:         * If we didn't have any chars in filename,
                    522:         * generate a default
                    523:         */
                    524:        if (!j)
                    525:                dn[0] = '_';
                    526:
                    527:        /*
                    528:         * The first character cannot be E5,
                    529:         * because that means a deleted entry
                    530:         */
                    531:        if (dn[0] == 0xe5)
                    532:                dn[0] = SLOT_E5;
                    533:
                    534:        /*
                    535:         * If there wasn't any char dropped,
                    536:         * there is no place for generation numbers
                    537:         */
                    538:        if (conv != 3) {
                    539:                if (gen > 1)
                    540:                        return 0;
                    541:                return conv;
                    542:        }
                    543:
                    544:        /*
                    545:         * Now insert the generation number into the filename part
                    546:         */
                    547:        for (cp = gentext + sizeof(gentext); cp > gentext && gen; gen /= 10)
                    548:                *--cp = gen % 10 + '0';
                    549:        if (gen)
                    550:                return 0;
                    551:        for (i = 8; dn[--i] == ' ';);
                    552:        if (gentext + sizeof(gentext) - cp + 1 > 8 - i)
                    553:                i = 8 - (gentext + sizeof(gentext) - cp + 1);
                    554:        dn[i++] = '~';
                    555:        while (cp < gentext + sizeof(gentext))
                    556:                dn[i++] = *cp++;
                    557:        return 3;
                    558: }
                    559:
                    560: /*
                    561:  * Create a Win95 long name directory entry
                    562:  * Note: assumes that the filename is valid,
                    563:  *      i.e. doesn't consist solely of blanks and dots
                    564:  */
                    565: int
                    566: unix2winfn(un, unlen, wep, cnt, chksum)
                    567:        u_char *un;
                    568:        int unlen;
                    569:        struct winentry *wep;
                    570:        int cnt;
                    571:        int chksum;
                    572: {
                    573:        u_int8_t *cp;
                    574:        int i;
                    575:
                    576:        /*
                    577:         * Drop trailing blanks and dots
                    578:         */
                    579:        for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
                    580:
                    581:        un += (cnt - 1) * WIN_CHARS;
                    582:        unlen -= (cnt - 1) * WIN_CHARS;
                    583:
                    584:        /*
                    585:         * Initialize winentry to some useful default
                    586:         */
                    587:        for (cp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *cp++ = 0xff);
                    588:        wep->weCnt = cnt;
                    589:        wep->weAttributes = ATTR_WIN95;
                    590:        wep->weReserved1 = 0;
                    591:        wep->weChksum = chksum;
                    592:        wep->weReserved2 = 0;
                    593:
                    594:        /*
                    595:         * Now convert the filename parts
                    596:         */
                    597:        for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
                    598:                if (--unlen < 0)
                    599:                        goto done;
                    600:                *cp++ = *un++;
                    601:                *cp++ = 0;
                    602:        }
                    603:        for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
                    604:                if (--unlen < 0)
                    605:                        goto done;
                    606:                *cp++ = *un++;
                    607:                *cp++ = 0;
                    608:        }
                    609:        for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
                    610:                if (--unlen < 0)
                    611:                        goto done;
                    612:                *cp++ = *un++;
                    613:                *cp++ = 0;
                    614:        }
                    615:        if (!unlen)
                    616:                wep->weCnt |= WIN_LAST;
                    617:        return unlen;
                    618:
                    619: done:
                    620:        *cp++ = 0;
                    621:        *cp++ = 0;
                    622:        wep->weCnt |= WIN_LAST;
                    623:        return 0;
                    624: }
                    625:
                    626: /*
                    627:  * Compare our filename to the one in the Win95 entry
                    628:  * Returns the checksum or -1 if no match
                    629:  */
                    630: int
                    631: winChkName(un, unlen, wep, chksum)
                    632:        u_char *un;
                    633:        int unlen;
                    634:        struct winentry *wep;
                    635:        int chksum;
                    636: {
                    637:        u_int8_t *cp;
                    638:        int i;
                    639:
                    640:        /*
                    641:         * First compare checksums
                    642:         */
                    643:        if (wep->weCnt&WIN_LAST)
                    644:                chksum = wep->weChksum;
                    645:        else if (chksum != wep->weChksum)
                    646:                chksum = -1;
                    647:        if (chksum == -1)
                    648:                return -1;
                    649:
                    650:        /*
                    651:         * Offset of this entry
                    652:         */
                    653:        i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
                    654:        if ((unlen -= i) <= 0)
                    655:                return -1;
                    656:        un += i;
                    657:
                    658:        if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS)
                    659:                return -1;
                    660:
                    661:        /*
                    662:         * Compare the name parts
                    663:         */
                    664:        for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
                    665:                if (--unlen < 0) {
                    666:                        if (!*cp++ && !*cp)
                    667:                                return chksum;
                    668:                        return -1;
                    669:                }
                    670:                if (u2l[*cp++] != u2l[*un++] || *cp++)
                    671:                        return -1;
                    672:        }
                    673:        for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
                    674:                if (--unlen < 0) {
                    675:                        if (!*cp++ && !*cp)
                    676:                                return chksum;
                    677:                        return -1;
                    678:                }
                    679:                if (u2l[*cp++] != u2l[*un++] || *cp++)
                    680:                        return -1;
                    681:        }
                    682:        for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
                    683:                if (--unlen < 0) {
                    684:                        if (!*cp++ && !*cp)
                    685:                                return chksum;
                    686:                        return -1;
                    687:                }
                    688:                if (u2l[*cp++] != u2l[*un++] || *cp++)
                    689:                        return -1;
                    690:        }
                    691:        return chksum;
                    692: }
                    693:
                    694: /*
                    695:  * Convert Win95 filename to dirbuf.
                    696:  * Returns the checksum or -1 if impossible
                    697:  */
                    698: int
                    699: win2unixfn(wep, dp, chksum)
                    700:        struct winentry *wep;
                    701:        struct dirent *dp;
                    702:        int chksum;
                    703: {
                    704:        u_int8_t *cp;
                    705:        u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
                    706:        int i;
                    707:
                    708:        if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
                    709:            || !(wep->weCnt&WIN_CNT))
                    710:                return -1;
                    711:
                    712:        /*
                    713:         * First compare checksums
                    714:         */
                    715:        if (wep->weCnt&WIN_LAST) {
                    716:                chksum = wep->weChksum;
                    717:                /*
                    718:                 * This works even though d_namlen is one byte!
                    719:                 */
                    720:                dp->d_namlen = (wep->weCnt&WIN_CNT) * WIN_CHARS;
                    721:        } else if (chksum != wep->weChksum)
                    722:                chksum = -1;
                    723:        if (chksum == -1)
                    724:                return -1;
                    725:
                    726:        /*
                    727:         * Offset of this entry
                    728:         */
                    729:        i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
                    730:        np = (u_int8_t *)dp->d_name + i;
                    731:
                    732:        /*
                    733:         * Convert the name parts
                    734:         */
                    735:        for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
                    736:                switch (*np++ = *cp++) {
                    737:                case 0:
                    738:                        dp->d_namlen -= sizeof(wep->wePart2)/2
                    739:                            + sizeof(wep->wePart3)/2 + i + 1;
                    740:                        return chksum;
                    741:                case '/':
                    742:                        np[-1] = 0;
                    743:                        return -1;
                    744:                }
                    745:                /*
                    746:                 * The size comparison should result in the compiler
                    747:                 * optimizing the whole if away
                    748:                 */
                    749:                if (WIN_MAXLEN % WIN_CHARS < sizeof(wep->wePart1) / 2
                    750:                    && np > ep) {
                    751:                        np[-1] = 0;
                    752:                        return -1;
                    753:                }
                    754:                if (*cp++)
                    755:                        return -1;
                    756:        }
                    757:        for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
                    758:                switch (*np++ = *cp++) {
                    759:                case 0:
                    760:                        dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
                    761:                        return chksum;
                    762:                case '/':
                    763:                        np[-1] = 0;
                    764:                        return -1;
                    765:                }
                    766:                /*
                    767:                 * The size comparisons should be optimized away
                    768:                 */
                    769:                if (WIN_MAXLEN % WIN_CHARS >= sizeof(wep->wePart1) / 2
                    770:                    && WIN_MAXLEN % WIN_CHARS < (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
                    771:                    && np > ep) {
                    772:                        np[-1] = 0;
                    773:                        return -1;
                    774:                }
                    775:                if (*cp++)
                    776:                        return -1;
                    777:        }
                    778:        for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
                    779:                switch (*np++ = *cp++) {
                    780:                case 0:
                    781:                        dp->d_namlen -= i + 1;
                    782:                        return chksum;
                    783:                case '/':
                    784:                        np[-1] = 0;
                    785:                        return -1;
                    786:                }
                    787:                /*
                    788:                 * See above
                    789:                 */
                    790:                if (WIN_MAXLEN % WIN_CHARS >= (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
                    791:                    && np > ep) {
                    792:                        np[-1] = 0;
                    793:                        return -1;
                    794:                }
                    795:                if (*cp++)
                    796:                        return -1;
                    797:        }
                    798:        return chksum;
                    799: }
                    800:
                    801: /*
                    802:  * Compute the checksum of a DOS filename for Win95 use
                    803:  */
                    804: u_int8_t
                    805: winChksum(name)
                    806:        u_int8_t *name;
                    807: {
                    808:        int i;
                    809:        u_int8_t s;
                    810:
                    811:        for (s = 0, i = 11; --i >= 0; s += *name++)
                    812:                s = (s << 7)|(s >> 1);
                    813:        return s;
                    814: }
                    815:
                    816: /*
                    817:  * Determine the number of slots necessary for Win95 names
                    818:  */
                    819: int
                    820: winSlotCnt(un, unlen)
                    821:        u_char *un;
                    822:        int unlen;
                    823: {
                    824:        for (un += unlen; unlen > 0; unlen--)
                    825:                if (*--un != ' ' && *un != '.')
                    826:                        break;
                    827:        if (unlen > WIN_MAXLEN)
                    828:                return 0;
                    829:        return howmany(unlen, WIN_CHARS);
                    830: }

CVSweb