xref: /freebsd/usr.sbin/makefs/msdos/msdosfs_conv.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
198dc8da5SEd Maste /*-
22037e988SEd Maste  * SPDX-License-Identifier: BSD-4-Clause
32037e988SEd Maste  *
498dc8da5SEd Maste  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
598dc8da5SEd Maste  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
698dc8da5SEd Maste  * All rights reserved.
798dc8da5SEd Maste  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
898dc8da5SEd Maste  *
998dc8da5SEd Maste  * Redistribution and use in source and binary forms, with or without
1098dc8da5SEd Maste  * modification, are permitted provided that the following conditions
1198dc8da5SEd Maste  * are met:
1298dc8da5SEd Maste  * 1. Redistributions of source code must retain the above copyright
1398dc8da5SEd Maste  *    notice, this list of conditions and the following disclaimer.
1498dc8da5SEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
1598dc8da5SEd Maste  *    notice, this list of conditions and the following disclaimer in the
1698dc8da5SEd Maste  *    documentation and/or other materials provided with the distribution.
1798dc8da5SEd Maste  * 3. All advertising materials mentioning features or use of this software
1898dc8da5SEd Maste  *    must display the following acknowledgement:
1998dc8da5SEd Maste  *	This product includes software developed by TooLs GmbH.
2098dc8da5SEd Maste  * 4. The name of TooLs GmbH may not be used to endorse or promote products
2198dc8da5SEd Maste  *    derived from this software without specific prior written permission.
2298dc8da5SEd Maste  *
2398dc8da5SEd Maste  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2498dc8da5SEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2598dc8da5SEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2698dc8da5SEd Maste  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2798dc8da5SEd Maste  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2898dc8da5SEd Maste  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2998dc8da5SEd Maste  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
3098dc8da5SEd Maste  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3198dc8da5SEd Maste  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3298dc8da5SEd Maste  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3398dc8da5SEd Maste  */
342037e988SEd Maste /*-
3598dc8da5SEd Maste  * Written by Paul Popelka (paulp@uts.amdahl.com)
3698dc8da5SEd Maste  *
3798dc8da5SEd Maste  * You can do anything you want with this software, just don't say you wrote
3898dc8da5SEd Maste  * it, and don't remove this notice.
3998dc8da5SEd Maste  *
4098dc8da5SEd Maste  * This software is provided "as is".
4198dc8da5SEd Maste  *
4298dc8da5SEd Maste  * The author supplies this software to be publicly redistributed on the
4398dc8da5SEd Maste  * understanding that the author is not responsible for the correct
4498dc8da5SEd Maste  * functioning of this software in any circumstances and is not liable for
4598dc8da5SEd Maste  * any damages caused by this software.
4698dc8da5SEd Maste  *
4798dc8da5SEd Maste  * October 1992
4898dc8da5SEd Maste  */
4998dc8da5SEd Maste 
5098dc8da5SEd Maste #include <sys/param.h>
5198dc8da5SEd Maste #include <sys/endian.h>
5298dc8da5SEd Maste 
5398dc8da5SEd Maste #include <dirent.h>
5498dc8da5SEd Maste #include <stdio.h>
5598dc8da5SEd Maste #include <string.h>
5698dc8da5SEd Maste 
5798dc8da5SEd Maste #include <fs/msdosfs/bpb.h>
58476b0ab7SEd Maste #include "msdos/direntry.h"
59*840aca28SEd Maste #include <fs/msdosfs/msdosfsmount.h>
6098dc8da5SEd Maste 
6198dc8da5SEd Maste #include "makefs.h"
6298dc8da5SEd Maste #include "msdos.h"
6398dc8da5SEd Maste 
6498dc8da5SEd Maste static int char8ucs2str(const uint8_t *in, int n, uint16_t *out, int m);
6598dc8da5SEd Maste static void ucs2pad(uint16_t *buf, int len, int size);
6698dc8da5SEd Maste static int char8match(uint16_t *w1, uint16_t *w2, int n);
6798dc8da5SEd Maste 
6898dc8da5SEd Maste static const u_char unix2dos[256] = {
6998dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 00-07 */
7098dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 08-0f */
7198dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 10-17 */
7298dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 18-1f */
7398dc8da5SEd Maste 	0,    '!',  0,    '#',  '$',  '%',  '&',  '\'',	/* 20-27 */
7498dc8da5SEd Maste 	'(',  ')',  0,    '+',  0,    '-',  0,    0,	/* 28-2f */
7598dc8da5SEd Maste 	'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',	/* 30-37 */
7698dc8da5SEd Maste 	'8',  '9',  0,    0,    0,    0,    0,    0,	/* 38-3f */
7798dc8da5SEd Maste 	'@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',	/* 40-47 */
7898dc8da5SEd Maste 	'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',	/* 48-4f */
7998dc8da5SEd Maste 	'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',	/* 50-57 */
8098dc8da5SEd Maste 	'X',  'Y',  'Z',  0,    0,    0,    '^',  '_',	/* 58-5f */
8198dc8da5SEd Maste 	'`',  'A',  'B',  'C',  'D',  'E',  'F',  'G',	/* 60-67 */
8298dc8da5SEd Maste 	'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',	/* 68-6f */
8398dc8da5SEd Maste 	'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',	/* 70-77 */
8498dc8da5SEd Maste 	'X',  'Y',  'Z',  '{',  0,    '}',  '~',  0,	/* 78-7f */
8598dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 80-87 */
8698dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 88-8f */
8798dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 90-97 */
8898dc8da5SEd Maste 	0,    0,    0,    0,    0,    0,    0,    0,	/* 98-9f */
8998dc8da5SEd Maste 	0,    0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5,	/* a0-a7 */
9098dc8da5SEd Maste 	0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee,	/* a8-af */
9198dc8da5SEd Maste 	0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa,	/* b0-b7 */
9298dc8da5SEd Maste 	0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8,	/* b8-bf */
9398dc8da5SEd Maste 	0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80,	/* c0-c7 */
9498dc8da5SEd Maste 	0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8,	/* c8-cf */
9598dc8da5SEd Maste 	0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e,	/* d0-d7 */
9698dc8da5SEd Maste 	0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1,	/* d8-df */
9798dc8da5SEd Maste 	0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80,	/* e0-e7 */
9898dc8da5SEd Maste 	0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8,	/* e8-ef */
9998dc8da5SEd Maste 	0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6,	/* f0-f7 */
10098dc8da5SEd Maste 	0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98,	/* f8-ff */
10198dc8da5SEd Maste };
10298dc8da5SEd Maste 
10398dc8da5SEd Maste static const u_char u2l[256] = {
10498dc8da5SEd Maste 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
10598dc8da5SEd Maste 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
10698dc8da5SEd Maste 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
10798dc8da5SEd Maste 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */
10898dc8da5SEd Maste 	' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'', /* 20-27 */
10998dc8da5SEd Maste 	'(',  ')',  '*',  '+',  ',',  '-',  '.',  '/', /* 28-2f */
11098dc8da5SEd Maste 	'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7', /* 30-37 */
11198dc8da5SEd Maste 	'8',  '9',  ':',  ';',  '<',  '=',  '>',  '?', /* 38-3f */
11298dc8da5SEd Maste 	'@',  'a',  'b',  'c',  'd',  'e',  'f',  'g', /* 40-47 */
11398dc8da5SEd Maste 	'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', /* 48-4f */
11498dc8da5SEd Maste 	'p',  'q',  'r',  's',  't',  'u',  'v',  'w', /* 50-57 */
11598dc8da5SEd Maste 	'x',  'y',  'z',  '[', '\\',  ']',  '^',  '_', /* 58-5f */
11698dc8da5SEd Maste 	'`',  'a',  'b',  'c',  'd',  'e',  'f',  'g', /* 60-67 */
11798dc8da5SEd Maste 	'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', /* 68-6f */
11898dc8da5SEd Maste 	'p',  'q',  'r',  's',  't',  'u',  'v',  'w', /* 70-77 */
11998dc8da5SEd Maste 	'x',  'y',  'z',  '{',  '|',  '}',  '~', 0x7f, /* 78-7f */
12098dc8da5SEd Maste 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
12198dc8da5SEd Maste 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
12298dc8da5SEd Maste 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
12398dc8da5SEd Maste 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
12498dc8da5SEd Maste 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
12598dc8da5SEd Maste 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
12698dc8da5SEd Maste 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
12798dc8da5SEd Maste 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
12898dc8da5SEd Maste 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */
12998dc8da5SEd Maste 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */
13098dc8da5SEd Maste 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */
13198dc8da5SEd Maste 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */
13298dc8da5SEd Maste 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
13398dc8da5SEd Maste 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
13498dc8da5SEd Maste 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
13598dc8da5SEd Maste 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */
13698dc8da5SEd Maste };
13798dc8da5SEd Maste 
13898dc8da5SEd Maste /*
13998dc8da5SEd Maste  * Determine the number of slots necessary for Win95 names
14098dc8da5SEd Maste  */
14198dc8da5SEd Maste int
winSlotCnt(const u_char * un,size_t unlen)14298dc8da5SEd Maste winSlotCnt(const u_char *un, size_t unlen)
14398dc8da5SEd Maste {
14498dc8da5SEd Maste 	const u_char *cp;
14598dc8da5SEd Maste 
14698dc8da5SEd Maste 	/*
14798dc8da5SEd Maste 	 * Drop trailing blanks and dots
14898dc8da5SEd Maste 	 */
14998dc8da5SEd Maste 	for (cp = un + unlen; unlen > 0; unlen--)
15098dc8da5SEd Maste 		if (*--cp != ' ' && *cp != '.')
15198dc8da5SEd Maste 			break;
15298dc8da5SEd Maste 
15398dc8da5SEd Maste 	return howmany(unlen, WIN_CHARS);
15498dc8da5SEd Maste }
15598dc8da5SEd Maste 
15698dc8da5SEd Maste /*
15798dc8da5SEd Maste  * Compare our filename to the one in the Win95 entry
15898dc8da5SEd Maste  * Returns the checksum or -1 if no match
15998dc8da5SEd Maste  */
16098dc8da5SEd Maste int
winChkName(const u_char * un,size_t unlen,struct winentry * wep,int chksum)16198dc8da5SEd Maste winChkName(const u_char *un, size_t unlen, struct winentry *wep, int chksum)
16298dc8da5SEd Maste {
16398dc8da5SEd Maste 	uint16_t wn[WIN_MAXLEN], *p;
16498dc8da5SEd Maste 	uint16_t buf[WIN_CHARS];
16598dc8da5SEd Maste 	int i, len;
16698dc8da5SEd Maste 
16798dc8da5SEd Maste 	/*
16898dc8da5SEd Maste 	 * First compare checksums
16998dc8da5SEd Maste 	 */
17098dc8da5SEd Maste 	if (wep->weCnt & WIN_LAST)
17198dc8da5SEd Maste 		chksum = wep->weChksum;
17298dc8da5SEd Maste 	else if (chksum != wep->weChksum)
17398dc8da5SEd Maste 		chksum = -1;
17498dc8da5SEd Maste 	if (chksum == -1)
17598dc8da5SEd Maste 		return -1;
17698dc8da5SEd Maste 
17798dc8da5SEd Maste 	/*
17898dc8da5SEd Maste 	 * Offset of this entry
17998dc8da5SEd Maste 	 */
18098dc8da5SEd Maste 	i = ((wep->weCnt & WIN_CNT) - 1) * WIN_CHARS;
18198dc8da5SEd Maste 
18298dc8da5SEd Maste 	/*
18398dc8da5SEd Maste 	 * Translate UNIX name to ucs-2
18498dc8da5SEd Maste 	 */
18598dc8da5SEd Maste 	len = char8ucs2str(un, unlen, wn, WIN_MAXLEN);
18698dc8da5SEd Maste 	ucs2pad(wn, len, WIN_MAXLEN);
18798dc8da5SEd Maste 
18898dc8da5SEd Maste 	if (i >= len + 1)
18998dc8da5SEd Maste 		return -1;
19098dc8da5SEd Maste 	if ((wep->weCnt & WIN_LAST) && (len - i > WIN_CHARS))
19198dc8da5SEd Maste 		return -1;
19298dc8da5SEd Maste 
19398dc8da5SEd Maste 	/*
19498dc8da5SEd Maste 	 * Fetch name segment from directory entry
19598dc8da5SEd Maste 	 */
19698dc8da5SEd Maste 	p = &buf[0];
19798dc8da5SEd Maste 	memcpy(p, wep->wePart1, sizeof(wep->wePart1));
19898dc8da5SEd Maste 	p += sizeof(wep->wePart1) / sizeof(*p);
19998dc8da5SEd Maste 	memcpy(p, wep->wePart2, sizeof(wep->wePart2));
20098dc8da5SEd Maste 	p += sizeof(wep->wePart2) / sizeof(*p);
20198dc8da5SEd Maste 	memcpy(p, wep->wePart3, sizeof(wep->wePart3));
20298dc8da5SEd Maste 
20398dc8da5SEd Maste 	/*
20498dc8da5SEd Maste 	 * And compare name segment
20598dc8da5SEd Maste 	 */
20698dc8da5SEd Maste 	if (!(char8match(&wn[i], buf, WIN_CHARS)))
20798dc8da5SEd Maste 		return -1;
20898dc8da5SEd Maste 
20998dc8da5SEd Maste 	return chksum;
21098dc8da5SEd Maste }
21198dc8da5SEd Maste 
21298dc8da5SEd Maste /*
21398dc8da5SEd Maste  * Compute the checksum of a DOS filename for Win95 use
21498dc8da5SEd Maste  */
21598dc8da5SEd Maste uint8_t
winChksum(uint8_t * name)21698dc8da5SEd Maste winChksum(uint8_t *name)
21798dc8da5SEd Maste {
21898dc8da5SEd Maste 	int i;
21998dc8da5SEd Maste 	uint8_t s;
22098dc8da5SEd Maste 
22198dc8da5SEd Maste 	for (s = 0, i = 11; --i >= 0; s += *name++)
22298dc8da5SEd Maste 		s = (s << 7) | (s >> 1);
22398dc8da5SEd Maste 	return s;
22498dc8da5SEd Maste }
22598dc8da5SEd Maste 
22698dc8da5SEd Maste /*
22798dc8da5SEd Maste  * Create a Win95 long name directory entry
22898dc8da5SEd Maste  * Note: assumes that the filename is valid,
22998dc8da5SEd Maste  *	 i.e. doesn't consist solely of blanks and dots
23098dc8da5SEd Maste  */
23198dc8da5SEd Maste int
unix2winfn(const u_char * un,size_t unlen,struct winentry * wep,int cnt,int chksum)23298dc8da5SEd Maste unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt,
23398dc8da5SEd Maste     int chksum)
23498dc8da5SEd Maste {
23598dc8da5SEd Maste 	uint16_t wn[WIN_MAXLEN], *p;
23698dc8da5SEd Maste 	int i, len;
23798dc8da5SEd Maste 	const u_char *cp;
23898dc8da5SEd Maste 
23998dc8da5SEd Maste 	/*
24098dc8da5SEd Maste 	 * Drop trailing blanks and dots
24198dc8da5SEd Maste 	 */
24298dc8da5SEd Maste 	for (cp = un + unlen; unlen > 0; unlen--)
24398dc8da5SEd Maste 		if (*--cp != ' ' && *cp != '.')
24498dc8da5SEd Maste 			break;
24598dc8da5SEd Maste 
24698dc8da5SEd Maste 	/*
24798dc8da5SEd Maste 	 * Offset of this entry
24898dc8da5SEd Maste 	 */
24998dc8da5SEd Maste 	i = (cnt - 1) * WIN_CHARS;
25098dc8da5SEd Maste 
25198dc8da5SEd Maste 	/*
25298dc8da5SEd Maste 	 * Translate UNIX name to ucs-2
25398dc8da5SEd Maste 	 */
25498dc8da5SEd Maste 	len = char8ucs2str(un, unlen, wn, WIN_MAXLEN);
25598dc8da5SEd Maste 	ucs2pad(wn, len, WIN_MAXLEN);
25698dc8da5SEd Maste 
25798dc8da5SEd Maste 	/*
25898dc8da5SEd Maste 	 * Initialize winentry to some useful default
25998dc8da5SEd Maste 	 */
26098dc8da5SEd Maste 	memset(wep, 0xff, sizeof(*wep));
26198dc8da5SEd Maste 	wep->weCnt = cnt;
26298dc8da5SEd Maste 	wep->weAttributes = ATTR_WIN95;
26398dc8da5SEd Maste 	wep->weReserved1 = 0;
26498dc8da5SEd Maste 	wep->weChksum = chksum;
26598dc8da5SEd Maste 	wep->weReserved2 = 0;
26698dc8da5SEd Maste 
26798dc8da5SEd Maste 	/*
26898dc8da5SEd Maste 	 * Store name segment into directory entry
26998dc8da5SEd Maste 	 */
27098dc8da5SEd Maste 	p = &wn[i];
27198dc8da5SEd Maste 	memcpy(wep->wePart1, p, sizeof(wep->wePart1));
27298dc8da5SEd Maste 	p += sizeof(wep->wePart1) / sizeof(*p);
27398dc8da5SEd Maste 	memcpy(wep->wePart2, p, sizeof(wep->wePart2));
27498dc8da5SEd Maste 	p += sizeof(wep->wePart2) / sizeof(*p);
27598dc8da5SEd Maste 	memcpy(wep->wePart3, p, sizeof(wep->wePart3));
27698dc8da5SEd Maste 
27798dc8da5SEd Maste 	if (len > i + WIN_CHARS)
27898dc8da5SEd Maste 		return 1;
27998dc8da5SEd Maste 
28098dc8da5SEd Maste 	wep->weCnt |= WIN_LAST;
28198dc8da5SEd Maste 	return 0;
28298dc8da5SEd Maste }
28398dc8da5SEd Maste 
28498dc8da5SEd Maste /*
28598dc8da5SEd Maste  * Convert a unix filename to a DOS filename according to Win95 rules.
28698dc8da5SEd Maste  * If applicable and gen is not 0, it is inserted into the converted
28798dc8da5SEd Maste  * filename as a generation number.
28898dc8da5SEd Maste  * Returns
28998dc8da5SEd Maste  *	0 if name couldn't be converted
29098dc8da5SEd Maste  *	1 if the converted name is the same as the original
29198dc8da5SEd Maste  *	  (no long filename entry necessary for Win95)
29298dc8da5SEd Maste  *	2 if conversion was successful
29398dc8da5SEd Maste  *	3 if conversion was successful and generation number was inserted
29498dc8da5SEd Maste  */
29598dc8da5SEd Maste int
unix2dosfn(const u_char * un,u_char dn[12],size_t unlen,u_int gen)29698dc8da5SEd Maste unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen)
29798dc8da5SEd Maste {
29898dc8da5SEd Maste 	int i, j, l;
29998dc8da5SEd Maste 	int conv = 1;
30098dc8da5SEd Maste 	const u_char *cp, *dp, *dp1;
30198dc8da5SEd Maste 	u_char gentext[6], *wcp;
30298dc8da5SEd Maste 	int shortlen;
30398dc8da5SEd Maste 
30498dc8da5SEd Maste 	/*
30598dc8da5SEd Maste 	 * Fill the dos filename string with blanks. These are DOS's pad
30698dc8da5SEd Maste 	 * characters.
30798dc8da5SEd Maste 	 */
30898dc8da5SEd Maste 	for (i = 0; i < 11; i++)
30998dc8da5SEd Maste 		dn[i] = ' ';
31098dc8da5SEd Maste 	dn[11] = 0;
31198dc8da5SEd Maste 
31298dc8da5SEd Maste 	/*
31398dc8da5SEd Maste 	 * The filenames "." and ".." are handled specially, since they
31498dc8da5SEd Maste 	 * don't follow dos filename rules.
31598dc8da5SEd Maste 	 */
31698dc8da5SEd Maste 	if (un[0] == '.' && unlen == 1) {
31798dc8da5SEd Maste 		dn[0] = '.';
31898dc8da5SEd Maste 		return gen <= 1;
31998dc8da5SEd Maste 	}
32098dc8da5SEd Maste 	if (un[0] == '.' && un[1] == '.' && unlen == 2) {
32198dc8da5SEd Maste 		dn[0] = '.';
32298dc8da5SEd Maste 		dn[1] = '.';
32398dc8da5SEd Maste 		return gen <= 1;
32498dc8da5SEd Maste 	}
32598dc8da5SEd Maste 
32698dc8da5SEd Maste 	/*
32798dc8da5SEd Maste 	 * Filenames with only blanks and dots are not allowed!
32898dc8da5SEd Maste 	 */
32998dc8da5SEd Maste 	for (cp = un, i = unlen; --i >= 0; cp++)
33098dc8da5SEd Maste 		if (*cp != ' ' && *cp != '.')
33198dc8da5SEd Maste 			break;
33298dc8da5SEd Maste 	if (i < 0)
33398dc8da5SEd Maste 		return 0;
33498dc8da5SEd Maste 
33598dc8da5SEd Maste 	/*
33698dc8da5SEd Maste 	 * Now find the extension
33798dc8da5SEd Maste 	 * Note: dot as first char doesn't start extension
33898dc8da5SEd Maste 	 *	 and trailing dots and blanks are ignored
33998dc8da5SEd Maste 	 */
34098dc8da5SEd Maste 	dp = dp1 = 0;
34198dc8da5SEd Maste 	for (cp = un + 1, i = unlen - 1; --i >= 0;) {
34298dc8da5SEd Maste 		switch (*cp++) {
34398dc8da5SEd Maste 		case '.':
34498dc8da5SEd Maste 			if (!dp1)
34598dc8da5SEd Maste 				dp1 = cp;
34698dc8da5SEd Maste 			break;
34798dc8da5SEd Maste 		case ' ':
34898dc8da5SEd Maste 			break;
34998dc8da5SEd Maste 		default:
35098dc8da5SEd Maste 			if (dp1)
35198dc8da5SEd Maste 				dp = dp1;
35298dc8da5SEd Maste 			dp1 = 0;
35398dc8da5SEd Maste 			break;
35498dc8da5SEd Maste 		}
35598dc8da5SEd Maste 	}
35698dc8da5SEd Maste 
35798dc8da5SEd Maste 	/*
35898dc8da5SEd Maste 	 * Now convert it
35998dc8da5SEd Maste 	 */
36098dc8da5SEd Maste 	if (dp) {
36198dc8da5SEd Maste 		if (dp1)
36298dc8da5SEd Maste 			l = dp1 - dp;
36398dc8da5SEd Maste 		else
36498dc8da5SEd Maste 			l = unlen - (dp - un);
36598dc8da5SEd Maste 		for (i = 0, j = 8; i < l && j < 11; i++, j++) {
36698dc8da5SEd Maste 			if (dp[i] != (dn[j] = unix2dos[dp[i]])
36798dc8da5SEd Maste 			    && conv != 3)
36898dc8da5SEd Maste 				conv = 2;
36998dc8da5SEd Maste 			if (!dn[j]) {
37098dc8da5SEd Maste 				conv = 3;
37198dc8da5SEd Maste 				dn[j--] = ' ';
37298dc8da5SEd Maste 			}
37398dc8da5SEd Maste 		}
37498dc8da5SEd Maste 		if (i < l)
37598dc8da5SEd Maste 			conv = 3;
37698dc8da5SEd Maste 		dp--;
37798dc8da5SEd Maste 	} else {
37898dc8da5SEd Maste 		for (dp = cp; *--dp == ' ' || *dp == '.';);
37998dc8da5SEd Maste 		dp++;
38098dc8da5SEd Maste 	}
38198dc8da5SEd Maste 
38298dc8da5SEd Maste 	shortlen = (dp - un) <= 8;
38398dc8da5SEd Maste 
38498dc8da5SEd Maste 	/*
38598dc8da5SEd Maste 	 * Now convert the rest of the name
38698dc8da5SEd Maste 	 */
38798dc8da5SEd Maste 	for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
38898dc8da5SEd Maste 		if ((*un == ' ') && shortlen)
38998dc8da5SEd Maste 			dn[j] = ' ';
39098dc8da5SEd Maste 		else
39198dc8da5SEd Maste 			dn[j] = unix2dos[*un];
39298dc8da5SEd Maste 		if ((*un != dn[j])
39398dc8da5SEd Maste 		    && conv != 3)
39498dc8da5SEd Maste 			conv = 2;
39598dc8da5SEd Maste 		if (!dn[j]) {
39698dc8da5SEd Maste 			conv = 3;
39798dc8da5SEd Maste 			dn[j--] = ' ';
39898dc8da5SEd Maste 		}
39998dc8da5SEd Maste 	}
40098dc8da5SEd Maste 	if (un < dp)
40198dc8da5SEd Maste 		conv = 3;
40298dc8da5SEd Maste 	/*
40398dc8da5SEd Maste 	 * If we didn't have any chars in filename,
40498dc8da5SEd Maste 	 * generate a default
40598dc8da5SEd Maste 	 */
40698dc8da5SEd Maste 	if (!j)
40798dc8da5SEd Maste 		dn[0] = '_';
40898dc8da5SEd Maste 
40998dc8da5SEd Maste 	/*
41098dc8da5SEd Maste 	 * The first character cannot be E5,
41198dc8da5SEd Maste 	 * because that means a deleted entry
41298dc8da5SEd Maste 	 */
41398dc8da5SEd Maste 	if (dn[0] == 0xe5)
41498dc8da5SEd Maste 		dn[0] = SLOT_E5;
41598dc8da5SEd Maste 
41698dc8da5SEd Maste 	/*
41798dc8da5SEd Maste 	 * If there wasn't any char dropped,
41898dc8da5SEd Maste 	 * there is no place for generation numbers
41998dc8da5SEd Maste 	 */
42098dc8da5SEd Maste 	if (conv != 3) {
42198dc8da5SEd Maste 		if (gen > 1)
42298dc8da5SEd Maste 			return 0;
42398dc8da5SEd Maste 		return conv;
42498dc8da5SEd Maste 	}
42598dc8da5SEd Maste 
42698dc8da5SEd Maste 	/*
42798dc8da5SEd Maste 	 * Now insert the generation number into the filename part
42898dc8da5SEd Maste 	 */
42998dc8da5SEd Maste 	for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
43098dc8da5SEd Maste 		*--wcp = gen % 10 + '0';
43198dc8da5SEd Maste 	if (gen)
43298dc8da5SEd Maste 		return 0;
43398dc8da5SEd Maste 	for (i = 8; dn[--i] == ' ';);
43498dc8da5SEd Maste 	i++;
43598dc8da5SEd Maste 	if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
43698dc8da5SEd Maste 		i = 8 - (gentext + sizeof(gentext) - wcp + 1);
43798dc8da5SEd Maste 	dn[i++] = '~';
43898dc8da5SEd Maste 	while (wcp < gentext + sizeof(gentext))
43998dc8da5SEd Maste 		dn[i++] = *wcp++;
44098dc8da5SEd Maste 	return 3;
44198dc8da5SEd Maste }
44298dc8da5SEd Maste 
44398dc8da5SEd Maste /*
44498dc8da5SEd Maste  * Convert 8bit character string into UCS-2 string
44598dc8da5SEd Maste  * return total number of output chacters
44698dc8da5SEd Maste  */
44798dc8da5SEd Maste static int
char8ucs2str(const uint8_t * in,int n,uint16_t * out,int m)44898dc8da5SEd Maste char8ucs2str(const uint8_t *in, int n, uint16_t *out, int m)
44998dc8da5SEd Maste {
45098dc8da5SEd Maste 	uint16_t *p;
45198dc8da5SEd Maste 
45298dc8da5SEd Maste 	p = out;
45398dc8da5SEd Maste 	while (n > 0 && in[0] != 0) {
45498dc8da5SEd Maste 		if (m < 1)
45598dc8da5SEd Maste 			break;
45698dc8da5SEd Maste 		if (p)
45798dc8da5SEd Maste 			p[0] = htole16(in[0]);
45898dc8da5SEd Maste 		p += 1;
45998dc8da5SEd Maste 		m -= 1;
46098dc8da5SEd Maste 		in += 1;
46198dc8da5SEd Maste 		n -= 1;
46298dc8da5SEd Maste 	}
46398dc8da5SEd Maste 
46498dc8da5SEd Maste 	return p - out;
46598dc8da5SEd Maste }
46698dc8da5SEd Maste 
46798dc8da5SEd Maste static void
ucs2pad(uint16_t * buf,int len,int size)46898dc8da5SEd Maste ucs2pad(uint16_t *buf, int len, int size)
46998dc8da5SEd Maste {
47098dc8da5SEd Maste 
47198dc8da5SEd Maste 	if (len < size-1)
47298dc8da5SEd Maste 		buf[len++] = 0x0000;
47398dc8da5SEd Maste 	while (len < size)
47498dc8da5SEd Maste 		buf[len++] = 0xffff;
47598dc8da5SEd Maste }
47698dc8da5SEd Maste 
47798dc8da5SEd Maste /*
47898dc8da5SEd Maste  * Compare two 8bit char conversions case-insensitive
47998dc8da5SEd Maste  *
48098dc8da5SEd Maste  * uses the DOS case folding table
48198dc8da5SEd Maste  */
48298dc8da5SEd Maste static int
char8match(uint16_t * w1,uint16_t * w2,int n)48398dc8da5SEd Maste char8match(uint16_t *w1, uint16_t *w2, int n)
48498dc8da5SEd Maste {
48598dc8da5SEd Maste 	uint16_t u1, u2;
48698dc8da5SEd Maste 
48798dc8da5SEd Maste 	while (n > 0) {
48898dc8da5SEd Maste 		u1 = le16toh(*w1);
48998dc8da5SEd Maste 		u2 = le16toh(*w2);
49098dc8da5SEd Maste 		if (u1 == 0 || u2 == 0)
49198dc8da5SEd Maste 			return u1 == u2;
49298dc8da5SEd Maste 		if (u1 > 255 || u2 > 255)
49398dc8da5SEd Maste 			return 0;
49498dc8da5SEd Maste 		u1 = u2l[u1 & 0xff];
49598dc8da5SEd Maste 		u2 = u2l[u2 & 0xff];
49698dc8da5SEd Maste 		if (u1 != u2)
49798dc8da5SEd Maste 			return 0;
49898dc8da5SEd Maste 		++w1;
49998dc8da5SEd Maste 		++w2;
50098dc8da5SEd Maste 		--n;
50198dc8da5SEd Maste 	}
50298dc8da5SEd Maste 
50398dc8da5SEd Maste 	return 1;
50498dc8da5SEd Maste }
505