Deleted Added
full compact
udf_vnops.c (144207) udf_vnops.c (145006)
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 *
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: head/sys/fs/udf/udf_vnops.c 144207 2005-03-28 09:31:57Z jeff $
26 * $FreeBSD: head/sys/fs/udf/udf_vnops.c 145006 2005-04-13 10:59:09Z jeff $
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/udf/ecma167-udf.h>
52#include <fs/udf/osta.h>
53#include <fs/udf/udf.h>
54#include <fs/udf/udf_mount.h>
55
56extern struct iconv_functions *udf_iconv;
57
58static vop_access_t udf_access;
59static vop_getattr_t udf_getattr;
60static vop_ioctl_t udf_ioctl;
61static vop_pathconf_t udf_pathconf;
62static vop_read_t udf_read;
63static vop_readdir_t udf_readdir;
64static vop_readlink_t udf_readlink;
65static vop_strategy_t udf_strategy;
66static vop_bmap_t udf_bmap;
67static vop_cachedlookup_t udf_lookup;
68static vop_reclaim_t udf_reclaim;
69static int udf_readatoffset(struct udf_node *node, int *size, off_t offset,
70 struct buf **bp, uint8_t **data);
71static int udf_bmap_internal(struct udf_node *node, off_t offset,
72 daddr_t *sector, uint32_t *max_size);
73
74static struct vop_vector udf_vnodeops = {
75 .vop_default = &default_vnodeops,
76
77 .vop_access = udf_access,
78 .vop_bmap = udf_bmap,
79 .vop_cachedlookup = udf_lookup,
80 .vop_getattr = udf_getattr,
81 .vop_ioctl = udf_ioctl,
82 .vop_lookup = vfs_cache_lookup,
83 .vop_pathconf = udf_pathconf,
84 .vop_read = udf_read,
85 .vop_readdir = udf_readdir,
86 .vop_readlink = udf_readlink,
87 .vop_reclaim = udf_reclaim,
88 .vop_strategy = udf_strategy,
89};
90
91MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
92MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
93
94#define UDF_INVALID_BMAP -1
95
96int
97udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
98{
99 int error;
100 struct vnode *vp;
101
102 error = getnewvnode("udf", mp, &udf_vnodeops, &vp);
103 if (error) {
104 printf("udf_allocv: failed to allocate new vnode\n");
105 return (error);
106 }
107
108 *vpp = vp;
109 return (0);
110}
111
112/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
113static mode_t
114udf_permtomode(struct udf_node *node)
115{
116 uint32_t perm;
117 uint16_t flags;
118 mode_t mode;
119
120 perm = le32toh(node->fentry->perm);
121 flags = le16toh(node->fentry->icbtag.flags);
122
123 mode = perm & UDF_FENTRY_PERM_USER_MASK;
124 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
125 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
126 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
127 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
128 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
129
130 return (mode);
131}
132
133static int
134udf_access(struct vop_access_args *a)
135{
136 struct vnode *vp;
137 struct udf_node *node;
138 mode_t a_mode, mode;
139
140 vp = a->a_vp;
141 node = VTON(vp);
142 a_mode = a->a_mode;
143
144 if (a_mode & VWRITE) {
145 switch (vp->v_type) {
146 case VDIR:
147 case VLNK:
148 case VREG:
149 return (EROFS);
150 /* NOT REACHED */
151 default:
152 break;
153 }
154 }
155
156 mode = udf_permtomode(node);
157
158 return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
159 a_mode, a->a_cred, NULL));
160}
161
162static int mon_lens[2][12] = {
163 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
164 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
165};
166
167static int
168udf_isaleapyear(int year)
169{
170 int i;
171
172 i = (year % 4) ? 0 : 1;
173 i &= (year % 100) ? 1 : 0;
174 i |= (year % 400) ? 0 : 1;
175
176 return i;
177}
178
179/*
180 * XXX This is just a rough hack. Daylight savings isn't calculated and tv_nsec
181 * is ignored.
182 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
183 */
184static void
185udf_timetotimespec(struct timestamp *time, struct timespec *t)
186{
187 int i, lpyear, daysinyear, year;
188 union {
189 uint16_t u_tz_offset;
190 int16_t s_tz_offset;
191 } tz;
192
193 t->tv_nsec = 0;
194
195 /* DirectCD seems to like using bogus year values */
196 year = le16toh(time->year);
197 if (year < 1970) {
198 t->tv_sec = 0;
199 return;
200 }
201
202 /* Calculate the time and day */
203 t->tv_sec = time->second;
204 t->tv_sec += time->minute * 60;
205 t->tv_sec += time->hour * 3600;
206 t->tv_sec += time->day * 3600 * 24;
207
208 /* Calclulate the month */
209 lpyear = udf_isaleapyear(year);
210 for (i = 1; i < time->month; i++)
211 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
212
213 /* Speed up the calculation */
214 if (year > 1979)
215 t->tv_sec += 315532800;
216 if (year > 1989)
217 t->tv_sec += 315619200;
218 if (year > 1999)
219 t->tv_sec += 315532800;
220 for (i = 2000; i < year; i++) {
221 daysinyear = udf_isaleapyear(i) + 365 ;
222 t->tv_sec += daysinyear * 3600 * 24;
223 }
224
225 /*
226 * Calculate the time zone. The timezone is 12 bit signed 2's
227 * compliment, so we gotta do some extra magic to handle it right.
228 */
229 tz.u_tz_offset = le16toh(time->type_tz);
230 tz.u_tz_offset &= 0x0fff;
231 if (tz.u_tz_offset & 0x0800)
232 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
233 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
234 t->tv_sec -= tz.s_tz_offset * 60;
235
236 return;
237}
238
239static int
240udf_getattr(struct vop_getattr_args *a)
241{
242 struct vnode *vp;
243 struct udf_node *node;
244 struct vattr *vap;
245 struct file_entry *fentry;
246 struct timespec ts;
247
248 ts.tv_sec = 0;
249
250 vp = a->a_vp;
251 vap = a->a_vap;
252 node = VTON(vp);
253 fentry = node->fentry;
254
255 vap->va_fsid = dev2udev(node->udfmp->im_dev);
256 vap->va_fileid = node->hash_id;
257 vap->va_mode = udf_permtomode(node);
258 vap->va_nlink = le16toh(fentry->link_cnt);
259 /*
260 * XXX The spec says that -1 is valid for uid/gid and indicates an
261 * invalid uid/gid. How should this be represented?
262 */
263 vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid);
264 vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid);
265 udf_timetotimespec(&fentry->atime, &vap->va_atime);
266 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
267 vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
268 vap->va_rdev = 0; /* XXX */
269 if (vp->v_type & VDIR) {
270 /*
271 * Directories that are recorded within their ICB will show
272 * as having 0 blocks recorded. Since tradition dictates
273 * that directories consume at least one logical block,
274 * make it appear so.
275 */
276 if (fentry->logblks_rec != 0) {
277 vap->va_size =
278 le64toh(fentry->logblks_rec) * node->udfmp->bsize;
279 } else {
280 vap->va_size = node->udfmp->bsize;
281 }
282 } else {
283 vap->va_size = le64toh(fentry->inf_len);
284 }
285 vap->va_flags = 0;
286 vap->va_gen = 1;
287 vap->va_blocksize = node->udfmp->bsize;
288 vap->va_bytes = le64toh(fentry->inf_len);
289 vap->va_type = vp->v_type;
290 vap->va_filerev = 0; /* XXX */
291 return (0);
292}
293
294/*
295 * File specific ioctls.
296 */
297static int
298udf_ioctl(struct vop_ioctl_args *a)
299{
300 printf("%s called\n", __func__);
301 return (ENOTTY);
302}
303
304/*
305 * I'm not sure that this has much value in a read-only filesystem, but
306 * cd9660 has it too.
307 */
308static int
309udf_pathconf(struct vop_pathconf_args *a)
310{
311
312 switch (a->a_name) {
313 case _PC_LINK_MAX:
314 *a->a_retval = 65535;
315 return (0);
316 case _PC_NAME_MAX:
317 *a->a_retval = NAME_MAX;
318 return (0);
319 case _PC_PATH_MAX:
320 *a->a_retval = PATH_MAX;
321 return (0);
322 case _PC_NO_TRUNC:
323 *a->a_retval = 1;
324 return (0);
325 default:
326 return (EINVAL);
327 }
328}
329
330static int
331udf_read(struct vop_read_args *a)
332{
333 struct vnode *vp = a->a_vp;
334 struct uio *uio = a->a_uio;
335 struct udf_node *node = VTON(vp);
336 struct buf *bp;
337 uint8_t *data;
338 off_t fsize, offset;
339 int error = 0;
340 int size;
341
342 if (uio->uio_offset < 0)
343 return (EINVAL);
344
345 fsize = le64toh(node->fentry->inf_len);
346
347 while (uio->uio_offset < fsize && uio->uio_resid > 0) {
348 offset = uio->uio_offset;
349 if (uio->uio_resid + offset <= fsize)
350 size = uio->uio_resid;
351 else
352 size = fsize - offset;
353 error = udf_readatoffset(node, &size, offset, &bp, &data);
354 if (error == 0)
355 error = uiomove(data, size, uio);
356 if (bp != NULL)
357 brelse(bp);
358 if (error)
359 break;
360 };
361
362 return (error);
363}
364
365/*
366 * Call the OSTA routines to translate the name from a CS0 dstring to a
367 * 16-bit Unicode String. Hooks need to be placed in here to translate from
368 * Unicode to the encoding that the kernel/user expects. Return the length
369 * of the translated string.
370 */
371static int
372udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
373{
374 unicode_t *transname;
375 char *unibuf, *unip;
376 int i, unilen = 0, destlen;
377 size_t destleft = MAXNAMLEN;
378
379 /* Convert 16-bit Unicode to destname */
380 if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
381 /* allocate a buffer big enough to hold an 8->16 bit expansion */
382 unibuf = uma_zalloc(udf_zone_trans, M_WAITOK);
383 unip = unibuf;
384 if ((unilen = udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) {
385 printf("udf: Unicode translation failed\n");
386 uma_zfree(udf_zone_trans, unibuf);
387 return 0;
388 }
389
390 while (unilen > 0 && destleft > 0) {
391 udf_iconv->conv(udfmp->im_d2l, (const char **)&unibuf,
392 (size_t *)&unilen, (char **)&destname, &destleft);
393 /* Unconverted character found */
394 if (unilen > 0 && destleft > 0) {
395 *destname++ = '?';
396 destleft--;
397 unibuf += 2;
398 unilen -= 2;
399 }
400 }
401 uma_zfree(udf_zone_trans, unip);
402 *destname = '\0';
403 destlen = MAXNAMLEN - (int)destleft;
404 } else {
405 /* allocate a buffer big enough to hold an 8->16 bit expansion */
406 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
407
408 if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) {
409 printf("udf: Unicode translation failed\n");
410 uma_zfree(udf_zone_trans, transname);
411 return 0;
412 }
413
414 for (i = 0; i < unilen ; i++) {
415 if (transname[i] & 0xff00) {
416 destname[i] = '.'; /* Fudge the 16bit chars */
417 } else {
418 destname[i] = transname[i] & 0xff;
419 }
420 }
421 uma_zfree(udf_zone_trans, transname);
422 destname[unilen] = 0;
423 destlen = unilen;
424 }
425
426 return (destlen);
427}
428
429/*
430 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
431 * 0 on a successful match, nonzero therwise. Unicode work may need to be done
432 * here also.
433 */
434static int
435udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
436{
437 char *transname;
438 int error = 0;
439
440 /* This is overkill, but not worth creating a new zone */
441 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
442
443 cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
444
445 /* Easy check. If they aren't the same length, they aren't equal */
446 if ((cs0len == 0) || (cs0len != cmplen))
447 error = -1;
448 else
449 error = bcmp(transname, cmpname, cmplen);
450
451 uma_zfree(udf_zone_trans, transname);
452 return (error);
453}
454
455struct udf_uiodir {
456 struct dirent *dirent;
457 u_long *cookies;
458 int ncookies;
459 int acookies;
460 int eofflag;
461};
462
463static int
464udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
465{
466 if (uiodir->cookies != NULL) {
467 if (++uiodir->acookies > uiodir->ncookies) {
468 uiodir->eofflag = 0;
469 return (-1);
470 }
471 *uiodir->cookies++ = cookie;
472 }
473
474 if (uio->uio_resid < de_size) {
475 uiodir->eofflag = 0;
476 return (-1);
477 }
478
479 return (uiomove(uiodir->dirent, de_size, uio));
480}
481
482static struct udf_dirstream *
483udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
484{
485 struct udf_dirstream *ds;
486
487 ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
488
489 ds->node = node;
490 ds->offset = offset;
491 ds->udfmp = udfmp;
492 ds->fsize = fsize;
493
494 return (ds);
495}
496
497static struct fileid_desc *
498udf_getfid(struct udf_dirstream *ds)
499{
500 struct fileid_desc *fid;
501 int error, frag_size = 0, total_fid_size;
502
503 /* End of directory? */
504 if (ds->offset + ds->off >= ds->fsize) {
505 ds->error = 0;
506 return (NULL);
507 }
508
509 /* Grab the first extent of the directory */
510 if (ds->off == 0) {
511 ds->size = 0;
512 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
513 &ds->bp, &ds->data);
514 if (error) {
515 ds->error = error;
516 if (ds->bp != NULL)
517 brelse(ds->bp);
518 return (NULL);
519 }
520 }
521
522 /*
523 * Clean up from a previous fragmented FID.
524 * XXX Is this the right place for this?
525 */
526 if (ds->fid_fragment && ds->buf != NULL) {
527 ds->fid_fragment = 0;
528 FREE(ds->buf, M_UDFFID);
529 }
530
531 fid = (struct fileid_desc*)&ds->data[ds->off];
532
533 /*
534 * Check to see if the fid is fragmented. The first test
535 * ensures that we don't wander off the end of the buffer
536 * looking for the l_iu and l_fi fields.
537 */
538 if (ds->off + UDF_FID_SIZE > ds->size ||
539 ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
540
541 /* Copy what we have of the fid into a buffer */
542 frag_size = ds->size - ds->off;
543 if (frag_size >= ds->udfmp->bsize) {
544 printf("udf: invalid FID fragment\n");
545 ds->error = EINVAL;
546 return (NULL);
547 }
548
549 /*
550 * File ID descriptors can only be at most one
551 * logical sector in size.
552 */
553 MALLOC(ds->buf, uint8_t*, ds->udfmp->bsize, M_UDFFID,
554 M_WAITOK | M_ZERO);
555 bcopy(fid, ds->buf, frag_size);
556
557 /* Reduce all of the casting magic */
558 fid = (struct fileid_desc*)ds->buf;
559
560 if (ds->bp != NULL)
561 brelse(ds->bp);
562
563 /* Fetch the next allocation */
564 ds->offset += ds->size;
565 ds->size = 0;
566 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
567 &ds->bp, &ds->data);
568 if (error) {
569 ds->error = error;
570 return (NULL);
571 }
572
573 /*
574 * If the fragment was so small that we didn't get
575 * the l_iu and l_fi fields, copy those in.
576 */
577 if (frag_size < UDF_FID_SIZE)
578 bcopy(ds->data, &ds->buf[frag_size],
579 UDF_FID_SIZE - frag_size);
580
581 /*
582 * Now that we have enough of the fid to work with,
583 * copy in the rest of the fid from the new
584 * allocation.
585 */
586 total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi;
587 if (total_fid_size > ds->udfmp->bsize) {
588 printf("udf: invalid FID\n");
589 ds->error = EIO;
590 return (NULL);
591 }
592 bcopy(ds->data, &ds->buf[frag_size],
593 total_fid_size - frag_size);
594
595 ds->fid_fragment = 1;
596 } else {
597 total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
598 }
599
600 /*
601 * Update the offset. Align on a 4 byte boundary because the
602 * UDF spec says so.
603 */
604 ds->this_off = ds->off;
605 if (!ds->fid_fragment) {
606 ds->off += (total_fid_size + 3) & ~0x03;
607 } else {
608 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
609 }
610
611 return (fid);
612}
613
614static void
615udf_closedir(struct udf_dirstream *ds)
616{
617
618 if (ds->bp != NULL)
619 brelse(ds->bp);
620
621 if (ds->fid_fragment && ds->buf != NULL)
622 FREE(ds->buf, M_UDFFID);
623
624 uma_zfree(udf_zone_ds, ds);
625}
626
627static int
628udf_readdir(struct vop_readdir_args *a)
629{
630 struct vnode *vp;
631 struct uio *uio;
632 struct dirent dir;
633 struct udf_node *node;
634 struct udf_mnt *udfmp;
635 struct fileid_desc *fid;
636 struct udf_uiodir uiodir;
637 struct udf_dirstream *ds;
638 u_long *cookies = NULL;
639 int ncookies;
640 int error = 0;
641
642 vp = a->a_vp;
643 uio = a->a_uio;
644 node = VTON(vp);
645 udfmp = node->udfmp;
646 uiodir.eofflag = 1;
647
648 if (a->a_ncookies != NULL) {
649 /*
650 * Guess how many entries are needed. If we run out, this
651 * function will be called again and thing will pick up were
652 * it left off.
653 */
654 ncookies = uio->uio_resid / 8;
655 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
656 M_TEMP, M_WAITOK);
657 if (cookies == NULL)
658 return (ENOMEM);
659 uiodir.ncookies = ncookies;
660 uiodir.cookies = cookies;
661 uiodir.acookies = 0;
662 } else {
663 uiodir.cookies = NULL;
664 }
665
666 /*
667 * Iterate through the file id descriptors. Give the parent dir
668 * entry special attention.
669 */
670 ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
671 node->udfmp);
672
673 while ((fid = udf_getfid(ds)) != NULL) {
674
675 /* XXX Should we return an error on a bad fid? */
676 if (udf_checktag(&fid->tag, TAGID_FID)) {
677 printf("Invalid FID tag\n");
678 hexdump(fid, UDF_FID_SIZE, NULL, 0);
679 error = EIO;
680 break;
681 }
682
683 /* Is this a deleted file? */
684 if (fid->file_char & UDF_FILE_CHAR_DEL)
685 continue;
686
687 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
688 /* Do up the '.' and '..' entries. Dummy values are
689 * used for the cookies since the offset here is
690 * usually zero, and NFS doesn't like that value
691 */
692 dir.d_fileno = node->hash_id;
693 dir.d_type = DT_DIR;
694 dir.d_name[0] = '.';
695 dir.d_name[1] = '\0';
696 dir.d_namlen = 1;
697 dir.d_reclen = GENERIC_DIRSIZ(&dir);
698 uiodir.dirent = &dir;
699 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
700 if (error)
701 break;
702
703 dir.d_fileno = udf_getid(&fid->icb);
704 dir.d_type = DT_DIR;
705 dir.d_name[0] = '.';
706 dir.d_name[1] = '.';
707 dir.d_name[2] = '\0';
708 dir.d_namlen = 2;
709 dir.d_reclen = GENERIC_DIRSIZ(&dir);
710 uiodir.dirent = &dir;
711 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
712 } else {
713 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
714 &dir.d_name[0], fid->l_fi, udfmp);
715 dir.d_fileno = udf_getid(&fid->icb);
716 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
717 DT_DIR : DT_UNKNOWN;
718 dir.d_reclen = GENERIC_DIRSIZ(&dir);
719 uiodir.dirent = &dir;
720 error = udf_uiodir(&uiodir, dir.d_reclen, uio,
721 ds->this_off);
722 }
723 if (error) {
724 printf("uiomove returned %d\n", error);
725 break;
726 }
727
728 }
729
730 /* tell the calling layer whether we need to be called again */
731 *a->a_eofflag = uiodir.eofflag;
732 uio->uio_offset = ds->offset + ds->off;
733
734 if (!error)
735 error = ds->error;
736
737 udf_closedir(ds);
738
739 if (a->a_ncookies != NULL) {
740 if (error)
741 FREE(cookies, M_TEMP);
742 else {
743 *a->a_ncookies = uiodir.acookies;
744 *a->a_cookies = cookies;
745 }
746 }
747
748 return (error);
749}
750
751/* Are there any implementations out there that do soft-links? */
752static int
753udf_readlink(struct vop_readlink_args *ap)
754{
755 printf("%s called\n", __func__);
756 return (EOPNOTSUPP);
757}
758
759static int
760udf_strategy(struct vop_strategy_args *a)
761{
762 struct buf *bp;
763 struct vnode *vp;
764 struct udf_node *node;
765 int maxsize;
766 struct bufobj *bo;
767
768 bp = a->a_bp;
769 vp = a->a_vp;
770 node = VTON(vp);
771
772 /* cd9660 has this test reversed, but it seems more logical this way */
773 if (bp->b_blkno != bp->b_lblkno) {
774 /*
775 * Files that are embedded in the fentry don't translate well
776 * to a block number. Reject.
777 */
778 if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
779 &bp->b_lblkno, &maxsize)) {
780 clrbuf(bp);
781 bp->b_blkno = -1;
782 }
783 }
784 if ((long)bp->b_blkno == -1) {
785 bufdone(bp);
786 return (0);
787 }
788 bo = node->udfmp->im_bo;
789 bp->b_iooffset = dbtob(bp->b_blkno);
790 BO_STRATEGY(bo, bp);
791 return (0);
792}
793
794static int
795udf_bmap(struct vop_bmap_args *a)
796{
797 struct udf_node *node;
798 uint32_t max_size;
799 daddr_t lsector;
800 int error;
801
802 node = VTON(a->a_vp);
803
804 if (a->a_bop != NULL)
805 *a->a_bop = &node->udfmp->im_devvp->v_bufobj;
806 if (a->a_bnp == NULL)
807 return (0);
808 if (a->a_runb)
809 *a->a_runb = 0;
810
811 error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector,
812 &max_size);
813 if (error)
814 return (error);
815
816 /* Translate logical to physical sector number */
817 *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
818
819 /* Punt on read-ahead for now */
820 if (a->a_runp)
821 *a->a_runp = 0;
822
823 return (0);
824}
825
826/*
827 * The all powerful VOP_LOOKUP().
828 */
829static int
830udf_lookup(struct vop_cachedlookup_args *a)
831{
832 struct vnode *dvp;
833 struct vnode *tdp = NULL;
834 struct vnode **vpp = a->a_vpp;
835 struct udf_node *node;
836 struct udf_mnt *udfmp;
837 struct fileid_desc *fid = NULL;
838 struct udf_dirstream *ds;
839 struct thread *td;
840 u_long nameiop;
841 u_long flags;
842 char *nameptr;
843 long namelen;
844 ino_t id = 0;
845 int offset, error = 0;
846 int numdirpasses, fsize;
847
848 dvp = a->a_dvp;
849 node = VTON(dvp);
850 udfmp = node->udfmp;
851 nameiop = a->a_cnp->cn_nameiop;
852 flags = a->a_cnp->cn_flags;
853 nameptr = a->a_cnp->cn_nameptr;
854 namelen = a->a_cnp->cn_namelen;
855 fsize = le64toh(node->fentry->inf_len);
856 td = a->a_cnp->cn_thread;
857
858 /*
859 * If this is a LOOKUP and we've already partially searched through
860 * the directory, pick up where we left off and flag that the
861 * directory may need to be searched twice. For a full description,
862 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
863 */
864 if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
865 offset = 0;
866 numdirpasses = 1;
867 } else {
868 offset = node->diroff;
869 numdirpasses = 2;
870 nchstats.ncs_2passes++;
871 }
872
873lookloop:
874 ds = udf_opendir(node, offset, fsize, udfmp);
875
876 while ((fid = udf_getfid(ds)) != NULL) {
877
878 /* XXX Should we return an error on a bad fid? */
879 if (udf_checktag(&fid->tag, TAGID_FID)) {
880 printf("udf_lookup: Invalid tag\n");
881 error = EIO;
882 break;
883 }
884
885 /* Is this a deleted file? */
886 if (fid->file_char & UDF_FILE_CHAR_DEL)
887 continue;
888
889 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
890 if (flags & ISDOTDOT) {
891 id = udf_getid(&fid->icb);
892 break;
893 }
894 } else {
895 if (!(udf_cmpname(&fid->data[fid->l_iu],
896 nameptr, fid->l_fi, namelen, udfmp))) {
897 id = udf_getid(&fid->icb);
898 break;
899 }
900 }
901 }
902
903 if (!error)
904 error = ds->error;
905
906 /* XXX Bail out here? */
907 if (error) {
908 udf_closedir(ds);
909 return (error);
910 }
911
912 /* Did we have a match? */
913 if (id) {
914 if (flags & ISDOTDOT)
915 VOP_UNLOCK(dvp, 0, a->a_cnp->cn_thread);
916 error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
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/udf/ecma167-udf.h>
52#include <fs/udf/osta.h>
53#include <fs/udf/udf.h>
54#include <fs/udf/udf_mount.h>
55
56extern struct iconv_functions *udf_iconv;
57
58static vop_access_t udf_access;
59static vop_getattr_t udf_getattr;
60static vop_ioctl_t udf_ioctl;
61static vop_pathconf_t udf_pathconf;
62static vop_read_t udf_read;
63static vop_readdir_t udf_readdir;
64static vop_readlink_t udf_readlink;
65static vop_strategy_t udf_strategy;
66static vop_bmap_t udf_bmap;
67static vop_cachedlookup_t udf_lookup;
68static vop_reclaim_t udf_reclaim;
69static int udf_readatoffset(struct udf_node *node, int *size, off_t offset,
70 struct buf **bp, uint8_t **data);
71static int udf_bmap_internal(struct udf_node *node, off_t offset,
72 daddr_t *sector, uint32_t *max_size);
73
74static struct vop_vector udf_vnodeops = {
75 .vop_default = &default_vnodeops,
76
77 .vop_access = udf_access,
78 .vop_bmap = udf_bmap,
79 .vop_cachedlookup = udf_lookup,
80 .vop_getattr = udf_getattr,
81 .vop_ioctl = udf_ioctl,
82 .vop_lookup = vfs_cache_lookup,
83 .vop_pathconf = udf_pathconf,
84 .vop_read = udf_read,
85 .vop_readdir = udf_readdir,
86 .vop_readlink = udf_readlink,
87 .vop_reclaim = udf_reclaim,
88 .vop_strategy = udf_strategy,
89};
90
91MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
92MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
93
94#define UDF_INVALID_BMAP -1
95
96int
97udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
98{
99 int error;
100 struct vnode *vp;
101
102 error = getnewvnode("udf", mp, &udf_vnodeops, &vp);
103 if (error) {
104 printf("udf_allocv: failed to allocate new vnode\n");
105 return (error);
106 }
107
108 *vpp = vp;
109 return (0);
110}
111
112/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
113static mode_t
114udf_permtomode(struct udf_node *node)
115{
116 uint32_t perm;
117 uint16_t flags;
118 mode_t mode;
119
120 perm = le32toh(node->fentry->perm);
121 flags = le16toh(node->fentry->icbtag.flags);
122
123 mode = perm & UDF_FENTRY_PERM_USER_MASK;
124 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
125 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
126 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
127 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
128 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
129
130 return (mode);
131}
132
133static int
134udf_access(struct vop_access_args *a)
135{
136 struct vnode *vp;
137 struct udf_node *node;
138 mode_t a_mode, mode;
139
140 vp = a->a_vp;
141 node = VTON(vp);
142 a_mode = a->a_mode;
143
144 if (a_mode & VWRITE) {
145 switch (vp->v_type) {
146 case VDIR:
147 case VLNK:
148 case VREG:
149 return (EROFS);
150 /* NOT REACHED */
151 default:
152 break;
153 }
154 }
155
156 mode = udf_permtomode(node);
157
158 return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
159 a_mode, a->a_cred, NULL));
160}
161
162static int mon_lens[2][12] = {
163 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
164 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
165};
166
167static int
168udf_isaleapyear(int year)
169{
170 int i;
171
172 i = (year % 4) ? 0 : 1;
173 i &= (year % 100) ? 1 : 0;
174 i |= (year % 400) ? 0 : 1;
175
176 return i;
177}
178
179/*
180 * XXX This is just a rough hack. Daylight savings isn't calculated and tv_nsec
181 * is ignored.
182 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
183 */
184static void
185udf_timetotimespec(struct timestamp *time, struct timespec *t)
186{
187 int i, lpyear, daysinyear, year;
188 union {
189 uint16_t u_tz_offset;
190 int16_t s_tz_offset;
191 } tz;
192
193 t->tv_nsec = 0;
194
195 /* DirectCD seems to like using bogus year values */
196 year = le16toh(time->year);
197 if (year < 1970) {
198 t->tv_sec = 0;
199 return;
200 }
201
202 /* Calculate the time and day */
203 t->tv_sec = time->second;
204 t->tv_sec += time->minute * 60;
205 t->tv_sec += time->hour * 3600;
206 t->tv_sec += time->day * 3600 * 24;
207
208 /* Calclulate the month */
209 lpyear = udf_isaleapyear(year);
210 for (i = 1; i < time->month; i++)
211 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
212
213 /* Speed up the calculation */
214 if (year > 1979)
215 t->tv_sec += 315532800;
216 if (year > 1989)
217 t->tv_sec += 315619200;
218 if (year > 1999)
219 t->tv_sec += 315532800;
220 for (i = 2000; i < year; i++) {
221 daysinyear = udf_isaleapyear(i) + 365 ;
222 t->tv_sec += daysinyear * 3600 * 24;
223 }
224
225 /*
226 * Calculate the time zone. The timezone is 12 bit signed 2's
227 * compliment, so we gotta do some extra magic to handle it right.
228 */
229 tz.u_tz_offset = le16toh(time->type_tz);
230 tz.u_tz_offset &= 0x0fff;
231 if (tz.u_tz_offset & 0x0800)
232 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
233 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
234 t->tv_sec -= tz.s_tz_offset * 60;
235
236 return;
237}
238
239static int
240udf_getattr(struct vop_getattr_args *a)
241{
242 struct vnode *vp;
243 struct udf_node *node;
244 struct vattr *vap;
245 struct file_entry *fentry;
246 struct timespec ts;
247
248 ts.tv_sec = 0;
249
250 vp = a->a_vp;
251 vap = a->a_vap;
252 node = VTON(vp);
253 fentry = node->fentry;
254
255 vap->va_fsid = dev2udev(node->udfmp->im_dev);
256 vap->va_fileid = node->hash_id;
257 vap->va_mode = udf_permtomode(node);
258 vap->va_nlink = le16toh(fentry->link_cnt);
259 /*
260 * XXX The spec says that -1 is valid for uid/gid and indicates an
261 * invalid uid/gid. How should this be represented?
262 */
263 vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid);
264 vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid);
265 udf_timetotimespec(&fentry->atime, &vap->va_atime);
266 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
267 vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
268 vap->va_rdev = 0; /* XXX */
269 if (vp->v_type & VDIR) {
270 /*
271 * Directories that are recorded within their ICB will show
272 * as having 0 blocks recorded. Since tradition dictates
273 * that directories consume at least one logical block,
274 * make it appear so.
275 */
276 if (fentry->logblks_rec != 0) {
277 vap->va_size =
278 le64toh(fentry->logblks_rec) * node->udfmp->bsize;
279 } else {
280 vap->va_size = node->udfmp->bsize;
281 }
282 } else {
283 vap->va_size = le64toh(fentry->inf_len);
284 }
285 vap->va_flags = 0;
286 vap->va_gen = 1;
287 vap->va_blocksize = node->udfmp->bsize;
288 vap->va_bytes = le64toh(fentry->inf_len);
289 vap->va_type = vp->v_type;
290 vap->va_filerev = 0; /* XXX */
291 return (0);
292}
293
294/*
295 * File specific ioctls.
296 */
297static int
298udf_ioctl(struct vop_ioctl_args *a)
299{
300 printf("%s called\n", __func__);
301 return (ENOTTY);
302}
303
304/*
305 * I'm not sure that this has much value in a read-only filesystem, but
306 * cd9660 has it too.
307 */
308static int
309udf_pathconf(struct vop_pathconf_args *a)
310{
311
312 switch (a->a_name) {
313 case _PC_LINK_MAX:
314 *a->a_retval = 65535;
315 return (0);
316 case _PC_NAME_MAX:
317 *a->a_retval = NAME_MAX;
318 return (0);
319 case _PC_PATH_MAX:
320 *a->a_retval = PATH_MAX;
321 return (0);
322 case _PC_NO_TRUNC:
323 *a->a_retval = 1;
324 return (0);
325 default:
326 return (EINVAL);
327 }
328}
329
330static int
331udf_read(struct vop_read_args *a)
332{
333 struct vnode *vp = a->a_vp;
334 struct uio *uio = a->a_uio;
335 struct udf_node *node = VTON(vp);
336 struct buf *bp;
337 uint8_t *data;
338 off_t fsize, offset;
339 int error = 0;
340 int size;
341
342 if (uio->uio_offset < 0)
343 return (EINVAL);
344
345 fsize = le64toh(node->fentry->inf_len);
346
347 while (uio->uio_offset < fsize && uio->uio_resid > 0) {
348 offset = uio->uio_offset;
349 if (uio->uio_resid + offset <= fsize)
350 size = uio->uio_resid;
351 else
352 size = fsize - offset;
353 error = udf_readatoffset(node, &size, offset, &bp, &data);
354 if (error == 0)
355 error = uiomove(data, size, uio);
356 if (bp != NULL)
357 brelse(bp);
358 if (error)
359 break;
360 };
361
362 return (error);
363}
364
365/*
366 * Call the OSTA routines to translate the name from a CS0 dstring to a
367 * 16-bit Unicode String. Hooks need to be placed in here to translate from
368 * Unicode to the encoding that the kernel/user expects. Return the length
369 * of the translated string.
370 */
371static int
372udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
373{
374 unicode_t *transname;
375 char *unibuf, *unip;
376 int i, unilen = 0, destlen;
377 size_t destleft = MAXNAMLEN;
378
379 /* Convert 16-bit Unicode to destname */
380 if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
381 /* allocate a buffer big enough to hold an 8->16 bit expansion */
382 unibuf = uma_zalloc(udf_zone_trans, M_WAITOK);
383 unip = unibuf;
384 if ((unilen = udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) {
385 printf("udf: Unicode translation failed\n");
386 uma_zfree(udf_zone_trans, unibuf);
387 return 0;
388 }
389
390 while (unilen > 0 && destleft > 0) {
391 udf_iconv->conv(udfmp->im_d2l, (const char **)&unibuf,
392 (size_t *)&unilen, (char **)&destname, &destleft);
393 /* Unconverted character found */
394 if (unilen > 0 && destleft > 0) {
395 *destname++ = '?';
396 destleft--;
397 unibuf += 2;
398 unilen -= 2;
399 }
400 }
401 uma_zfree(udf_zone_trans, unip);
402 *destname = '\0';
403 destlen = MAXNAMLEN - (int)destleft;
404 } else {
405 /* allocate a buffer big enough to hold an 8->16 bit expansion */
406 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
407
408 if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) {
409 printf("udf: Unicode translation failed\n");
410 uma_zfree(udf_zone_trans, transname);
411 return 0;
412 }
413
414 for (i = 0; i < unilen ; i++) {
415 if (transname[i] & 0xff00) {
416 destname[i] = '.'; /* Fudge the 16bit chars */
417 } else {
418 destname[i] = transname[i] & 0xff;
419 }
420 }
421 uma_zfree(udf_zone_trans, transname);
422 destname[unilen] = 0;
423 destlen = unilen;
424 }
425
426 return (destlen);
427}
428
429/*
430 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
431 * 0 on a successful match, nonzero therwise. Unicode work may need to be done
432 * here also.
433 */
434static int
435udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
436{
437 char *transname;
438 int error = 0;
439
440 /* This is overkill, but not worth creating a new zone */
441 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
442
443 cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
444
445 /* Easy check. If they aren't the same length, they aren't equal */
446 if ((cs0len == 0) || (cs0len != cmplen))
447 error = -1;
448 else
449 error = bcmp(transname, cmpname, cmplen);
450
451 uma_zfree(udf_zone_trans, transname);
452 return (error);
453}
454
455struct udf_uiodir {
456 struct dirent *dirent;
457 u_long *cookies;
458 int ncookies;
459 int acookies;
460 int eofflag;
461};
462
463static int
464udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
465{
466 if (uiodir->cookies != NULL) {
467 if (++uiodir->acookies > uiodir->ncookies) {
468 uiodir->eofflag = 0;
469 return (-1);
470 }
471 *uiodir->cookies++ = cookie;
472 }
473
474 if (uio->uio_resid < de_size) {
475 uiodir->eofflag = 0;
476 return (-1);
477 }
478
479 return (uiomove(uiodir->dirent, de_size, uio));
480}
481
482static struct udf_dirstream *
483udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
484{
485 struct udf_dirstream *ds;
486
487 ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
488
489 ds->node = node;
490 ds->offset = offset;
491 ds->udfmp = udfmp;
492 ds->fsize = fsize;
493
494 return (ds);
495}
496
497static struct fileid_desc *
498udf_getfid(struct udf_dirstream *ds)
499{
500 struct fileid_desc *fid;
501 int error, frag_size = 0, total_fid_size;
502
503 /* End of directory? */
504 if (ds->offset + ds->off >= ds->fsize) {
505 ds->error = 0;
506 return (NULL);
507 }
508
509 /* Grab the first extent of the directory */
510 if (ds->off == 0) {
511 ds->size = 0;
512 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
513 &ds->bp, &ds->data);
514 if (error) {
515 ds->error = error;
516 if (ds->bp != NULL)
517 brelse(ds->bp);
518 return (NULL);
519 }
520 }
521
522 /*
523 * Clean up from a previous fragmented FID.
524 * XXX Is this the right place for this?
525 */
526 if (ds->fid_fragment && ds->buf != NULL) {
527 ds->fid_fragment = 0;
528 FREE(ds->buf, M_UDFFID);
529 }
530
531 fid = (struct fileid_desc*)&ds->data[ds->off];
532
533 /*
534 * Check to see if the fid is fragmented. The first test
535 * ensures that we don't wander off the end of the buffer
536 * looking for the l_iu and l_fi fields.
537 */
538 if (ds->off + UDF_FID_SIZE > ds->size ||
539 ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
540
541 /* Copy what we have of the fid into a buffer */
542 frag_size = ds->size - ds->off;
543 if (frag_size >= ds->udfmp->bsize) {
544 printf("udf: invalid FID fragment\n");
545 ds->error = EINVAL;
546 return (NULL);
547 }
548
549 /*
550 * File ID descriptors can only be at most one
551 * logical sector in size.
552 */
553 MALLOC(ds->buf, uint8_t*, ds->udfmp->bsize, M_UDFFID,
554 M_WAITOK | M_ZERO);
555 bcopy(fid, ds->buf, frag_size);
556
557 /* Reduce all of the casting magic */
558 fid = (struct fileid_desc*)ds->buf;
559
560 if (ds->bp != NULL)
561 brelse(ds->bp);
562
563 /* Fetch the next allocation */
564 ds->offset += ds->size;
565 ds->size = 0;
566 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
567 &ds->bp, &ds->data);
568 if (error) {
569 ds->error = error;
570 return (NULL);
571 }
572
573 /*
574 * If the fragment was so small that we didn't get
575 * the l_iu and l_fi fields, copy those in.
576 */
577 if (frag_size < UDF_FID_SIZE)
578 bcopy(ds->data, &ds->buf[frag_size],
579 UDF_FID_SIZE - frag_size);
580
581 /*
582 * Now that we have enough of the fid to work with,
583 * copy in the rest of the fid from the new
584 * allocation.
585 */
586 total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi;
587 if (total_fid_size > ds->udfmp->bsize) {
588 printf("udf: invalid FID\n");
589 ds->error = EIO;
590 return (NULL);
591 }
592 bcopy(ds->data, &ds->buf[frag_size],
593 total_fid_size - frag_size);
594
595 ds->fid_fragment = 1;
596 } else {
597 total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
598 }
599
600 /*
601 * Update the offset. Align on a 4 byte boundary because the
602 * UDF spec says so.
603 */
604 ds->this_off = ds->off;
605 if (!ds->fid_fragment) {
606 ds->off += (total_fid_size + 3) & ~0x03;
607 } else {
608 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
609 }
610
611 return (fid);
612}
613
614static void
615udf_closedir(struct udf_dirstream *ds)
616{
617
618 if (ds->bp != NULL)
619 brelse(ds->bp);
620
621 if (ds->fid_fragment && ds->buf != NULL)
622 FREE(ds->buf, M_UDFFID);
623
624 uma_zfree(udf_zone_ds, ds);
625}
626
627static int
628udf_readdir(struct vop_readdir_args *a)
629{
630 struct vnode *vp;
631 struct uio *uio;
632 struct dirent dir;
633 struct udf_node *node;
634 struct udf_mnt *udfmp;
635 struct fileid_desc *fid;
636 struct udf_uiodir uiodir;
637 struct udf_dirstream *ds;
638 u_long *cookies = NULL;
639 int ncookies;
640 int error = 0;
641
642 vp = a->a_vp;
643 uio = a->a_uio;
644 node = VTON(vp);
645 udfmp = node->udfmp;
646 uiodir.eofflag = 1;
647
648 if (a->a_ncookies != NULL) {
649 /*
650 * Guess how many entries are needed. If we run out, this
651 * function will be called again and thing will pick up were
652 * it left off.
653 */
654 ncookies = uio->uio_resid / 8;
655 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
656 M_TEMP, M_WAITOK);
657 if (cookies == NULL)
658 return (ENOMEM);
659 uiodir.ncookies = ncookies;
660 uiodir.cookies = cookies;
661 uiodir.acookies = 0;
662 } else {
663 uiodir.cookies = NULL;
664 }
665
666 /*
667 * Iterate through the file id descriptors. Give the parent dir
668 * entry special attention.
669 */
670 ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
671 node->udfmp);
672
673 while ((fid = udf_getfid(ds)) != NULL) {
674
675 /* XXX Should we return an error on a bad fid? */
676 if (udf_checktag(&fid->tag, TAGID_FID)) {
677 printf("Invalid FID tag\n");
678 hexdump(fid, UDF_FID_SIZE, NULL, 0);
679 error = EIO;
680 break;
681 }
682
683 /* Is this a deleted file? */
684 if (fid->file_char & UDF_FILE_CHAR_DEL)
685 continue;
686
687 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
688 /* Do up the '.' and '..' entries. Dummy values are
689 * used for the cookies since the offset here is
690 * usually zero, and NFS doesn't like that value
691 */
692 dir.d_fileno = node->hash_id;
693 dir.d_type = DT_DIR;
694 dir.d_name[0] = '.';
695 dir.d_name[1] = '\0';
696 dir.d_namlen = 1;
697 dir.d_reclen = GENERIC_DIRSIZ(&dir);
698 uiodir.dirent = &dir;
699 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
700 if (error)
701 break;
702
703 dir.d_fileno = udf_getid(&fid->icb);
704 dir.d_type = DT_DIR;
705 dir.d_name[0] = '.';
706 dir.d_name[1] = '.';
707 dir.d_name[2] = '\0';
708 dir.d_namlen = 2;
709 dir.d_reclen = GENERIC_DIRSIZ(&dir);
710 uiodir.dirent = &dir;
711 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
712 } else {
713 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
714 &dir.d_name[0], fid->l_fi, udfmp);
715 dir.d_fileno = udf_getid(&fid->icb);
716 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
717 DT_DIR : DT_UNKNOWN;
718 dir.d_reclen = GENERIC_DIRSIZ(&dir);
719 uiodir.dirent = &dir;
720 error = udf_uiodir(&uiodir, dir.d_reclen, uio,
721 ds->this_off);
722 }
723 if (error) {
724 printf("uiomove returned %d\n", error);
725 break;
726 }
727
728 }
729
730 /* tell the calling layer whether we need to be called again */
731 *a->a_eofflag = uiodir.eofflag;
732 uio->uio_offset = ds->offset + ds->off;
733
734 if (!error)
735 error = ds->error;
736
737 udf_closedir(ds);
738
739 if (a->a_ncookies != NULL) {
740 if (error)
741 FREE(cookies, M_TEMP);
742 else {
743 *a->a_ncookies = uiodir.acookies;
744 *a->a_cookies = cookies;
745 }
746 }
747
748 return (error);
749}
750
751/* Are there any implementations out there that do soft-links? */
752static int
753udf_readlink(struct vop_readlink_args *ap)
754{
755 printf("%s called\n", __func__);
756 return (EOPNOTSUPP);
757}
758
759static int
760udf_strategy(struct vop_strategy_args *a)
761{
762 struct buf *bp;
763 struct vnode *vp;
764 struct udf_node *node;
765 int maxsize;
766 struct bufobj *bo;
767
768 bp = a->a_bp;
769 vp = a->a_vp;
770 node = VTON(vp);
771
772 /* cd9660 has this test reversed, but it seems more logical this way */
773 if (bp->b_blkno != bp->b_lblkno) {
774 /*
775 * Files that are embedded in the fentry don't translate well
776 * to a block number. Reject.
777 */
778 if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
779 &bp->b_lblkno, &maxsize)) {
780 clrbuf(bp);
781 bp->b_blkno = -1;
782 }
783 }
784 if ((long)bp->b_blkno == -1) {
785 bufdone(bp);
786 return (0);
787 }
788 bo = node->udfmp->im_bo;
789 bp->b_iooffset = dbtob(bp->b_blkno);
790 BO_STRATEGY(bo, bp);
791 return (0);
792}
793
794static int
795udf_bmap(struct vop_bmap_args *a)
796{
797 struct udf_node *node;
798 uint32_t max_size;
799 daddr_t lsector;
800 int error;
801
802 node = VTON(a->a_vp);
803
804 if (a->a_bop != NULL)
805 *a->a_bop = &node->udfmp->im_devvp->v_bufobj;
806 if (a->a_bnp == NULL)
807 return (0);
808 if (a->a_runb)
809 *a->a_runb = 0;
810
811 error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector,
812 &max_size);
813 if (error)
814 return (error);
815
816 /* Translate logical to physical sector number */
817 *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
818
819 /* Punt on read-ahead for now */
820 if (a->a_runp)
821 *a->a_runp = 0;
822
823 return (0);
824}
825
826/*
827 * The all powerful VOP_LOOKUP().
828 */
829static int
830udf_lookup(struct vop_cachedlookup_args *a)
831{
832 struct vnode *dvp;
833 struct vnode *tdp = NULL;
834 struct vnode **vpp = a->a_vpp;
835 struct udf_node *node;
836 struct udf_mnt *udfmp;
837 struct fileid_desc *fid = NULL;
838 struct udf_dirstream *ds;
839 struct thread *td;
840 u_long nameiop;
841 u_long flags;
842 char *nameptr;
843 long namelen;
844 ino_t id = 0;
845 int offset, error = 0;
846 int numdirpasses, fsize;
847
848 dvp = a->a_dvp;
849 node = VTON(dvp);
850 udfmp = node->udfmp;
851 nameiop = a->a_cnp->cn_nameiop;
852 flags = a->a_cnp->cn_flags;
853 nameptr = a->a_cnp->cn_nameptr;
854 namelen = a->a_cnp->cn_namelen;
855 fsize = le64toh(node->fentry->inf_len);
856 td = a->a_cnp->cn_thread;
857
858 /*
859 * If this is a LOOKUP and we've already partially searched through
860 * the directory, pick up where we left off and flag that the
861 * directory may need to be searched twice. For a full description,
862 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
863 */
864 if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
865 offset = 0;
866 numdirpasses = 1;
867 } else {
868 offset = node->diroff;
869 numdirpasses = 2;
870 nchstats.ncs_2passes++;
871 }
872
873lookloop:
874 ds = udf_opendir(node, offset, fsize, udfmp);
875
876 while ((fid = udf_getfid(ds)) != NULL) {
877
878 /* XXX Should we return an error on a bad fid? */
879 if (udf_checktag(&fid->tag, TAGID_FID)) {
880 printf("udf_lookup: Invalid tag\n");
881 error = EIO;
882 break;
883 }
884
885 /* Is this a deleted file? */
886 if (fid->file_char & UDF_FILE_CHAR_DEL)
887 continue;
888
889 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
890 if (flags & ISDOTDOT) {
891 id = udf_getid(&fid->icb);
892 break;
893 }
894 } else {
895 if (!(udf_cmpname(&fid->data[fid->l_iu],
896 nameptr, fid->l_fi, namelen, udfmp))) {
897 id = udf_getid(&fid->icb);
898 break;
899 }
900 }
901 }
902
903 if (!error)
904 error = ds->error;
905
906 /* XXX Bail out here? */
907 if (error) {
908 udf_closedir(ds);
909 return (error);
910 }
911
912 /* Did we have a match? */
913 if (id) {
914 if (flags & ISDOTDOT)
915 VOP_UNLOCK(dvp, 0, a->a_cnp->cn_thread);
916 error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
917 vn_lock(dvp, LK_EXCLUSIVE|LK_RETRY, a->a_cnp->cn_thread);
917 if (!error) {
918 /*
919 * Remember where this entry was if it's the final
920 * component.
921 */
922 if ((flags & ISLASTCN) && nameiop == LOOKUP)
923 node->diroff = ds->offset + ds->off;
924 if (numdirpasses == 2)
925 nchstats.ncs_pass2++;
926 *vpp = tdp;
927 /* Put this entry in the cache */
928 if (flags & MAKEENTRY)
929 cache_enter(dvp, *vpp, a->a_cnp);
918 if (!error) {
919 /*
920 * Remember where this entry was if it's the final
921 * component.
922 */
923 if ((flags & ISLASTCN) && nameiop == LOOKUP)
924 node->diroff = ds->offset + ds->off;
925 if (numdirpasses == 2)
926 nchstats.ncs_pass2++;
927 *vpp = tdp;
928 /* Put this entry in the cache */
929 if (flags & MAKEENTRY)
930 cache_enter(dvp, *vpp, a->a_cnp);
930 } else if (flags & ISDOTDOT)
931 vn_lock(dvp, LK_EXCLUSIVE|LK_RETRY,
932 a->a_cnp->cn_thread);
931 }
933 } else {
934 /* Name wasn't found on this pass. Do another pass? */
935 if (numdirpasses == 2) {
936 numdirpasses--;
937 offset = 0;
938 udf_closedir(ds);
939 goto lookloop;
940 }
941
942 /* Enter name into cache as non-existant */
943 if (flags & MAKEENTRY)
944 cache_enter(dvp, *vpp, a->a_cnp);
945
946 if ((flags & ISLASTCN) &&
947 (nameiop == CREATE || nameiop == RENAME)) {
948 error = EROFS;
949 } else {
950 error = ENOENT;
951 }
952 }
953
954 udf_closedir(ds);
955 return (error);
956}
957
958static int
959udf_reclaim(struct vop_reclaim_args *a)
960{
961 struct vnode *vp;
962 struct udf_node *unode;
963
964 vp = a->a_vp;
965 unode = VTON(vp);
966
967 if (unode != NULL) {
968 vfs_hash_remove(vp);
969
970 if (unode->fentry != NULL)
971 FREE(unode->fentry, M_UDFFENTRY);
972 uma_zfree(udf_zone_node, unode);
973 vp->v_data = NULL;
974 }
975 vnode_destroy_vobject(vp);
976
977 return (0);
978}
979
980/*
981 * Read the block and then set the data pointer to correspond with the
982 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
983 * to the number of bytes pointed to. If 'size' is zero, try to read in a
984 * whole extent.
985 *
986 * Note that *bp may be assigned error or not.
987 *
988 */
989static int
990udf_readatoffset(struct udf_node *node, int *size, off_t offset,
991 struct buf **bp, uint8_t **data)
992{
993 struct udf_mnt *udfmp;
994 struct file_entry *fentry = NULL;
995 struct buf *bp1;
996 uint32_t max_size;
997 daddr_t sector;
998 int error;
999
1000 udfmp = node->udfmp;
1001
1002 *bp = NULL;
1003 error = udf_bmap_internal(node, offset, &sector, &max_size);
1004 if (error == UDF_INVALID_BMAP) {
1005 /*
1006 * This error means that the file *data* is stored in the
1007 * allocation descriptor field of the file entry.
1008 */
1009 fentry = node->fentry;
1010 *data = &fentry->data[le32toh(fentry->l_ea)];
1011 *size = le32toh(fentry->l_ad);
1012 return (0);
1013 } else if (error != 0) {
1014 return (error);
1015 }
1016
1017 /* Adjust the size so that it is within range */
1018 if (*size == 0 || *size > max_size)
1019 *size = max_size;
1020 *size = min(*size, MAXBSIZE);
1021
1022 if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
1023 printf("warning: udf_readlblks returned error %d\n", error);
1024 /* note: *bp may be non-NULL */
1025 return (error);
1026 }
1027
1028 bp1 = *bp;
1029 *data = (uint8_t *)&bp1->b_data[offset % udfmp->bsize];
1030 return (0);
1031}
1032
1033/*
1034 * Translate a file offset into a logical block and then into a physical
1035 * block.
1036 */
1037static int
1038udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector,
1039 uint32_t *max_size)
1040{
1041 struct udf_mnt *udfmp;
1042 struct file_entry *fentry;
1043 void *icb;
1044 struct icb_tag *tag;
1045 uint32_t icblen = 0;
1046 daddr_t lsector;
1047 int ad_offset, ad_num = 0;
1048 int i, p_offset;
1049
1050 udfmp = node->udfmp;
1051 fentry = node->fentry;
1052 tag = &fentry->icbtag;
1053
1054 switch (le16toh(tag->strat_type)) {
1055 case 4:
1056 break;
1057
1058 case 4096:
1059 printf("Cannot deal with strategy4096 yet!\n");
1060 return (ENODEV);
1061
1062 default:
1063 printf("Unknown strategy type %d\n", tag->strat_type);
1064 return (ENODEV);
1065 }
1066
1067 switch (le16toh(tag->flags) & 0x7) {
1068 case 0:
1069 /*
1070 * The allocation descriptor field is filled with short_ad's.
1071 * If the offset is beyond the current extent, look for the
1072 * next extent.
1073 */
1074 do {
1075 offset -= icblen;
1076 ad_offset = sizeof(struct short_ad) * ad_num;
1077 if (ad_offset > le32toh(fentry->l_ad)) {
1078 printf("File offset out of bounds\n");
1079 return (EINVAL);
1080 }
1081 icb = GETICB(short_ad, fentry,
1082 le32toh(fentry->l_ea) + ad_offset);
1083 icblen = GETICBLEN(short_ad, icb);
1084 ad_num++;
1085 } while(offset >= icblen);
1086
1087 lsector = (offset >> udfmp->bshift) +
1088 ((struct short_ad *)(icb))->pos;
1089
1090 *max_size = GETICBLEN(short_ad, icb);
1091
1092 break;
1093 case 1:
1094 /*
1095 * The allocation descriptor field is filled with long_ad's
1096 * If the offset is beyond the current extent, look for the
1097 * next extent.
1098 */
1099 do {
1100 offset -= icblen;
1101 ad_offset = sizeof(struct long_ad) * ad_num;
1102 if (ad_offset > le32toh(fentry->l_ad)) {
1103 printf("File offset out of bounds\n");
1104 return (EINVAL);
1105 }
1106 icb = GETICB(long_ad, fentry,
1107 le32toh(fentry->l_ea) + ad_offset);
1108 icblen = GETICBLEN(long_ad, icb);
1109 ad_num++;
1110 } while(offset >= icblen);
1111
1112 lsector = (offset >> udfmp->bshift) +
1113 le32toh(((struct long_ad *)(icb))->loc.lb_num);
1114
1115 *max_size = GETICBLEN(long_ad, icb);
1116
1117 break;
1118 case 3:
1119 /*
1120 * This type means that the file *data* is stored in the
1121 * allocation descriptor field of the file entry.
1122 */
1123 *max_size = 0;
1124 *sector = node->hash_id + udfmp->part_start;
1125
1126 return (UDF_INVALID_BMAP);
1127 case 2:
1128 /* DirectCD does not use extended_ad's */
1129 default:
1130 printf("Unsupported allocation descriptor %d\n",
1131 tag->flags & 0x7);
1132 return (ENODEV);
1133 }
1134
1135 *sector = lsector + udfmp->part_start;
1136
1137 /*
1138 * Check the sparing table. Each entry represents the beginning of
1139 * a packet.
1140 */
1141 if (udfmp->s_table != NULL) {
1142 for (i = 0; i< udfmp->s_table_entries; i++) {
1143 p_offset =
1144 lsector - le32toh(udfmp->s_table->entries[i].org);
1145 if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1146 *sector =
1147 le32toh(udfmp->s_table->entries[i].map) +
1148 p_offset;
1149 break;
1150 }
1151 }
1152 }
1153
1154 return (0);
1155}
932 } else {
933 /* Name wasn't found on this pass. Do another pass? */
934 if (numdirpasses == 2) {
935 numdirpasses--;
936 offset = 0;
937 udf_closedir(ds);
938 goto lookloop;
939 }
940
941 /* Enter name into cache as non-existant */
942 if (flags & MAKEENTRY)
943 cache_enter(dvp, *vpp, a->a_cnp);
944
945 if ((flags & ISLASTCN) &&
946 (nameiop == CREATE || nameiop == RENAME)) {
947 error = EROFS;
948 } else {
949 error = ENOENT;
950 }
951 }
952
953 udf_closedir(ds);
954 return (error);
955}
956
957static int
958udf_reclaim(struct vop_reclaim_args *a)
959{
960 struct vnode *vp;
961 struct udf_node *unode;
962
963 vp = a->a_vp;
964 unode = VTON(vp);
965
966 if (unode != NULL) {
967 vfs_hash_remove(vp);
968
969 if (unode->fentry != NULL)
970 FREE(unode->fentry, M_UDFFENTRY);
971 uma_zfree(udf_zone_node, unode);
972 vp->v_data = NULL;
973 }
974 vnode_destroy_vobject(vp);
975
976 return (0);
977}
978
979/*
980 * Read the block and then set the data pointer to correspond with the
981 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
982 * to the number of bytes pointed to. If 'size' is zero, try to read in a
983 * whole extent.
984 *
985 * Note that *bp may be assigned error or not.
986 *
987 */
988static int
989udf_readatoffset(struct udf_node *node, int *size, off_t offset,
990 struct buf **bp, uint8_t **data)
991{
992 struct udf_mnt *udfmp;
993 struct file_entry *fentry = NULL;
994 struct buf *bp1;
995 uint32_t max_size;
996 daddr_t sector;
997 int error;
998
999 udfmp = node->udfmp;
1000
1001 *bp = NULL;
1002 error = udf_bmap_internal(node, offset, &sector, &max_size);
1003 if (error == UDF_INVALID_BMAP) {
1004 /*
1005 * This error means that the file *data* is stored in the
1006 * allocation descriptor field of the file entry.
1007 */
1008 fentry = node->fentry;
1009 *data = &fentry->data[le32toh(fentry->l_ea)];
1010 *size = le32toh(fentry->l_ad);
1011 return (0);
1012 } else if (error != 0) {
1013 return (error);
1014 }
1015
1016 /* Adjust the size so that it is within range */
1017 if (*size == 0 || *size > max_size)
1018 *size = max_size;
1019 *size = min(*size, MAXBSIZE);
1020
1021 if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
1022 printf("warning: udf_readlblks returned error %d\n", error);
1023 /* note: *bp may be non-NULL */
1024 return (error);
1025 }
1026
1027 bp1 = *bp;
1028 *data = (uint8_t *)&bp1->b_data[offset % udfmp->bsize];
1029 return (0);
1030}
1031
1032/*
1033 * Translate a file offset into a logical block and then into a physical
1034 * block.
1035 */
1036static int
1037udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector,
1038 uint32_t *max_size)
1039{
1040 struct udf_mnt *udfmp;
1041 struct file_entry *fentry;
1042 void *icb;
1043 struct icb_tag *tag;
1044 uint32_t icblen = 0;
1045 daddr_t lsector;
1046 int ad_offset, ad_num = 0;
1047 int i, p_offset;
1048
1049 udfmp = node->udfmp;
1050 fentry = node->fentry;
1051 tag = &fentry->icbtag;
1052
1053 switch (le16toh(tag->strat_type)) {
1054 case 4:
1055 break;
1056
1057 case 4096:
1058 printf("Cannot deal with strategy4096 yet!\n");
1059 return (ENODEV);
1060
1061 default:
1062 printf("Unknown strategy type %d\n", tag->strat_type);
1063 return (ENODEV);
1064 }
1065
1066 switch (le16toh(tag->flags) & 0x7) {
1067 case 0:
1068 /*
1069 * The allocation descriptor field is filled with short_ad's.
1070 * If the offset is beyond the current extent, look for the
1071 * next extent.
1072 */
1073 do {
1074 offset -= icblen;
1075 ad_offset = sizeof(struct short_ad) * ad_num;
1076 if (ad_offset > le32toh(fentry->l_ad)) {
1077 printf("File offset out of bounds\n");
1078 return (EINVAL);
1079 }
1080 icb = GETICB(short_ad, fentry,
1081 le32toh(fentry->l_ea) + ad_offset);
1082 icblen = GETICBLEN(short_ad, icb);
1083 ad_num++;
1084 } while(offset >= icblen);
1085
1086 lsector = (offset >> udfmp->bshift) +
1087 ((struct short_ad *)(icb))->pos;
1088
1089 *max_size = GETICBLEN(short_ad, icb);
1090
1091 break;
1092 case 1:
1093 /*
1094 * The allocation descriptor field is filled with long_ad's
1095 * If the offset is beyond the current extent, look for the
1096 * next extent.
1097 */
1098 do {
1099 offset -= icblen;
1100 ad_offset = sizeof(struct long_ad) * ad_num;
1101 if (ad_offset > le32toh(fentry->l_ad)) {
1102 printf("File offset out of bounds\n");
1103 return (EINVAL);
1104 }
1105 icb = GETICB(long_ad, fentry,
1106 le32toh(fentry->l_ea) + ad_offset);
1107 icblen = GETICBLEN(long_ad, icb);
1108 ad_num++;
1109 } while(offset >= icblen);
1110
1111 lsector = (offset >> udfmp->bshift) +
1112 le32toh(((struct long_ad *)(icb))->loc.lb_num);
1113
1114 *max_size = GETICBLEN(long_ad, icb);
1115
1116 break;
1117 case 3:
1118 /*
1119 * This type means that the file *data* is stored in the
1120 * allocation descriptor field of the file entry.
1121 */
1122 *max_size = 0;
1123 *sector = node->hash_id + udfmp->part_start;
1124
1125 return (UDF_INVALID_BMAP);
1126 case 2:
1127 /* DirectCD does not use extended_ad's */
1128 default:
1129 printf("Unsupported allocation descriptor %d\n",
1130 tag->flags & 0x7);
1131 return (ENODEV);
1132 }
1133
1134 *sector = lsector + udfmp->part_start;
1135
1136 /*
1137 * Check the sparing table. Each entry represents the beginning of
1138 * a packet.
1139 */
1140 if (udfmp->s_table != NULL) {
1141 for (i = 0; i< udfmp->s_table_entries; i++) {
1142 p_offset =
1143 lsector - le32toh(udfmp->s_table->entries[i].org);
1144 if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1145 *sector =
1146 le32toh(udfmp->s_table->entries[i].map) +
1147 p_offset;
1148 break;
1149 }
1150 }
1151 }
1152
1153 return (0);
1154}