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