1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <malloc.h>
29#include <unistd.h>
30#include <strings.h>
31#include <errno.h>
32#include <libintl.h>
33#include <libgen.h>
34#include <fcntl.h>
35#include <sys/types.h>
36#include <sys/int_types.h>
37#include <sys/dkio.h>
38#include <sys/cdio.h>
39#include <sys/vtoc.h>
40#include <sys/stat.h>
41#include <sys/param.h>
42#include <sys/fs/udf_volume.h>
43#include "ud_lib.h"
44
45extern char *getfullrawname(char *);
46
47static int32_t ud_get_ecma_ver(ud_handle_t, uint32_t);
48static int32_t ud_get_fs_bsize(ud_handle_t, uint32_t, uint32_t *);
49static int32_t ud_parse_fill_vds(ud_handle_t, struct vds *, uint32_t, uint32_t);
50static int32_t	ud_read_and_translate_lvd(ud_handle_t, uint32_t, uint32_t);
51static int32_t ud_get_latest_lvid(ud_handle_t, uint32_t, uint32_t);
52static int32_t	ud_get_latest_fsd(ud_handle_t, uint16_t, uint32_t, uint32_t);
53
54static uint16_t ud_crc(uint8_t *, int32_t);
55static int32_t UdfTxName(uint16_t *, int32_t);
56static int32_t UncompressUnicode(int32_t, uint8_t *, uint16_t *);
57static int32_t ud_compressunicode(int32_t, int32_t, uint16_t *, uint8_t *);
58static int32_t ud_convert2utf8(uint8_t *, uint8_t *, int32_t);
59static int32_t ud_convert2utf16(uint8_t *, uint8_t *, int32_t);
60
61
62int
63ud_init(int fd, ud_handle_t *hp)
64{
65	struct ud_handle *h;
66
67	if ((h = calloc(1, sizeof (struct ud_handle))) == NULL) {
68		return (ENOMEM);
69	}
70	h->fd = fd;
71	*hp = h;
72	return (0);
73}
74
75void
76ud_fini(ud_handle_t h)
77{
78	free(h);
79}
80
81/* ARGSUSED */
82int32_t
83ud_open_dev(ud_handle_t h, char *special, uint32_t flags)
84{
85	char *temp;
86	struct stat i_stat, r_stat;
87
88	(void) bzero(&i_stat, sizeof (struct stat));
89	(void) bzero(&r_stat, sizeof (struct stat));
90
91	/*
92	 * Get the stat structure
93	 */
94	if (stat(special, &i_stat) < 0) {
95		temp = special;
96	} else {
97
98		if ((i_stat.st_mode & S_IFMT) == S_IFCHR) {
99
100			/*
101			 * If Raw deivce is given use it as it is
102			 */
103
104			temp = special;
105		} else if ((i_stat.st_mode & S_IFMT) == S_IFBLK) {
106
107			/*
108			 * Block device try to convert to raw device
109			 */
110
111			temp = getfullrawname(special);
112
113			/*
114			 * Stat the converted device name and verify
115			 * both the raw and block device belong to
116			 * the same device
117			 */
118			if (stat(temp, &r_stat) < 0) {
119				temp = special;
120			} else {
121				if (((r_stat.st_mode & S_IFMT) == S_IFBLK) ||
122					(r_stat.st_rdev != i_stat.st_rdev)) {
123					temp = special;
124				}
125			}
126		}
127	}
128
129	/*
130	 * Now finally open the device
131	 */
132	h->fd = open(temp, flags);
133
134	return (h->fd);
135}
136
137/* ARGSUSED */
138void
139ud_close_dev(ud_handle_t h)
140{
141	/*
142	 * Too simple Just close it
143	 */
144	(void) close(h->fd);
145}
146
147int32_t
148ud_read_dev(ud_handle_t h, uint64_t offset, uint8_t *buf, uint32_t count)
149{
150	/*
151	 * Seek to the given offset
152	 */
153	if (lseek(h->fd, offset, SEEK_SET) == -1) {
154		return (1);
155	}
156
157	/*
158	 * Read the required number of bytes
159	 */
160	if (read(h->fd, buf, count) != count) {
161		return (1);
162	}
163	return (0);
164}
165
166int32_t
167ud_write_dev(ud_handle_t h, uint64_t offset, uint8_t *buf, uint32_t count)
168{
169	/*
170	 * Seek to the given offset
171	 */
172	if (lseek(h->fd, offset, SEEK_SET) == -1) {
173		return (1);
174	}
175
176	/*
177	 * Read the appropriate number of bytes
178	 */
179	if (write(h->fd, buf, count) != count) {
180		return (1);
181	}
182	return (0);
183}
184
185/* ----- BEGIN Read and translate the on disk VDS to IN CORE format -------- */
186
187int32_t
188ud_fill_udfs_info(ud_handle_t h)
189{
190	struct	anch_vol_desc_ptr	*avdp = NULL;
191	uint32_t			offset = 0;
192
193	if (ioctl(h->fd, CDROMREADOFFSET, &offset) == -1) {
194		offset = 0;
195	}
196
197	h->udfs.flags = INVALID_UDFS;
198
199	h->udfs.ecma_version = ud_get_ecma_ver(h, offset);
200	if (h->udfs.ecma_version == UD_ECMA_UNKN) {
201		return (1);
202	}
203
204	h->udfs.lbsize = ud_get_fs_bsize(h, offset, &h->udfs.avdp_loc);
205	if (h->udfs.lbsize == 0) {
206		return (2);
207	}
208
209	h->udfs.avdp_len = lb_roundup(512, h->udfs.lbsize);
210
211
212	if ((avdp = (struct anch_vol_desc_ptr *)
213			malloc(h->udfs.lbsize)) == NULL) {
214		return (3);
215	}
216	if (ud_read_dev(h, h->udfs.avdp_loc * h->udfs.lbsize,
217			(uint8_t *)avdp, h->udfs.lbsize) != 0) {
218		free(avdp);
219		return (4);
220	}
221	if (ud_verify_tag(h, &avdp->avd_tag, UD_ANCH_VOL_DESC,
222			h->udfs.avdp_loc, 1, 0) != 0) {
223		free(avdp);
224		return (5);
225	}
226
227	h->udfs.mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc);
228	h->udfs.mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len);
229
230	h->udfs.rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc);
231	h->udfs.rvds_len = SWAP_32(avdp->avd_res_vdse.ext_len);
232
233	free(avdp);
234
235	/*
236	 * get information from mvds and rvds
237	 */
238	if (ud_parse_fill_vds(h, &h->udfs.mvds,
239			h->udfs.mvds_loc, h->udfs.mvds_len) == 0) {
240		h->udfs.flags |= VALID_MVDS;
241	}
242	if (ud_parse_fill_vds(h, &h->udfs.rvds,
243			h->udfs.rvds_loc, h->udfs.rvds_len) == 0) {
244		h->udfs.flags |= VALID_RVDS;
245	}
246
247	if ((h->udfs.flags & (VALID_MVDS | VALID_RVDS)) == 0) {
248		return (6);
249	}
250
251	/*
252	 * If we are here we have
253	 * a valid Volume Descriptor Seqence
254	 * Read and understand lvd
255	 */
256	if (h->udfs.flags & VALID_MVDS) {
257		if (ud_read_and_translate_lvd(h, h->udfs.mvds.lvd_loc,
258				h->udfs.mvds.lvd_len) != 0) {
259			return (7);
260		}
261	} else {
262		if (ud_read_and_translate_lvd(h, h->udfs.rvds.lvd_loc,
263				h->udfs.rvds.lvd_len) != 0) {
264			return (8);
265		}
266	}
267
268	h->udfs.flags |= VALID_UDFS;
269
270	return (0);
271}
272
273static int32_t
274ud_get_ecma_ver(ud_handle_t h, uint32_t offset)
275{
276	uint8_t *buf;
277	uint64_t off;
278	uint64_t end_off;
279	struct nsr_desc *ndsc;
280	uint32_t ecma_ver = UD_ECMA_UNKN;
281
282	/*
283	 * Allocate a buffer of size UD_VOL_REC_BSZ
284	 */
285	if ((buf = (uint8_t *)malloc(UD_VOL_REC_BSZ)) == NULL) {
286
287		/*
288		 * Uh could not even allocate this much
289		 */
290		goto end;
291	}
292
293	/*
294	 * Start from 32k and keep reading 2k blocks we
295	 * should be able to find NSR if we have one by 256 * 2k bytes
296	 */
297	off = offset * 2048 + UD_VOL_REC_START;
298	end_off = offset * 2048 + UD_VOL_REC_END;
299	for (; off < end_off; off += UD_VOL_REC_BSZ) {
300
301		if (ud_read_dev(h, off, buf, UD_VOL_REC_BSZ) == 0) {
302
303			ndsc = (struct nsr_desc *)buf;
304			/*
305			 * Is this either NSR02 or NSR03
306			 */
307			if ((ndsc->nsr_str_type == 0) &&
308				(ndsc->nsr_ver == 1) &&
309				(ndsc->nsr_id[0] == 'N') &&
310				(ndsc->nsr_id[1] == 'S') &&
311				(ndsc->nsr_id[2] == 'R') &&
312				(ndsc->nsr_id[3] == '0') &&
313					((ndsc->nsr_id[4] == '2') ||
314					(ndsc->nsr_id[4] == '3'))) {
315
316				(void) strncpy((char *)h->udfs.ecma_id,
317					(char *)ndsc->nsr_id, 5);
318
319				switch (ndsc->nsr_id[4]) {
320				case '2' :
321
322					/*
323					 * ECMA 167/2
324					 */
325					ecma_ver = UD_ECMA_VER2;
326					goto end;
327				case '3' :
328
329					/*
330					 * ECMA 167/3
331					 */
332					ecma_ver = UD_ECMA_VER3;
333					goto end;
334				}
335			}
336		}
337	}
338
339end:
340	/*
341	 * Cleanup
342	 */
343	free(buf);
344	return (ecma_ver);
345}
346
347static uint32_t last_block_index[] = {0, 0, 256, 2, 2 + 256,
348		150, 150 + 256, 152, 152 + 256};
349
350static int32_t
351ud_get_fs_bsize(ud_handle_t h, uint32_t offset, uint32_t *avd_loc)
352{
353	uint64_t off;
354	int32_t index, bsize, shift, end_index;
355	uint32_t num_blocks, sub_blk;
356	uint8_t *buf = NULL;
357	struct anch_vol_desc_ptr *avdp;
358
359	if ((buf = (uint8_t *)malloc(MAXBSIZE)) == NULL) {
360		return (0);
361	}
362
363	/*
364	 * If we could figure out the last block
365	 * search at 256, N, N - 256 blocks
366	 * otherwise just check at 256
367	 */
368	if (ud_get_num_blks(h, &num_blocks) != 0) {
369		end_index = 1;
370		num_blocks = 0;
371	} else {
372		end_index = sizeof (last_block_index) / 4;
373	}
374
375	for (index = 0; index < end_index; index++) {
376		sub_blk = last_block_index[index];
377
378		/*
379		 * Start guessing from DEV_BSIZE to MAXBSIZE
380		 */
381		for (bsize = DEV_BSIZE, shift = 0;
382			bsize <= MAXBSIZE; bsize <<= 1, shift++) {
383
384			if (index == 0) {
385
386				/*
387				 * Check if we atleast have 256 of bsize
388				 * blocks on the device
389				 */
390				if ((end_index == 0) ||
391					(num_blocks > (256 << shift))) {
392					*avd_loc = 256;
393					if (bsize <= 2048) {
394						*avd_loc +=
395							offset * 2048 / bsize;
396					} else {
397						*avd_loc +=
398							offset / (bsize / 2048);
399					}
400				} else {
401					continue;
402				}
403			} else {
404				/*
405				 * Calculate the bsize avd block
406				 */
407				if ((num_blocks) &&
408					(num_blocks > (sub_blk << shift))) {
409					*avd_loc = (num_blocks >> shift) -
410						sub_blk;
411				} else {
412					continue;
413				}
414			}
415
416			off = (uint64_t)*avd_loc * bsize;
417
418			/*
419			 * Read bsize bytes at off
420			 */
421			if (ud_read_dev(h, off, buf, bsize) != 0) {
422				continue;
423			}
424
425			/*
426			 * Check if we have a Anchor Volume Descriptor here
427			 */
428
429			/* LINTED */
430			avdp = (struct anch_vol_desc_ptr *)buf;
431			if (ud_verify_tag(h, &avdp->avd_tag,
432				UD_ANCH_VOL_DESC, *avd_loc, 1, 0) != 0) {
433				continue;
434			}
435			goto end;
436		}
437	}
438
439end:
440	if (bsize > MAXBSIZE) {
441		bsize = 0;
442		*avd_loc = 0;
443	}
444	free(buf);
445	return (bsize);
446}
447
448static int32_t
449ud_parse_fill_vds(ud_handle_t h, struct vds *v,
450	uint32_t vds_loc, uint32_t vds_len)
451{
452	uint8_t *addr, *taddr, *eaddr;
453	uint16_t id;
454	int32_t i;
455	uint64_t off;
456	struct tag *tag;
457	struct pri_vol_desc *pvd;
458	struct log_vol_desc *lvd;
459	struct vol_desc_ptr *vds;
460	struct unall_spc_desc *usd;
461
462begin:
463	if ((addr = (uint8_t *)malloc(vds_len)) == NULL) {
464		return (1);
465	}
466
467	off = vds_loc * h->udfs.lbsize;
468	if (ud_read_dev(h, off, addr, vds_len) != 0) {
469		goto end;
470	}
471
472	for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr;
473			taddr += h->udfs.lbsize, vds_loc ++) {
474
475		/* LINTED */
476		tag = (struct tag *)taddr;
477		id = SWAP_16(tag->tag_id);
478		/*
479		 * If you cannot verify the tag just skip it
480		 * This is not a fatal error
481		 */
482		if (ud_verify_tag(h, tag, id, vds_loc, 1, 0) != 0) {
483			continue;
484		}
485		switch (id) {
486		case UD_PRI_VOL_DESC :
487
488			/*
489			 * Primary Volume Descriptor
490			 */
491			/* LINTED */
492			pvd = (struct pri_vol_desc *)taddr;
493			if ((v->pvd_len == 0) ||
494				(SWAP_32(pvd->pvd_vdsn) > v->pvd_vdsn)) {
495				v->pvd_vdsn = SWAP_32(pvd->pvd_vdsn);
496				v->pvd_loc = vds_loc;
497				v->pvd_len = h->udfs.lbsize;
498			}
499			break;
500		case UD_VOL_DESC_PTR :
501
502			/*
503			 * Curent sequence is continued from
504			 * the location pointed by vdp
505			 */
506			/* LINTED */
507			vds = (struct vol_desc_ptr *)taddr;
508
509			if (SWAP_32(vds->vdp_nvdse.ext_len) != 0) {
510				vds_loc = SWAP_32(vds->vdp_nvdse.ext_loc);
511				vds_len = SWAP_32(vds->vdp_nvdse.ext_len);
512				free(addr);
513				goto begin;
514			}
515			break;
516		case UD_IMPL_USE_DESC :
517
518			/*
519			 * Implementation Use Volume Descriptor
520			 */
521			v->iud_loc = vds_loc;
522			v->iud_len = lb_roundup(512, h->udfs.lbsize);
523			break;
524		case UD_PART_DESC :
525			{
526				struct ud_part *p;
527				struct phdr_desc *ph;
528				struct part_desc *pd;
529
530				/*
531				 * Partition Descriptor
532				 */
533				/* LINTED */
534				pd = (struct part_desc *)taddr;
535
536				for (i = 0; i < h->n_parts; i++) {
537					p = &h->part[i];
538
539					if ((SWAP_16(pd->pd_pnum) ==
540							p->udp_number) &&
541						(SWAP_32(pd->pd_vdsn) >
542							p->udp_seqno)) {
543						break;
544					}
545				}
546
547				v->part_loc[i] = vds_loc;
548				v->part_len[i] =
549					lb_roundup(512, h->udfs.lbsize);
550
551				p = &h->part[i];
552				p->udp_number = SWAP_16(pd->pd_pnum);
553				p->udp_seqno = SWAP_32(pd->pd_vdsn);
554				p->udp_access = SWAP_32(pd->pd_acc_type);
555				p->udp_start = SWAP_32(pd->pd_part_start);
556				p->udp_length = SWAP_32(pd->pd_part_length);
557
558				/* LINTED */
559				ph = (struct phdr_desc *)pd->pd_pc_use;
560				if (ph->phdr_ust.sad_ext_len) {
561			p->udp_flags = UDP_SPACETBLS;
562			p->udp_unall_loc = SWAP_32(ph->phdr_ust.sad_ext_loc);
563			p->udp_unall_len = SWAP_32(ph->phdr_ust.sad_ext_len);
564			p->udp_freed_loc = SWAP_32(ph->phdr_fst.sad_ext_loc);
565			p->udp_freed_len = SWAP_32(ph->phdr_fst.sad_ext_len);
566				} else {
567			p->udp_flags = UDP_BITMAPS;
568			p->udp_unall_loc = SWAP_32(ph->phdr_usb.sad_ext_loc);
569			p->udp_unall_len = SWAP_32(ph->phdr_usb.sad_ext_len);
570			p->udp_freed_loc = SWAP_32(ph->phdr_fsb.sad_ext_loc);
571			p->udp_freed_len = SWAP_32(ph->phdr_fsb.sad_ext_len);
572				}
573
574				if (i == h->n_parts) {
575					h->n_parts ++;
576				}
577			}
578			break;
579		case UD_LOG_VOL_DESC :
580
581			/*
582			 * Logical Volume Descriptor
583			 */
584			/* LINTED */
585			lvd = (struct log_vol_desc *)taddr;
586			if ((v->lvd_len == 0) ||
587				(SWAP_32(lvd->lvd_vdsn) > v->lvd_vdsn)) {
588				v->lvd_vdsn = SWAP_32(lvd->lvd_vdsn);
589				v->lvd_loc = vds_loc;
590				v->lvd_len = ((uint32_t)
591					&((struct log_vol_desc *)0)->lvd_pmaps);
592				v->lvd_len =
593					lb_roundup(v->lvd_len, h->udfs.lbsize);
594			}
595			break;
596		case UD_UNALL_SPA_DESC :
597
598			/*
599			 * Unallocated Space Descriptor
600			 */
601			/* LINTED */
602			usd = (struct unall_spc_desc *)taddr;
603			v->usd_loc = vds_loc;
604			v->usd_len = ((uint32_t)
605			&((unall_spc_desc_t *)0)->ua_al_dsc) +
606				SWAP_32(usd->ua_nad) *
607				sizeof (struct extent_ad);
608			v->usd_len = lb_roundup(v->usd_len, h->udfs.lbsize);
609			break;
610		case UD_TERM_DESC :
611			/*
612			 * Success fully completed
613			 */
614			goto end;
615		default :
616			/*
617			 * If you donot undetstand any tag just skip
618			 * it. This is not a fatal error
619			 */
620			break;
621		}
622	}
623
624end:
625	free(addr);
626	if ((v->pvd_len == 0) ||
627		(v->part_len[0] == 0) ||
628		(v->lvd_len == 0)) {
629		return (1);
630	}
631
632	return (0);
633}
634
635static int32_t
636ud_read_and_translate_lvd(ud_handle_t h, uint32_t lvd_loc, uint32_t lvd_len)
637{
638	caddr_t addr;
639	uint16_t fsd_prn;
640	uint32_t fsd_loc, fsd_len;
641	uint32_t lvds_loc, lvds_len;
642	uint64_t off;
643	struct log_vol_desc *lvd = NULL;
644
645	int32_t max_maps, i, mp_sz, index;
646	struct ud_map *m;
647	struct pmap_hdr *ph;
648	struct pmap_typ1 *typ1;
649	struct pmap_typ2 *typ2;
650
651	if (lvd_len == 0) {
652		return (1);
653	}
654
655	if ((lvd = (struct log_vol_desc *)
656			malloc(lvd_len)) == NULL) {
657		return (1);
658	}
659
660	off = lvd_loc * h->udfs.lbsize;
661	if (ud_read_dev(h, off, (uint8_t *)lvd, lvd_len) != 0) {
662		free(lvd);
663		return (1);
664	}
665
666	if (ud_verify_tag(h, &lvd->lvd_tag, UD_LOG_VOL_DESC,
667			lvd_loc, 1, 0) != 0) {
668		free(lvd);
669		return (1);
670	}
671
672	/*
673	 * Take care of maps
674	 */
675	max_maps = SWAP_32(lvd->lvd_num_pmaps);
676	ph = (struct pmap_hdr *)lvd->lvd_pmaps;
677	for (h->n_maps = index = 0; index < max_maps; index++) {
678		m = &h->maps[h->n_maps];
679		switch (ph->maph_type) {
680		case MAP_TYPE1 :
681
682			/* LINTED */
683			typ1 = (struct pmap_typ1 *)ph;
684
685			m->udm_flags = UDM_MAP_NORM;
686			m->udm_vsn = SWAP_16(typ1->map1_vsn);
687			m->udm_pn = SWAP_16(typ1->map1_pn);
688			h->n_maps++;
689			break;
690
691		case MAP_TYPE2 :
692
693			/* LINTED */
694			typ2 = (struct pmap_typ2 *)ph;
695
696			if (strncmp(typ2->map2_pti.reg_id,
697					UDF_VIRT_PART, 23) == 0) {
698
699				m->udm_flags = UDM_MAP_VPM;
700				m->udm_vsn = SWAP_16(typ2->map2_vsn);
701				m->udm_pn = SWAP_16(typ2->map2_pn);
702			} else if (strncmp(typ2->map2_pti.reg_id,
703					UDF_SPAR_PART, 23) == 0) {
704
705				if ((SWAP_16(typ2->map2_pl) != 32) ||
706						(typ2->map2_nst < 1) ||
707						(typ2->map2_nst > 4)) {
708					break;
709				}
710				m->udm_flags = UDM_MAP_SPM;
711				m->udm_vsn = SWAP_16(typ2->map2_vsn);
712				m->udm_pn = SWAP_16(typ2->map2_pn);
713
714				m->udm_plen = SWAP_16(typ2->map2_pl);
715				m->udm_nspm = typ2->map2_nst;
716				m->udm_spsz = SWAP_32(typ2->map2_sest);
717
718				mp_sz = lb_roundup(m->udm_spsz, h->udfs.lbsize);
719
720				if ((addr = malloc(mp_sz * m->udm_nspm)) ==
721						NULL) {
722					break;
723				}
724
725				for (i = 0; i < m->udm_nspm; i++) {
726					m->udm_loc[i] =
727						SWAP_32(typ2->map2_st[index]);
728					m->udm_spaddr[i] = addr + i * mp_sz;
729
730					off = m->udm_loc[i] * h->udfs.lbsize;
731					if (ud_read_dev(h, off,
732						(uint8_t *)m->udm_spaddr[i],
733							mp_sz) != 0) {
734						m->udm_spaddr[i] = NULL;
735						continue;
736					}
737				}
738			}
739			h->n_maps++;
740		default :
741			break;
742		}
743		ph = (struct pmap_hdr *)(((uint8_t *)h) + ph->maph_length);
744	}
745
746	lvds_loc = SWAP_32(lvd->lvd_int_seq_ext.ext_loc);
747	lvds_len = SWAP_32(lvd->lvd_int_seq_ext.ext_len);
748
749	fsd_prn = SWAP_16(lvd->lvd_lvcu.lad_ext_prn);
750	fsd_loc = SWAP_32(lvd->lvd_lvcu.lad_ext_loc);
751	fsd_len = SWAP_32(lvd->lvd_lvcu.lad_ext_len);
752
753	free(lvd);
754
755	/*
756	 * Get the latest LVID
757	 */
758	if (ud_get_latest_lvid(h, lvds_loc, lvds_len) != 0) {
759		return (1);
760	}
761
762	if (ud_get_latest_fsd(h, fsd_prn, fsd_loc, fsd_len) != 0) {
763		return (1);
764	}
765
766	return (0);
767}
768
769static int32_t
770ud_get_latest_lvid(ud_handle_t h, uint32_t lvds_loc, uint32_t lvds_len)
771{
772	uint8_t *addr, *taddr, *eaddr;
773	uint16_t id;
774	uint64_t off;
775	struct tag *tag;
776	struct log_vol_int_desc *lvid;
777
778begin:
779	if ((addr = (uint8_t *)malloc(lvds_len)) == NULL) {
780		return (1);
781	}
782
783	off = lvds_loc * h->udfs.lbsize;
784	if (ud_read_dev(h, off, addr, lvds_len) != 0) {
785		goto end;
786	}
787
788	for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr;
789			taddr += h->udfs.lbsize, lvds_loc ++) {
790
791		/* LINTED */
792		tag = (struct tag *)taddr;
793		id = SWAP_16(tag->tag_id);
794		/*
795		 * If you cannot verify the tag just skip it
796		 * This is not a fatal error
797		 */
798		if (ud_verify_tag(h, tag, id, lvds_loc, 1, 0) != 0) {
799			continue;
800		}
801		switch (id) {
802		case UD_LOG_VOL_INT :
803
804			/*
805			 * Logical Volume Integrity Descriptor
806			 */
807			/* LINTED */
808			lvid = (struct log_vol_int_desc *)taddr;
809			h->udfs.lvid_loc = lvds_loc;
810			h->udfs.lvid_len = ((uint32_t)
811			&((struct log_vol_int_desc *)0)->lvid_fst) +
812				SWAP_32(lvid->lvid_npart) * 8 +
813				SWAP_32(lvid->lvid_liu);
814			h->udfs.lvid_len = lb_roundup(h->udfs.lvid_len,
815				h->udfs.lbsize);
816
817			/*
818			 * It seems we have a next integrity
819			 * sequence
820			 */
821			if (SWAP_32(lvid->lvid_nie.ext_len) != 0) {
822				free(addr);
823				lvds_loc = SWAP_32(lvid->lvid_nie.ext_loc);
824				lvds_len = SWAP_32(lvid->lvid_nie.ext_len);
825				goto begin;
826			}
827			goto end;
828		case UD_TERM_DESC :
829
830			/*
831			 * Success fully completed
832			 */
833				goto end;
834		default :
835			/*
836			 * If you donot undetstand any tag just skip
837			 * it. This is not a fatal error
838			 */
839			break;
840		}
841	}
842end:
843	free(addr);
844	if (h->udfs.lvid_len == 0) {
845		return (1);
846	}
847	return (0);
848}
849
850static int32_t
851ud_get_latest_fsd(ud_handle_t h, uint16_t fsd_prn,
852	uint32_t fsd_loc, uint32_t fsd_len)
853{
854	uint8_t *addr, *taddr, *eaddr;
855	uint16_t id;
856	uint64_t off;
857	uint32_t fsds_loc, fsds_len;
858	struct tag *tag;
859	struct file_set_desc *fsd;
860	uint32_t old_fsn = 0;
861
862begin:
863	h->udfs.fsds_prn = fsd_prn;
864	h->udfs.fsds_loc = fsd_loc;
865	h->udfs.fsds_len = fsd_len;
866
867	fsds_loc = ud_xlate_to_daddr(h, fsd_prn, fsd_loc);
868	fsds_len = lb_roundup(fsd_len, h->udfs.lbsize);
869
870	if ((addr = (uint8_t *)malloc(fsds_len)) == NULL) {
871		return (1);
872	}
873
874	off = fsds_loc * h->udfs.lbsize;
875	if (ud_read_dev(h, off, addr, fsds_len) != 0) {
876		goto end;
877	}
878
879	for (taddr = addr, eaddr = addr + h->udfs.mvds_len; taddr < eaddr;
880			taddr += h->udfs.lbsize, fsds_loc ++) {
881
882		/* LINTED */
883		tag = (struct tag *)taddr;
884		id = SWAP_16(tag->tag_id);
885		/*
886		 * If you cannot verify the tag just skip it
887		 * This is not a fatal error
888		 */
889		if (ud_verify_tag(h, tag, id, fsds_loc, 1, 0) != 0) {
890			continue;
891		}
892		switch (id) {
893		case UD_FILE_SET_DESC :
894			/* LINTED */
895			fsd = (struct file_set_desc *)taddr;
896			if ((h->udfs.fsd_len == 0) ||
897				(SWAP_32(fsd->fsd_fs_no) > old_fsn)) {
898				old_fsn = SWAP_32(fsd->fsd_fs_no);
899				h->udfs.fsd_loc = fsds_loc;
900				h->udfs.fsd_len = lb_roundup(512,
901					h->udfs.lbsize);
902				h->udfs.ricb_prn =
903					SWAP_16(fsd->fsd_root_icb.lad_ext_prn);
904				h->udfs.ricb_loc =
905					SWAP_32(fsd->fsd_root_icb.lad_ext_loc);
906				h->udfs.ricb_len =
907					SWAP_32(fsd->fsd_root_icb.lad_ext_len);
908			}
909			if (SWAP_32(fsd->fsd_next.lad_ext_len) != 0) {
910				fsd_prn = SWAP_16(fsd->fsd_next.lad_ext_prn);
911				fsd_loc = SWAP_32(fsd->fsd_next.lad_ext_loc);
912				fsd_len = SWAP_32(fsd->fsd_next.lad_ext_len);
913				goto begin;
914			}
915			break;
916		case UD_TERM_DESC :
917
918			/*
919			 * Success fully completed
920			 */
921			goto end;
922		default :
923			/*
924			 * If you donot undetstand any tag just skip
925			 * it. This is not a fatal error
926			 */
927			break;
928		}
929	}
930
931end:
932	free(addr);
933	if (h->udfs.fsd_len == 0) {
934		return (1);
935	}
936	return (0);
937}
938
939int32_t
940ud_get_num_blks(ud_handle_t h, uint32_t *blkno)
941{
942	struct vtoc vtoc;
943	struct dk_cinfo dki_info;
944	int32_t error;
945
946	/*
947	 * Get VTOC from driver
948	 */
949	if ((error = ioctl(h->fd, DKIOCGVTOC, (intptr_t)&vtoc)) != 0) {
950		return (error);
951	}
952
953	/*
954	 * Verify if is proper
955	 */
956	if (vtoc.v_sanity != VTOC_SANE) {
957		return (EINVAL);
958	}
959
960	/*
961	 * Get dk_cinfo from driver
962	 */
963	if ((error = ioctl(h->fd, DKIOCINFO, (intptr_t)&dki_info)) != 0) {
964		return (error);
965	}
966
967	if (dki_info.dki_partition >= V_NUMPAR) {
968		return (EINVAL);
969	}
970
971	/*
972	 * Return the size of the partition
973	 */
974	*blkno = vtoc.v_part[dki_info.dki_partition].p_size;
975
976	return (0);
977}
978
979uint32_t
980ud_xlate_to_daddr(ud_handle_t h, uint16_t prn, uint32_t blkno)
981{
982	int32_t i;
983	struct ud_map *m;
984	struct ud_part *p;
985
986
987	if (prn < h->n_maps) {
988		m = &h->maps[prn];
989		for (i = 0; i < h->n_parts; i++) {
990			p = &h->part[i];
991			if (m->udm_pn == p->udp_number) {
992				return (p->udp_start + blkno);
993			}
994		}
995	}
996	return (0);
997}
998
999/* ------ END Read and translate the on disk VDS to IN CORE format -------- */
1000
1001int32_t
1002ud_verify_tag(ud_handle_t h, struct tag *tag, uint16_t id,
1003	uint32_t blockno, int32_t do_crc, int32_t print_msg)
1004{
1005	int32_t i;
1006	uint8_t *addr, cksum = 0;
1007	uint16_t crc;
1008
1009
1010	/*
1011	 * Verify Tag Identifier
1012	 */
1013	if (tag->tag_id != SWAP_16(id)) {
1014		if (print_msg != 0) {
1015			(void) fprintf(stderr,
1016				gettext("tag does not verify tag %x req %x\n"),
1017				SWAP_16(tag->tag_id), id);
1018		}
1019		return (1);
1020	}
1021
1022	/*
1023	 * Verify Tag Descriptor Version
1024	 */
1025	if (SWAP_16(tag->tag_desc_ver) != h->udfs.ecma_version) {
1026		if (print_msg != 0) {
1027			(void) fprintf(stderr,
1028				gettext("tag version does not match with "
1029				"NSR descriptor version TAG %x NSR %x\n"),
1030				SWAP_16(tag->tag_desc_ver),
1031				h->udfs.ecma_version);
1032		}
1033		return (1);
1034	}
1035
1036	/*
1037	 * Caliculate Tag Checksum
1038	 */
1039	addr = (uint8_t *)tag;
1040	for (i = 0; i <= 15; i++) {
1041		if (i != 4) {
1042			cksum += addr[i];
1043		}
1044	}
1045
1046	/*
1047	 * Verify Tag Checksum
1048	 */
1049	if (cksum != tag->tag_cksum) {
1050		if (print_msg != 0) {
1051			(void) fprintf(stderr,
1052				gettext("Checksum Does not Verify TAG"
1053				" %x CALC %x\n"), tag->tag_cksum, cksum);
1054		}
1055		return (1);
1056	}
1057
1058
1059	/*
1060	 * Do we want to do crc
1061	 */
1062	if (do_crc) {
1063		if (tag->tag_crc_len) {
1064
1065			/*
1066			 * Caliculate CRC for the descriptor
1067			 */
1068			crc = ud_crc(addr + 0x10, SWAP_16(tag->tag_crc_len));
1069
1070			/*
1071			 * Verify CRC
1072			 */
1073			if (crc != SWAP_16(tag->tag_crc)) {
1074				if (print_msg != 0) {
1075					(void) fprintf(stderr,
1076						gettext("CRC Does not verify"
1077						" TAG %x CALC %x %x\n"),
1078						SWAP_16(tag->tag_crc),
1079						crc, addr);
1080				}
1081			}
1082		}
1083
1084		/*
1085		 * Verify Tag Location
1086		 */
1087		if (SWAP_32(blockno) != tag->tag_loc) {
1088			if (print_msg != 0) {
1089				(void) fprintf(stderr,
1090					gettext("Tag Location Does not verify"
1091					" blockno %x tag_blockno %x\n"),
1092					blockno, SWAP_32(tag->tag_loc));
1093			}
1094		}
1095	}
1096
1097	return (0);
1098}
1099
1100
1101/* ARGSUSED1 */
1102void
1103ud_make_tag(ud_handle_t h, struct tag *tag, uint16_t tag_id,
1104	uint32_t blkno, uint16_t crc_len)
1105{
1106	int32_t i;
1107	uint16_t crc;
1108	uint8_t *addr, cksum = 0;
1109
1110	tag->tag_id = SWAP_16(tag_id);
1111	tag->tag_desc_ver = SWAP_16(h->udfs.ecma_version);
1112	tag->tag_cksum = 0;
1113	tag->tag_res = 0;
1114
1115	/*
1116	 * Calicualte and assign CRC, CRC_LEN
1117	 */
1118	addr = (uint8_t *)tag;
1119	crc = ud_crc(addr + 0x10, crc_len);
1120	tag->tag_crc = SWAP_16(crc);
1121	tag->tag_crc_len = SWAP_16(crc_len);
1122	tag->tag_loc = SWAP_32(blkno);
1123
1124	/*
1125	 * Caliculate Checksum
1126	 */
1127	for (i = 0; i <= 15; i++) {
1128		cksum += addr[i];
1129	}
1130
1131	/*
1132	 * Assign Checksum
1133	 */
1134	tag->tag_cksum = cksum;
1135}
1136
1137/* **************** udf specific subroutines *********************** */
1138
1139static uint16_t ud_crc_table[256] = {
1140	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
1141	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
1142	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
1143	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
1144	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
1145	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
1146	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
1147	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
1148	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
1149	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
1150	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
1151	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
1152	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
1153	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
1154	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
1155	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
1156	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
1157	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
1158	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
1159	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
1160	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
1161	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1162	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
1163	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
1164	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
1165	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
1166	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
1167	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
1168	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
1169	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
1170	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
1171	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
1172};
1173
1174static uint16_t
1175ud_crc(uint8_t *addr, int32_t len)
1176{
1177	uint16_t crc = 0;
1178
1179	while (len-- > 0) {
1180		crc = ud_crc_table[(crc >> 8 ^ *addr++) & 0xff] ^ (crc<<8);
1181	}
1182
1183	return (crc);
1184}
1185
1186#define	MAXNAMLEN	0x200
1187
1188
1189#define	POUND		0x0023
1190#define	DOT		0x002E
1191#define	SLASH		0x002F
1192#define	UNDERBAR	0x005F
1193
1194
1195static uint16_t htoc[16] = {'0', '1', '2', '3',
1196	'4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1197/*
1198 * unicode is the string of 16-bot characters
1199 * length is the number of 16-bit characters
1200 */
1201static int32_t
1202UdfTxName(uint16_t *unicode, int32_t count)
1203{
1204	int32_t i, j, k, lic, make_crc, dot_loc;
1205	uint16_t crc;
1206
1207	if ((unicode[0] == DOT) &&
1208		((count == 1) || ((count == 2) && (unicode[1] == DOT)))) {
1209		crc = DOT;
1210		if (count == 2) {
1211			crc += DOT;
1212		}
1213		unicode[0] = UNDERBAR;
1214		unicode[1] = POUND;
1215		unicode[2] = htoc[(uint16_t)(crc & 0xf000) >> 12];
1216		unicode[3] = htoc[(uint16_t)(crc & 0xf00) >> 8];
1217		unicode[4] = htoc[(uint16_t)(crc & 0xf0) >> 4];
1218		unicode[5] = htoc[crc & 0xf];
1219		return (6);
1220	}
1221	crc = 0;
1222	j = make_crc = 0;
1223	lic = dot_loc = -1;
1224	for (i = 0; i < count; i++) {
1225		if (make_crc) {
1226			crc += unicode[i];
1227		}
1228		if (unicode[i] == DOT) {
1229			dot_loc = j;
1230		}
1231		if ((unicode[i] == SLASH) ||
1232			(unicode[i] == 0)) {
1233			if (make_crc == 0) {
1234				for (k = 0; k <= i; k++) {
1235					crc += unicode[k];
1236				}
1237				make_crc = 1;
1238			}
1239			if (lic != (i - 1)) {
1240				unicode[j++] = UNDERBAR;
1241			}
1242			lic = i;
1243		} else {
1244			unicode[j++] = unicode[i];
1245		}
1246	}
1247
1248	if (make_crc) {
1249		if (dot_loc != -1) {
1250			if ((j + 5) > MAXNAMLEN) {
1251				if ((j - dot_loc + 5) > MAXNAMLEN) {
1252					j = MAXNAMLEN - 5 + dot_loc;
1253					for (k = MAXNAMLEN;
1254						j >= dot_loc; k --, j--) {
1255						unicode[k] = unicode[j];
1256					}
1257					k = 0;
1258				} else {
1259					for (k = MAXNAMLEN;
1260						j >= dot_loc; k--, j--) {
1261						unicode[k] = unicode[j];
1262					}
1263					k -= 4;
1264				}
1265				j = MAXNAMLEN;
1266			} else {
1267				for (k = j; k >= dot_loc; k--) {
1268					unicode[k + 5] = unicode[k];
1269				}
1270				k = dot_loc;
1271				j += 5;
1272			}
1273		} else {
1274			if ((j + 5) > MAXNAMLEN) {
1275				j = MAXNAMLEN;
1276				k = MAXNAMLEN - 5;
1277			} else {
1278				k = j;
1279				j += 5;
1280			}
1281		}
1282		unicode[k++] = POUND;
1283		unicode[k++] = htoc[(uint16_t)(crc & 0xf000) >> 12];
1284		unicode[k++] = htoc[(uint16_t)(crc & 0xf00) >> 8];
1285		unicode[k++] = htoc[(uint16_t)(crc & 0xf0) >> 4];
1286		unicode[k++] = htoc[crc & 0xf];
1287	}
1288	return (j);
1289}
1290
1291/*
1292 * Assumes the output buffer is large
1293 * enough to hold the uncompressed
1294 * code
1295 */
1296static int32_t
1297UncompressUnicode(
1298	int32_t numberOfBytes,	/* (Input) number of bytes read from media. */
1299	uint8_t *UDFCompressed,	/* (Input) bytes read from media. */
1300	uint16_t *unicode)	/* (Output) uncompressed unicode characters. */
1301{
1302	int32_t compID;
1303	int32_t returnValue, unicodeIndex, byteIndex;
1304
1305
1306	/*
1307	 * Use UDFCompressed to store current byte being read.
1308	 */
1309	compID = UDFCompressed[0];
1310
1311	/* First check for valid compID. */
1312	if (compID != 8 && compID != 16) {
1313		returnValue = -1;
1314	} else {
1315		unicodeIndex = 0;
1316		byteIndex = 1;
1317
1318		/* Loop through all the bytes. */
1319		while (byteIndex < numberOfBytes) {
1320			if (compID == 16) {
1321				/*
1322				 * Move the first byte to the
1323				 * high bits of the unicode char.
1324				 */
1325				unicode[unicodeIndex] =
1326					UDFCompressed[byteIndex++] << 8;
1327			} else {
1328				unicode[unicodeIndex] = 0;
1329			}
1330			if (byteIndex < numberOfBytes) {
1331				/*
1332				 * Then the next byte to the low bits.
1333				 */
1334				unicode[unicodeIndex] |=
1335					UDFCompressed[byteIndex++];
1336			}
1337			unicodeIndex++;
1338		}
1339		returnValue = unicodeIndex;
1340	}
1341	return (returnValue);
1342}
1343
1344
1345
1346
1347
1348static int32_t
1349ud_compressunicode(
1350	int32_t numberOfChars,	/* (Input) number of unicode characters. */
1351	int32_t compID,		/* (Input) compression ID to be used. */
1352	uint16_t *unicode,	/* (Input) unicode characters to compress. */
1353	uint8_t *UDFCompressed) /* (Output) compressed string, as bytes. */
1354{
1355	int32_t byteIndex;
1356
1357	if (compID != 8 && compID != 16) {
1358		/*
1359		 * Unsupported compression ID !
1360		 */
1361		byteIndex = -1;
1362	} else {
1363		/*
1364		 * Place compression code in first byte.
1365		 */
1366		UDFCompressed[0] = (uint8_t)compID;
1367		(void) strncpy((caddr_t)&UDFCompressed[1],
1368			(caddr_t)unicode, numberOfChars);
1369		byteIndex = numberOfChars + 1;
1370	}
1371	return (byteIndex);
1372}
1373
1374
1375static int32_t
1376ud_convert2utf8(uint8_t *ibuf, uint8_t *obuf, int32_t length)
1377{
1378	int i, size;
1379	uint16_t *buf;
1380
1381	/* LINTED */
1382	buf = (uint16_t *)obuf;
1383
1384	size = UncompressUnicode(length, ibuf, buf);
1385
1386	size = UdfTxName(buf, size);
1387
1388	for (i = 0; i < size; i++) {
1389		obuf[i] = (uint8_t)buf[i];
1390	}
1391	obuf[i] = '\0';
1392
1393	return (size);
1394}
1395
1396static int32_t
1397ud_convert2utf16(uint8_t *ibuf, uint8_t *obuf, int32_t length)
1398{
1399	int32_t comp_len;
1400	uint16_t *ptr;
1401
1402	/* LINTED */
1403	ptr = (uint16_t *)ibuf;
1404	comp_len = ud_compressunicode(length, 8, ptr, obuf);
1405
1406	return (comp_len);
1407}
1408
1409/*
1410 * Assumption code set is zero in udfs
1411 */
1412void
1413ud_convert2local(int8_t *ibuf, int8_t *obuf, int32_t length)
1414{
1415	wchar_t buf4c[128];
1416	int32_t i, comp, index;
1417
1418	/*
1419	 * Special uncompress code
1420	 * written to accomodate solaris wchar_t
1421	 */
1422	comp = ibuf[0];
1423	for (i = 0, index = 1; i < length; i++) {
1424		if (comp == 16) {
1425			buf4c[i] = ibuf[index++] << 8;
1426		} else {
1427			buf4c[i] = 0;
1428		}
1429		if (index < length) {
1430			buf4c[i] |= ibuf[index++];
1431		}
1432	}
1433	(void) wcstombs((char *)obuf, buf4c, 128);
1434}
1435
1436
1437/* ------------ Routines to print basic structures Part 1 ---------------- */
1438
1439
1440
1441void
1442print_charspec(FILE *fout, char *name, struct charspec *cspec)
1443{
1444	int i = 0;
1445
1446	(void) fprintf(fout,
1447		"%s : %x - \"", name, cspec->cs_type);
1448	for (i = 0; i < 63; i++) {
1449		(void) fprintf(fout,
1450			"%c", cspec->cs_info[i]);
1451	}
1452	(void) fprintf(fout, "\n");
1453}
1454
1455/* ARGSUSED */
1456void
1457print_dstring(FILE *fout, char *name, uint16_t cset, char *bufc, uint8_t length)
1458{
1459	int8_t bufmb[1024];
1460
1461	ud_convert2local(bufc, bufmb, length);
1462
1463	(void) fprintf(fout,
1464		"%s %s\n", name, bufmb);
1465}
1466
1467void
1468set_dstring(dstring_t *dp, char *cp, int32_t len)
1469{
1470	int32_t length;
1471
1472	bzero(dp, len);
1473	length = strlen(cp);
1474	if (length > len - 1) {
1475		length = len - 1;
1476	}
1477	(void) strncpy(dp, cp, length);
1478	dp[len - 1] = length;
1479}
1480
1481void
1482print_tstamp(FILE *fout, char *name, tstamp_t *ts)
1483{
1484	(void) fprintf(fout, "%s tz : %d yr : %d mo : %d da : %d "
1485		"Time : %d : %d : %d : %d : %d : %d\n", name,
1486		SWAP_16(ts->ts_tzone), SWAP_16(ts->ts_year), ts->ts_month,
1487		ts->ts_day, ts->ts_hour, ts->ts_min, ts->ts_sec, ts->ts_csec,
1488		ts->ts_husec, ts->ts_usec);
1489}
1490
1491
1492
1493void
1494make_regid(ud_handle_t h, struct regid *reg, char *id, int32_t type)
1495{
1496	reg->reg_flags = 0;
1497	(void) strncpy(reg->reg_id, id, 23);
1498
1499	if (type == REG_DOM_ID) {
1500		struct dom_id_suffix *dis;
1501
1502		/* LINTED */
1503		dis = (struct dom_id_suffix *)reg->reg_ids;
1504		dis->dis_udf_revison = SWAP_16(h->udfs.ma_write);
1505		dis->dis_domain_flags = 0;
1506
1507	} else if (type == REG_UDF_ID) {
1508		struct udf_id_suffix *uis;
1509
1510		/* LINTED */
1511		uis = (struct udf_id_suffix *)reg->reg_ids;
1512		uis->uis_udf_revision = SWAP_16(h->udfs.ma_write);
1513		uis->uis_os_class = OS_CLASS_UNIX;
1514		uis->uis_os_identifier = OS_IDENTIFIER_SOLARIS;
1515	} else if (type == REG_UDF_II) {
1516		struct impl_id_suffix *iis;
1517
1518		iis = (struct impl_id_suffix *)reg->reg_ids;
1519		iis->iis_os_class = OS_CLASS_UNIX;
1520		iis->iis_os_identifier = OS_IDENTIFIER_SOLARIS;
1521	}
1522}
1523
1524void
1525print_regid(FILE *fout, char *name, struct regid *reg, int32_t type)
1526{
1527	(void) fprintf(fout, "%s : 0x%x : \"%s\" :",
1528		name, reg->reg_flags, reg->reg_id);
1529
1530	if (type == REG_DOM_ID) {
1531		struct dom_id_suffix *dis;
1532
1533		/* LINTED */
1534		dis = (struct dom_id_suffix *)reg->reg_ids;
1535		(void) fprintf(fout, " 0x%x : %s : %s\n",
1536			SWAP_16(dis->dis_udf_revison),
1537			(dis->dis_domain_flags & PROTECT_SOFT_WRITE) ?
1538				"HW Protect" : "No HW Write Protect",
1539			(dis->dis_domain_flags & PROTECT_HARD_WRITE) ?
1540				"SW Protect" : "No SW Protect");
1541	} else if (type == REG_UDF_ID) {
1542		struct udf_id_suffix *uis;
1543
1544		/* LINTED */
1545		uis = (struct udf_id_suffix *)reg->reg_ids;
1546		(void) fprintf(fout,
1547			" 0x%x : OS Class 0x%x : OS Identifier 0x%x\n",
1548			SWAP_16(uis->uis_udf_revision),
1549			uis->uis_os_class, uis->uis_os_identifier);
1550	} else {
1551		struct impl_id_suffix *iis;
1552
1553		iis = (struct impl_id_suffix *)reg->reg_ids;
1554		(void) fprintf(fout,
1555			" OS Class 0x%x : OS Identifier 0x%x\n",
1556			iis->iis_os_class, iis->iis_os_identifier);
1557	}
1558}
1559
1560#ifdef	OLD
1561void
1562print_regid(FILE *fout, char *name, struct regid *reg)
1563{
1564	(void) fprintf(fout, "%s : 0x%x : \"%s\" :",
1565		name, reg->reg_flags, reg->reg_id);
1566
1567	if (strncmp(reg->reg_id, "*OSTA UDF Compliant", 19) == 0) {
1568		(void) fprintf(fout, " 0x%x : %s : %s\n",
1569			reg->reg_ids[0] | (reg->reg_ids[1] << 8),
1570			(reg->reg_ids[2] & 1) ?
1571				"HW Protect" : "No HW Write Protect",
1572			(reg->reg_ids[2] & 2) ?
1573				"SW Protect" : "No SW Protect");
1574	} else if ((strncmp(reg->reg_id, "*UDF Virtual Partition", 22) == 0) ||
1575		(strncmp(reg->reg_id, "*UDF Sparable Partition", 23) == 0) ||
1576		(strncmp(reg->reg_id, "*UDF Virtual Alloc Tbl", 22) == 0) ||
1577		(strncmp(reg->reg_id, "*UDF Sparing Table", 18) == 0)) {
1578		(void) fprintf(fout,
1579			" 0x%x : OS Class 0x%x : OS Identifier 0x%x\n",
1580			reg->reg_ids[0] | (reg->reg_ids[1] << 8),
1581			reg->reg_ids[2], reg->reg_ids[3]);
1582	} else {
1583		(void) fprintf(fout,
1584			" OS Class 0x%x : OS Identifier 0x%x\n",
1585			reg->reg_ids[0], reg->reg_ids[1]);
1586	}
1587}
1588#endif
1589
1590
1591/* ------------ Routines to print basic structures Part 2 ---------------- */
1592/*
1593 * Part 2
1594 * This part is OS specific and is currently
1595 * not supported
1596 */
1597
1598/* ------------ Routines to print basic structures Part 3 ---------------- */
1599
1600void
1601print_ext_ad(FILE *fout, char *name, struct extent_ad *ead)
1602{
1603	(void) fprintf(fout,
1604		"%s EAD Len %x Loc %x\n",
1605		name, SWAP_32(ead->ext_len), SWAP_32(ead->ext_loc));
1606}
1607
1608void
1609print_tag(FILE *fout, struct tag *tag)
1610{
1611	(void) fprintf(fout,
1612		"tag_id : %x ver : %x cksum : %x "
1613		"sno : %x crc : %x crc_len : %x loc : %x\n",
1614		SWAP_16(tag->tag_id), SWAP_16(tag->tag_desc_ver),
1615		tag->tag_cksum, SWAP_16(tag->tag_sno),
1616		SWAP_16(tag->tag_crc), SWAP_16(tag->tag_crc_len),
1617		SWAP_32(tag->tag_loc));
1618}
1619
1620
1621void
1622print_pvd(FILE *fout, struct pri_vol_desc *pvd)
1623{
1624	(void) fprintf(fout,
1625		"\n\t\t\tPrimary Volume Descriptor\n");
1626	print_tag(fout, &pvd->pvd_tag);
1627	(void) fprintf(fout, "vdsn : %x vdn : %x\n",
1628		SWAP_32(pvd->pvd_vdsn), SWAP_32(pvd->pvd_pvdn));
1629	print_dstring(fout, "volid : ", pvd->pvd_desc_cs.cs_type,
1630			pvd->pvd_vol_id, 32);
1631	(void) fprintf(fout,
1632		"vsn : %x mvsn : %x il : %x mil :"
1633		" %x csl : %x mcsl %x\n",
1634		SWAP_16(pvd->pvd_vsn), SWAP_16(pvd->pvd_mvsn),
1635		SWAP_16(pvd->pvd_il), SWAP_16(pvd->pvd_mil),
1636		SWAP_32(pvd->pvd_csl), SWAP_32(pvd->pvd_mcsl));
1637	print_dstring(fout, "vsid :", pvd->pvd_desc_cs.cs_type,
1638			pvd->pvd_vsi, 128);
1639	print_charspec(fout, "desc_cs", &pvd->pvd_desc_cs);
1640	print_charspec(fout, "exp_cs", &pvd->pvd_exp_cs);
1641	print_ext_ad(fout, "val ", &pvd->pvd_vol_abs);
1642	print_ext_ad(fout, "vcnl ", &pvd->pvd_vcn);
1643	print_regid(fout, "ai", &pvd->pvd_appl_id, REG_UDF_II);
1644	print_regid(fout, "ii", &pvd->pvd_ii, REG_UDF_II);
1645	(void) fprintf(fout, "pvdsl : %x flags : %x\n",
1646		SWAP_32(pvd->pvd_pvdsl),
1647		SWAP_16(pvd->pvd_flags));
1648}
1649
1650void
1651print_avd(FILE *fout, struct anch_vol_desc_ptr *avdp)
1652{
1653	(void) fprintf(fout,
1654		"\n\t\t\tAnchor Volume Descriptor\n");
1655	print_tag(fout, &avdp->avd_tag);
1656	print_ext_ad(fout, "Main Volume Descriptor Sequence : ",
1657			&avdp->avd_main_vdse);
1658	print_ext_ad(fout, "Reserve Volume Descriptor Sequence : ",
1659			&avdp->avd_res_vdse);
1660}
1661
1662void
1663print_vdp(FILE *fout, struct vol_desc_ptr *vdp)
1664{
1665	(void) fprintf(fout,
1666		"\n\t\t\tVolume Descriptor Pointer\n");
1667	print_tag(fout, &vdp->vdp_tag);
1668	(void) fprintf(fout, "vdsn : %x ",
1669		SWAP_32(vdp->vdp_vdsn));
1670	print_ext_ad(fout, "vdse ", &vdp->vdp_nvdse);
1671}
1672
1673void
1674print_iuvd(FILE *fout, struct iuvd_desc *iuvd)
1675{
1676	(void) fprintf(fout,
1677		"\n\t\t\tImplementation Use Volume Descriptor\n");
1678	print_tag(fout, &iuvd->iuvd_tag);
1679	(void) fprintf(fout,
1680		"vdsn : %x ", SWAP_32(iuvd->iuvd_vdsn));
1681	print_regid(fout, "Impl Id : ", &iuvd->iuvd_ii, REG_UDF_ID);
1682	print_charspec(fout, "cset ", &iuvd->iuvd_cset);
1683	print_dstring(fout, "lvi : ", iuvd->iuvd_cset.cs_type,
1684			iuvd->iuvd_lvi, 128);
1685	print_dstring(fout, "ifo1 : ", iuvd->iuvd_cset.cs_type,
1686			iuvd->iuvd_ifo1, 36);
1687	print_dstring(fout, "ifo2 : ", iuvd->iuvd_cset.cs_type,
1688			iuvd->iuvd_ifo2, 36);
1689	print_dstring(fout, "ifo3 : ", iuvd->iuvd_cset.cs_type,
1690			iuvd->iuvd_ifo3, 36);
1691
1692	print_regid(fout, "iid ", &iuvd->iuvd_iid, REG_UDF_II);
1693}
1694
1695void
1696print_part(FILE *fout, struct part_desc *pd)
1697{
1698	(void) fprintf(fout,
1699		"\n\t\t\tPartition Descriptor\n");
1700	print_tag(fout, &pd->pd_tag);
1701	(void) fprintf(fout,
1702		"vdsn : %x flags : %x num : %x ",
1703		SWAP_32(pd->pd_vdsn),
1704		SWAP_16(pd->pd_pflags),
1705		SWAP_16(pd->pd_pnum));
1706	print_regid(fout, "contents ", &pd->pd_pcontents, REG_UDF_II);
1707	/* LINTED */
1708	print_phdr(fout, (struct phdr_desc *)(&pd->pd_pc_use));
1709	(void) fprintf(fout,
1710		"acc : %x start : %x length : %x ",
1711		SWAP_32(pd->pd_acc_type),
1712		SWAP_32(pd->pd_part_start),
1713		SWAP_32(pd->pd_part_length));
1714	print_regid(fout, "Impl Id : ", &pd->pd_ii, REG_UDF_II);
1715}
1716
1717void
1718print_lvd(FILE *fout, struct log_vol_desc *lvd)
1719{
1720	(void) fprintf(fout,
1721		"\n\t\t\tLogical Volume Descriptor\n");
1722	print_tag(fout, &lvd->lvd_tag);
1723	(void) fprintf(fout,
1724		"vdsn : %x ", SWAP_32(lvd->lvd_vdsn));
1725	print_charspec(fout, "Desc Char Set ", &lvd->lvd_desc_cs);
1726	print_dstring(fout, "lvid : ", lvd->lvd_desc_cs.cs_type,
1727			lvd->lvd_lvid, 28);
1728	(void) fprintf(fout,
1729		"lbsize : %x ",
1730		SWAP_32(lvd->lvd_log_bsize));
1731	print_regid(fout, "Dom Id", &lvd->lvd_dom_id, REG_DOM_ID);
1732	print_long_ad(fout, "lvcu", &lvd->lvd_lvcu);
1733	(void) fprintf(fout,
1734		"mtlen : %x nmaps : %x ",
1735		SWAP_32(lvd->lvd_mtbl_len),
1736		SWAP_32(lvd->lvd_num_pmaps));
1737	print_regid(fout, "Impl Id : ", &lvd->lvd_ii, REG_UDF_II);
1738	print_ext_ad(fout, "Int Seq", &lvd->lvd_int_seq_ext);
1739	print_pmaps(fout, lvd->lvd_pmaps, SWAP_32(lvd->lvd_num_pmaps));
1740}
1741
1742void
1743print_usd(FILE *fout, struct unall_spc_desc *ua)
1744{
1745	int32_t i, count;
1746
1747	(void) fprintf(fout,
1748		"\n\t\t\tUnallocated Space Descriptor\n");
1749	print_tag(fout, &ua->ua_tag);
1750	count = SWAP_32(ua->ua_nad);
1751	(void) fprintf(fout,
1752		"vdsn : %x nad : %x\n",
1753		SWAP_32(ua->ua_vdsn), count);
1754	for (i = 0; i < count; i++) {
1755		(void) fprintf(fout,
1756			"loc : %x len : %x\n",
1757			SWAP_32(ua->ua_al_dsc[i * 2]),
1758			SWAP_32(ua->ua_al_dsc[i * 2 + 1]));
1759	}
1760}
1761
1762void
1763print_lvid(FILE *fout, struct log_vol_int_desc *lvid)
1764{
1765	int32_t i, count;
1766	caddr_t addr;
1767	struct lvid_iu *liu;
1768
1769	(void) fprintf(fout,
1770		"\n\t\t\tLogical Volume Integrity Descriptor\n");
1771	print_tag(fout, &lvid->lvid_tag);
1772	print_tstamp(fout, "Rec TM ", &lvid->lvid_tstamp);
1773	if (SWAP_32(lvid->lvid_int_type) == 0) {
1774		(void) fprintf(fout,
1775			"int_typ : Open\n");
1776	} else if (SWAP_32(lvid->lvid_int_type) == 1) {
1777		(void) fprintf(fout, "int_typ : Closed\n");
1778	} else {
1779		(void) fprintf(fout, "int_typ : Unknown\n");
1780	}
1781	print_ext_ad(fout, "Nie ", &lvid->lvid_nie);
1782	count = SWAP_32(lvid->lvid_npart);
1783	(void) fprintf(fout,
1784		"Uniq : %llx npart : %x liu : %x\n",
1785		SWAP_64(lvid->lvid_lvcu.lvhd_uniqid),
1786		count, SWAP_32(lvid->lvid_liu));
1787	for (i = 0; i < count; i++) {
1788		(void) fprintf(fout,
1789			"Part : %x Free : %x Size : %x\n",
1790			i, SWAP_32(lvid->lvid_fst[i]),
1791			SWAP_32(lvid->lvid_fst[count + i]));
1792	}
1793
1794	addr = (caddr_t)lvid->lvid_fst;
1795	/* LINTED */
1796	liu = (struct lvid_iu *)(addr + 2 * count * 4);
1797	print_regid(fout, "Impl Id :", &liu->lvidiu_regid, REG_UDF_II);
1798	(void) fprintf(fout,
1799		"nfiles : %x ndirs : %x miread : %x"
1800		" miwrite : %x mawrite : %x\n",
1801		SWAP_32(liu->lvidiu_nfiles), SWAP_32(liu->lvidiu_ndirs),
1802		SWAP_16(liu->lvidiu_mread), SWAP_16(liu->lvidiu_mwrite),
1803		SWAP_16(liu->lvidiu_maxwr));
1804}
1805
1806
1807/* ------------ Routines to print basic structures Part 4 ---------------- */
1808
1809void
1810print_fsd(FILE *fout, ud_handle_t h, struct file_set_desc *fsd)
1811{
1812	(void) fprintf(fout,
1813		"\n\t\t\tFile Set Descriptor\n");
1814
1815	print_tag(fout, &fsd->fsd_tag);
1816	print_tstamp(fout, "Rec TM ", &fsd->fsd_time);
1817	(void) fprintf(fout,
1818		"ilvl : %x milvl : %x csl : %x"
1819		" mcsl : %x fsn : %x fsdn : %x\n",
1820		SWAP_16(fsd->fsd_ilevel), SWAP_16(fsd->fsd_mi_level),
1821		SWAP_32(fsd->fsd_cs_list), SWAP_32(fsd->fsd_mcs_list),
1822		SWAP_32(fsd->fsd_fs_no), SWAP_32(fsd->fsd_fsd_no));
1823	print_charspec(fout, "ID CS ", &fsd->fsd_lvidcs);
1824	print_dstring(fout, "lvi : ", fsd->fsd_lvidcs.cs_type,
1825			fsd->fsd_lvid, 128);
1826	print_charspec(fout, "ID CS ", &fsd->fsd_fscs);
1827	print_dstring(fout, "fsi : ", fsd->fsd_lvidcs.cs_type,
1828			fsd->fsd_fsi, 32);
1829	print_dstring(fout, "cfi : ", fsd->fsd_lvidcs.cs_type,
1830			fsd->fsd_cfi, 32);
1831	print_dstring(fout, "afi : ", fsd->fsd_lvidcs.cs_type,
1832			fsd->fsd_afi, 32);
1833	print_long_ad(fout, "Ricb ", &fsd->fsd_root_icb);
1834	print_regid(fout, "DI ", &fsd->fsd_did, REG_DOM_ID);
1835	print_long_ad(fout, "Next Fsd ", &fsd->fsd_next);
1836	if (h->udfs.ecma_version == UD_ECMA_VER3) {
1837		print_long_ad(fout, "System Stream Directory ICB ",
1838				&fsd->fsd_next);
1839	}
1840}
1841
1842void
1843print_phdr(FILE *fout, struct phdr_desc *ph)
1844{
1845	print_short_ad(fout, "ust ", &ph->phdr_ust);
1846	print_short_ad(fout, "usb ", &ph->phdr_usb);
1847	print_short_ad(fout, "int ", &ph->phdr_it);
1848	print_short_ad(fout, "fst ", &ph->phdr_fst);
1849	print_short_ad(fout, "fsh ", &ph->phdr_fsb);
1850}
1851
1852void
1853print_fid(FILE *fout, struct file_id *fid)
1854{
1855	int32_t i;
1856	uint8_t *addr;
1857
1858	(void) fprintf(fout,
1859		"File Identifier Descriptor\n");
1860	print_tag(fout, &fid->fid_tag);
1861	(void) fprintf(fout, "fvn : %x fc : %x length : %x ",
1862		fid->fid_ver, fid->fid_flags, fid->fid_idlen);
1863	print_long_ad(fout, "ICB", &fid->fid_icb);
1864	addr = &fid->fid_spec[SWAP_16(fid->fid_iulen)];
1865	(void) fprintf(fout, "iulen : %x comp : %x name : ",
1866		SWAP_16(fid->fid_iulen), *addr);
1867	addr++;
1868	for (i = 0; i < fid->fid_idlen; i++) {
1869		(void) fprintf(fout, "%c", *addr++);
1870	}
1871	(void) fprintf(fout, "\n");
1872}
1873
1874void
1875print_aed(FILE *fout, struct alloc_ext_desc *aed)
1876{
1877	(void) fprintf(fout,
1878		"Allocation Extent Descriptor\n");
1879	print_tag(fout, &aed->aed_tag);
1880	(void) fprintf(fout, "prev ael loc : %x laed : %x\n",
1881		SWAP_32(aed->aed_rev_ael), SWAP_32(aed->aed_len_aed));
1882}
1883
1884static char *ftype[] = {
1885	"NON",  "USE",  "PIE",  "IE",
1886	"DIR",  "REG",  "BDEV", "CDEV",
1887	"EATT", "FIFO", "SOCK", "TERM",
1888	"SYML", "SDIR"
1889};
1890
1891void
1892print_icb_tag(FILE *fout, struct icb_tag *itag)
1893{
1894	(void) fprintf(fout,
1895		"prnde : %x strat : %x param : %x max_ent %x\n",
1896		SWAP_32(itag->itag_prnde), SWAP_16(itag->itag_strategy),
1897		SWAP_16(itag->itag_param), SWAP_16(itag->itag_max_ent));
1898	(void) fprintf(fout,
1899		"ftype : %s prn : %x loc : %x flags : %x\n",
1900		(itag->itag_ftype >= 14) ? ftype[0] : ftype[itag->itag_ftype],
1901		SWAP_16(itag->itag_lb_prn),
1902		SWAP_32(itag->itag_lb_loc), SWAP_16(itag->itag_flags));
1903}
1904
1905
1906void
1907print_ie(FILE *fout, struct indirect_entry *ie)
1908{
1909	(void) fprintf(fout,
1910		"Indirect Entry\n");
1911	print_tag(fout, &ie->ie_tag);
1912	print_icb_tag(fout, &ie->ie_icb_tag);
1913	print_long_ad(fout, "ICB", &ie->ie_indirecticb);
1914}
1915
1916void
1917print_td(FILE *fout, struct term_desc *td)
1918{
1919	(void) fprintf(fout,
1920		"Terminating Descriptor\n");
1921	print_tag(fout, &td->td_tag);
1922}
1923
1924void
1925print_fe(FILE *fout, struct file_entry *fe)
1926{
1927	(void) fprintf(fout,
1928		"File Entry\n");
1929	print_tag(fout, &fe->fe_tag);
1930	print_icb_tag(fout, &fe->fe_icb_tag);
1931	(void) fprintf(fout,
1932		"uid : %x gid : %x perms : %x nlnk : %x\n",
1933		SWAP_32(fe->fe_uid), SWAP_32(fe->fe_gid),
1934		SWAP_32(fe->fe_perms), SWAP_16(fe->fe_lcount));
1935	(void) fprintf(fout,
1936		"rec_for : %x rec_dis : %x rec_len : %x "
1937		"sz : %llx blks : %llx\n",
1938		fe->fe_rec_for, fe->fe_rec_dis, SWAP_32(fe->fe_rec_len),
1939		SWAP_64(fe->fe_info_len), SWAP_64(fe->fe_lbr));
1940	print_tstamp(fout, "ctime ", &fe->fe_acc_time);
1941	print_tstamp(fout, "mtime ", &fe->fe_mod_time);
1942	print_tstamp(fout, "atime ", &fe->fe_attr_time);
1943	(void) fprintf(fout,
1944		"ckpoint : %x ", SWAP_32(fe->fe_ckpoint));
1945	print_long_ad(fout, "ICB", &fe->fe_ea_icb);
1946	print_regid(fout, "impl", &fe->fe_impl_id, REG_UDF_II);
1947	(void) fprintf(fout,
1948		"uniq_id : %llx len_ear : %x len_adesc %x\n",
1949		SWAP_64(fe->fe_uniq_id), SWAP_32(fe->fe_len_ear),
1950		SWAP_32(fe->fe_len_adesc));
1951}
1952
1953void
1954print_pmaps(FILE *fout, uint8_t *addr, int32_t count)
1955{
1956	struct pmap_hdr *hdr;
1957	struct pmap_typ1 *map1;
1958	struct pmap_typ2 *map2;
1959
1960	while (count--) {
1961		hdr = (struct pmap_hdr *)addr;
1962		switch (hdr->maph_type) {
1963		case 1 :
1964			/* LINTED */
1965			map1 = (struct pmap_typ1 *)hdr;
1966			(void) fprintf(fout, "Map type 1 ");
1967			(void) fprintf(fout, "VSN %x prn %x\n",
1968					SWAP_16(map1->map1_vsn),
1969					SWAP_16(map1->map1_pn));
1970			break;
1971		case 2 :
1972			/* LINTED */
1973			map2 = (struct pmap_typ2 *)hdr;
1974			(void) fprintf(fout, "Map type 2 ");
1975			(void) fprintf(fout, "VSN %x prn %x\n",
1976					SWAP_16(map2->map2_vsn),
1977					SWAP_16(map2->map2_pn));
1978			print_regid(fout, "Partition Type Identifier",
1979					&map2->map2_pti, REG_UDF_ID);
1980			break;
1981		default :
1982			(void) fprintf(fout, "unknown map type\n");
1983		}
1984		addr += hdr->maph_length;
1985	}
1986}
1987
1988
1989
1990void
1991print_short_ad(FILE *fout, char *name, struct short_ad *sad)
1992{
1993	(void) fprintf(fout,
1994		"%s loc : %x len : %x\n", name,
1995		SWAP_32(sad->sad_ext_loc), SWAP_32(sad->sad_ext_len));
1996}
1997
1998void
1999print_long_ad(FILE *fout, char *name, struct long_ad *lad)
2000{
2001	(void) fprintf(fout,
2002		"%s prn : %x loc : %x len : %x\n", name,
2003		SWAP_16(lad->lad_ext_prn), SWAP_32(lad->lad_ext_loc),
2004		SWAP_32(lad->lad_ext_len));
2005}
2006