Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/cd9660.c
34677 views
1
/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */
2
3
/*
4
* Copyright (C) 1996 Wolfgang Solfrank.
5
* Copyright (C) 1996 TooLs GmbH.
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
* 3. All advertising materials mentioning features or use of this software
17
* must display the following acknowledgement:
18
* This product includes software developed by TooLs GmbH.
19
* 4. The name of TooLs GmbH may not be used to endorse or promote products
20
* derived from this software without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
*/
33
34
/*
35
* Stand-alone ISO9660 file reading package.
36
*
37
* Note: This doesn't support Rock Ridge extensions, extended attributes,
38
* blocksizes other than 2048 bytes, multi-extent files, etc.
39
*/
40
#include <sys/param.h>
41
#include <string.h>
42
#include <stdbool.h>
43
#include <sys/dirent.h>
44
#include <fs/cd9660/iso.h>
45
#include <fs/cd9660/cd9660_rrip.h>
46
47
#include "stand.h"
48
49
#define SUSP_CONTINUATION "CE"
50
#define SUSP_PRESENT "SP"
51
#define SUSP_STOP "ST"
52
#define SUSP_EXTREF "ER"
53
#define RRIP_NAME "NM"
54
55
typedef struct {
56
ISO_SUSP_HEADER h;
57
u_char signature [ISODCL ( 5, 6)];
58
u_char len_skp [ISODCL ( 7, 7)]; /* 711 */
59
} ISO_SUSP_PRESENT;
60
61
static int buf_read_file(struct open_file *f, char **buf_p,
62
size_t *size_p);
63
static int cd9660_open(const char *path, struct open_file *f);
64
static int cd9660_close(struct open_file *f);
65
static int cd9660_read(struct open_file *f, void *buf, size_t size,
66
size_t *resid);
67
static off_t cd9660_seek(struct open_file *f, off_t offset, int where);
68
static int cd9660_stat(struct open_file *f, struct stat *sb);
69
static int cd9660_readdir(struct open_file *f, struct dirent *d);
70
static int cd9660_mount(const char *, const char *, void **);
71
static int cd9660_unmount(const char *, void *);
72
static int dirmatch(struct open_file *f, const char *path,
73
struct iso_directory_record *dp, int use_rrip, int lenskip);
74
static int rrip_check(struct open_file *f, struct iso_directory_record *dp,
75
int *lenskip);
76
static char *rrip_lookup_name(struct open_file *f,
77
struct iso_directory_record *dp, int lenskip, size_t *len);
78
static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f,
79
const char *identifier, struct iso_directory_record *dp,
80
int lenskip);
81
82
struct fs_ops cd9660_fsops = {
83
.fs_name = "cd9660",
84
.fs_flags = 0,
85
.fo_open = cd9660_open,
86
.fo_close = cd9660_close,
87
.fo_read = cd9660_read,
88
.fo_write = null_write,
89
.fo_seek = cd9660_seek,
90
.fo_stat = cd9660_stat,
91
.fo_readdir = cd9660_readdir,
92
.fo_mount = cd9660_mount,
93
.fo_unmount = cd9660_unmount
94
};
95
96
typedef struct cd9660_mnt {
97
struct devdesc *cd_dev;
98
int cd_fd;
99
struct iso_directory_record cd_rec;
100
STAILQ_ENTRY(cd9660_mnt) cd_link;
101
} cd9660_mnt_t;
102
103
typedef STAILQ_HEAD(cd9660_mnt_list, cd9660_mnt) cd9660_mnt_list_t;
104
static cd9660_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
105
106
#define F_ISDIR 0x0001 /* Directory */
107
#define F_ROOTDIR 0x0002 /* Root directory */
108
#define F_RR 0x0004 /* Rock Ridge on this volume */
109
110
struct file {
111
int f_flags; /* file flags */
112
off_t f_off; /* Current offset within file */
113
daddr_t f_bno; /* Starting block number */
114
off_t f_size; /* Size of file */
115
daddr_t f_buf_blkno; /* block number of data block */
116
char *f_buf; /* buffer for data block */
117
int f_susp_skip; /* len_skip for SUSP records */
118
};
119
120
struct ptable_ent {
121
char namlen [ISODCL( 1, 1)]; /* 711 */
122
char extlen [ISODCL( 2, 2)]; /* 711 */
123
char block [ISODCL( 3, 6)]; /* 732 */
124
char parent [ISODCL( 7, 8)]; /* 722 */
125
char name [1];
126
};
127
#define PTFIXSZ 8
128
#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
129
130
#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
131
132
static ISO_SUSP_HEADER *
133
susp_lookup_record(struct open_file *f, const char *identifier,
134
struct iso_directory_record *dp, int lenskip)
135
{
136
static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE];
137
ISO_SUSP_HEADER *sh;
138
ISO_RRIP_CONT *shc;
139
char *p, *end;
140
int error;
141
size_t read;
142
143
p = dp->name + isonum_711(dp->name_len) + lenskip;
144
/* Names of even length have a padding byte after the name. */
145
if ((isonum_711(dp->name_len) & 1) == 0)
146
p++;
147
end = (char *)dp + isonum_711(dp->length);
148
while (p + 3 < end) {
149
sh = (ISO_SUSP_HEADER *)p;
150
if (bcmp(sh->type, identifier, 2) == 0)
151
return (sh);
152
if (bcmp(sh->type, SUSP_STOP, 2) == 0)
153
return (NULL);
154
if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
155
shc = (ISO_RRIP_CONT *)sh;
156
error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
157
cdb2devb(isonum_733(shc->location)),
158
ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read);
159
160
/* Bail if it fails. */
161
if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE)
162
return (NULL);
163
p = susp_buffer + isonum_733(shc->offset);
164
end = p + isonum_733(shc->length);
165
} else {
166
/* Ignore this record and skip to the next. */
167
p += isonum_711(sh->length);
168
169
/* Avoid infinite loops with corrupted file systems */
170
if (isonum_711(sh->length) == 0)
171
return (NULL);
172
}
173
}
174
return (NULL);
175
}
176
177
static char *
178
rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp,
179
int lenskip, size_t *len)
180
{
181
ISO_RRIP_ALTNAME *p;
182
183
if (len == NULL)
184
return (NULL);
185
186
p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip);
187
if (p == NULL)
188
return (NULL);
189
switch (*p->flags) {
190
case ISO_SUSP_CFLAG_CURRENT:
191
*len = 1;
192
return (".");
193
case ISO_SUSP_CFLAG_PARENT:
194
*len = 2;
195
return ("..");
196
case 0:
197
*len = isonum_711(p->h.length) - 5;
198
return ((char *)p + 5);
199
default:
200
/*
201
* We don't handle hostnames or continued names as they are
202
* too hard, so just bail and use the default name.
203
*/
204
return (NULL);
205
}
206
}
207
208
static int
209
rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip)
210
{
211
ISO_SUSP_PRESENT *sp;
212
ISO_RRIP_EXTREF *er;
213
char *p;
214
215
/* First, see if we can find a SP field. */
216
p = dp->name + isonum_711(dp->name_len);
217
if (p > (char *)dp + isonum_711(dp->length))
218
return (0);
219
sp = (ISO_SUSP_PRESENT *)p;
220
if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0)
221
return (0);
222
if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT))
223
return (0);
224
if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef)
225
return (0);
226
*lenskip = isonum_711(sp->len_skp);
227
228
/*
229
* Now look for an ER field. If RRIP is present, then there must
230
* be at least one of these. It would be more pedantic to walk
231
* through the list of fields looking for a Rock Ridge ER field.
232
*/
233
er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0);
234
if (er == NULL)
235
return (0);
236
return (1);
237
}
238
239
static int
240
dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp,
241
int use_rrip, int lenskip)
242
{
243
size_t len, plen;
244
char *cp, *sep;
245
int i, icase;
246
247
if (use_rrip)
248
cp = rrip_lookup_name(f, dp, lenskip, &len);
249
else
250
cp = NULL;
251
if (cp == NULL) {
252
len = isonum_711(dp->name_len);
253
cp = dp->name;
254
icase = 1;
255
} else
256
icase = 0;
257
258
sep = strchr(path, '/');
259
if (sep != NULL) {
260
plen = sep - path;
261
} else {
262
plen = strlen(path);
263
}
264
265
if (plen != len)
266
return (0);
267
268
for (i = len; --i >= 0; path++, cp++) {
269
if (!*path || *path == '/')
270
break;
271
if (*path == *cp)
272
continue;
273
if (!icase && toupper(*path) == *cp)
274
continue;
275
return 0;
276
}
277
if (*path && *path != '/')
278
return 0;
279
/*
280
* Allow stripping of trailing dots and the version number.
281
* Note that this will find the first instead of the last version
282
* of a file.
283
*/
284
if (i >= 0 && (*cp == ';' || *cp == '.')) {
285
/* This is to prevent matching of numeric extensions */
286
if (*cp == '.' && cp[1] != ';')
287
return 0;
288
while (--i >= 0)
289
if (*++cp != ';' && (*cp < '0' || *cp > '9'))
290
return 0;
291
}
292
return 1;
293
}
294
295
static int
296
cd9660_read_dr(struct open_file *f, struct iso_directory_record *rec)
297
{
298
struct iso_primary_descriptor *vd;
299
size_t read;
300
daddr_t bno;
301
int rc;
302
303
errno = 0;
304
vd = malloc(MAX(ISO_DEFAULT_BLOCK_SIZE,
305
sizeof(struct iso_primary_descriptor)));
306
if (vd == NULL)
307
return (errno);
308
309
for (bno = 16;; bno++) {
310
twiddle(1);
311
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
312
ISO_DEFAULT_BLOCK_SIZE, (char *)vd, &read);
313
if (rc)
314
goto out;
315
if (read != ISO_DEFAULT_BLOCK_SIZE) {
316
rc = EIO;
317
goto out;
318
}
319
rc = EINVAL;
320
if (bcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0)
321
goto out;
322
if (isonum_711(vd->type) == ISO_VD_END)
323
goto out;
324
if (isonum_711(vd->type) == ISO_VD_PRIMARY)
325
break;
326
}
327
if (isonum_723(vd->logical_block_size) == ISO_DEFAULT_BLOCK_SIZE) {
328
bcopy(vd->root_directory_record, rec, sizeof(*rec));
329
rc = 0;
330
}
331
out:
332
free(vd);
333
return (rc);
334
}
335
336
static int
337
cd9660_open(const char *path, struct open_file *f)
338
{
339
struct file *fp = NULL;
340
void *buf;
341
size_t read, dsize, off;
342
daddr_t bno, boff;
343
struct iso_directory_record rec;
344
struct iso_directory_record *dp = NULL;
345
int rc, first, use_rrip, lenskip;
346
bool isdir = false;
347
struct devdesc *dev;
348
cd9660_mnt_t *mnt;
349
350
/* First find the volume descriptor */
351
errno = 0;
352
buf = malloc(MAX(ISO_DEFAULT_BLOCK_SIZE,
353
sizeof(struct iso_primary_descriptor)));
354
if (buf == NULL)
355
return (errno);
356
357
dev = f->f_devdata;
358
STAILQ_FOREACH(mnt, &mnt_list, cd_link) {
359
if (dev->d_dev->dv_type == mnt->cd_dev->d_dev->dv_type &&
360
dev->d_unit == mnt->cd_dev->d_unit)
361
break;
362
}
363
364
rc = 0;
365
if (mnt == NULL)
366
rc = cd9660_read_dr(f, &rec);
367
else
368
rec = mnt->cd_rec;
369
370
if (rc != 0)
371
goto out;
372
373
if (*path == '/')
374
path++; /* eat leading '/' */
375
376
first = 1;
377
use_rrip = 0;
378
lenskip = 0;
379
while (*path) {
380
bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
381
dsize = isonum_733(rec.size);
382
off = 0;
383
boff = 0;
384
385
while (off < dsize) {
386
if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
387
twiddle(1);
388
rc = f->f_dev->dv_strategy
389
(f->f_devdata, F_READ,
390
cdb2devb(bno + boff),
391
ISO_DEFAULT_BLOCK_SIZE,
392
buf, &read);
393
if (rc)
394
goto out;
395
if (read != ISO_DEFAULT_BLOCK_SIZE) {
396
rc = EIO;
397
goto out;
398
}
399
boff++;
400
dp = (struct iso_directory_record *) buf;
401
}
402
if (isonum_711(dp->length) == 0) {
403
/* skip to next block, if any */
404
off = boff * ISO_DEFAULT_BLOCK_SIZE;
405
continue;
406
}
407
408
/* See if RRIP is in use. */
409
if (first)
410
use_rrip = rrip_check(f, dp, &lenskip);
411
412
if (dirmatch(f, path, dp, use_rrip,
413
first ? 0 : lenskip)) {
414
first = 0;
415
break;
416
} else
417
first = 0;
418
419
dp = (struct iso_directory_record *)
420
((char *) dp + isonum_711(dp->length));
421
/* If the new block has zero length, it is padding. */
422
if (isonum_711(dp->length) == 0) {
423
/* Skip to next block, if any. */
424
off = boff * ISO_DEFAULT_BLOCK_SIZE;
425
continue;
426
}
427
off += isonum_711(dp->length);
428
}
429
if (off >= dsize) {
430
rc = ENOENT;
431
goto out;
432
}
433
434
rec = *dp;
435
while (*path && *path != '/') /* look for next component */
436
path++;
437
438
if (*path) /* this component was directory */
439
isdir = true;
440
441
while (*path == '/')
442
path++; /* skip '/' */
443
444
if (*path) /* We do have next component. */
445
isdir = false;
446
}
447
448
/*
449
* if the path had trailing / but the path does point to file,
450
* report the error ENOTDIR.
451
*/
452
if (isdir == true && (isonum_711(rec.flags) & 2) == 0) {
453
rc = ENOTDIR;
454
goto out;
455
}
456
457
/* allocate file system specific data structure */
458
fp = malloc(sizeof(struct file));
459
bzero(fp, sizeof(struct file));
460
f->f_fsdata = (void *)fp;
461
462
if ((isonum_711(rec.flags) & 2) != 0) {
463
fp->f_flags = F_ISDIR;
464
}
465
if (first) {
466
fp->f_flags |= F_ROOTDIR;
467
468
/* Check for Rock Ridge since we didn't in the loop above. */
469
bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
470
twiddle(1);
471
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
472
ISO_DEFAULT_BLOCK_SIZE, buf, &read);
473
if (rc)
474
goto out;
475
if (read != ISO_DEFAULT_BLOCK_SIZE) {
476
rc = EIO;
477
goto out;
478
}
479
dp = (struct iso_directory_record *)buf;
480
use_rrip = rrip_check(f, dp, &lenskip);
481
}
482
if (use_rrip) {
483
fp->f_flags |= F_RR;
484
fp->f_susp_skip = lenskip;
485
}
486
fp->f_off = 0;
487
fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
488
fp->f_size = isonum_733(rec.size);
489
free(buf);
490
491
return 0;
492
493
out:
494
free(fp);
495
free(buf);
496
497
return rc;
498
}
499
500
static int
501
cd9660_close(struct open_file *f)
502
{
503
struct file *fp = (struct file *)f->f_fsdata;
504
505
f->f_fsdata = NULL;
506
free(fp);
507
508
return 0;
509
}
510
511
static int
512
buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
513
{
514
struct file *fp = (struct file *)f->f_fsdata;
515
daddr_t blkno, blkoff;
516
int rc = 0;
517
size_t read;
518
519
blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno;
520
blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE;
521
522
if (blkno != fp->f_buf_blkno) {
523
if (fp->f_buf == (char *)0)
524
fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE);
525
526
twiddle(16);
527
rc = f->f_dev->dv_strategy(f->f_devdata, F_READ,
528
cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE,
529
fp->f_buf, &read);
530
if (rc)
531
return (rc);
532
if (read != ISO_DEFAULT_BLOCK_SIZE)
533
return (EIO);
534
535
fp->f_buf_blkno = blkno;
536
}
537
538
*buf_p = fp->f_buf + blkoff;
539
*size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff;
540
541
if (*size_p > fp->f_size - fp->f_off)
542
*size_p = fp->f_size - fp->f_off;
543
return (rc);
544
}
545
546
static int
547
cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid)
548
{
549
struct file *fp = (struct file *)f->f_fsdata;
550
char *buf, *addr;
551
size_t buf_size, csize;
552
int rc = 0;
553
554
addr = start;
555
while (size) {
556
if (fp->f_off < 0 || fp->f_off >= fp->f_size)
557
break;
558
559
rc = buf_read_file(f, &buf, &buf_size);
560
if (rc)
561
break;
562
563
csize = size > buf_size ? buf_size : size;
564
bcopy(buf, addr, csize);
565
566
fp->f_off += csize;
567
addr += csize;
568
size -= csize;
569
}
570
if (resid)
571
*resid = size;
572
return (rc);
573
}
574
575
static int
576
cd9660_readdir(struct open_file *f, struct dirent *d)
577
{
578
struct file *fp = (struct file *)f->f_fsdata;
579
struct iso_directory_record *ep;
580
size_t buf_size, reclen, namelen;
581
int error = 0;
582
int lenskip;
583
char *buf, *name;
584
585
again:
586
if (fp->f_off >= fp->f_size)
587
return (ENOENT);
588
error = buf_read_file(f, &buf, &buf_size);
589
if (error)
590
return (error);
591
ep = (struct iso_directory_record *)buf;
592
593
if (isonum_711(ep->length) == 0) {
594
daddr_t blkno;
595
596
/* skip to next block, if any */
597
blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE;
598
fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE;
599
goto again;
600
}
601
602
if (fp->f_flags & F_RR) {
603
if (fp->f_flags & F_ROOTDIR && fp->f_off == 0)
604
lenskip = 0;
605
else
606
lenskip = fp->f_susp_skip;
607
name = rrip_lookup_name(f, ep, lenskip, &namelen);
608
} else
609
name = NULL;
610
if (name == NULL) {
611
namelen = isonum_711(ep->name_len);
612
name = ep->name;
613
if (namelen == 1) {
614
if (ep->name[0] == 0)
615
name = ".";
616
else if (ep->name[0] == 1) {
617
namelen = 2;
618
name = "..";
619
}
620
}
621
}
622
reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1;
623
reclen = (reclen + 3) & ~3;
624
625
d->d_fileno = isonum_733(ep->extent);
626
d->d_reclen = reclen;
627
if (isonum_711(ep->flags) & 2)
628
d->d_type = DT_DIR;
629
else
630
d->d_type = DT_REG;
631
d->d_namlen = namelen;
632
633
bcopy(name, d->d_name, d->d_namlen);
634
d->d_name[d->d_namlen] = 0;
635
636
fp->f_off += isonum_711(ep->length);
637
return (0);
638
}
639
640
static off_t
641
cd9660_seek(struct open_file *f, off_t offset, int where)
642
{
643
struct file *fp = (struct file *)f->f_fsdata;
644
645
switch (where) {
646
case SEEK_SET:
647
fp->f_off = offset;
648
break;
649
case SEEK_CUR:
650
fp->f_off += offset;
651
break;
652
case SEEK_END:
653
fp->f_off = fp->f_size - offset;
654
break;
655
default:
656
return -1;
657
}
658
return fp->f_off;
659
}
660
661
static int
662
cd9660_stat(struct open_file *f, struct stat *sb)
663
{
664
struct file *fp = (struct file *)f->f_fsdata;
665
666
/* only important stuff */
667
sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
668
if (fp->f_flags & F_ISDIR)
669
sb->st_mode |= S_IFDIR;
670
else
671
sb->st_mode |= S_IFREG;
672
sb->st_uid = sb->st_gid = 0;
673
sb->st_size = fp->f_size;
674
return 0;
675
}
676
677
static int
678
cd9660_mount(const char *dev, const char *path, void **data)
679
{
680
cd9660_mnt_t *mnt;
681
struct open_file *f;
682
char *fs;
683
684
errno = 0;
685
mnt = calloc(1, sizeof(*mnt));
686
if (mnt == NULL)
687
return (errno);
688
mnt->cd_fd = -1;
689
690
if (asprintf(&fs, "%s%s", dev, path) < 0)
691
goto done;
692
693
mnt->cd_fd = open(fs, O_RDONLY);
694
free(fs);
695
if (mnt->cd_fd == -1)
696
goto done;
697
698
f = fd2open_file(mnt->cd_fd);
699
/* Is it cd9660 file system? */
700
if (strcmp(f->f_ops->fs_name, "cd9660") == 0) {
701
mnt->cd_dev = f->f_devdata;
702
errno = cd9660_read_dr(f, &mnt->cd_rec);
703
STAILQ_INSERT_TAIL(&mnt_list, mnt, cd_link);
704
} else {
705
errno = ENXIO;
706
}
707
708
done:
709
if (errno != 0) {
710
free(mnt->cd_dev);
711
if (mnt->cd_fd >= 0)
712
close(mnt->cd_fd);
713
free(mnt);
714
} else {
715
*data = mnt;
716
}
717
return (errno);
718
}
719
720
static int
721
cd9660_unmount(const char *dev __unused, void *data)
722
{
723
cd9660_mnt_t *mnt = data;
724
725
STAILQ_REMOVE(&mnt_list, mnt, cd9660_mnt, cd_link);
726
close(mnt->cd_fd);
727
free(mnt);
728
return (0);
729
}
730
731