Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1994 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley | |
6 | * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension | |
7 | * Support code is derived from software contributed to Berkeley | |
8 | * by Atsushi Murai (amurai@spec.co.jp). | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
2c64e990 | 18 | * 3. Neither the name of the University nor the names of its contributors |
984263bc MD |
19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | * | |
34 | * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 | |
35 | * $FreeBSD: src/sys/isofs/cd9660/cd9660_vfsops.c,v 1.74.2.7 2002/04/08 09:39:29 bde Exp $ | |
36 | */ | |
37 | ||
38 | #include <sys/param.h> | |
39 | #include <sys/systm.h> | |
984263bc | 40 | #include <sys/proc.h> |
2b3f93ea | 41 | #include <sys/caps.h> |
fad57d0e | 42 | #include <sys/nlookup.h> |
984263bc MD |
43 | #include <sys/kernel.h> |
44 | #include <sys/vnode.h> | |
45 | #include <sys/mount.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> | |
60c47c5e | 53 | #include <sys/iconv.h> |
984263bc MD |
54 | |
55 | #include <vm/vm_zone.h> | |
56 | ||
54341a3b MD |
57 | #include <sys/buf2.h> |
58 | ||
1f2de5d4 MD |
59 | #include "iso.h" |
60 | #include "iso_rrip.h" | |
61 | #include "cd9660_node.h" | |
62 | #include "cd9660_mount.h" | |
984263bc | 63 | |
66a1ddf5 MD |
64 | extern struct vop_ops cd9660_vnode_vops; |
65 | extern struct vop_ops cd9660_spec_vops; | |
66 | extern struct vop_ops cd9660_fifo_vops; | |
0961aa92 | 67 | |
984263bc MD |
68 | MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); |
69 | MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part"); | |
70 | ||
60c47c5e AP |
71 | struct iconv_functions *cd9660_iconv = NULL; |
72 | ||
e961ef71 | 73 | static int cd9660_mount(struct mount *, char *, caddr_t, struct ucred *); |
74 | static int cd9660_unmount(struct mount *, int); | |
75 | static int cd9660_root(struct mount *, struct vnode **); | |
76 | static int cd9660_statfs(struct mount *, struct statfs *, struct ucred *); | |
77 | static int cd9660_vget(struct mount *, struct vnode *, ino_t, struct vnode **); | |
78 | static int cd9660_fhtovp(struct mount *, struct vnode *rootvp, | |
79 | struct fid *, struct vnode **); | |
80 | static int cd9660_checkexp(struct mount *, struct sockaddr *, | |
81 | int *, struct ucred **); | |
a6ee311a | 82 | static int cd9660_vptofh (struct vnode *, struct fid *); |
984263bc MD |
83 | |
84 | static struct vfsops cd9660_vfsops = { | |
00369c4a | 85 | .vfs_flags = 0, |
e961ef71 | 86 | .vfs_mount = cd9660_mount, |
87 | .vfs_unmount = cd9660_unmount, | |
88 | .vfs_root = cd9660_root, | |
89 | .vfs_statfs = cd9660_statfs, | |
e961ef71 | 90 | .vfs_vget = cd9660_vget, |
91 | .vfs_fhtovp = cd9660_fhtovp, | |
92 | .vfs_checkexp = cd9660_checkexp, | |
93 | .vfs_vptofh = cd9660_vptofh, | |
94 | .vfs_init = cd9660_init, | |
95 | .vfs_uninit = cd9660_uninit, | |
984263bc MD |
96 | }; |
97 | VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); | |
98 | MODULE_VERSION(cd9660, 1); | |
99 | ||
100 | ||
101 | /* | |
102 | * Called by vfs_mountroot when iso is going to be mounted as root. | |
103 | */ | |
104 | ||
e961ef71 | 105 | static int iso_get_ssector(cdev_t dev); |
106 | static int iso_mountfs(struct vnode *devvp, struct mount *mp, | |
107 | struct iso_args *argp); | |
984263bc MD |
108 | |
109 | /* | |
110 | * Try to find the start of the last data track on this CD-ROM. This | |
111 | * is used to mount the last session of a multi-session CD. Bail out | |
112 | * and return 0 if we fail, this is always a safe bet. | |
113 | */ | |
114 | static int | |
b13267a5 | 115 | iso_get_ssector(cdev_t dev) |
984263bc MD |
116 | { |
117 | struct ioc_toc_header h; | |
118 | struct ioc_read_toc_single_entry t; | |
119 | int i; | |
984263bc | 120 | |
87baaf0c | 121 | if (dev_dioctl(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, |
8c530b23 | 122 | proc0.p_ucred, NULL, NULL) != 0) |
984263bc MD |
123 | return 0; |
124 | ||
125 | for (i = h.ending_track; i >= 0; i--) { | |
126 | t.address_format = CD_LBA_FORMAT; | |
127 | t.track = i; | |
87baaf0c | 128 | if (dev_dioctl(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, |
8c530b23 | 129 | proc0.p_ucred, NULL, NULL) != 0) { |
984263bc | 130 | return 0; |
335dda38 | 131 | } |
984263bc MD |
132 | if ((t.entry.control & 4) != 0) |
133 | /* found a data track */ | |
134 | break; | |
135 | } | |
136 | ||
137 | if (i < 0) | |
138 | return 0; | |
139 | ||
140 | return ntohl(t.entry.addr.lba); | |
141 | } | |
142 | ||
984263bc | 143 | static int |
acde96db | 144 | iso_mountroot(struct mount *mp) |
984263bc MD |
145 | { |
146 | struct iso_args args; | |
21739618 | 147 | struct vnode *rootvp; |
984263bc MD |
148 | int error; |
149 | ||
150 | if ((error = bdevvp(rootdev, &rootvp))) { | |
086c1d7e | 151 | kprintf("iso_mountroot: can't find rootvp\n"); |
984263bc MD |
152 | return (error); |
153 | } | |
154 | args.flags = ISOFSMNT_ROOT; | |
155 | ||
ca466bae | 156 | vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY); |
87de5057 | 157 | error = VOP_OPEN(rootvp, FREAD, FSCRED, NULL); |
a11aaa81 | 158 | vn_unlock(rootvp); |
984263bc MD |
159 | if (error) |
160 | return (error); | |
161 | ||
acde96db | 162 | args.ssector = iso_get_ssector(rootdev); |
984263bc | 163 | |
12cdc371 | 164 | vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY); |
3596743e | 165 | VOP_CLOSE(rootvp, FREAD, NULL); |
12cdc371 | 166 | vn_unlock(rootvp); |
984263bc MD |
167 | |
168 | if (bootverbose) | |
086c1d7e | 169 | kprintf("iso_mountroot(): using session at block %d\n", |
984263bc | 170 | args.ssector); |
acde96db | 171 | if ((error = iso_mountfs(rootvp, mp, &args)) != 0) |
984263bc MD |
172 | return (error); |
173 | ||
acde96db | 174 | cd9660_statfs(mp, &mp->mnt_stat, proc0.p_ucred); |
984263bc MD |
175 | return (0); |
176 | } | |
177 | ||
178 | /* | |
179 | * VFS Operations. | |
180 | * | |
181 | * mount system call | |
182 | */ | |
183 | static int | |
acde96db | 184 | cd9660_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) |
984263bc MD |
185 | { |
186 | struct vnode *devvp; | |
187 | struct iso_args args; | |
188 | size_t size; | |
189 | int error; | |
190 | mode_t accessmode; | |
4090d6ff | 191 | struct iso_mnt *imp = NULL; |
fad57d0e | 192 | struct nlookupdata nd; |
984263bc | 193 | |
83760fab | 194 | if ((mp->mnt_flag & (MNT_ROOTFS|MNT_UPDATE)) == MNT_ROOTFS) { |
acde96db | 195 | return (iso_mountroot(mp)); |
984263bc MD |
196 | } |
197 | if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args)))) | |
198 | return (error); | |
199 | ||
200 | if ((mp->mnt_flag & MNT_RDONLY) == 0) | |
201 | return (EROFS); | |
202 | ||
203 | /* | |
204 | * If updating, check whether changing from read-only to | |
205 | * read/write; if there is no device name, that's all we do. | |
206 | */ | |
207 | if (mp->mnt_flag & MNT_UPDATE) { | |
208 | imp = VFSTOISOFS(mp); | |
914b334c | 209 | if (args.fspec == NULL) |
984263bc MD |
210 | return (vfs_export(mp, &imp->im_export, &args.export)); |
211 | } | |
212 | /* | |
213 | * Not an update, or updating the name: look up the name | |
214 | * and verify that it refers to a sensible block device. | |
215 | */ | |
fad57d0e MD |
216 | devvp = NULL; |
217 | error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); | |
218 | if (error == 0) | |
219 | error = nlookup(&nd); | |
220 | if (error == 0) | |
28623bf9 | 221 | error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); |
fad57d0e MD |
222 | nlookup_done(&nd); |
223 | if (error) | |
984263bc | 224 | return (error); |
984263bc MD |
225 | |
226 | if (!vn_isdisk(devvp, &error)) { | |
227 | vrele(devvp); | |
228 | return (error); | |
229 | } | |
230 | ||
e961ef71 | 231 | /* |
984263bc MD |
232 | * Verify that user has necessary permissions on the device, |
233 | * or has superuser abilities | |
234 | */ | |
235 | accessmode = VREAD; | |
ca466bae | 236 | vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); |
cb66845a | 237 | error = VOP_EACCESS(devvp, accessmode, cred); |
e961ef71 | 238 | if (error) |
2b3f93ea | 239 | error = caps_priv_check(cred, SYSCAP_RESTRICTEDROOT); |
984263bc MD |
240 | if (error) { |
241 | vput(devvp); | |
242 | return (error); | |
243 | } | |
a11aaa81 | 244 | vn_unlock(devvp); |
984263bc MD |
245 | |
246 | if ((mp->mnt_flag & MNT_UPDATE) == 0) { | |
acde96db | 247 | error = iso_mountfs(devvp, mp, &args); |
984263bc MD |
248 | } else { |
249 | if (devvp != imp->im_devvp) | |
250 | error = EINVAL; /* needs translation */ | |
251 | else | |
252 | vrele(devvp); | |
253 | } | |
254 | if (error) { | |
255 | vrele(devvp); | |
256 | return error; | |
257 | } | |
258 | imp = VFSTOISOFS(mp); | |
b1ce5639 | 259 | copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, |
984263bc MD |
260 | &size); |
261 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
acde96db | 262 | cd9660_statfs(mp, &mp->mnt_stat, cred); |
984263bc MD |
263 | return 0; |
264 | } | |
265 | ||
266 | /* | |
267 | * Common code for mount and mountroot | |
268 | */ | |
269 | static int | |
acde96db | 270 | iso_mountfs(struct vnode *devvp, struct mount *mp, struct iso_args *argp) |
3fa8192b | 271 | { |
460af697 | 272 | struct iso_mnt *isomp = NULL; |
984263bc MD |
273 | struct buf *bp = NULL; |
274 | struct buf *pribp = NULL, *supbp = NULL; | |
b13267a5 | 275 | cdev_t dev; |
984263bc MD |
276 | int error = EINVAL; |
277 | int needclose = 0; | |
278 | int high_sierra = 0; | |
279 | int iso_bsize; | |
280 | int iso_blknum; | |
281 | int joliet_level; | |
4090d6ff | 282 | struct iso_volume_descriptor *vdp = NULL; |
984263bc MD |
283 | struct iso_primary_descriptor *pri = NULL; |
284 | struct iso_sierra_primary_descriptor *pri_sierra = NULL; | |
285 | struct iso_supplementary_descriptor *sup = NULL; | |
286 | struct iso_directory_record *rootp; | |
287 | int logical_block_size; | |
60c47c5e AP |
288 | char cs_local[ICONV_CSNMAXLEN]; |
289 | char cs_disk[ICONV_CSNMAXLEN]; | |
984263bc MD |
290 | |
291 | if (!(mp->mnt_flag & MNT_RDONLY)) | |
292 | return EROFS; | |
293 | ||
294 | /* | |
295 | * Disallow multiple mounts of the same device. | |
296 | * Disallow mounting of a device that is currently in use | |
984263bc MD |
297 | * Flush out any old buffers remaining from a previous use. |
298 | */ | |
299 | if ((error = vfs_mountedon(devvp))) | |
300 | return error; | |
8be7edad | 301 | if (vcount(devvp) > 0) |
984263bc | 302 | return EBUSY; |
87de5057 | 303 | if ((error = vinvalbuf(devvp, V_SAVE, 0, 0))) |
984263bc MD |
304 | return (error); |
305 | ||
ca466bae | 306 | vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); |
87de5057 | 307 | error = VOP_OPEN(devvp, FREAD, FSCRED, NULL); |
a11aaa81 | 308 | vn_unlock(devvp); |
984263bc MD |
309 | if (error) |
310 | return error; | |
e4c9c0c8 MD |
311 | dev = devvp->v_rdev; |
312 | if (dev->si_iosize_max != 0) | |
313 | mp->mnt_iosize_max = dev->si_iosize_max; | |
984263bc MD |
314 | if (mp->mnt_iosize_max > MAXPHYS) |
315 | mp->mnt_iosize_max = MAXPHYS; | |
316 | ||
317 | needclose = 1; | |
318 | ||
319 | /* This is the "logical sector size". The standard says this | |
320 | * should be 2048 or the physical sector size on the device, | |
321 | * whichever is greater. For now, we'll just use a constant. | |
322 | */ | |
323 | iso_bsize = ISO_DEFAULT_BLOCK_SIZE; | |
324 | ||
325 | joliet_level = 0; | |
326 | for (iso_blknum = 16 + argp->ssector; | |
327 | iso_blknum < 100 + argp->ssector; | |
328 | iso_blknum++) { | |
54078292 | 329 | if ((error = bread(devvp, (off_t)iso_blknum * iso_bsize, |
3b568787 | 330 | iso_bsize, &bp)) != 0) |
984263bc | 331 | goto out; |
e961ef71 | 332 | |
984263bc MD |
333 | vdp = (struct iso_volume_descriptor *)bp->b_data; |
334 | if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { | |
335 | if (bcmp (vdp->id_sierra, ISO_SIERRA_ID, | |
336 | sizeof vdp->id) != 0) { | |
337 | error = EINVAL; | |
338 | goto out; | |
339 | } else | |
340 | high_sierra = 1; | |
341 | } | |
342 | switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){ | |
343 | case ISO_VD_PRIMARY: | |
344 | if (pribp == NULL) { | |
345 | pribp = bp; | |
346 | bp = NULL; | |
347 | pri = (struct iso_primary_descriptor *)vdp; | |
348 | pri_sierra = | |
349 | (struct iso_sierra_primary_descriptor *)vdp; | |
350 | } | |
351 | break; | |
352 | ||
353 | case ISO_VD_SUPPLEMENTARY: | |
354 | if (supbp == NULL) { | |
355 | supbp = bp; | |
356 | bp = NULL; | |
357 | sup = (struct iso_supplementary_descriptor *)vdp; | |
358 | ||
359 | if (!(argp->flags & ISOFSMNT_NOJOLIET)) { | |
360 | if (bcmp(sup->escape, "%/@", 3) == 0) | |
361 | joliet_level = 1; | |
362 | if (bcmp(sup->escape, "%/C", 3) == 0) | |
363 | joliet_level = 2; | |
364 | if (bcmp(sup->escape, "%/E", 3) == 0) | |
365 | joliet_level = 3; | |
366 | ||
367 | if ((isonum_711 (sup->flags) & 1) && | |
368 | (argp->flags & ISOFSMNT_BROKENJOLIET) == 0) | |
369 | joliet_level = 0; | |
370 | } | |
371 | } | |
372 | break; | |
373 | ||
374 | case ISO_VD_END: | |
375 | goto vd_end; | |
376 | ||
377 | default: | |
378 | break; | |
379 | } | |
380 | if (bp) { | |
381 | brelse(bp); | |
382 | bp = NULL; | |
383 | } | |
384 | } | |
385 | vd_end: | |
386 | if (bp) { | |
387 | brelse(bp); | |
388 | bp = NULL; | |
389 | } | |
390 | ||
391 | if (pri == NULL) { | |
392 | error = EINVAL; | |
393 | goto out; | |
394 | } | |
395 | ||
396 | logical_block_size = | |
397 | isonum_723 (high_sierra? | |
398 | pri_sierra->logical_block_size: | |
399 | pri->logical_block_size); | |
400 | ||
401 | if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE | |
402 | || (logical_block_size & (logical_block_size - 1)) != 0) { | |
403 | error = EINVAL; | |
404 | goto out; | |
405 | } | |
406 | ||
407 | rootp = (struct iso_directory_record *) | |
408 | (high_sierra? | |
409 | pri_sierra->root_directory_record: | |
410 | pri->root_directory_record); | |
411 | ||
efda3bd0 | 412 | isomp = kmalloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO); |
984263bc MD |
413 | isomp->logical_block_size = logical_block_size; |
414 | isomp->volume_space_size = | |
415 | isonum_733 (high_sierra? | |
416 | pri_sierra->volume_space_size: | |
417 | pri->volume_space_size); | |
418 | isomp->joliet_level = 0; | |
419 | /* | |
420 | * Since an ISO9660 multi-session CD can also access previous | |
421 | * sessions, we have to include them into the space consider- | |
422 | * ations. This doesn't yield a very accurate number since | |
423 | * parts of the old sessions might be inaccessible now, but we | |
424 | * can't do much better. This is also important for the NFS | |
425 | * filehandle validation. | |
426 | */ | |
427 | isomp->volume_space_size += argp->ssector; | |
428 | bcopy (rootp, isomp->root, sizeof isomp->root); | |
429 | isomp->root_extent = isonum_733 (rootp->extent); | |
430 | isomp->root_size = isonum_733 (rootp->size); | |
431 | ||
432 | isomp->im_bmask = logical_block_size - 1; | |
433 | isomp->im_bshift = ffs(logical_block_size) - 1; | |
434 | ||
435 | pribp->b_flags |= B_AGE; | |
436 | brelse(pribp); | |
437 | pribp = NULL; | |
438 | ||
439 | mp->mnt_data = (qaddr_t)isomp; | |
2ac7d105 | 440 | mp->mnt_stat.f_fsid.val[0] = devid_from_dev(dev); |
984263bc MD |
441 | mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; |
442 | mp->mnt_maxsymlinklen = 0; | |
443 | mp->mnt_flag |= MNT_LOCAL; | |
444 | isomp->im_mountp = mp; | |
445 | isomp->im_dev = dev; | |
446 | isomp->im_devvp = devvp; | |
447 | ||
e4c9c0c8 | 448 | dev->si_mountpoint = mp; |
984263bc | 449 | |
7764eb66 RB |
450 | if (argp->flags & ISOFSMNT_UID) |
451 | isomp->im_uid = argp->uid; | |
452 | if (argp->flags & ISOFSMNT_GID) | |
453 | isomp->im_gid = argp->gid; | |
454 | isomp->im_fmask = argp->fmask & ACCESSPERMS; | |
455 | isomp->im_dmask = argp->dmask & ACCESSPERMS; | |
456 | ||
e961ef71 | 457 | /* Check the Rock Ridge Extension support */ |
984263bc MD |
458 | if (!(argp->flags & ISOFSMNT_NORRIP)) { |
459 | if ((error = bread(isomp->im_devvp, | |
54078292 | 460 | lblktooff(isomp, isomp->root_extent + isonum_711(rootp->ext_attr_length)), |
3b568787 | 461 | isomp->logical_block_size, &bp)) != 0) |
e961ef71 | 462 | goto out; |
463 | ||
984263bc | 464 | rootp = (struct iso_directory_record *)bp->b_data; |
e961ef71 | 465 | |
984263bc | 466 | if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { |
e961ef71 | 467 | argp->flags |= ISOFSMNT_NORRIP; |
984263bc | 468 | } else { |
e961ef71 | 469 | argp->flags &= ~ISOFSMNT_GENS; |
984263bc MD |
470 | } |
471 | ||
472 | /* | |
473 | * The contents are valid, | |
474 | * but they will get reread as part of another vnode, so... | |
475 | */ | |
476 | bp->b_flags |= B_AGE; | |
477 | brelse(bp); | |
478 | bp = NULL; | |
479 | } | |
480 | isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS | | |
60c47c5e | 481 | ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET | |
7764eb66 RB |
482 | ISOFSMNT_KICONV | |
483 | ISOFSMNT_UID | ISOFSMNT_GID); | |
e961ef71 | 484 | |
60c47c5e | 485 | if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) { |
e961ef71 | 486 | bcopy(argp->cs_local, cs_local, sizeof(cs_local)); |
487 | bcopy(argp->cs_disk, cs_disk, sizeof(cs_disk)); | |
488 | cd9660_iconv->open(cs_local, cs_disk, &isomp->im_d2l); | |
489 | cd9660_iconv->open(cs_disk, cs_local, &isomp->im_l2d); | |
490 | } else { | |
491 | isomp->im_d2l = NULL; | |
492 | isomp->im_l2d = NULL; | |
493 | } | |
984263bc MD |
494 | |
495 | if (high_sierra) { | |
496 | /* this effectively ignores all the mount flags */ | |
497 | log(LOG_INFO, "cd9660: High Sierra Format\n"); | |
498 | isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA; | |
0961aa92 | 499 | } else { |
984263bc MD |
500 | switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) { |
501 | default: | |
502 | isomp->iso_ftype = ISO_FTYPE_DEFAULT; | |
503 | break; | |
504 | case ISOFSMNT_GENS|ISOFSMNT_NORRIP: | |
505 | isomp->iso_ftype = ISO_FTYPE_9660; | |
506 | break; | |
507 | case 0: | |
508 | log(LOG_INFO, "cd9660: RockRidge Extension\n"); | |
509 | isomp->iso_ftype = ISO_FTYPE_RRIP; | |
510 | break; | |
511 | } | |
0961aa92 | 512 | } |
984263bc MD |
513 | |
514 | /* Decide whether to use the Joliet descriptor */ | |
515 | ||
516 | if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) { | |
517 | log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n", joliet_level); | |
518 | rootp = (struct iso_directory_record *) | |
519 | sup->root_directory_record; | |
520 | bcopy (rootp, isomp->root, sizeof isomp->root); | |
521 | isomp->root_extent = isonum_733 (rootp->extent); | |
522 | isomp->root_size = isonum_733 (rootp->size); | |
523 | isomp->joliet_level = joliet_level; | |
524 | supbp->b_flags |= B_AGE; | |
525 | } | |
526 | ||
527 | if (supbp) { | |
528 | brelse(supbp); | |
529 | supbp = NULL; | |
530 | } | |
531 | ||
66a1ddf5 MD |
532 | vfs_add_vnodeops(mp, &cd9660_vnode_vops, &mp->mnt_vn_norm_ops); |
533 | vfs_add_vnodeops(mp, &cd9660_spec_vops, &mp->mnt_vn_spec_ops); | |
534 | vfs_add_vnodeops(mp, &cd9660_fifo_vops, &mp->mnt_vn_fifo_ops); | |
0961aa92 | 535 | |
984263bc MD |
536 | return 0; |
537 | out: | |
e4c9c0c8 | 538 | dev->si_mountpoint = NULL; |
984263bc MD |
539 | if (bp) |
540 | brelse(bp); | |
541 | if (pribp) | |
542 | brelse(pribp); | |
543 | if (supbp) | |
544 | brelse(supbp); | |
12cdc371 MD |
545 | if (needclose) { |
546 | vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); | |
3596743e | 547 | VOP_CLOSE(devvp, FREAD, NULL); |
12cdc371 MD |
548 | vn_unlock(devvp); |
549 | } | |
984263bc | 550 | if (isomp) { |
efda3bd0 | 551 | kfree((caddr_t)isomp, M_ISOFSMNT); |
984263bc MD |
552 | mp->mnt_data = (qaddr_t)0; |
553 | } | |
554 | return error; | |
555 | } | |
556 | ||
557 | /* | |
558 | * unmount system call | |
559 | */ | |
560 | static int | |
acde96db | 561 | cd9660_unmount(struct mount *mp, int mntflags) |
984263bc | 562 | { |
3a1b0fdc | 563 | struct iso_mnt *isomp; |
984263bc MD |
564 | int error, flags = 0; |
565 | ||
566 | if (mntflags & MNT_FORCE) | |
567 | flags |= FORCECLOSE; | |
568 | #if 0 | |
569 | mntflushbuf(mp, 0); | |
570 | if (mntinvalbuf(mp)) | |
571 | return EBUSY; | |
572 | #endif | |
573 | if ((error = vflush(mp, 0, flags))) | |
574 | return (error); | |
575 | ||
576 | isomp = VFSTOISOFS(mp); | |
577 | ||
60c47c5e | 578 | if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) { |
e961ef71 | 579 | if (isomp->im_d2l) |
580 | cd9660_iconv->close(isomp->im_d2l); | |
581 | if (isomp->im_l2d) | |
582 | cd9660_iconv->close(isomp->im_l2d); | |
583 | } | |
60c47c5e | 584 | |
e4c9c0c8 | 585 | isomp->im_devvp->v_rdev->si_mountpoint = NULL; |
12cdc371 | 586 | vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY); |
3596743e | 587 | error = VOP_CLOSE(isomp->im_devvp, FREAD, NULL); |
12cdc371 | 588 | vn_unlock(isomp->im_devvp); |
984263bc | 589 | vrele(isomp->im_devvp); |
efda3bd0 | 590 | kfree((caddr_t)isomp, M_ISOFSMNT); |
984263bc MD |
591 | mp->mnt_data = (qaddr_t)0; |
592 | mp->mnt_flag &= ~MNT_LOCAL; | |
593 | return (error); | |
594 | } | |
595 | ||
596 | /* | |
597 | * Return root of a filesystem | |
598 | */ | |
599 | static int | |
3fa8192b | 600 | cd9660_root(struct mount *mp, struct vnode **vpp) |
984263bc MD |
601 | { |
602 | struct iso_mnt *imp = VFSTOISOFS(mp); | |
603 | struct iso_directory_record *dp = | |
604 | (struct iso_directory_record *)imp->root; | |
605 | ino_t ino = isodirino(dp, imp); | |
e961ef71 | 606 | |
984263bc MD |
607 | /* |
608 | * With RRIP we must use the `.' entry of the root directory. | |
609 | * Simply tell vget, that it's a relocated directory. | |
610 | */ | |
611 | return (cd9660_vget_internal(mp, ino, vpp, | |
612 | imp->iso_ftype == ISO_FTYPE_RRIP, dp)); | |
613 | } | |
614 | ||
615 | /* | |
e961ef71 | 616 | * Get filesystem statistics. |
984263bc MD |
617 | */ |
618 | int | |
acde96db | 619 | cd9660_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) |
984263bc | 620 | { |
dadab5e9 | 621 | struct iso_mnt *isomp; |
984263bc MD |
622 | |
623 | isomp = VFSTOISOFS(mp); | |
624 | ||
625 | sbp->f_bsize = isomp->logical_block_size; | |
626 | sbp->f_iosize = sbp->f_bsize; /* XXX */ | |
627 | sbp->f_blocks = isomp->volume_space_size; | |
628 | sbp->f_bfree = 0; /* total free blocks */ | |
629 | sbp->f_bavail = 0; /* blocks free for non superuser */ | |
630 | sbp->f_files = 0; /* total files */ | |
631 | sbp->f_ffree = 0; /* free file nodes */ | |
632 | if (sbp != &mp->mnt_stat) { | |
633 | sbp->f_type = mp->mnt_vfc->vfc_typenum; | |
984263bc MD |
634 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); |
635 | } | |
636 | return 0; | |
637 | } | |
638 | ||
639 | /* | |
640 | * File handle to vnode | |
641 | * | |
642 | * Have to be really careful about stale file handles: | |
643 | * - check that the inode number is in range | |
644 | * - call iget() to get the locked inode | |
645 | * - check for an unallocated inode (i_mode == 0) | |
646 | * - check that the generation number matches | |
647 | */ | |
648 | ||
649 | struct ifid { | |
650 | ushort ifid_len; | |
651 | ushort ifid_pad; | |
652 | int ifid_ino; | |
653 | long ifid_start; | |
654 | }; | |
655 | ||
656 | /* ARGSUSED */ | |
657 | int | |
67863d04 MD |
658 | cd9660_fhtovp(struct mount *mp, struct vnode *rootvp, |
659 | struct fid *fhp, struct vnode **vpp) | |
984263bc MD |
660 | { |
661 | struct ifid *ifhp = (struct ifid *)fhp; | |
3a1b0fdc | 662 | struct iso_node *ip; |
984263bc MD |
663 | struct vnode *nvp; |
664 | int error; | |
e961ef71 | 665 | |
984263bc | 666 | #ifdef ISOFS_DBG |
086c1d7e | 667 | kprintf("fhtovp: ino %d, start %ld\n", |
e961ef71 | 668 | ifhp->ifid_ino, ifhp->ifid_start); |
984263bc | 669 | #endif |
e961ef71 | 670 | |
b9b0a6d0 | 671 | if ((error = VFS_VGET(mp, NULL, ifhp->ifid_ino, &nvp)) != 0) { |
984263bc MD |
672 | *vpp = NULLVP; |
673 | return (error); | |
674 | } | |
675 | ip = VTOI(nvp); | |
676 | if (ip->inode.iso_mode == 0) { | |
677 | vput(nvp); | |
678 | *vpp = NULLVP; | |
679 | return (ESTALE); | |
680 | } | |
681 | *vpp = nvp; | |
682 | return (0); | |
683 | } | |
684 | ||
685 | int | |
3fa8192b CP |
686 | cd9660_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp, |
687 | struct ucred **credanonp) | |
984263bc | 688 | { |
3a1b0fdc RG |
689 | struct netcred *np; |
690 | struct iso_mnt *imp; | |
984263bc | 691 | |
e961ef71 | 692 | imp = VFSTOISOFS(mp); |
984263bc MD |
693 | |
694 | /* | |
695 | * Get the export permission structure for this <mp, client> tuple. | |
696 | */ | |
697 | np = vfs_export_lookup(mp, &imp->im_export, nam); | |
698 | if (np == NULL) | |
699 | return (EACCES); | |
700 | ||
701 | *exflagsp = np->netc_exflags; | |
702 | *credanonp = &np->netc_anon; | |
703 | return (0); | |
704 | } | |
705 | ||
706 | int | |
b9b0a6d0 | 707 | cd9660_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp) |
984263bc MD |
708 | { |
709 | ||
710 | /* | |
711 | * XXXX | |
712 | * It would be nice if we didn't always set the `relocated' flag | |
713 | * and force the extra read, but I don't want to think about fixing | |
714 | * that right now. | |
715 | */ | |
716 | return (cd9660_vget_internal(mp, ino, vpp, | |
717 | #if 0 | |
718 | VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, | |
719 | #else | |
720 | 0, | |
721 | #endif | |
60233e58 | 722 | NULL)); |
984263bc MD |
723 | } |
724 | ||
725 | int | |
3fa8192b CP |
726 | cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp, |
727 | int relocated, struct iso_directory_record *isodir) | |
984263bc MD |
728 | { |
729 | struct iso_mnt *imp; | |
730 | struct iso_node *ip; | |
731 | struct buf *bp; | |
732 | struct vnode *vp; | |
b13267a5 | 733 | cdev_t dev; |
984263bc MD |
734 | int error; |
735 | ||
736 | imp = VFSTOISOFS(mp); | |
737 | dev = imp->im_dev; | |
3446c007 | 738 | again: |
984263bc MD |
739 | if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) |
740 | return (0); | |
741 | ||
742 | /* Allocate a new vnode/iso_node. */ | |
6ddb7618 | 743 | error = getnewvnode(VT_ISOFS, mp, &vp, 0, 0); |
3446c007 | 744 | if (error) { |
984263bc MD |
745 | *vpp = NULLVP; |
746 | return (error); | |
747 | } | |
884717e1 | 748 | ip = kmalloc(sizeof(struct iso_node), M_ISOFSNODE, M_WAITOK | M_ZERO); |
984263bc MD |
749 | ip->i_vnode = vp; |
750 | ip->i_dev = dev; | |
751 | ip->i_number = ino; | |
752 | ||
753 | /* | |
3446c007 MD |
754 | * Insert it into the inode hash table and check for a collision. |
755 | * If a collision occurs, throw away the vnode and try again. | |
984263bc | 756 | */ |
3446c007 | 757 | if (cd9660_ihashins(ip) != 0) { |
086c1d7e | 758 | kprintf("debug: cd9660 ihashins collision, retrying\n"); |
5fd012e0 | 759 | vx_put(vp); |
efda3bd0 | 760 | kfree(ip, M_ISOFSNODE); |
3446c007 MD |
761 | goto again; |
762 | } | |
763 | vp->v_data = ip; | |
984263bc | 764 | |
899483f5 | 765 | if (isodir == NULL) { |
984263bc MD |
766 | int lbn, off; |
767 | ||
768 | lbn = lblkno(imp, ino); | |
769 | if (lbn >= imp->volume_space_size) { | |
5fd012e0 | 770 | vx_put(vp); |
086c1d7e | 771 | kprintf("fhtovp: lbn exceed volume space %d\n", lbn); |
984263bc MD |
772 | return (ESTALE); |
773 | } | |
e961ef71 | 774 | |
984263bc MD |
775 | off = blkoff(imp, ino); |
776 | if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { | |
5fd012e0 | 777 | vx_put(vp); |
086c1d7e | 778 | kprintf("fhtovp: crosses block boundary %d\n", |
984263bc MD |
779 | off + ISO_DIRECTORY_RECORD_SIZE); |
780 | return (ESTALE); | |
781 | } | |
e961ef71 | 782 | |
984263bc | 783 | error = bread(imp->im_devvp, |
54078292 | 784 | lblktooff(imp, lbn), |
3b568787 | 785 | imp->logical_block_size, &bp); |
984263bc | 786 | if (error) { |
5fd012e0 | 787 | vx_put(vp); |
984263bc | 788 | brelse(bp); |
086c1d7e | 789 | kprintf("fhtovp: bread error %d\n",error); |
984263bc MD |
790 | return (error); |
791 | } | |
792 | isodir = (struct iso_directory_record *)(bp->b_data + off); | |
793 | ||
794 | if (off + isonum_711(isodir->length) > | |
795 | imp->logical_block_size) { | |
5fd012e0 | 796 | vx_put(vp); |
899483f5 | 797 | if (bp != NULL) |
984263bc | 798 | brelse(bp); |
086c1d7e | 799 | kprintf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", |
984263bc MD |
800 | off +isonum_711(isodir->length), off, |
801 | isonum_711(isodir->length)); | |
802 | return (ESTALE); | |
803 | } | |
e961ef71 | 804 | |
984263bc MD |
805 | #if 0 |
806 | if (isonum_733(isodir->extent) + | |
807 | isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { | |
899483f5 | 808 | if (bp != NULL) |
984263bc | 809 | brelse(bp); |
086c1d7e | 810 | kprintf("fhtovp: file start miss %d vs %d\n", |
984263bc MD |
811 | isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), |
812 | ifhp->ifid_start); | |
813 | return (ESTALE); | |
814 | } | |
815 | #endif | |
816 | } else | |
4090d6ff | 817 | bp = NULL; |
984263bc MD |
818 | |
819 | ip->i_mnt = imp; | |
820 | ip->i_devvp = imp->im_devvp; | |
597aea93 | 821 | vref(ip->i_devvp); |
984263bc MD |
822 | |
823 | if (relocated) { | |
824 | /* | |
825 | * On relocated directories we must | |
826 | * read the `.' entry out of a dir. | |
827 | */ | |
828 | ip->iso_start = ino >> imp->im_bshift; | |
899483f5 | 829 | if (bp != NULL) |
984263bc | 830 | brelse(bp); |
899483f5 | 831 | if ((error = cd9660_devblkatoff(vp, (off_t)0, NULL, &bp)) != 0) { |
5fd012e0 | 832 | vx_put(vp); |
984263bc MD |
833 | return (error); |
834 | } | |
835 | isodir = (struct iso_directory_record *)bp->b_data; | |
836 | } | |
837 | ||
838 | ip->iso_extent = isonum_733(isodir->extent); | |
839 | ip->i_size = isonum_733(isodir->size); | |
840 | ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; | |
57f7b636 | 841 | |
984263bc MD |
842 | /* |
843 | * Setup time stamp, attribute | |
844 | */ | |
845 | vp->v_type = VNON; | |
846 | switch (imp->iso_ftype) { | |
847 | default: /* ISO_FTYPE_9660 */ | |
848 | { | |
849 | struct buf *bp2; | |
850 | int off; | |
851 | if ((imp->im_flags & ISOFSMNT_EXTATT) | |
852 | && (off = isonum_711(isodir->ext_attr_length))) | |
899483f5 | 853 | cd9660_devblkatoff(vp, (off_t)-(off << imp->im_bshift), NULL, |
984263bc MD |
854 | &bp2); |
855 | else | |
856 | bp2 = NULL; | |
857 | cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); | |
858 | cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); | |
859 | if (bp2) | |
860 | brelse(bp2); | |
861 | break; | |
862 | } | |
863 | case ISO_FTYPE_RRIP: | |
864 | cd9660_rrip_analyze(isodir, ip, imp); | |
865 | break; | |
866 | } | |
867 | ||
899483f5 | 868 | if (bp != NULL) |
984263bc MD |
869 | brelse(bp); |
870 | ||
871 | /* | |
872 | * Initialize the associated vnode | |
873 | */ | |
57f7b636 MD |
874 | vp->v_type = IFTOVT(ip->inode.iso_mode); |
875 | ||
876 | switch (vp->v_type) { | |
984263bc | 877 | case VFIFO: |
6ddb7618 | 878 | vp->v_ops = &mp->mnt_vn_fifo_ops; |
984263bc MD |
879 | break; |
880 | case VCHR: | |
881 | case VBLK: | |
6ddb7618 | 882 | vp->v_ops = &mp->mnt_vn_spec_ops; |
0e9b9130 MD |
883 | addaliasu(vp, umajor(ip->inode.iso_rdev), |
884 | uminor(ip->inode.iso_rdev)); | |
984263bc | 885 | break; |
1c843a13 MD |
886 | case VREG: |
887 | case VDIR: | |
b0d18f7d | 888 | vinitvmio(vp, ip->i_size, PAGE_SIZE, -1); |
1c843a13 | 889 | break; |
984263bc MD |
890 | default: |
891 | break; | |
892 | } | |
e961ef71 | 893 | |
984263bc | 894 | if (ip->iso_extent == imp->root_extent) |
2247fe02 | 895 | vsetflags(vp, VROOT); |
984263bc MD |
896 | |
897 | /* | |
5fd012e0 | 898 | * Return the locked and refd vp |
984263bc | 899 | */ |
fc36a10b | 900 | vx_downgrade(vp); |
984263bc MD |
901 | *vpp = vp; |
902 | return (0); | |
903 | } | |
904 | ||
905 | /* | |
906 | * Vnode pointer to File handle | |
907 | */ | |
908 | /* ARGSUSED */ | |
909 | int | |
3fa8192b | 910 | cd9660_vptofh(struct vnode *vp, struct fid *fhp) |
984263bc | 911 | { |
3a1b0fdc RG |
912 | struct iso_node *ip = VTOI(vp); |
913 | struct ifid *ifhp; | |
984263bc MD |
914 | |
915 | ifhp = (struct ifid *)fhp; | |
916 | ifhp->ifid_len = sizeof(struct ifid); | |
917 | ||
918 | ifhp->ifid_ino = ip->i_number; | |
919 | ifhp->ifid_start = ip->iso_start; | |
920 | ||
921 | #ifdef ISOFS_DBG | |
086c1d7e | 922 | kprintf("vptofh: ino %d, start %ld\n", |
984263bc MD |
923 | ifhp->ifid_ino,ifhp->ifid_start); |
924 | #endif | |
925 | return 0; | |
926 | } |