Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/cd9660/cd9660_vfsops.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
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 ([email protected]). The Rock Ridge Extension
9
* Support code is derived from software contributed to Berkeley
10
* by Atsushi Murai ([email protected]).
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
37
#include <sys/param.h>
38
#include <sys/systm.h>
39
#include <sys/namei.h>
40
#include <sys/priv.h>
41
#include <sys/proc.h>
42
#include <sys/kernel.h>
43
#include <sys/vnode.h>
44
#include <sys/mount.h>
45
#include <sys/bio.h>
46
#include <sys/buf.h>
47
#include <sys/cdio.h>
48
#include <sys/conf.h>
49
#include <sys/fcntl.h>
50
#include <sys/malloc.h>
51
#include <sys/stat.h>
52
#include <sys/syslog.h>
53
#include <sys/iconv.h>
54
55
#include <fs/cd9660/iso.h>
56
#include <fs/cd9660/iso_rrip.h>
57
#include <fs/cd9660/cd9660_node.h>
58
#include <fs/cd9660/cd9660_mount.h>
59
60
#include <geom/geom.h>
61
#include <geom/geom_vfs.h>
62
63
MALLOC_DEFINE(M_ISOFSMNT, "isofs_mount", "ISOFS mount structure");
64
MALLOC_DEFINE(M_ISOFSNODE, "isofs_node", "ISOFS vnode private part");
65
66
struct iconv_functions *cd9660_iconv = NULL;
67
68
static vfs_mount_t cd9660_mount;
69
static vfs_cmount_t cd9660_cmount;
70
static vfs_unmount_t cd9660_unmount;
71
static vfs_root_t cd9660_root;
72
static vfs_statfs_t cd9660_statfs;
73
static vfs_vget_t cd9660_vget;
74
static vfs_fhtovp_t cd9660_fhtovp;
75
76
static struct vfsops cd9660_vfsops = {
77
.vfs_fhtovp = cd9660_fhtovp,
78
.vfs_mount = cd9660_mount,
79
.vfs_cmount = cd9660_cmount,
80
.vfs_root = cd9660_root,
81
.vfs_statfs = cd9660_statfs,
82
.vfs_unmount = cd9660_unmount,
83
.vfs_vget = cd9660_vget,
84
};
85
VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY);
86
MODULE_VERSION(cd9660, 1);
87
88
static int cd9660_vfs_hash_cmp(struct vnode *vp, void *pino);
89
static int iso_mountfs(struct vnode *devvp, struct mount *mp);
90
91
/*
92
* VFS Operations.
93
*/
94
95
static int
96
cd9660_cmount(struct mntarg *ma, void *data, uint64_t flags)
97
{
98
struct iso_args args;
99
int error;
100
101
error = copyin(data, &args, sizeof args);
102
if (error)
103
return (error);
104
105
ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
106
ma = mount_arg(ma, "export", &args.export, sizeof(args.export));
107
if (args.flags & ISOFSMNT_UID)
108
ma = mount_argf(ma, "uid", "%d", args.uid);
109
if (args.flags & ISOFSMNT_GID)
110
ma = mount_argf(ma, "gid", "%d", args.gid);
111
ma = mount_argf(ma, "mask", "%d", args.fmask);
112
ma = mount_argf(ma, "dirmask", "%d", args.dmask);
113
ma = mount_argsu(ma, "cs_disk", args.cs_disk, 64);
114
ma = mount_argsu(ma, "cs_local", args.cs_local, 64);
115
ma = mount_argf(ma, "ssector", "%u", args.ssector);
116
ma = mount_argb(ma, !(args.flags & ISOFSMNT_NORRIP), "norrip");
117
ma = mount_argb(ma, args.flags & ISOFSMNT_GENS, "nogens");
118
ma = mount_argb(ma, args.flags & ISOFSMNT_EXTATT, "noextatt");
119
ma = mount_argb(ma, !(args.flags & ISOFSMNT_NOJOLIET), "nojoliet");
120
ma = mount_argb(ma,
121
args.flags & ISOFSMNT_BROKENJOLIET, "nobrokenjoliet");
122
ma = mount_argb(ma, args.flags & ISOFSMNT_KICONV, "nokiconv");
123
124
error = kernel_mount(ma, flags);
125
126
return (error);
127
}
128
129
static int
130
cd9660_mount(struct mount *mp)
131
{
132
struct vnode *devvp;
133
struct thread *td;
134
char *fspec;
135
int error;
136
accmode_t accmode;
137
struct nameidata ndp;
138
struct iso_mnt *imp = NULL;
139
140
td = curthread;
141
142
/*
143
* Unconditionally mount as read-only.
144
*/
145
MNT_ILOCK(mp);
146
mp->mnt_flag |= MNT_RDONLY;
147
MNT_IUNLOCK(mp);
148
149
fspec = vfs_getopts(mp->mnt_optnew, "from", &error);
150
if (error)
151
return (error);
152
153
imp = VFSTOISOFS(mp);
154
155
if (mp->mnt_flag & MNT_UPDATE) {
156
if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0))
157
return (0);
158
}
159
/*
160
* Not an update, or updating the name: look up the name
161
* and verify that it refers to a sensible block device.
162
*/
163
NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec);
164
if ((error = namei(&ndp)))
165
return (error);
166
NDFREE_PNBUF(&ndp);
167
devvp = ndp.ni_vp;
168
169
if (!vn_isdisk_error(devvp, &error)) {
170
vput(devvp);
171
return (error);
172
}
173
174
/*
175
* Verify that user has necessary permissions on the device,
176
* or has superuser abilities
177
*/
178
accmode = VREAD;
179
error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
180
if (error)
181
error = priv_check(td, PRIV_VFS_MOUNT_PERM);
182
if (error) {
183
vput(devvp);
184
return (error);
185
}
186
187
if ((mp->mnt_flag & MNT_UPDATE) == 0) {
188
error = iso_mountfs(devvp, mp);
189
if (error)
190
vrele(devvp);
191
} else {
192
if (devvp != imp->im_devvp)
193
error = EINVAL; /* needs translation */
194
vput(devvp);
195
}
196
if (error)
197
return (error);
198
vfs_mountedfrom(mp, fspec);
199
return (0);
200
}
201
202
/*
203
* Common code for mount and mountroot
204
*/
205
static int
206
iso_mountfs(struct vnode *devvp, struct mount *mp)
207
{
208
struct iso_mnt *isomp = NULL;
209
struct buf *bp = NULL;
210
struct buf *pribp = NULL, *supbp = NULL;
211
struct cdev *dev;
212
int error = EINVAL;
213
int high_sierra = 0;
214
int iso_bsize;
215
int iso_blknum;
216
int joliet_level;
217
int isverified = 0;
218
struct iso_volume_descriptor *vdp = NULL;
219
struct iso_primary_descriptor *pri = NULL;
220
struct iso_sierra_primary_descriptor *pri_sierra = NULL;
221
struct iso_supplementary_descriptor *sup = NULL;
222
struct iso_directory_record *rootp;
223
int logical_block_size, ssector;
224
struct g_consumer *cp;
225
struct bufobj *bo;
226
char *cs_local, *cs_disk;
227
int v;
228
229
dev = devvp->v_rdev;
230
dev_ref(dev);
231
g_topology_lock();
232
error = g_vfs_open(devvp, &cp, "cd9660", 0);
233
if (error == 0)
234
g_getattr("MNT::verified", cp, &isverified);
235
g_topology_unlock();
236
VOP_UNLOCK(devvp);
237
if (error)
238
goto out;
239
if (devvp->v_rdev->si_iosize_max != 0)
240
mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
241
if (mp->mnt_iosize_max > maxphys)
242
mp->mnt_iosize_max = maxphys;
243
244
bo = &devvp->v_bufobj;
245
246
/* This is the "logical sector size". The standard says this
247
* should be 2048 or the physical sector size on the device,
248
* whichever is greater.
249
*/
250
if ((ISO_DEFAULT_BLOCK_SIZE % cp->provider->sectorsize) != 0) {
251
error = EINVAL;
252
goto out;
253
}
254
255
iso_bsize = cp->provider->sectorsize;
256
257
joliet_level = 0;
258
if (1 != vfs_scanopt(mp->mnt_optnew, "ssector", "%d", &ssector))
259
ssector = 0;
260
for (iso_blknum = 16 + ssector;
261
iso_blknum < 100 + ssector;
262
iso_blknum++) {
263
if ((error = bread(devvp, iso_blknum * btodb(ISO_DEFAULT_BLOCK_SIZE),
264
iso_bsize, NOCRED, &bp)) != 0)
265
goto out;
266
267
vdp = (struct iso_volume_descriptor *)bp->b_data;
268
if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
269
if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
270
sizeof vdp->id_sierra) != 0) {
271
error = EINVAL;
272
goto out;
273
} else
274
high_sierra = 1;
275
}
276
switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){
277
case ISO_VD_PRIMARY:
278
if (pribp == NULL) {
279
pribp = bp;
280
bp = NULL;
281
pri = (struct iso_primary_descriptor *)vdp;
282
pri_sierra =
283
(struct iso_sierra_primary_descriptor *)vdp;
284
}
285
break;
286
287
case ISO_VD_SUPPLEMENTARY:
288
if (supbp == NULL) {
289
supbp = bp;
290
bp = NULL;
291
sup = (struct iso_supplementary_descriptor *)vdp;
292
293
if (!vfs_flagopt(mp->mnt_optnew, "nojoliet", NULL, 0)) {
294
if (bcmp(sup->escape, "%/@", 3) == 0)
295
joliet_level = 1;
296
if (bcmp(sup->escape, "%/C", 3) == 0)
297
joliet_level = 2;
298
if (bcmp(sup->escape, "%/E", 3) == 0)
299
joliet_level = 3;
300
301
if ((isonum_711 (sup->flags) & 1) &&
302
!vfs_flagopt(mp->mnt_optnew, "brokenjoliet", NULL, 0))
303
joliet_level = 0;
304
}
305
}
306
break;
307
308
case ISO_VD_END:
309
goto vd_end;
310
311
default:
312
break;
313
}
314
if (bp != NULL) {
315
brelse(bp);
316
bp = NULL;
317
}
318
}
319
vd_end:
320
if (bp != NULL) {
321
brelse(bp);
322
bp = NULL;
323
}
324
325
if (pri == NULL) {
326
error = EINVAL;
327
goto out;
328
}
329
330
logical_block_size =
331
isonum_723 (high_sierra?
332
pri_sierra->logical_block_size:
333
pri->logical_block_size);
334
335
if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
336
|| (logical_block_size & (logical_block_size - 1)) != 0) {
337
error = EINVAL;
338
goto out;
339
}
340
341
if (logical_block_size < cp->provider->sectorsize) {
342
printf("cd9660: Unsupported logical block size %u\n",
343
logical_block_size);
344
error = EINVAL;
345
goto out;
346
}
347
348
rootp = (struct iso_directory_record *)
349
(high_sierra?
350
pri_sierra->root_directory_record:
351
pri->root_directory_record);
352
353
isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO);
354
isomp->im_cp = cp;
355
isomp->im_bo = bo;
356
isomp->logical_block_size = logical_block_size;
357
isomp->volume_space_size =
358
isonum_733 (high_sierra?
359
pri_sierra->volume_space_size:
360
pri->volume_space_size);
361
isomp->joliet_level = 0;
362
/*
363
* Since an ISO9660 multi-session CD can also access previous
364
* sessions, we have to include them into the space consider-
365
* ations. This doesn't yield a very accurate number since
366
* parts of the old sessions might be inaccessible now, but we
367
* can't do much better. This is also important for the NFS
368
* filehandle validation.
369
*/
370
isomp->volume_space_size += ssector;
371
memcpy(isomp->root, rootp, sizeof isomp->root);
372
isomp->root_extent = isonum_733 (rootp->extent);
373
isomp->root_size = isonum_733 (rootp->size);
374
375
isomp->im_bmask = logical_block_size - 1;
376
isomp->im_bshift = ffs(logical_block_size) - 1;
377
378
pribp->b_flags |= B_AGE;
379
brelse(pribp);
380
pribp = NULL;
381
rootp = NULL;
382
pri = NULL;
383
pri_sierra = NULL;
384
385
mp->mnt_data = isomp;
386
mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
387
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
388
MNT_ILOCK(mp);
389
if (isverified)
390
mp->mnt_flag |= MNT_VERIFIED;
391
mp->mnt_flag |= MNT_LOCAL;
392
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
393
MNT_IUNLOCK(mp);
394
isomp->im_mountp = mp;
395
isomp->im_dev = dev;
396
isomp->im_devvp = devvp;
397
isomp->im_fmask = isomp->im_dmask = ALLPERMS;
398
399
vfs_flagopt(mp->mnt_optnew, "norrip", &isomp->im_flags, ISOFSMNT_NORRIP);
400
vfs_flagopt(mp->mnt_optnew, "gens", &isomp->im_flags, ISOFSMNT_GENS);
401
vfs_flagopt(mp->mnt_optnew, "extatt", &isomp->im_flags, ISOFSMNT_EXTATT);
402
vfs_flagopt(mp->mnt_optnew, "nojoliet", &isomp->im_flags, ISOFSMNT_NOJOLIET);
403
vfs_flagopt(mp->mnt_optnew, "kiconv", &isomp->im_flags, ISOFSMNT_KICONV);
404
405
if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) {
406
isomp->im_flags |= ISOFSMNT_UID;
407
isomp->im_uid = v;
408
}
409
if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) {
410
isomp->im_flags |= ISOFSMNT_GID;
411
isomp->im_gid = v;
412
}
413
if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1) {
414
isomp->im_fmask &= v;
415
}
416
if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1) {
417
isomp->im_dmask &= v;
418
}
419
420
/* Check the Rock Ridge Extension support */
421
if (!(isomp->im_flags & ISOFSMNT_NORRIP)) {
422
if ((error = bread(isomp->im_devvp, (isomp->root_extent +
423
isonum_711(((struct iso_directory_record *)isomp->root)->
424
ext_attr_length)) << (isomp->im_bshift - DEV_BSHIFT),
425
isomp->logical_block_size, NOCRED, &bp)) != 0)
426
goto out;
427
428
rootp = (struct iso_directory_record *)bp->b_data;
429
430
if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
431
isomp->im_flags |= ISOFSMNT_NORRIP;
432
} else {
433
isomp->im_flags &= ~ISOFSMNT_GENS;
434
}
435
436
/*
437
* The contents are valid,
438
* but they will get reread as part of another vnode, so...
439
*/
440
bp->b_flags |= B_AGE;
441
brelse(bp);
442
bp = NULL;
443
rootp = NULL;
444
}
445
446
if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
447
cs_local = vfs_getopts(mp->mnt_optnew, "cs_local", &error);
448
if (error)
449
goto out;
450
cs_disk = vfs_getopts(mp->mnt_optnew, "cs_disk", &error);
451
if (error)
452
goto out;
453
cd9660_iconv->open(cs_local, cs_disk, &isomp->im_d2l);
454
cd9660_iconv->open(cs_disk, cs_local, &isomp->im_l2d);
455
} else {
456
isomp->im_d2l = NULL;
457
isomp->im_l2d = NULL;
458
}
459
460
if (high_sierra) {
461
/* this effectively ignores all the mount flags */
462
if (bootverbose)
463
log(LOG_INFO, "cd9660: High Sierra Format\n");
464
isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA;
465
} else
466
switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
467
default:
468
isomp->iso_ftype = ISO_FTYPE_DEFAULT;
469
break;
470
case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
471
isomp->iso_ftype = ISO_FTYPE_9660;
472
break;
473
case 0:
474
if (bootverbose)
475
log(LOG_INFO, "cd9660: RockRidge Extension\n");
476
isomp->iso_ftype = ISO_FTYPE_RRIP;
477
break;
478
}
479
480
/* Decide whether to use the Joliet descriptor */
481
482
if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) {
483
if (bootverbose)
484
log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n",
485
joliet_level);
486
rootp = (struct iso_directory_record *)
487
sup->root_directory_record;
488
memcpy(isomp->root, rootp, sizeof isomp->root);
489
isomp->root_extent = isonum_733 (rootp->extent);
490
isomp->root_size = isonum_733 (rootp->size);
491
isomp->joliet_level = joliet_level;
492
supbp->b_flags |= B_AGE;
493
}
494
495
if (supbp) {
496
brelse(supbp);
497
supbp = NULL;
498
sup = NULL;
499
}
500
501
return 0;
502
out:
503
if (bp != NULL)
504
brelse(bp);
505
if (pribp != NULL)
506
brelse(pribp);
507
if (supbp != NULL)
508
brelse(supbp);
509
if (cp != NULL) {
510
g_topology_lock();
511
g_vfs_close(cp);
512
g_topology_unlock();
513
}
514
if (isomp) {
515
free(isomp, M_ISOFSMNT);
516
mp->mnt_data = NULL;
517
}
518
dev_rel(dev);
519
return error;
520
}
521
522
/*
523
* unmount system call
524
*/
525
static int
526
cd9660_unmount(struct mount *mp, int mntflags)
527
{
528
struct iso_mnt *isomp;
529
int error, flags = 0;
530
531
if (mntflags & MNT_FORCE)
532
flags |= FORCECLOSE;
533
if ((error = vflush(mp, 0, flags, curthread)))
534
return (error);
535
536
isomp = VFSTOISOFS(mp);
537
538
if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
539
if (isomp->im_d2l)
540
cd9660_iconv->close(isomp->im_d2l);
541
if (isomp->im_l2d)
542
cd9660_iconv->close(isomp->im_l2d);
543
}
544
g_topology_lock();
545
g_vfs_close(isomp->im_cp);
546
g_topology_unlock();
547
vrele(isomp->im_devvp);
548
dev_rel(isomp->im_dev);
549
free(isomp, M_ISOFSMNT);
550
mp->mnt_data = NULL;
551
return (error);
552
}
553
554
/*
555
* Return root of a filesystem
556
*/
557
static int
558
cd9660_root(struct mount *mp, int flags, struct vnode **vpp)
559
{
560
struct iso_mnt *imp = VFSTOISOFS(mp);
561
struct iso_directory_record *dp =
562
(struct iso_directory_record *)imp->root;
563
ino_t ino = isodirino(dp, imp);
564
565
/*
566
* With RRIP we must use the `.' entry of the root directory.
567
* Simply tell vget, that it's a relocated directory.
568
*/
569
return (cd9660_vget_internal(mp, ino, flags, vpp,
570
imp->iso_ftype == ISO_FTYPE_RRIP, dp));
571
}
572
573
/*
574
* Get filesystem statistics.
575
*/
576
static int
577
cd9660_statfs(struct mount *mp, struct statfs *sbp)
578
{
579
struct iso_mnt *isomp;
580
581
isomp = VFSTOISOFS(mp);
582
583
sbp->f_bsize = isomp->logical_block_size;
584
sbp->f_iosize = sbp->f_bsize; /* XXX */
585
sbp->f_blocks = isomp->volume_space_size;
586
sbp->f_bfree = 0; /* total free blocks */
587
sbp->f_bavail = 0; /* blocks free for non superuser */
588
sbp->f_files = 0; /* total files */
589
sbp->f_ffree = 0; /* free file nodes */
590
return 0;
591
}
592
593
/*
594
* File handle to vnode
595
*
596
* Have to be really careful about stale file handles:
597
* - check that the inode number is in range
598
* - call iget() to get the locked inode
599
* - check for an unallocated inode (i_mode == 0)
600
* - check that the generation number matches
601
*/
602
603
/* ARGSUSED */
604
static int
605
cd9660_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
606
{
607
struct ifid ifh;
608
struct iso_node *ip;
609
struct vnode *nvp;
610
int error;
611
612
memcpy(&ifh, fhp, sizeof(ifh));
613
614
#ifdef ISOFS_DBG
615
printf("fhtovp: ino %d, start %ld\n",
616
ifh.ifid_ino, ifh.ifid_start);
617
#endif
618
619
if ((error = VFS_VGET(mp, ifh.ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
620
*vpp = NULL;
621
return (error);
622
}
623
ip = VTOI(nvp);
624
if (ip->inode.iso_mode == 0) {
625
vput(nvp);
626
*vpp = NULL;
627
return (ESTALE);
628
}
629
*vpp = nvp;
630
vnode_create_vobject(*vpp, ip->i_size, curthread);
631
return (0);
632
}
633
634
/*
635
* Conform to standard VFS interface; can't vget arbitrary inodes beyond 4GB
636
* into media with current inode scheme and 32-bit ino_t. This shouldn't be
637
* needed for anything other than nfsd, and who exports a mounted DVD over NFS?
638
*/
639
static int
640
cd9660_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
641
{
642
643
/*
644
* XXXX
645
* It would be nice if we didn't always set the `relocated' flag
646
* and force the extra read, but I don't want to think about fixing
647
* that right now.
648
*/
649
return (cd9660_vget_internal(mp, ino, flags, vpp,
650
#if 0
651
VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
652
#else
653
0,
654
#endif
655
(struct iso_directory_record *)0));
656
}
657
658
/* Use special comparator for full 64-bit ino comparison. */
659
static int
660
cd9660_vfs_hash_cmp(struct vnode *vp, void *pino)
661
{
662
struct iso_node *ip;
663
ino_t ino;
664
665
ip = VTOI(vp);
666
ino = *(ino_t *)pino;
667
return (ip->i_number != ino);
668
}
669
670
int
671
cd9660_vget_internal(struct mount *mp, ino_t ino, int flags,
672
struct vnode **vpp, int relocated, struct iso_directory_record *isodir)
673
{
674
struct iso_mnt *imp;
675
struct iso_node *ip;
676
struct buf *bp;
677
struct vnode *vp;
678
int error;
679
struct thread *td;
680
681
td = curthread;
682
error = vfs_hash_get(mp, ino, flags, td, vpp, cd9660_vfs_hash_cmp,
683
&ino);
684
if (error || *vpp != NULL)
685
return (error);
686
687
/*
688
* We must promote to an exclusive lock for vnode creation. This
689
* can happen if lookup is passed LOCKSHARED.
690
*/
691
if ((flags & LK_TYPE_MASK) == LK_SHARED) {
692
flags &= ~LK_TYPE_MASK;
693
flags |= LK_EXCLUSIVE;
694
}
695
696
/*
697
* We do not lock vnode creation as it is believed to be too
698
* expensive for such rare case as simultaneous creation of vnode
699
* for same ino by different processes. We just allow them to race
700
* and check later to decide who wins. Let the race begin!
701
*/
702
703
imp = VFSTOISOFS(mp);
704
705
/* Allocate a new vnode/iso_node. */
706
if ((error = getnewvnode("isofs", mp, &cd9660_vnodeops, &vp)) != 0) {
707
*vpp = NULL;
708
return (error);
709
}
710
ip = malloc(sizeof(struct iso_node), M_ISOFSNODE,
711
M_WAITOK | M_ZERO);
712
vp->v_data = ip;
713
ip->i_vnode = vp;
714
ip->i_number = ino;
715
716
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
717
error = insmntque(vp, mp);
718
if (error != 0) {
719
free(ip, M_ISOFSNODE);
720
*vpp = NULL;
721
return (error);
722
}
723
error = vfs_hash_insert(vp, ino, flags, td, vpp, cd9660_vfs_hash_cmp,
724
&ino);
725
if (error || *vpp != NULL)
726
return (error);
727
728
if (isodir == NULL) {
729
int lbn, off;
730
731
lbn = lblkno(imp, ino);
732
if (lbn >= imp->volume_space_size) {
733
vput(vp);
734
printf("fhtovp: lbn exceed volume space %d\n", lbn);
735
return (ESTALE);
736
}
737
738
off = blkoff(imp, ino);
739
if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
740
vput(vp);
741
printf("fhtovp: crosses block boundary %d\n",
742
off + ISO_DIRECTORY_RECORD_SIZE);
743
return (ESTALE);
744
}
745
746
error = bread(imp->im_devvp,
747
lbn << (imp->im_bshift - DEV_BSHIFT),
748
imp->logical_block_size, NOCRED, &bp);
749
if (error) {
750
vput(vp);
751
printf("fhtovp: bread error %d\n",error);
752
return (error);
753
}
754
isodir = (struct iso_directory_record *)(bp->b_data + off);
755
756
if (off + isonum_711(isodir->length) >
757
imp->logical_block_size) {
758
vput(vp);
759
brelse(bp);
760
printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
761
off +isonum_711(isodir->length), off,
762
isonum_711(isodir->length));
763
return (ESTALE);
764
}
765
766
#if 0
767
if (isonum_733(isodir->extent) +
768
isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
769
brelse(bp);
770
printf("fhtovp: file start miss %d vs %d\n",
771
isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
772
ifhp->ifid_start);
773
return (ESTALE);
774
}
775
#endif
776
} else
777
bp = NULL;
778
779
ip->i_mnt = imp;
780
781
if (relocated) {
782
/*
783
* On relocated directories we must
784
* read the `.' entry out of a dir.
785
*/
786
ip->iso_start = ino >> imp->im_bshift;
787
if (bp != NULL)
788
brelse(bp);
789
if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) {
790
vput(vp);
791
return (error);
792
}
793
isodir = (struct iso_directory_record *)bp->b_data;
794
}
795
796
ip->iso_extent = isonum_733(isodir->extent);
797
ip->i_size = isonum_733(isodir->size);
798
ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
799
800
/*
801
* Setup time stamp, attribute
802
*/
803
vp->v_type = VNON;
804
switch (imp->iso_ftype) {
805
default: /* ISO_FTYPE_9660 */
806
{
807
struct buf *bp2;
808
int off;
809
if ((imp->im_flags & ISOFSMNT_EXTATT)
810
&& (off = isonum_711(isodir->ext_attr_length)))
811
cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL,
812
&bp2);
813
else
814
bp2 = NULL;
815
cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660);
816
cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660);
817
if (bp2)
818
brelse(bp2);
819
break;
820
}
821
case ISO_FTYPE_RRIP:
822
cd9660_rrip_analyze(isodir, ip, imp);
823
break;
824
}
825
826
brelse(bp);
827
828
/*
829
* Initialize the associated vnode
830
*/
831
switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
832
case VFIFO:
833
vp->v_op = &cd9660_fifoops;
834
break;
835
default:
836
VN_LOCK_ASHARE(vp);
837
break;
838
}
839
840
if (ip->iso_extent == imp->root_extent)
841
vp->v_vflag |= VV_ROOT;
842
843
/*
844
* XXX need generation number?
845
*/
846
847
vn_set_state(vp, VSTATE_CONSTRUCTED);
848
*vpp = vp;
849
return (0);
850
}
851
852