udf_subr.c revision 1.11.2.1 1 /* $NetBSD: udf_subr.c,v 1.11.2.1 2006/08/24 12:44:26 tron Exp $ */
2
3 /*
4 * Copyright (c) 2006 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the
18 * NetBSD Project. See http://www.NetBSD.org/ for
19 * information about NetBSD.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 __RCSID("$NetBSD: udf_subr.c,v 1.11.2.1 2006/08/24 12:44:26 tron Exp $");
40 #endif /* not lint */
41
42
43 #if defined(_KERNEL_OPT)
44 #include "opt_quota.h"
45 #include "opt_compat_netbsd.h"
46 #endif
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/sysctl.h>
51 #include <sys/namei.h>
52 #include <sys/proc.h>
53 #include <sys/kernel.h>
54 #include <sys/vnode.h>
55 #include <miscfs/genfs/genfs_node.h>
56 #include <sys/mount.h>
57 #include <sys/buf.h>
58 #include <sys/file.h>
59 #include <sys/device.h>
60 #include <sys/disklabel.h>
61 #include <sys/ioctl.h>
62 #include <sys/malloc.h>
63 #include <sys/dirent.h>
64 #include <sys/stat.h>
65 #include <sys/conf.h>
66 #include <sys/kauth.h>
67
68 #include <fs/udf/ecma167-udf.h>
69 #include <fs/udf/udf_mount.h>
70
71 #include "udf.h"
72 #include "udf_subr.h"
73 #include "udf_bswap.h"
74
75
76 #define VTOI(vnode) ((struct udf_node *) vnode->v_data)
77
78
79 /* predefines */
80
81
82 #if 0
83 {
84 int i, j, dlen;
85 uint8_t *blob;
86
87 blob = (uint8_t *) fid;
88 dlen = file_size - (*offset);
89
90 printf("blob = %p\n", blob);
91 printf("dump of %d bytes\n", dlen);
92
93 for (i = 0; i < dlen; i+ = 16) {
94 printf("%04x ", i);
95 for (j = 0; j < 16; j++) {
96 if (i+j < dlen) {
97 printf("%02x ", blob[i+j]);
98 } else {
99 printf(" ");
100 }
101 }
102 for (j = 0; j < 16; j++) {
103 if (i+j < dlen) {
104 if (blob[i+j]>32 && blob[i+j]! = 127) {
105 printf("%c", blob[i+j]);
106 } else {
107 printf(".");
108 }
109 }
110 }
111 printf("\n");
112 }
113 printf("\n");
114 }
115 Debugger();
116 #endif
117
118
119 /* --------------------------------------------------------------------- */
120
121 /* STUB */
122
123 static int
124 udf_bread(struct udf_mount *ump, uint32_t sector, struct buf **bpp)
125 {
126 int sector_size = ump->discinfo.sector_size;
127 int blks = sector_size / DEV_BSIZE;
128
129 /* NOTE bread() checks if block is in cache or not */
130 return bread(ump->devvp, sector*blks, sector_size, NOCRED, bpp);
131 }
132
133
134 /* --------------------------------------------------------------------- */
135
136 /*
137 * Check if the blob starts with a good UDF tag. Tags are protected by a
138 * checksum over the reader except one byte at position 4 that is the checksum
139 * itself.
140 */
141
142 int
143 udf_check_tag(void *blob)
144 {
145 struct desc_tag *tag = blob;
146 uint8_t *pos, sum, cnt;
147
148 /* check TAG header checksum */
149 pos = (uint8_t *) tag;
150 sum = 0;
151
152 for(cnt = 0; cnt < 16; cnt++) {
153 if (cnt != 4)
154 sum += *pos;
155 pos++;
156 }
157 if (sum != tag->cksum) {
158 /* bad tag header checksum; this is not a valid tag */
159 return EINVAL;
160 }
161
162 return 0;
163 }
164
165 /* --------------------------------------------------------------------- */
166
167 /*
168 * check tag payload will check descriptor CRC as specified.
169 * If the descriptor is too short, it will return EIO otherwise EINVAL.
170 */
171
172 int
173 udf_check_tag_payload(void *blob, uint32_t max_length)
174 {
175 struct desc_tag *tag = blob;
176 uint16_t crc, crc_len;
177
178 crc_len = udf_rw16(tag->desc_crc_len);
179
180 /* check payload CRC if applicable */
181 if (crc_len == 0)
182 return 0;
183
184 if (crc_len > max_length)
185 return EIO;
186
187 crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, crc_len);
188 if (crc != udf_rw16(tag->desc_crc)) {
189 /* bad payload CRC; this is a broken tag */
190 return EINVAL;
191 }
192
193 return 0;
194 }
195
196 /* --------------------------------------------------------------------- */
197
198 int
199 udf_validate_tag_sum(void *blob)
200 {
201 struct desc_tag *tag = blob;
202 uint8_t *pos, sum, cnt;
203
204 /* calculate TAG header checksum */
205 pos = (uint8_t *) tag;
206 sum = 0;
207
208 for(cnt = 0; cnt < 16; cnt++) {
209 if (cnt != 4) sum += *pos;
210 pos++;
211 }
212 tag->cksum = sum; /* 8 bit */
213
214 return 0;
215 }
216
217 /* --------------------------------------------------------------------- */
218
219 /* assumes sector number of descriptor to be saved already present */
220
221 int
222 udf_validate_tag_and_crc_sums(void *blob)
223 {
224 struct desc_tag *tag = blob;
225 uint8_t *btag = (uint8_t *) tag;
226 uint16_t crc, crc_len;
227
228 crc_len = udf_rw16(tag->desc_crc_len);
229
230 /* check payload CRC if applicable */
231 if (crc_len > 0) {
232 crc = udf_cksum(btag + UDF_DESC_TAG_LENGTH, crc_len);
233 tag->desc_crc = udf_rw16(crc);
234 }
235
236 /* calculate TAG header checksum */
237 return udf_validate_tag_sum(blob);
238 }
239
240 /* --------------------------------------------------------------------- */
241
242 /*
243 * XXX note the different semantics from udfclient: for FIDs it still rounds
244 * up to sectors. Use udf_fidsize() for a correct length.
245 */
246
247 int
248 udf_tagsize(union dscrptr *dscr, uint32_t udf_sector_size)
249 {
250 uint32_t size, tag_id, num_secs, elmsz;
251
252 tag_id = udf_rw16(dscr->tag.id);
253
254 switch (tag_id) {
255 case TAGID_LOGVOL :
256 size = sizeof(struct logvol_desc) - 1;
257 size += udf_rw32(dscr->lvd.mt_l);
258 break;
259 case TAGID_UNALLOC_SPACE :
260 elmsz = sizeof(struct extent_ad);
261 size = sizeof(struct unalloc_sp_desc) - elmsz;
262 size += udf_rw32(dscr->usd.alloc_desc_num) * elmsz;
263 break;
264 case TAGID_FID :
265 size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu);
266 size = (size + 3) & ~3;
267 break;
268 case TAGID_LOGVOL_INTEGRITY :
269 size = sizeof(struct logvol_int_desc) - sizeof(uint32_t);
270 size += udf_rw32(dscr->lvid.l_iu);
271 size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t));
272 break;
273 case TAGID_SPACE_BITMAP :
274 size = sizeof(struct space_bitmap_desc) - 1;
275 size += udf_rw32(dscr->sbd.num_bytes);
276 break;
277 case TAGID_SPARING_TABLE :
278 elmsz = sizeof(struct spare_map_entry);
279 size = sizeof(struct udf_sparing_table) - elmsz;
280 size += udf_rw16(dscr->spt.rt_l) * elmsz;
281 break;
282 case TAGID_FENTRY :
283 size = sizeof(struct file_entry);
284 size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1;
285 break;
286 case TAGID_EXTFENTRY :
287 size = sizeof(struct extfile_entry);
288 size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1;
289 break;
290 case TAGID_FSD :
291 size = sizeof(struct fileset_desc);
292 break;
293 default :
294 size = sizeof(union dscrptr);
295 break;
296 }
297
298 if ((size == 0) || (udf_sector_size == 0)) return 0;
299
300 /* round up in sectors */
301 num_secs = (size + udf_sector_size -1) / udf_sector_size;
302 return num_secs * udf_sector_size;
303 }
304
305
306 static int
307 udf_fidsize(struct fileid_desc *fid, uint32_t udf_sector_size)
308 {
309 uint32_t size;
310
311 if (udf_rw16(fid->tag.id) != TAGID_FID)
312 panic("got udf_fidsize on non FID\n");
313
314 size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
315 size = (size + 3) & ~3;
316
317 return size;
318 }
319
320 /* --------------------------------------------------------------------- */
321
322 /*
323 * Problem with read_descriptor are long descriptors spanning more than one
324 * sector. Luckily long descriptors can't be in `logical space'.
325 *
326 * Size of allocated piece is returned in multiple of sector size due to
327 * udf_calc_udf_malloc_size().
328 */
329
330 int
331 udf_read_descriptor(struct udf_mount *ump, uint32_t sector,
332 struct malloc_type *mtype, union dscrptr **dstp)
333 {
334 union dscrptr *src, *dst;
335 struct buf *bp;
336 uint8_t *pos;
337 int blks, blk, dscrlen;
338 int i, error, sector_size;
339
340 sector_size = ump->discinfo.sector_size;
341
342 *dstp = dst = NULL;
343 dscrlen = sector_size;
344
345 /* read initial piece */
346 error = udf_bread(ump, sector, &bp);
347 DPRINTFIF(DESCRIPTOR, error, ("read error (%d)\n", error));
348
349 if (!error) {
350 /* check if its a valid tag */
351 error = udf_check_tag(bp->b_data);
352 if (error) {
353 /* check if its an empty block */
354 pos = bp->b_data;
355 for (i = 0; i < sector_size; i++, pos++) {
356 if (*pos) break;
357 }
358 if (i == sector_size) {
359 /* return no error but with no dscrptr */
360 /* dispose first block */
361 brelse(bp);
362 return 0;
363 }
364 }
365 }
366 DPRINTFIF(DESCRIPTOR, error, ("bad tag checksum\n"));
367 if (!error) {
368 src = (union dscrptr *) bp->b_data;
369 dscrlen = udf_tagsize(src, sector_size);
370 dst = malloc(dscrlen, mtype, M_WAITOK);
371 memcpy(dst, src, dscrlen);
372 }
373 /* dispose first block */
374 bp->b_flags |= B_AGE;
375 brelse(bp);
376
377 if (!error && (dscrlen > sector_size)) {
378 DPRINTF(DESCRIPTOR, ("multi block descriptor read\n"));
379 /*
380 * Read the rest of descriptor. Since it is only used at mount
381 * time its overdone to define and use a specific udf_breadn
382 * for this alone.
383 */
384 blks = (dscrlen + sector_size -1) / sector_size;
385 for (blk = 1; blk < blks; blk++) {
386 error = udf_bread(ump, sector + blk, &bp);
387 if (error) {
388 brelse(bp);
389 break;
390 }
391 pos = (uint8_t *) dst + blk*sector_size;
392 memcpy(pos, bp->b_data, sector_size);
393
394 /* dispose block */
395 bp->b_flags |= B_AGE;
396 brelse(bp);
397 }
398 DPRINTFIF(DESCRIPTOR, error, ("read error on multi (%d)\n",
399 error));
400 }
401 if (!error) {
402 error = udf_check_tag_payload(dst, dscrlen);
403 DPRINTFIF(DESCRIPTOR, error, ("bad payload check sum\n"));
404 }
405 if (error && dst) {
406 free(dst, mtype);
407 dst = NULL;
408 }
409 *dstp = dst;
410
411 return error;
412 }
413
414 /* --------------------------------------------------------------------- */
415 #ifdef DEBUG
416 static void
417 udf_dump_discinfo(struct udf_mount *ump)
418 {
419 char bits[128];
420 struct mmc_discinfo *di = &ump->discinfo;
421
422 if ((udf_verbose & UDF_DEBUG_VOLUMES) == 0)
423 return;
424
425 printf("Device/media info :\n");
426 printf("\tMMC profile 0x%02x\n", di->mmc_profile);
427 printf("\tderived class %d\n", di->mmc_class);
428 printf("\tsector size %d\n", di->sector_size);
429 printf("\tdisc state %d\n", di->disc_state);
430 printf("\tlast ses state %d\n", di->last_session_state);
431 printf("\tbg format state %d\n", di->bg_format_state);
432 printf("\tfrst track %d\n", di->first_track);
433 printf("\tfst on last ses %d\n", di->first_track_last_session);
434 printf("\tlst on last ses %d\n", di->last_track_last_session);
435 printf("\tlink block penalty %d\n", di->link_block_penalty);
436 bitmask_snprintf(di->disc_flags, MMC_DFLAGS_FLAGBITS, bits,
437 sizeof(bits));
438 printf("\tdisc flags %s\n", bits);
439 printf("\tdisc id %x\n", di->disc_id);
440 printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode);
441
442 printf("\tnum sessions %d\n", di->num_sessions);
443 printf("\tnum tracks %d\n", di->num_tracks);
444
445 bitmask_snprintf(di->mmc_cur, MMC_CAP_FLAGBITS, bits, sizeof(bits));
446 printf("\tcapabilities cur %s\n", bits);
447 bitmask_snprintf(di->mmc_cap, MMC_CAP_FLAGBITS, bits, sizeof(bits));
448 printf("\tcapabilities cap %s\n", bits);
449 }
450 #else
451 #define udf_dump_discinfo(a);
452 #endif
453
454 /* not called often */
455 int
456 udf_update_discinfo(struct udf_mount *ump)
457 {
458 struct vnode *devvp = ump->devvp;
459 struct partinfo dpart;
460 struct mmc_discinfo *di;
461 int error;
462
463 DPRINTF(VOLUMES, ("read/update disc info\n"));
464 di = &ump->discinfo;
465 memset(di, 0, sizeof(struct mmc_discinfo));
466
467 /* check if we're on a MMC capable device, i.e. CD/DVD */
468 error = VOP_IOCTL(devvp, MMCGETDISCINFO, di, FKIOCTL, NOCRED, NULL);
469 if (error == 0) {
470 udf_dump_discinfo(ump);
471 return 0;
472 }
473
474 /* disc partition support */
475 error = VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, NOCRED, NULL);
476 if (error)
477 return ENODEV;
478
479 /* set up a disc info profile for partitions */
480 di->mmc_profile = 0x01; /* disc type */
481 di->mmc_class = MMC_CLASS_DISC;
482 di->disc_state = MMC_STATE_CLOSED;
483 di->last_session_state = MMC_STATE_CLOSED;
484 di->bg_format_state = MMC_BGFSTATE_COMPLETED;
485 di->link_block_penalty = 0;
486
487 di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE |
488 MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE;
489 di->mmc_cap = di->mmc_cur;
490 di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
491
492 /* TODO problem with last_possible_lba on resizable VND; request */
493 di->last_possible_lba = dpart.part->p_size;
494 di->sector_size = dpart.disklab->d_secsize;
495 di->blockingnr = 1;
496
497 di->num_sessions = 1;
498 di->num_tracks = 1;
499
500 di->first_track = 1;
501 di->first_track_last_session = di->last_track_last_session = 1;
502
503 udf_dump_discinfo(ump);
504 return 0;
505 }
506
507 /* --------------------------------------------------------------------- */
508
509 int
510 udf_update_trackinfo(struct udf_mount *ump, struct mmc_trackinfo *ti)
511 {
512 struct vnode *devvp = ump->devvp;
513 struct mmc_discinfo *di = &ump->discinfo;
514 int error, class;
515
516 DPRINTF(VOLUMES, ("read track info\n"));
517
518 class = di->mmc_class;
519 if (class != MMC_CLASS_DISC) {
520 /* tracknr specified in struct ti */
521 error = VOP_IOCTL(devvp, MMCGETTRACKINFO, ti, FKIOCTL,
522 NOCRED, NULL);
523 return error;
524 }
525
526 /* disc partition support */
527 if (ti->tracknr != 1)
528 return EIO;
529
530 /* create fake ti (TODO check for resized vnds) */
531 ti->sessionnr = 1;
532
533 ti->track_mode = 0; /* XXX */
534 ti->data_mode = 0; /* XXX */
535 ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
536
537 ti->track_start = 0;
538 ti->packet_size = 1;
539
540 /* TODO support for resizable vnd */
541 ti->track_size = di->last_possible_lba;
542 ti->next_writable = di->last_possible_lba;
543 ti->last_recorded = ti->next_writable;
544 ti->free_blocks = 0;
545
546 return 0;
547 }
548
549 /* --------------------------------------------------------------------- */
550
551 /* track/session searching for mounting */
552
553 static int
554 udf_search_tracks(struct udf_mount *ump, struct udf_args *args,
555 int *first_tracknr, int *last_tracknr)
556 {
557 struct mmc_trackinfo trackinfo;
558 uint32_t tracknr, start_track, num_tracks;
559 int error;
560
561 /* if negative, sessionnr is relative to last session */
562 if (args->sessionnr < 0) {
563 args->sessionnr += ump->discinfo.num_sessions;
564 /* sanity */
565 if (args->sessionnr < 0)
566 args->sessionnr = 0;
567 }
568
569 /* sanity */
570 if (args->sessionnr > ump->discinfo.num_sessions)
571 args->sessionnr = ump->discinfo.num_sessions;
572
573 /* search the tracks for this session, zero session nr indicates last */
574 if (args->sessionnr == 0) {
575 args->sessionnr = ump->discinfo.num_sessions;
576 if (ump->discinfo.last_session_state == MMC_STATE_EMPTY) {
577 args->sessionnr--;
578 }
579 }
580
581 /* search the first and last track of the specified session */
582 num_tracks = ump->discinfo.num_tracks;
583 start_track = ump->discinfo.first_track;
584
585 /* search for first track of this session */
586 for (tracknr = start_track; tracknr <= num_tracks; tracknr++) {
587 /* get track info */
588 trackinfo.tracknr = tracknr;
589 error = udf_update_trackinfo(ump, &trackinfo);
590 if (error)
591 return error;
592
593 if (trackinfo.sessionnr == args->sessionnr)
594 break;
595 }
596 *first_tracknr = tracknr;
597
598 /* search for last track of this session */
599 for (;tracknr <= num_tracks; tracknr++) {
600 /* get track info */
601 trackinfo.tracknr = tracknr;
602 error = udf_update_trackinfo(ump, &trackinfo);
603 if (error || (trackinfo.sessionnr != args->sessionnr)) {
604 tracknr--;
605 break;
606 }
607 }
608 if (tracknr > num_tracks)
609 tracknr--;
610
611 *last_tracknr = tracknr;
612
613 assert(*last_tracknr >= *first_tracknr);
614 return 0;
615 }
616
617 /* --------------------------------------------------------------------- */
618
619 static int
620 udf_read_anchor(struct udf_mount *ump, uint32_t sector, struct anchor_vdp **dst)
621 {
622 int error;
623
624 error = udf_read_descriptor(ump, sector, M_UDFVOLD,
625 (union dscrptr **) dst);
626 if (!error) {
627 /* blank terminator blocks are not allowed here */
628 if (*dst == NULL)
629 return ENOENT;
630 if (udf_rw16((*dst)->tag.id) != TAGID_ANCHOR) {
631 error = ENOENT;
632 free(*dst, M_UDFVOLD);
633 *dst = NULL;
634 DPRINTF(VOLUMES, ("Not an anchor\n"));
635 }
636 }
637
638 return error;
639 }
640
641
642 int
643 udf_read_anchors(struct udf_mount *ump, struct udf_args *args)
644 {
645 struct mmc_trackinfo first_track;
646 struct mmc_trackinfo last_track;
647 struct anchor_vdp **anchorsp;
648 uint32_t track_start;
649 uint32_t track_end;
650 uint32_t positions[4];
651 int first_tracknr, last_tracknr;
652 int error, anch, ok, first_anchor;
653
654 /* search the first and last track of the specified session */
655 error = udf_search_tracks(ump, args, &first_tracknr, &last_tracknr);
656 if (!error) {
657 first_track.tracknr = first_tracknr;
658 error = udf_update_trackinfo(ump, &first_track);
659 }
660 if (!error) {
661 last_track.tracknr = last_tracknr;
662 error = udf_update_trackinfo(ump, &last_track);
663 }
664 if (error) {
665 printf("UDF mount: reading disc geometry failed\n");
666 return 0;
667 }
668
669 track_start = first_track.track_start;
670
671 /* `end' is not as straitforward as start. */
672 track_end = last_track.track_start
673 + last_track.track_size - last_track.free_blocks - 1;
674
675 if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
676 /* end of track is not straitforward here */
677 if (last_track.flags & MMC_TRACKINFO_LRA_VALID)
678 track_end = last_track.last_recorded;
679 else if (last_track.flags & MMC_TRACKINFO_NWA_VALID)
680 track_end = last_track.next_writable
681 - ump->discinfo.link_block_penalty;
682 }
683
684 /* its no use reading a blank track */
685 first_anchor = 0;
686 if (first_track.flags & MMC_TRACKINFO_BLANK)
687 first_anchor = 1;
688
689 /* read anchors start+256, start+512, end-256, end */
690 positions[0] = track_start+256;
691 positions[1] = track_end-256;
692 positions[2] = track_end;
693 positions[3] = track_start+512; /* [UDF 2.60/6.11.2] */
694 /* XXX shouldn't +512 be prefered above +256 for compat with Roxio CD */
695
696 ok = 0;
697 anchorsp = ump->anchors;
698 for (anch = first_anchor; anch < 4; anch++) {
699 DPRINTF(VOLUMES, ("Read anchor %d at sector %d\n", anch,
700 positions[anch]));
701 error = udf_read_anchor(ump, positions[anch], anchorsp);
702 if (!error) {
703 anchorsp++;
704 ok++;
705 }
706 }
707
708 /* VATs are only recorded on sequential media, but initialise */
709 ump->first_possible_vat_location = track_start + 256 + 1;
710 ump->last_possible_vat_location = track_end;
711
712 return ok;
713 }
714
715 /* --------------------------------------------------------------------- */
716
717 /* we dont try to be smart; we just record the parts */
718 #define UDF_UPDATE_DSCR(name, dscr) \
719 if (name) \
720 free(name, M_UDFVOLD); \
721 name = dscr;
722
723 static int
724 udf_process_vds_descriptor(struct udf_mount *ump, union dscrptr *dscr)
725 {
726 uint16_t partnr;
727
728 DPRINTF(VOLUMES, ("\tprocessing VDS descr %d\n",
729 udf_rw16(dscr->tag.id)));
730 switch (udf_rw16(dscr->tag.id)) {
731 case TAGID_PRI_VOL : /* primary partition */
732 UDF_UPDATE_DSCR(ump->primary_vol, &dscr->pvd);
733 break;
734 case TAGID_LOGVOL : /* logical volume */
735 UDF_UPDATE_DSCR(ump->logical_vol, &dscr->lvd);
736 break;
737 case TAGID_UNALLOC_SPACE : /* unallocated space */
738 UDF_UPDATE_DSCR(ump->unallocated, &dscr->usd);
739 break;
740 case TAGID_IMP_VOL : /* implementation */
741 /* XXX do we care about multiple impl. descr ? */
742 UDF_UPDATE_DSCR(ump->implementation, &dscr->ivd);
743 break;
744 case TAGID_PARTITION : /* physical partition */
745 /* not much use if its not allocated */
746 if ((udf_rw16(dscr->pd.flags) & UDF_PART_FLAG_ALLOCATED) == 0) {
747 free(dscr, M_UDFVOLD);
748 break;
749 }
750
751 /* check partnr boundaries */
752 partnr = udf_rw16(dscr->pd.part_num);
753 if (partnr >= UDF_PARTITIONS)
754 return EINVAL;
755
756 UDF_UPDATE_DSCR(ump->partitions[partnr], &dscr->pd);
757 break;
758 case TAGID_VOL : /* volume space extender; rare */
759 DPRINTF(VOLUMES, ("VDS extender ignored\n"));
760 free(dscr, M_UDFVOLD);
761 break;
762 default :
763 DPRINTF(VOLUMES, ("Unhandled VDS type %d\n",
764 udf_rw16(dscr->tag.id)));
765 free(dscr, M_UDFVOLD);
766 }
767
768 return 0;
769 }
770 #undef UDF_UPDATE_DSCR
771
772 /* --------------------------------------------------------------------- */
773
774 static int
775 udf_read_vds_extent(struct udf_mount *ump, uint32_t loc, uint32_t len)
776 {
777 union dscrptr *dscr;
778 uint32_t sector_size, dscr_size;
779 int error;
780
781 sector_size = ump->discinfo.sector_size;
782
783 /* loc is sectornr, len is in bytes */
784 error = EIO;
785 while (len) {
786 error = udf_read_descriptor(ump, loc, M_UDFVOLD, &dscr);
787 if (error)
788 return error;
789
790 /* blank block is a terminator */
791 if (dscr == NULL)
792 return 0;
793
794 /* TERM descriptor is a terminator */
795 if (udf_rw16(dscr->tag.id) == TAGID_TERM)
796 return 0;
797
798 /* process all others */
799 dscr_size = udf_tagsize(dscr, sector_size);
800 error = udf_process_vds_descriptor(ump, dscr);
801 if (error) {
802 free(dscr, M_UDFVOLD);
803 break;
804 }
805 assert((dscr_size % sector_size) == 0);
806
807 len -= dscr_size;
808 loc += dscr_size / sector_size;
809 }
810
811 return error;
812 }
813
814
815 int
816 udf_read_vds_space(struct udf_mount *ump)
817 {
818 struct anchor_vdp *anchor, *anchor2;
819 size_t size;
820 uint32_t main_loc, main_len;
821 uint32_t reserve_loc, reserve_len;
822 int error;
823
824 /*
825 * read in VDS space provided by the anchors; if one descriptor read
826 * fails, try the mirror sector.
827 *
828 * check if 2nd anchor is different from 1st; if so, go for 2nd. This
829 * avoids the `compatibility features' of DirectCD that may confuse
830 * stuff completely.
831 */
832
833 anchor = ump->anchors[0];
834 anchor2 = ump->anchors[1];
835 assert(anchor);
836
837 if (anchor2) {
838 size = sizeof(struct extent_ad);
839 if (memcmp(&anchor->main_vds_ex, &anchor2->main_vds_ex, size))
840 anchor = anchor2;
841 /* reserve is specified to be a literal copy of main */
842 }
843
844 main_loc = udf_rw32(anchor->main_vds_ex.loc);
845 main_len = udf_rw32(anchor->main_vds_ex.len);
846
847 reserve_loc = udf_rw32(anchor->reserve_vds_ex.loc);
848 reserve_len = udf_rw32(anchor->reserve_vds_ex.len);
849
850 error = udf_read_vds_extent(ump, main_loc, main_len);
851 if (error) {
852 printf("UDF mount: reading in reserve VDS extent\n");
853 error = udf_read_vds_extent(ump, reserve_loc, reserve_len);
854 }
855
856 return error;
857 }
858
859 /* --------------------------------------------------------------------- */
860
861 /*
862 * Read in the logical volume integrity sequence pointed to by our logical
863 * volume descriptor. Its a sequence that can be extended using fields in the
864 * integrity descriptor itself. On sequential media only one is found, on
865 * rewritable media a sequence of descriptors can be found as a form of
866 * history keeping and on non sequential write-once media the chain is vital
867 * to allow more and more descriptors to be written. The last descriptor
868 * written in an extent needs to claim space for a new extent.
869 */
870
871 static int
872 udf_retrieve_lvint(struct udf_mount *ump, struct logvol_int_desc **lvintp)
873 {
874 union dscrptr *dscr;
875 struct logvol_int_desc *lvint;
876 uint32_t sector_size, sector, len;
877 int dscr_type, error;
878
879 sector_size = ump->discinfo.sector_size;
880 len = udf_rw32(ump->logical_vol->integrity_seq_loc.len);
881 sector = udf_rw32(ump->logical_vol->integrity_seq_loc.loc);
882
883 lvint = NULL;
884 dscr = NULL;
885 error = 0;
886 while (len) {
887 /* read in our integrity descriptor */
888 error = udf_read_descriptor(ump, sector, M_UDFVOLD, &dscr);
889 if (!error) {
890 if (dscr == NULL)
891 break; /* empty terminates */
892 dscr_type = udf_rw16(dscr->tag.id);
893 if (dscr_type == TAGID_TERM) {
894 break; /* clean terminator */
895 }
896 if (dscr_type != TAGID_LOGVOL_INTEGRITY) {
897 /* fatal... corrupt disc */
898 error = ENOENT;
899 break;
900 }
901 if (lvint)
902 free(lvint, M_UDFVOLD);
903 lvint = &dscr->lvid;
904 dscr = NULL;
905 } /* else hope for the best... maybe the next is ok */
906
907 DPRINTFIF(VOLUMES, lvint, ("logvol integrity read, state %s\n",
908 udf_rw32(lvint->integrity_type) ? "CLOSED" : "OPEN"));
909
910 /* proceed sequential */
911 sector += 1;
912 len -= sector_size;
913
914 /* are we linking to a new piece? */
915 if (lvint->next_extent.len) {
916 len = udf_rw32(lvint->next_extent.len);
917 sector = udf_rw32(lvint->next_extent.loc);
918 }
919 }
920
921 /* clean up the mess, esp. when there is an error */
922 if (dscr)
923 free(dscr, M_UDFVOLD);
924
925 if (error && lvint) {
926 free(lvint, M_UDFVOLD);
927 lvint = NULL;
928 }
929
930 if (!lvint)
931 error = ENOENT;
932
933 *lvintp = lvint;
934 return error;
935 }
936
937 /* --------------------------------------------------------------------- */
938
939 /*
940 * Checks if ump's vds information is correct and complete
941 */
942
943 int
944 udf_process_vds(struct udf_mount *ump, struct udf_args *args) {
945 union udf_pmap *mapping;
946 struct logvol_int_desc *lvint;
947 struct udf_logvol_info *lvinfo;
948 uint32_t n_pm, mt_l;
949 uint8_t *pmap_pos;
950 char *domain_name, *map_name;
951 const char *check_name;
952 int pmap_stype, pmap_size;
953 int pmap_type, log_part, phys_part;
954 int n_phys, n_virt, n_spar, n_meta;
955 int len, error;
956
957 if (ump == NULL)
958 return ENOENT;
959
960 /* we need at least an anchor (trivial, but for safety) */
961 if (ump->anchors[0] == NULL)
962 return EINVAL;
963
964 /* we need at least one primary and one logical volume descriptor */
965 if ((ump->primary_vol == NULL) || (ump->logical_vol) == NULL)
966 return EINVAL;
967
968 /* we need at least one partition descriptor */
969 if (ump->partitions[0] == NULL)
970 return EINVAL;
971
972 /* check logical volume sector size verses device sector size */
973 if (udf_rw32(ump->logical_vol->lb_size) != ump->discinfo.sector_size) {
974 printf("UDF mount: format violation, lb_size != sector size\n");
975 return EINVAL;
976 }
977
978 domain_name = ump->logical_vol->domain_id.id;
979 if (strncmp(domain_name, "*OSTA UDF Compliant", 20)) {
980 printf("mount_udf: disc not OSTA UDF Compliant, aborting\n");
981 return EINVAL;
982 }
983
984 /* retrieve logical volume integrity sequence */
985 error = udf_retrieve_lvint(ump, &ump->logvol_integrity);
986
987 /*
988 * We need at least one logvol integrity descriptor recorded. Note
989 * that its OK to have an open logical volume integrity here. The VAT
990 * will close/update the integrity.
991 */
992 if (ump->logvol_integrity == NULL)
993 return EINVAL;
994
995 /* process derived structures */
996 n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
997 lvint = ump->logvol_integrity;
998 lvinfo = (struct udf_logvol_info *) (&lvint->tables[2 * n_pm]);
999 ump->logvol_info = lvinfo;
1000
1001 /* TODO check udf versions? */
1002
1003 /*
1004 * check logvol mappings: effective virt->log partmap translation
1005 * check and recording of the mapping results. Saves expensive
1006 * strncmp() in tight places.
1007 */
1008 DPRINTF(VOLUMES, ("checking logvol mappings\n"));
1009 n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
1010 mt_l = udf_rw32(ump->logical_vol->mt_l); /* partmaps data length */
1011 pmap_pos = ump->logical_vol->maps;
1012
1013 if (n_pm > UDF_PMAPS) {
1014 printf("UDF mount: too many mappings\n");
1015 return EINVAL;
1016 }
1017
1018 n_phys = n_virt = n_spar = n_meta = 0;
1019 for (log_part = 0; log_part < n_pm; log_part++) {
1020 mapping = (union udf_pmap *) pmap_pos;
1021 pmap_stype = pmap_pos[0];
1022 pmap_size = pmap_pos[1];
1023 switch (pmap_stype) {
1024 case 1: /* physical mapping */
1025 /* volseq = udf_rw16(mapping->pm1.vol_seq_num); */
1026 phys_part = udf_rw16(mapping->pm1.part_num);
1027 pmap_type = UDF_VTOP_TYPE_PHYS;
1028 n_phys++;
1029 break;
1030 case 2: /* virtual/sparable/meta mapping */
1031 map_name = mapping->pm2.part_id.id;
1032 /* volseq = udf_rw16(mapping->pm2.vol_seq_num); */
1033 phys_part = udf_rw16(mapping->pm2.part_num);
1034 pmap_type = UDF_VTOP_TYPE_UNKNOWN;
1035 len = UDF_REGID_ID_SIZE;
1036
1037 check_name = "*UDF Virtual Partition";
1038 if (strncmp(map_name, check_name, len) == 0) {
1039 pmap_type = UDF_VTOP_TYPE_VIRT;
1040 n_virt++;
1041 break;
1042 }
1043 check_name = "*UDF Sparable Partition";
1044 if (strncmp(map_name, check_name, len) == 0) {
1045 pmap_type = UDF_VTOP_TYPE_SPARABLE;
1046 n_spar++;
1047 break;
1048 }
1049 check_name = "*UDF Metadata Partition";
1050 if (strncmp(map_name, check_name, len) == 0) {
1051 pmap_type = UDF_VTOP_TYPE_META;
1052 n_meta++;
1053 break;
1054 }
1055 break;
1056 default:
1057 return EINVAL;
1058 }
1059
1060 DPRINTF(VOLUMES, ("\t%d -> %d type %d\n", log_part, phys_part,
1061 pmap_type));
1062 if (pmap_type == UDF_VTOP_TYPE_UNKNOWN)
1063 return EINVAL;
1064
1065 ump->vtop [log_part] = phys_part;
1066 ump->vtop_tp[log_part] = pmap_type;
1067
1068 pmap_pos += pmap_size;
1069 }
1070 /* not winning the beauty contest */
1071 ump->vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
1072
1073 /* test some basic UDF assertions/requirements */
1074 if ((n_virt > 1) || (n_spar > 1) || (n_meta > 1))
1075 return EINVAL;
1076
1077 if (n_virt) {
1078 if ((n_phys == 0) || n_spar || n_meta)
1079 return EINVAL;
1080 }
1081 if (n_spar + n_phys == 0)
1082 return EINVAL;
1083
1084 /* vat's can only be on a sequential media */
1085 ump->data_alloc = UDF_ALLOC_SPACEMAP;
1086 if (n_virt)
1087 ump->data_alloc = UDF_ALLOC_SEQUENTIAL;
1088
1089 ump->meta_alloc = UDF_ALLOC_SPACEMAP;
1090 if (n_virt)
1091 ump->meta_alloc = UDF_ALLOC_VAT;
1092 if (n_meta)
1093 ump->meta_alloc = UDF_ALLOC_METABITMAP;
1094
1095 /* special cases for pseudo-overwrite */
1096 if (ump->discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {
1097 ump->data_alloc = UDF_ALLOC_SEQUENTIAL;
1098 if (n_meta) {
1099 ump->meta_alloc = UDF_ALLOC_METASEQUENTIAL;
1100 } else {
1101 ump->meta_alloc = UDF_ALLOC_RELAXEDSEQUENTIAL;
1102 }
1103 }
1104
1105 DPRINTF(VOLUMES, ("\tdata alloc scheme %d, meta alloc scheme %d\n",
1106 ump->data_alloc, ump->meta_alloc));
1107 /* TODO determine partitions to write data and metadata ? */
1108
1109 /* signal its OK for now */
1110 return 0;
1111 }
1112
1113 /* --------------------------------------------------------------------- */
1114
1115 /*
1116 * Read in complete VAT file and check if its indeed a VAT file descriptor
1117 */
1118
1119 static int
1120 udf_check_for_vat(struct udf_node *vat_node)
1121 {
1122 struct udf_mount *ump;
1123 struct icb_tag *icbtag;
1124 struct timestamp *mtime;
1125 struct regid *regid;
1126 struct udf_vat *vat;
1127 struct udf_logvol_info *lvinfo;
1128 uint32_t vat_length, alloc_length;
1129 uint32_t vat_offset, vat_entries;
1130 uint32_t sector_size;
1131 uint32_t sectors;
1132 uint32_t *raw_vat;
1133 char *regid_name;
1134 int filetype;
1135 int error;
1136
1137 /* vat_length is really 64 bits though impossible */
1138
1139 DPRINTF(VOLUMES, ("Checking for VAT\n"));
1140 if (!vat_node)
1141 return ENOENT;
1142
1143 /* get mount info */
1144 ump = vat_node->ump;
1145
1146 /* check assertions */
1147 assert(vat_node->fe || vat_node->efe);
1148 assert(ump->logvol_integrity);
1149
1150 /* get information from fe/efe */
1151 if (vat_node->fe) {
1152 vat_length = udf_rw64(vat_node->fe->inf_len);
1153 icbtag = &vat_node->fe->icbtag;
1154 mtime = &vat_node->fe->mtime;
1155 } else {
1156 vat_length = udf_rw64(vat_node->efe->inf_len);
1157 icbtag = &vat_node->efe->icbtag;
1158 mtime = &vat_node->efe->mtime;
1159 }
1160
1161 /* Check icb filetype! it has to be 0 or UDF_ICB_FILETYPE_VAT */
1162 filetype = icbtag->file_type;
1163 if ((filetype != 0) && (filetype != UDF_ICB_FILETYPE_VAT))
1164 return ENOENT;
1165
1166 DPRINTF(VOLUMES, ("\tPossible VAT length %d\n", vat_length));
1167 /* place a sanity check on the length; currently 1Mb in size */
1168 if (vat_length > 1*1024*1024)
1169 return ENOENT;
1170
1171 /* get sector size */
1172 sector_size = vat_node->ump->discinfo.sector_size;
1173
1174 /* calculate how many sectors to read in and how much to allocate */
1175 sectors = (vat_length + sector_size -1) / sector_size;
1176 alloc_length = (sectors + 2) * sector_size;
1177
1178 /* try to allocate the space */
1179 ump->vat_table_alloc_length = alloc_length;
1180 ump->vat_table = malloc(alloc_length, M_UDFMNT, M_CANFAIL | M_WAITOK);
1181 if (!ump->vat_table)
1182 return ENOMEM; /* impossible to allocate */
1183 DPRINTF(VOLUMES, ("\talloced fine\n"));
1184
1185 /* read it in! */
1186 raw_vat = (uint32_t *) ump->vat_table;
1187 error = udf_read_file_extent(vat_node, 0, sectors, (uint8_t *) raw_vat);
1188 if (error) {
1189 DPRINTF(VOLUMES, ("\tread failed : %d\n", error));
1190 /* not completely readable... :( bomb out */
1191 free(ump->vat_table, M_UDFMNT);
1192 ump->vat_table = NULL;
1193 return error;
1194 }
1195 DPRINTF(VOLUMES, ("VAT read in fine!\n"));
1196
1197 /*
1198 * check contents of the file if its the old 1.50 VAT table format.
1199 * Its notoriously broken and allthough some implementations support an
1200 * extention as defined in the UDF 1.50 errata document, its doubtfull
1201 * to be useable since a lot of implementations don't maintain it.
1202 */
1203 lvinfo = ump->logvol_info;
1204
1205 if (filetype == 0) {
1206 /* definition */
1207 vat_offset = 0;
1208 vat_entries = (vat_length-36)/4;
1209
1210 /* check 1.50 VAT */
1211 regid = (struct regid *) (raw_vat + vat_entries);
1212 regid_name = (char *) regid->id;
1213 error = strncmp(regid_name, "*UDF Virtual Alloc Tbl", 22);
1214 if (error) {
1215 DPRINTF(VOLUMES, ("VAT format 1.50 rejected\n"));
1216 free(ump->vat_table, M_UDFMNT);
1217 ump->vat_table = NULL;
1218 return ENOENT;
1219 }
1220 /* TODO update LVID from "*UDF VAT LVExtension" ext. attr. */
1221 } else {
1222 vat = (struct udf_vat *) raw_vat;
1223
1224 /* definition */
1225 vat_offset = vat->header_len;
1226 vat_entries = (vat_length - vat_offset)/4;
1227
1228 assert(lvinfo);
1229 lvinfo->num_files = vat->num_files;
1230 lvinfo->num_directories = vat->num_directories;
1231 lvinfo->min_udf_readver = vat->min_udf_readver;
1232 lvinfo->min_udf_writever = vat->min_udf_writever;
1233 lvinfo->max_udf_writever = vat->max_udf_writever;
1234 }
1235
1236 ump->vat_offset = vat_offset;
1237 ump->vat_entries = vat_entries;
1238
1239 DPRINTF(VOLUMES, ("VAT format accepted, marking it closed\n"));
1240 ump->logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
1241 ump->logvol_integrity->time = *mtime;
1242
1243 return 0; /* success! */
1244 }
1245
1246 /* --------------------------------------------------------------------- */
1247
1248 static int
1249 udf_search_vat(struct udf_mount *ump, union udf_pmap *mapping)
1250 {
1251 struct udf_node *vat_node;
1252 struct long_ad icb_loc;
1253 uint32_t early_vat_loc, late_vat_loc, vat_loc;
1254 int error;
1255
1256 /* mapping info not needed */
1257 mapping = mapping;
1258
1259 vat_loc = ump->last_possible_vat_location;
1260 early_vat_loc = vat_loc - ump->discinfo.blockingnr;
1261 early_vat_loc = MAX(early_vat_loc, ump->first_possible_vat_location);
1262 late_vat_loc = vat_loc + 1024;
1263
1264 /* TODO first search last sector? */
1265 do {
1266 DPRINTF(VOLUMES, ("Checking for VAT at sector %d\n", vat_loc));
1267 icb_loc.loc.part_num = udf_rw16(UDF_VTOP_RAWPART);
1268 icb_loc.loc.lb_num = udf_rw32(vat_loc);
1269
1270 error = udf_get_node(ump, &icb_loc, &vat_node);
1271 if (!error) error = udf_check_for_vat(vat_node);
1272 if (!error) break;
1273 if (vat_node) {
1274 vput(vat_node->vnode);
1275 udf_dispose_node(vat_node);
1276 }
1277 vat_loc--; /* walk backwards */
1278 } while (vat_loc >= early_vat_loc);
1279
1280 /* we don't need our VAT node anymore */
1281 if (vat_node) {
1282 vput(vat_node->vnode);
1283 udf_dispose_node(vat_node);
1284 }
1285
1286 return error;
1287 }
1288
1289 /* --------------------------------------------------------------------- */
1290
1291 static int
1292 udf_read_sparables(struct udf_mount *ump, union udf_pmap *mapping)
1293 {
1294 union dscrptr *dscr;
1295 struct part_map_spare *pms = (struct part_map_spare *) mapping;
1296 uint32_t lb_num;
1297 int spar, error;
1298
1299 /*
1300 * The partition mapping passed on to us specifies the information we
1301 * need to locate and initialise the sparable partition mapping
1302 * information we need.
1303 */
1304
1305 DPRINTF(VOLUMES, ("Read sparable table\n"));
1306 ump->sparable_packet_len = udf_rw16(pms->packet_len);
1307 for (spar = 0; spar < pms->n_st; spar++) {
1308 lb_num = pms->st_loc[spar];
1309 DPRINTF(VOLUMES, ("Checking for sparing table %d\n", lb_num));
1310 error = udf_read_descriptor(ump, lb_num, M_UDFVOLD, &dscr);
1311 if (!error && dscr) {
1312 if (udf_rw16(dscr->tag.id) == TAGID_SPARING_TABLE) {
1313 if (ump->sparing_table)
1314 free(ump->sparing_table, M_UDFVOLD);
1315 ump->sparing_table = &dscr->spt;
1316 dscr = NULL;
1317 DPRINTF(VOLUMES,
1318 ("Sparing table accepted (%d entries)\n",
1319 udf_rw16(ump->sparing_table->rt_l)));
1320 break; /* we're done */
1321 }
1322 }
1323 if (dscr)
1324 free(dscr, M_UDFVOLD);
1325 }
1326
1327 if (ump->sparing_table)
1328 return 0;
1329
1330 return ENOENT;
1331 }
1332
1333 /* --------------------------------------------------------------------- */
1334
1335 int
1336 udf_read_vds_tables(struct udf_mount *ump, struct udf_args *args)
1337 {
1338 union udf_pmap *mapping;
1339 uint32_t n_pm, mt_l;
1340 uint32_t log_part;
1341 uint8_t *pmap_pos;
1342 int pmap_size;
1343 int error;
1344
1345 /* We have to iterate again over the part mappings for locations */
1346 n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
1347 mt_l = udf_rw32(ump->logical_vol->mt_l); /* partmaps data length */
1348 pmap_pos = ump->logical_vol->maps;
1349
1350 for (log_part = 0; log_part < n_pm; log_part++) {
1351 mapping = (union udf_pmap *) pmap_pos;
1352 switch (ump->vtop_tp[log_part]) {
1353 case UDF_VTOP_TYPE_PHYS :
1354 /* nothing */
1355 break;
1356 case UDF_VTOP_TYPE_VIRT :
1357 /* search and load VAT */
1358 error = udf_search_vat(ump, mapping);
1359 if (error)
1360 return ENOENT;
1361 break;
1362 case UDF_VTOP_TYPE_SPARABLE :
1363 /* load one of the sparable tables */
1364 error = udf_read_sparables(ump, mapping);
1365 break;
1366 case UDF_VTOP_TYPE_META :
1367 /* TODO load metafile and metabitmapfile FE/EFEs */
1368 break;
1369 default:
1370 break;
1371 }
1372 pmap_size = pmap_pos[1];
1373 pmap_pos += pmap_size;
1374 }
1375
1376 return 0;
1377 }
1378
1379 /* --------------------------------------------------------------------- */
1380
1381 int
1382 udf_read_rootdirs(struct udf_mount *ump, struct udf_args *args)
1383 {
1384 struct udf_node *rootdir_node, *streamdir_node;
1385 union dscrptr *dscr;
1386 struct long_ad fsd_loc, *dir_loc;
1387 uint32_t lb_num, dummy;
1388 uint32_t fsd_len;
1389 int dscr_type;
1390 int error;
1391
1392 /* TODO implement FSD reading in seperate function like integrity? */
1393 /* get fileset descriptor sequence */
1394 fsd_loc = ump->logical_vol->lv_fsd_loc;
1395 fsd_len = udf_rw32(fsd_loc.len);
1396
1397 dscr = NULL;
1398 error = 0;
1399 while (fsd_len || error) {
1400 DPRINTF(VOLUMES, ("fsd_len = %d\n", fsd_len));
1401 /* translate fsd_loc to lb_num */
1402 error = udf_translate_vtop(ump, &fsd_loc, &lb_num, &dummy);
1403 if (error)
1404 break;
1405 DPRINTF(VOLUMES, ("Reading FSD at lb %d\n", lb_num));
1406 error = udf_read_descriptor(ump, lb_num, M_UDFVOLD, &dscr);
1407 /* end markers */
1408 if (error || (dscr == NULL))
1409 break;
1410
1411 /* analyse */
1412 dscr_type = udf_rw16(dscr->tag.id);
1413 if (dscr_type == TAGID_TERM)
1414 break;
1415 if (dscr_type != TAGID_FSD) {
1416 free(dscr, M_UDFVOLD);
1417 return ENOENT;
1418 }
1419
1420 /*
1421 * TODO check for multiple fileset descriptors; its only
1422 * picking the last now. Also check for FSD
1423 * correctness/interpretability
1424 */
1425
1426 /* update */
1427 if (ump->fileset_desc) {
1428 free(ump->fileset_desc, M_UDFVOLD);
1429 }
1430 ump->fileset_desc = &dscr->fsd;
1431 dscr = NULL;
1432
1433 /* continue to the next fsd */
1434 fsd_len -= ump->discinfo.sector_size;
1435 fsd_loc.loc.lb_num = udf_rw32(udf_rw32(fsd_loc.loc.lb_num)+1);
1436
1437 /* follow up to fsd->next_ex (long_ad) if its not null */
1438 if (udf_rw32(ump->fileset_desc->next_ex.len)) {
1439 DPRINTF(VOLUMES, ("follow up FSD extent\n"));
1440 fsd_loc = ump->fileset_desc->next_ex;
1441 fsd_len = udf_rw32(ump->fileset_desc->next_ex.len);
1442 }
1443 }
1444 if (dscr)
1445 free(dscr, M_UDFVOLD);
1446
1447 /* there has to be one */
1448 if (ump->fileset_desc == NULL)
1449 return ENOENT;
1450
1451 DPRINTF(VOLUMES, ("FSD read in fine\n"));
1452
1453 /*
1454 * Now the FSD is known, read in the rootdirectory and if one exists,
1455 * the system stream dir. Some files in the system streamdir are not
1456 * wanted in this implementation since they are not maintained. If
1457 * writing is enabled we'll delete these files if they exist.
1458 */
1459
1460 rootdir_node = streamdir_node = NULL;
1461 dir_loc = NULL;
1462
1463 /* try to read in the rootdir */
1464 dir_loc = &ump->fileset_desc->rootdir_icb;
1465 error = udf_get_node(ump, dir_loc, &rootdir_node);
1466 if (error)
1467 return ENOENT;
1468
1469 /* aparently it read in fine */
1470
1471 /*
1472 * Try the system stream directory; not very likely in the ones we
1473 * test, but for completeness.
1474 */
1475 dir_loc = &ump->fileset_desc->streamdir_icb;
1476 if (udf_rw32(dir_loc->len)) {
1477 error = udf_get_node(ump, dir_loc, &streamdir_node);
1478 if (error)
1479 printf("udf mount: streamdir defined but ignored\n");
1480 if (!error) {
1481 /*
1482 * TODO process streamdir `baddies' i.e. files we dont
1483 * want if R/W
1484 */
1485 }
1486 }
1487
1488 DPRINTF(VOLUMES, ("Rootdir(s) read in fine\n"));
1489
1490 /* release the vnodes again; they'll be auto-recycled later */
1491 if (streamdir_node) {
1492 vput(streamdir_node->vnode);
1493 }
1494 if (rootdir_node) {
1495 vput(rootdir_node->vnode);
1496 }
1497
1498 return 0;
1499 }
1500
1501 /* --------------------------------------------------------------------- */
1502
1503 int
1504 udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
1505 uint32_t *lb_numres, uint32_t *extres)
1506 {
1507 struct part_desc *pdesc;
1508 struct spare_map_entry *sme;
1509 uint32_t *trans;
1510 uint32_t lb_num, lb_rel, lb_packet;
1511 int rel, vpart, part;
1512
1513 assert(ump && icb_loc && lb_numres);
1514
1515 vpart = udf_rw16(icb_loc->loc.part_num);
1516 lb_num = udf_rw32(icb_loc->loc.lb_num);
1517 if (vpart < 0 || vpart > UDF_VTOP_RAWPART)
1518 return EINVAL;
1519
1520 switch (ump->vtop_tp[vpart]) {
1521 case UDF_VTOP_TYPE_RAW :
1522 /* 1:1 to the end of the device */
1523 *lb_numres = lb_num;
1524 *extres = INT_MAX;
1525 return 0;
1526 case UDF_VTOP_TYPE_PHYS :
1527 /* transform into its disc logical block */
1528 part = ump->vtop[vpart];
1529 pdesc = ump->partitions[part];
1530 if (lb_num > udf_rw32(pdesc->part_len))
1531 return EINVAL;
1532 *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
1533
1534 /* extent from here to the end of the partition */
1535 *extres = udf_rw32(pdesc->part_len) - lb_num;
1536 return 0;
1537 case UDF_VTOP_TYPE_VIRT :
1538 /* only maps one sector, lookup in VAT */
1539 if (lb_num >= ump->vat_entries) /* XXX > or >= ? */
1540 return EINVAL;
1541
1542 /* lookup in virtual allocation table */
1543 trans = (uint32_t *) (ump->vat_table + ump->vat_offset);
1544 lb_num = udf_rw32(trans[lb_num]);
1545
1546 /* transform into its disc logical block */
1547 part = ump->vtop[vpart];
1548 pdesc = ump->partitions[part];
1549 if (lb_num > udf_rw32(pdesc->part_len))
1550 return EINVAL;
1551 *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
1552
1553 /* just one logical block */
1554 *extres = 1;
1555 return 0;
1556 case UDF_VTOP_TYPE_SPARABLE :
1557 /* check if the packet containing the lb_num is remapped */
1558 lb_packet = lb_num / ump->sparable_packet_len;
1559 lb_rel = lb_num % ump->sparable_packet_len;
1560
1561 for (rel = 0; rel < udf_rw16(ump->sparing_table->rt_l); rel++) {
1562 sme = &ump->sparing_table->entries[rel];
1563 if (lb_packet == udf_rw32(sme->org)) {
1564 /* NOTE maps to absolute disc logical block! */
1565 *lb_numres = udf_rw32(sme->map) + lb_rel;
1566 *extres = ump->sparable_packet_len - lb_rel;
1567 return 0;
1568 }
1569 }
1570
1571 /* transform into its disc logical block */
1572 part = ump->vtop[vpart];
1573 pdesc = ump->partitions[part];
1574 if (lb_num > udf_rw32(pdesc->part_len))
1575 return EINVAL;
1576 *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
1577
1578 /* rest of block */
1579 *extres = ump->sparable_packet_len - lb_rel;
1580 return 0;
1581 case UDF_VTOP_TYPE_META :
1582 default:
1583 printf("UDF vtop translation scheme %d unimplemented yet\n",
1584 ump->vtop_tp[vpart]);
1585 }
1586
1587 return EINVAL;
1588 }
1589
1590 /* --------------------------------------------------------------------- */
1591
1592 /* To make absolutely sure we are NOT returning zero, add one :) */
1593
1594 long
1595 udf_calchash(struct long_ad *icbptr)
1596 {
1597 /* ought to be enough since each mountpoint has its own chain */
1598 return udf_rw32(icbptr->loc.lb_num) + 1;
1599 }
1600
1601 /* --------------------------------------------------------------------- */
1602
1603 static struct udf_node *
1604 udf_hashget(struct udf_mount *ump, struct long_ad *icbptr)
1605 {
1606 struct udf_node *unp;
1607 struct vnode *vp;
1608 uint32_t hashline;
1609
1610 loop:
1611 simple_lock(&ump->ihash_slock);
1612
1613 hashline = udf_calchash(icbptr) & UDF_INODE_HASHMASK;
1614 LIST_FOREACH(unp, &ump->udf_nodes[hashline], hashchain) {
1615 assert(unp);
1616 if (unp->loc.loc.lb_num == icbptr->loc.lb_num &&
1617 unp->loc.loc.part_num == icbptr->loc.part_num) {
1618 vp = unp->vnode;
1619 assert(vp);
1620 simple_lock(&vp->v_interlock);
1621 simple_unlock(&ump->ihash_slock);
1622 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
1623 goto loop;
1624 return unp;
1625 }
1626 }
1627 simple_unlock(&ump->ihash_slock);
1628
1629 return NULL;
1630 }
1631
1632 /* --------------------------------------------------------------------- */
1633
1634 static void
1635 udf_hashins(struct udf_node *unp)
1636 {
1637 struct udf_mount *ump;
1638 uint32_t hashline;
1639
1640 ump = unp->ump;
1641 simple_lock(&ump->ihash_slock);
1642
1643 hashline = udf_calchash(&unp->loc) & UDF_INODE_HASHMASK;
1644 LIST_INSERT_HEAD(&ump->udf_nodes[hashline], unp, hashchain);
1645
1646 simple_unlock(&ump->ihash_slock);
1647 }
1648
1649 /* --------------------------------------------------------------------- */
1650
1651 static void
1652 udf_hashrem(struct udf_node *unp)
1653 {
1654 struct udf_mount *ump;
1655
1656 ump = unp->ump;
1657 simple_lock(&ump->ihash_slock);
1658
1659 LIST_REMOVE(unp, hashchain);
1660
1661 simple_unlock(&ump->ihash_slock);
1662 }
1663
1664 /* --------------------------------------------------------------------- */
1665
1666 int
1667 udf_dispose_locked_node(struct udf_node *node)
1668 {
1669 if (!node)
1670 return 0;
1671 if (node->vnode)
1672 VOP_UNLOCK(node->vnode, 0);
1673 return udf_dispose_node(node);
1674 }
1675
1676 /* --------------------------------------------------------------------- */
1677
1678 int
1679 udf_dispose_node(struct udf_node *node)
1680 {
1681 struct vnode *vp;
1682
1683 DPRINTF(NODE, ("udf_dispose_node called on node %p\n", node));
1684 if (!node) {
1685 DPRINTF(NODE, ("UDF: Dispose node on node NULL, ignoring\n"));
1686 return 0;
1687 }
1688
1689 vp = node->vnode;
1690
1691 /* TODO extended attributes and streamdir */
1692
1693 /* remove from our hash lookup table */
1694 udf_hashrem(node);
1695
1696 /* dissociate our udf_node from the vnode */
1697 vp->v_data = NULL;
1698
1699 /* free associated memory and the node itself */
1700 if (node->fe)
1701 pool_put(&node->ump->desc_pool, node->fe);
1702 if (node->efe)
1703 pool_put(&node->ump->desc_pool, node->efe);
1704 pool_put(&udf_node_pool, node);
1705
1706 return 0;
1707 }
1708
1709 /* --------------------------------------------------------------------- */
1710
1711 /*
1712 * Genfs interfacing
1713 *
1714 * static const struct genfs_ops udffs_genfsops = {
1715 * .gop_size = genfs_size,
1716 * size of transfers
1717 * .gop_alloc = udf_gop_alloc,
1718 * unknown
1719 * .gop_write = genfs_gop_write,
1720 * putpages interface code
1721 * .gop_markupdate = udf_gop_markupdate,
1722 * set update/modify flags etc.
1723 * }
1724 */
1725
1726 /*
1727 * Genfs interface. These four functions are the only ones defined though not
1728 * documented... great.... why is chosen for the `.' initialisers i dont know
1729 * but other filingsystems seem to use it this way.
1730 */
1731
1732 static int
1733 udf_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
1734 kauth_cred_t cred)
1735 {
1736 return 0;
1737 }
1738
1739
1740 static void
1741 udf_gop_markupdate(struct vnode *vp, int flags)
1742 {
1743 struct udf_node *udf_node = VTOI(vp);
1744 u_long mask;
1745
1746 udf_node = udf_node; /* shut up gcc */
1747
1748 mask = 0;
1749 #ifdef notyet
1750 if ((flags & GOP_UPDATE_ACCESSED) != 0) {
1751 mask = UDF_SET_ACCESS;
1752 }
1753 if ((flags & GOP_UPDATE_MODIFIED) != 0) {
1754 mask |= UDF_SET_UPDATE;
1755 }
1756 if (mask) {
1757 udf_node->update_flag |= mask;
1758 }
1759 #endif
1760 /* msdosfs doesn't do it, but shouldn't we update the times here? */
1761 }
1762
1763
1764 static const struct genfs_ops udf_genfsops = {
1765 .gop_size = genfs_size,
1766 .gop_alloc = udf_gop_alloc,
1767 .gop_write = genfs_gop_write,
1768 .gop_markupdate = udf_gop_markupdate,
1769 };
1770
1771 /* --------------------------------------------------------------------- */
1772
1773 /*
1774 * Each node can have an attached streamdir node though not
1775 * recursively. These are otherwise known as named substreams/named
1776 * extended attributes that have no size limitations.
1777 *
1778 * `Normal' extended attributes are indicated with a number and are recorded
1779 * in either the fe/efe descriptor itself for small descriptors or recorded in
1780 * the attached extended attribute file. Since this file can get fragmented,
1781 * care ought to be taken.
1782 */
1783
1784 int
1785 udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc,
1786 struct udf_node **noderes)
1787 {
1788 union dscrptr *dscr, *tmpdscr;
1789 struct udf_node *node;
1790 struct vnode *nvp;
1791 struct long_ad icb_loc;
1792 extern int (**udf_vnodeop_p)(void *);
1793 uint64_t file_size;
1794 uint32_t lb_size, sector, dummy;
1795 int udf_file_type, dscr_type, strat, strat4096, needs_indirect;
1796 int error;
1797
1798 DPRINTF(NODE, ("udf_get_node called\n"));
1799 *noderes = node = NULL;
1800
1801 /* lock to disallow simultanious creation of same node */
1802 lockmgr(&ump->get_node_lock, LK_EXCLUSIVE, NULL);
1803
1804 DPRINTF(NODE, ("\tlookup in hash table\n"));
1805 /* lookup in hash table */
1806 assert(ump);
1807 assert(node_icb_loc);
1808 node = udf_hashget(ump, node_icb_loc);
1809 if (node) {
1810 DPRINTF(NODE, ("\tgot it from the hash!\n"));
1811 /* vnode is returned locked */
1812 *noderes = node;
1813 lockmgr(&ump->get_node_lock, LK_RELEASE, NULL);
1814 return 0;
1815 }
1816
1817 /* garbage check: translate node_icb_loc to sectornr */
1818 error = udf_translate_vtop(ump, node_icb_loc, §or, &dummy);
1819 if (error) {
1820 /* no use, this will fail anyway */
1821 lockmgr(&ump->get_node_lock, LK_RELEASE, NULL);
1822 return EINVAL;
1823 }
1824
1825 /* build node (do initialise!) */
1826 node = pool_get(&udf_node_pool, PR_WAITOK);
1827 memset(node, 0, sizeof(struct udf_node));
1828
1829 DPRINTF(NODE, ("\tget new vnode\n"));
1830 /* give it a vnode */
1831 error = getnewvnode(VT_UDF, ump->vfs_mountp, udf_vnodeop_p, &nvp);
1832 if (error) {
1833 pool_put(&udf_node_pool, node);
1834 lockmgr(&ump->get_node_lock, LK_RELEASE, NULL);
1835 return error;
1836 }
1837
1838 /* allways return locked vnode */
1839 if ((error = vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY))) {
1840 /* recycle vnode and unlock; simultanious will fail too */
1841 ungetnewvnode(nvp);
1842 lockmgr(&ump->get_node_lock, LK_RELEASE, NULL);
1843 return error;
1844 }
1845
1846 /* initialise crosslinks, note location of fe/efe for hashing */
1847 node->ump = ump;
1848 node->vnode = nvp;
1849 nvp->v_data = node;
1850 node->loc = *node_icb_loc;
1851 node->lockf = 0;
1852
1853 /* insert into the hash lookup */
1854 udf_hashins(node);
1855
1856 /* safe to unlock, the entry is in the hash table, vnode is locked */
1857 lockmgr(&ump->get_node_lock, LK_RELEASE, NULL);
1858
1859 icb_loc = *node_icb_loc;
1860 needs_indirect = 0;
1861 strat4096 = 0;
1862 udf_file_type = UDF_ICB_FILETYPE_UNKNOWN;
1863 file_size = 0;
1864 lb_size = udf_rw32(ump->logical_vol->lb_size);
1865
1866 do {
1867 error = udf_translate_vtop(ump, &icb_loc, §or, &dummy);
1868 if (error)
1869 break;
1870
1871 /* try to read in fe/efe */
1872 error = udf_read_descriptor(ump, sector, M_UDFTEMP, &tmpdscr);
1873
1874 /* blank sector marks end of sequence, check this */
1875 if ((tmpdscr == NULL) && (!strat4096))
1876 error = ENOENT;
1877
1878 /* break if read error or blank sector */
1879 if (error || (tmpdscr == NULL))
1880 break;
1881
1882 /* process descriptor based on the descriptor type */
1883 dscr_type = udf_rw16(tmpdscr->tag.id);
1884
1885 /* if dealing with an indirect entry, follow the link */
1886 if (dscr_type == TAGID_INDIRECT_ENTRY) {
1887 needs_indirect = 0;
1888 icb_loc = tmpdscr->inde.indirect_icb;
1889 free(tmpdscr, M_UDFTEMP);
1890 continue;
1891 }
1892
1893 /* only file entries and extended file entries allowed here */
1894 if ((dscr_type != TAGID_FENTRY) &&
1895 (dscr_type != TAGID_EXTFENTRY)) {
1896 free(tmpdscr, M_UDFTEMP);
1897 error = ENOENT;
1898 break;
1899 }
1900
1901 /* get descriptor space from our pool */
1902 KASSERT(udf_tagsize(tmpdscr, lb_size) == lb_size);
1903
1904 dscr = pool_get(&ump->desc_pool, PR_WAITOK);
1905 memcpy(dscr, tmpdscr, lb_size);
1906 free(tmpdscr, M_UDFTEMP);
1907
1908 /* record and process/update (ext)fentry */
1909 if (dscr_type == TAGID_FENTRY) {
1910 if (node->fe)
1911 pool_put(&ump->desc_pool, node->fe);
1912 node->fe = &dscr->fe;
1913 strat = udf_rw16(node->fe->icbtag.strat_type);
1914 udf_file_type = node->fe->icbtag.file_type;
1915 file_size = udf_rw64(node->fe->inf_len);
1916 } else {
1917 if (node->efe)
1918 pool_put(&ump->desc_pool, node->efe);
1919 node->efe = &dscr->efe;
1920 strat = udf_rw16(node->efe->icbtag.strat_type);
1921 udf_file_type = node->efe->icbtag.file_type;
1922 file_size = udf_rw64(node->efe->inf_len);
1923 }
1924
1925 /* check recording strategy (structure) */
1926
1927 /*
1928 * Strategy 4096 is a daisy linked chain terminating with an
1929 * unrecorded sector or a TERM descriptor. The next
1930 * descriptor is to be found in the sector that follows the
1931 * current sector.
1932 */
1933 if (strat == 4096) {
1934 strat4096 = 1;
1935 needs_indirect = 1;
1936
1937 icb_loc.loc.lb_num = udf_rw32(icb_loc.loc.lb_num) + 1;
1938 }
1939
1940 /*
1941 * Strategy 4 is the normal strategy and terminates, but if
1942 * we're in strategy 4096, we can't have strategy 4 mixed in
1943 */
1944
1945 if (strat == 4) {
1946 if (strat4096) {
1947 error = EINVAL;
1948 break;
1949 }
1950 break; /* done */
1951 }
1952 } while (!error);
1953
1954 if (error) {
1955 /* recycle udf_node */
1956 udf_dispose_node(node);
1957
1958 /* recycle vnode */
1959 nvp->v_data = NULL;
1960 ungetnewvnode(nvp);
1961
1962 return EINVAL; /* error code ok? */
1963 }
1964
1965 /* post process and initialise node */
1966
1967 /* assert no references to dscr anymore beyong this point */
1968 assert((node->fe) || (node->efe));
1969 dscr = NULL;
1970
1971 /*
1972 * Record where to record an updated version of the descriptor. If
1973 * there is a sequence of indirect entries, icb_loc will have been
1974 * updated. Its the write disipline to allocate new space and to make
1975 * sure the chain is maintained.
1976 *
1977 * `needs_indirect' flags if the next location is to be filled with
1978 * with an indirect entry.
1979 */
1980 node->next_loc = icb_loc;
1981 node->needs_indirect = needs_indirect;
1982
1983 /*
1984 * Translate UDF filetypes into vnode types.
1985 *
1986 * Systemfiles like the meta main and mirror files are not treated as
1987 * normal files, so we type them as having no type. UDF dictates that
1988 * they are not allowed to be visible.
1989 */
1990
1991 /* TODO specfs, fifofs etc etc. vnops setting */
1992 switch (udf_file_type) {
1993 case UDF_ICB_FILETYPE_DIRECTORY :
1994 case UDF_ICB_FILETYPE_STREAMDIR :
1995 nvp->v_type = VDIR;
1996 break;
1997 case UDF_ICB_FILETYPE_BLOCKDEVICE :
1998 nvp->v_type = VBLK;
1999 break;
2000 case UDF_ICB_FILETYPE_CHARDEVICE :
2001 nvp->v_type = VCHR;
2002 break;
2003 case UDF_ICB_FILETYPE_SYMLINK :
2004 nvp->v_type = VLNK;
2005 break;
2006 case UDF_ICB_FILETYPE_META_MAIN :
2007 case UDF_ICB_FILETYPE_META_MIRROR :
2008 nvp->v_type = VNON;
2009 break;
2010 case UDF_ICB_FILETYPE_RANDOMACCESS :
2011 nvp->v_type = VREG;
2012 break;
2013 default:
2014 /* YIKES, either a block/char device, fifo or something else */
2015 nvp->v_type = VNON;
2016 }
2017
2018 /* initialise genfs */
2019 genfs_node_init(nvp, &udf_genfsops);
2020
2021 /* don't forget to set vnode's v_size */
2022 nvp->v_size = file_size;
2023
2024 /* TODO ext attr and streamdir nodes */
2025
2026 *noderes = node;
2027
2028 return 0;
2029 }
2030
2031 /* --------------------------------------------------------------------- */
2032
2033 /* UDF<->unix converters */
2034
2035 /* --------------------------------------------------------------------- */
2036
2037 static mode_t
2038 udf_perm_to_unix_mode(uint32_t perm)
2039 {
2040 mode_t mode;
2041
2042 mode = ((perm & UDF_FENTRY_PERM_USER_MASK) );
2043 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK ) >> 2);
2044 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
2045
2046 return mode;
2047 }
2048
2049 /* --------------------------------------------------------------------- */
2050
2051 #ifdef notyet
2052 static uint32_t
2053 unix_mode_to_udf_perm(mode_t mode)
2054 {
2055 uint32_t perm;
2056
2057 perm = ((mode & S_IRWXO) );
2058 perm |= ((mode & S_IRWXG) << 2);
2059 perm |= ((mode & S_IRWXU) << 4);
2060 perm |= ((mode & S_IWOTH) << 3);
2061 perm |= ((mode & S_IWGRP) << 5);
2062 perm |= ((mode & S_IWUSR) << 7);
2063
2064 return perm;
2065 }
2066 #endif
2067
2068 /* --------------------------------------------------------------------- */
2069
2070 static uint32_t
2071 udf_icb_to_unix_filetype(uint32_t icbftype)
2072 {
2073 switch (icbftype) {
2074 case UDF_ICB_FILETYPE_DIRECTORY :
2075 case UDF_ICB_FILETYPE_STREAMDIR :
2076 return S_IFDIR;
2077 case UDF_ICB_FILETYPE_FIFO :
2078 return S_IFIFO;
2079 case UDF_ICB_FILETYPE_CHARDEVICE :
2080 return S_IFCHR;
2081 case UDF_ICB_FILETYPE_BLOCKDEVICE :
2082 return S_IFBLK;
2083 case UDF_ICB_FILETYPE_RANDOMACCESS :
2084 return S_IFREG;
2085 case UDF_ICB_FILETYPE_SYMLINK :
2086 return S_IFLNK;
2087 case UDF_ICB_FILETYPE_SOCKET :
2088 return S_IFSOCK;
2089 }
2090 /* no idea what this is */
2091 return 0;
2092 }
2093
2094 /* --------------------------------------------------------------------- */
2095
2096 /* TODO KNF-ify */
2097
2098 void
2099 udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp)
2100 {
2101 uint16_t *raw_name, *unix_name;
2102 uint16_t *inchp, ch;
2103 uint8_t *outchp;
2104 int ucode_chars, nice_uchars;
2105
2106 raw_name = malloc(2048 * sizeof(uint16_t), M_UDFTEMP, M_WAITOK);
2107 unix_name = raw_name + 1024; /* split space in half */
2108 assert(sizeof(char) == sizeof(uint8_t));
2109 outchp = (uint8_t *) result;
2110 if ((chsp->type == 0) && (strcmp((char*) chsp->inf, "OSTA Compressed Unicode") == 0)) {
2111 *raw_name = *unix_name = 0;
2112 ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name);
2113 ucode_chars = MIN(ucode_chars, UnicodeLength((unicode_t *) raw_name));
2114 nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars);
2115 for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) {
2116 ch = *inchp;
2117 /* XXX sloppy unicode -> latin */
2118 *outchp++ = ch & 255;
2119 if (!ch) break;
2120 }
2121 *outchp++ = 0;
2122 } else {
2123 /* assume 8bit char length byte latin-1 */
2124 assert(*id == 8);
2125 strncpy((char *) result, (char *) (id+1), strlen((char *) (id+1)));
2126 }
2127 free(raw_name, M_UDFTEMP);
2128 }
2129
2130 /* --------------------------------------------------------------------- */
2131
2132 /* TODO KNF-ify */
2133
2134 void
2135 unix_to_udf_name(char *result, char *name,
2136 uint8_t *result_len, struct charspec *chsp)
2137 {
2138 uint16_t *raw_name;
2139 int udf_chars, name_len;
2140 char *inchp;
2141 uint16_t *outchp;
2142
2143 raw_name = malloc(1024, M_UDFTEMP, M_WAITOK);
2144 /* convert latin-1 or whatever to unicode-16 */
2145 *raw_name = 0;
2146 name_len = 0;
2147 inchp = name;
2148 outchp = raw_name;
2149 while (*inchp) {
2150 *outchp++ = (uint16_t) (*inchp++);
2151 name_len++;
2152 }
2153
2154 if ((chsp->type == 0) && (strcmp((char *) chsp->inf, "OSTA Compressed Unicode") == 0)) {
2155 udf_chars = udf_CompressUnicode(name_len, 8, (unicode_t *) raw_name, (byte *) result);
2156 } else {
2157 /* XXX assume 8bit char length byte latin-1 */
2158 *result++ = 8; udf_chars = 1;
2159 strncpy(result, name + 1, strlen(name+1));
2160 udf_chars += strlen(name);
2161 }
2162 *result_len = udf_chars;
2163 free(raw_name, M_UDFTEMP);
2164 }
2165
2166 /* --------------------------------------------------------------------- */
2167
2168 /*
2169 * Timestamp to timespec conversion code is taken with small modifications
2170 * from FreeBSDs /sys/fs/udf by Scott Long <scottl (at) freebsd.org>. Added with
2171 * permission from Scott.
2172 */
2173
2174 static int mon_lens[2][12] = {
2175 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
2176 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
2177 };
2178
2179
2180 static int
2181 udf_isaleapyear(int year)
2182 {
2183 int i;
2184
2185 i = (year % 4) ? 0 : 1;
2186 i &= (year % 100) ? 1 : 0;
2187 i |= (year % 400) ? 0 : 1;
2188
2189 return i;
2190 }
2191
2192
2193 void
2194 udf_timestamp_to_timespec(struct udf_mount *ump,
2195 struct timestamp *timestamp,
2196 struct timespec *timespec)
2197 {
2198 uint32_t usecs, secs, nsecs;
2199 uint16_t tz;
2200 int i, lpyear, daysinyear, year;
2201
2202 timespec->tv_sec = secs = 0;
2203 timespec->tv_nsec = nsecs = 0;
2204
2205 /*
2206 * DirectCD seems to like using bogus year values.
2207 *
2208 * Distrust time->month especially, since it will be used for an array
2209 * index.
2210 */
2211 year = udf_rw16(timestamp->year);
2212 if ((year < 1970) || (timestamp->month > 12)) {
2213 return;
2214 }
2215
2216 /* Calculate the time and day
2217 * Day is 1-31, Month is 1-12
2218 */
2219
2220 usecs = timestamp->usec +
2221 100*timestamp->hund_usec + 10000*timestamp->centisec;
2222 nsecs = usecs * 1000;
2223 secs = timestamp->second;
2224 secs += timestamp->minute * 60;
2225 secs += timestamp->hour * 3600;
2226 secs += (timestamp->day-1) * 3600 * 24;
2227
2228 /* Calclulate the month */
2229 lpyear = udf_isaleapyear(year);
2230 for (i = 1; i < timestamp->month; i++)
2231 secs += mon_lens[lpyear][i-1] * 3600 * 24;
2232
2233 for (i = 1970; i < year; i++) {
2234 daysinyear = udf_isaleapyear(i) + 365 ;
2235 secs += daysinyear * 3600 * 24;
2236 }
2237
2238 /*
2239 * Calculate the time zone. The timezone is 12 bit signed 2's
2240 * compliment, so we gotta do some extra magic to handle it right.
2241 */
2242 tz = udf_rw16(timestamp->type_tz);
2243 tz &= 0x0fff; /* only lower 12 bits are significant */
2244 if (tz & 0x0800) /* sign extention */
2245 tz |= 0xf000;
2246
2247 /* TODO check timezone conversion */
2248 /* check if we are specified a timezone to convert */
2249 if (udf_rw16(timestamp->type_tz) & 0x1000) {
2250 if ((int16_t) tz != -2047)
2251 secs -= (int16_t) tz * 60;
2252 } else {
2253 secs -= ump->mount_args.gmtoff;
2254 }
2255
2256 timespec->tv_sec = secs;
2257 timespec->tv_nsec = nsecs;
2258 }
2259
2260 /* --------------------------------------------------------------------- */
2261
2262 /*
2263 * Attribute and filetypes converters with get/set pairs
2264 */
2265
2266 uint32_t
2267 udf_getaccessmode(struct udf_node *udf_node)
2268 {
2269 struct file_entry *fe;
2270 struct extfile_entry *efe;
2271 uint32_t udf_perm, icbftype;
2272 uint32_t mode, ftype;
2273 uint16_t icbflags;
2274
2275 if (udf_node->fe) {
2276 fe = udf_node->fe;
2277 udf_perm = udf_rw32(fe->perm);
2278 icbftype = fe->icbtag.file_type;
2279 icbflags = udf_rw16(fe->icbtag.flags);
2280 } else {
2281 assert(udf_node->efe);
2282 efe = udf_node->efe;
2283 udf_perm = udf_rw32(efe->perm);
2284 icbftype = efe->icbtag.file_type;
2285 icbflags = udf_rw16(efe->icbtag.flags);
2286 }
2287
2288 mode = udf_perm_to_unix_mode(udf_perm);
2289 ftype = udf_icb_to_unix_filetype(icbftype);
2290
2291 /* set suid, sgid, sticky from flags in fe/efe */
2292 if (icbflags & UDF_ICB_TAG_FLAGS_SETUID)
2293 mode |= S_ISUID;
2294 if (icbflags & UDF_ICB_TAG_FLAGS_SETGID)
2295 mode |= S_ISGID;
2296 if (icbflags & UDF_ICB_TAG_FLAGS_STICKY)
2297 mode |= S_ISVTX;
2298
2299 return mode | ftype;
2300 }
2301
2302 /* --------------------------------------------------------------------- */
2303
2304 /*
2305 * Directory read and manipulation functions
2306 */
2307
2308 int
2309 udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen,
2310 struct long_ad *icb_loc)
2311 {
2312 struct udf_node *dir_node = VTOI(vp);
2313 struct file_entry *fe;
2314 struct extfile_entry *efe;
2315 struct fileid_desc *fid;
2316 struct dirent dirent;
2317 uint64_t file_size, diroffset;
2318 uint32_t lb_size;
2319 int found, error;
2320
2321 /* get directory filesize */
2322 if (dir_node->fe) {
2323 fe = dir_node->fe;
2324 file_size = udf_rw64(fe->inf_len);
2325 } else {
2326 assert(dir_node->efe);
2327 efe = dir_node->efe;
2328 file_size = udf_rw64(efe->inf_len);
2329 }
2330
2331 /* allocate temporary space for fid */
2332 lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
2333 fid = malloc(lb_size, M_TEMP, M_WAITOK);
2334
2335 found = 0;
2336 diroffset = 0;
2337 while (!found && (diroffset < file_size)) {
2338 /* transfer a new fid/dirent */
2339 error = udf_read_fid_stream(vp, &diroffset, fid, &dirent);
2340 if (error)
2341 break;
2342
2343 /* skip deleted entries */
2344 if (fid->file_char & UDF_FILE_CHAR_DEL)
2345 continue;
2346
2347 if ((strlen(dirent.d_name) == namelen) &&
2348 (strncmp(dirent.d_name, name, namelen) == 0)) {
2349 found = 1;
2350 *icb_loc = fid->icb;
2351 }
2352 }
2353 free(fid, M_TEMP);
2354
2355 return found;
2356 }
2357
2358 /* --------------------------------------------------------------------- */
2359
2360 /*
2361 * Read one fid and process it into a dirent and advance to the next (*fid)
2362 * has to be allocated a logical block in size, (*dirent) struct dirent length
2363 */
2364
2365 int
2366 udf_read_fid_stream(struct vnode *vp, uint64_t *offset,
2367 struct fileid_desc *fid, struct dirent *dirent)
2368 {
2369 struct udf_node *dir_node = VTOI(vp);
2370 struct udf_mount *ump = dir_node->ump;
2371 struct file_entry *fe;
2372 struct extfile_entry *efe;
2373 struct uio dir_uio;
2374 struct iovec dir_iovec;
2375 uint32_t entry_length, lb_size;
2376 uint64_t file_size;
2377 char *fid_name;
2378 int enough, error;
2379
2380 assert(fid);
2381 assert(dirent);
2382 assert(dir_node);
2383 assert(offset);
2384 assert(*offset != 1);
2385
2386 DPRINTF(FIDS, ("read_fid_stream called\n"));
2387 /* check if we're past the end of the directory */
2388 if (dir_node->fe) {
2389 fe = dir_node->fe;
2390 file_size = udf_rw64(fe->inf_len);
2391 } else {
2392 assert(dir_node->efe);
2393 efe = dir_node->efe;
2394 file_size = udf_rw64(efe->inf_len);
2395 }
2396 if (*offset >= file_size)
2397 return EINVAL;
2398
2399 /* get maximum length of FID descriptor */
2400 lb_size = udf_rw32(ump->logical_vol->lb_size);
2401
2402 /* initialise return values */
2403 entry_length = 0;
2404 memset(dirent, 0, sizeof(struct dirent));
2405 memset(fid, 0, lb_size);
2406
2407 /* TODO use vn_rdwr instead of creating our own uio */
2408 /* read part of the directory */
2409 memset(&dir_uio, 0, sizeof(struct uio));
2410 dir_uio.uio_rw = UIO_READ; /* read into this space */
2411 dir_uio.uio_iovcnt = 1;
2412 dir_uio.uio_iov = &dir_iovec;
2413 UIO_SETUP_SYSSPACE(&dir_uio);
2414 dir_iovec.iov_base = fid;
2415 dir_iovec.iov_len = lb_size;
2416 dir_uio.uio_offset = *offset;
2417
2418 /* limit length of read in piece */
2419 dir_uio.uio_resid = MIN(file_size - (*offset), lb_size);
2420
2421 /* read the part into the fid space */
2422 error = VOP_READ(vp, &dir_uio, IO_ALTSEMANTICS, NOCRED);
2423 if (error)
2424 return error;
2425
2426 /*
2427 * Check if we got a whole descriptor.
2428 * XXX Try to `resync' directory stream when something is very wrong.
2429 *
2430 */
2431 enough = (dir_uio.uio_offset - (*offset) >= UDF_FID_SIZE);
2432 if (!enough) {
2433 /* short dir ... */
2434 return EIO;
2435 }
2436
2437 /* check if our FID header is OK */
2438 error = udf_check_tag(fid);
2439 DPRINTFIF(FIDS, error, ("read fids: tag check failed\n"));
2440 if (!error) {
2441 if (udf_rw16(fid->tag.id) != TAGID_FID)
2442 error = ENOENT;
2443 }
2444 DPRINTFIF(FIDS, !error, ("\ttag checked ok: got TAGID_FID\n"));
2445
2446 /* check for length */
2447 if (!error) {
2448 entry_length = udf_fidsize(fid, lb_size);
2449 enough = (dir_uio.uio_offset - (*offset) >= entry_length);
2450 }
2451 DPRINTFIF(FIDS, !error, ("\tentry_length = %d, enough = %s\n",
2452 entry_length, enough?"yes":"no"));
2453
2454 if (!enough) {
2455 /* short dir ... bomb out */
2456 return EIO;
2457 }
2458
2459 /* check FID contents */
2460 if (!error) {
2461 error = udf_check_tag_payload((union dscrptr *) fid, lb_size);
2462 DPRINTF(FIDS, ("\tpayload checked ok\n"));
2463 }
2464 if (error) {
2465 /* note that is sometimes a bit quick to report */
2466 printf("BROKEN DIRECTORY ENTRY\n");
2467 /* RESYNC? */
2468 /* TODO: use udf_resync_fid_stream */
2469 return EIO;
2470 }
2471 DPRINTF(FIDS, ("\tinterpret FID\n"));
2472
2473 /* we got a whole and valid descriptor! */
2474
2475 /* create resulting dirent structure */
2476 fid_name = (char *) fid->data + udf_rw16(fid->l_iu);
2477 udf_to_unix_name(dirent->d_name,
2478 fid_name, fid->l_fi, &ump->logical_vol->desc_charset);
2479
2480 /* '..' has no name, so provide one */
2481 if (fid->file_char & UDF_FILE_CHAR_PAR)
2482 strcpy(dirent->d_name, "..");
2483
2484 dirent->d_fileno = udf_calchash(&fid->icb); /* inode hash XXX */
2485 dirent->d_namlen = strlen(dirent->d_name);
2486 dirent->d_reclen = _DIRENT_SIZE(dirent);
2487
2488 /*
2489 * Note that its not worth trying to go for the filetypes now... its
2490 * too expensive too
2491 */
2492 dirent->d_type = DT_UNKNOWN;
2493
2494 /* initial guess for filetype we can make */
2495 if (fid->file_char & UDF_FILE_CHAR_DIR)
2496 dirent->d_type = DT_DIR;
2497
2498 /* advance */
2499 *offset += entry_length;
2500
2501 return error;
2502 }
2503
2504 /* --------------------------------------------------------------------- */
2505
2506 /*
2507 * block based file reading and writing
2508 */
2509
2510 static int
2511 udf_read_internal(struct udf_node *node, uint8_t *blob)
2512 {
2513 struct udf_mount *ump;
2514 struct file_entry *fe;
2515 struct extfile_entry *efe;
2516 uint64_t inflen;
2517 uint32_t sector_size;
2518 uint8_t *pos;
2519 int icbflags, addr_type;
2520
2521 /* shut up gcc */
2522 inflen = addr_type = icbflags = 0;
2523 pos = NULL;
2524
2525 /* get extent and do some paranoia checks */
2526 ump = node->ump;
2527 sector_size = ump->discinfo.sector_size;
2528
2529 fe = node->fe;
2530 efe = node->efe;
2531 if (fe) {
2532 inflen = udf_rw64(fe->inf_len);
2533 pos = &fe->data[0] + udf_rw32(fe->l_ea);
2534 icbflags = udf_rw16(fe->icbtag.flags);
2535 }
2536 if (efe) {
2537 inflen = udf_rw64(efe->inf_len);
2538 pos = &efe->data[0] + udf_rw32(efe->l_ea);
2539 icbflags = udf_rw16(efe->icbtag.flags);
2540 }
2541 addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
2542
2543 assert(addr_type == UDF_ICB_INTERN_ALLOC);
2544 assert(inflen < sector_size);
2545
2546 /* copy out info */
2547 memset(blob, 0, sector_size);
2548 memcpy(blob, pos, inflen);
2549
2550 return 0;
2551 }
2552
2553 /* --------------------------------------------------------------------- */
2554
2555 /*
2556 * Read file extent reads an extent specified in sectors from the file. It is
2557 * sector based; i.e. no `fancy' offsets.
2558 */
2559
2560 int
2561 udf_read_file_extent(struct udf_node *node,
2562 uint32_t from, uint32_t sectors,
2563 uint8_t *blob)
2564 {
2565 struct buf buf;
2566 uint32_t sector_size;
2567
2568 BUF_INIT(&buf);
2569
2570 sector_size = node->ump->discinfo.sector_size;
2571
2572 buf.b_bufsize = sectors * sector_size;
2573 buf.b_data = blob;
2574 buf.b_bcount = buf.b_bufsize;
2575 buf.b_resid = buf.b_bcount;
2576 buf.b_flags = B_BUSY | B_READ;
2577 buf.b_vp = node->vnode;
2578 buf.b_proc = NULL;
2579
2580 buf.b_blkno = from;
2581 buf.b_lblkno = 0;
2582 BIO_SETPRIO(&buf, BPRIO_TIMELIMITED);
2583
2584 udf_read_filebuf(node, &buf);
2585 return biowait(&buf);
2586 }
2587
2588
2589 /* --------------------------------------------------------------------- */
2590
2591 /*
2592 * Read file extent in the buffer.
2593 *
2594 * The splitup of the extent into seperate request-buffers is to minimise
2595 * copying around as much as possible.
2596 */
2597
2598
2599 /* mininum of 128 translations (!) (64 kb in 512 byte sectors) */
2600 #define FILEBUFSECT 128
2601
2602 void
2603 udf_read_filebuf(struct udf_node *node, struct buf *buf)
2604 {
2605 struct buf *nestbuf;
2606 uint64_t *mapping;
2607 uint64_t run_start;
2608 uint32_t sector_size;
2609 uint32_t buf_offset, sector, rbuflen, rblk;
2610 uint8_t *buf_pos;
2611 int error, run_length;
2612
2613 uint32_t from;
2614 uint32_t sectors;
2615
2616 sector_size = node->ump->discinfo.sector_size;
2617
2618 from = buf->b_blkno;
2619 sectors = buf->b_bcount / sector_size;
2620
2621 /* assure we have enough translation slots */
2622 KASSERT(buf->b_bcount / sector_size <= FILEBUFSECT);
2623 KASSERT(MAXPHYS / sector_size <= FILEBUFSECT);
2624
2625 if (sectors > FILEBUFSECT) {
2626 printf("udf_read_filebuf: implementation limit on bufsize\n");
2627 buf->b_error = EIO;
2628 buf->b_flags |= B_ERROR;
2629 biodone(buf);
2630 return;
2631 }
2632
2633 mapping = malloc(sizeof(*mapping) * FILEBUFSECT, M_TEMP, M_WAITOK);
2634
2635 error = 0;
2636 DPRINTF(READ, ("\ttranslate %d-%d\n", from, sectors));
2637 error = udf_translate_file_extent(node, from, sectors, mapping);
2638 if (error) {
2639 buf->b_error = error;
2640 buf->b_flags |= B_ERROR;
2641 biodone(buf);
2642 goto out;
2643 }
2644 DPRINTF(READ, ("\ttranslate extent went OK\n"));
2645
2646 /* pre-check if internal or parts are zero */
2647 if (*mapping == UDF_TRANS_INTERN) {
2648 error = udf_read_internal(node, (uint8_t *) buf->b_data);
2649 if (error) {
2650 buf->b_error = error;
2651 buf->b_flags |= B_ERROR;
2652 }
2653 biodone(buf);
2654 goto out;
2655 }
2656 DPRINTF(READ, ("\tnot intern\n"));
2657
2658 /* request read-in of data from disc sheduler */
2659 buf->b_resid = buf->b_bcount;
2660 for (sector = 0; sector < sectors; sector++) {
2661 buf_offset = sector * sector_size;
2662 buf_pos = (uint8_t *) buf->b_data + buf_offset;
2663 DPRINTF(READ, ("\tprocessing rel sector %d\n", sector));
2664
2665 switch (mapping[sector]) {
2666 case UDF_TRANS_UNMAPPED:
2667 case UDF_TRANS_ZERO:
2668 /* copy zero sector */
2669 memset(buf_pos, 0, sector_size);
2670 DPRINTF(READ, ("\treturning zero sector\n"));
2671 nestiobuf_done(buf, sector_size, 0);
2672 break;
2673 default :
2674 DPRINTF(READ, ("\tread sector "
2675 "%"PRIu64"\n", mapping[sector]));
2676
2677 run_start = mapping[sector];
2678 run_length = 1;
2679 while (sector < sectors-1) {
2680 if (mapping[sector+1] != mapping[sector]+1)
2681 break;
2682 run_length++;
2683 sector++;
2684 }
2685
2686 /*
2687 * nest an iobuf and mark it for async reading. Since
2688 * we're using nested buffers, they can't be cached by
2689 * design.
2690 */
2691 rbuflen = run_length * sector_size;
2692 rblk = run_start * (sector_size/DEV_BSIZE);
2693
2694 nestbuf = getiobuf();
2695 nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
2696 /* nestbuf is B_ASYNC */
2697
2698 /* CD shedules on raw blkno */
2699 nestbuf->b_blkno = rblk;
2700 nestbuf->b_proc = NULL;
2701 nestbuf->b_cylinder = 0;
2702 nestbuf->b_rawblkno = rblk;
2703 VOP_STRATEGY(node->ump->devvp, nestbuf);
2704 }
2705 }
2706 out:
2707 DPRINTF(READ, ("\tend of read_filebuf\n"));
2708 free(mapping, M_TEMP);
2709 return;
2710 }
2711 #undef FILEBUFSECT
2712
2713
2714 /* --------------------------------------------------------------------- */
2715
2716 /*
2717 * Translate an extent (in sectors) into sector numbers; used for read and
2718 * write operations. DOESNT't check extents.
2719 */
2720
2721 int
2722 udf_translate_file_extent(struct udf_node *node,
2723 uint32_t from, uint32_t pages,
2724 uint64_t *map)
2725 {
2726 struct udf_mount *ump;
2727 struct file_entry *fe;
2728 struct extfile_entry *efe;
2729 struct short_ad *s_ad;
2730 struct long_ad *l_ad, t_ad;
2731 uint64_t transsec;
2732 uint32_t sector_size, transsec32;
2733 uint32_t overlap, translen;
2734 uint32_t vpart_num, lb_num, len, alloclen;
2735 uint8_t *pos;
2736 int error, flags, addr_type, icblen, icbflags;
2737
2738 if (!node)
2739 return ENOENT;
2740
2741 /* shut up gcc */
2742 alloclen = addr_type = icbflags = 0;
2743 pos = NULL;
2744
2745 /* do the work */
2746 ump = node->ump;
2747 sector_size = ump->discinfo.sector_size;
2748 fe = node->fe;
2749 efe = node->efe;
2750 if (fe) {
2751 alloclen = udf_rw32(fe->l_ad);
2752 pos = &fe->data[0] + udf_rw32(fe->l_ea);
2753 icbflags = udf_rw16(fe->icbtag.flags);
2754 }
2755 if (efe) {
2756 alloclen = udf_rw32(efe->l_ad);
2757 pos = &efe->data[0] + udf_rw32(efe->l_ea);
2758 icbflags = udf_rw16(efe->icbtag.flags);
2759 }
2760 addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
2761
2762 DPRINTF(TRANSLATE, ("udf trans: alloc_len = %d, addr_type %d, "
2763 "fe %p, efe %p\n", alloclen, addr_type, fe, efe));
2764
2765 vpart_num = udf_rw16(node->loc.loc.part_num);
2766 lb_num = len = icblen = 0; /* shut up gcc */
2767 while (pages && alloclen) {
2768 DPRINTF(TRANSLATE, ("\taddr_type %d\n", addr_type));
2769 switch (addr_type) {
2770 case UDF_ICB_INTERN_ALLOC :
2771 /* TODO check extents? */
2772 *map = UDF_TRANS_INTERN;
2773 return 0;
2774 case UDF_ICB_SHORT_ALLOC :
2775 icblen = sizeof(struct short_ad);
2776 s_ad = (struct short_ad *) pos;
2777 len = udf_rw32(s_ad->len);
2778 lb_num = udf_rw32(s_ad->lb_num);
2779 break;
2780 case UDF_ICB_LONG_ALLOC :
2781 icblen = sizeof(struct long_ad);
2782 l_ad = (struct long_ad *) pos;
2783 len = udf_rw32(l_ad->len);
2784 lb_num = udf_rw32(l_ad->loc.lb_num);
2785 vpart_num = udf_rw16(l_ad->loc.part_num);
2786 DPRINTFIF(TRANSLATE,
2787 (l_ad->impl.im_used.flags &
2788 UDF_ADIMP_FLAGS_EXTENT_ERASED),
2789 ("UDF: got an `extent erased' flag in long_ad\n"));
2790 break;
2791 default:
2792 /* can't be here */
2793 return EINVAL; /* for sure */
2794 }
2795
2796 /* process extent */
2797 flags = UDF_EXT_FLAGS(len);
2798 len = UDF_EXT_LEN(len);
2799
2800 overlap = (len + sector_size -1) / sector_size;
2801 if (from) {
2802 if (from > overlap) {
2803 from -= overlap;
2804 overlap = 0;
2805 } else {
2806 lb_num += from; /* advance in extent */
2807 overlap -= from;
2808 from = 0;
2809 }
2810 }
2811
2812 overlap = MIN(overlap, pages);
2813 while (overlap) {
2814 switch (flags) {
2815 case UDF_EXT_REDIRECT :
2816 /* no support for allocation extentions yet */
2817 /* TODO support for allocation extention */
2818 return ENOENT;
2819 case UDF_EXT_FREED :
2820 case UDF_EXT_FREE :
2821 transsec = UDF_TRANS_ZERO;
2822 translen = overlap;
2823 while (overlap && pages && translen) {
2824 *map++ = transsec;
2825 overlap--; pages--; translen--;
2826 }
2827 break;
2828 case UDF_EXT_ALLOCATED :
2829 t_ad.loc.lb_num = udf_rw32(lb_num);
2830 t_ad.loc.part_num = udf_rw16(vpart_num);
2831 error = udf_translate_vtop(ump,
2832 &t_ad, &transsec32, &translen);
2833 transsec = transsec32;
2834 if (error)
2835 return error;
2836 while (overlap && pages && translen) {
2837 *map++ = transsec;
2838 transsec++;
2839 overlap--; pages--; translen--;
2840 }
2841 break;
2842 }
2843 }
2844 pos += icblen;
2845 alloclen -= icblen;
2846 }
2847 return 0;
2848 }
2849
2850 /* --------------------------------------------------------------------- */
2851
2852