Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/cd9660read.c
34677 views
1
/*
2
* Copyright (C) 1996 Wolfgang Solfrank.
3
* Copyright (C) 1996 TooLs GmbH.
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. All advertising materials mentioning features or use of this software
15
* must display the following acknowledgement:
16
* This product includes software developed by TooLs GmbH.
17
* 4. The name of TooLs GmbH may not be used to endorse or promote products
18
* derived from this software without specific prior written permission.
19
*
20
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
*/
31
32
/* Originally derived from libsa/cd9660.c: */
33
/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */
34
35
#include <sys/param.h>
36
#include <fs/cd9660/iso.h>
37
#include <fs/cd9660/cd9660_rrip.h>
38
39
static uint64_t cd9660_lookup(const char *);
40
static ssize_t cd9660_fsread(uint64_t, void *, size_t);
41
42
#define SUSP_CONTINUATION "CE"
43
#define SUSP_PRESENT "SP"
44
#define SUSP_STOP "ST"
45
#define SUSP_EXTREF "ER"
46
#define RRIP_NAME "NM"
47
48
typedef struct {
49
ISO_SUSP_HEADER h;
50
u_char signature [ISODCL ( 5, 6)];
51
u_char len_skp [ISODCL ( 7, 7)]; /* 711 */
52
} ISO_SUSP_PRESENT;
53
54
static int
55
read_iso_block(void *buffer, daddr_t blkno)
56
{
57
58
return (drvread(&dsk, buffer, blkno * 4, 4));
59
}
60
61
static ISO_SUSP_HEADER *
62
susp_lookup_record(const char *identifier, struct iso_directory_record *dp,
63
int lenskip)
64
{
65
static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE];
66
ISO_SUSP_HEADER *sh;
67
ISO_RRIP_CONT *shc;
68
char *p, *end;
69
int error;
70
71
p = dp->name + isonum_711(dp->name_len) + lenskip;
72
/* Names of even length have a padding byte after the name. */
73
if ((isonum_711(dp->name_len) & 1) == 0)
74
p++;
75
end = (char *)dp + isonum_711(dp->length);
76
while (p + 3 < end) {
77
sh = (ISO_SUSP_HEADER *)p;
78
if (bcmp(sh->type, identifier, 2) == 0)
79
return (sh);
80
if (bcmp(sh->type, SUSP_STOP, 2) == 0)
81
return (NULL);
82
if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
83
shc = (ISO_RRIP_CONT *)sh;
84
error = read_iso_block(susp_buffer,
85
isonum_733(shc->location));
86
87
/* Bail if it fails. */
88
if (error != 0)
89
return (NULL);
90
p = susp_buffer + isonum_733(shc->offset);
91
end = p + isonum_733(shc->length);
92
} else {
93
/* Ignore this record and skip to the next. */
94
p += isonum_711(sh->length);
95
96
/* Avoid infinite loops with corrupted file systems */
97
if (isonum_711(sh->length) == 0)
98
return (NULL);
99
}
100
}
101
return (NULL);
102
}
103
104
static const char *
105
rrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len)
106
{
107
ISO_RRIP_ALTNAME *p;
108
109
if (len == NULL)
110
return (NULL);
111
112
p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip);
113
if (p == NULL)
114
return (NULL);
115
switch (*p->flags) {
116
case ISO_SUSP_CFLAG_CURRENT:
117
*len = 1;
118
return (".");
119
case ISO_SUSP_CFLAG_PARENT:
120
*len = 2;
121
return ("..");
122
case 0:
123
*len = isonum_711(p->h.length) - 5;
124
return ((char *)p + 5);
125
default:
126
/*
127
* We don't handle hostnames or continued names as they are
128
* too hard, so just bail and use the default name.
129
*/
130
return (NULL);
131
}
132
}
133
134
static int
135
rrip_check(struct iso_directory_record *dp, int *lenskip)
136
{
137
ISO_SUSP_PRESENT *sp;
138
ISO_RRIP_EXTREF *er;
139
char *p;
140
141
/* First, see if we can find a SP field. */
142
p = dp->name + isonum_711(dp->name_len);
143
if (p > (char *)dp + isonum_711(dp->length)) {
144
return (0);
145
}
146
sp = (ISO_SUSP_PRESENT *)p;
147
if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) {
148
return (0);
149
}
150
if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) {
151
return (0);
152
}
153
if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) {
154
return (0);
155
}
156
*lenskip = isonum_711(sp->len_skp);
157
158
/*
159
* Now look for an ER field. If RRIP is present, then there must
160
* be at least one of these. It would be more pedantic to walk
161
* through the list of fields looking for a Rock Ridge ER field.
162
*/
163
er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0);
164
if (er == NULL) {
165
return (0);
166
}
167
return (1);
168
}
169
170
static int
171
dirmatch(const char *path, struct iso_directory_record *dp, int use_rrip,
172
int lenskip)
173
{
174
size_t len;
175
const char *cp = NULL;
176
int i, icase;
177
178
if (use_rrip)
179
cp = rrip_lookup_name(dp, lenskip, &len);
180
else
181
cp = NULL;
182
if (cp == NULL) {
183
len = isonum_711(dp->name_len);
184
cp = dp->name;
185
icase = 1;
186
} else
187
icase = 0;
188
for (i = len; --i >= 0; path++, cp++) {
189
if (!*path || *path == '/')
190
break;
191
if (*path == *cp)
192
continue;
193
if (!icase && toupper(*path) == *cp)
194
continue;
195
return 0;
196
}
197
if (*path && *path != '/') {
198
return 0;
199
}
200
/*
201
* Allow stripping of trailing dots and the version number.
202
* Note that this will find the first instead of the last version
203
* of a file.
204
*/
205
if (i >= 0 && (*cp == ';' || *cp == '.')) {
206
/* This is to prevent matching of numeric extensions */
207
if (*cp == '.' && cp[1] != ';') {
208
return 0;
209
}
210
while (--i >= 0)
211
if (*++cp != ';' && (*cp < '0' || *cp > '9')) {
212
return 0;
213
}
214
}
215
return 1;
216
}
217
218
static uint64_t
219
cd9660_lookup(const char *path)
220
{
221
static char blkbuf[MAX(ISO_DEFAULT_BLOCK_SIZE,
222
sizeof(struct iso_primary_descriptor))];
223
struct iso_primary_descriptor *vd;
224
struct iso_directory_record rec;
225
struct iso_directory_record *dp = NULL;
226
size_t dsize, off;
227
daddr_t bno, boff;
228
int rc, first, use_rrip, lenskip;
229
uint64_t cookie;
230
231
for (bno = 16;; bno++) {
232
rc = read_iso_block(blkbuf, bno);
233
vd = (struct iso_primary_descriptor *)blkbuf;
234
235
if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
236
return (0);
237
if (isonum_711(vd->type) == ISO_VD_END)
238
return (0);
239
if (isonum_711(vd->type) == ISO_VD_PRIMARY)
240
break;
241
}
242
243
bcopy(vd->root_directory_record, &rec, sizeof(rec));
244
if (*path == '/') path++; /* eat leading '/' */
245
246
first = 1;
247
use_rrip = 0;
248
lenskip = 0;
249
while (*path) {
250
bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
251
dsize = isonum_733(rec.size);
252
off = 0;
253
boff = 0;
254
255
while (off < dsize) {
256
if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
257
rc = read_iso_block(blkbuf, bno + boff);
258
if (rc) {
259
return (0);
260
}
261
boff++;
262
dp = (struct iso_directory_record *) blkbuf;
263
}
264
if (isonum_711(dp->length) == 0) {
265
/* skip to next block, if any */
266
off = boff * ISO_DEFAULT_BLOCK_SIZE;
267
continue;
268
}
269
270
/* See if RRIP is in use. */
271
if (first)
272
use_rrip = rrip_check(dp, &lenskip);
273
274
if (dirmatch(path, dp, use_rrip,
275
first ? 0 : lenskip)) {
276
first = 0;
277
break;
278
} else
279
first = 0;
280
281
dp = (struct iso_directory_record *)
282
((char *) dp + isonum_711(dp->length));
283
/* If the new block has zero length, it is padding. */
284
if (isonum_711(dp->length) == 0) {
285
/* Skip to next block, if any. */
286
off = boff * ISO_DEFAULT_BLOCK_SIZE;
287
continue;
288
}
289
off += isonum_711(dp->length);
290
}
291
if (off >= dsize) {
292
return (0);
293
}
294
295
rec = *dp;
296
while (*path && *path != '/') /* look for next component */
297
path++;
298
if (*path) path++; /* skip '/' */
299
}
300
301
if ((isonum_711(rec.flags) & 2) != 0) {
302
return (0);
303
}
304
305
cookie = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
306
cookie = (cookie << 32) | isonum_733(rec.size);
307
308
return (cookie);
309
}
310
311
static ssize_t
312
cd9660_fsread(uint64_t cookie, void *buf, size_t nbytes)
313
{
314
static char blkbuf[ISO_DEFAULT_BLOCK_SIZE];
315
static daddr_t curstart = 0, curblk = 0;
316
daddr_t blk, blk_off;
317
off_t byte_off;
318
size_t size, remaining, n;
319
char *s;
320
321
size = cookie & 0xffffffff;
322
blk = (cookie >> 32) & 0xffffffff;
323
324
/* Make sure we're looking at the right file. */
325
if (((blk << 32) | size) != cookie) {
326
return (-1);
327
}
328
329
if (blk != curstart) {
330
curstart = blk;
331
fs_off = 0;
332
}
333
334
size -= fs_off;
335
if (size < nbytes) {
336
nbytes = size;
337
}
338
remaining = nbytes;
339
s = buf;
340
341
while (remaining > 0) {
342
blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT;
343
byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1);
344
345
if (curblk != curstart + blk_off) {
346
curblk = curstart + blk_off;
347
read_iso_block(blkbuf, curblk);
348
}
349
350
if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) {
351
n = remaining;
352
} else {
353
n = ISO_DEFAULT_BLOCK_SIZE - byte_off;
354
}
355
memcpy(s, blkbuf + byte_off, n);
356
remaining -= n;
357
s += n;
358
359
fs_off += n;
360
}
361
362
return (nbytes);
363
}
364
365