xref: /minix3/sys/fs/cd9660/cd9660_util.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: cd9660_util.c,v 1.12 2014/11/10 18:46:33 maxv Exp $	*/
284d9c625SLionel Sambuc 
384d9c625SLionel Sambuc /*-
484d9c625SLionel Sambuc  * Copyright (c) 1994
584d9c625SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
684d9c625SLionel Sambuc  *
784d9c625SLionel Sambuc  * This code is derived from software contributed to Berkeley
884d9c625SLionel Sambuc  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
984d9c625SLionel Sambuc  * Support code is derived from software contributed to Berkeley
1084d9c625SLionel Sambuc  * by Atsushi Murai (amurai@spec.co.jp).
1184d9c625SLionel Sambuc  *
1284d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
1384d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
1484d9c625SLionel Sambuc  * are met:
1584d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1684d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1784d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1884d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1984d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
2084d9c625SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
2184d9c625SLionel Sambuc  *    may be used to endorse or promote products derived from this software
2284d9c625SLionel Sambuc  *    without specific prior written permission.
2384d9c625SLionel Sambuc  *
2484d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2584d9c625SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2684d9c625SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2784d9c625SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2884d9c625SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2984d9c625SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3084d9c625SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3184d9c625SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3284d9c625SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3384d9c625SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3484d9c625SLionel Sambuc  * SUCH DAMAGE.
3584d9c625SLionel Sambuc  *
3684d9c625SLionel Sambuc  *	@(#)cd9660_util.c	8.3 (Berkeley) 12/5/94
3784d9c625SLionel Sambuc  */
3884d9c625SLionel Sambuc 
3984d9c625SLionel Sambuc #include <sys/cdefs.h>
40*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: cd9660_util.c,v 1.12 2014/11/10 18:46:33 maxv Exp $");
4184d9c625SLionel Sambuc 
4284d9c625SLionel Sambuc #include <sys/param.h>
4384d9c625SLionel Sambuc #include <sys/systm.h>
4484d9c625SLionel Sambuc #include <sys/namei.h>
4584d9c625SLionel Sambuc #include <sys/resourcevar.h>
4684d9c625SLionel Sambuc #include <sys/kernel.h>
4784d9c625SLionel Sambuc #include <sys/file.h>
4884d9c625SLionel Sambuc #include <sys/stat.h>
4984d9c625SLionel Sambuc #include <sys/buf.h>
5084d9c625SLionel Sambuc #include <sys/proc.h>
5184d9c625SLionel Sambuc #include <sys/mount.h>
5284d9c625SLionel Sambuc #include <sys/vnode.h>
5384d9c625SLionel Sambuc #include <sys/dirent.h>
5484d9c625SLionel Sambuc 
5584d9c625SLionel Sambuc #include <fs/cd9660/iso.h>
5684d9c625SLionel Sambuc #include <fs/cd9660/cd9660_extern.h>
5784d9c625SLionel Sambuc 
5884d9c625SLionel Sambuc #include <fs/unicode.h>
5984d9c625SLionel Sambuc 
6084d9c625SLionel Sambuc static u_int16_t wget(const u_char **, size_t *, int);
6184d9c625SLionel Sambuc static int wput(u_char *, size_t, u_int16_t, int);
6284d9c625SLionel Sambuc 
6384d9c625SLionel Sambuc int cd9660_utf8_joliet = 1;
6484d9c625SLionel Sambuc 
6584d9c625SLionel Sambuc /*
6684d9c625SLionel Sambuc  * Get one character out of an iso filename
6784d9c625SLionel Sambuc  * Return number of bytes consumed
6884d9c625SLionel Sambuc  */
6984d9c625SLionel Sambuc int
isochar(const u_char * isofn,const u_char * isoend,int joliet_level,u_int16_t * c)7084d9c625SLionel Sambuc isochar(const u_char *isofn, const u_char *isoend, int joliet_level,
7184d9c625SLionel Sambuc 	u_int16_t *c)
7284d9c625SLionel Sambuc {
7384d9c625SLionel Sambuc 	*c = isofn[0];
7484d9c625SLionel Sambuc 	if (joliet_level == 0 || isofn + 1 == isoend) {
7584d9c625SLionel Sambuc 		/* (00) and (01) are one byte in Joliet, too */
7684d9c625SLionel Sambuc 		return 1;
7784d9c625SLionel Sambuc 	}
7884d9c625SLionel Sambuc 
7984d9c625SLionel Sambuc 	if (cd9660_utf8_joliet) {
8084d9c625SLionel Sambuc 		*c = (*c << 8) + isofn[1];
8184d9c625SLionel Sambuc 	} else {
8284d9c625SLionel Sambuc 		/* characters outside ISO-8859-1 subset replaced with '?' */
8384d9c625SLionel Sambuc 		if (*c != 0)
8484d9c625SLionel Sambuc 			*c = '?';
8584d9c625SLionel Sambuc 		else
8684d9c625SLionel Sambuc 			*c = isofn[1];
8784d9c625SLionel Sambuc 	}
8884d9c625SLionel Sambuc 
8984d9c625SLionel Sambuc 	return 2;
9084d9c625SLionel Sambuc }
9184d9c625SLionel Sambuc 
9284d9c625SLionel Sambuc /*
9384d9c625SLionel Sambuc  * translate and compare a filename
9484d9c625SLionel Sambuc  * Note: Version number plus ';' may be omitted.
9584d9c625SLionel Sambuc  */
9684d9c625SLionel Sambuc int
isofncmp(const u_char * fn,size_t fnlen,const u_char * isofn,size_t isolen,int joliet_level)9784d9c625SLionel Sambuc isofncmp(const u_char *fn, size_t fnlen, const u_char *isofn, size_t isolen,
9884d9c625SLionel Sambuc 	int joliet_level)
9984d9c625SLionel Sambuc {
10084d9c625SLionel Sambuc 	int i, j;
10184d9c625SLionel Sambuc 	u_int16_t fc, ic;
10284d9c625SLionel Sambuc 	const u_char *isoend = isofn + isolen;
10384d9c625SLionel Sambuc 
10484d9c625SLionel Sambuc 	while (fnlen > 0) {
10584d9c625SLionel Sambuc 		fc = wget(&fn, &fnlen, joliet_level);
10684d9c625SLionel Sambuc 
10784d9c625SLionel Sambuc 		if (isofn == isoend)
10884d9c625SLionel Sambuc 			return fc;
10984d9c625SLionel Sambuc 		isofn += isochar(isofn, isoend, joliet_level, &ic);
11084d9c625SLionel Sambuc 		if (ic == ';') {
11184d9c625SLionel Sambuc 			switch (fc) {
11284d9c625SLionel Sambuc 			default:
11384d9c625SLionel Sambuc 				return fc;
11484d9c625SLionel Sambuc 			case 0:
11584d9c625SLionel Sambuc 				return 0;
11684d9c625SLionel Sambuc 			case ';':
11784d9c625SLionel Sambuc 				break;
11884d9c625SLionel Sambuc 			}
11984d9c625SLionel Sambuc 			for (i = 0; fnlen-- != 0; i = i * 10 + *fn++ - '0') {
12084d9c625SLionel Sambuc 				if (*fn < '0' || *fn > '9') {
12184d9c625SLionel Sambuc 					return -1;
12284d9c625SLionel Sambuc 				}
12384d9c625SLionel Sambuc 			}
12484d9c625SLionel Sambuc 			for (j = 0; isofn != isoend; j = j * 10 + ic - '0')
12584d9c625SLionel Sambuc 				isofn += isochar(isofn, isoend,
12684d9c625SLionel Sambuc 						 joliet_level, &ic);
12784d9c625SLionel Sambuc 			return i - j;
12884d9c625SLionel Sambuc 		}
12984d9c625SLionel Sambuc 		if (ic != fc) {
13084d9c625SLionel Sambuc 			if (ic >= 'A' && ic <= 'Z') {
13184d9c625SLionel Sambuc 				if (ic + ('a' - 'A') != fc) {
13284d9c625SLionel Sambuc 					if (fc >= 'a' && fc <= 'z')
13384d9c625SLionel Sambuc 						fc -= 'a' - 'A';
13484d9c625SLionel Sambuc 
13584d9c625SLionel Sambuc 					return (int) fc - (int) ic;
13684d9c625SLionel Sambuc 				}
13784d9c625SLionel Sambuc 			} else
13884d9c625SLionel Sambuc 				return (int) fc - (int) ic;
13984d9c625SLionel Sambuc 		}
14084d9c625SLionel Sambuc 	}
14184d9c625SLionel Sambuc 	if (isofn != isoend) {
14284d9c625SLionel Sambuc 		isofn += isochar(isofn, isoend, joliet_level, &ic);
14384d9c625SLionel Sambuc 		switch (ic) {
14484d9c625SLionel Sambuc 		default:
14584d9c625SLionel Sambuc 			return -1;
14684d9c625SLionel Sambuc 		case '.':
14784d9c625SLionel Sambuc 			if (isofn != isoend) {
14884d9c625SLionel Sambuc 				isochar(isofn, isoend, joliet_level, &ic);
14984d9c625SLionel Sambuc 				if (ic == ';')
15084d9c625SLionel Sambuc 					return 0;
15184d9c625SLionel Sambuc 			}
15284d9c625SLionel Sambuc 			return -1;
15384d9c625SLionel Sambuc 		case ';':
15484d9c625SLionel Sambuc 			return 0;
15584d9c625SLionel Sambuc 		}
15684d9c625SLionel Sambuc 	}
15784d9c625SLionel Sambuc 	return 0;
15884d9c625SLionel Sambuc }
15984d9c625SLionel Sambuc 
16084d9c625SLionel Sambuc /*
16184d9c625SLionel Sambuc  * translate a filename
16284d9c625SLionel Sambuc  */
16384d9c625SLionel Sambuc void
isofntrans(const u_char * infn,int infnlen,u_char * outfn,u_short * outfnlen,int original,int casetrans,int assoc,int joliet_level)16484d9c625SLionel Sambuc isofntrans(const u_char *infn, int infnlen, u_char *outfn, u_short *outfnlen,
16584d9c625SLionel Sambuc 	int original, int casetrans, int assoc, int joliet_level)
16684d9c625SLionel Sambuc {
16784d9c625SLionel Sambuc 	int fnidx = 0;
16884d9c625SLionel Sambuc 	const u_char *infnend = infn + infnlen;
16984d9c625SLionel Sambuc 	u_int16_t c;
17084d9c625SLionel Sambuc 	int sz;
17184d9c625SLionel Sambuc 
17284d9c625SLionel Sambuc 	if (assoc) {
17384d9c625SLionel Sambuc 		*outfn++ = ASSOCCHAR;
17484d9c625SLionel Sambuc 		fnidx++;
17584d9c625SLionel Sambuc 	}
17684d9c625SLionel Sambuc 
17784d9c625SLionel Sambuc 	for(; infn != infnend; fnidx += sz) {
17884d9c625SLionel Sambuc 		infn += isochar(infn, infnend, joliet_level, &c);
17984d9c625SLionel Sambuc 
18084d9c625SLionel Sambuc 		if (casetrans && joliet_level == 0 && c >= 'A' && c <= 'Z')
18184d9c625SLionel Sambuc 			c = c + ('a' - 'A');
18284d9c625SLionel Sambuc 		else if (!original && c == ';') {
18384d9c625SLionel Sambuc 			if (fnidx > 0 && outfn[-1] == '.')
18484d9c625SLionel Sambuc 				fnidx--;
18584d9c625SLionel Sambuc 			break;
18684d9c625SLionel Sambuc 		}
18784d9c625SLionel Sambuc 
18884d9c625SLionel Sambuc 		sz = wput(outfn, ISO_MAXNAMLEN - fnidx, c, joliet_level);
18984d9c625SLionel Sambuc 		if (sz == 0) {
19084d9c625SLionel Sambuc 			/* not enough space to write the character */
19184d9c625SLionel Sambuc 			if (fnidx < ISO_MAXNAMLEN) {
19284d9c625SLionel Sambuc 				*outfn = '?';
19384d9c625SLionel Sambuc 				fnidx++;
19484d9c625SLionel Sambuc 			}
19584d9c625SLionel Sambuc 			break;
19684d9c625SLionel Sambuc 		}
19784d9c625SLionel Sambuc 		outfn += sz;
19884d9c625SLionel Sambuc 	}
19984d9c625SLionel Sambuc 	*outfnlen = fnidx;
20084d9c625SLionel Sambuc }
20184d9c625SLionel Sambuc 
20284d9c625SLionel Sambuc static u_int16_t
wget(const u_char ** str,size_t * sz,int joliet_level)20384d9c625SLionel Sambuc wget(const u_char **str, size_t *sz, int joliet_level)
20484d9c625SLionel Sambuc {
20584d9c625SLionel Sambuc 	if (joliet_level > 0 && cd9660_utf8_joliet) {
20684d9c625SLionel Sambuc 		/* decode UTF-8 sequence */
20784d9c625SLionel Sambuc 		return wget_utf8((const char **) str, sz);
20884d9c625SLionel Sambuc 	} else {
20984d9c625SLionel Sambuc 		/*
21084d9c625SLionel Sambuc 		 * Raw 8-bit characters without any conversion. For Joliet,
21184d9c625SLionel Sambuc 		 * this effectively assumes provided file name is using
21284d9c625SLionel Sambuc 		 * ISO-8859-1 subset.
21384d9c625SLionel Sambuc 		 */
21484d9c625SLionel Sambuc 		u_int16_t c = *str[0];
21584d9c625SLionel Sambuc 		(*str)++;
21684d9c625SLionel Sambuc 		(*sz)--;
21784d9c625SLionel Sambuc 
21884d9c625SLionel Sambuc 		return c;
21984d9c625SLionel Sambuc 	}
22084d9c625SLionel Sambuc }
22184d9c625SLionel Sambuc 
22284d9c625SLionel Sambuc static int
wput(u_char * s,size_t n,u_int16_t c,int joliet_level)22384d9c625SLionel Sambuc wput(u_char *s, size_t n, u_int16_t c, int joliet_level)
22484d9c625SLionel Sambuc {
22584d9c625SLionel Sambuc 	if (joliet_level > 0 && cd9660_utf8_joliet) {
22684d9c625SLionel Sambuc 		/* Store Joliet file name encoded into UTF-8 */
22784d9c625SLionel Sambuc 		return wput_utf8((char *)s, n, c);
22884d9c625SLionel Sambuc 	} else {
22984d9c625SLionel Sambuc 		/*
23084d9c625SLionel Sambuc 		 * Store raw 8-bit characters without any conversion.
23184d9c625SLionel Sambuc 		 * For Joliet case, this filters the Unicode characters
23284d9c625SLionel Sambuc 		 * to ISO-8859-1 subset.
23384d9c625SLionel Sambuc 		 */
23484d9c625SLionel Sambuc 		*s = (u_char)c;
23584d9c625SLionel Sambuc 		return 1;
23684d9c625SLionel Sambuc 	}
23784d9c625SLionel Sambuc }
238