Commit | Line | Data |
---|---|---|
5fc285c5 KM |
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 | * %sccs.include.redist.c% | |
11 | * | |
706651ee | 12 | * @(#)cd9660_vfsops.c 8.13 (Berkeley) %G% |
5fc285c5 KM |
13 | */ |
14 | ||
15 | #include <sys/param.h> | |
16 | #include <sys/systm.h> | |
17 | #include <sys/namei.h> | |
18 | #include <sys/proc.h> | |
19 | #include <sys/kernel.h> | |
20 | #include <sys/vnode.h> | |
21 | #include <miscfs/specfs/specdev.h> | |
22 | #include <sys/mount.h> | |
23 | #include <sys/buf.h> | |
24 | #include <sys/file.h> | |
25 | #include <sys/dkbad.h> | |
26 | #include <sys/disklabel.h> | |
27 | #include <sys/ioctl.h> | |
28 | #include <sys/errno.h> | |
29 | #include <sys/malloc.h> | |
b3e9029f | 30 | #include <sys/stat.h> |
5fc285c5 KM |
31 | |
32 | #include <isofs/cd9660/iso.h> | |
13275923 | 33 | #include <isofs/cd9660/cd9660_node.h> |
eceb865c | 34 | #include <isofs/cd9660/cd9660_mount.h> |
5fc285c5 KM |
35 | |
36 | extern int enodev (); | |
37 | ||
13275923 KM |
38 | struct vfsops cd9660_vfsops = { |
39 | cd9660_mount, | |
40 | cd9660_start, | |
41 | cd9660_unmount, | |
42 | cd9660_root, | |
43 | cd9660_quotactl, | |
44 | cd9660_statfs, | |
45 | cd9660_sync, | |
46 | cd9660_vget, | |
47 | cd9660_fhtovp, | |
48 | cd9660_vptofh, | |
49 | cd9660_init, | |
eceb865c | 50 | cd9660_sysctl |
5fc285c5 KM |
51 | }; |
52 | ||
53 | /* | |
54 | * Called by vfs_mountroot when iso is going to be mounted as root. | |
55 | * | |
56 | * Name is updated by mount(8) after booting. | |
57 | */ | |
58 | #define ROOTNAME "root_device" | |
59 | ||
60 | static iso_mountfs(); | |
61 | ||
13275923 | 62 | cd9660_mountroot() |
5fc285c5 KM |
63 | { |
64 | register struct mount *mp; | |
65 | extern struct vnode *rootvp; | |
66 | struct proc *p = curproc; /* XXX */ | |
67 | struct iso_mnt *imp; | |
68 | register struct fs *fs; | |
69 | u_int size; | |
70 | int error; | |
71 | struct iso_args args; | |
72 | ||
73 | /* | |
74 | * Get vnodes for swapdev and rootdev. | |
75 | */ | |
76 | if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) | |
13275923 | 77 | panic("cd9660_mountroot: can't setup bdevvp's"); |
5fc285c5 KM |
78 | |
79 | mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); | |
80 | bzero((char *)mp, (u_long)sizeof(struct mount)); | |
13275923 | 81 | mp->mnt_op = &cd9660_vfsops; |
5fc285c5 | 82 | mp->mnt_flag = MNT_RDONLY; |
05e5da84 | 83 | LIST_INIT(&mp->mnt_vnodelist); |
5fc285c5 KM |
84 | args.flags = ISOFSMNT_ROOT; |
85 | if (error = iso_mountfs(rootvp, mp, p, &args)) { | |
86 | free(mp, M_MOUNT); | |
87 | return (error); | |
88 | } | |
89 | if (error = vfs_lock(mp)) { | |
13275923 | 90 | (void)cd9660_unmount(mp, 0, p); |
5fc285c5 KM |
91 | free(mp, M_MOUNT); |
92 | return (error); | |
93 | } | |
3df1ed0c | 94 | CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
5fc285c5 KM |
95 | mp->mnt_vnodecovered = NULLVP; |
96 | imp = VFSTOISOFS(mp); | |
706651ee KM |
97 | (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, |
98 | &size); | |
99 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); | |
5fc285c5 KM |
100 | (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, |
101 | &size); | |
102 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
706651ee | 103 | (void)cd9660_statfs(mp, &mp->mnt_stat, p); |
5fc285c5 KM |
104 | vfs_unlock(mp); |
105 | return (0); | |
106 | } | |
107 | ||
5fc285c5 KM |
108 | /* |
109 | * VFS Operations. | |
110 | * | |
111 | * mount system call | |
112 | */ | |
13275923 | 113 | cd9660_mount(mp, path, data, ndp, p) |
5fc285c5 KM |
114 | register struct mount *mp; |
115 | char *path; | |
116 | caddr_t data; | |
117 | struct nameidata *ndp; | |
118 | struct proc *p; | |
119 | { | |
120 | struct vnode *devvp; | |
121 | struct iso_args args; | |
122 | u_int size; | |
123 | int error; | |
124 | struct iso_mnt *imp; | |
125 | ||
126 | if (error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))) | |
127 | return (error); | |
128 | ||
129 | if ((mp->mnt_flag & MNT_RDONLY) == 0) | |
130 | return (EROFS); | |
131 | ||
132 | /* | |
133 | * If updating, check whether changing from read-only to | |
134 | * read/write; if there is no device name, that's all we do. | |
135 | */ | |
136 | if (mp->mnt_flag & MNT_UPDATE) { | |
137 | imp = VFSTOISOFS(mp); | |
138 | if (args.fspec == 0) | |
139 | return (vfs_export(mp, &imp->im_export, &args.export)); | |
140 | } | |
141 | /* | |
142 | * Not an update, or updating the name: look up the name | |
143 | * and verify that it refers to a sensible block device. | |
144 | */ | |
145 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); | |
146 | if (error = namei(ndp)) | |
147 | return (error); | |
148 | devvp = ndp->ni_vp; | |
149 | ||
150 | if (devvp->v_type != VBLK) { | |
151 | vrele(devvp); | |
152 | return ENOTBLK; | |
153 | } | |
154 | if (major(devvp->v_rdev) >= nblkdev) { | |
155 | vrele(devvp); | |
156 | return ENXIO; | |
157 | } | |
158 | if ((mp->mnt_flag & MNT_UPDATE) == 0) | |
159 | error = iso_mountfs(devvp, mp, p, &args); | |
160 | else { | |
161 | if (devvp != imp->im_devvp) | |
162 | error = EINVAL; /* needs translation */ | |
163 | else | |
164 | vrele(devvp); | |
165 | } | |
166 | if (error) { | |
167 | vrele(devvp); | |
168 | return error; | |
169 | } | |
170 | imp = VFSTOISOFS(mp); | |
706651ee KM |
171 | (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); |
172 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); | |
5fc285c5 KM |
173 | (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, |
174 | &size); | |
175 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
13275923 | 176 | (void) cd9660_statfs(mp, &mp->mnt_stat, p); |
5fc285c5 KM |
177 | return 0; |
178 | } | |
179 | ||
180 | /* | |
181 | * Common code for mount and mountroot | |
182 | */ | |
183 | static iso_mountfs(devvp, mp, p, argp) | |
184 | register struct vnode *devvp; | |
185 | struct mount *mp; | |
186 | struct proc *p; | |
187 | struct iso_args *argp; | |
188 | { | |
189 | register struct iso_mnt *isomp = (struct iso_mnt *)0; | |
190 | struct buf *bp = NULL; | |
191 | dev_t dev = devvp->v_rdev; | |
192 | caddr_t base, space; | |
193 | int havepart = 0, blks; | |
194 | int error = EINVAL, i, size; | |
195 | int needclose = 0; | |
196 | int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; | |
197 | extern struct vnode *rootvp; | |
198 | int j; | |
199 | int iso_bsize; | |
200 | int iso_blknum; | |
201 | struct iso_volume_descriptor *vdp; | |
202 | struct iso_primary_descriptor *pri; | |
203 | struct iso_directory_record *rootp; | |
204 | int logical_block_size; | |
205 | ||
206 | if (!ronly) | |
207 | return EROFS; | |
208 | ||
209 | /* | |
210 | * Disallow multiple mounts of the same device. | |
211 | * Disallow mounting of a device that is currently in use | |
212 | * (except for root, which might share swap device for miniroot). | |
213 | * Flush out any old buffers remaining from a previous use. | |
214 | */ | |
215 | if (error = vfs_mountedon(devvp)) | |
216 | return error; | |
217 | if (vcount(devvp) > 1 && devvp != rootvp) | |
218 | return EBUSY; | |
219 | if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) | |
220 | return (error); | |
221 | ||
222 | if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) | |
223 | return error; | |
224 | needclose = 1; | |
225 | ||
226 | /* This is the "logical sector size". The standard says this | |
227 | * should be 2048 or the physical sector size on the device, | |
228 | * whichever is greater. For now, we'll just use a constant. | |
229 | */ | |
230 | iso_bsize = ISO_DEFAULT_BLOCK_SIZE; | |
231 | ||
232 | for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) { | |
349b9aaf KM |
233 | if (error = bread(devvp, iso_blknum * btodb(iso_bsize), |
234 | iso_bsize, NOCRED, &bp)) | |
5fc285c5 KM |
235 | goto out; |
236 | ||
349b9aaf | 237 | vdp = (struct iso_volume_descriptor *)bp->b_data; |
5fc285c5 KM |
238 | if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { |
239 | error = EINVAL; | |
240 | goto out; | |
241 | } | |
242 | ||
243 | if (isonum_711 (vdp->type) == ISO_VD_END) { | |
244 | error = EINVAL; | |
245 | goto out; | |
246 | } | |
247 | ||
248 | if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) | |
249 | break; | |
250 | brelse(bp); | |
251 | } | |
252 | ||
253 | if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) { | |
254 | error = EINVAL; | |
255 | goto out; | |
256 | } | |
257 | ||
258 | pri = (struct iso_primary_descriptor *)vdp; | |
259 | ||
260 | logical_block_size = isonum_723 (pri->logical_block_size); | |
261 | ||
262 | if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE | |
263 | || (logical_block_size & (logical_block_size - 1)) != 0) { | |
264 | error = EINVAL; | |
265 | goto out; | |
266 | } | |
267 | ||
268 | rootp = (struct iso_directory_record *)pri->root_directory_record; | |
269 | ||
2d80cfd2 MH |
270 | isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK); |
271 | bzero((caddr_t)isomp, sizeof *isomp); | |
5fc285c5 KM |
272 | isomp->logical_block_size = logical_block_size; |
273 | isomp->volume_space_size = isonum_733 (pri->volume_space_size); | |
274 | bcopy (rootp, isomp->root, sizeof isomp->root); | |
275 | isomp->root_extent = isonum_733 (rootp->extent); | |
276 | isomp->root_size = isonum_733 (rootp->size); | |
277 | ||
278 | isomp->im_bmask = logical_block_size - 1; | |
279 | isomp->im_bshift = 0; | |
280 | while ((1 << isomp->im_bshift) < isomp->logical_block_size) | |
281 | isomp->im_bshift++; | |
282 | ||
283 | bp->b_flags |= B_AGE; | |
284 | brelse(bp); | |
285 | bp = NULL; | |
286 | ||
287 | mp->mnt_data = (qaddr_t)isomp; | |
288 | mp->mnt_stat.f_fsid.val[0] = (long)dev; | |
eceb865c | 289 | mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; |
5fc285c5 KM |
290 | mp->mnt_maxsymlinklen = 0; |
291 | mp->mnt_flag |= MNT_LOCAL; | |
292 | isomp->im_mountp = mp; | |
293 | isomp->im_dev = dev; | |
294 | isomp->im_devvp = devvp; | |
295 | ||
296 | devvp->v_specflags |= SI_MOUNTEDON; | |
297 | ||
298 | /* Check the Rock Ridge Extention support */ | |
299 | if (!(argp->flags & ISOFSMNT_NORRIP)) { | |
349b9aaf KM |
300 | if (error = bread(isomp->im_devvp, |
301 | (isomp->root_extent + isonum_711(rootp->ext_attr_length)) << | |
302 | (isomp->im_bshift - DEV_BSHIFT), | |
303 | isomp->logical_block_size, NOCRED, &bp)) | |
5fc285c5 KM |
304 | goto out; |
305 | ||
349b9aaf | 306 | rootp = (struct iso_directory_record *)bp->b_data; |
5fc285c5 | 307 | |
13275923 | 308 | if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { |
5fc285c5 KM |
309 | argp->flags |= ISOFSMNT_NORRIP; |
310 | } else { | |
311 | argp->flags &= ~ISOFSMNT_GENS; | |
312 | } | |
313 | ||
314 | /* | |
315 | * The contents are valid, | |
316 | * but they will get reread as part of another vnode, so... | |
317 | */ | |
318 | bp->b_flags |= B_AGE; | |
319 | brelse(bp); | |
320 | bp = NULL; | |
321 | } | |
322 | isomp->im_flags = argp->flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS|ISOFSMNT_EXTATT); | |
323 | switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) { | |
324 | default: | |
325 | isomp->iso_ftype = ISO_FTYPE_DEFAULT; | |
326 | break; | |
327 | case ISOFSMNT_GENS|ISOFSMNT_NORRIP: | |
328 | isomp->iso_ftype = ISO_FTYPE_9660; | |
329 | break; | |
330 | case 0: | |
331 | isomp->iso_ftype = ISO_FTYPE_RRIP; | |
332 | break; | |
333 | } | |
334 | ||
335 | return 0; | |
336 | out: | |
337 | if (bp) | |
338 | brelse(bp); | |
339 | if (needclose) | |
340 | (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); | |
341 | if (isomp) { | |
342 | free((caddr_t)isomp, M_ISOFSMNT); | |
343 | mp->mnt_data = (qaddr_t)0; | |
344 | } | |
345 | return error; | |
346 | } | |
347 | ||
348 | /* | |
349 | * Make a filesystem operational. | |
350 | * Nothing to do at the moment. | |
351 | */ | |
352 | /* ARGSUSED */ | |
13275923 | 353 | cd9660_start(mp, flags, p) |
5fc285c5 KM |
354 | struct mount *mp; |
355 | int flags; | |
356 | struct proc *p; | |
357 | { | |
358 | return 0; | |
359 | } | |
360 | ||
361 | /* | |
362 | * unmount system call | |
363 | */ | |
364 | int | |
13275923 | 365 | cd9660_unmount(mp, mntflags, p) |
5fc285c5 KM |
366 | struct mount *mp; |
367 | int mntflags; | |
368 | struct proc *p; | |
369 | { | |
370 | register struct iso_mnt *isomp; | |
371 | int i, error, ronly, flags = 0; | |
372 | ||
fe5239dc | 373 | if (mntflags & MNT_FORCE) |
5fc285c5 | 374 | flags |= FORCECLOSE; |
5fc285c5 KM |
375 | #if 0 |
376 | mntflushbuf(mp, 0); | |
377 | if (mntinvalbuf(mp)) | |
378 | return EBUSY; | |
379 | #endif | |
380 | if (error = vflush(mp, NULLVP, flags)) | |
381 | return (error); | |
382 | ||
383 | isomp = VFSTOISOFS(mp); | |
384 | ||
385 | #ifdef ISODEVMAP | |
386 | if (isomp->iso_ftype == ISO_FTYPE_RRIP) | |
387 | iso_dunmap(isomp->im_dev); | |
388 | #endif | |
389 | ||
390 | isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON; | |
391 | error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p); | |
392 | vrele(isomp->im_devvp); | |
393 | free((caddr_t)isomp, M_ISOFSMNT); | |
394 | mp->mnt_data = (qaddr_t)0; | |
395 | mp->mnt_flag &= ~MNT_LOCAL; | |
396 | return (error); | |
397 | } | |
398 | ||
399 | /* | |
400 | * Return root of a filesystem | |
401 | */ | |
13275923 | 402 | cd9660_root(mp, vpp) |
5fc285c5 KM |
403 | struct mount *mp; |
404 | struct vnode **vpp; | |
405 | { | |
b3e9029f | 406 | struct iso_mnt *imp = VFSTOISOFS(mp); |
085443c5 KM |
407 | struct iso_directory_record *dp = |
408 | (struct iso_directory_record *)imp->root; | |
349b9aaf | 409 | ino_t ino = isodirino(dp, imp); |
5fc285c5 KM |
410 | |
411 | /* | |
412 | * With RRIP we must use the `.' entry of the root directory. | |
085443c5 | 413 | * Simply tell vget, that it's a relocated directory. |
5fc285c5 | 414 | */ |
085443c5 KM |
415 | return (cd9660_vget_internal(mp, ino, vpp, |
416 | imp->iso_ftype == ISO_FTYPE_RRIP, dp)); | |
5fc285c5 KM |
417 | } |
418 | ||
419 | /* | |
420 | * Do operations associated with quotas, not supported | |
421 | */ | |
422 | /* ARGSUSED */ | |
423 | int | |
13275923 | 424 | cd9660_quotactl(mp, cmd, uid, arg, p) |
5fc285c5 KM |
425 | struct mount *mp; |
426 | int cmd; | |
427 | uid_t uid; | |
428 | caddr_t arg; | |
429 | struct proc *p; | |
430 | { | |
431 | ||
432 | return (EOPNOTSUPP); | |
433 | } | |
434 | ||
435 | /* | |
436 | * Get file system statistics. | |
437 | */ | |
13275923 | 438 | cd9660_statfs(mp, sbp, p) |
5fc285c5 KM |
439 | struct mount *mp; |
440 | register struct statfs *sbp; | |
441 | struct proc *p; | |
442 | { | |
443 | register struct iso_mnt *isomp; | |
444 | register struct fs *fs; | |
445 | ||
446 | isomp = VFSTOISOFS(mp); | |
05e5da84 | 447 | |
349b9aaf KM |
448 | #ifdef COMPAT_09 |
449 | sbp->f_type = 5; | |
450 | #else | |
451 | sbp->f_type = 0; | |
452 | #endif | |
5fc285c5 KM |
453 | sbp->f_bsize = isomp->logical_block_size; |
454 | sbp->f_iosize = sbp->f_bsize; /* XXX */ | |
455 | sbp->f_blocks = isomp->volume_space_size; | |
456 | sbp->f_bfree = 0; /* total free blocks */ | |
457 | sbp->f_bavail = 0; /* blocks free for non superuser */ | |
458 | sbp->f_files = 0; /* total files */ | |
459 | sbp->f_ffree = 0; /* free file nodes */ | |
460 | if (sbp != &mp->mnt_stat) { | |
706651ee KM |
461 | bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); |
462 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); | |
5fc285c5 KM |
463 | } |
464 | /* Use the first spare for flags: */ | |
465 | sbp->f_spare[0] = isomp->im_flags; | |
466 | return 0; | |
467 | } | |
468 | ||
469 | /* ARGSUSED */ | |
470 | int | |
13275923 | 471 | cd9660_sync(mp, waitfor, cred, p) |
5fc285c5 KM |
472 | struct mount *mp; |
473 | int waitfor; | |
474 | struct ucred *cred; | |
475 | struct proc *p; | |
476 | { | |
477 | return (0); | |
478 | } | |
479 | ||
5fc285c5 KM |
480 | /* |
481 | * File handle to vnode | |
482 | * | |
483 | * Have to be really careful about stale file handles: | |
484 | * - check that the inode number is in range | |
485 | * - call iget() to get the locked inode | |
486 | * - check for an unallocated inode (i_mode == 0) | |
487 | * - check that the generation number matches | |
488 | */ | |
489 | ||
490 | struct ifid { | |
491 | ushort ifid_len; | |
492 | ushort ifid_pad; | |
493 | int ifid_ino; | |
494 | long ifid_start; | |
495 | }; | |
496 | ||
497 | /* ARGSUSED */ | |
498 | int | |
13275923 | 499 | cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) |
5fc285c5 KM |
500 | register struct mount *mp; |
501 | struct fid *fhp; | |
502 | struct mbuf *nam; | |
503 | struct vnode **vpp; | |
504 | int *exflagsp; | |
505 | struct ucred **credanonp; | |
506 | { | |
b3e9029f KM |
507 | struct ifid *ifhp = (struct ifid *)fhp; |
508 | register struct iso_node *ip; | |
509 | register struct netcred *np; | |
510 | register struct iso_mnt *imp = VFSTOISOFS(mp); | |
511 | struct vnode *nvp; | |
512 | int error; | |
5fc285c5 KM |
513 | |
514 | #ifdef ISOFS_DBG | |
515 | printf("fhtovp: ino %d, start %ld\n", | |
516 | ifhp->ifid_ino, ifhp->ifid_start); | |
517 | #endif | |
518 | ||
b3e9029f KM |
519 | /* |
520 | * Get the export permission structure for this <mp, client> tuple. | |
521 | */ | |
5fc285c5 KM |
522 | np = vfs_export_lookup(mp, &imp->im_export, nam); |
523 | if (np == NULL) | |
524 | return (EACCES); | |
525 | ||
b3e9029f KM |
526 | if (error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) { |
527 | *vpp = NULLVP; | |
528 | return (error); | |
529 | } | |
530 | ip = VTOI(nvp); | |
531 | if (ip->inode.iso_mode == 0) { | |
532 | vput(nvp); | |
533 | *vpp = NULLVP; | |
534 | return (ESTALE); | |
535 | } | |
536 | *vpp = nvp; | |
537 | *exflagsp = np->netc_exflags; | |
538 | *credanonp = &np->netc_anon; | |
539 | return (0); | |
540 | } | |
541 | ||
542 | int | |
543 | cd9660_vget(mp, ino, vpp) | |
544 | struct mount *mp; | |
545 | ino_t ino; | |
546 | struct vnode **vpp; | |
547 | { | |
548 | ||
549 | /* | |
550 | * XXXX | |
551 | * It would be nice if we didn't always set the `relocated' flag | |
552 | * and force the extra read, but I don't want to think about fixing | |
553 | * that right now. | |
554 | */ | |
555 | return (cd9660_vget_internal(mp, ino, vpp, | |
085443c5 | 556 | #if 0 |
b3e9029f | 557 | VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, |
085443c5 KM |
558 | #else |
559 | 0, | |
560 | #endif | |
b3e9029f KM |
561 | (struct iso_directory_entry *)0)); |
562 | } | |
563 | ||
564 | int | |
565 | cd9660_vget_internal(mp, ino, vpp, relocated, isodir) | |
566 | struct mount *mp; | |
567 | ino_t ino; | |
568 | struct vnode **vpp; | |
569 | int relocated; | |
570 | struct iso_directory_record *isodir; | |
571 | { | |
572 | register struct iso_mnt *imp; | |
573 | struct iso_node *ip; | |
574 | struct buf *bp; | |
575 | struct vnode *vp, *nvp; | |
b3e9029f KM |
576 | dev_t dev; |
577 | int error; | |
578 | ||
579 | imp = VFSTOISOFS(mp); | |
580 | dev = imp->im_dev; | |
581 | if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) | |
582 | return (0); | |
583 | ||
584 | /* Allocate a new vnode/iso_node. */ | |
585 | if (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) { | |
586 | *vpp = NULLVP; | |
587 | return (error); | |
588 | } | |
589 | MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, | |
590 | M_WAITOK); | |
591 | bzero((caddr_t)ip, sizeof(struct iso_node)); | |
592 | vp->v_data = ip; | |
593 | ip->i_vnode = vp; | |
594 | ip->i_dev = dev; | |
595 | ip->i_number = ino; | |
596 | ||
597 | /* | |
598 | * Put it onto its hash chain and lock it so that other requests for | |
599 | * this inode will block if they arrive while we are sleeping waiting | |
600 | * for old data structures to be purged or for the contents of the | |
601 | * disk portion of this inode to be read. | |
602 | */ | |
603 | cd9660_ihashins(ip); | |
604 | ||
085443c5 KM |
605 | if (isodir == 0) { |
606 | int lbn, off; | |
607 | ||
349b9aaf | 608 | lbn = lblkno(imp, ino); |
085443c5 KM |
609 | if (lbn >= imp->volume_space_size) { |
610 | vput(vp); | |
611 | printf("fhtovp: lbn exceed volume space %d\n", lbn); | |
612 | return (ESTALE); | |
613 | } | |
5fc285c5 | 614 | |
349b9aaf | 615 | off = blkoff(imp, ino); |
085443c5 KM |
616 | if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { |
617 | vput(vp); | |
618 | printf("fhtovp: crosses block boundary %d\n", | |
619 | off + ISO_DIRECTORY_RECORD_SIZE); | |
620 | return (ESTALE); | |
621 | } | |
5fc285c5 | 622 | |
085443c5 | 623 | error = bread(imp->im_devvp, |
349b9aaf | 624 | lbn << (imp->im_bshift - DEV_BSHIFT), |
b3e9029f KM |
625 | imp->logical_block_size, NOCRED, &bp); |
626 | if (error) { | |
627 | vput(vp); | |
628 | brelse(bp); | |
629 | printf("fhtovp: bread error %d\n",error); | |
630 | return (error); | |
631 | } | |
632 | isodir = (struct iso_directory_record *)(bp->b_data + off); | |
b3e9029f | 633 | |
085443c5 KM |
634 | if (off + isonum_711(isodir->length) > |
635 | imp->logical_block_size) { | |
636 | vput(vp); | |
637 | if (bp != 0) | |
638 | brelse(bp); | |
639 | printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", | |
640 | off +isonum_711(isodir->length), off, | |
641 | isonum_711(isodir->length)); | |
642 | return (ESTALE); | |
643 | } | |
5fc285c5 | 644 | |
b3e9029f | 645 | #if 0 |
085443c5 KM |
646 | if (isonum_733(isodir->extent) + |
647 | isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { | |
648 | if (bp != 0) | |
649 | brelse(bp); | |
650 | printf("fhtovp: file start miss %d vs %d\n", | |
651 | isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), | |
652 | ifhp->ifid_start); | |
653 | return (ESTALE); | |
654 | } | |
b3e9029f | 655 | #endif |
085443c5 KM |
656 | } else |
657 | bp = 0; | |
b3e9029f KM |
658 | |
659 | ip->i_mnt = imp; | |
660 | ip->i_devvp = imp->im_devvp; | |
661 | VREF(ip->i_devvp); | |
662 | ||
663 | if (relocated) { | |
664 | /* | |
665 | * On relocated directories we must | |
666 | * read the `.' entry out of a dir. | |
667 | */ | |
668 | ip->iso_start = ino >> imp->im_bshift; | |
669 | if (bp != 0) | |
670 | brelse(bp); | |
349b9aaf | 671 | if (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) { |
b3e9029f KM |
672 | vput(vp); |
673 | return (error); | |
674 | } | |
675 | isodir = (struct iso_directory_record *)bp->b_data; | |
676 | } | |
677 | ||
678 | ip->iso_extent = isonum_733(isodir->extent); | |
679 | ip->i_size = isonum_733(isodir->size); | |
680 | ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; | |
5fc285c5 | 681 | |
b3e9029f KM |
682 | /* |
683 | * Setup time stamp, attribute | |
684 | */ | |
685 | vp->v_type = VNON; | |
686 | switch (imp->iso_ftype) { | |
687 | default: /* ISO_FTYPE_9660 */ | |
688 | { | |
689 | struct buf *bp2; | |
349b9aaf | 690 | int off; |
b3e9029f | 691 | if ((imp->im_flags & ISOFSMNT_EXTATT) |
349b9aaf KM |
692 | && (off = isonum_711(isodir->ext_attr_length))) |
693 | VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, | |
b3e9029f | 694 | &bp2); |
672f03cc KM |
695 | else |
696 | bp2 = NULL; | |
b3e9029f KM |
697 | cd9660_defattr(isodir, ip, bp2); |
698 | cd9660_deftstamp(isodir, ip, bp2); | |
672f03cc KM |
699 | if (bp2) |
700 | brelse(bp2); | |
b3e9029f KM |
701 | break; |
702 | } | |
703 | case ISO_FTYPE_RRIP: | |
704 | cd9660_rrip_analyze(isodir, ip, imp); | |
705 | break; | |
5fc285c5 | 706 | } |
b3e9029f KM |
707 | |
708 | if (bp != 0) | |
709 | brelse(bp); | |
710 | ||
5fc285c5 | 711 | /* |
b3e9029f | 712 | * Initialize the associated vnode |
5fc285c5 | 713 | */ |
b3e9029f KM |
714 | switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { |
715 | case VFIFO: | |
716 | #ifdef FIFO | |
717 | vp->v_op = cd9660_fifoop_p; | |
718 | break; | |
719 | #else | |
720 | vput(vp); | |
721 | return (EOPNOTSUPP); | |
722 | #endif /* FIFO */ | |
723 | case VCHR: | |
724 | case VBLK: | |
725 | /* | |
726 | * if device, look at device number table for translation | |
727 | */ | |
728 | #ifdef ISODEVMAP | |
729 | if (dp = iso_dmap(dev, ino, 0)) | |
730 | ip->inode.iso_rdev = dp->d_dev; | |
731 | #endif | |
732 | vp->v_op = cd9660_specop_p; | |
733 | if (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) { | |
734 | /* | |
735 | * Discard unneeded vnode, but save its iso_node. | |
736 | */ | |
737 | cd9660_ihashrem(ip); | |
738 | VOP_UNLOCK(vp); | |
739 | nvp->v_data = vp->v_data; | |
740 | vp->v_data = NULL; | |
741 | vp->v_op = spec_vnodeop_p; | |
742 | vrele(vp); | |
743 | vgone(vp); | |
744 | /* | |
745 | * Reinitialize aliased inode. | |
746 | */ | |
747 | vp = nvp; | |
748 | ip->i_vnode = vp; | |
749 | cd9660_ihashins(ip); | |
750 | } | |
751 | break; | |
5fc285c5 | 752 | } |
b3e9029f KM |
753 | |
754 | if (ip->iso_extent == imp->root_extent) | |
755 | vp->v_flag |= VROOT; | |
756 | ||
757 | /* | |
758 | * XXX need generation number? | |
759 | */ | |
760 | ||
761 | *vpp = vp; | |
762 | return (0); | |
5fc285c5 KM |
763 | } |
764 | ||
765 | /* | |
766 | * Vnode pointer to File handle | |
767 | */ | |
768 | /* ARGSUSED */ | |
13275923 | 769 | cd9660_vptofh(vp, fhp) |
5fc285c5 KM |
770 | struct vnode *vp; |
771 | struct fid *fhp; | |
772 | { | |
773 | register struct iso_node *ip = VTOI(vp); | |
774 | register struct ifid *ifhp; | |
775 | register struct iso_mnt *mp = ip->i_mnt; | |
776 | ||
777 | ifhp = (struct ifid *)fhp; | |
778 | ifhp->ifid_len = sizeof(struct ifid); | |
779 | ||
780 | ifhp->ifid_ino = ip->i_number; | |
781 | ifhp->ifid_start = ip->iso_start; | |
782 | ||
783 | #ifdef ISOFS_DBG | |
784 | printf("vptofh: ino %d, start %ld\n", | |
785 | ifhp->ifid_ino,ifhp->ifid_start); | |
786 | #endif | |
787 | return 0; | |
788 | } |