1 /* $OpenBSD: udf_vnops.c,v 1.75 2024/10/18 05:52:32 miod 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_vnops.c,v 1.50 2005/01/28 14:42:16 phk Exp $
29 */
30
31 /*
32 * Ported to OpenBSD by Pedro Martelletto in February 2005.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/namei.h>
38 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <sys/stat.h>
41 #include <sys/buf.h>
42 #include <sys/pool.h>
43 #include <sys/lock.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/dirent.h>
47 #include <sys/queue.h>
48 #include <sys/endian.h>
49 #include <sys/specdev.h>
50 #include <sys/unistd.h>
51
52 #include <crypto/siphash.h>
53
54 #include <isofs/udf/ecma167-udf.h>
55 #include <isofs/udf/udf.h>
56 #include <isofs/udf/udf_extern.h>
57
58 int udf_bmap_internal(struct unode *, off_t, daddr_t *, uint32_t *);
59
60 const struct vops udf_vops = {
61 .vop_access = udf_access,
62 .vop_bmap = udf_bmap,
63 .vop_lookup = udf_lookup,
64 .vop_getattr = udf_getattr,
65 .vop_open = udf_open,
66 .vop_close = udf_close,
67 .vop_ioctl = udf_ioctl,
68 .vop_read = udf_read,
69 .vop_readdir = udf_readdir,
70 .vop_readlink = udf_readlink,
71 .vop_inactive = udf_inactive,
72 .vop_reclaim = udf_reclaim,
73 .vop_strategy = udf_strategy,
74 .vop_lock = udf_lock,
75 .vop_unlock = udf_unlock,
76 .vop_pathconf = udf_pathconf,
77 .vop_islocked = udf_islocked,
78 .vop_print = udf_print,
79
80 .vop_abortop = NULL,
81 .vop_advlock = NULL,
82 .vop_bwrite = NULL,
83 .vop_create = NULL,
84 .vop_fsync = NULL,
85 .vop_link = NULL,
86 .vop_mknod = NULL,
87 .vop_remove = eopnotsupp,
88 .vop_rename = NULL,
89 .vop_revoke = NULL,
90 .vop_mkdir = NULL,
91 .vop_rmdir = NULL,
92 .vop_setattr = NULL,
93 .vop_symlink = NULL,
94 .vop_write = NULL,
95 .vop_kqfilter = NULL
96 };
97
98 #define UDF_INVALID_BMAP -1
99
100 /* Look up a unode based on the udfino_t passed in and return its vnode */
101 int
udf_hashlookup(struct umount * ump,udfino_t id,int flags,struct vnode ** vpp)102 udf_hashlookup(struct umount *ump, udfino_t id, int flags, struct vnode **vpp)
103 {
104 struct unode *up;
105 struct udf_hash_lh *lh;
106 int error;
107
108 *vpp = NULL;
109
110 loop:
111 mtx_enter(&ump->um_hashmtx);
112 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, &id, sizeof(id)) &
113 ump->um_hashsz];
114 if (lh == NULL) {
115 mtx_leave(&ump->um_hashmtx);
116 return (ENOENT);
117 }
118
119 LIST_FOREACH(up, lh, u_le) {
120 if (up->u_ino == id) {
121 mtx_leave(&ump->um_hashmtx);
122 error = vget(up->u_vnode, flags);
123 if (error == ENOENT)
124 goto loop;
125 if (error)
126 return (error);
127 *vpp = up->u_vnode;
128 return (0);
129 }
130 }
131
132 mtx_leave(&ump->um_hashmtx);
133
134 return (0);
135 }
136
137 int
udf_hashins(struct unode * up)138 udf_hashins(struct unode *up)
139 {
140 struct umount *ump;
141 struct udf_hash_lh *lh;
142
143 ump = up->u_ump;
144
145 vn_lock(up->u_vnode, LK_EXCLUSIVE | LK_RETRY);
146 mtx_enter(&ump->um_hashmtx);
147 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey,
148 &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz];
149 if (lh == NULL)
150 panic("hash entry is NULL, up->u_ino = %d", up->u_ino);
151 LIST_INSERT_HEAD(lh, up, u_le);
152 mtx_leave(&ump->um_hashmtx);
153
154 return (0);
155 }
156
157 int
udf_hashrem(struct unode * up)158 udf_hashrem(struct unode *up)
159 {
160 struct umount *ump;
161 struct udf_hash_lh *lh;
162
163 ump = up->u_ump;
164
165 mtx_enter(&ump->um_hashmtx);
166 lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey,
167 &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz];
168 if (lh == NULL)
169 panic("hash entry is NULL, up->u_ino = %d", up->u_ino);
170 LIST_REMOVE(up, u_le);
171 mtx_leave(&ump->um_hashmtx);
172
173 return (0);
174 }
175
176 int
udf_allocv(struct mount * mp,struct vnode ** vpp,struct proc * p)177 udf_allocv(struct mount *mp, struct vnode **vpp, struct proc *p)
178 {
179 int error;
180 struct vnode *vp;
181
182 error = getnewvnode(VT_UDF, mp, &udf_vops, &vp);
183 if (error) {
184 printf("udf_allocv: failed to allocate new vnode\n");
185 return (error);
186 }
187
188 *vpp = vp;
189 return (0);
190 }
191
192 /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
193 static mode_t
udf_permtomode(struct unode * up)194 udf_permtomode(struct unode *up)
195 {
196 uint32_t perm;
197 uint16_t flags;
198 mode_t mode;
199
200 perm = letoh32(up->u_fentry->perm);
201 flags = letoh16(up->u_fentry->icbtag.flags);
202
203 mode = perm & UDF_FENTRY_PERM_USER_MASK;
204 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
205 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
206 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
207 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
208 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
209
210 return (mode);
211 }
212
213 int
udf_access(void * v)214 udf_access(void *v)
215 {
216 struct vop_access_args *ap = v;
217 struct vnode *vp;
218 struct unode *up;
219 mode_t a_mode, mode;
220
221 vp = ap->a_vp;
222 up = VTOU(vp);
223 a_mode = ap->a_mode;
224
225 if (a_mode & VWRITE) {
226 switch (vp->v_type) {
227 case VDIR:
228 case VLNK:
229 case VREG:
230 return (EROFS);
231 /* NOTREACHED */
232 default:
233 break;
234 }
235 }
236
237 mode = udf_permtomode(up);
238
239 return (vaccess(vp->v_type, mode, up->u_fentry->uid, up->u_fentry->gid,
240 a_mode, ap->a_cred));
241 }
242
243 static int mon_lens[2][12] = {
244 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
245 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
246 };
247
248 static int
udf_isaleapyear(int year)249 udf_isaleapyear(int year)
250 {
251 int i;
252
253 i = (year % 4) ? 0 : 1;
254 i &= (year % 100) ? 1 : 0;
255 i |= (year % 400) ? 0 : 1;
256
257 return (i);
258 }
259
260 /*
261 * This is just a rough hack. Daylight savings isn't calculated and tv_nsec
262 * is ignored.
263 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
264 */
265 static void
udf_timetotimespec(struct timestamp * time,struct timespec * t)266 udf_timetotimespec(struct timestamp *time, struct timespec *t)
267 {
268 int i, lpyear, daysinyear, year;
269 union {
270 uint16_t u_tz_offset;
271 int16_t s_tz_offset;
272 } tz;
273
274 /* DirectCD seems to like using bogus year values */
275 year = letoh16(time->year);
276 if (year < 1970) {
277 t->tv_sec = 0;
278 t->tv_nsec = 0;
279 return;
280 }
281
282 /* Calculate the time and day */
283 t->tv_nsec = 1000 * time->usec + 100000 * time->hund_usec
284 + 10000000 * time->centisec;
285 t->tv_sec = time->second;
286 t->tv_sec += time->minute * 60;
287 t->tv_sec += time->hour * 3600;
288 t->tv_sec += time->day * 3600 * 24;
289
290 /* Calculate the month */
291 lpyear = udf_isaleapyear(year);
292 for (i = 1; i < time->month; i++)
293 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
294
295 /* Speed up the calculation */
296 if (year > 1979)
297 t->tv_sec += 315532800;
298 if (year > 1989)
299 t->tv_sec += 315619200;
300 if (year > 1999)
301 t->tv_sec += 315532800;
302 for (i = 2000; i < year; i++) {
303 daysinyear = udf_isaleapyear(i) + 365 ;
304 t->tv_sec += daysinyear * 3600 * 24;
305 }
306
307 /*
308 * Calculate the time zone. The timezone is 12 bit signed 2's
309 * compliment, so we gotta do some extra magic to handle it right.
310 */
311 tz.u_tz_offset = letoh16(time->type_tz);
312 tz.u_tz_offset &= 0x0fff;
313 if (tz.u_tz_offset & 0x0800)
314 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
315 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
316 t->tv_sec -= tz.s_tz_offset * 60;
317
318 return;
319 }
320
321 int
udf_getattr(void * v)322 udf_getattr(void *v)
323 {
324 struct vop_getattr_args *ap = v;
325 struct vnode *vp;
326 struct unode *up;
327 struct vattr *vap;
328 struct extfile_entry *xfentry;
329 struct file_entry *fentry;
330 struct timespec ts;
331
332 ts.tv_sec = 0;
333
334 vp = ap->a_vp;
335 vap = ap->a_vap;
336 up = VTOU(vp);
337
338 xfentry = up->u_fentry;
339 fentry = (struct file_entry *)up->u_fentry;
340
341 vap->va_fsid = up->u_dev;
342 vap->va_fileid = up->u_ino;
343 vap->va_mode = udf_permtomode(up);
344 vap->va_nlink = letoh16(fentry->link_cnt);
345 /*
346 * The spec says that -1 is valid for uid/gid and indicates an
347 * invalid uid/gid. How should this be represented?
348 */
349 vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid);
350 vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid);
351 vap->va_rdev = 0;
352 if (vp->v_type & VDIR) {
353 vap->va_nlink++; /* Count a reference to ourselves */
354 /*
355 * Directories that are recorded within their ICB will show
356 * as having 0 blocks recorded. Since tradition dictates
357 * that directories consume at least one logical block,
358 * make it appear so.
359 */
360 vap->va_size = up->u_ump->um_bsize;
361 } else
362 vap->va_size = letoh64(fentry->inf_len);
363 if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) {
364 udf_timetotimespec(&xfentry->atime, &vap->va_atime);
365 udf_timetotimespec(&xfentry->mtime, &vap->va_mtime);
366 if ((vp->v_type & VDIR) && xfentry->logblks_rec != 0)
367 vap->va_size =
368 letoh64(xfentry->logblks_rec) * up->u_ump->um_bsize;
369 } else {
370 udf_timetotimespec(&fentry->atime, &vap->va_atime);
371 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
372 if ((vp->v_type & VDIR) && fentry->logblks_rec != 0)
373 vap->va_size =
374 letoh64(fentry->logblks_rec) * up->u_ump->um_bsize;
375 }
376 vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */
377 vap->va_flags = 0;
378 vap->va_gen = 1;
379 vap->va_blocksize = up->u_ump->um_bsize;
380 vap->va_bytes = letoh64(fentry->inf_len);
381 vap->va_type = vp->v_type;
382 vap->va_filerev = 0;
383
384 return (0);
385 }
386
387 int
udf_open(void * v)388 udf_open(void *v)
389 {
390 return (0); /* Nothing to be done at this point */
391 }
392
393 int
udf_close(void * v)394 udf_close(void *v)
395 {
396 return (0); /* Nothing to be done at this point */
397 }
398
399 /*
400 * File specific ioctls.
401 */
402 int
udf_ioctl(void * v)403 udf_ioctl(void *v)
404 {
405 return (ENOTTY);
406 }
407
408 /*
409 * I'm not sure that this has much value in a read-only filesystem, but
410 * cd9660 has it too.
411 */
412 int
udf_pathconf(void * v)413 udf_pathconf(void *v)
414 {
415 struct vop_pathconf_args *ap = v;
416 int error = 0;
417
418 switch (ap->a_name) {
419 case _PC_LINK_MAX:
420 *ap->a_retval = 65535;
421 break;
422 case _PC_NAME_MAX:
423 *ap->a_retval = NAME_MAX;
424 break;
425 case _PC_CHOWN_RESTRICTED:
426 *ap->a_retval = 1;
427 break;
428 case _PC_NO_TRUNC:
429 *ap->a_retval = 1;
430 break;
431 case _PC_TIMESTAMP_RESOLUTION:
432 *ap->a_retval = 1000; /* 1 microsecond */
433 break;
434 default:
435 error = EINVAL;
436 break;
437 }
438
439 return (error);
440 }
441
442 int
udf_read(void * v)443 udf_read(void *v)
444 {
445 struct vop_read_args *ap = v;
446 struct vnode *vp = ap->a_vp;
447 struct uio *uio = ap->a_uio;
448 struct unode *up = VTOU(vp);
449 struct buf *bp;
450 uint8_t *data;
451 off_t fsize, offset;
452 int error = 0;
453 int size;
454
455 if (uio->uio_offset < 0)
456 return (EINVAL);
457
458 fsize = letoh64(up->u_fentry->inf_len);
459
460 while (uio->uio_offset < fsize && uio->uio_resid > 0) {
461 offset = uio->uio_offset;
462 size = ulmin(uio->uio_resid, MAXBSIZE);
463 if (size > fsize - offset)
464 size = fsize - offset;
465 error = udf_readatoffset(up, &size, offset, &bp, &data);
466 if (error == 0)
467 error = uiomove(data, (size_t)size, uio);
468 if (bp != NULL) {
469 brelse(bp);
470 bp = NULL;
471 }
472 if (error)
473 break;
474 }
475
476 return (error);
477 }
478
479 /*
480 * Translate the name from a CS0 dstring to a 16-bit Unicode String.
481 * Hooks need to be placed in here to translate from Unicode to the encoding
482 * that the kernel/user expects. Return the length of the translated string.
483 */
484 int
udf_transname(char * cs0string,char * destname,int len,struct umount * ump)485 udf_transname(char *cs0string, char *destname, int len, struct umount *ump)
486 {
487 unicode_t *transname;
488 int i, unilen = 0, destlen;
489
490 if (len > MAXNAMLEN) {
491 #ifdef DIAGNOSTIC
492 printf("udf_transname(): name too long\n");
493 #endif
494 return (0);
495 }
496
497 /* allocate a buffer big enough to hold an 8->16 bit expansion */
498 transname = pool_get(&udf_trans_pool, PR_WAITOK);
499
500 if ((unilen = udf_rawnametounicode(len, cs0string, transname)) == -1) {
501 #ifdef DIAGNOSTIC
502 printf("udf_transname(): Unicode translation failed\n");
503 #endif
504 pool_put(&udf_trans_pool, transname);
505 return (0);
506 }
507
508 /* Pack it back to 8-bit Unicode. */
509 for (i = 0; i < unilen ; i++)
510 if (transname[i] & 0xff00)
511 destname[i] = '?'; /* Fudge the 16bit chars */
512 else
513 destname[i] = transname[i] & 0xff;
514
515 pool_put(&udf_trans_pool, transname);
516
517 /* Don't forget to terminate the string. */
518 destname[unilen] = 0;
519 destlen = unilen;
520
521 return (destlen);
522 }
523
524 /*
525 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
526 * 0 on a successful match, nonzero otherwise. Unicode work may need to be
527 * done here also.
528 */
529 static int
udf_cmpname(char * cs0string,char * cmpname,int cs0len,int cmplen,struct umount * ump)530 udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct umount *ump)
531 {
532 char *transname;
533 int error = 0;
534
535 /* This is overkill, but not worth creating a new pool */
536 transname = pool_get(&udf_trans_pool, PR_WAITOK);
537
538 cs0len = udf_transname(cs0string, transname, cs0len, ump);
539
540 /* Easy check. If they aren't the same length, they aren't equal */
541 if ((cs0len == 0) || (cs0len != cmplen))
542 error = -1;
543 else
544 error = bcmp(transname, cmpname, cmplen);
545
546 pool_put(&udf_trans_pool, transname);
547
548 return (error);
549 }
550
551 struct udf_uiodir {
552 struct dirent *dirent;
553 int eofflag;
554 };
555
556 static int
udf_uiodir(struct udf_uiodir * uiodir,struct uio * uio,long off)557 udf_uiodir(struct udf_uiodir *uiodir, struct uio *uio, long off)
558 {
559 size_t de_size = DIRENT_SIZE(uiodir->dirent);
560
561 if (uio->uio_resid < de_size) {
562 uiodir->eofflag = 0;
563 return (-1);
564 }
565 uiodir->dirent->d_off = off;
566 uiodir->dirent->d_reclen = de_size;
567
568 if (memchr(uiodir->dirent->d_name, '/',
569 uiodir->dirent->d_namlen) != NULL) {
570 /* illegal file name */
571 return (EINVAL);
572 }
573
574 return (uiomove(uiodir->dirent, de_size, uio));
575 }
576
577 static struct udf_dirstream *
udf_opendir(struct unode * up,int offset,int fsize,struct umount * ump)578 udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump)
579 {
580 struct udf_dirstream *ds;
581
582 ds = pool_get(&udf_ds_pool, PR_WAITOK | PR_ZERO);
583
584 ds->node = up;
585 ds->offset = offset;
586 ds->ump = ump;
587 ds->fsize = fsize;
588
589 return (ds);
590 }
591
592 static struct fileid_desc *
udf_getfid(struct udf_dirstream * ds)593 udf_getfid(struct udf_dirstream *ds)
594 {
595 struct fileid_desc *fid;
596 int error, frag_size = 0, total_fid_size;
597
598 /* End of directory? */
599 if (ds->offset + ds->off >= ds->fsize) {
600 ds->error = 0;
601 return (NULL);
602 }
603
604 /* Grab the first extent of the directory */
605 if (ds->off == 0) {
606 ds->size = 0;
607 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
608 &ds->bp, &ds->data);
609 if (error) {
610 ds->error = error;
611 if (ds->bp != NULL) {
612 brelse(ds->bp);
613 ds->bp = NULL;
614 }
615 return (NULL);
616 }
617 }
618
619 /*
620 * Clean up from a previous fragmented FID.
621 * Is this the right place for this?
622 */
623 if (ds->fid_fragment && ds->buf != NULL) {
624 ds->fid_fragment = 0;
625 free(ds->buf, M_UDFFID, 0);
626 }
627
628 fid = (struct fileid_desc*)&ds->data[ds->off];
629
630 /*
631 * Check to see if the fid is fragmented. The first test
632 * ensures that we don't wander off the end of the buffer
633 * looking for the l_iu and l_fi fields.
634 */
635 if (ds->off + UDF_FID_SIZE > ds->size ||
636 ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
637
638 /* Copy what we have of the fid into a buffer */
639 frag_size = ds->size - ds->off;
640 if (frag_size >= ds->ump->um_bsize) {
641 printf("udf: invalid FID fragment\n");
642 ds->error = EINVAL;
643 return (NULL);
644 }
645
646 /*
647 * File ID descriptors can only be at most one
648 * logical sector in size.
649 */
650 ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK|M_ZERO);
651 bcopy(fid, ds->buf, frag_size);
652
653 /* Reduce all of the casting magic */
654 fid = (struct fileid_desc*)ds->buf;
655
656 if (ds->bp != NULL) {
657 brelse(ds->bp);
658 ds->bp = NULL;
659 }
660
661 /* Fetch the next allocation */
662 ds->offset += ds->size;
663 ds->size = 0;
664 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
665 &ds->bp, &ds->data);
666 if (error) {
667 ds->error = error;
668 if (ds->bp != NULL) {
669 brelse(ds->bp);
670 ds->bp = NULL;
671 }
672 return (NULL);
673 }
674
675 /*
676 * If the fragment was so small that we didn't get
677 * the l_iu and l_fi fields, copy those in.
678 */
679 if (frag_size < UDF_FID_SIZE)
680 bcopy(ds->data, &ds->buf[frag_size],
681 UDF_FID_SIZE - frag_size);
682
683 /*
684 * Now that we have enough of the fid to work with,
685 * copy in the rest of the fid from the new
686 * allocation.
687 */
688 total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi;
689 if (total_fid_size > ds->ump->um_bsize) {
690 printf("udf: invalid FID\n");
691 ds->error = EIO;
692 return (NULL);
693 }
694 bcopy(ds->data, &ds->buf[frag_size],
695 total_fid_size - frag_size);
696
697 ds->fid_fragment = 1;
698 } else {
699 total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
700 }
701
702 /*
703 * Update the offset. Align on a 4 byte boundary because the
704 * UDF spec says so.
705 */
706 if (!ds->fid_fragment) {
707 ds->off += (total_fid_size + 3) & ~0x03;
708 } else {
709 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
710 }
711 ds->this_off = ds->offset + ds->off;
712
713 return (fid);
714 }
715
716 static void
udf_closedir(struct udf_dirstream * ds)717 udf_closedir(struct udf_dirstream *ds)
718 {
719
720 if (ds->bp != NULL) {
721 brelse(ds->bp);
722 ds->bp = NULL;
723 }
724
725 if (ds->fid_fragment && ds->buf != NULL)
726 free(ds->buf, M_UDFFID, 0);
727
728 pool_put(&udf_ds_pool, ds);
729 }
730
731 #define SELF_OFFSET 1
732 #define PARENT_OFFSET 2
733
734 int
udf_readdir(void * v)735 udf_readdir(void *v)
736 {
737 struct vop_readdir_args *ap = v;
738 struct vnode *vp;
739 struct uio *uio;
740 struct dirent dir;
741 struct unode *up;
742 struct umount *ump;
743 struct fileid_desc *fid;
744 struct udf_uiodir uiodir;
745 struct udf_dirstream *ds;
746 off_t last_off;
747 enum { MODE_NORMAL, MODE_SELF, MODE_PARENT } mode;
748 int error = 0;
749
750 vp = ap->a_vp;
751 uio = ap->a_uio;
752 up = VTOU(vp);
753 ump = up->u_ump;
754 uiodir.eofflag = 1;
755 uiodir.dirent = &dir;
756 memset(&dir, 0, sizeof(dir));
757
758 /*
759 * if asked to start at SELF_OFFSET or PARENT_OFFSET, search
760 * for the parent ref
761 */
762 if (uio->uio_offset == SELF_OFFSET) {
763 mode = MODE_SELF;
764 uio->uio_offset = 0;
765 } else if (uio->uio_offset == PARENT_OFFSET) {
766 mode = MODE_PARENT;
767 uio->uio_offset = 0;
768 } else
769 mode = MODE_NORMAL;
770
771 /*
772 * Iterate through the file id descriptors. Give the parent dir
773 * entry special attention.
774 */
775 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
776 up->u_ump->um_start += up->u_ump->um_meta_start;
777 up->u_ump->um_len = up->u_ump->um_meta_len;
778 }
779 ds = udf_opendir(up, uio->uio_offset,
780 letoh64(up->u_fentry->inf_len), up->u_ump);
781
782 last_off = ds->offset + ds->off;
783 while ((fid = udf_getfid(ds)) != NULL) {
784
785 /* Should we return an error on a bad fid? */
786 if (udf_checktag(&fid->tag, TAGID_FID)) {
787 printf("Invalid FID tag (%d)\n", fid->tag.id);
788 error = EIO;
789 break;
790 }
791
792 /* Is this a deleted file? */
793 if (fid->file_char & UDF_FILE_CHAR_DEL)
794 continue;
795
796 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
797 /* Do up the '.' and '..' entries. Dummy values are
798 * used for the offset since the offset here is
799 * usually zero, and NFS doesn't like that value
800 */
801 if (mode == MODE_NORMAL) {
802 dir.d_fileno = up->u_ino;
803 dir.d_type = DT_DIR;
804 dir.d_name[0] = '.';
805 dir.d_name[1] = '\0';
806 dir.d_namlen = 1;
807 error = udf_uiodir(&uiodir, uio, SELF_OFFSET);
808 if (error)
809 break;
810 }
811 if (mode != MODE_PARENT) {
812 dir.d_fileno = udf_getid(&fid->icb);
813 dir.d_type = DT_DIR;
814 dir.d_name[0] = '.';
815 dir.d_name[1] = '.';
816 dir.d_name[2] = '\0';
817 dir.d_namlen = 2;
818 error = udf_uiodir(&uiodir, uio, PARENT_OFFSET);
819 }
820 mode = MODE_NORMAL;
821 } else if (mode != MODE_NORMAL) {
822 continue;
823 } else {
824 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
825 &dir.d_name[0], fid->l_fi, ump);
826 dir.d_fileno = udf_getid(&fid->icb);
827 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
828 DT_DIR : DT_UNKNOWN;
829 error = udf_uiodir(&uiodir, uio, ds->this_off);
830 }
831 if (error) {
832 /*
833 * udf_uiodir() indicates there isn't space for
834 * another entry by returning -1
835 */
836 if (error == -1)
837 error = 0;
838 break;
839 }
840 last_off = ds->this_off;
841 }
842
843 /* tell the calling layer whether we need to be called again */
844 *ap->a_eofflag = uiodir.eofflag;
845 uio->uio_offset = last_off;
846
847 if (!error)
848 error = ds->error;
849
850 udf_closedir(ds);
851 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
852 up->u_ump->um_start = up->u_ump->um_realstart;
853 up->u_ump->um_len = up->u_ump->um_reallen;
854 }
855
856 return (error);
857 }
858
859 /* Are there any implementations out there that do soft-links? */
860 int
udf_readlink(void * v)861 udf_readlink(void *v)
862 {
863 return (EOPNOTSUPP);
864 }
865
866 int
udf_strategy(void * v)867 udf_strategy(void *v)
868 {
869 struct vop_strategy_args *ap = v;
870 struct buf *bp;
871 struct vnode *vp;
872 struct unode *up;
873 int maxsize, s, error;
874
875 bp = ap->a_bp;
876 vp = bp->b_vp;
877 up = VTOU(vp);
878
879 /* cd9660 has this test reversed, but it seems more logical this way */
880 if (bp->b_blkno != bp->b_lblkno) {
881 /*
882 * Files that are embedded in the fentry don't translate well
883 * to a block number. Reject.
884 */
885 if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize,
886 &bp->b_lblkno, &maxsize)) {
887 clrbuf(bp);
888 bp->b_blkno = -1;
889 }
890 } else {
891 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
892 if (error) {
893 bp->b_error = error;
894 bp->b_flags |= B_ERROR;
895 s = splbio();
896 biodone(bp);
897 splx(s);
898 return (error);
899 }
900
901 if ((long)bp->b_blkno == -1)
902 clrbuf(bp);
903 }
904
905 if ((long)bp->b_blkno == -1) {
906 s = splbio();
907 biodone(bp);
908 splx(s);
909 } else {
910 bp->b_dev = vp->v_rdev;
911 VOP_STRATEGY(up->u_devvp, bp);
912 }
913
914 return (0);
915 }
916
917 int
udf_lock(void * v)918 udf_lock(void *v)
919 {
920 struct vop_lock_args *ap = v;
921 struct vnode *vp = ap->a_vp;
922
923 return rrw_enter(&VTOU(vp)->u_lock, ap->a_flags & LK_RWFLAGS);
924 }
925
926 int
udf_unlock(void * v)927 udf_unlock(void *v)
928 {
929 struct vop_unlock_args *ap = v;
930 struct vnode *vp = ap->a_vp;
931
932 rrw_exit(&VTOU(vp)->u_lock);
933 return 0;
934 }
935
936 int
udf_islocked(void * v)937 udf_islocked(void *v)
938 {
939 struct vop_islocked_args *ap = v;
940
941 return rrw_status(&VTOU(ap->a_vp)->u_lock);
942 }
943
944 int
udf_print(void * v)945 udf_print(void *v)
946 {
947 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG)
948 struct vop_print_args *ap = v;
949 struct vnode *vp = ap->a_vp;
950 struct unode *up = VTOU(vp);
951
952 /*
953 * Complete the information given by vprint().
954 */
955 printf("tag VT_UDF, hash id %u\n", up->u_ino);
956 #ifdef DIAGNOSTIC
957 printf("\n");
958 #endif
959 #endif
960 return (0);
961 }
962
963 int
udf_bmap(void * v)964 udf_bmap(void *v)
965 {
966 struct vop_bmap_args *ap = v;
967 struct unode *up;
968 uint32_t max_size;
969 daddr_t lsector;
970 int error;
971
972 up = VTOU(ap->a_vp);
973
974 if (ap->a_vpp != NULL)
975 *ap->a_vpp = up->u_devvp;
976 if (ap->a_bnp == NULL)
977 return (0);
978
979 error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize,
980 &lsector, &max_size);
981 if (error)
982 return (error);
983
984 /* Translate logical to physical sector number */
985 *ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT);
986
987 /* Punt on read-ahead for now */
988 if (ap->a_runp)
989 *ap->a_runp = 0;
990
991 return (0);
992 }
993
994 /*
995 * The all powerful VOP_LOOKUP().
996 */
997 int
udf_lookup(void * v)998 udf_lookup(void *v)
999 {
1000 struct vop_lookup_args *ap = v;
1001 struct vnode *dvp;
1002 struct vnode *tdp = NULL;
1003 struct vnode **vpp = ap->a_vpp;
1004 struct unode *up;
1005 struct umount *ump;
1006 struct fileid_desc *fid = NULL;
1007 struct udf_dirstream *ds;
1008 struct proc *p;
1009 u_long nameiop;
1010 u_long flags;
1011 char *nameptr;
1012 long namelen;
1013 udfino_t id = 0;
1014 int offset, error = 0;
1015 int numdirpasses, fsize;
1016
1017 extern struct nchstats nchstats;
1018
1019 dvp = ap->a_dvp;
1020 up = VTOU(dvp);
1021 ump = up->u_ump;
1022 nameiop = ap->a_cnp->cn_nameiop;
1023 flags = ap->a_cnp->cn_flags;
1024 nameptr = ap->a_cnp->cn_nameptr;
1025 namelen = ap->a_cnp->cn_namelen;
1026 fsize = letoh64(up->u_fentry->inf_len);
1027 p = ap->a_cnp->cn_proc;
1028 *vpp = NULL;
1029
1030 /*
1031 * Make sure the process can scan the requested directory.
1032 */
1033 error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p);
1034 if (error)
1035 return (error);
1036
1037 /*
1038 * Check if the (directory, name) tuple has been already cached.
1039 */
1040 error = cache_lookup(dvp, vpp, ap->a_cnp);
1041 if (error >= 0)
1042 return (error);
1043 else
1044 error = 0;
1045
1046 /*
1047 * If dvp is what's being looked up, then return it.
1048 */
1049 if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') {
1050 vref(dvp);
1051 *vpp = dvp;
1052 return (0);
1053 }
1054
1055 /*
1056 * If this is a LOOKUP and we've already partially searched through
1057 * the directory, pick up where we left off and flag that the
1058 * directory may need to be searched twice. For a full description,
1059 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
1060 */
1061 if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) {
1062 offset = 0;
1063 numdirpasses = 1;
1064 } else {
1065 offset = up->u_diroff;
1066 numdirpasses = 2;
1067 nchstats.ncs_2passes++;
1068 }
1069
1070 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1071 up->u_ump->um_start += up->u_ump->um_meta_start;
1072 up->u_ump->um_len = up->u_ump->um_meta_len;
1073 }
1074 lookloop:
1075 ds = udf_opendir(up, offset, fsize, ump);
1076
1077 while ((fid = udf_getfid(ds)) != NULL) {
1078 /* Check for a valid FID tag. */
1079 if (udf_checktag(&fid->tag, TAGID_FID)) {
1080 printf("udf_lookup: Invalid tag\n");
1081 error = EIO;
1082 break;
1083 }
1084
1085 /* Is this a deleted file? */
1086 if (fid->file_char & UDF_FILE_CHAR_DEL)
1087 continue;
1088
1089 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
1090 if (flags & ISDOTDOT) {
1091 id = udf_getid(&fid->icb);
1092 break;
1093 }
1094 } else {
1095 if (!(udf_cmpname(&fid->data[fid->l_iu],
1096 nameptr, fid->l_fi, namelen, ump))) {
1097 id = udf_getid(&fid->icb);
1098 break;
1099 }
1100 }
1101 }
1102
1103 if (!error)
1104 error = ds->error;
1105
1106 if (error) {
1107 udf_closedir(ds);
1108 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1109 up->u_ump->um_start = up->u_ump->um_realstart;
1110 up->u_ump->um_len = up->u_ump->um_reallen;
1111 }
1112 return (error);
1113 }
1114
1115 /* Did we have a match? */
1116 if (id) {
1117 error = udf_vget(ump->um_mountp, id, &tdp);
1118 if (!error) {
1119 /*
1120 * Remember where this entry was if it's the final
1121 * component.
1122 */
1123 if ((flags & ISLASTCN) && nameiop == LOOKUP)
1124 up->u_diroff = ds->offset + ds->off;
1125 if (numdirpasses == 2)
1126 nchstats.ncs_pass2++;
1127 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
1128 ap->a_cnp->cn_flags |= PDIRUNLOCK;
1129 VOP_UNLOCK(dvp);
1130 }
1131
1132 *vpp = tdp;
1133 }
1134 } else {
1135 /* Name wasn't found on this pass. Do another pass? */
1136 if (numdirpasses == 2) {
1137 numdirpasses--;
1138 offset = 0;
1139 udf_closedir(ds);
1140 goto lookloop;
1141 }
1142
1143 if ((flags & ISLASTCN) &&
1144 (nameiop == CREATE || nameiop == RENAME)) {
1145 error = EROFS;
1146 } else {
1147 error = ENOENT;
1148 }
1149 }
1150
1151 /*
1152 * Cache the result of this lookup.
1153 */
1154 if (flags & MAKEENTRY)
1155 cache_enter(dvp, *vpp, ap->a_cnp);
1156
1157 udf_closedir(ds);
1158 if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1159 up->u_ump->um_start = up->u_ump->um_realstart;
1160 up->u_ump->um_len = up->u_ump->um_reallen;
1161 }
1162
1163 return (error);
1164 }
1165
1166 int
udf_inactive(void * v)1167 udf_inactive(void *v)
1168 {
1169 struct vop_inactive_args *ap = v;
1170 struct vnode *vp = ap->a_vp;
1171
1172 /*
1173 * No need to sync anything, so just unlock the vnode and return.
1174 */
1175 VOP_UNLOCK(vp);
1176
1177 return (0);
1178 }
1179
1180 int
udf_reclaim(void * v)1181 udf_reclaim(void *v)
1182 {
1183 struct vop_reclaim_args *ap = v;
1184 struct vnode *vp;
1185 struct unode *up;
1186
1187 vp = ap->a_vp;
1188 up = VTOU(vp);
1189
1190 if (up != NULL) {
1191 udf_hashrem(up);
1192 if (up->u_devvp) {
1193 vrele(up->u_devvp);
1194 up->u_devvp = 0;
1195 }
1196
1197 if (up->u_fentry != NULL)
1198 free(up->u_fentry, M_UDFFENTRY, 0);
1199
1200 pool_put(&unode_pool, up);
1201 vp->v_data = NULL;
1202 }
1203
1204 return (0);
1205 }
1206
1207 /*
1208 * Read the block and then set the data pointer to correspond with the
1209 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
1210 * to the number of bytes pointed to. If 'size' is zero, try to read in a
1211 * whole extent.
1212 *
1213 * Note that *bp may be assigned error or not.
1214 *
1215 */
1216 int
udf_readatoffset(struct unode * up,int * size,off_t offset,struct buf ** bp,uint8_t ** data)1217 udf_readatoffset(struct unode *up, int *size, off_t offset,
1218 struct buf **bp, uint8_t **data)
1219 {
1220 struct umount *ump;
1221 struct extfile_entry *xfentry = NULL;
1222 struct file_entry *fentry = NULL;
1223 struct buf *bp1;
1224 uint32_t max_size;
1225 daddr_t sector;
1226 int error;
1227
1228 ump = up->u_ump;
1229
1230 *bp = NULL;
1231 error = udf_bmap_internal(up, offset, §or, &max_size);
1232 if (error == UDF_INVALID_BMAP) {
1233 /*
1234 * This error means that the file *data* is stored in the
1235 * allocation descriptor field of the file entry.
1236 */
1237 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) {
1238 xfentry = up->u_fentry;
1239 *data = &xfentry->data[letoh32(xfentry->l_ea)];
1240 *size = letoh32(xfentry->l_ad);
1241 } else {
1242 fentry = (struct file_entry *)up->u_fentry;
1243 *data = &fentry->data[letoh32(fentry->l_ea)];
1244 *size = letoh32(fentry->l_ad);
1245 }
1246 return (0);
1247 } else if (error != 0) {
1248 return (error);
1249 }
1250
1251 /* Adjust the size so that it is within range */
1252 if (*size == 0 || *size > max_size)
1253 *size = max_size;
1254 *size = min(*size, MAXBSIZE);
1255
1256 if ((error = udf_readlblks(ump, sector, *size, bp))) {
1257 printf("warning: udf_readlblks returned error %d\n", error);
1258 /* note: *bp may be non-NULL */
1259 return (error);
1260 }
1261
1262 bp1 = *bp;
1263 *data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize];
1264 return (0);
1265 }
1266
1267 /*
1268 * Translate a file offset into a logical block and then into a physical
1269 * block.
1270 */
1271 int
udf_bmap_internal(struct unode * up,off_t offset,daddr_t * sector,uint32_t * max_size)1272 udf_bmap_internal(struct unode *up, off_t offset, daddr_t *sector,
1273 uint32_t *max_size)
1274 {
1275 struct umount *ump;
1276 struct extfile_entry *xfentry;
1277 struct file_entry *fentry;
1278 void *icb;
1279 struct icb_tag *tag;
1280 uint32_t icblen = 0;
1281 daddr_t lsector;
1282 int ad_offset, ad_num = 0;
1283 int i, p_offset, l_ea, l_ad;
1284
1285 ump = up->u_ump;
1286 xfentry = up->u_fentry;
1287 fentry = (struct file_entry *)up->u_fentry;
1288 tag = &fentry->icbtag;
1289 if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) {
1290 l_ea = letoh32(xfentry->l_ea);
1291 l_ad = letoh32(xfentry->l_ad);
1292 } else {
1293 l_ea = letoh32(fentry->l_ea);
1294 l_ad = letoh32(fentry->l_ad);
1295 }
1296
1297 switch (letoh16(tag->strat_type)) {
1298 case 4:
1299 break;
1300
1301 case 4096:
1302 printf("Cannot deal with strategy4096 yet!\n");
1303 return (ENODEV);
1304
1305 default:
1306 printf("Unknown strategy type %d\n", tag->strat_type);
1307 return (ENODEV);
1308 }
1309
1310 switch (letoh16(tag->flags) & 0x7) {
1311 case 0:
1312 /*
1313 * The allocation descriptor field is filled with short_ad's.
1314 * If the offset is beyond the current extent, look for the
1315 * next extent.
1316 */
1317 do {
1318 offset -= icblen;
1319 ad_offset = sizeof(struct short_ad) * ad_num;
1320 if (ad_offset > l_ad) {
1321 printf("SFile offset out of bounds (%d > %d)\n",
1322 ad_offset, l_ad);
1323 return (EINVAL);
1324 }
1325
1326 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0)
1327 icb = GETICB(short_ad, xfentry, l_ea + ad_offset);
1328 else
1329 icb = GETICB(short_ad, fentry, l_ea + ad_offset);
1330
1331 icblen = GETICBLEN(short_ad, icb);
1332 ad_num++;
1333 } while(offset >= icblen);
1334
1335 lsector = (offset >> ump->um_bshift) +
1336 letoh32(((struct short_ad *)(icb))->lb_num);
1337
1338 *max_size = GETICBLEN(short_ad, icb);
1339
1340 break;
1341 case 1:
1342 /*
1343 * The allocation descriptor field is filled with long_ad's
1344 * If the offset is beyond the current extent, look for the
1345 * next extent.
1346 */
1347 do {
1348 offset -= icblen;
1349 ad_offset = sizeof(struct long_ad) * ad_num;
1350 if (ad_offset > l_ad) {
1351 printf("LFile offset out of bounds (%d > %d)\n",
1352 ad_offset, l_ad);
1353 return (EINVAL);
1354 }
1355 if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0)
1356 icb = GETICB(long_ad, xfentry, l_ea + ad_offset);
1357 else
1358 icb = GETICB(long_ad, fentry, l_ea + ad_offset);
1359 icblen = GETICBLEN(long_ad, icb);
1360 ad_num++;
1361 } while(offset >= icblen);
1362
1363 lsector = (offset >> ump->um_bshift) +
1364 letoh32(((struct long_ad *)(icb))->loc.lb_num);
1365
1366 *max_size = GETICBLEN(long_ad, icb);
1367
1368 break;
1369 case 3:
1370 /*
1371 * This type means that the file *data* is stored in the
1372 * allocation descriptor field of the file entry.
1373 */
1374 *max_size = 0;
1375 *sector = up->u_ino + ump->um_start;
1376
1377 return (UDF_INVALID_BMAP);
1378 case 2:
1379 /* DirectCD does not use extended_ad's */
1380 default:
1381 printf("Unsupported allocation descriptor %d\n",
1382 tag->flags & 0x7);
1383 return (ENODEV);
1384 }
1385
1386 *sector = lsector + ump->um_start;
1387
1388 /*
1389 * Check the sparing table. Each entry represents the beginning of
1390 * a packet.
1391 */
1392 if (ump->um_stbl != NULL) {
1393 for (i = 0; i< ump->um_stbl_len; i++) {
1394 p_offset =
1395 lsector - letoh32(ump->um_stbl->entries[i].org);
1396 if ((p_offset < ump->um_psecs) && (p_offset >= 0)) {
1397 *sector =
1398 letoh32(ump->um_stbl->entries[i].map) +
1399 p_offset;
1400 break;
1401 }
1402 }
1403 }
1404
1405 return (0);
1406 }
1407