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