1 /* $NetBSD$ */
2 
3 /*
4  * File "udf_verbose.c" is part of the UDFclient toolkit.
5  * File $Id: udf_verbose.c,v 1.120 2018/08/09 20:28:46 reinoud Exp $ $Name:  $
6  *
7  * Copyright (c) 2003, 2004, 2005, 2006, 2011
8  * 	Reinoud Zandijk <reinoud@netbsd.org>
9  * All rights reserved.
10  *
11  * The UDFclient toolkit is distributed under the Clarified Artistic Licence.
12  * A copy of the licence is included in the distribution as
13  * `LICENCE.clearified.artistic' and a copy of the licence can also be
14  * requested at the GNU foundantion's website.
15  *
16  * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
39 
40 #include <sys/types.h>
41 
42 #include "udf.h"
43 #include "udf_bswap.h"
44 
45 
46 /* globals */
47 void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp);
48 void udf_dump_long_ad(char *prefix, struct long_ad *adr);
49 void udf_dump_descriptor(union dscrptr *dscrpt);
50 void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping);
51 
52 
udf_dump_unimpl(union dscrptr * dscrpt,char * name)53 void udf_dump_unimpl(union dscrptr *dscrpt, char *name) {
54 	dscrpt = dscrpt;
55 	printf("\t\t(unimplemented dump of `%s` tag)\n", name);
56 }
57 
58 
udf_dump_desc(struct desc_tag * tag)59 void udf_dump_desc(struct desc_tag *tag) {
60 	printf("\tTAG: descriptor %d, serial_num %d at sector %d, crc length %d bytes\n",
61 			udf_rw16(tag->id), udf_rw16(tag->serial_num), udf_rw32(tag->tag_loc), udf_rw16(tag->desc_crc_len));
62 }
63 
64 
udf_dump_anchor(struct anchor_vdp * vdp)65 void udf_dump_anchor(struct anchor_vdp *vdp) {
66 	printf("\t\tAnchor\n");
67 	printf("\t\t\tMain    volume descriptor set at %d for %d bytes\n",
68 			udf_rw32(vdp->main_vds_ex.loc),    udf_rw32(vdp->main_vds_ex.len));
69 	printf("\t\t\tReserve volume descriptor set at %d for %d bytes\n",
70 			udf_rw32(vdp->reserve_vds_ex.loc), udf_rw32(vdp->reserve_vds_ex.len));
71 }
72 
73 
udf_dump_disc_anchors(struct udf_discinfo * disc)74 void udf_dump_disc_anchors(struct udf_discinfo *disc) {
75 	int session;
76 
77 	printf("\nUDF Dump of disc in device %s\n", disc->dev->dev_name);
78 	printf("UDF sessions : ");
79 	for (session = 0; session < disc->num_sessions; session++) {
80 		if (disc->session_is_UDF[session]) {
81 			printf("Yes");
82 #if 0
83 			if (disc->session_quirks[session] & CD_SESS_QUIRK_SESSION_LOCAL) {
84 				printf("(local)");
85 			}
86 #endif
87 			printf(" ");
88 		} else {
89 			printf("No ");
90 		}
91 	}
92 	printf("\n\n");
93 	UDF_VERBOSE_TABLES(
94 		struct udf_session *udf_session;
95 		/* Dump anchors */
96 		STAILQ_FOREACH(udf_session, &disc->sessions, next_session) {
97 			printf("UDF session %d (lba %d + %d sectors) anchor dump : \n", udf_session->session_num,
98 					(uint32_t) disc->session_start[udf_session->session_num], (uint32_t) udf_session->session_length);
99 			udf_dump_descriptor((union dscrptr *) &udf_session->anchor);
100 		}
101 	)
102 }
103 
104 
udf_messy_unicode_conv(char * buf)105 char *udf_messy_unicode_conv(char *buf) {
106 	static char out_buf[1024];
107 	uint16_t *uni_pos, uni_char;
108 	char *pos;
109 
110 	pos = out_buf;
111 	uni_pos = (uint16_t *) buf;
112 
113 	while ((uni_char = *uni_pos++)) {
114 		if (uni_char & 0xff00) uni_char='_';
115 		*pos++ = uni_char;
116 	}
117 
118 	return out_buf;
119 }
120 
121 
udf_get_osname(int os_class,int os_id)122 char *udf_get_osname(int os_class, int os_id) {
123 	static char buffer[40];
124 
125 	switch (os_class) {
126 		case 0 : return "undefined OS";
127 		case 1 : return "DOS/Windows 3.x";
128 		case 2 : return "OS/2";
129 		case 3 : return "MacOS";
130 		case 4 :
131 			switch (os_id) {
132 				case 0 : return "UNIX";
133 				case 1 : return "IBM AIX";
134 				case 2 : return "SunOS/Solaris";
135 				case 3 : return "HP/UX";
136 				case 4 : return "Silicon Graphics Irix";
137 				case 5 : return "Linux";
138 				case 6 : return "MKLinux";
139 				case 7 : return "FreeBSD";
140 				case 8 : return "NetBSD";
141 				default :
142 					 sprintf(buffer, "unknown UNIX (%d)", os_id);
143 					 return buffer;
144 			}
145 		case 5 : return "MS Windows 9x";
146 		case 6 : return "MS Windows NT";
147 		case 7 : return "OS/400";
148 		case 8 : return "BeOS";
149 		case 9 : return "MS Windows CE";
150 		default :
151 			break;
152 	}
153 	sprintf(buffer, "unknown OS (%d, %d)", os_class, os_id);
154 	return buffer;
155 }
156 
157 
udf_dump_regid(char * prefix,struct regid * id,int regid_type)158 void udf_dump_regid(char *prefix, struct regid *id, int regid_type) {
159 	char    buffer[UDF_REGID_ID_SIZE+1];
160 	int     cnt, version;
161 	uint8_t *pos;
162 
163 	memcpy(buffer, id->id, UDF_REGID_ID_SIZE);
164 	buffer[UDF_REGID_ID_SIZE] = 0;
165 
166 	printf("%s `%s`", prefix, buffer);
167 	if (regid_type == UDF_REGID_NAME) {
168 		printf("\n");
169 		return;
170 	}
171 	printf(" (");
172 	pos = id->id_suffix;
173 	switch (regid_type) {
174 		case UDF_REGID_DOMAIN :
175 			version = udf_rw16(*((uint16_t *) pos));
176 			printf("UDFv %x; ", version);
177 			if ((pos[2]) & UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT) printf("HARD ");
178 			if ((pos[2]) & UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT) printf("SOFT");
179 			if (((pos[2]) & 3) == 0) printf("no");
180 			printf(" write protect ");
181 			if ((pos[2]) & ~3) printf("; also undefined flags 0x%d", pos[2] & ~3);
182 			break;
183 		case UDF_REGID_UDF :
184 			version = udf_rw16(*((uint16_t *) pos));
185 			printf("UDFv %x; ", version);
186 			printf("%s ", udf_get_osname(pos[2], pos[3]));
187 			break;
188 		case UDF_REGID_IMPLEMENTATION :
189 			printf("%s [", udf_get_osname(pos[0], pos[1]));
190 			for(cnt=2; cnt < 8; cnt++) {
191 				printf("%02x ", *pos++);
192 			}
193 			printf("]");
194 			break;
195 		case UDF_REGID_NAME :
196 			break;
197 		case UDF_REGID_APPLICATION :
198 		default :
199 			printf("[");
200 			for(cnt=0; cnt < 8; cnt++) {
201 				printf("%02x ", *pos++);
202 			}
203 			printf("]");
204 			break;
205 	}
206 	printf(") (flags=%d)\n", id->flags);
207 }
208 
209 
udf_dump_timestamp(char * prefix,struct timestamp * t)210 void udf_dump_timestamp(char *prefix, struct timestamp *t) {
211 	printf("%s (%4d %02d %02d at %02d:%02d:%02d.%02d.%02d.%02d)\n", prefix, udf_rw16(t->year), t->month, t->day,
212 			t->hour, t->minute, t->second, t->centisec, t->hund_usec, t->usec);
213 }
214 
215 
216 #if 0
217 void udf_dump_charspec(char *prefix, struct charspec *chsp) {
218 	int cnt, ch;
219 
220 	printf("%s type CS%d (", prefix, chsp->type);
221 	for (cnt=0; cnt<63; cnt++) {
222 		ch = chsp->inf[cnt];
223 		if (ch < 32 || ch > 126) {
224 			printf(".");
225 		} else {
226 			printf("%c", ch);
227 		}
228 	}
229 	printf(")\n");
230 }
231 #endif
232 
233 
udf_dump_sparing_table(struct udf_sparing_table * spt)234 void udf_dump_sparing_table(struct udf_sparing_table *spt) {
235 	struct spare_map_entry *sp_entry;
236 	uint32_t entry, entries;
237 
238 	printf("\t\tSparing table descriptor\n");
239 	udf_dump_regid("\t\t\tSparing table Id ", &spt->id, UDF_REGID_UDF);
240 	printf("\t\t\tRelocation table entries          %d\n", udf_rw16(spt->rt_l));
241 	printf("\t\t\tSequence number                   %d\n", udf_rw32(spt->seq_num));
242 	printf("\t\t\tMappings :");
243 
244 	entries = udf_rw16(spt->rt_l);
245 	for(entry = 0; entry < entries; entry++) {
246 		if (entry % 4 == 0) printf("\n\t\t\t\t");
247 		sp_entry = &spt->entries[entry];
248 		printf("[%08x -> %08x]   ", udf_rw32(sp_entry->org), udf_rw32(sp_entry->map));
249 	}
250 	printf("\n");
251 }
252 
253 
udf_dump_pri_vol(struct pri_vol_desc * pvd)254 void udf_dump_pri_vol(struct pri_vol_desc *pvd) {
255 	struct extent_ad *ext;
256 
257 	printf("\t\tPrimary volume descriptor\n");
258 	printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pvd->seq_num));
259 	printf("\t\t\tPrimary volume descriptor number  %d\n", udf_rw32(pvd->pvd_num));
260 	udf_dump_id("\t\t\tVolume Id     ", 32, pvd->vol_id, &pvd->desc_charset);
261 	printf("\t\t\tVolume sequence number            %d\n", udf_rw16(pvd->vds_num));
262 	printf("\t\t\tMaximum volume sequence number    %d\n", udf_rw16(pvd->max_vol_seq));
263 	printf("\t\t\tInterchange level                 %d\n", udf_rw16(pvd->ichg_lvl));
264 	printf("\t\t\tMaximum interchange level         %d\n", udf_rw16(pvd->max_ichg_lvl));
265 	udf_dump_id("\t\t\tVolume set Id ", 128, pvd->volset_id, &pvd->desc_charset);
266 	/* udf_dump_charspec("\t\t\tCharspec for this descriptor     ", &pvd->desc_charset); */
267 	/* udf_dump_charspec("\t\t\tCharspec for the explaination    ", &pvd->explanatory_charset); */
268 	ext = &pvd->vol_abstract;
269 	printf("\t\t\tVolume abstract  at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len));
270 	ext = &pvd->vol_copyright;
271 	printf("\t\t\tVolume copyright at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len));
272 	udf_dump_regid("\t\t\tApplication   id", &pvd->app_id, UDF_REGID_APPLICATION);
273 	udf_dump_timestamp("\t\t\tTimestamp", &pvd->time);
274 	udf_dump_regid("\t\t\tImplementator id", &pvd->imp_id, UDF_REGID_IMPLEMENTATION);
275 	printf("\t\t\tPrevious volume descriptor sequence locator at sector %d\n", udf_rw32(pvd->prev_vds_loc));
276 	printf("\t\t\tFlags %d\n", udf_rw16(pvd->flags));
277 }
278 
279 
udf_dump_implementation_volume(struct impvol_desc * ivd)280 void udf_dump_implementation_volume(struct impvol_desc *ivd) {
281 	struct charspec *charspec;
282 
283 	printf("\t\tImplementation use volume descriptor\n");
284 	printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(ivd->seq_num));
285 	udf_dump_regid("\t\t\tImplementator identifier", &ivd->impl_id, UDF_REGID_UDF);
286 
287 	/* check on UDF implementation info ... */
288 	if (strcmp((char *) ivd->impl_id.id, "*UDF LV Info") == 0) {
289 		charspec = &ivd->_impl_use.lv_info.lvi_charset;
290 		/* udf_dump_charspec("\t\t\tLV info charspec                 ", charspec); */
291 	        udf_dump_id("\t\t\tLogical volume identifier         ", 128, ivd->_impl_use.lv_info.logvol_id, charspec);
292 	        udf_dump_id("\t\t\tLV info 1                         ",  36, ivd->_impl_use.lv_info.lvinfo1,   charspec);
293 	        udf_dump_id("\t\t\tLV info 2                         ",  36, ivd->_impl_use.lv_info.lvinfo2,   charspec);
294 	        udf_dump_id("\t\t\tLV info 3                         ",  36, ivd->_impl_use.lv_info.lvinfo3,   charspec);
295 		udf_dump_regid("\t\t\tImplementation identifier", &ivd->_impl_use.lv_info.impl_id, UDF_REGID_IMPLEMENTATION);
296 	}
297 }
298 
299 
udf_dump_partition_access_type(int type)300 char *udf_dump_partition_access_type(int type) {
301 	switch (type) {
302 		case UDF_ACCESSTYPE_PSEUDO_OVERWITE : return "Pseudo overwiteable";
303 		case UDF_ACCESSTYPE_READ_ONLY       : return "Read only";
304 		case UDF_ACCESSTYPE_WRITE_ONCE      : return "Write once";
305 		case UDF_ACCESSTYPE_REWRITEABLE     : return "Rewritable (blocked or with erase)";
306 		case UDF_ACCESSTYPE_OVERWRITABLE    : return "Overwritable";
307 	}
308 	return "Unknown partion access type";
309 }
310 
311 
udf_dump_part(struct part_desc * pd)312 void udf_dump_part(struct part_desc *pd) {
313 	struct part_hdr_desc *part_hdr_desc;
314 
315 	printf("\t\tPartition descriptor\n");
316 	printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pd->seq_num));
317 	printf("\t\t\tFlags                             %d\n", udf_rw16(pd->flags));
318 	printf("\t\t\tPartition number                  %d\n", udf_rw16(pd->part_num));
319 	udf_dump_regid("\t\t\tContents", &pd->contents, UDF_REGID_APPLICATION);
320 	printf("\t\t\tAccessType                        %s\n", udf_dump_partition_access_type(udf_rw32(pd->access_type)));
321 	printf("\t\t\tPartition starts at sector %u for %u sectors\n", udf_rw32(pd->start_loc), udf_rw32(pd->part_len));
322 	udf_dump_regid("\t\t\tImplementator id", &pd->imp_id, UDF_REGID_IMPLEMENTATION);
323 
324 	printf("\t\t\tPartition contents use (file) descriptors:\n");
325 	if (strncmp((char *) pd->contents.id, "+NSR0", 5) == 0) {
326 		part_hdr_desc = &pd->pd_part_hdr;
327 		printf("\t\t\t\tUnallocated space table       at logic block %u for %u bytes\n",
328 				udf_rw32(part_hdr_desc->unalloc_space_table.lb_num),
329 				udf_rw32(part_hdr_desc->unalloc_space_table.len)
330 			);
331 		printf("\t\t\t\tUnallocated space bitmap      at logic block %u for %u bytes\n",
332 				udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num),
333 				udf_rw32(part_hdr_desc->unalloc_space_bitmap.len)
334 			);
335 		printf("\t\t\t\tPartition integrity table     at logic block %u for %u bytes\n",
336 				udf_rw32(part_hdr_desc->part_integrity_table.lb_num),
337 				udf_rw32(part_hdr_desc->part_integrity_table.len)
338 			);
339 		printf("\t\t\t\tReusable (freed) space table  at logic block %u for %u bytes\n",
340 				udf_rw32(part_hdr_desc->freed_space_table.lb_num),
341 				udf_rw32(part_hdr_desc->freed_space_table.len)
342 			);
343 		printf("\t\t\t\tReusable (freed) space bitmap at logic block %u for %u bytes\n",
344 				udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num),
345 				udf_rw32(part_hdr_desc->freed_space_bitmap.len)
346 			);
347 	} else {
348 		printf("\t\t\t\tWARNING: Unknown or unused contents\n");
349 	}
350 }
351 
352 
udf_dump_log_vol(struct logvol_desc * lvd)353 void udf_dump_log_vol(struct logvol_desc *lvd) {
354 	union udf_pmap *pmap;
355 	uint8_t pmap_type, pmap_size;
356 	uint8_t *pmap_pos;
357 	uint32_t map, sparing_table;
358 	uint32_t lb_size, packet_len;
359 
360 	lb_size = udf_rw32(lvd->lb_size);
361 
362 	printf("\t\tLogical volume descriptor\n");
363 	printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(lvd->seq_num));
364 	udf_dump_id("\t\t\tLogical volume id                ",  128, lvd->logvol_id, &lvd->desc_charset);
365 	printf("\t\t\tLogical block size                %d\n", udf_rw32(lvd->lb_size));
366 	udf_dump_regid("\t\t\tDomainId", &lvd->domain_id, UDF_REGID_DOMAIN);
367 	udf_dump_long_ad("\t\t\tFileset descriptor at", &lvd->_lvd_use.fsd_loc);
368 	printf("\t\t\tMap table length                  %d\n", udf_rw32(lvd->mt_l));
369 	printf("\t\t\tNumber of part maps               %d\n", udf_rw32(lvd->n_pm));
370 	udf_dump_regid("\t\t\tImplementation id", &lvd->imp_id, UDF_REGID_IMPLEMENTATION);
371 	printf("\t\t\tIntegrety sequence at %d for %d bytes\n",
372 			udf_rw32(lvd->integrity_seq_loc.loc), udf_rw32(lvd->integrity_seq_loc.len));
373 	printf("\t\t\tPartion maps follow\n");
374 
375 	pmap_pos = &lvd->maps[0];
376 	for (map = 0; map < udf_rw32(lvd->n_pm); map++) {
377 		pmap = (union udf_pmap *) pmap_pos;
378 		pmap_type = pmap->data[0];
379 		pmap_size = pmap->data[1];
380 
381 		printf("\t\t\t\tPartion map type %d length %d \n", pmap_type, pmap_size);
382 		/* only pmap types 1 and pmap types 2 are to be used */
383 		printf("\t\t\t\t\tLogical %d maps to ", map);
384 		switch (pmap_type) {
385 			case 1 :
386 				printf("partition %d on volume seq. number %d directly\n",
387 						udf_rw16(pmap->pm1.part_num), udf_rw16(pmap->pm1.vol_seq_num));
388 				break;
389 			case 2 :
390 				printf("partition %d on volume seq. number %d using\n",
391 						udf_rw16(pmap->pm2.part_num), udf_rw16(pmap->pm2.vol_seq_num));
392 				udf_dump_regid("\t\t\t\t\tmapping type", &pmap->pm2.part_id, UDF_REGID_UDF);
393 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Virtual Partition", UDF_REGID_ID_SIZE) == 0) {
394 					/* nothing to print... */
395 				}
396 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Sparable Partition", UDF_REGID_ID_SIZE) == 0) {
397 					packet_len = udf_rw16(pmap->pms.packet_len);
398 					printf("\t\t\t\t\t\tPacket length                %d sectors (%d bytes)\n",
399 							packet_len, packet_len * lb_size);
400 					printf("\t\t\t\t\t\tNumber of sparing tables     %d\n", pmap->pms.n_st);
401 					printf("\t\t\t\t\t\tSize of each sparing table   %d\n", udf_rw32(pmap->pms.st_size));
402 					if (pmap->pms.n_st) {
403 						printf("\t\t\t\t\t\tSparing tables at sectors    ");
404 						for (sparing_table = 0; sparing_table < pmap->pms.n_st; sparing_table++) {
405 							printf("%d ", udf_rw32(pmap->pms.st_loc[sparing_table]));
406 						}
407 						printf("\n");
408 					}
409 				}
410 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Metadata Partition", UDF_REGID_ID_SIZE) == 0) {
411 					printf("\t\t\t\t\t\tMetadata is %sduplicated on disc\n", pmap->pmm.flags & METADATA_DUPLICATED ? "":"NOT ");
412 					printf("\t\t\t\t\t\tAllocation unit size                  %d sectors\n", udf_rw32(pmap->pmm.alloc_unit_size));
413 					printf("\t\t\t\t\t\tAlignment  unit size                  %d sectors\n", udf_rw32(pmap->pmm.alignment_unit_size));
414 					printf("\t\t\t\t\t\tMetadata file at part. sector         %d\n", udf_rw32(pmap->pmm.meta_file_lbn));
415 					if (udf_rw32(pmap->pmm.meta_mirror_file_lbn) != (uint32_t) -1)
416 						printf("\t\t\t\t\t\tMetadata mirror file at part. sector  %d\n", udf_rw32(pmap->pmm.meta_mirror_file_lbn));
417 					if (udf_rw32(pmap->pmm.meta_bitmap_file_lbn) != (uint32_t) -1)
418 						printf("\t\t\t\t\t\tMetadata bitmap file at part. sector  %d\n", udf_rw32(pmap->pmm.meta_bitmap_file_lbn));
419 				}
420 				break;
421 			default :
422 				break;
423 		}
424 		pmap_pos += pmap_size;
425 	}
426 }
427 
428 
udf_dump_unalloc_space(struct unalloc_sp_desc * usd)429 void udf_dump_unalloc_space(struct unalloc_sp_desc *usd) {
430 	struct extent_ad *alloc_desc;
431 	uint32_t desc_num;
432 
433 	printf("\t\tUnallocated space descriptor\n");
434 	printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(usd->seq_num));
435 	printf("\t\t\tNumber of free space slots        %d\n", udf_rw32(usd->alloc_desc_num));
436 	if (udf_rw32(usd->alloc_desc_num)) {
437 		printf("\t\t\tFree space at : ");
438 		for (desc_num = 0; desc_num < udf_rw32(usd->alloc_desc_num); desc_num++) {
439 			alloc_desc = &usd->alloc_desc[desc_num];
440 			printf("[%d %d] ", udf_rw32(alloc_desc->loc), udf_rw32(alloc_desc->loc)+udf_rw32(alloc_desc->len));
441 		}
442 		printf("\n");
443 	}
444 }
445 
446 
udf_dump_terminating_desc(union dscrptr * desc)447 void udf_dump_terminating_desc(union dscrptr *desc) {
448 	desc = desc;
449 
450 	printf("\t\tTerminating descriptor\n");
451 }
452 
453 
udf_dump_logvol_integrity(struct logvol_int_desc * lvid)454 void udf_dump_logvol_integrity(struct logvol_int_desc *lvid) {
455 	struct udf_logvol_info *impl;
456 	uint32_t  part, num_part;
457 	uint32_t *pos1, *pos2;
458 	uint32_t  free, size, rest_bytes;
459 	uint32_t  version;
460 	const char *inttp;
461 
462 	printf("\t\tLogical volume integrity descriptor\n");
463 	udf_dump_timestamp("\t\t\tTimestamp                           ", &lvid->time);
464 
465 	inttp = "UNKNOWN/INVALID";
466 	if (udf_rw32(lvid->integrity_type) == UDF_INTEGRITY_CLOSED)
467 		inttp = "closed";
468 	if (udf_rw32(lvid->integrity_type) == UDF_INTEGRITY_OPEN)
469 		inttp = "closed";
470 	printf("\t\t\tIntegrity type                       %s\n", inttp);
471 	printf("\t\t\tNext integrity sequence at %d for %d bytes\n",
472 			udf_rw32(lvid->next_extent.loc), udf_rw32(lvid->next_extent.len));
473 	printf("\t\t\tNext free unique file ID             %d\n", (uint32_t) udf_rw64(lvid->lvint_next_unique_id));
474 	printf("\t\t\tLength of implementation use area    %d bytes\n", udf_rw32(lvid->l_iu));
475 
476 	num_part = udf_rw32(lvid->num_part);
477 	printf("\t\t\tNumber of partitions                 %d\n", num_part);
478 	for (part=0; part < num_part; part++) {
479 		pos1 = &lvid->tables[0] + part;
480 		pos2 = &lvid->tables[0] + num_part + part;
481 		free = udf_rw32(*pos1);
482 		size = udf_rw32(*pos2);
483 		printf("\t\t\tPartition %d : %u blocks free space out of %u blocks\n", part, free, size);
484 	}
485 
486 	/* printout the implementation use field */
487 	impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
488 
489 	udf_dump_regid("\t\t\tImplemenator Id", &impl->impl_id, UDF_REGID_IMPLEMENTATION );
490 	printf("\t\t\tNumber of files                      %d\n", udf_rw32(impl->num_files));
491 	printf("\t\t\tNumber of directories                %d\n", udf_rw32(impl->num_directories));
492 	version = udf_rw16(impl->min_udf_readver);
493 	printf("\t\t\tMinimum readversion                  UDFv %x\n", version);
494 	version = udf_rw16(impl->min_udf_writever);
495 	printf("\t\t\tMinimum writeversion                 UDFv %x\n", version);
496 	version = udf_rw16(impl->max_udf_writever);
497 	printf("\t\t\tMaximum writeversion                 UDFv %x\n", version);
498 	rest_bytes = udf_rw32(lvid->l_iu)-sizeof(struct udf_logvol_info);
499 	if (rest_bytes > 0) printf("\t\t\t<%d bytes of undumped extra implementation use area>", rest_bytes);
500 	printf("\n");
501 }
502 
503 
udf_dump_fileset_desc(struct fileset_desc * fsd)504 void udf_dump_fileset_desc(struct fileset_desc *fsd) {
505 	printf("\t\tFileset descriptor\n");
506 	udf_dump_timestamp("\t\t\tTimestamp                         ", &fsd->time);
507 	printf("\t\t\tInterchange level                  %d\n", udf_rw16(fsd->ichg_lvl));
508 	printf("\t\t\tMax interchange level              %d\n", udf_rw16(fsd->max_ichg_lvl));
509 	printf("\t\t\tCharset lists                      %d\n", udf_rw32(fsd->charset_list));
510 	printf("\t\t\tMax charset lists                  %d\n", udf_rw32(fsd->max_charset_list));
511 	printf("\t\t\tFileset number                     %d\n", udf_rw32(fsd->fileset_num));
512 	printf("\t\t\tFileset descriptor number          %d\n", udf_rw32(fsd->fileset_desc_num));
513 	/* udf_dump_charspec("\t\t\tLogical volume id charspec        ", &fsd->logvol_id_charset); */
514 	/* udf_dump_charspec("\t\t\tFileset id charspec               ", &fsd->fileset_charset); */
515 	udf_dump_id("\t\t\tLogical volume id                 ", 128, fsd->logvol_id,  &fsd->logvol_id_charset);
516 	udf_dump_id("\t\t\tFileset id                        ",  32, fsd->fileset_id, &fsd->fileset_charset);
517 	udf_dump_id("\t\t\tCopyright file id                 ",  32, fsd->copyright_file_id, &fsd->fileset_charset);
518 	udf_dump_id("\t\t\tAbstract file id                  ",  32, fsd->abstract_file_id,  &fsd->fileset_charset);
519 	udf_dump_regid("\t\t\tDomainId", &fsd->domain_id, UDF_REGID_DOMAIN);
520 	udf_dump_long_ad("\t\t\tRootdir ICB found       ", &fsd->rootdir_icb);
521 	udf_dump_long_ad("\t\t\tNext extend for fileset ", &fsd->next_ex);
522 	udf_dump_long_ad("\t\t\tStreamdir ICB found     ", &fsd->streamdir_icb);
523 }
524 
525 
udf_dump_fileid_in_charspec(struct fileid_desc * fid,struct charspec * chsp)526 void udf_dump_fileid_in_charspec(struct fileid_desc *fid, struct charspec *chsp) {
527 	char *pos, file_char;
528 
529 	printf("\tFile id entry\n");
530 	printf("\t\tFile version number                  %d\n", udf_rw16(fid->file_version_num));
531 	file_char = fid->file_char;
532 	printf("\t\tFile characteristics %d :\t", file_char);
533 	if (file_char & UDF_FILE_CHAR_VIS)  printf("hidden ");
534 	if (file_char & UDF_FILE_CHAR_DEL)  printf("deleted ");
535 	if (file_char & UDF_FILE_CHAR_PAR)  printf("parent(..) ");
536 	if (file_char & UDF_FILE_CHAR_DIR)  printf("directory ");
537 	if (file_char & UDF_FILE_CHAR_META) printf("METADATA ");
538 	printf("\n");
539 	udf_dump_long_ad("\t\tFile ICB", &fid->icb);
540 	printf("\t\tLength of file identifier area       %d\n", fid->l_fi);
541 	printf("\t\tOSTA UDF Unique ID                   %d\n", udf_rw32(fid->icb.impl.im_used.unique_id));
542 	printf("\t\tOSTA UDF fileflags                   %d\n", udf_rw16(fid->icb.impl.im_used.flags));
543 	printf("\t\tImplementation use length            %d\n", udf_rw16(fid->l_iu));
544 
545 	if (udf_rw16(fid->l_iu)) {
546 		/* Ecma 1/7.4 demands a (padded if wanted) implementation identifier */
547 		if (udf_rw16(fid->l_iu) >= sizeof(struct regid)) {
548 			udf_dump_regid("\t\t\tModified by", (struct regid *) &fid->data, UDF_REGID_IMPLEMENTATION);
549 		} else {
550 			printf("\t\t\tBROKEN fid, expected at least enough space for implementation regid\n");
551 		}
552 	}
553 
554 	pos = (char *) fid->data + udf_rw16(fid->l_iu);
555 	if (file_char & UDF_FILE_CHAR_PAR) {
556 		printf("\t\tParent directory ..\n");
557 	} else {
558 		udf_dump_id("\t\tFilename", fid->l_fi, pos, chsp);
559 	}
560 }
561 
562 
udf_dump_fileid(struct fileid_desc * fid)563 void udf_dump_fileid(struct fileid_desc *fid) {
564 	struct charspec chsp;
565 
566 	/* prolly OSTA compressed unicode anyway */
567 	chsp.type = 0;
568 	strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
569 
570 	udf_dump_fileid_in_charspec(fid, &chsp);
571 }
572 
573 
udf_dump_icb_tag(struct icb_tag * icb_tag)574 void udf_dump_icb_tag(struct icb_tag *icb_tag) {
575 	uint32_t flags, strat_param16;
576 
577 	flags = udf_rw16(icb_tag->flags);
578 	strat_param16 = udf_rw16(icb_tag->strat_param16);
579 	printf("\t\tICB Prior direct entries recorded (excl.)   %d\n", udf_rw32(icb_tag->prev_num_dirs));
580 	printf("\t\tICB Strategy type                           %d\n", udf_rw16(icb_tag->strat_type));
581 	printf("\t\tICB Strategy type flags                     %d %d\n", icb_tag->strat_param[0], icb_tag->strat_param[1]);
582 	printf("\t\tICB Maximum number of entries (non strat 4) %d\n", udf_rw16(icb_tag->max_num_entries));
583 	printf("\t\tICB     indirect entries/depth              %d\n", strat_param16);
584 	printf("\t\tICB File type                               %d\n", icb_tag->file_type);
585 	printf("\t\tICB Parent ICB in logical block %d of mapped partition %d\n",
586 		udf_rw32(icb_tag->parent_icb.lb_num), udf_rw16(icb_tag->parent_icb.part_num));
587 	printf("\t\tICB Flags                                   %d\n", udf_rw16(icb_tag->flags));
588 	printf("\t\t\tFile/directory information using : ");
589 	switch (flags & UDF_ICB_TAG_FLAGS_ALLOC_MASK) {
590 		case UDF_ICB_SHORT_ALLOC :
591 			printf("short allocation descriptor\n");
592 			break;
593 		case UDF_ICB_LONG_ALLOC :
594 			printf("long allocation descriptor\n");
595 			break;
596 		case UDF_ICB_EXT_ALLOC :
597 			printf("extended allocation descriptor (out of specs)\n");
598 			break;
599 		case UDF_ICB_INTERN_ALLOC :
600 			printf("internal in the ICB\n");
601 			break;
602 	}
603 	if (icb_tag->file_type == UDF_ICB_FILETYPE_DIRECTORY)
604 		if (flags & UDF_ICB_TAG_FLAGS_DIRORDERED)
605 			printf("\t\t\tOrdered directory\n");
606 	if (flags & UDF_ICB_TAG_FLAGS_NONRELOC) printf("\t\t\tNot relocatable\n");
607 	printf("\t\t\tFile flags :");
608 		if (flags & UDF_ICB_TAG_FLAGS_SETUID) printf("setuid() ");
609 		if (flags & UDF_ICB_TAG_FLAGS_SETGID) printf("setgid() ");
610 		if (flags & UDF_ICB_TAG_FLAGS_STICKY) printf("sticky ");
611 	printf("\n");
612 	if (flags & UDF_ICB_TAG_FLAGS_CONTIGUES)
613 		printf("\t\t\tFile is contigues i.e. in one piece effectively \n");
614 	if (flags & UDF_ICB_TAG_FLAGS_MULTIPLEVERS)
615 		printf("\t\t\tExpect multiple versions of a file in this directory\n");
616 }
617 
618 
udf_dump_indirect_entry(struct indirect_entry * inde)619 void udf_dump_indirect_entry(struct indirect_entry *inde) {
620 	printf("\tIndirect (ICB) entry\n");
621 	udf_dump_icb_tag(&inde->icbtag);
622 	udf_dump_long_ad("\t\tPointing at", &inde->indirect_icb);
623 	printf("\n");
624 }
625 
626 
udf_dump_allocation_entries(uint8_t addr_type,uint8_t * pos,uint32_t data_length)627 void udf_dump_allocation_entries(uint8_t addr_type, uint8_t *pos, uint32_t data_length) {
628 	union icb	*icb;
629 	uint32_t	 size, piece_length, piece_flags;
630 	uint32_t	 entry;
631 
632 	entry = 0;
633 	size  = 0;
634 	while (data_length) {
635 		if (entry % 1 == 0) printf("\n\t");
636 		printf(" [ ");
637 		printf("blob at ");
638 		/* what to do with strat type == 3 ? or is all set up ok then ? */
639 		icb = (union icb *) pos;
640 		switch (addr_type) {
641 			case UDF_ICB_SHORT_ALLOC  :
642 				piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<30)-1);
643 				piece_flags  = udf_rw32(icb->s_ad.len) >> 30;		/* XXX ecma167 48.14.1.1 XXX */
644 				printf("sector %8u for %8d bytes", udf_rw32(icb->s_ad.lb_num), piece_length);
645 				if (piece_flags) printf(" flags %d", piece_flags);
646 				size = sizeof(struct short_ad);
647 				if (piece_length == 0) size = data_length;
648 				break;
649 			case UDF_ICB_LONG_ALLOC   :
650 				piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<30)-1);
651 				piece_flags  = udf_rw32(icb->l_ad.len) >> 30;		/* XXX ecma167 48.14.1.1 XXX */
652 				printf("sector %8d for %8d bytes in logical partion %d", udf_rw32(icb->l_ad.loc.lb_num), piece_length,
653 						udf_rw16(icb->l_ad.loc.part_num));
654 				if (piece_flags) printf(" flags %d", piece_flags);
655 				size = sizeof(struct long_ad);
656 				if (piece_length == 0) size = data_length;
657 				break;
658 			case UDF_ICB_EXT_ALLOC    :
659 				printf("extended alloc (help)");
660 				size = sizeof(struct ext_ad);
661 				break;
662 			case UDF_ICB_INTERN_ALLOC :
663 				printf("internal blob here for %d bytes", data_length);
664 				size = data_length;
665 				break;
666 		}
667 		printf(" ] ");
668 		entry++;
669 		pos += size;
670 		data_length -=size;
671 	}
672 	printf("\n");
673 
674 }
675 
676 
677 /* TODO create a read-in/insert/cleanup etc. for extra attributes */
udf_dump_extattrseq(uint8_t * start,uint32_t offset,uint32_t impl_offset,uint32_t appl_offset,uint32_t length)678 void udf_dump_extattrseq(uint8_t *start, uint32_t offset, uint32_t impl_offset, uint32_t appl_offset, uint32_t length) {
679 	struct impl_extattr_entry	*impl_extattr;
680 	struct appl_extattr_entry	*appl_extattr;
681 	struct filetimes_extattr_entry	*filetimes_extattr;
682 	struct device_extattr_entry	*device_extattr;
683 	struct vatlvext_extattr_entry	*vatlvext_extattr;
684 	struct extattr_entry	*extattr;
685 	struct timestamp	*timestamp;
686 	struct charspec  chsp;
687 	uint32_t  extattr_len, au_l, iu_l, d_l;
688 	uint32_t  type, subtype, chksum, attr_space, print_attr_space;
689 	uint32_t  existence;
690 	uint8_t  *pos;
691 	char     *type_txt, what[256];
692 	int       is_free_ea_space, is_free_app_ea_space, is_vatlvext_space, bit;
693 
694 	/* if used its OSTA compressed unicode anyway */
695 	chsp.type = 0;
696 	strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
697 
698 	/* if one of the offsets is `-1' (0xffffffff), it indicates that its not present; God i hate magic values */
699 	if (impl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
700 		printf("\t\tNOTE: indicated no implementation related attributes are recorded in this extent\n");
701 	if (appl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
702 		printf("\t\tNOTE: indicated no application related attributes are recorded in this extent\n");
703 
704 	pos    = start;
705 	attr_space  = UDF_REGID_UDF;	/* really? */
706 	while (length > 0) {
707 		extattr = (struct extattr_entry *) pos;
708 		extattr_len = udf_rw32(extattr->a_l);
709 		type        = udf_rw32(extattr->type);
710 		subtype     = extattr->subtype;
711 
712 		if (pos    == start)       printf("\t\tStart of extended file related attributes area\n");
713 		if (offset == impl_offset) printf("\t\tStart of implementation related attributes area\n");
714 		if (offset == appl_offset) printf("\t\tStart of application related attributes area\n");
715 
716 		if (pos    == start)       attr_space = UDF_REGID_UDF;
717 		if (offset == impl_offset) attr_space = UDF_REGID_IMPLEMENTATION;
718 		if (offset == appl_offset) attr_space = UDF_REGID_APPLICATION;
719 
720 		if (subtype != 1) printf("\t\t\tWARNING: unknown subtype %d\n", subtype);
721 
722 		print_attr_space = attr_space;
723 		switch (type) {
724 			case 65536 :	/* [4/48.10.8] application use extended attributes */
725 				appl_extattr = (struct appl_extattr_entry *) pos;
726 				au_l = udf_rw32(appl_extattr->au_l);
727 				printf("\t\t\tApplication use extended attribute\n");
728 				if (attr_space != UDF_REGID_APPLICATION)
729 					printf("\t\t\t\t*** application use extended attribute found in non application use area ***\n");
730 				printf("\t\t\t\tLength of application use space     %d\n", au_l);
731 				udf_dump_regid("\t\t\t\tApplication use Id", &appl_extattr->appl_id, attr_space);
732 				break;
733 			case  2048 :	/* [4/48.10.9] implementation use extended attributes */
734 				impl_extattr = (struct impl_extattr_entry *) pos;
735 				iu_l = udf_rw32(impl_extattr->iu_l);
736 				chksum = udf_rw16(impl_extattr->data16);
737 
738 				printf("\t\t\tImplementation use extended attribute\n");
739 				if (chksum != udf_ea_cksum(pos))
740 					printf("\t\t\t\t*** header checksum failed (%d should be %d) ***\n", chksum, udf_ea_cksum(pos));
741 				if (attr_space != UDF_REGID_IMPLEMENTATION)
742 					printf("\t\t\t\t*** implementation use extended attribute found in non implementation use area ***\n");
743 
744 				if (strncmp((char *) impl_extattr->imp_id.id, "*UDF", 4) == 0)
745 					print_attr_space = UDF_REGID_UDF;
746 				printf("\t\t\t\tLength of implementation use space     %d\n", iu_l);
747 				udf_dump_regid("\t\t\t\tImplementation use Id", &impl_extattr->imp_id, print_attr_space);
748 				is_free_ea_space     = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeEASpace")    == 0);
749 				is_free_app_ea_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeAppEASpace") == 0);
750 				is_vatlvext_space    = (strcmp((char *) impl_extattr->imp_id.id, "*UDF VAT LVExtension") == 0);
751 				if (is_free_ea_space || is_free_app_ea_space) {
752 					printf("\t\t\t\tFree space for new extended attributes (%d bytes total)\n", extattr_len);
753 				} else if (is_vatlvext_space) {
754 					vatlvext_extattr = (struct vatlvext_extattr_entry *) (impl_extattr->data + iu_l);
755 					printf("\t\t\t\t\tUniqueID check            %"PRIu64"\n", udf_rw64(vatlvext_extattr->unique_id_chk));
756 					printf("\t\t\t\t\tNumber of files           %d\n", udf_rw32(vatlvext_extattr->num_files));
757 					printf("\t\t\t\t\tNumber of directories     %d\n", udf_rw32(vatlvext_extattr->num_directories));
758 					udf_dump_id("\t\t\t\t\tLogical volume id        ", 128, vatlvext_extattr->logvol_id,  &chsp);
759 				} else {
760 					printf("\t\t\t\t<Undumped %d bytes of implementation use data>\n", iu_l);
761 				}
762 				break;
763 			case 1 :	/* [4/48.10.3] : Character set information; UDF does allow/disallow explicitly */
764 				printf("\t\t\tCharacter set information attribute\n");
765 				printf("\t\t\t\t<Undumped %d bytes attribute>\n", extattr_len);
766 				break;
767 			case 3 :	/* [4/48.10.4] : Alternate permissions; UDF 3.3.4.2: not to be recorded */
768 				printf("\t\t\tAlternate permission attribute\n");
769 				printf("\t\t\t\t<Undumped %d bytes attribute>\n", extattr_len);
770 				break;
771 			case 5 :	/* [4/48.10.5] : File Times Extended Attribute */
772 			case 6 :	/* [4/48.10.6] : Information Times Extended Attribute; recorded in UDF ? */
773 				/* ASSUMPTION : bit fields are not exlusive */
774 				filetimes_extattr = (struct filetimes_extattr_entry *) pos;
775 				d_l = udf_rw32(filetimes_extattr->d_l);
776 				existence = udf_rw32(filetimes_extattr->existence);
777 				type_txt = "File";
778 				if (type == 6) type_txt = "File information";
779 
780 				printf("\t\t\t%s times extended attribute\n", type_txt);
781 				timestamp = &filetimes_extattr->times[0];
782 				for (bit = 0; bit < 32; bit++) {
783 					if (d_l == 0) break;
784 					if ((existence & (1 << bit)) == 0)
785 						continue;
786 					switch (bit) {
787 						case 0 : /* File Creation Date and Time: the date and time of the day at which the file was created. */
788 							sprintf(what, "\t\t\t\t%s created at            ", type_txt);
789 							break;
790 						case 1 : /* Information Last Modification Date and Time: the date and time of the day at which the information in the file was last modified. */
791 							sprintf(what, "\t\t\t\t%s last modified at      ", type_txt);
792 							break;
793 						case 2 : /* File Deletion Date and Time: the date and time of the day after which the file may be deleted. */
794 							sprintf(what, "\t\t\t\t%s may be deleted after  ", type_txt);
795 							break;
796 						case 3 : /* File Effective Date and Time: the date and time of the day after which the file may be used. */
797 							sprintf(what, "\t\t\t\t%s may only be used after ", type_txt);
798 							break;
799 						case 5 : /* File Last Backup Date and Time: the date and time of the day at which the file was last backed up. */
800 							sprintf(what, "\t\t\t\t%s last backuped at       ", type_txt);
801 							break;
802 						default : /* unspec */
803 							sprintf(what, "\t\t\t\tUndefined meaning for %s time stamp ", type_txt);
804 							break;
805 					}
806 					udf_dump_timestamp(what, timestamp);
807 					d_l -= sizeof(struct timestamp);
808 					timestamp++;	/* advance */
809 				}
810 				break;
811 			case 12 :	/* [4/48.10.7] : Device Specification Extended Attribute */
812 				device_extattr = (struct device_extattr_entry *) pos;
813 				iu_l = udf_rw32(device_extattr->iu_l);
814 				printf("\t\t\tDevice node extended attribute\n");
815 				printf("\t\t\t\tMajor    %d\n", udf_rw32(device_extattr->major));
816 				printf("\t\t\t\tMinor    %d\n", udf_rw32(device_extattr->minor));
817 				if (iu_l >= sizeof(struct regid)) {
818 					udf_dump_regid("\t\t\t\tImplementator", (struct regid *) (device_extattr->data), UDF_REGID_IMPLEMENTATION);
819 				}
820 				break;
821 			default :
822 				printf("\t\t\tUndumped extended attribute type       %d\n", type);
823 				printf("\t\t\t\tSubtype                        %d\n", subtype);
824 				printf("\t\t\t\tLength                         %d\n", extattr_len);
825 				break;
826 		}
827 		if (extattr_len == 0) {
828 			printf("\t\t\tABORTing dump\n");
829 			break;
830 		}
831 		pos    += extattr_len;
832 		offset += extattr_len;
833 		length -= extattr_len;
834 	}
835 	printf("\n");
836 }
837 
838 
udf_dump_extattr_hdr(struct extattrhdr_desc * eahd,uint32_t length)839 void udf_dump_extattr_hdr(struct extattrhdr_desc *eahd, uint32_t length) {
840 	uint32_t  hdr_len, impl_attr_loc, appl_attr_loc;
841 	uint8_t	 *pos;
842 
843 	hdr_len = (uint32_t) sizeof(struct extattrhdr_desc);
844 	impl_attr_loc = udf_rw32(eahd->impl_attr_loc);
845 	appl_attr_loc = udf_rw32(eahd->appl_attr_loc);
846 
847 	printf("\t\tExtended attributes header:\n");
848 	printf("\t\t\tLength                                    %d bytes\n", length);
849 	printf("\t\t\tImplementation attributes at offset       %d\n", impl_attr_loc);
850 	printf("\t\t\tApplication attributes at offset          %d\n", appl_attr_loc);
851 	printf("\t\t\tBytes remaining after header              %d\n", length - hdr_len);
852 
853 	/* determine length of file related attributes space */
854 	pos     = (uint8_t *) eahd;
855 	pos    += hdr_len;
856 	length -= hdr_len;
857 
858 	udf_dump_extattrseq(pos, hdr_len, impl_attr_loc, appl_attr_loc, length);
859 }
860 
861 
udf_dump_file_entry(struct file_entry * fe)862 void udf_dump_file_entry(struct file_entry *fe) {
863 	uint8_t		*pos;
864 	uint32_t	 length;
865 	uint8_t		 addr_type;
866 
867 	/* direct_entries = udf_rw32(fe->icbtag.prev_num_dirs); */
868 	//strat_param16  = udf_rw16(* (uint16_t *) (fe->icbtag.strat_param));
869 	//entries        = udf_rw16(fe->icbtag.max_num_entries);
870 	//strategy       = udf_rw16(fe->icbtag.strat_type);
871 	addr_type      = udf_rw16(fe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
872 
873 	printf("\tFile entry\n");
874 	udf_dump_icb_tag(&fe->icbtag);
875 	printf("\t\tUid                                         %d\n", udf_rw32(fe->uid));
876 	printf("\t\tGid                                         %d\n", udf_rw32(fe->gid));
877 	printf("\t\tPermissions                                 %x\n", udf_rw32(fe->perm));
878 	printf("\t\tLink count                                  %d\n", udf_rw16(fe->link_cnt));
879 	printf("\t\tRecord format                               %d\n", fe->rec_format);
880 	printf("\t\tRecord display attributes                   %d\n", fe->rec_disp_attr);
881 	printf("\t\tRecord length                               %d\n", fe->rec_len);
882 	printf("\t\tInformation length                          %"PRIu64"\n", (uint64_t) udf_rw64(fe->inf_len));
883 	printf("\t\tLogical blocks recorded                     %"PRIu64"\n", (uint64_t) udf_rw64(fe->logblks_rec));
884 	udf_dump_timestamp("\t\tAccess time                                ", &fe->atime);
885 	udf_dump_timestamp("\t\tModification time                          ", &fe->mtime);
886 	udf_dump_timestamp("\t\tAttribute time                             ", &fe->attrtime);
887 	printf("\t\tCheckpoint                                  %d\n", udf_rw32(fe->ckpoint));
888 	udf_dump_long_ad("\t\tExtended attributes ICB at", &fe->ex_attr_icb);
889 	udf_dump_regid("\t\tImplementation", &fe->imp_id, UDF_REGID_IMPLEMENTATION);
890 	printf("\t\tUniqueID                                    %d\n", (uint32_t) udf_rw64(fe->unique_id));
891 	printf("\t\tLength of extended attribute area           %d\n", udf_rw32(fe->l_ea));
892 	printf("\t\tLength of allocation descriptors            %d\n", udf_rw32(fe->l_ad));
893 
894 	if (udf_rw32(fe->l_ea)) {
895 		udf_dump_extattr_hdr((struct extattrhdr_desc *) &fe->data[0], udf_rw32(fe->l_ea));
896 	}
897 	if (udf_rw32(fe->ex_attr_icb.len)) {
898 		printf("\t\t<Undumped %d bytes of extended attributes descriptor\n", udf_rw32(fe->ex_attr_icb.len));
899 	}
900 
901 	printf("\t\tAllocation descriptors : \n");
902 
903 	pos            = &fe->data[0] + udf_rw32(fe->l_ea);
904 	length         = udf_rw32(fe->l_ad);
905 
906 	udf_dump_allocation_entries(addr_type, pos, length);
907 }
908 
909 
udf_dump_extfile_entry(struct extfile_entry * efe)910 void udf_dump_extfile_entry(struct extfile_entry *efe) {
911 	uint8_t		*pos;
912 	uint32_t	 length;
913 	uint8_t		 addr_type;
914 
915 	/* direct_entries = udf_rw32(efe->icbtag.prev_num_dirs); */
916 	//strat_param16  = udf_rw16(* (uint16_t *) (efe->icbtag.strat_param));
917 	//entries        = udf_rw16(efe->icbtag.max_num_entries);
918 	//strategy       = udf_rw16(efe->icbtag.strat_type);
919 	addr_type      = udf_rw16(efe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
920 
921 	printf("\tExtended file entry\n");
922 	udf_dump_icb_tag(&efe->icbtag);
923 	printf("\t\tUid                                         %d\n", udf_rw32(efe->uid));
924 	printf("\t\tGid                                         %d\n", udf_rw32(efe->gid));
925 	printf("\t\tPermissions                                 %x\n", udf_rw32(efe->perm));
926 	printf("\t\tLink count                                  %d\n", udf_rw16(efe->link_cnt));
927 	printf("\t\tRecord format                               %d\n", efe->rec_format);
928 	printf("\t\tRecord display attributes                   %d\n", efe->rec_disp_attr);
929 	printf("\t\tRecord length                               %d\n", efe->rec_len);
930 	printf("\t\tInformation length                          %"PRIu64"\n", (uint64_t) udf_rw64(efe->inf_len));
931 	printf("\t\tObject size                                 %"PRIu64"\n", (uint64_t) udf_rw64(efe->obj_size));
932 	printf("\t\tLogical blocks recorded                     %"PRIu64"\n", (uint64_t) udf_rw64(efe->logblks_rec));
933 	udf_dump_timestamp("\t\tAccess time                                ", &efe->atime);
934 	udf_dump_timestamp("\t\tModification time                          ", &efe->mtime);
935 	udf_dump_timestamp("\t\tCreation time                              ", &efe->ctime);
936 	udf_dump_timestamp("\t\tAttribute time                             ", &efe->attrtime);
937 	printf("\t\tCheckpoint                                  %d\n", udf_rw32(efe->ckpoint));
938 	udf_dump_long_ad("\t\tExtended attributes ICB at", &efe->ex_attr_icb);
939 	udf_dump_long_ad("\t\tStreamdir ICB at", &efe->streamdir_icb);
940 	udf_dump_regid("\t\tImplementation", &efe->imp_id, UDF_REGID_IMPLEMENTATION);
941 	printf("\t\tUniqueID                                    %d\n", (uint32_t) udf_rw64(efe->unique_id));
942 	printf("\t\tLength of extended attribute area           %d\n", udf_rw32(efe->l_ea));
943 	printf("\t\tLength of allocation descriptors            %d\n", udf_rw32(efe->l_ad));
944 
945 	if (udf_rw32(efe->l_ea)) {
946 		udf_dump_extattr_hdr((struct extattrhdr_desc *) &efe->data[0], udf_rw32(efe->l_ea));
947 	}
948 	if (udf_rw32(efe->ex_attr_icb.len)) {
949 		printf("\t\t<Undumped %d bytes of extended attributes descriptor\n", udf_rw32(efe->ex_attr_icb.len));
950 	}
951 
952 	printf("\t\tAllocation descriptors : \n");
953 
954 	pos            = &efe->data[0] + udf_rw32(efe->l_ea);
955 	length         = udf_rw32(efe->l_ad);
956 
957 	udf_dump_allocation_entries(addr_type, pos, length);
958 }
959 
960 
961 /* dump allocation extention descriptor */
udf_dump_alloc_extent(struct alloc_ext_entry * ext,int addr_type)962 void udf_dump_alloc_extent(struct alloc_ext_entry *ext, int addr_type) {
963 	uint8_t		*pos;
964 	uint32_t	 length;
965 	int		 isshort, islong;
966 
967 	/* note we DONT know if its filled with short_ad's or long_ad's! */
968 	printf("\tAllocation Extent descriptor\n");
969 	printf("\t\tPrevious entry                              %d\n", udf_rw32(ext->prev_entry));
970 	printf("\t\tLength of allocation descriptors            %d\n", udf_rw32(ext->l_ad));
971 
972 	pos    =  &ext->data[0];
973 	length =  udf_rw32(ext->l_ad);
974 
975 	if (addr_type < 0) {
976 		isshort = ((length % sizeof(struct short_ad)) == 0);
977 		islong  = ((length % sizeof(struct long_ad)) == 0);
978 		if (isshort)
979 			addr_type = UDF_ICB_SHORT_ALLOC;
980 		if (islong)
981 			addr_type = UDF_ICB_LONG_ALLOC;
982 		if (!(isshort ^ islong)) {
983 			printf("\t\tCan't determine if its filled with long_ad's or short_ad's !\n");
984 			return;
985 		}
986 	}
987 
988 	udf_dump_allocation_entries(addr_type, pos, length);
989 }
990 
991 
992 /* dump a space table(entry) descriptor */
udf_dump_space_entry(struct space_entry_desc * sed)993 void udf_dump_space_entry(struct space_entry_desc *sed) {
994 	union icb *icb;
995 	uint32_t addr_type, size, bytes;
996 	uint32_t piece_sector, piece_length, piece_part;
997 	uint8_t *pos;
998 
999 	printf("\tSpace entry table\n");
1000 	udf_dump_icb_tag(&sed->icbtag);
1001 	printf("\t\tSize in bytes                               %d\n", udf_rw32(sed->l_ad));
1002 
1003 	pos   = &sed->entry[0];
1004 	bytes = udf_rw32(sed->l_ad);
1005 
1006 	addr_type = udf_rw16(sed->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
1007 	while (bytes) {
1008 		size = piece_length = piece_sector = piece_part = 0;
1009 		icb = (union icb *) pos;
1010 		switch (addr_type) {
1011 			case UDF_ICB_SHORT_ALLOC :
1012 				piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<31)-1);
1013 				piece_sector = udf_rw32(icb->s_ad.lb_num);
1014 				printf("[at sec %u for %d bytes] ", piece_sector, piece_length);
1015 				size = sizeof(struct short_ad);
1016 				break;
1017 			case UDF_ICB_LONG_ALLOC :
1018 				piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<31)-1);
1019 				piece_sector = udf_rw32(icb->l_ad.loc.lb_num);
1020 				piece_part   = udf_rw16(icb->l_ad.loc.part_num);
1021 				size = sizeof(struct long_ad);
1022 				printf("[at sec %u for %d bytes at partition %d] ", piece_sector, piece_length, piece_part);
1023 				break;
1024 			case UDF_ICB_EXT_ALLOC :
1025 			case UDF_ICB_INTERN_ALLOC :
1026 				printf("\t\t\tWARNING : an internal alloc in a space entry?\n");
1027 				return;
1028 		}
1029 		bytes -= size;
1030 	}
1031 }
1032 
1033 
1034 /* dump a space bitmap descriptor */
udf_dump_space_bitmap(struct space_bitmap_desc * sbd)1035 void udf_dump_space_bitmap(struct space_bitmap_desc *sbd) {
1036 	uint32_t bits, from, now, cnt;
1037 	uint8_t byte, bit, bitpos, state, *pos;
1038 
1039 	printf("\t\tSpace bitmap\n");
1040 	printf("\t\t\tNumber of bits                      %u\n", udf_rw32(sbd->num_bits));
1041 	printf("\t\t\tNumber of bytes                     %u\n", udf_rw32(sbd->num_bytes));
1042 	printf("\t\t\tMarked parts at :\n");
1043 
1044 	pos = sbd->data;
1045 	bits = udf_rw32(sbd->num_bits);
1046 
1047 	/* shield */
1048 	/* if (bits > 2000*8) bits = 2000*8; */
1049 
1050 	printf("\t\t\t\t");
1051 	cnt = 0; from = 0; now = 0; bitpos = 0; byte = *pos; state = byte & 1;
1052 	while (now < bits) {
1053 		if (bitpos == 0) {
1054 			byte = *pos++;
1055 		}
1056 		bit = byte & 1;
1057 		if (bit != state) {
1058 			if (state) {
1059 				printf("[%08u - %08u]", from, now-1);
1060 				if (cnt % 4 == 3) printf("\n\t\t\t\t"); else printf("    ");
1061 				cnt++;
1062 			}
1063 			from = now;
1064 			state = bit;
1065 		}
1066 		byte >>= 1;
1067 		bitpos = (bitpos+1) & 7;
1068 		now++;
1069 	}
1070 	if (state) printf("[%08u - %08u]", from, now);
1071 	if (bits < udf_rw32(sbd->num_bits)) printf(" .... <trimmed>\n");
1072 }
1073 
1074 
1075 /* main descriptor `dump' function */
udf_dump_descriptor(union dscrptr * dscrpt)1076 void udf_dump_descriptor(union dscrptr *dscrpt) {
1077 	struct desc_tag *tag = &dscrpt->tag;
1078 	int error;
1079 
1080 	if (!dscrpt)
1081 		return;
1082 
1083 	/* check if its a valid descritor */
1084 	if (udf_rw16(tag->id == 0) && udf_rw16(tag->descriptor_ver) == 0) return;
1085 
1086 	udf_dump_desc(tag);
1087 
1088 	error = udf_check_tag(dscrpt);
1089 	if (error) {
1090 		printf("\tBAD TAG\n");
1091 		return;
1092 	}
1093 	switch (udf_rw16(tag->id)) {
1094 		case TAGID_SPARING_TABLE :
1095 			udf_dump_sparing_table(&dscrpt->spt);
1096 			break;
1097 		case TAGID_PRI_VOL :
1098 			udf_dump_pri_vol(&dscrpt->pvd);
1099 			break;
1100 		case TAGID_ANCHOR :
1101 			udf_dump_anchor(&dscrpt->avdp);
1102 			break;
1103 		case TAGID_VOL :
1104 			udf_dump_unimpl(dscrpt, "volume descriptor");
1105 			break;
1106 		case TAGID_IMP_VOL :
1107 			udf_dump_implementation_volume(&dscrpt->ivd);
1108 			break;
1109 		case TAGID_PARTITION :
1110 			udf_dump_part(&dscrpt->pd);
1111 			break;
1112 		case TAGID_LOGVOL :
1113 			udf_dump_log_vol(&dscrpt->lvd);
1114 			break;
1115 		case TAGID_UNALLOC_SPACE :
1116 			udf_dump_unalloc_space(&dscrpt->usd);
1117 			break;
1118 		case TAGID_TERM :
1119 			udf_dump_terminating_desc(dscrpt);
1120 			break;
1121 		case TAGID_LOGVOL_INTEGRITY :
1122 			udf_dump_logvol_integrity(&dscrpt->lvid);
1123 			break;
1124 		case TAGID_FSD :
1125 			udf_dump_fileset_desc(&dscrpt->fsd);
1126 			break;
1127 		case TAGID_FID :
1128 			udf_dump_fileid(&dscrpt->fid);
1129 			break;
1130 		case TAGID_ALLOCEXTENT :
1131 			udf_dump_alloc_extent(&dscrpt->aee, -1);
1132 			break;
1133 		case TAGID_INDIRECTENTRY :
1134 			udf_dump_indirect_entry(&dscrpt->inde);
1135 			break;
1136 		case TAGID_FENTRY :
1137 			udf_dump_file_entry(&dscrpt->fe);
1138 			break;
1139 		case TAGID_EXTATTR_HDR :
1140 			udf_dump_extattr_hdr(&dscrpt->eahd, sizeof(struct extattrhdr_desc));
1141 			break;
1142 		case TAGID_UNALL_SP_ENTRY :
1143 			udf_dump_space_entry(&dscrpt->sed);
1144 			break;
1145 		case TAGID_SPACE_BITMAP :
1146 			udf_dump_space_bitmap(&dscrpt->sbd);
1147 			break;
1148 		case TAGID_PART_INTEGRITY :
1149 			udf_dump_unimpl(dscrpt, "partition integrity");
1150 			break;
1151 		case TAGID_EXTFENTRY :
1152 			udf_dump_extfile_entry(&dscrpt->efe);
1153 			break;
1154 		default :
1155 			break;
1156 	}
1157 	printf("\n");
1158 }
1159 
1160 
1161 /* this one is special since the VAT table has no tag but is a file */
udf_dump_vat_table(struct udf_part_mapping * udf_part_mapping)1162 void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping) {
1163 	struct charspec  chsp;
1164 	struct udf_vat  *vat;
1165 	uint32_t	 previous_vat, entry, vat_entries, *vat_pos, version;
1166 
1167 	/* prolly OSTA compressed unicode anyway */
1168 	chsp.type = 0;
1169 	strcpy((char *) chsp.inf, "OSTA Compressed Unicode");
1170 
1171 	vat = udf_part_mapping->vat;
1172 	printf("\tVAT table: ");
1173 	printf("%s UDF 2.00 format\n", vat?"post":"pre");
1174 
1175 	vat_entries = udf_part_mapping->vat_entries;
1176 	vat_pos = (uint32_t *) udf_part_mapping->vat_translation;
1177 	if (vat) {
1178 		printf("\t\tHeader length                        %d\n", udf_rw16(vat->header_len));
1179 		printf("\t\tImplementation use length            %d\n", udf_rw16(vat->impl_use_len));
1180 		udf_dump_id("\t\tLogical volume id                   ", 128, vat->logvol_id,  &chsp);
1181 		printf("\t\tNumber of files                      %d\n", udf_rw32(vat->num_files));
1182 		printf("\t\tNumber of directories                %d\n", udf_rw32(vat->num_directories));
1183 		version = udf_rw16(vat->min_udf_readver);
1184 		printf("\t\tMinimum readversion                  UDFv %x\n", version);
1185 		version = udf_rw16(vat->min_udf_writever);
1186 		printf("\t\tMinimum writeversion                 UDFv %x\n", version);
1187 		version = udf_rw16(vat->max_udf_writever);
1188 		printf("\t\tMaximum writeversion                 UDFv %x\n", version);
1189 		if (udf_rw16(vat->impl_use_len)) printf("\t\t<undumped implementation use area>");
1190 		previous_vat = udf_rw32(vat->prev_vat);
1191 	} else {
1192 		udf_dump_regid("\t\tIdentifier id (can be wrong)        ", (struct regid *) (vat_pos+vat_entries), UDF_REGID_NAME);
1193 		previous_vat = udf_rw32(*(vat_pos + vat_entries + 32/4));			/* definition */
1194 	}
1195 	if (previous_vat == 0xffffffff) {
1196 		printf("\t\tNo previous VAT recorded\n");
1197 	} else {
1198 		printf("\t\tPrevious VAT recorded at offset      %d\n", previous_vat);
1199 	}
1200 
1201 	printf("\t\tNumber of VAT entries                %d\n", vat_entries);
1202 	printf("\t\tVAT dump :");
1203 	for (entry=0; entry < vat_entries; entry++) {
1204 		if ((entry % 4) == 0) printf("\n\t");
1205 		printf("[0x%08x -> 0x%08x] ", entry, *vat_pos++);
1206 	}
1207 	printf("\n");
1208 }
1209 
1210 
udf_dump_volumeset_info(struct udf_volumeset * udf_volumeset)1211 void udf_dump_volumeset_info(struct udf_volumeset *udf_volumeset) {
1212 	struct udf_pri_vol	*primary;
1213 	struct udf_log_vol	*logical;
1214 	struct udf_partition	*udf_partition;
1215 	struct udf_part_mapping *udf_part_mapping;
1216 	struct udf_discinfo	*disc;
1217 	char			*name;
1218 	int			 num_volumes, num_partitions;
1219 	int			 subvolume, part_num, track_num;
1220 
1221 	num_volumes = 0;	/* shut up gcc */
1222 	if (udf_volumeset->obsolete) return;
1223 
1224 	primary = STAILQ_FIRST(&udf_volumeset->primaries);
1225 	if (primary) {
1226 		num_volumes =  udf_rw16(primary->pri_vol->max_vol_seq);
1227 		if (udf_volumeset->obsolete) printf("OBSOLETE\n");	/* XXX */
1228 
1229 		printf("Volume set ");
1230 		udf_dump_id(NULL, 32, primary->pri_vol->volset_id, &primary->pri_vol->desc_charset);
1231 		printf(" (%d volume%s) ", num_volumes, num_volumes>1?"s":"");
1232 
1233 		num_partitions = udf_volumeset->max_partnum;
1234 		printf("with %d partition%s\n", num_partitions, (num_partitions!=1)?"s":"");
1235 
1236 		/* better loop trough the partition numbers to display them in a defined order */
1237 		SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) {
1238 			part_num = udf_rw16(udf_partition->partition->part_num);
1239 			if (udf_partition) {
1240 				/* there is information */
1241 				assert(udf_partition->udf_session);
1242 				assert(udf_partition->udf_session->disc);
1243 				assert(udf_partition->partition);
1244 				assert(part_num == udf_rw16(udf_partition->partition->part_num));
1245 				track_num = udf_partition->udf_session->session_num;
1246 				disc      = udf_partition->udf_session->disc;
1247 
1248 				printf("\tPartition number %d at device `%s' session %d from sector %d(+%d) for %u sectors\n",
1249 						part_num,
1250 						disc->dev->dev_name,
1251 						track_num,
1252 						udf_rw32(udf_partition->partition->start_loc),
1253 						udf_partition->udf_session->session_offset,
1254 						udf_rw32(udf_partition->partition->part_len)
1255 				      );
1256 			} else {
1257 				printf("\tUnknown partition %d [unknown]\n", part_num);
1258 			}
1259 		}
1260 	}
1261 
1262 	STAILQ_FOREACH(primary, &udf_volumeset->primaries, next_primary) {
1263 		subvolume = udf_rw16(primary->pri_vol->vds_num);
1264 
1265 		printf("\tPrimary volume ");
1266 		udf_dump_id(NULL, 32, primary->pri_vol->vol_id, &primary->pri_vol->desc_charset);
1267 		printf(" (part %d/%d) ", subvolume, num_volumes);
1268 
1269 		printf("created by implementator `%s' ", primary->pri_vol->imp_id.id);
1270 		if (*primary->pri_vol->app_id.id)
1271 			printf("by/for application `%s' ",primary->pri_vol->app_id.id);
1272 		printf("\n");
1273 
1274 		SLIST_FOREACH(logical, &primary->log_vols, next_logvol) {
1275 			name = logical->log_vol->logvol_id;
1276 			udf_dump_id("\t\tcontains logical volume ", 128, name, &logical->log_vol->desc_charset);
1277 			if (logical->broken) {
1278 				printf("\t\t\tBROKEN\n");
1279 				continue;
1280 			}
1281 
1282 			SLIST_FOREACH(udf_part_mapping, &logical->part_mappings, next_mapping) {
1283 				printf("\t\t\tmapping %d on %d as ", udf_part_mapping->udf_virt_part_num,
1284 						udf_part_mapping->udf_phys_part_num);
1285 				switch (udf_part_mapping->udf_part_mapping_type) {
1286 					case UDF_PART_MAPPING_ERROR :
1287 						printf("bad partition");
1288 						break;
1289 					case UDF_PART_MAPPING_PHYSICAL :
1290 						printf("direct");
1291 						break;
1292 					case UDF_PART_MAPPING_VIRTUAL :
1293 						printf("virtual partition");
1294 						break;
1295 					case UDF_PART_MAPPING_SPARABLE :
1296 						printf("sparable");
1297 						break;
1298 					case UDF_PART_MAPPING_META :
1299 						printf("metadata only");
1300 				}
1301 				printf(" recording");
1302 				if (udf_part_mapping->data_writable) printf(" data");
1303 				if (udf_part_mapping->metadata_writable) printf(" metadata");
1304 				if (!udf_part_mapping->data_writable && !udf_part_mapping->metadata_writable) printf(" nothing");
1305 				printf("\n");
1306 			}
1307 		}
1308 		printf("\n");
1309 	}
1310 }
1311 
1312 
udf_dump_alive_sets(void)1313 void udf_dump_alive_sets(void) {
1314 	struct udf_volumeset *udf_volumeset;
1315 
1316 	printf("UDF volume sets marked alive :\n");
1317 	SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) {
1318 		udf_dump_volumeset_info(udf_volumeset);
1319 	}
1320 	printf("\n");
1321 }
1322 
1323 
1324 /*
1325  * extern defined read_logvol_descriptor breaks splitting rules but how
1326  * otherwise to provide a detailed description of the file entry udf_node
1327  */
1328 
1329 #define DUMP_DIRBUFFER_SIZE (16*1024)
udf_dump_file_entry_node(struct udf_node * udf_node,char * prefix)1330 void udf_dump_file_entry_node(struct udf_node *udf_node, char *prefix) {
1331 	struct long_ad   udf_icbptr;
1332 	struct uio       dir_uio;
1333 	struct iovec     dir_iovec;
1334 	struct dirent   *dirent;
1335 	struct fileid_desc *fid;
1336 	struct udf_node *entry_node;
1337 	uint32_t         pos, lb_size;
1338 	uint8_t         *buffer;
1339 	char             fullpath[1024];	/* XXX arbitrary length XXX */
1340 	int              isdot, isdotdot, isdir, found, eof;
1341 	int		 error;
1342 
1343 	if (!udf_node)
1344 		return;
1345 
1346 	/* XXX could pass on dirent XXX */
1347 	isdir  = (udf_node->udf_filetype == UDF_ICB_FILETYPE_DIRECTORY);
1348 	isdir |= (udf_node->udf_filetype == UDF_ICB_FILETYPE_STREAMDIR);
1349 	if (isdir) {
1350 		buffer = malloc(DUMP_DIRBUFFER_SIZE);
1351 		if (!buffer)
1352 			return;
1353 		lb_size = udf_node->udf_log_vol->lb_size;
1354 		fid = malloc(lb_size);
1355 		assert(fid);	/* or just return? */
1356 
1357 		/* recurse into this directory */
1358 		dir_uio.uio_offset = 0;			/* begin at start */
1359 		do {
1360 			dir_iovec.iov_base = buffer;
1361 			dir_iovec.iov_len  = DUMP_DIRBUFFER_SIZE;
1362 			dir_uio.uio_resid  = DUMP_DIRBUFFER_SIZE;
1363 			dir_uio.uio_iovcnt = 1;
1364 			dir_uio.uio_iov    = &dir_iovec;
1365 			dir_uio.uio_rw     = UIO_WRITE;
1366 
1367 			error = udf_readdir(udf_node, &dir_uio, &eof);
1368 			if (error) {
1369 				printf("While reading in dirbuffer for dumping file entry udf_node : %s\n", strerror(error));
1370 				break;
1371 			}
1372 			pos = 0;
1373 			while (pos < DUMP_DIRBUFFER_SIZE - dir_uio.uio_resid) {
1374 				dirent = (struct dirent *) (buffer + pos);
1375 
1376 				sprintf(fullpath, "%s/%s", prefix, dirent->d_name);
1377 
1378 				/* looking for '.' or '..' ? */
1379 				isdot    = (strncmp(dirent->d_name, ".",  DIRENT_NAMLEN(dirent)) == 0);
1380 				isdotdot = (strncmp(dirent->d_name, "..", DIRENT_NAMLEN(dirent)) == 0);
1381 
1382 				pos += sizeof(struct dirent);	/* XXX variable size dirents possible XXX */
1383 
1384 				if (isdotdot)
1385 					continue;
1386 
1387 				if (isdot)
1388 					continue;
1389 
1390 				error = udf_lookup_name_in_dir(udf_node, dirent->d_name, DIRENT_NAMLEN(dirent), &udf_icbptr, fid, &found);
1391 				if (!error) {
1392 					error = ENOENT;
1393 					if (found)
1394 						error = udf_readin_udf_node(udf_node, &udf_icbptr, fid, &entry_node);
1395 				}
1396 				if (!error)
1397 					udf_dump_file_entry_node(entry_node, fullpath);
1398 			}
1399 		} while (!eof);
1400 
1401 		free(fid);
1402 		free(buffer);
1403 		return;
1404 	}
1405 	/* leaf udf_node */
1406 	printf("%s\n", prefix);
1407 }
1408 #undef DUMP_DIRBUFFER_SIZE
1409 
1410 
udf_dump_root_dir(struct udf_mountpoint * mountpoint)1411 void udf_dump_root_dir(struct udf_mountpoint *mountpoint) {
1412 	printf("\n\nRoot dir dump\n");
1413 	if (mountpoint->rootdir_node)   udf_dump_file_entry_node(mountpoint->rootdir_node, ":Rootdir");
1414 
1415 	printf("\n\nStreamdir dump\n");
1416 	if (mountpoint->streamdir_node) udf_dump_file_entry_node(mountpoint->streamdir_node, ":Streamdir");
1417 }
1418 
1419 
1420 /* XXX These should move to form one cd verbose file with cd_discect XXX */
print_disc_state(int state)1421 static char *print_disc_state(int state) {
1422 	switch (state) {
1423 		case 0: return "empty disc";
1424 		case 1: return "incomplete (appendable)";
1425 		case 2: return "full (not appendable)";
1426 		case 3: return "random writable";
1427 	}
1428 	return "unknown disc state";
1429 }
1430 
1431 
print_session_state(int state)1432 static char *print_session_state(int state) {
1433 	switch (state) {
1434 		case 0 : return "empty";
1435 		case 1 : return "incomplete";
1436 		case 2 : return "reserved/damaged";
1437 		case 3 : return "complete/closed disc";
1438 	}
1439 	return "unknown session_state";
1440 }
1441 
1442 
print_mmc_profile(int profile)1443 static char *print_mmc_profile(int profile) {
1444 	static char scrap[100];
1445 
1446 	switch (profile) {
1447 		case 0x00 : return "Unknown[0] profile";
1448 		case 0x01 : return "Non removable disc";
1449 		case 0x02 : return "Removable disc";
1450 		case 0x03 : return "Magneto Optical with sector erase";
1451 		case 0x04 : return "Magneto Optical write once";
1452 		case 0x05 : return "Advance Storage Magneto Optical";
1453 		case 0x08 : return "CD-ROM";
1454 		case 0x09 : return "CD-R recordable";
1455 		case 0x0a : return "CD-RW rewritable";
1456 		case 0x10 : return "DVD-ROM";
1457 		case 0x11 : return "DVD-R sequential";
1458 		case 0x12 : return "DVD-RAM rewritable";
1459 		case 0x13 : return "DVD-RW restricted overwrite";
1460 		case 0x14 : return "DVD-RW sequential";
1461 		case 0x1a : return "DVD+RW rewritable";
1462 		case 0x1b : return "DVD+R recordable";
1463 		case 0x20 : return "DDCD readonly";
1464 		case 0x21 : return "DDCD-R recodable";
1465 		case 0x22 : return "DDCD-RW rewritable";
1466 		case 0x2b : return "DVD+R double layer";
1467 		case 0x40 : return "BD-ROM";
1468 		case 0x41 : return "BD-R Sequential Recording (SRM)";
1469 		case 0x42 : return "BD-R Random Recording (RRM)";
1470 		case 0x43 : return "BD-RE rewritable";
1471 	}
1472 	sprintf(scrap, "Reserved profile 0x%02x", profile);
1473 	return scrap;
1474 }
1475 
1476 
udf_dump_discinfo(struct udf_discinfo * disc)1477 void udf_dump_discinfo(struct udf_discinfo *disc) {
1478 	int session;
1479 
1480 	printf("Disc info for disc in device %s\n", disc->dev->dev_name);
1481 	printf("\tMMC profile        : %s\n", print_mmc_profile(disc->mmc_profile));
1482 	printf("\tsequential         : %s\n", disc->sequential       ?"yes":" no");
1483 	printf("\trecordable         : %s\n", disc->recordable       ?"yes":" no");
1484 	printf("\terasable           : %s\n", disc->erasable         ?"yes":" no");
1485 	printf("\tblankable          : %s\n", disc->blankable        ?"yes":" no");
1486 	printf("\tformattable        : %s\n", disc->formattable      ?"yes":" no");
1487 	printf("\trewritable         : %s\n", disc->rewritable       ?"yes":" no");
1488 	printf("\tmount raineer      : %s\n", disc->mrw              ?"yes":" no");
1489 	printf("\tpacket writing     : %s\n", disc->packet           ?"yes":" no");
1490 	printf("\tstrict overwrite   : %s\n", disc->strict_overwrite ?"yes":" no");
1491 	printf("\tblocking number    : %d\n", disc->blockingnr);
1492 	printf("\tdisc state         : %s\n", print_disc_state(disc->disc_state));
1493 	printf("\tlast session state : %s\n", print_session_state(disc->last_session_state));
1494 	printf("\tsectorsize         : %d\n", disc->sector_size);
1495 	printf("\tNumber of sessions     %d\n", disc->num_sessions);
1496 	for (session = 0; session < disc->num_sessions; session++) {
1497 		printf("\tSession %d\n", session);
1498 		printf("\t\tstart  at         %u\n", (uint32_t) disc->session_start[session]);
1499 		printf("\t\tends   at         %u\n", (uint32_t) disc->session_end[session]);
1500 		printf("\t\tlength for        %u\n", (uint32_t) (disc->session_end[session] - disc->session_start[session]));
1501 		printf("\t\tnext writable at  %u\n", disc->next_writable[session]);
1502 		printf("\t\tfree blocks       %u\n", disc->free_blocks[session]);
1503 		printf("\t\tpacket size       %u\n", disc->packet_size[session]);
1504 		printf("\n");
1505 	}
1506 }
1507 
1508 /* end of udf_verbose.c */
1509 
1510