1/* $NetBSD: cd9660_util.c,v 1.14 2016/03/09 20:18:17 christos Exp $ */
2
3/*-
4 * Copyright (c) 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley
8 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai@spec.co.jp).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)cd9660_util.c 8.3 (Berkeley) 12/5/94
37 */
38
39#include <sys/cdefs.h>
40#ifdef _KERNEL
41__KERNEL_RCSID(0, "$NetBSD: cd9660_util.c,v 1.14 2016/03/09 20:18:17 christos Exp $");
42#else
43/* used by macppc_installboot */
44#if HAVE_NBTOOL_CONFIG_H
45#include "nbtool_config.h"
46#endif
47#endif
48
49#include <sys/param.h>
50#ifdef _KERNEL
51#include <sys/systm.h>
52#include <sys/namei.h>
53#include <sys/resourcevar.h>
54#include <sys/kernel.h>
55#include <sys/file.h>
56#include <sys/stat.h>
57#include <sys/buf.h>
58#include <sys/proc.h>
59#include <sys/mount.h>
60#include <sys/vnode.h>
61#include <sys/dirent.h>
62#else
63#include <assert.h>
64#include <dirent.h>
65#define KASSERT(x) assert(x) /* XXX for <fs/unicode.h> */
66#endif
67
68#include <fs/cd9660/iso.h>
69#ifdef _KERNEL
70#include <fs/cd9660/cd9660_extern.h>
71#else
72static int isochar(const u_char *, const u_char *, int, uint16_t *);
73#endif
74
75#include <fs/unicode.h>
76
77static uint16_t wget(const u_char **, size_t *, int);
78static int wput(u_char *, size_t, uint16_t, int);
79
80int cd9660_utf8_joliet = 1;
81
82/*
83 * Get one character out of an iso filename
84 * Return number of bytes consumed
85 */
86int
87isochar(const u_char *isofn, const u_char *isoend, int joliet_level,
88 uint16_t *c)
89{
90
91 *c = isofn[0];
92 if (joliet_level == 0 || isofn + 1 == isoend) {
93 /* (00) and (01) are one byte in Joliet, too */
94 return 1;
95 }
96
97 if (cd9660_utf8_joliet) {
98 *c = (*c << 8) + isofn[1];
99 } else {
100 /* characters outside ISO-8859-1 subset replaced with '?' */
101 if (*c != 0)
102 *c = '?';
103 else
104 *c = isofn[1];
105 }
106
107 return 2;
108}
109
110/*
111 * translate and compare a filename
112 * Note: Version number plus ';' may be omitted.
113 */
114int
115isofncmp(const u_char *fn, size_t fnlen, const u_char *isofn, size_t isolen,
116 int joliet_level)
117{
118 int i, j;
119 uint16_t fc, ic;
120 const u_char *isoend = isofn + isolen;
121
122#ifdef ISOFNCMPDEBUG
123 printf("fn = %s, fnlen = %zu, isofn = %s, isolen = %zu\n",
124 fn, fnlen, isofn, isolen);
125#endif
126
127 while (fnlen > 0) {
128 fc = wget(&fn, &fnlen, joliet_level);
129
130 if (isofn == isoend)
131 return fc;
132 isofn += isochar(isofn, isoend, joliet_level, &ic);
133 if (ic == ';') {
134 switch (fc) {
135 default:
136 return fc;
137 case 0:
138 return 0;
139 case ';':
140 break;
141 }
142 for (i = 0; fnlen-- != 0; i = i * 10 + *fn++ - '0') {
143 if (*fn < '0' || *fn > '9') {
144 return -1;
145 }
146 }
147 for (j = 0; isofn != isoend; j = j * 10 + ic - '0')
148 isofn += isochar(isofn, isoend,
149 joliet_level, &ic);
150 return i - j;
151 }
152 if (ic != fc) {
153 if (ic >= 'A' && ic <= 'Z') {
154 if (ic + ('a' - 'A') != fc) {
155 if (fc >= 'a' && fc <= 'z')
156 fc -= 'a' - 'A';
157
158 return (int)fc - (int)ic;
159 }
160 } else
161 return (int)fc - (int)ic;
162 }
163 }
164 if (isofn != isoend) {
165 isofn += isochar(isofn, isoend, joliet_level, &ic);
166 switch (ic) {
167 default:
168 return -1;
169 case '.':
170 if (isofn != isoend) {
171 isochar(isofn, isoend, joliet_level, &ic);
172 if (ic == ';')
173 return 0;
174 }
175 return -1;
176 case ';':
177 return 0;
178 }
179 }
180 return 0;
181}
182
183/*
184 * translate a filename
185 */
186void
187isofntrans(const u_char *infn, int infnlen, u_char *outfn, u_short *outfnlen,
188 int original, int casetrans, int assoc, int joliet_level)
189{
190 int fnidx = 0;
191 const u_char *infnend = infn + infnlen;
192 uint16_t c;
193 int sz;
194
195 if (assoc) {
196 *outfn++ = ASSOCCHAR;
197 fnidx++;
198 }
199
200 for(; infn != infnend; fnidx += sz) {
201 infn += isochar(infn, infnend, joliet_level, &c);
202
203 if (casetrans && joliet_level == 0 && c >= 'A' && c <= 'Z')
204 c = c + ('a' - 'A');
205 else if (!original && c == ';') {
206 if (fnidx > 0 && outfn[-1] == '.')
207 fnidx--;
208 break;
209 }
210
211 sz = wput(outfn, ISO_MAXNAMLEN - fnidx, c, joliet_level);
212 if (sz == 0) {
213 /* not enough space to write the character */
214 if (fnidx < ISO_MAXNAMLEN) {
215 *outfn = '?';
216 fnidx++;
217 }
218 break;
219 }
220 outfn += sz;
221 }
222 *outfnlen = fnidx;
223}
224
225static uint16_t
226wget(const u_char **str, size_t *sz, int joliet_level)
227{
228 if (joliet_level > 0 && cd9660_utf8_joliet) {
229 /* decode UTF-8 sequence */
230 return wget_utf8((const char **) str, sz);
231 } else {
232 /*
233 * Raw 8-bit characters without any conversion. For Joliet,
234 * this effectively assumes provided file name is using
235 * ISO-8859-1 subset.
236 */
237 uint16_t c = *str[0];
238 (*str)++;
239 (*sz)--;
240
241 return c;
242 }
243}
244
245static int
246wput(u_char *s, size_t n, uint16_t c, int joliet_level)
247{
248 if (joliet_level > 0 && cd9660_utf8_joliet) {
249 /* Store Joliet file name encoded into UTF-8 */
250 return wput_utf8((char *)s, n, c);
251 } else {
252 /*
253 * Store raw 8-bit characters without any conversion.
254 * For Joliet case, this filters the Unicode characters
255 * to ISO-8859-1 subset.
256 */
257 *s = (u_char)c;
258 return 1;
259 }
260}
261