Line data Source code
1 : /* $OpenBSD: udf_vfsops.c,v 1.65 2018/05/02 02:24:55 visa Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 : * SUCH DAMAGE.
27 : *
28 : * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.25 2005/01/25 15:52:03 phk Exp $
29 : */
30 :
31 : /*
32 : * Ported to OpenBSD by Pedro Martelletto in February 2005.
33 : */
34 :
35 : /*
36 : * Ok, here's how it goes. The UDF specs are pretty clear on how each data
37 : * structure is made up, but not very clear on how they relate to each other.
38 : * Here is the skinny... This demostrates a filesystem with one file in the
39 : * root directory. Subdirectories are treated just as normal files, but they
40 : * have File Id Descriptors of their children as their file data. As for the
41 : * Anchor Volume Descriptor Pointer, it can exist in two of the following three
42 : * places: sector 256, sector n (the max sector of the disk), or sector
43 : * n - 256. It's a pretty good bet that one will exist at sector 256 though.
44 : * One caveat is unclosed CD media. For that, sector 256 cannot be written,
45 : * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
46 : * media is closed.
47 : */
48 :
49 : #include <sys/param.h>
50 : #include <sys/systm.h>
51 : #include <sys/uio.h>
52 : #include <sys/buf.h>
53 : #include <sys/dirent.h>
54 : #include <sys/fcntl.h>
55 : #include <sys/kernel.h>
56 : #include <sys/malloc.h>
57 : #include <sys/mutex.h>
58 : #include <sys/mount.h>
59 : #include <sys/namei.h>
60 : #include <sys/pool.h>
61 : #include <sys/proc.h>
62 : #include <sys/lock.h>
63 : #include <sys/queue.h>
64 : #include <sys/vnode.h>
65 : #include <sys/lock.h>
66 : #include <sys/endian.h>
67 : #include <sys/specdev.h>
68 :
69 : #include <crypto/siphash.h>
70 :
71 : #include <isofs/udf/ecma167-udf.h>
72 : #include <isofs/udf/udf.h>
73 : #include <isofs/udf/udf_extern.h>
74 :
75 : struct pool udf_trans_pool;
76 : struct pool unode_pool;
77 : struct pool udf_ds_pool;
78 :
79 : int udf_find_partmaps(struct umount *, struct logvol_desc *);
80 : int udf_get_vpartmap(struct umount *, struct part_map_virt *);
81 : int udf_get_spartmap(struct umount *, struct part_map_spare *);
82 : int udf_get_mpartmap(struct umount *, struct part_map_meta *);
83 : int udf_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *);
84 :
85 : const struct vfsops udf_vfsops = {
86 : .vfs_fhtovp = udf_fhtovp,
87 : .vfs_init = udf_init,
88 : .vfs_mount = udf_mount,
89 : .vfs_start = udf_start,
90 : .vfs_root = udf_root,
91 : .vfs_quotactl = udf_quotactl,
92 : .vfs_statfs = udf_statfs,
93 : .vfs_sync = udf_sync,
94 : .vfs_unmount = udf_unmount,
95 : .vfs_vget = udf_vget,
96 : .vfs_vptofh = udf_vptofh,
97 : .vfs_sysctl = udf_sysctl,
98 : .vfs_checkexp = udf_checkexp,
99 : };
100 :
101 : int
102 0 : udf_init(struct vfsconf *foo)
103 : {
104 0 : pool_init(&udf_trans_pool, MAXNAMLEN * sizeof(unicode_t), 0, IPL_NONE,
105 : PR_WAITOK, "udftrpl", NULL);
106 0 : pool_init(&unode_pool, sizeof(struct unode), 0, IPL_NONE,
107 : PR_WAITOK, "udfndpl", NULL);
108 0 : pool_init(&udf_ds_pool, sizeof(struct udf_dirstream), 0, IPL_NONE,
109 : PR_WAITOK, "udfdspl", NULL);
110 :
111 0 : return (0);
112 : }
113 :
114 : int
115 0 : udf_start(struct mount *mp, int flags, struct proc *p)
116 : {
117 0 : return (0);
118 : }
119 :
120 : int
121 0 : udf_mount(struct mount *mp, const char *path, void *data,
122 : struct nameidata *ndp, struct proc *p)
123 : {
124 : struct vnode *devvp; /* vnode of the mount device */
125 0 : struct udf_args *args = data;
126 0 : char fspec[MNAMELEN];
127 : int error;
128 :
129 0 : if ((mp->mnt_flag & MNT_RDONLY) == 0) {
130 0 : mp->mnt_flag |= MNT_RDONLY;
131 : #ifdef UDF_DEBUG
132 : printf("udf_mount: enforcing read-only mode\n");
133 : #endif
134 0 : }
135 :
136 : /*
137 : * No root filesystem support. Probably not a big deal, since the
138 : * bootloader doesn't understand UDF.
139 : */
140 0 : if (mp->mnt_flag & MNT_ROOTFS)
141 0 : return (EOPNOTSUPP);
142 :
143 : /*
144 : * If updating, check whether changing from read-only to
145 : * read/write; if there is no device name, that's all we do.
146 : */
147 0 : if (mp->mnt_flag & MNT_UPDATE) {
148 0 : return (0);
149 : }
150 :
151 0 : error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
152 0 : if (error)
153 0 : return (error);
154 :
155 0 : NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, p);
156 0 : if ((error = namei(ndp)))
157 0 : return (error);
158 :
159 0 : devvp = ndp->ni_vp;
160 0 : if (devvp->v_type != VBLK) {
161 0 : vrele(devvp);
162 0 : return (ENOTBLK);
163 : }
164 :
165 0 : if (major(devvp->v_rdev) >= nblkdev) {
166 0 : vrele(devvp);
167 0 : return (ENXIO);
168 : }
169 :
170 0 : if ((error = udf_mountfs(devvp, mp, args->lastblock, p))) {
171 0 : vrele(devvp);
172 0 : return (error);
173 : }
174 :
175 : /*
176 : * Keep a copy of the mount information.
177 : */
178 0 : bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
179 0 : strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
180 0 : bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
181 0 : strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN);
182 0 : bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
183 0 : strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
184 :
185 0 : return (0);
186 0 : };
187 :
188 : /*
189 : * Check the descriptor tag for both the correct id and correct checksum.
190 : * Return zero if all is good, EINVAL if not.
191 : */
192 : int
193 0 : udf_checktag(struct desc_tag *tag, uint16_t id)
194 : {
195 : uint8_t *itag;
196 : uint8_t i, cksum = 0;
197 :
198 0 : itag = (uint8_t *)tag;
199 :
200 0 : if (letoh16(tag->id) != id)
201 0 : return (EINVAL);
202 :
203 0 : for (i = 0; i < 15; i++)
204 0 : cksum = cksum + itag[i];
205 0 : cksum = cksum - itag[4];
206 :
207 0 : if (cksum == tag->cksum)
208 0 : return (0);
209 :
210 0 : return (EINVAL);
211 0 : }
212 :
213 : int
214 0 : udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p)
215 : {
216 0 : struct buf *bp = NULL;
217 0 : struct anchor_vdp avdp;
218 : struct umount *ump = NULL;
219 : struct part_desc *pd;
220 : struct logvol_desc *lvd;
221 : struct fileset_desc *fsd;
222 : struct extfile_entry *xfentry;
223 : struct file_entry *fentry;
224 0 : uint32_t sector, size, mvds_start, mvds_end;
225 : uint32_t fsd_offset = 0;
226 : uint16_t part_num = 0, fsd_part = 0;
227 : int error = EINVAL;
228 : int logvol_found = 0, part_found = 0, fsd_found = 0;
229 : int bsize;
230 :
231 : /*
232 : * Disallow multiple mounts of the same device.
233 : * Disallow mounting of a device that is currently in use
234 : * (except for root, which might share swap device for miniroot).
235 : * Flush out any old buffers remaining from a previous use.
236 : */
237 0 : if ((error = vfs_mountedon(devvp)))
238 0 : return (error);
239 0 : if (vcount(devvp) > 1 && devvp != rootvp)
240 0 : return (EBUSY);
241 0 : vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
242 0 : error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
243 0 : VOP_UNLOCK(devvp);
244 0 : if (error)
245 0 : return (error);
246 :
247 0 : error = VOP_OPEN(devvp, FREAD, FSCRED, p);
248 0 : if (error)
249 0 : return (error);
250 :
251 0 : ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO);
252 :
253 0 : mp->mnt_data = ump;
254 0 : mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
255 0 : mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
256 0 : mp->mnt_stat.f_namemax = NAME_MAX;
257 0 : mp->mnt_flag |= MNT_LOCAL;
258 :
259 0 : ump->um_mountp = mp;
260 0 : ump->um_dev = devvp->v_rdev;
261 0 : ump->um_devvp = devvp;
262 :
263 : bsize = 2048; /* Should probe the media for its size. */
264 :
265 : /*
266 : * Get the Anchor Volume Descriptor Pointer from sector 256.
267 : * Should also check sector n - 256, n, and 512.
268 : */
269 0 : sector = 256;
270 0 : if ((error = bread(devvp, sector * btodb(bsize), bsize, &bp)) != 0)
271 : goto bail;
272 0 : if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
273 : goto bail;
274 :
275 0 : bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
276 0 : brelse(bp);
277 0 : bp = NULL;
278 :
279 : /*
280 : * Extract the Partition Descriptor and Logical Volume Descriptor
281 : * from the Volume Descriptor Sequence.
282 : * Should we care about the partition type right now?
283 : * What about multiple partitions?
284 : */
285 0 : mvds_start = letoh32(avdp.main_vds_ex.loc);
286 0 : mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;
287 0 : for (sector = mvds_start; sector < mvds_end; sector++) {
288 0 : if ((error = bread(devvp, sector * btodb(bsize), bsize,
289 0 : &bp)) != 0) {
290 0 : printf("Can't read sector %d of VDS\n", sector);
291 0 : goto bail;
292 : }
293 0 : lvd = (struct logvol_desc *)bp->b_data;
294 0 : if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
295 0 : ump->um_bsize = letoh32(lvd->lb_size);
296 0 : ump->um_bmask = ump->um_bsize - 1;
297 0 : ump->um_bshift = ffs(ump->um_bsize) - 1;
298 0 : fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num);
299 0 : fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num);
300 0 : if (udf_find_partmaps(ump, lvd))
301 : break;
302 : logvol_found = 1;
303 0 : }
304 0 : pd = (struct part_desc *)bp->b_data;
305 0 : if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
306 : part_found = 1;
307 0 : part_num = letoh16(pd->part_num);
308 0 : ump->um_len = ump->um_reallen = letoh32(pd->part_len);
309 0 : ump->um_start = ump->um_realstart = letoh32(pd->start_loc);
310 0 : }
311 :
312 0 : brelse(bp);
313 0 : bp = NULL;
314 0 : if ((part_found) && (logvol_found))
315 : break;
316 : }
317 :
318 0 : if (!part_found || !logvol_found) {
319 : error = EINVAL;
320 0 : goto bail;
321 : }
322 :
323 0 : if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
324 : /* Read Metadata File 'File Entry' to find Metadata file. */
325 : struct long_ad *la;
326 0 : sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */
327 0 : if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
328 0 : printf("Cannot read sector %d for Metadata File Entry\n", sector);
329 : error = EINVAL;
330 0 : goto bail;
331 : }
332 0 : xfentry = (struct extfile_entry *)bp->b_data;
333 0 : fentry = (struct file_entry *)bp->b_data;
334 0 : if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0)
335 0 : la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)];
336 0 : else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0)
337 0 : la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)];
338 : else {
339 0 : printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n",
340 0 : sector, fentry->tag.id);
341 : error = EINVAL;
342 0 : goto bail;
343 : }
344 0 : ump->um_meta_start = letoh32(la->loc.lb_num);
345 0 : ump->um_meta_len = letoh32(la->len);
346 0 : if (bp != NULL) {
347 0 : brelse(bp);
348 0 : bp = NULL;
349 0 : }
350 0 : } else if (fsd_part != part_num) {
351 0 : printf("FSD does not lie within the partition!\n");
352 : error = EINVAL;
353 0 : goto bail;
354 : }
355 :
356 0 : mtx_init(&ump->um_hashmtx, IPL_NONE);
357 0 : ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK,
358 0 : &ump->um_hashsz);
359 0 : arc4random_buf(&ump->um_hashkey, sizeof(ump->um_hashkey));
360 :
361 : /* Get the VAT, if needed */
362 0 : if (ump->um_flags & UDF_MNT_FIND_VAT) {
363 0 : error = udf_vat_get(ump, lb);
364 0 : if (error)
365 : goto bail;
366 : }
367 :
368 : /*
369 : * Grab the Fileset Descriptor
370 : * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
371 : * me in the right direction here.
372 : */
373 :
374 0 : if (ISSET(ump->um_flags, UDF_MNT_USES_META))
375 0 : sector = ump->um_meta_start;
376 : else
377 0 : sector = fsd_offset;
378 0 : udf_vat_map(ump, §or);
379 0 : if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
380 0 : printf("Cannot read sector %d of FSD\n", sector);
381 0 : goto bail;
382 : }
383 0 : fsd = (struct fileset_desc *)bp->b_data;
384 0 : if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
385 : fsd_found = 1;
386 0 : bcopy(&fsd->rootdir_icb, &ump->um_root_icb,
387 : sizeof(struct long_ad));
388 0 : if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
389 0 : ump->um_root_icb.loc.lb_num += ump->um_meta_start;
390 0 : ump->um_root_icb.loc.part_num = part_num;
391 0 : }
392 : }
393 :
394 0 : brelse(bp);
395 0 : bp = NULL;
396 :
397 0 : if (!fsd_found) {
398 0 : printf("Couldn't find the fsd\n");
399 : error = EINVAL;
400 0 : goto bail;
401 : }
402 :
403 : /*
404 : * Find the file entry for the root directory.
405 : */
406 0 : sector = letoh32(ump->um_root_icb.loc.lb_num);
407 0 : size = letoh32(ump->um_root_icb.len);
408 0 : udf_vat_map(ump, §or);
409 0 : if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) {
410 0 : printf("Cannot read sector %d\n", sector);
411 0 : goto bail;
412 : }
413 :
414 0 : xfentry = (struct extfile_entry *)bp->b_data;
415 0 : fentry = (struct file_entry *)bp->b_data;
416 0 : error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY);
417 0 : if (error) {
418 0 : error = udf_checktag(&fentry->tag, TAGID_FENTRY);
419 0 : if (error) {
420 0 : printf("Invalid root file entry!\n");
421 0 : goto bail;
422 : }
423 : }
424 :
425 0 : brelse(bp);
426 0 : bp = NULL;
427 :
428 0 : devvp->v_specmountpoint = mp;
429 :
430 0 : return (0);
431 :
432 : bail:
433 0 : if (ump != NULL) {
434 0 : hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE, M_UDFMOUNT);
435 0 : free(ump, M_UDFMOUNT, 0);
436 0 : mp->mnt_data = NULL;
437 0 : mp->mnt_flag &= ~MNT_LOCAL;
438 0 : }
439 0 : if (devvp->v_specinfo)
440 0 : devvp->v_specmountpoint = NULL;
441 0 : if (bp != NULL)
442 0 : brelse(bp);
443 :
444 0 : vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY);
445 0 : VOP_CLOSE(devvp, FREAD, FSCRED, p);
446 0 : VOP_UNLOCK(devvp);
447 :
448 0 : return (error);
449 0 : }
450 :
451 : int
452 0 : udf_unmount(struct mount *mp, int mntflags, struct proc *p)
453 : {
454 : struct umount *ump;
455 : struct vnode *devvp;
456 : int error, flags = 0;
457 :
458 0 : ump = VFSTOUDFFS(mp);
459 0 : devvp = ump->um_devvp;
460 :
461 0 : if (mntflags & MNT_FORCE)
462 0 : flags |= FORCECLOSE;
463 :
464 0 : if ((error = vflush(mp, NULL, flags)))
465 0 : return (error);
466 :
467 0 : vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
468 0 : vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0);
469 0 : (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
470 0 : VOP_UNLOCK(devvp);
471 :
472 0 : devvp->v_specmountpoint = NULL;
473 0 : vrele(devvp);
474 :
475 0 : if (ump->um_flags & UDF_MNT_USES_VAT)
476 0 : free(ump->um_vat, M_UDFMOUNT, 0);
477 :
478 0 : if (ump->um_stbl != NULL)
479 0 : free(ump->um_stbl, M_UDFMOUNT, 0);
480 :
481 0 : hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE, M_UDFMOUNT);
482 0 : free(ump, M_UDFMOUNT, 0);
483 :
484 0 : mp->mnt_data = NULL;
485 0 : mp->mnt_flag &= ~MNT_LOCAL;
486 :
487 0 : return (0);
488 0 : }
489 :
490 : int
491 0 : udf_root(struct mount *mp, struct vnode **vpp)
492 : {
493 : struct umount *ump;
494 : struct vnode *vp;
495 : udfino_t id;
496 : int error;
497 :
498 0 : ump = VFSTOUDFFS(mp);
499 :
500 0 : id = udf_getid(&ump->um_root_icb);
501 :
502 0 : error = udf_vget(mp, id, vpp);
503 0 : if (error)
504 0 : return (error);
505 :
506 0 : vp = *vpp;
507 0 : vp->v_flag |= VROOT;
508 :
509 0 : return (0);
510 0 : }
511 :
512 : int
513 0 : udf_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
514 : struct proc *p)
515 : {
516 0 : return (EOPNOTSUPP);
517 : }
518 :
519 : int
520 0 : udf_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
521 : {
522 : struct umount *ump;
523 :
524 0 : ump = VFSTOUDFFS(mp);
525 :
526 0 : sbp->f_bsize = ump->um_bsize;
527 0 : sbp->f_iosize = ump->um_bsize;
528 0 : sbp->f_blocks = ump->um_len;
529 0 : sbp->f_bfree = 0;
530 0 : sbp->f_bavail = 0;
531 0 : sbp->f_files = 0;
532 0 : sbp->f_ffree = 0;
533 0 : sbp->f_favail = 0;
534 0 : copy_statfs_info(sbp, mp);
535 :
536 0 : return (0);
537 : }
538 :
539 : int
540 0 : udf_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
541 : {
542 0 : return (0);
543 : }
544 :
545 : int
546 0 : udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
547 : {
548 0 : struct buf *bp;
549 : struct vnode *devvp;
550 : struct umount *ump;
551 : struct proc *p;
552 0 : struct vnode *vp, *nvp;
553 : struct unode *up;
554 : struct extfile_entry *xfe;
555 : struct file_entry *fe;
556 0 : uint32_t sector;
557 : int error, size;
558 :
559 0 : if (ino > (udfino_t)-1)
560 0 : panic("udf_vget: alien ino_t %llu", (unsigned long long)ino);
561 :
562 0 : p = curproc;
563 0 : bp = NULL;
564 0 : *vpp = NULL;
565 0 : ump = VFSTOUDFFS(mp);
566 :
567 : /* See if we already have this in the cache */
568 0 : if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0)
569 0 : return (error);
570 0 : if (*vpp != NULL)
571 0 : return (0);
572 :
573 : /*
574 : * Allocate memory and check the tag id's before grabbing a new
575 : * vnode, since it's hard to roll back if there is a problem.
576 : */
577 0 : up = pool_get(&unode_pool, PR_WAITOK | PR_ZERO);
578 :
579 : /*
580 : * Copy in the file entry. Per the spec, the size can only be 1 block.
581 : */
582 0 : sector = ino;
583 0 : devvp = ump->um_devvp;
584 0 : udf_vat_map(ump, §or);
585 0 : if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
586 0 : printf("Cannot read sector %d\n", sector);
587 0 : pool_put(&unode_pool, up);
588 0 : if (bp != NULL)
589 0 : brelse(bp);
590 0 : return (error);
591 : }
592 :
593 0 : xfe = (struct extfile_entry *)bp->b_data;
594 0 : fe = (struct file_entry *)bp->b_data;
595 0 : error = udf_checktag(&xfe->tag, TAGID_EXTFENTRY);
596 0 : if (error == 0) {
597 0 : size = letoh32(xfe->l_ea) + letoh32(xfe->l_ad);
598 0 : } else {
599 0 : error = udf_checktag(&fe->tag, TAGID_FENTRY);
600 0 : if (error) {
601 0 : printf("Invalid file entry!\n");
602 0 : pool_put(&unode_pool, up);
603 0 : if (bp != NULL)
604 0 : brelse(bp);
605 0 : return (ENOMEM);
606 : } else
607 0 : size = letoh32(fe->l_ea) + letoh32(fe->l_ad);
608 : }
609 :
610 : /* Allocate max size of FE/XFE. */
611 0 : up->u_fentry = malloc(size + UDF_EXTFENTRY_SIZE, M_UDFFENTRY, M_NOWAIT | M_ZERO);
612 0 : if (up->u_fentry == NULL) {
613 0 : pool_put(&unode_pool, up);
614 0 : if (bp != NULL)
615 0 : brelse(bp);
616 0 : return (ENOMEM); /* Cannot allocate file entry block */
617 : }
618 :
619 0 : if (udf_checktag(&xfe->tag, TAGID_EXTFENTRY) == 0)
620 0 : bcopy(bp->b_data, up->u_fentry, size + UDF_EXTFENTRY_SIZE);
621 : else
622 0 : bcopy(bp->b_data, up->u_fentry, size + UDF_FENTRY_SIZE);
623 :
624 0 : brelse(bp);
625 0 : bp = NULL;
626 :
627 0 : if ((error = udf_allocv(mp, &vp, p))) {
628 0 : free(up->u_fentry, M_UDFFENTRY, 0);
629 0 : pool_put(&unode_pool, up);
630 0 : return (error); /* Error from udf_allocv() */
631 : }
632 :
633 0 : up->u_vnode = vp;
634 0 : up->u_ino = ino;
635 0 : up->u_devvp = ump->um_devvp;
636 0 : up->u_dev = ump->um_dev;
637 0 : up->u_ump = ump;
638 0 : vp->v_data = up;
639 0 : vref(ump->um_devvp);
640 :
641 0 : rrw_init_flags(&up->u_lock, "unode", RWL_DUPOK | RWL_IS_VNODE);
642 :
643 : /*
644 : * udf_hashins() will lock the vnode for us.
645 : */
646 0 : udf_hashins(up);
647 :
648 0 : switch (up->u_fentry->icbtag.file_type) {
649 : default:
650 0 : printf("Unrecognized file type (%d)\n", vp->v_type);
651 0 : vp->v_type = VREG;
652 0 : break;
653 : case UDF_ICB_FILETYPE_DIRECTORY:
654 0 : vp->v_type = VDIR;
655 0 : break;
656 : case UDF_ICB_FILETYPE_BLOCKDEVICE:
657 0 : vp->v_type = VBLK;
658 0 : break;
659 : case UDF_ICB_FILETYPE_CHARDEVICE:
660 0 : vp->v_type = VCHR;
661 0 : break;
662 : case UDF_ICB_FILETYPE_FIFO:
663 0 : vp->v_type = VFIFO;
664 0 : break;
665 : case UDF_ICB_FILETYPE_SOCKET:
666 0 : vp->v_type = VSOCK;
667 0 : break;
668 : case UDF_ICB_FILETYPE_SYMLINK:
669 0 : vp->v_type = VLNK;
670 0 : break;
671 : case UDF_ICB_FILETYPE_RANDOMACCESS:
672 : case UDF_ICB_FILETYPE_REALTIME:
673 : case UDF_ICB_FILETYPE_UNKNOWN:
674 0 : vp->v_type = VREG;
675 0 : break;
676 : }
677 :
678 : /* check if this is a vnode alias */
679 0 : if ((nvp = checkalias(vp, up->u_dev, ump->um_mountp)) != NULL) {
680 0 : printf("found a vnode alias\n");
681 : /*
682 : * Discard unneeded vnode, but save its udf_node.
683 : * Note that the lock is carried over in the udf_node
684 : */
685 0 : nvp->v_data = vp->v_data;
686 0 : vp->v_data = NULL;
687 0 : vp->v_op = &spec_vops;
688 0 : vrele(vp);
689 0 : vgone(vp);
690 : /*
691 : * Reinitialize aliased inode.
692 : */
693 0 : vp = nvp;
694 0 : ump->um_devvp = vp;
695 0 : }
696 :
697 0 : *vpp = vp;
698 :
699 0 : return (0);
700 0 : }
701 :
702 : struct ifid {
703 : u_short ifid_len;
704 : u_short ifid_pad;
705 : int ifid_ino;
706 : long ifid_start;
707 : };
708 :
709 : int
710 0 : udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
711 : {
712 : struct ifid *ifhp;
713 0 : struct vnode *nvp;
714 : int error;
715 :
716 0 : ifhp = (struct ifid *)fhp;
717 :
718 0 : if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
719 0 : *vpp = NULLVP;
720 0 : return (error);
721 : }
722 :
723 0 : *vpp = nvp;
724 :
725 0 : return (0);
726 0 : }
727 :
728 : int
729 0 : udf_vptofh(struct vnode *vp, struct fid *fhp)
730 : {
731 : struct unode *up;
732 : struct ifid *ifhp;
733 :
734 0 : up = VTOU(vp);
735 0 : ifhp = (struct ifid *)fhp;
736 0 : ifhp->ifid_len = sizeof(struct ifid);
737 0 : ifhp->ifid_ino = up->u_ino;
738 :
739 0 : return (0);
740 : }
741 :
742 : int
743 0 : udf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
744 : size_t newlen, struct proc *p)
745 : {
746 0 : return (EINVAL);
747 : }
748 :
749 : int
750 0 : udf_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
751 : struct ucred **credanonp)
752 : {
753 0 : return (EACCES); /* For the time being */
754 : }
755 :
756 : /* Handle a virtual partition map */
757 : int
758 0 : udf_get_vpartmap(struct umount *ump, struct part_map_virt *pmv)
759 : {
760 0 : ump->um_flags |= UDF_MNT_FIND_VAT; /* Should do more than this */
761 0 : return (0);
762 : }
763 :
764 : /* Handle a sparable partition map */
765 : int
766 0 : udf_get_spartmap(struct umount *ump, struct part_map_spare *pms)
767 : {
768 0 : struct buf *bp;
769 : int i, error;
770 :
771 0 : ump->um_stbl = malloc(letoh32(pms->st_size), M_UDFMOUNT, M_NOWAIT);
772 0 : if (ump->um_stbl == NULL)
773 0 : return (ENOMEM);
774 :
775 0 : bzero(ump->um_stbl, letoh32(pms->st_size));
776 :
777 : /* Calculate the number of sectors per packet */
778 0 : ump->um_psecs = letoh16(pms->packet_len) / ump->um_bsize;
779 :
780 0 : error = udf_readlblks(ump, letoh32(pms->st_loc[0]),
781 0 : letoh32(pms->st_size), &bp);
782 :
783 0 : if (error) {
784 0 : if (bp != NULL)
785 0 : brelse(bp);
786 0 : free(ump->um_stbl, M_UDFMOUNT, 0);
787 0 : return (error); /* Failed to read sparing table */
788 : }
789 :
790 0 : bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size));
791 0 : brelse(bp);
792 0 : bp = NULL;
793 :
794 0 : if (udf_checktag(&ump->um_stbl->tag, 0)) {
795 0 : free(ump->um_stbl, M_UDFMOUNT, 0);
796 0 : return (EINVAL); /* Invalid sparing table found */
797 : }
798 :
799 : /*
800 : * See how many valid entries there are here. The list is
801 : * supposed to be sorted, 0xfffffff0 and higher are not valid.
802 : */
803 0 : for (i = 0; i < letoh16(ump->um_stbl->rt_l); i++) {
804 0 : ump->um_stbl_len = i;
805 0 : if (letoh32(ump->um_stbl->entries[i].org) >= 0xfffffff0)
806 : break;
807 : }
808 :
809 0 : return (0);
810 0 : }
811 :
812 : /* Handle a metadata partition map */
813 : int
814 0 : udf_get_mpartmap(struct umount *ump, struct part_map_meta *pmm)
815 : {
816 0 : ump->um_flags |= UDF_MNT_USES_META;
817 0 : ump->um_meta_start = pmm->meta_file_lbn;
818 0 : return (0);
819 : }
820 :
821 : /* Scan the partition maps */
822 : int
823 0 : udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd)
824 : {
825 : struct regid *pmap_id;
826 0 : unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
827 : int i, ptype, psize, error;
828 0 : uint8_t *pmap = (uint8_t *) &lvd->maps[0];
829 :
830 0 : for (i = 0; i < letoh32(lvd->n_pm); i++) {
831 0 : ptype = pmap[0];
832 0 : psize = pmap[1];
833 :
834 0 : if (ptype != 1 && ptype != 2)
835 0 : return (EINVAL); /* Invalid partition map type */
836 :
837 0 : if (psize != sizeof(struct part_map_1) &&
838 0 : psize != sizeof(struct part_map_2))
839 0 : return (EINVAL); /* Invalid partition map size */
840 :
841 0 : if (ptype == 1) {
842 0 : pmap += sizeof(struct part_map_1);
843 0 : continue;
844 : }
845 :
846 : /* Type 2 map. Find out the details */
847 0 : pmap_id = (struct regid *) &pmap[4];
848 0 : regid_id[UDF_REGID_ID_SIZE] = '\0';
849 0 : bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE);
850 :
851 0 : if (!bcmp(®id_id[0], "*UDF Virtual Partition",
852 : UDF_REGID_ID_SIZE))
853 0 : error = udf_get_vpartmap(ump,
854 0 : (struct part_map_virt *) pmap);
855 0 : else if (!bcmp(®id_id[0], "*UDF Sparable Partition",
856 : UDF_REGID_ID_SIZE))
857 0 : error = udf_get_spartmap(ump,
858 0 : (struct part_map_spare *) pmap);
859 0 : else if (!bcmp(®id_id[0], "*UDF Metadata Partition",
860 : UDF_REGID_ID_SIZE))
861 0 : error = udf_get_mpartmap(ump,
862 0 : (struct part_map_meta *) pmap);
863 : else
864 0 : return (EINVAL); /* Unsupported partition map */
865 :
866 0 : if (error)
867 0 : return (error); /* Error getting partition */
868 :
869 0 : pmap += sizeof(struct part_map_2);
870 0 : }
871 :
872 0 : return (0);
873 0 : }
|