Annotation of sys/msdosfs/msdosfs_conv.c, Revision 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