FreeBSD/Linux Kernel Cross Reference
sys/fs/udf/udf_vnops.c
1 /*-
2 * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/9.0/sys/fs/udf/udf_vnops.c 209425 2010-06-22 08:22:25Z avg $
27 */
28
29 /* udf_vnops.c */
30 /* Take care of the vnode side of things */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/namei.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/stat.h>
38 #include <sys/bio.h>
39 #include <sys/conf.h>
40 #include <sys/buf.h>
41 #include <sys/iconv.h>
42 #include <sys/mount.h>
43 #include <sys/vnode.h>
44 #include <sys/dirent.h>
45 #include <sys/queue.h>
46 #include <sys/unistd.h>
47 #include <sys/endian.h>
48
49 #include <vm/uma.h>
50
51 #include <fs/fifofs/fifo.h>
52 #include <fs/udf/ecma167-udf.h>
53 #include <fs/udf/osta.h>
54 #include <fs/udf/udf.h>
55 #include <fs/udf/udf_mount.h>
56
57 extern struct iconv_functions *udf_iconv;
58
59 static vop_access_t udf_access;
60 static vop_getattr_t udf_getattr;
61 static vop_open_t udf_open;
62 static vop_ioctl_t udf_ioctl;
63 static vop_pathconf_t udf_pathconf;
64 static vop_print_t udf_print;
65 static vop_read_t udf_read;
66 static vop_readdir_t udf_readdir;
67 static vop_readlink_t udf_readlink;
68 static vop_setattr_t udf_setattr;
69 static vop_strategy_t udf_strategy;
70 static vop_bmap_t udf_bmap;
71 static vop_cachedlookup_t udf_lookup;
72 static vop_reclaim_t udf_reclaim;
73 static vop_vptofh_t udf_vptofh;
74 static int udf_readatoffset(struct udf_node *node, int *size, off_t offset,
75 struct buf **bp, uint8_t **data);
76 static int udf_bmap_internal(struct udf_node *node, off_t offset,
77 daddr_t *sector, uint32_t *max_size);
78
79 static struct vop_vector udf_vnodeops = {
80 .vop_default = &default_vnodeops,
81
82 .vop_access = udf_access,
83 .vop_bmap = udf_bmap,
84 .vop_cachedlookup = udf_lookup,
85 .vop_getattr = udf_getattr,
86 .vop_ioctl = udf_ioctl,
87 .vop_lookup = vfs_cache_lookup,
88 .vop_open = udf_open,
89 .vop_pathconf = udf_pathconf,
90 .vop_print = udf_print,
91 .vop_read = udf_read,
92 .vop_readdir = udf_readdir,
93 .vop_readlink = udf_readlink,
94 .vop_reclaim = udf_reclaim,
95 .vop_setattr = udf_setattr,
96 .vop_strategy = udf_strategy,
97 .vop_vptofh = udf_vptofh,
98 };
99
100 struct vop_vector udf_fifoops = {
101 .vop_default = &fifo_specops,
102 .vop_access = udf_access,
103 .vop_getattr = udf_getattr,
104 .vop_print = udf_print,
105 .vop_reclaim = udf_reclaim,
106 .vop_setattr = udf_setattr,
107 .vop_vptofh = udf_vptofh,
108 };
109
110 MALLOC_DEFINE(M_UDFFID, "udf_fid", "UDF FileId structure");
111 MALLOC_DEFINE(M_UDFDS, "udf_ds", "UDF Dirstream structure");
112
113 #define UDF_INVALID_BMAP -1
114
115 int
116 udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
117 {
118 int error;
119 struct vnode *vp;
120
121 error = getnewvnode("udf", mp, &udf_vnodeops, &vp);
122 if (error) {
123 printf("udf_allocv: failed to allocate new vnode\n");
124 return (error);
125 }
126
127 *vpp = vp;
128 return (0);
129 }
130
131 /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
132 static mode_t
133 udf_permtomode(struct udf_node *node)
134 {
135 uint32_t perm;
136 uint16_t flags;
137 mode_t mode;
138
139 perm = le32toh(node->fentry->perm);
140 flags = le16toh(node->fentry->icbtag.flags);
141
142 mode = perm & UDF_FENTRY_PERM_USER_MASK;
143 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
144 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
145 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
146 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
147 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
148
149 return (mode);
150 }
151
152 static int
153 udf_access(struct vop_access_args *a)
154 {
155 struct vnode *vp;
156 struct udf_node *node;
157 accmode_t accmode;
158 mode_t mode;
159
160 vp = a->a_vp;
161 node = VTON(vp);
162 accmode = a->a_accmode;
163
164 if (accmode & VWRITE) {
165 switch (vp->v_type) {
166 case VDIR:
167 case VLNK:
168 case VREG:
169 return (EROFS);
170 /* NOT REACHED */
171 default:
172 break;
173 }
174 }
175
176 mode = udf_permtomode(node);
177
178 return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
179 accmode, a->a_cred, NULL));
180 }
181
182 static int
183 udf_open(struct vop_open_args *ap) {
184 struct udf_node *np = VTON(ap->a_vp);
185 off_t fsize;
186
187 fsize = le64toh(np->fentry->inf_len);
188 vnode_create_vobject(ap->a_vp, fsize, ap->a_td);
189 return 0;
190 }
191
192 static const int mon_lens[2][12] = {
193 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
194 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
195 };
196
197 static int
198 udf_isaleapyear(int year)
199 {
200 int i;
201
202 i = (year % 4) ? 0 : 1;
203 i &= (year % 100) ? 1 : 0;
204 i |= (year % 400) ? 0 : 1;
205
206 return i;
207 }
208
209 /*
210 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
211 */
212 static void
213 udf_timetotimespec(struct timestamp *time, struct timespec *t)
214 {
215 int i, lpyear, daysinyear, year, startyear;
216 union {
217 uint16_t u_tz_offset;
218 int16_t s_tz_offset;
219 } tz;
220
221 /*
222 * DirectCD seems to like using bogus year values.
223 * Don't trust time->month as it will be used for an array index.
224 */
225 year = le16toh(time->year);
226 if (year < 1970 || time->month < 1 || time->month > 12) {
227 t->tv_sec = 0;
228 t->tv_nsec = 0;
229 return;
230 }
231
232 /* Calculate the time and day */
233 t->tv_sec = time->second;
234 t->tv_sec += time->minute * 60;
235 t->tv_sec += time->hour * 3600;
236 t->tv_sec += (time->day - 1) * 3600 * 24;
237
238 /* Calculate the month */
239 lpyear = udf_isaleapyear(year);
240 t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24;
241
242 /* Speed up the calculation */
243 startyear = 1970;
244 if (year > 2009) {
245 t->tv_sec += 1262304000;
246 startyear += 40;
247 } else if (year > 1999) {
248 t->tv_sec += 946684800;
249 startyear += 30;
250 } else if (year > 1989) {
251 t->tv_sec += 631152000;
252 startyear += 20;
253 } else if (year > 1979) {
254 t->tv_sec += 315532800;
255 startyear += 10;
256 }
257
258 daysinyear = (year - startyear) * 365;
259 for (i = startyear; i < year; i++)
260 daysinyear += udf_isaleapyear(i);
261 t->tv_sec += daysinyear * 3600 * 24;
262
263 /* Calculate microseconds */
264 t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 +
265 time->usec;
266
267 /*
268 * Calculate the time zone. The timezone is 12 bit signed 2's
269 * complement, so we gotta do some extra magic to handle it right.
270 */
271 tz.u_tz_offset = le16toh(time->type_tz);
272 tz.u_tz_offset &= 0x0fff;
273 if (tz.u_tz_offset & 0x0800)
274 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
275 if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047))
276 t->tv_sec -= tz.s_tz_offset * 60;
277
278 return;
279 }
280
281 static int
282 udf_getattr(struct vop_getattr_args *a)
283 {
284 struct vnode *vp;
285 struct udf_node *node;
286 struct vattr *vap;
287 struct file_entry *fentry;
288 struct timespec ts;
289
290 ts.tv_sec = 0;
291
292 vp = a->a_vp;
293 vap = a->a_vap;
294 node = VTON(vp);
295 fentry = node->fentry;
296
297 vap->va_fsid = dev2udev(node->udfmp->im_dev);
298 vap->va_fileid = node->hash_id;
299 vap->va_mode = udf_permtomode(node);
300 vap->va_nlink = le16toh(fentry->link_cnt);
301 /*
302 * XXX The spec says that -1 is valid for uid/gid and indicates an
303 * invalid uid/gid. How should this be represented?
304 */
305 vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid);
306 vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid);
307 udf_timetotimespec(&fentry->atime, &vap->va_atime);
308 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
309 vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
310 vap->va_rdev = NODEV;
311 if (vp->v_type & VDIR) {
312 /*
313 * Directories that are recorded within their ICB will show
314 * as having 0 blocks recorded. Since tradition dictates
315 * that directories consume at least one logical block,
316 * make it appear so.
317 */
318 if (fentry->logblks_rec != 0) {
319 vap->va_size =
320 le64toh(fentry->logblks_rec) * node->udfmp->bsize;
321 } else {
322 vap->va_size = node->udfmp->bsize;
323 }
324 } else {
325 vap->va_size = le64toh(fentry->inf_len);
326 }
327 vap->va_flags = 0;
328 vap->va_gen = 1;
329 vap->va_blocksize = node->udfmp->bsize;
330 vap->va_bytes = le64toh(fentry->inf_len);
331 vap->va_type = vp->v_type;
332 vap->va_filerev = 0; /* XXX */
333 return (0);
334 }
335
336 static int
337 udf_setattr(struct vop_setattr_args *a)
338 {
339 struct vnode *vp;
340 struct vattr *vap;
341
342 vp = a->a_vp;
343 vap = a->a_vap;
344 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
345 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
346 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
347 return (EROFS);
348 if (vap->va_size != (u_quad_t)VNOVAL) {
349 switch (vp->v_type) {
350 case VDIR:
351 return (EISDIR);
352 case VLNK:
353 case VREG:
354 return (EROFS);
355 case VCHR:
356 case VBLK:
357 case VSOCK:
358 case VFIFO:
359 case VNON:
360 case VBAD:
361 case VMARKER:
362 return (0);
363 }
364 }
365 return (0);
366 }
367
368 /*
369 * File specific ioctls.
370 */
371 static int
372 udf_ioctl(struct vop_ioctl_args *a)
373 {
374 printf("%s called\n", __func__);
375 return (ENOTTY);
376 }
377
378 /*
379 * I'm not sure that this has much value in a read-only filesystem, but
380 * cd9660 has it too.
381 */
382 static int
383 udf_pathconf(struct vop_pathconf_args *a)
384 {
385
386 switch (a->a_name) {
387 case _PC_LINK_MAX:
388 *a->a_retval = 65535;
389 return (0);
390 case _PC_NAME_MAX:
391 *a->a_retval = NAME_MAX;
392 return (0);
393 case _PC_PATH_MAX:
394 *a->a_retval = PATH_MAX;
395 return (0);
396 case _PC_NO_TRUNC:
397 *a->a_retval = 1;
398 return (0);
399 default:
400 return (EINVAL);
401 }
402 }
403
404 static int
405 udf_print(struct vop_print_args *ap)
406 {
407 struct vnode *vp = ap->a_vp;
408 struct udf_node *node = VTON(vp);
409
410 printf(" ino %lu, on dev %s", (u_long)node->hash_id,
411 devtoname(node->udfmp->im_dev));
412 if (vp->v_type == VFIFO)
413 fifo_printinfo(vp);
414 printf("\n");
415 return (0);
416 }
417
418 #define lblkno(udfmp, loc) ((loc) >> (udfmp)->bshift)
419 #define blkoff(udfmp, loc) ((loc) & (udfmp)->bmask)
420 #define lblktosize(udfmp, blk) ((blk) << (udfmp)->bshift)
421
422 static inline int
423 is_data_in_fentry(const struct udf_node *node)
424 {
425 const struct file_entry *fentry = node->fentry;
426
427 return ((le16toh(fentry->icbtag.flags) & 0x7) == 3);
428 }
429
430 static int
431 udf_read(struct vop_read_args *ap)
432 {
433 struct vnode *vp = ap->a_vp;
434 struct uio *uio = ap->a_uio;
435 struct udf_node *node = VTON(vp);
436 struct udf_mnt *udfmp;
437 struct file_entry *fentry;
438 struct buf *bp;
439 uint8_t *data;
440 daddr_t lbn, rablock;
441 off_t diff, fsize;
442 int error = 0;
443 long size, n, on;
444
445 if (uio->uio_resid == 0)
446 return (0);
447 if (uio->uio_offset < 0)
448 return (EINVAL);
449
450 if (is_data_in_fentry(node)) {
451 fentry = node->fentry;
452 data = &fentry->data[le32toh(fentry->l_ea)];
453 fsize = le32toh(fentry->l_ad);
454
455 n = uio->uio_resid;
456 diff = fsize - uio->uio_offset;
457 if (diff <= 0)
458 return (0);
459 if (diff < n)
460 n = diff;
461 error = uiomove(data + uio->uio_offset, (int)n, uio);
462 return (error);
463 }
464
465 fsize = le64toh(node->fentry->inf_len);
466 udfmp = node->udfmp;
467 do {
468 lbn = lblkno(udfmp, uio->uio_offset);
469 on = blkoff(udfmp, uio->uio_offset);
470 n = min((u_int)(udfmp->bsize - on),
471 uio->uio_resid);
472 diff = fsize - uio->uio_offset;
473 if (diff <= 0)
474 return (0);
475 if (diff < n)
476 n = diff;
477 size = udfmp->bsize;
478 rablock = lbn + 1;
479 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
480 if (lblktosize(udfmp, rablock) < fsize) {
481 error = cluster_read(vp, fsize, lbn, size, NOCRED,
482 uio->uio_resid, (ap->a_ioflag >> 16), &bp);
483 } else {
484 error = bread(vp, lbn, size, NOCRED, &bp);
485 }
486 } else {
487 error = bread(vp, lbn, size, NOCRED, &bp);
488 }
489 n = min(n, size - bp->b_resid);
490 if (error) {
491 brelse(bp);
492 return (error);
493 }
494
495 error = uiomove(bp->b_data + on, (int)n, uio);
496 brelse(bp);
497 } while (error == 0 && uio->uio_resid > 0 && n != 0);
498 return (error);
499 }
500
501 /*
502 * Call the OSTA routines to translate the name from a CS0 dstring to a
503 * 16-bit Unicode String. Hooks need to be placed in here to translate from
504 * Unicode to the encoding that the kernel/user expects. Return the length
505 * of the translated string.
506 */
507 static int
508 udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
509 {
510 unicode_t *transname;
511 char *unibuf, *unip;
512 int i, destlen;
513 ssize_t unilen = 0;
514 size_t destleft = MAXNAMLEN;
515
516 /* Convert 16-bit Unicode to destname */
517 if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
518 /* allocate a buffer big enough to hold an 8->16 bit expansion */
519 unibuf = uma_zalloc(udf_zone_trans, M_WAITOK);
520 unip = unibuf;
521 if ((unilen = (ssize_t)udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) {
522 printf("udf: Unicode translation failed\n");
523 uma_zfree(udf_zone_trans, unibuf);
524 return 0;
525 }
526
527 while (unilen > 0 && destleft > 0) {
528 udf_iconv->conv(udfmp->im_d2l, (const char **)&unibuf,
529 (size_t *)&unilen, (char **)&destname, &destleft);
530 /* Unconverted character found */
531 if (unilen > 0 && destleft > 0) {
532 *destname++ = '?';
533 destleft--;
534 unibuf += 2;
535 unilen -= 2;
536 }
537 }
538 uma_zfree(udf_zone_trans, unip);
539 *destname = '\0';
540 destlen = MAXNAMLEN - (int)destleft;
541 } else {
542 /* allocate a buffer big enough to hold an 8->16 bit expansion */
543 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
544
545 if ((unilen = (ssize_t)udf_UncompressUnicode(len, cs0string, transname)) == -1) {
546 printf("udf: Unicode translation failed\n");
547 uma_zfree(udf_zone_trans, transname);
548 return 0;
549 }
550
551 for (i = 0; i < unilen ; i++) {
552 if (transname[i] & 0xff00) {
553 destname[i] = '.'; /* Fudge the 16bit chars */
554 } else {
555 destname[i] = transname[i] & 0xff;
556 }
557 }
558 uma_zfree(udf_zone_trans, transname);
559 destname[unilen] = 0;
560 destlen = (int)unilen;
561 }
562
563 return (destlen);
564 }
565
566 /*
567 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
568 * 0 on a successful match, nonzero otherwise. Unicode work may need to be done
569 * here also.
570 */
571 static int
572 udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
573 {
574 char *transname;
575 int error = 0;
576
577 /* This is overkill, but not worth creating a new zone */
578 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
579
580 cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
581
582 /* Easy check. If they aren't the same length, they aren't equal */
583 if ((cs0len == 0) || (cs0len != cmplen))
584 error = -1;
585 else
586 error = bcmp(transname, cmpname, cmplen);
587
588 uma_zfree(udf_zone_trans, transname);
589 return (error);
590 }
591
592 struct udf_uiodir {
593 struct dirent *dirent;
594 u_long *cookies;
595 int ncookies;
596 int acookies;
597 int eofflag;
598 };
599
600 static int
601 udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
602 {
603 if (uiodir->cookies != NULL) {
604 if (++uiodir->acookies > uiodir->ncookies) {
605 uiodir->eofflag = 0;
606 return (-1);
607 }
608 *uiodir->cookies++ = cookie;
609 }
610
611 if (uio->uio_resid < de_size) {
612 uiodir->eofflag = 0;
613 return (-1);
614 }
615
616 return (uiomove(uiodir->dirent, de_size, uio));
617 }
618
619 static struct udf_dirstream *
620 udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
621 {
622 struct udf_dirstream *ds;
623
624 ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
625
626 ds->node = node;
627 ds->offset = offset;
628 ds->udfmp = udfmp;
629 ds->fsize = fsize;
630
631 return (ds);
632 }
633
634 static struct fileid_desc *
635 udf_getfid(struct udf_dirstream *ds)
636 {
637 struct fileid_desc *fid;
638 int error, frag_size = 0, total_fid_size;
639
640 /* End of directory? */
641 if (ds->offset + ds->off >= ds->fsize) {
642 ds->error = 0;
643 return (NULL);
644 }
645
646 /* Grab the first extent of the directory */
647 if (ds->off == 0) {
648 ds->size = 0;
649 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
650 &ds->bp, &ds->data);
651 if (error) {
652 ds->error = error;
653 if (ds->bp != NULL)
654 brelse(ds->bp);
655 return (NULL);
656 }
657 }
658
659 /*
660 * Clean up from a previous fragmented FID.
661 * XXX Is this the right place for this?
662 */
663 if (ds->fid_fragment && ds->buf != NULL) {
664 ds->fid_fragment = 0;
665 free(ds->buf, M_UDFFID);
666 }
667
668 fid = (struct fileid_desc*)&ds->data[ds->off];
669
670 /*
671 * Check to see if the fid is fragmented. The first test
672 * ensures that we don't wander off the end of the buffer
673 * looking for the l_iu and l_fi fields.
674 */
675 if (ds->off + UDF_FID_SIZE > ds->size ||
676 ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
677
678 /* Copy what we have of the fid into a buffer */
679 frag_size = ds->size - ds->off;
680 if (frag_size >= ds->udfmp->bsize) {
681 printf("udf: invalid FID fragment\n");
682 ds->error = EINVAL;
683 return (NULL);
684 }
685
686 /*
687 * File ID descriptors can only be at most one
688 * logical sector in size.
689 */
690 ds->buf = malloc(ds->udfmp->bsize, M_UDFFID,
691 M_WAITOK | M_ZERO);
692 bcopy(fid, ds->buf, frag_size);
693
694 /* Reduce all of the casting magic */
695 fid = (struct fileid_desc*)ds->buf;
696
697 if (ds->bp != NULL)
698 brelse(ds->bp);
699
700 /* Fetch the next allocation */
701 ds->offset += ds->size;
702 ds->size = 0;
703 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
704 &ds->bp, &ds->data);
705 if (error) {
706 ds->error = error;
707 return (NULL);
708 }
709
710 /*
711 * If the fragment was so small that we didn't get
712 * the l_iu and l_fi fields, copy those in.
713 */
714 if (frag_size < UDF_FID_SIZE)
715 bcopy(ds->data, &ds->buf[frag_size],
716 UDF_FID_SIZE - frag_size);
717
718 /*
719 * Now that we have enough of the fid to work with,
720 * copy in the rest of the fid from the new
721 * allocation.
722 */
723 total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi;
724 if (total_fid_size > ds->udfmp->bsize) {
725 printf("udf: invalid FID\n");
726 ds->error = EIO;
727 return (NULL);
728 }
729 bcopy(ds->data, &ds->buf[frag_size],
730 total_fid_size - frag_size);
731
732 ds->fid_fragment = 1;
733 } else {
734 total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
735 }
736
737 /*
738 * Update the offset. Align on a 4 byte boundary because the
739 * UDF spec says so.
740 */
741 ds->this_off = ds->offset + ds->off;
742 if (!ds->fid_fragment) {
743 ds->off += (total_fid_size + 3) & ~0x03;
744 } else {
745 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
746 }
747
748 return (fid);
749 }
750
751 static void
752 udf_closedir(struct udf_dirstream *ds)
753 {
754
755 if (ds->bp != NULL)
756 brelse(ds->bp);
757
758 if (ds->fid_fragment && ds->buf != NULL)
759 free(ds->buf, M_UDFFID);
760
761 uma_zfree(udf_zone_ds, ds);
762 }
763
764 static int
765 udf_readdir(struct vop_readdir_args *a)
766 {
767 struct vnode *vp;
768 struct uio *uio;
769 struct dirent dir;
770 struct udf_node *node;
771 struct udf_mnt *udfmp;
772 struct fileid_desc *fid;
773 struct udf_uiodir uiodir;
774 struct udf_dirstream *ds;
775 u_long *cookies = NULL;
776 int ncookies;
777 int error = 0;
778
779 vp = a->a_vp;
780 uio = a->a_uio;
781 node = VTON(vp);
782 udfmp = node->udfmp;
783 uiodir.eofflag = 1;
784
785 if (a->a_ncookies != NULL) {
786 /*
787 * Guess how many entries are needed. If we run out, this
788 * function will be called again and thing will pick up were
789 * it left off.
790 */
791 ncookies = uio->uio_resid / 8;
792 cookies = malloc(sizeof(u_long) * ncookies,
793 M_TEMP, M_WAITOK);
794 if (cookies == NULL)
795 return (ENOMEM);
796 uiodir.ncookies = ncookies;
797 uiodir.cookies = cookies;
798 uiodir.acookies = 0;
799 } else {
800 uiodir.cookies = NULL;
801 }
802
803 /*
804 * Iterate through the file id descriptors. Give the parent dir
805 * entry special attention.
806 */
807 ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
808 node->udfmp);
809
810 while ((fid = udf_getfid(ds)) != NULL) {
811
812 /* XXX Should we return an error on a bad fid? */
813 if (udf_checktag(&fid->tag, TAGID_FID)) {
814 printf("Invalid FID tag\n");
815 hexdump(fid, UDF_FID_SIZE, NULL, 0);
816 error = EIO;
817 break;
818 }
819
820 /* Is this a deleted file? */
821 if (fid->file_char & UDF_FILE_CHAR_DEL)
822 continue;
823
824 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
825 /* Do up the '.' and '..' entries. Dummy values are
826 * used for the cookies since the offset here is
827 * usually zero, and NFS doesn't like that value
828 */
829 dir.d_fileno = node->hash_id;
830 dir.d_type = DT_DIR;
831 dir.d_name[0] = '.';
832 dir.d_name[1] = '\0';
833 dir.d_namlen = 1;
834 dir.d_reclen = GENERIC_DIRSIZ(&dir);
835 uiodir.dirent = &dir;
836 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
837 if (error)
838 break;
839
840 dir.d_fileno = udf_getid(&fid->icb);
841 dir.d_type = DT_DIR;
842 dir.d_name[0] = '.';
843 dir.d_name[1] = '.';
844 dir.d_name[2] = '\0';
845 dir.d_namlen = 2;
846 dir.d_reclen = GENERIC_DIRSIZ(&dir);
847 uiodir.dirent = &dir;
848 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
849 } else {
850 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
851 &dir.d_name[0], fid->l_fi, udfmp);
852 dir.d_fileno = udf_getid(&fid->icb);
853 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
854 DT_DIR : DT_UNKNOWN;
855 dir.d_reclen = GENERIC_DIRSIZ(&dir);
856 uiodir.dirent = &dir;
857 error = udf_uiodir(&uiodir, dir.d_reclen, uio,
858 ds->this_off);
859 }
860 if (error)
861 break;
862 uio->uio_offset = ds->offset + ds->off;
863 }
864
865 /* tell the calling layer whether we need to be called again */
866 *a->a_eofflag = uiodir.eofflag;
867
868 if (error < 0)
869 error = 0;
870 if (!error)
871 error = ds->error;
872
873 udf_closedir(ds);
874
875 if (a->a_ncookies != NULL) {
876 if (error)
877 free(cookies, M_TEMP);
878 else {
879 *a->a_ncookies = uiodir.acookies;
880 *a->a_cookies = cookies;
881 }
882 }
883
884 return (error);
885 }
886
887 static int
888 udf_readlink(struct vop_readlink_args *ap)
889 {
890 struct path_component *pc, *end;
891 struct vnode *vp;
892 struct uio uio;
893 struct iovec iov[1];
894 struct udf_node *node;
895 void *buf;
896 char *cp;
897 int error, len, root;
898
899 /*
900 * A symbolic link in UDF is a list of variable-length path
901 * component structures. We build a pathname in the caller's
902 * uio by traversing this list.
903 */
904 vp = ap->a_vp;
905 node = VTON(vp);
906 len = le64toh(node->fentry->inf_len);
907 buf = malloc(len, M_DEVBUF, M_WAITOK);
908 iov[0].iov_len = len;
909 iov[0].iov_base = buf;
910 uio.uio_iov = iov;
911 uio.uio_iovcnt = 1;
912 uio.uio_offset = 0;
913 uio.uio_resid = iov[0].iov_len;
914 uio.uio_segflg = UIO_SYSSPACE;
915 uio.uio_rw = UIO_READ;
916 uio.uio_td = curthread;
917 error = VOP_READ(vp, &uio, 0, ap->a_cred);
918 if (error)
919 goto error;
920
921 pc = buf;
922 end = (void *)((char *)buf + len);
923 root = 0;
924 while (pc < end) {
925 switch (pc->type) {
926 case UDF_PATH_ROOT:
927 /* Only allow this at the beginning of a path. */
928 if ((void *)pc != buf) {
929 error = EINVAL;
930 goto error;
931 }
932 cp = "/";
933 len = 1;
934 root = 1;
935 break;
936 case UDF_PATH_DOT:
937 cp = ".";
938 len = 1;
939 break;
940 case UDF_PATH_DOTDOT:
941 cp = "..";
942 len = 2;
943 break;
944 case UDF_PATH_PATH:
945 if (pc->length == 0) {
946 error = EINVAL;
947 goto error;
948 }
949 /*
950 * XXX: We only support CS8 which appears to map
951 * to ASCII directly.
952 */
953 switch (pc->identifier[0]) {
954 case 8:
955 cp = pc->identifier + 1;
956 len = pc->length - 1;
957 break;
958 default:
959 error = EOPNOTSUPP;
960 goto error;
961 }
962 break;
963 default:
964 error = EINVAL;
965 goto error;
966 }
967
968 /*
969 * If this is not the first component, insert a path
970 * separator.
971 */
972 if (pc != buf) {
973 /* If we started with root we already have a "/". */
974 if (root)
975 goto skipslash;
976 root = 0;
977 if (ap->a_uio->uio_resid < 1) {
978 error = ENAMETOOLONG;
979 goto error;
980 }
981 error = uiomove("/", 1, ap->a_uio);
982 if (error)
983 break;
984 }
985 skipslash:
986
987 /* Append string at 'cp' of length 'len' to our path. */
988 if (len > ap->a_uio->uio_resid) {
989 error = ENAMETOOLONG;
990 goto error;
991 }
992 error = uiomove(cp, len, ap->a_uio);
993 if (error)
994 break;
995
996 /* Advance to next component. */
997 pc = (void *)((char *)pc + 4 + pc->length);
998 }
999 error:
1000 free(buf, M_DEVBUF);
1001 return (error);
1002 }
1003
1004 static int
1005 udf_strategy(struct vop_strategy_args *a)
1006 {
1007 struct buf *bp;
1008 struct vnode *vp;
1009 struct udf_node *node;
1010 struct bufobj *bo;
1011 off_t offset;
1012 uint32_t maxsize;
1013 daddr_t sector;
1014 int error;
1015
1016 bp = a->a_bp;
1017 vp = a->a_vp;
1018 node = VTON(vp);
1019
1020 if (bp->b_blkno == bp->b_lblkno) {
1021 offset = lblktosize(node->udfmp, bp->b_lblkno);
1022 error = udf_bmap_internal(node, offset, §or, &maxsize);
1023 if (error) {
1024 clrbuf(bp);
1025 bp->b_blkno = -1;
1026 bufdone(bp);
1027 return (0);
1028 }
1029 /* bmap gives sector numbers, bio works with device blocks */
1030 bp->b_blkno = sector << (node->udfmp->bshift - DEV_BSHIFT);
1031 }
1032 bo = node->udfmp->im_bo;
1033 bp->b_iooffset = dbtob(bp->b_blkno);
1034 BO_STRATEGY(bo, bp);
1035 return (0);
1036 }
1037
1038 static int
1039 udf_bmap(struct vop_bmap_args *a)
1040 {
1041 struct udf_node *node;
1042 uint32_t max_size;
1043 daddr_t lsector;
1044 int nblk;
1045 int error;
1046
1047 node = VTON(a->a_vp);
1048
1049 if (a->a_bop != NULL)
1050 *a->a_bop = &node->udfmp->im_devvp->v_bufobj;
1051 if (a->a_bnp == NULL)
1052 return (0);
1053 if (a->a_runb)
1054 *a->a_runb = 0;
1055
1056 /*
1057 * UDF_INVALID_BMAP means data embedded into fentry, this is an internal
1058 * error that should not be propagated to calling code.
1059 * Most obvious mapping for this error is EOPNOTSUPP as we can not truly
1060 * translate block numbers in this case.
1061 * Incidentally, this return code will make vnode pager to use VOP_READ
1062 * to get data for mmap-ed pages and udf_read knows how to do the right
1063 * thing for this kind of files.
1064 */
1065 error = udf_bmap_internal(node, a->a_bn << node->udfmp->bshift,
1066 &lsector, &max_size);
1067 if (error == UDF_INVALID_BMAP)
1068 return (EOPNOTSUPP);
1069 if (error)
1070 return (error);
1071
1072 /* Translate logical to physical sector number */
1073 *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
1074
1075 /*
1076 * Determine maximum number of readahead blocks following the
1077 * requested block.
1078 */
1079 if (a->a_runp) {
1080 nblk = (max_size >> node->udfmp->bshift) - 1;
1081 if (nblk <= 0)
1082 *a->a_runp = 0;
1083 else if (nblk >= (MAXBSIZE >> node->udfmp->bshift))
1084 *a->a_runp = (MAXBSIZE >> node->udfmp->bshift) - 1;
1085 else
1086 *a->a_runp = nblk;
1087 }
1088
1089 if (a->a_runb) {
1090 *a->a_runb = 0;
1091 }
1092
1093 return (0);
1094 }
1095
1096 /*
1097 * The all powerful VOP_LOOKUP().
1098 */
1099 static int
1100 udf_lookup(struct vop_cachedlookup_args *a)
1101 {
1102 struct vnode *dvp;
1103 struct vnode *tdp = NULL;
1104 struct vnode **vpp = a->a_vpp;
1105 struct udf_node *node;
1106 struct udf_mnt *udfmp;
1107 struct fileid_desc *fid = NULL;
1108 struct udf_dirstream *ds;
1109 u_long nameiop;
1110 u_long flags;
1111 char *nameptr;
1112 long namelen;
1113 ino_t id = 0;
1114 int offset, error = 0;
1115 int fsize, lkflags, ltype, numdirpasses;
1116
1117 dvp = a->a_dvp;
1118 node = VTON(dvp);
1119 udfmp = node->udfmp;
1120 nameiop = a->a_cnp->cn_nameiop;
1121 flags = a->a_cnp->cn_flags;
1122 lkflags = a->a_cnp->cn_lkflags;
1123 nameptr = a->a_cnp->cn_nameptr;
1124 namelen = a->a_cnp->cn_namelen;
1125 fsize = le64toh(node->fentry->inf_len);
1126
1127 /*
1128 * If this is a LOOKUP and we've already partially searched through
1129 * the directory, pick up where we left off and flag that the
1130 * directory may need to be searched twice. For a full description,
1131 * see /sys/fs/cd9660/cd9660_lookup.c:cd9660_lookup()
1132 */
1133 if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
1134 offset = 0;
1135 numdirpasses = 1;
1136 } else {
1137 offset = node->diroff;
1138 numdirpasses = 2;
1139 nchstats.ncs_2passes++;
1140 }
1141
1142 lookloop:
1143 ds = udf_opendir(node, offset, fsize, udfmp);
1144
1145 while ((fid = udf_getfid(ds)) != NULL) {
1146
1147 /* XXX Should we return an error on a bad fid? */
1148 if (udf_checktag(&fid->tag, TAGID_FID)) {
1149 printf("udf_lookup: Invalid tag\n");
1150 error = EIO;
1151 break;
1152 }
1153
1154 /* Is this a deleted file? */
1155 if (fid->file_char & UDF_FILE_CHAR_DEL)
1156 continue;
1157
1158 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
1159 if (flags & ISDOTDOT) {
1160 id = udf_getid(&fid->icb);
1161 break;
1162 }
1163 } else {
1164 if (!(udf_cmpname(&fid->data[fid->l_iu],
1165 nameptr, fid->l_fi, namelen, udfmp))) {
1166 id = udf_getid(&fid->icb);
1167 break;
1168 }
1169 }
1170 }
1171
1172 if (!error)
1173 error = ds->error;
1174
1175 /* XXX Bail out here? */
1176 if (error) {
1177 udf_closedir(ds);
1178 return (error);
1179 }
1180
1181 /* Did we have a match? */
1182 if (id) {
1183 /*
1184 * Remember where this entry was if it's the final
1185 * component.
1186 */
1187 if ((flags & ISLASTCN) && nameiop == LOOKUP)
1188 node->diroff = ds->offset + ds->off;
1189 if (numdirpasses == 2)
1190 nchstats.ncs_pass2++;
1191 udf_closedir(ds);
1192
1193 if (flags & ISDOTDOT) {
1194 error = vn_vget_ino(dvp, id, lkflags, &tdp);
1195 } else if (node->hash_id == id) {
1196 VREF(dvp); /* we want ourself, ie "." */
1197 /*
1198 * When we lookup "." we still can be asked to lock it
1199 * differently.
1200 */
1201 ltype = lkflags & LK_TYPE_MASK;
1202 if (ltype != VOP_ISLOCKED(dvp)) {
1203 if (ltype == LK_EXCLUSIVE)
1204 vn_lock(dvp, LK_UPGRADE | LK_RETRY);
1205 else /* if (ltype == LK_SHARED) */
1206 vn_lock(dvp, LK_DOWNGRADE | LK_RETRY);
1207 }
1208 tdp = dvp;
1209 } else
1210 error = udf_vget(udfmp->im_mountp, id, lkflags, &tdp);
1211 if (!error) {
1212 *vpp = tdp;
1213 /* Put this entry in the cache */
1214 if (flags & MAKEENTRY)
1215 cache_enter(dvp, *vpp, a->a_cnp);
1216 }
1217 } else {
1218 /* Name wasn't found on this pass. Do another pass? */
1219 if (numdirpasses == 2) {
1220 numdirpasses--;
1221 offset = 0;
1222 udf_closedir(ds);
1223 goto lookloop;
1224 }
1225 udf_closedir(ds);
1226
1227 /* Enter name into cache as non-existant */
1228 if (flags & MAKEENTRY)
1229 cache_enter(dvp, *vpp, a->a_cnp);
1230
1231 if ((flags & ISLASTCN) &&
1232 (nameiop == CREATE || nameiop == RENAME)) {
1233 error = EROFS;
1234 } else {
1235 error = ENOENT;
1236 }
1237 }
1238
1239 return (error);
1240 }
1241
1242 static int
1243 udf_reclaim(struct vop_reclaim_args *a)
1244 {
1245 struct vnode *vp;
1246 struct udf_node *unode;
1247
1248 vp = a->a_vp;
1249 unode = VTON(vp);
1250
1251 /*
1252 * Destroy the vm object and flush associated pages.
1253 */
1254 vnode_destroy_vobject(vp);
1255
1256 if (unode != NULL) {
1257 vfs_hash_remove(vp);
1258
1259 if (unode->fentry != NULL)
1260 free(unode->fentry, M_UDFFENTRY);
1261 uma_zfree(udf_zone_node, unode);
1262 vp->v_data = NULL;
1263 }
1264
1265 return (0);
1266 }
1267
1268 static int
1269 udf_vptofh(struct vop_vptofh_args *a)
1270 {
1271 struct udf_node *node;
1272 struct ifid *ifhp;
1273
1274 node = VTON(a->a_vp);
1275 ifhp = (struct ifid *)a->a_fhp;
1276 ifhp->ifid_len = sizeof(struct ifid);
1277 ifhp->ifid_ino = node->hash_id;
1278
1279 return (0);
1280 }
1281
1282 /*
1283 * Read the block and then set the data pointer to correspond with the
1284 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
1285 * to the number of bytes pointed to. If 'size' is zero, try to read in a
1286 * whole extent.
1287 *
1288 * Note that *bp may be assigned error or not.
1289 *
1290 */
1291 static int
1292 udf_readatoffset(struct udf_node *node, int *size, off_t offset,
1293 struct buf **bp, uint8_t **data)
1294 {
1295 struct udf_mnt *udfmp = node->udfmp;
1296 struct vnode *vp = node->i_vnode;
1297 struct file_entry *fentry;
1298 struct buf *bp1;
1299 uint32_t max_size;
1300 daddr_t sector;
1301 off_t off;
1302 int adj_size;
1303 int error;
1304
1305 /*
1306 * This call is made *not* only to detect UDF_INVALID_BMAP case,
1307 * max_size is used as an ad-hoc read-ahead hint for "normal" case.
1308 */
1309 error = udf_bmap_internal(node, offset, §or, &max_size);
1310 if (error == UDF_INVALID_BMAP) {
1311 /*
1312 * This error means that the file *data* is stored in the
1313 * allocation descriptor field of the file entry.
1314 */
1315 fentry = node->fentry;
1316 *data = &fentry->data[le32toh(fentry->l_ea)];
1317 *size = le32toh(fentry->l_ad);
1318 if (offset >= *size)
1319 *size = 0;
1320 else {
1321 *data += offset;
1322 *size -= offset;
1323 }
1324 return (0);
1325 } else if (error != 0) {
1326 return (error);
1327 }
1328
1329 /* Adjust the size so that it is within range */
1330 if (*size == 0 || *size > max_size)
1331 *size = max_size;
1332
1333 /*
1334 * Because we will read starting at block boundary, we need to adjust
1335 * how much we need to read so that all promised data is in.
1336 * Also, we can't promise to read more than MAXBSIZE bytes starting
1337 * from block boundary, so adjust what we promise too.
1338 */
1339 off = blkoff(udfmp, offset);
1340 *size = min(*size, MAXBSIZE - off);
1341 adj_size = (*size + off + udfmp->bmask) & ~udfmp->bmask;
1342 *bp = NULL;
1343 if ((error = bread(vp, lblkno(udfmp, offset), adj_size, NOCRED, bp))) {
1344 printf("warning: udf_readlblks returned error %d\n", error);
1345 /* note: *bp may be non-NULL */
1346 return (error);
1347 }
1348
1349 bp1 = *bp;
1350 *data = (uint8_t *)&bp1->b_data[offset & udfmp->bmask];
1351 return (0);
1352 }
1353
1354 /*
1355 * Translate a file offset into a logical block and then into a physical
1356 * block.
1357 * max_size - maximum number of bytes that can be read starting from given
1358 * offset, rather than beginning of calculated sector number
1359 */
1360 static int
1361 udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector,
1362 uint32_t *max_size)
1363 {
1364 struct udf_mnt *udfmp;
1365 struct file_entry *fentry;
1366 void *icb;
1367 struct icb_tag *tag;
1368 uint32_t icblen = 0;
1369 daddr_t lsector;
1370 int ad_offset, ad_num = 0;
1371 int i, p_offset;
1372
1373 udfmp = node->udfmp;
1374 fentry = node->fentry;
1375 tag = &fentry->icbtag;
1376
1377 switch (le16toh(tag->strat_type)) {
1378 case 4:
1379 break;
1380
1381 case 4096:
1382 printf("Cannot deal with strategy4096 yet!\n");
1383 return (ENODEV);
1384
1385 default:
1386 printf("Unknown strategy type %d\n", tag->strat_type);
1387 return (ENODEV);
1388 }
1389
1390 switch (le16toh(tag->flags) & 0x7) {
1391 case 0:
1392 /*
1393 * The allocation descriptor field is filled with short_ad's.
1394 * If the offset is beyond the current extent, look for the
1395 * next extent.
1396 */
1397 do {
1398 offset -= icblen;
1399 ad_offset = sizeof(struct short_ad) * ad_num;
1400 if (ad_offset > le32toh(fentry->l_ad)) {
1401 printf("File offset out of bounds\n");
1402 return (EINVAL);
1403 }
1404 icb = GETICB(short_ad, fentry,
1405 le32toh(fentry->l_ea) + ad_offset);
1406 icblen = GETICBLEN(short_ad, icb);
1407 ad_num++;
1408 } while(offset >= icblen);
1409
1410 lsector = (offset >> udfmp->bshift) +
1411 le32toh(((struct short_ad *)(icb))->pos);
1412
1413 *max_size = icblen - offset;
1414
1415 break;
1416 case 1:
1417 /*
1418 * The allocation descriptor field is filled with long_ad's
1419 * If the offset is beyond the current extent, look for the
1420 * next extent.
1421 */
1422 do {
1423 offset -= icblen;
1424 ad_offset = sizeof(struct long_ad) * ad_num;
1425 if (ad_offset > le32toh(fentry->l_ad)) {
1426 printf("File offset out of bounds\n");
1427 return (EINVAL);
1428 }
1429 icb = GETICB(long_ad, fentry,
1430 le32toh(fentry->l_ea) + ad_offset);
1431 icblen = GETICBLEN(long_ad, icb);
1432 ad_num++;
1433 } while(offset >= icblen);
1434
1435 lsector = (offset >> udfmp->bshift) +
1436 le32toh(((struct long_ad *)(icb))->loc.lb_num);
1437
1438 *max_size = icblen - offset;
1439
1440 break;
1441 case 3:
1442 /*
1443 * This type means that the file *data* is stored in the
1444 * allocation descriptor field of the file entry.
1445 */
1446 *max_size = 0;
1447 *sector = node->hash_id + udfmp->part_start;
1448
1449 return (UDF_INVALID_BMAP);
1450 case 2:
1451 /* DirectCD does not use extended_ad's */
1452 default:
1453 printf("Unsupported allocation descriptor %d\n",
1454 tag->flags & 0x7);
1455 return (ENODEV);
1456 }
1457
1458 *sector = lsector + udfmp->part_start;
1459
1460 /*
1461 * Check the sparing table. Each entry represents the beginning of
1462 * a packet.
1463 */
1464 if (udfmp->s_table != NULL) {
1465 for (i = 0; i< udfmp->s_table_entries; i++) {
1466 p_offset =
1467 lsector - le32toh(udfmp->s_table->entries[i].org);
1468 if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1469 *sector =
1470 le32toh(udfmp->s_table->entries[i].map) +
1471 p_offset;
1472 break;
1473 }
1474 }
1475 }
1476
1477 return (0);
1478 }
Cache object: ccbb5c23de03695f851a802b5d2c1a36
|