1 /* $NetBSD$ */
2 
3 /*
4  * File "udf.c" is part of the UDFclient toolkit.
5  * File $Id: udf.c,v 1.305 2020/04/18 09:14:49 reinoud Exp $ $Name:  $
6  *
7  * Copyright (c) 2003, 2004, 2005, 2006, 2011, 2020
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 
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <assert.h>
41 #include <dirent.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <limits.h>
45 #include <time.h>
46 
47 #include "uscsilib.h"
48 
49 
50 /* for locals */
51 #include "udf.h"
52 #include "udf_bswap.h"
53 #include "udf_discop.h"
54 #include "udf_unix.h"
55 #include "uio.h"
56 #include "dirhash.h"
57 #include <pthread.h>
58 
59 
60 /* for scsilib */
61 const char *dvname="UDF device";
62 
63 
64 #ifndef MAX
65 #	define MAX(a,b) ((a)>(b)?(a):(b))
66 #	define MIN(a,b) ((a)<(b)?(a):(b))
67 #endif
68 
69 
70 /* #define DEBUG(a) { a; } */
71 #define DEBUG(a) if (0) { a; }
72 
73 
74 /* global settings */
75 int     udf_verbose = UDF_VERBLEV_ACTIONS;
76 
77 /* static structures shared over all programs */
78 struct discslist       udf_discs_list;
79 struct volumeset_list  udf_volumeset_list;
80 struct mountables_list udf_mountables;
81 
82 #define UDF_INODE_NUM_GUESS  2048
83 
84 
85 /* predefines */
86 int  udf_validate_tag_and_crc_sums(union dscrptr *dscr);
87 void udf_node_mark_dirty(struct udf_node *udf_node);
88 
89 static void udf_set_imp_id(struct regid *regid);
90 static void udf_set_app_id(struct regid *regid);
91 static void udf_node_unmark_dirty(struct udf_node *udf_node);
92 static void udf_init_desc_tag(struct desc_tag *tag, uint16_t id, uint16_t dscr_ver, uint16_t serial_num);
93 static int  udf_translate_icb_filetype_to_dirent_filetype(int udf_filetype);
94 static int  udf_remove_directory_prim(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname);
95 static int  udf_remove_directory_entry(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname);
96 
97 
98 /* external dumpers */
99 extern void udf_dump_descriptor(union dscrptr *dscrpt);
100 extern void udf_dump_file_entry(struct file_entry *fe);
101 extern void udf_dump_extfile_entry(struct extfile_entry *efe);
102 extern void udf_dump_alloc_extent(struct alloc_ext_entry *ext, int addr_type);
103 extern void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping);
104 extern void udf_dump_disc_anchors(struct udf_discinfo *disc);
105 extern void udf_dump_alive_sets(void);
106 extern void udf_dump_root_dir(struct udf_mountpoint *mountpoint);
107 extern void udf_dump_timestamp(char *dscr, struct timestamp *t);
108 
109 
110 /******************************************************************************************
111  *
112  * Filename space conversion
113  *
114  ******************************************************************************************/
115 
udf_to_unix_name(char * result,char * id,int len,struct charspec * chsp)116 void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp) {
117 	uint16_t  raw_name[1024], unix_name[1024];
118 	uint16_t *inchp, ch;
119 	uint8_t	 *outchp;
120 	int       ucode_chars, nice_uchars;
121 
122 	assert(sizeof(char) == sizeof(uint8_t));
123 	outchp = (uint8_t *) result;
124 	if ((chsp->type == 0) && (strcmp((char*) chsp->inf, "OSTA Compressed Unicode") == 0)) {
125 		*raw_name = *unix_name = 0;
126 		ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name);
127 		ucode_chars = UnicodeLength((unicode_t *) raw_name, ucode_chars);
128 		nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars);
129 		for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) {
130 			ch = *inchp;
131 			/* sloppy unicode -> latin */
132 			*outchp++ = ch & 255;
133 			if (!ch) break;
134 		}
135 		*outchp++ = 0;
136 	} else {
137 		/* assume 8bit char length byte latin-1 */
138 		assert(*id == 8);
139 		strncpy(result, id+1, len);
140 	}
141 }
142 
143 
unix_to_udf_name(char * result,char * name,uint8_t * result_len,struct charspec * chsp)144 void unix_to_udf_name(char *result, char *name, uint8_t *result_len, struct charspec *chsp) {
145 	uint16_t  raw_name[1024];
146 	int       udf_chars, name_len;
147 	char     *inchp;
148 	uint16_t *outchp;
149 
150 	/* convert latin-1 or whatever to unicode-16 */
151 	*raw_name = 0;
152 	name_len  = 0;
153 	inchp  = name;
154 	outchp = raw_name;
155 	while (*inchp) {
156 		*outchp++ = (uint16_t) (*inchp++);
157 		name_len++;
158 	}
159 
160 	if ((chsp->type == 0) && (strcmp((char *) chsp->inf, "OSTA Compressed Unicode") == 0)) {
161 		udf_chars = udf_CompressUnicode(name_len, 8, (unicode_t *) raw_name, (byte *) result);
162 	} else {
163 		/* assume 8bit char length byte latin-1 */
164 		*result++ = 8; udf_chars = 1;
165 		strcpy(result, name + 1);
166 		udf_chars += strlen(name);
167 	}
168 	*result_len = udf_chars;
169 }
170 
171 
udf_get_compound_name(struct udf_mountpoint * mountpoint)172 static char *udf_get_compound_name(struct udf_mountpoint *mountpoint) {
173 	static char         compound[128+128+32+32+1];
174 	struct charspec    *charspec;
175 	struct udf_log_vol *udf_log_vol;
176 	struct udf_pri_vol *udf_pri_vol;
177 	char               *unix_name;
178 
179 	udf_log_vol = mountpoint->udf_log_vol;
180 	udf_pri_vol = udf_log_vol->primary;
181 
182 	charspec = &udf_pri_vol->pri_vol->desc_charset;
183 	assert(charspec->type == 0);
184 	assert(strcmp((const char *) charspec->inf, "OSTA Compressed Unicode")==0);
185 
186 	unix_name = compound;
187 
188 	udf_to_unix_name(unix_name, udf_pri_vol->pri_vol->volset_id, 128, charspec);
189 	strcat(unix_name, ":");
190 	unix_name += strlen(unix_name);
191 
192 	udf_to_unix_name(unix_name, udf_pri_vol->pri_vol->vol_id, 32, charspec);
193 	strcat(unix_name, ":");
194 	unix_name += strlen(unix_name);
195 
196 	udf_to_unix_name(unix_name, udf_log_vol->log_vol->logvol_id, 128, charspec);
197 	strcat(unix_name, ":");
198 	unix_name += strlen(unix_name);
199 
200 	udf_to_unix_name(unix_name, mountpoint->fileset_desc->fileset_id, 32, charspec);
201 
202 	return compound;
203 }
204 
205 
206 /******************************************************************************************
207  *
208  * Dump helpers for printing out information during parse
209  *
210  ******************************************************************************************/
211 
udf_dump_long_ad(char * prefix,struct long_ad * adr)212 void udf_dump_long_ad(char *prefix, struct long_ad *adr) {
213 	printf("%s at sector %d within partion space %d for %d bytes\n", prefix,
214 			udf_rw32(adr->loc.lb_num), udf_rw16(adr->loc.part_num),
215 			udf_rw32(adr->len)
216 			);
217 }
218 
219 
udf_dump_id(char * prefix,int len,char * id,struct charspec * chsp)220 void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp) {
221 	uint16_t  raw_name[1024];
222 	uint16_t *pos, ch;
223 	int       ucode_chars;
224 
225 	if (prefix) printf("%s ", prefix);
226 	if ((chsp->type == 0) && (strcmp((char *) chsp->inf, "OSTA Compressed Unicode") == 0)) {
227 		/* print the identifier using the OSTA compressed unicode */
228 		printf("`");
229 		ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name);
230 		for (pos = raw_name; ucode_chars > 0; pos++, ucode_chars--) {
231 			ch = *pos;		/* OSTA code decompresses to machine endian */
232 			if (!ch) break;
233 			if ((ch < 32) || (ch > 255)) {
234 				printf("[%d]", ch);
235 			} else {
236 				printf("%c", ch & 255);
237 			}
238 		}
239 		printf("`");
240 	} else {
241 		printf("(roughly) `%s`", id+1);
242 	}
243 	if (prefix) printf("\n");
244 }
245 
246 
udf_dump_volume_name(char * prefix,struct udf_log_vol * udf_log_vol)247 void udf_dump_volume_name(char *prefix, struct udf_log_vol *udf_log_vol) {
248 	if (prefix) printf("%s%s", prefix, udf_log_vol->primary->udf_session->session_offset?" (local) ":" ");
249 	udf_dump_id(NULL, 128, udf_log_vol->primary->pri_vol->volset_id, &udf_log_vol->primary->pri_vol->desc_charset);
250 	printf(":");
251 	udf_dump_id(NULL,  32, udf_log_vol->primary->pri_vol->vol_id, &udf_log_vol->primary->pri_vol->desc_charset);
252 	printf(":");
253 	udf_dump_id(NULL, 128, udf_log_vol->log_vol->logvol_id, &udf_log_vol->log_vol->desc_charset);
254 	if (prefix) printf("\n");
255 }
256 
257 
258 /******************************************************************************************
259  *
260  * UDF tag checkers and size calculator
261  *
262  ******************************************************************************************/
263 
264 
265 /* not used extensively enough yet */
udf_check_tag(union dscrptr * dscr)266 int udf_check_tag(union dscrptr *dscr) {
267 	struct desc_tag *tag = &dscr->tag;
268 	uint8_t *pos, sum, cnt;
269 
270 	/* check TAG header checksum */
271 	pos = (uint8_t *) tag;
272 	sum = 0;
273 
274 	for(cnt = 0; cnt < 16; cnt++) {
275 		if (cnt != 4) sum += *pos;
276 		pos++;
277 	}
278 	if (sum != tag->cksum) {
279 		/* bad tag header checksum; this is not a valid tag */
280 		DEBUG(printf("Bad checksum\n"));
281 		return EINVAL;
282 	}
283 	return 0;
284 }
285 
286 
udf_check_tag_payload(union dscrptr * dscr)287 int udf_check_tag_payload(union dscrptr *dscr) {
288 	struct desc_tag *tag = &dscr->tag;
289 	uint16_t crc;
290 
291 	/* check payload CRC if applicable */
292 	if (udf_rw16(tag->desc_crc_len) == 0) return 0;
293 
294 	crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, udf_rw16(tag->desc_crc_len));
295 	if (crc != udf_rw16(tag->desc_crc)) {
296 		DEBUG(printf("ERROR: CRC bad read 0x%0x calc 0x%0x\n", udf_rw16(tag->desc_crc), crc));
297 		/* bad payload CRC; this is a broken tag */
298 		return EINVAL;
299 	}
300 
301 	return 0;
302 }
303 
304 
udf_validate_tag_sum(union dscrptr * dscr)305 int udf_validate_tag_sum(union dscrptr *dscr) {
306 	struct desc_tag *tag = &dscr->tag;
307 	uint8_t *pos, sum, cnt;
308 
309 	/* calculate TAG header checksum */
310 	pos = (uint8_t *) tag;
311 	sum = 0;
312 
313 	for(cnt = 0; cnt < 16; cnt++) {
314 		if (cnt != 4) sum += *pos;
315 		pos++;
316 	}
317 	tag->cksum = sum;	/* 8 bit */
318 
319 	return 0;
320 }
321 
322 
323 /* assumes sector number of descriptor to be allready present */
udf_validate_tag_and_crc_sums(union dscrptr * dscr)324 int udf_validate_tag_and_crc_sums(union dscrptr *dscr) {
325 	struct desc_tag *tag = &dscr->tag;
326 	uint16_t crc;
327 
328 	/* check payload CRC if applicable */
329 	if (udf_rw16(tag->desc_crc_len) > 0) {
330 		crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, udf_rw16(tag->desc_crc_len));
331 		tag->desc_crc = udf_rw16(crc);
332 	}
333 
334 	/* calculate TAG header checksum */
335 	return udf_validate_tag_sum(dscr);
336 }
337 
338 
udf_check_tag_presence(union dscrptr * dscr,int TAG)339 int udf_check_tag_presence(union dscrptr *dscr, int TAG) {
340 	struct desc_tag *tag = &dscr->tag;
341 	int error;
342 
343 	error = udf_check_tag(dscr);
344 	if (error) return error;
345 
346 	if (udf_rw16(tag->id) != TAG) {
347 		DEBUG(fprintf(stderr, "looking for tag %d but found %d\n", TAG, udf_rw16(tag->id)));
348 		return ENOENT;
349 	}
350 
351 	return 0;
352 }
353 
354 
355 
356 /*
357  * for malloc() purposes ... rather have an upperlimit than an exact size
358  */
udf_calc_tag_malloc_size(union dscrptr * dscr,uint32_t udf_sector_size)359 uint64_t udf_calc_tag_malloc_size(union dscrptr *dscr, uint32_t udf_sector_size) {
360 	uint32_t size, tag_id;
361 
362 	tag_id = udf_rw16(dscr->tag.id);
363 
364 	switch (tag_id) {
365 		case TAGID_LOGVOL :
366 			size  = sizeof(struct logvol_desc) - 1;					/* maps[1]		*/
367 			size += udf_rw32(dscr->lvd.mt_l);
368 			break;
369 		case TAGID_UNALLOC_SPACE :
370 			size  = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad);	/* alloc_desc[1]	*/
371 			size += udf_rw32(dscr->usd.alloc_desc_num) * sizeof(struct extent_ad);
372 			break;
373 		case TAGID_FID :
374 			size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu);
375 			size = (size + 3) & ~3;
376 			return size;		/* RETURN !! */
377 		case TAGID_LOGVOL_INTEGRITY :
378 			size  = sizeof(struct logvol_int_desc) - sizeof(uint32_t);		/* tables[1]		*/
379 			size += udf_rw32(dscr->lvid.l_iu);
380 			size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t));
381 			break;
382 		case TAGID_SPACE_BITMAP :
383 			size  = sizeof(struct space_bitmap_desc) - 1;				/* data[1]		*/
384 			size += udf_rw32(dscr->sbd.num_bytes);
385 			break;
386 		case TAGID_SPARING_TABLE :
387 			size  = sizeof(struct udf_sparing_table) - sizeof(struct spare_map_entry);	/* entries[1]	*/
388 			size += udf_rw16(dscr->spt.rt_l) * sizeof(struct spare_map_entry);
389 			break;
390 		case TAGID_FENTRY :
391 			size  = sizeof(struct file_entry);
392 			size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1;		/* data[0] 		*/
393 			break;
394 		case TAGID_EXTFENTRY :
395 			size  = sizeof(struct extfile_entry);
396 			size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1;		/* data[0]		*/
397 			break;
398 		case TAGID_FSD :
399 			size  = sizeof(struct fileset_desc);
400 			break;
401 		default :
402 			size = sizeof(union dscrptr);
403 			break;
404 	}
405 
406 	if ((size == 0) || (udf_sector_size == 0)) return 0;
407 	return ((size + udf_sector_size -1) / udf_sector_size) * udf_sector_size;
408 }
409 
410 
411 /* explicit only for FID's */
412 static int
udf_fidsize(struct fileid_desc * fid)413 udf_fidsize(struct fileid_desc *fid)
414 {
415 	int size;
416 
417 	size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
418 	size = (size + 3) & ~3;
419 
420 	return size;
421 }
422 
423 
424 /******************************************************************************************
425  *
426  * Logical to physical adres transformation
427  *
428  ******************************************************************************************/
429 
430 
431 /* convert (udf_log_vol, vpart_num) to a udf_partion structure */
udf_logvol_vpart_to_partition(struct udf_log_vol * udf_log_vol,uint32_t vpart_num,struct udf_part_mapping ** udf_part_mapping_ptr,struct udf_partition ** udf_partition_ptr)432 int udf_logvol_vpart_to_partition(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, struct udf_part_mapping **udf_part_mapping_ptr, struct udf_partition **udf_partition_ptr) {
433 	struct udf_volumeset	 *udf_volumeset;
434 	struct udf_partition	 *udf_partition;
435 	struct udf_part_mapping  *udf_part_mapping;
436 	uint32_t		  part_num;
437 	int found;
438 
439 	assert(udf_log_vol);
440 	assert(!SLIST_EMPTY(&udf_log_vol->part_mappings));
441 
442 	/* clear result */
443 	if (udf_part_mapping_ptr) *udf_part_mapping_ptr = NULL;
444 	if (udf_partition_ptr)    *udf_partition_ptr    = NULL;
445 
446 	/* map the requested partition map to the physical udf partition */
447 	found = 0;
448 	SLIST_FOREACH(udf_part_mapping, &udf_log_vol->part_mappings, next_mapping) {
449 		if (udf_part_mapping->udf_virt_part_num == vpart_num) {
450 			found = 1;
451 			break;
452 		}
453 	}
454 	if (!found) {
455 		printf("\t\t\tVirtual partition number %d not found!\n", vpart_num);
456 		return EINVAL;
457 	}
458 
459 	assert(udf_part_mapping);	/* call me paranoid */
460 	part_num = udf_part_mapping->udf_phys_part_num;
461 
462 	/* search for the physical partition information */
463 	udf_volumeset = udf_log_vol->primary->volumeset;
464 	SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) {
465 		if (udf_rw16(udf_partition->partition->part_num) == part_num) break;
466 	}
467 
468 	if (!udf_partition) {
469 		printf("\t\t\tNo information known about partition %d yet!\n", part_num);
470 		printf("\t\t\t\tPlease insert volume %d of this volumeset and try again\n", udf_part_mapping->vol_seq_num);
471 		return ENOENT;
472 	}
473 
474 	if (udf_part_mapping_ptr) *udf_part_mapping_ptr = udf_part_mapping;
475 	if (udf_partition_ptr)    *udf_partition_ptr    = udf_partition;
476 	return 0;
477 }
478 
479 
480 /* no recursive translations yet (UDF OK) */
481 /* All translation is done in 64 bits to prevent bitrot and returns the PARTITION relative address */
udf_vpartoff_to_sessionoff(struct udf_log_vol * udf_log_vol,struct udf_part_mapping * udf_part_mapping,struct udf_partition * udf_partition,uint64_t offset,uint64_t * ses_off,uint64_t * trans_valid_len)482 int udf_vpartoff_to_sessionoff(struct udf_log_vol *udf_log_vol, struct udf_part_mapping *udf_part_mapping, struct udf_partition *udf_partition, uint64_t offset, uint64_t *ses_off, uint64_t *trans_valid_len) {
483 	struct spare_map_entry	 *sp_entry;
484 	struct udf_node		 *udf_node;
485 	struct udf_allocentry	 *alloc_entry;
486 
487 	uint64_t	part_start, part_length;
488 	uint64_t	eff_sector, eff_offset;
489 	uint64_t	trans_sector;
490 	uint64_t	cur_offset;
491 	uint32_t	len, lb_num, block_offset;
492 	uint32_t	entry, entries;
493 	uint32_t	sector_size, lb_size;
494 
495 	uint64_t	packet_num, packet_rlb;
496 	uint64_t	packet_len;
497 
498 	uint32_t	vat_entries, *vat_pos;
499 	int		flags;
500 
501 	assert(udf_part_mapping);
502 	assert(udf_partition);
503 	assert(ses_off);
504 	assert(trans_valid_len);
505 
506 	/* not ok, but rather this than a dangling random value */
507 	*ses_off         = UINT_MAX;
508 	*trans_valid_len = 0;
509 
510 	lb_size     = udf_log_vol->lb_size;
511 	sector_size = udf_log_vol->sector_size;
512 	part_start  = (uint64_t) udf_rw32(udf_partition->partition->start_loc) * sector_size;
513 	part_length = (uint64_t) udf_rw32(udf_partition->partition->part_len)  * sector_size;
514 
515 	/* get the offset (in bytes) in the partition and check its validity */
516 	if (offset >= part_length) {
517 		printf("\t\toffset %"PRIu64" is outside partition %d!\n", offset, udf_rw16(udf_partition->partition->part_num));
518 		return EFAULT;
519 	}
520 
521 	/* do the address translations based on the partition mapping type */
522 	/* translation of virt/sparable etc. is assumed to be done in logical block sizes */
523 	switch (udf_part_mapping->udf_part_mapping_type) {
524 		case UDF_PART_MAPPING_PHYSICAL :
525 			/* nothing to be done; physical is logical */
526 			*ses_off	 = part_start  + offset;				/* 1:1 */
527 			*trans_valid_len = part_length - offset;				/* rest of partition */
528 			return 0;
529 
530 		case UDF_PART_MAPPING_VIRTUAL :
531 			vat_entries = udf_part_mapping->vat_entries;
532 			vat_pos = (uint32_t *) udf_part_mapping->vat_translation;
533 
534 			/* this translation is dependent on logical sector numbers */
535 			eff_sector = offset / lb_size;
536 			eff_offset = offset % lb_size;
537 
538 			/* TODO check range for logical sector against VAT length */
539 			assert(eff_sector < vat_entries);
540 			trans_sector     = vat_pos[eff_sector];
541 			*ses_off         = part_start + (trans_sector * lb_size) + eff_offset;	/* trans sectors are in lb->lb ? */
542 			*trans_valid_len = lb_size - eff_offset;				/* maximum one logical sector */
543 			return 0;
544 
545 		case UDF_PART_MAPPING_SPARABLE :
546 			/* this translation is dependent on logical sector numbers */
547 			*ses_off   = part_start + offset;					/* 1:1 */
548 			eff_sector = offset / lb_size;
549 			eff_offset = offset % lb_size;
550 
551 			/* transform on packet-length base */
552 			packet_len = udf_rw16(udf_part_mapping->udf_pmap->pms.packet_len);	/* in lb */
553 			entries    = udf_rw16(udf_part_mapping->sparing_table->rt_l);
554 
555 			packet_num = (eff_sector / packet_len) * packet_len;
556 			packet_rlb =  eff_sector % packet_len;					/* within packet */
557 
558 			/* translate this packet; source is in partition, destination is absolute disc address */
559 			sp_entry = &udf_part_mapping->sparing_table->entries[0];
560 			for (entry = 0; entry < entries; entry++) {
561 				if (udf_rw32(sp_entry->org) - packet_num == 0) {
562 					/* mappings contain absolute disc addresses, so no partition offsets please */
563 					*ses_off = (uint64_t) (udf_rw32(sp_entry->map) + packet_rlb) * lb_size + eff_offset;
564 					break;
565 				}
566 				sp_entry++;
567 			}
568 			*trans_valid_len = (packet_len - packet_rlb) * lb_size;			/* maximum one packet */
569 			return 0;
570 
571 		case UDF_PART_MAPPING_META :
572 			/* We follow the allocation entries to calculate our offset */
573 			udf_node = udf_part_mapping->meta_file;
574 			assert(udf_node->addr_type != UDF_ICB_INTERN_ALLOC);
575 
576 			/* find sector in the allocation space */
577 			UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
578 			cur_offset = 0;
579 			TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) {
580 				len       = alloc_entry->len;
581 				lb_num    = alloc_entry->lb_num;
582 				/* vpart_num = alloc_entry->vpart_num; */
583 				flags     = alloc_entry->flags;
584 
585 				/* check overlap with this alloc entry */
586 				if (cur_offset + len > offset) {
587 					assert(((offset - cur_offset) % lb_size) == 0);	/* ought to be on sector boundary */
588 					if (flags != UDF_EXT_ALLOCATED)
589 						break;
590 					block_offset = offset - cur_offset;
591 					*ses_off     = part_start + lb_num * lb_size + block_offset;	/* 1:1 within the block */
592 					*trans_valid_len = len - block_offset;				/* rest of this chunk   */
593 					UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
594 					return 0;
595 				}
596 				cur_offset += len;
597 			} /* FOREACH */
598 			UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
599 
600 			printf("\t\toffset %"PRIu64" is not translated within current metadata partition %d file descriptor!\n", offset, udf_rw16(udf_partition->partition->part_num));
601 			return EFAULT;
602 		case UDF_PART_MAPPING_ERROR :
603 		default :
604 			break;
605 	}
606 	printf("Unsupported or bad mapping %d; can't translate\n", udf_part_mapping->udf_part_mapping_type);
607 
608 	return EFAULT;
609 }
610 
611 
612 
613 /******************************************************************************************
614  *
615  * udf_node creator, destructor and syncer
616  *
617  ******************************************************************************************/
618 
619 
udf_perm_to_unix_mode(uint32_t perm)620 static mode_t udf_perm_to_unix_mode(uint32_t perm) {
621 	mode_t mode;
622 
623 	mode  = ((perm & UDF_FENTRY_PERM_USER_MASK)      );
624 	mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK  ) >> 2);
625 	mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
626 
627 	return mode;
628 }
629 
630 
unix_mode_to_udf_perm(mode_t mode)631 static uint32_t unix_mode_to_udf_perm(mode_t mode) {
632 	uint32_t perm;
633 
634 	perm  = ((mode & S_IRWXO)     );
635 	perm |= ((mode & S_IRWXG) << 2);
636 	perm |= ((mode & S_IRWXU) << 4);
637 	perm |= ((mode & S_IWOTH) << 3);
638 	perm |= ((mode & S_IWGRP) << 5);
639 	perm |= ((mode & S_IWUSR) << 7);
640 
641 	return perm;
642 }
643 
644 
645 /*
646  * Fill in timestamp structure based on clock_gettime(). Time is reported back as a time_t
647  * accompanied with a nano second field.
648  *
649  * The husec, usec and csec could be relaxed in type.
650  */
udf_timespec_to_timestamp(struct timespec * timespec,struct timestamp * timestamp)651 static void udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp) {
652 	struct tm tm;
653 	uint64_t husec, usec, csec;
654 
655 	bzero(timestamp, sizeof(struct timestamp));
656 	gmtime_r(&timespec->tv_sec, &tm);
657 
658 	/*
659 	 * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1.
660 	 *
661 	 * Lower 12 bits are two complement signed timezone offset if bit 12
662 	 * (method 1) is clear. Otherwise if bit 12 is set, specify timezone
663 	 * offset to -2047 i.e. unsigned `zero'
664 	 */
665 
666 	timestamp->type_tz	= udf_rw16((1<<12) + 0);	/* has to be method 1 for CUT/GMT */
667 	timestamp->year		= udf_rw16(tm.tm_year + 1900);
668 	timestamp->month	= tm.tm_mon + 1;		/* `tm' structure uses 0..11 for months */
669 	timestamp->day		= tm.tm_mday;
670 	timestamp->hour		= tm.tm_hour;
671 	timestamp->minute	= tm.tm_min;
672 	timestamp->second	= tm.tm_sec;
673 
674 	usec   = (timespec->tv_nsec + 500) / 1000;	/* round (if possible)        */
675 	husec  =   usec / 100;
676 	usec  -=  husec * 100;				/* we only want 0-99 in usec  */
677 	csec   =  husec / 100;				/* we       get 0-99 in csec  */
678 	husec -=   csec * 100;				/* we only want 0-99 in husec */
679 
680 	timestamp->centisec	= csec;
681 	timestamp->hund_usec	= husec;
682 	timestamp->usec		= usec;
683 }
684 
685 
udf_set_timestamp_now(struct timestamp * timestamp)686 void udf_set_timestamp_now(struct timestamp *timestamp) {
687 	struct timespec now;
688 
689 	clock_gettime(CLOCK_REALTIME, &now);
690 	udf_timespec_to_timestamp(&now, timestamp);
691 }
692 
693 
694 /* implemented as a seperate function to allow tuning */
udf_set_timespec_now(struct timespec * timespec)695 void udf_set_timespec_now(struct timespec *timespec) {
696 	clock_gettime(CLOCK_REALTIME, timespec);
697 }
698 
699 
udf_insanetimespec(struct timespec * check)700 int udf_insanetimespec(struct timespec *check) {
701 	struct timespec now;
702 	struct tm tm;
703 
704 	gmtime_r(&check->tv_sec, &tm);
705 
706 	/* since our converters can only deal with timestamps after 1970 we
707 	 * reject earlier */
708 	if (tm.tm_year < 1970) return 1;
709 
710 	/* don't accept values from the future; FFS or NFS might not mind, but
711 	 * UDF does! */
712 	clock_gettime(CLOCK_REALTIME, &now);
713 	if (now.tv_sec < check->tv_sec)
714 		return 1;
715 	if ((now.tv_sec == check->tv_sec) && (now.tv_nsec < check->tv_nsec))
716 		return 1;
717 
718 	return 0;
719 }
720 
721 
722 /*
723  * Timestamp to timespec conversion code is taken with small modifications
724  * from FreeBSD /sys/fs/udf by Scott Long <scottl@freebsd.org>
725  */
726 
727 static int mon_lens[2][12] = {
728 	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
729 	{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
730 };
731 
732 
733 static int
udf_isaleapyear(int year)734 udf_isaleapyear(int year)
735 {
736 	int i;
737 
738 	i = (year % 4) ? 0 : 1;
739 	i &= (year % 100) ? 1 : 0;
740 	i |= (year % 400) ? 0 : 1;
741 
742 	return i;
743 }
744 
745 
udf_timestamp_to_timespec(struct timestamp * timestamp,struct timespec * timespec)746 static void udf_timestamp_to_timespec(struct timestamp *timestamp, struct timespec *timespec) {
747 	uint32_t usecs, secs, nsecs;
748 	uint16_t tz;
749 	int i, lpyear, daysinyear, year;
750 
751 	timespec->tv_sec  = secs  = 0;
752 	timespec->tv_nsec = nsecs = 0;
753 
754        /*
755 	* DirectCD seems to like using bogus year values.
756 	* Distrust time->month especially, since it will be used for an array
757 	* index.
758 	*/
759 	year = udf_rw16(timestamp->year);
760 	if ((year < 1970) || (timestamp->month > 12)) {
761 		return;
762 	}
763 
764 	/* Calculate the time and day */
765 	usecs = timestamp->usec + 100*timestamp->hund_usec + 10000*timestamp->centisec;
766 	nsecs = usecs * 1000;
767 	secs  = timestamp->second;
768 	secs += timestamp->minute * 60;
769 	secs += timestamp->hour * 3600;
770 	secs += (timestamp->day-1) * 3600 * 24;			/* day : 1-31 */
771 
772 	/* Calclulate the month */
773 	lpyear = udf_isaleapyear(year);
774 	for (i = 1; i < timestamp->month; i++)
775 		secs += mon_lens[lpyear][i-1] * 3600 * 24;	/* month: 1-12 */
776 
777 	for (i = 1970; i < year; i++) {
778 		daysinyear = udf_isaleapyear(i) + 365 ;
779 		secs += daysinyear * 3600 * 24;
780 	}
781 
782 	/*
783 	 * Calculate the time zone.  The timezone is 12 bit signed 2's
784 	 * compliment, so we gotta do some extra magic to handle it right.
785 	 */
786 	tz  = udf_rw16(timestamp->type_tz);
787 	tz &= 0x0fff;				/* only lower 12 bits are significant */
788 	if (tz & 0x0800)			/* sign extention */
789 		tz |= 0xf000;
790 
791 	/* TODO check timezone conversion */
792 #if 1
793 	/* check if we are specified a timezone to convert */
794 	if (udf_rw16(timestamp->type_tz) & 0x1000)
795 		if ((int16_t) tz != -2047)
796 			secs -= (int16_t) tz * 60;
797 #endif
798 	timespec->tv_sec  = secs;
799 	timespec->tv_nsec = nsecs;
800 }
801 
802 
udf_node_get_fileinfo(struct udf_node * udf_node,union dscrptr * dscrptr)803 static void udf_node_get_fileinfo(struct udf_node *udf_node, union dscrptr *dscrptr) {
804 	struct stat          *stat;
805 	struct file_entry    *file_entry;
806 	struct extfile_entry *extfile_entry;
807 	struct timestamp     *atime, *mtime, *ctime, *attrtime;
808 	uint64_t inf_len, unique_id;
809 	uint32_t uid, gid, udf_perm;
810 	uint16_t fe_tag;
811 	uint16_t udf_icbtag_flags, serial_num, link_cnt;
812 	uint8_t  filetype;
813 
814 	assert(udf_node);
815 	assert(dscrptr);
816 	stat   = &udf_node->stat;
817 
818 	/* check if its an normal file entry or a extended file entry ICB */
819 	fe_tag = udf_rw16(dscrptr->tag.id);
820 	if (fe_tag == TAGID_FENTRY) {
821 		file_entry = &dscrptr->fe;
822 #if 0
823 		prev_direct_entries = udf_rw32(file_entry->icbtag.prev_num_dirs);
824 		strat_param16  = udf_rw16(* (uint16_t *) (file_entry->icbtag.strat_param));
825 		entries        = udf_rw16(file_entry->icbtag.max_num_entries);
826 		strategy       = udf_rw16(file_entry->icbtag.strat_type);
827 		data_length    = udf_rw32(file_entry->l_ad);
828 		addr_type      = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
829 		pos            = &file_entry->data[0] + udf_rw32(file_entry->l_ea);
830 #endif
831 		filetype         = file_entry->icbtag.file_type;
832 		inf_len          = udf_rw64(file_entry->inf_len);
833 		uid              = udf_rw32(file_entry->uid);
834 		gid              = udf_rw32(file_entry->gid);
835 		udf_perm         = udf_rw32(file_entry->perm);
836 		serial_num       = udf_rw16(file_entry->tag.serial_num);
837 		udf_icbtag_flags = udf_rw16(file_entry->icbtag.flags);
838 		link_cnt         = udf_rw16(file_entry->link_cnt);
839 		unique_id        = udf_rw64(file_entry->unique_id);
840 		atime            = &file_entry->atime;
841 		mtime            = &file_entry->mtime;
842 		ctime		 = &file_entry->mtime;		/* XXX assumption */
843 		attrtime         = &file_entry->attrtime;
844 	} else if (fe_tag == TAGID_EXTFENTRY) {
845 		extfile_entry = &dscrptr->efe;
846 #if 0
847 		prev_direct_entries = udf_rw32(extfile_entry->icbtag.prev_num_dirs);
848 		strat_param16  = udf_rw16(* (uint16_t *) (extfile_entry->icbtag.strat_param));
849 		entries        = udf_rw16(extfile_entry->icbtag.max_num_entries);
850 		strategy       = udf_rw16(extfile_entry->icbtag.strat_type);
851 		data_length    = udf_rw32(extfile_entry->l_ad);
852 		addr_type      = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
853 		pos            = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea);
854 #endif
855 		filetype         = extfile_entry->icbtag.file_type;
856 		inf_len          = udf_rw64(extfile_entry->inf_len);
857 		uid              = udf_rw32(extfile_entry->uid);
858 		gid              = udf_rw32(extfile_entry->gid);
859 		udf_perm         = udf_rw32(extfile_entry->perm);
860 		serial_num       = udf_rw16(extfile_entry->tag.serial_num);
861 		udf_icbtag_flags = udf_rw16(extfile_entry->icbtag.flags);
862 		link_cnt         = udf_rw16(extfile_entry->link_cnt);	/* how many FID's are linked to this (ext)fentry	*/
863 		unique_id        = udf_rw64(extfile_entry->unique_id);	/* unique file ID					*/
864 		atime            = &extfile_entry->atime;
865 		mtime            = &extfile_entry->mtime;
866 		ctime		 = &extfile_entry->ctime;
867 		attrtime         = &extfile_entry->attrtime;
868 	} else {
869 		printf("udf_node_set_file_info : help! i can't be here!!! i got a %d tag\n", fe_tag);
870 		udf_dump_descriptor(dscrptr);
871 		return;
872 	}
873 
874 	/* fill in (parts of) the stat structure */
875 	/* XXX important info missing still like access mode, times etc. XXX */
876 	udf_node->udf_filetype     = filetype;
877 	udf_node->serial_num       = serial_num;
878 	udf_node->udf_icbtag_flags = udf_icbtag_flags;
879 	udf_node->link_cnt         = link_cnt;		/* how many FID's are linked to this (ext)fentry	*/
880 	udf_node->unique_id        = unique_id;		/* unique file ID					*/
881 
882 	/* fill in stat basics */
883 	bzero(stat, sizeof(struct stat));
884 	stat->st_ino     = unique_id;				/* lowest 32 bit(!) only */
885 	stat->st_mode    = udf_perm_to_unix_mode(udf_perm);	/* CONVERT from udf_perm */
886 	stat->st_mode   |= (udf_translate_icb_filetype_to_dirent_filetype(filetype) & DT_DIR) ? S_IFDIR : S_IFREG;
887 	stat->st_uid     = uid;
888 	stat->st_gid     = gid;
889 
890 	/* ... times */
891 	udf_timestamp_to_timespec(atime,    &stat->st_atimespec);
892 	udf_timestamp_to_timespec(mtime,    &stat->st_mtimespec);
893 	udf_timestamp_to_timespec(attrtime, &stat->st_ctimespec);
894 #ifndef NO_STAT_BIRTHTIME
895 	udf_timestamp_to_timespec(ctime,    &stat->st_birthtimespec);
896 #endif
897 
898 	/* ... sizes */
899 	stat->st_size    = inf_len;
900 	stat->st_blksize = udf_node->udf_log_vol->lb_size;
901 
902 	/* special: updatables */
903 	stat->st_nlink   = link_cnt;
904 	stat->st_blocks  = (stat->st_size + 512 -1)/512;	/* blocks are hardcoded 512 bytes/sector in stat :-/ */
905 	return;
906 }
907 
908 
udf_node_set_fileinfo(struct udf_node * udf_node,union dscrptr * dscrptr)909 static void udf_node_set_fileinfo(struct udf_node *udf_node, union dscrptr *dscrptr) {
910 	struct stat          *stat;
911 	struct file_entry    *file_entry;
912 	struct extfile_entry *extfile_entry;
913 	struct timestamp     *atime, *mtime, *ctime, *attrtime;
914 	uint64_t inf_len, unique_id;
915 	uint32_t uid, gid, udf_perm;
916 	uint16_t fe_tag, serial_num, link_cnt;
917 	uint8_t  filetype;
918 
919 	assert(udf_node);
920 	assert(dscrptr);
921 	stat   = &udf_node->stat;
922 
923 	/* set (parts of) the stat structure */
924 	/* XXX important info missing still like times etc. XXX */
925 	uid      = stat->st_uid;
926 	gid      = stat->st_gid;
927 	inf_len  = stat->st_size;
928 	udf_perm = unix_mode_to_udf_perm(stat->st_mode);	/* conversion to UDF perm. */
929 
930 	filetype   = udf_node->udf_filetype;
931 	unique_id  = udf_node->unique_id;
932 	serial_num = udf_node->serial_num;
933 	link_cnt   = udf_node->link_cnt;
934 
935 	/* check if its to be written in an normal file entry or a extended file entry ICB */
936 	fe_tag = udf_rw16(dscrptr->tag.id);
937 	if (fe_tag == TAGID_FENTRY) {
938 		file_entry = &dscrptr->fe;
939 #if 0
940 		prev_direct_entries = udf_rw32(file_entry->icbtag.prev_num_dirs);
941 		strat_param16  = udf_rw16(* (uint16_t *) (file_entry->icbtag.strat_param));
942 		entries        = udf_rw16(file_entry->icbtag.max_num_entries);
943 		strategy       = udf_rw16(file_entry->icbtag.strat_type);
944 		data_length    = udf_rw32(file_entry->l_ad);
945 		addr_type      = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
946 		pos            = &file_entry->data[0] + udf_rw32(file_entry->l_ea);
947 #endif
948 		file_entry->icbtag.file_type = filetype;
949 		file_entry->inf_len         = udf_rw64(inf_len);
950 		file_entry->uid             = udf_rw32(uid);
951 		file_entry->gid             = udf_rw32(gid);
952 		file_entry->perm            = udf_rw32(udf_perm);
953 		file_entry->tag.serial_num  = udf_rw16(serial_num);
954 		file_entry->link_cnt        = udf_rw16(link_cnt);
955 		file_entry->unique_id       = udf_rw64(unique_id);
956 		atime                       = &file_entry->atime;
957 		mtime                       = &file_entry->mtime;
958 		ctime                       = mtime;			/* XXX assumption */
959 		attrtime                    = &file_entry->attrtime;
960 	} else if (fe_tag == TAGID_EXTFENTRY) {
961 		extfile_entry = &dscrptr->efe;
962 #if 0
963 		prev_direct_entries = udf_rw32(extfile_entry->icbtag.prev_num_dirs);
964 		strat_param16  = udf_rw16(* (uint16_t *) (extfile_entry->icbtag.strat_param));
965 		entries        = udf_rw16(extfile_entry->icbtag.max_num_entries);
966 		strategy       = udf_rw16(extfile_entry->icbtag.strat_type);
967 		data_length    = udf_rw32(extfile_entry->l_ad);
968 		addr_type      = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
969 		pos            = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea);
970 #endif
971 		extfile_entry->icbtag.file_type = filetype;
972 		extfile_entry->inf_len        = udf_rw64(inf_len);
973 		extfile_entry->uid            = udf_rw32(uid);
974 		extfile_entry->gid            = udf_rw32(gid);
975 		extfile_entry->perm           = udf_rw32(udf_perm);
976 		extfile_entry->tag.serial_num = udf_rw16(serial_num);
977 		extfile_entry->link_cnt       = udf_rw16(link_cnt);	/* how many FID's are linked to this (ext)fentry	*/
978 		extfile_entry->unique_id      = udf_rw64(unique_id);	/* unique file ID					*/
979 		atime          = &extfile_entry->atime;
980 		mtime          = &extfile_entry->mtime;
981 		ctime          = &extfile_entry->ctime;
982 		attrtime       = &extfile_entry->attrtime;
983 	} else {
984 		printf("udf_node_set_file_info : help! i can't be here!!! i got a %d tag\n", fe_tag);
985 		udf_dump_descriptor(dscrptr);
986 		return;
987 	}
988 	/* FILL in {atime, mtime, attrtime} TIMES! */
989 	udf_timespec_to_timestamp(&stat->st_atimespec,     atime);
990 	udf_timespec_to_timestamp(&stat->st_mtimespec,     mtime);
991 	udf_timespec_to_timestamp(&stat->st_ctimespec,     attrtime);
992 #ifndef NO_STAT_BIRTHTIME
993 	udf_timespec_to_timestamp(&stat->st_birthtimespec, ctime);
994 #else
995 	memcpy(ctime, mtime, sizeof(*ctime));
996 #endif
997 
998 	return;
999 }
1000 
1001 
1002 /* with 32 bits ino_t, a maximum of about 8 TB discs are supported (1<<32) * 2KB*/
udf_calc_hash(struct long_ad * icbptr)1003 ino_t udf_calc_hash(struct long_ad *icbptr) {
1004 	/* TODO unique file-id would be better */
1005 	return (ino_t) udf_rw32(icbptr->loc.lb_num);
1006 }
1007 
1008 
udf_insert_node_in_hash(struct udf_node * udf_node)1009 void udf_insert_node_in_hash(struct udf_node *udf_node) {
1010 	struct udf_log_vol *log_vol;
1011 	uint32_t     bucket;
1012 	ino_t        hashkey;
1013 	struct long_ad icb;
1014 
1015 	icb.loc.lb_num = udf_rw32(TAILQ_FIRST(&udf_node->dscr_allocs)->lb_num);
1016 
1017 	log_vol           = udf_node->udf_log_vol;
1018 	hashkey           = udf_calc_hash(&icb);
1019 	udf_node->hashkey = hashkey;
1020 	bucket            = hashkey & UDF_INODE_HASHMASK;
1021 	LIST_INSERT_HEAD(&log_vol->udf_nodes[bucket], udf_node, next_node);
1022 }
1023 
1024 
1025 /* dispose udf_node's administration */
udf_dispose_udf_node(struct udf_node * udf_node)1026 void udf_dispose_udf_node(struct udf_node *udf_node) {
1027 	struct udf_allocentry *alloc_entry;
1028 	struct udf_buf	 *buf_entry;
1029 	struct udf_node	 *lookup;
1030 	uint32_t bucket;
1031 	ino_t    hashkey;
1032 
1033 	if (!udf_node) return;
1034 
1035 /* XXX locks? XXX */
1036 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
1037 
1038 	if (udf_node->dirty) {
1039 		DEBUG(printf("Warning: disposing dirty node\n"));
1040 		udf_node_unmark_dirty(udf_node);
1041 	}
1042 
1043 	/* free all associated buffers */
1044 	UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
1045 	UDF_MUTEX_LOCK(&udf_node->buf_mutex);
1046 		/* due to this `trick' we don't need to use a marker */
1047 		while ((buf_entry = TAILQ_FIRST(&udf_node->vn_bufs))) {
1048 			udf_mark_buf_clean(udf_node, buf_entry);	/* its destroyed so not dirty */
1049 			udf_mark_buf_allocated(udf_node, buf_entry);	/* i.e. taken care of */
1050 			udf_detach_buf_from_node(udf_node, buf_entry);
1051 			udf_free_buf_entry(buf_entry);
1052 		}
1053 		/* free in-node filedata blob if present */
1054 		if (udf_node->intern_data)
1055 			free(udf_node->intern_data);
1056 	UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
1057 	UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
1058 
1059 	/* free our extended attribute administration if present */
1060 	if (udf_node->extattrfile_icb)
1061 		free(udf_node->extattrfile_icb);
1062 	if (udf_node->streamdir_icb)
1063 		free(udf_node->streamdir_icb);
1064 	if (udf_node->extended_attr)
1065 		free(udf_node->extended_attr);
1066 
1067 	/* free dscr_allocs queue */
1068 	while ((alloc_entry = TAILQ_FIRST(&udf_node->dscr_allocs))) {
1069 		TAILQ_REMOVE(&udf_node->dscr_allocs, alloc_entry, next_alloc);
1070 		free(alloc_entry);
1071 	}
1072 
1073 	/* free allocation queue */
1074 	while ((alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries))) {
1075 		TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc);
1076 		free(alloc_entry);
1077 	}
1078 
1079 	/* if its part of a logical volume, delete it in its hash table */
1080 	if (udf_node->udf_log_vol) {
1081 		hashkey = udf_node->hashkey;
1082 		bucket  = hashkey & UDF_INODE_HASHMASK;
1083 		LIST_FOREACH(lookup, &udf_node->udf_log_vol->udf_nodes[bucket], next_node) {
1084 			/* hashkey doesn't matter; just remove same udf_node pointer */
1085 			if (lookup == udf_node) {
1086 				assert(lookup->hashkey == hashkey);
1087 				DEBUG(printf("removal of udf_node from the hash table\n"));
1088 				LIST_REMOVE(lookup, next_node);
1089 				break;
1090 			}
1091 		}
1092 	}
1093 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1094 
1095 	/* free the node */
1096 	free(udf_node);
1097 }
1098 
1099 
udf_increment_unique_id(struct udf_log_vol * udf_log_vol)1100 uint64_t udf_increment_unique_id(struct udf_log_vol *udf_log_vol) {
1101 	uint64_t unique_id, next_unique_id;
1102 
1103 	/* lock? */
1104 	unique_id = udf_log_vol->next_unique_id;
1105 
1106 	/* increment according to UDF 3/3.2.1.1 */
1107 	next_unique_id = unique_id + 1;
1108 	if (((next_unique_id << 32) >> 32) < 16) next_unique_id |= 16;
1109 
1110 	udf_log_vol->next_unique_id = next_unique_id;
1111 	DEBUG(printf("next unique_id <-- %"PRIu64"\n", udf_log_vol->next_unique_id));
1112 
1113 	return unique_id;
1114 }
1115 
1116 
udf_init_udf_node(struct udf_mountpoint * mountpoint,struct udf_log_vol * udf_log_vol,char * what,struct udf_node ** udf_nodeptr)1117 int udf_init_udf_node(struct udf_mountpoint *mountpoint, struct udf_log_vol *udf_log_vol, char *what, struct udf_node **udf_nodeptr) {
1118 	struct udf_node	*udf_node;
1119 	uint32_t lb_size, data_space_avail;
1120 	int descr_ver;
1121 
1122 	what = what;	/* not used yet */
1123 
1124 	assert(udf_log_vol);
1125 	lb_size = udf_log_vol->lb_size;
1126 
1127 	/* get ourselves some space */
1128 	udf_node = calloc(1, sizeof(struct udf_node));
1129 	if (!udf_node) return ENOMEM;
1130 
1131 	/* setup basic udf_node */
1132 	udf_node->addr_type = UDF_ICB_LONG_ALLOC;
1133 	udf_node->icb_len   = sizeof(struct long_ad);
1134 
1135 	udf_node->serial_num       = 1;
1136 	udf_node->udf_icbtag_flags = UDF_ICB_INTERN_ALLOC;
1137 	udf_node->link_cnt         = 1;						/* how many FID's are linked to this node */
1138 	udf_node->unique_id        = 0;						/* unique file ID unknown		  */
1139 
1140 	/* get internal space available for internal nodes */
1141 	/* TODO keep in mind the extended attributes! XXX */
1142 	descr_ver = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver);
1143 	if (descr_ver == 2) {
1144 		/* TODO reserve some space for the icb creation time */
1145 		data_space_avail = lb_size - sizeof(struct file_entry)    - 0; /* udf_rw32(file_entry->l_ea) */
1146 	} else {
1147 		data_space_avail = lb_size - sizeof(struct extfile_entry) - 0; /* udf_rw32(extfile_entry->l_ea) */
1148 	}
1149 	udf_node->intern_free = data_space_avail;
1150 	udf_node->intern_data = NULL;
1151 	udf_node->intern_len  = 0;
1152 
1153 	/* finalise udf_node */
1154 	udf_node->mountpoint  = mountpoint;
1155 	udf_node->udf_log_vol = udf_log_vol;
1156 	TAILQ_INIT(&udf_node->dscr_allocs);
1157 	TAILQ_INIT(&udf_node->alloc_entries);
1158 	TAILQ_INIT(&udf_node->vn_bufs);
1159 	UDF_MUTEX_INIT(&udf_node->alloc_mutex);
1160 	UDF_MUTEX_INIT(&udf_node->buf_mutex);
1161 
1162 	/* XXX udf_node_lock NOT USED XXX */
1163 	/* pthread_rwlock_init(&udf_node->udf_node_lock, NULL); */
1164 
1165 	*udf_nodeptr = udf_node;
1166 	return 0;
1167 }
1168 
1169 
udf_allocate_udf_node_on_disc(struct udf_node * udf_node)1170 int udf_allocate_udf_node_on_disc(struct udf_node *udf_node) {
1171 	struct udf_allocentry *alloc_entry;
1172 	uint32_t  lb_num, lb_size;
1173 	uint16_t  vpart_num;
1174 	int       error;
1175 
1176 	assert(udf_node);
1177 	assert(udf_node->udf_log_vol);
1178 	assert(udf_node->udf_log_vol->log_vol);
1179 
1180 	lb_size   = udf_node->udf_log_vol->lb_size;
1181 	assert(lb_size);
1182 
1183 	/* pre-allocate node; its needed in directory linkage for now */
1184 	error = udf_allocate_lbs(udf_node->udf_log_vol, UDF_C_NODE, /*num lb */ 1, "New FID", &vpart_num, &lb_num, NULL);
1185 	if (error) return error;
1186 
1187 	alloc_entry = calloc(1, sizeof(struct udf_allocentry));
1188 	if (!alloc_entry) {
1189 		return ENOMEM;
1190 	}
1191 
1192 	alloc_entry->len        = lb_size;
1193 	alloc_entry->vpart_num  = vpart_num;
1194 	alloc_entry->lb_num     = lb_num;
1195 	alloc_entry->flags      = 0;
1196 	TAILQ_INSERT_TAIL(&udf_node->dscr_allocs, alloc_entry, next_alloc);
1197 
1198 	assert(error == 0);
1199 	return error;
1200 }
1201 
1202 
1203 /* note: the udf_node (inode) is not stored in a hashtable! hash value is still invalid */
1204 /* TODO remember our extended attributes and remember our streamdir long_ad  */
udf_readin_anon_udf_node(struct udf_log_vol * udf_log_vol,union dscrptr * given_dscrptr,struct long_ad * udf_icbptr,char * what,struct udf_node ** udf_nodeptr)1205 int udf_readin_anon_udf_node(struct udf_log_vol *udf_log_vol, union dscrptr *given_dscrptr, struct long_ad *udf_icbptr, char *what, struct udf_node **udf_nodeptr) {
1206 	union  dscrptr  	*dscrptr;
1207 	struct udf_node 	*udf_node;
1208 	struct udf_allocentry	*alloc_entry;
1209 	struct udf_allocentry	*cur_alloc, *next_alloc;
1210 	struct file_entry	*file_entry;
1211 	struct extfile_entry	*extfile_entry;
1212 	struct alloc_ext_entry	*alloc_ext_entry;
1213 	struct long_ad		*l_ad;
1214 	struct short_ad		*s_ad;
1215 	uint64_t		 inf_len, calculated_len;
1216 	uint32_t		 lb_size, entries;
1217 	uint64_t		 data_length;
1218 	uint32_t		 data_space_avail;
1219 	uint32_t		 fe_tag;
1220 	uint64_t		 len;
1221 	uint32_t		 lb_num, vpart_num;
1222 	uint32_t		 icb_len;
1223 	int16_t			 addr_type;
1224 	uint8_t			*pos;
1225 	uint8_t			 flags;
1226 	int			 error, advance_sector;
1227 
1228 	if ((udf_icbptr->loc.lb_num == 0) && (udf_icbptr->loc.part_num == 0) && (udf_icbptr->len == 0)) return ENOENT;
1229 
1230 	DEBUG(printf("udf_readin_anon_udf_node for %s\n", what));
1231 
1232 	error = udf_init_udf_node(/*mountpoint*/ NULL, udf_log_vol, what, &udf_node);
1233 	DEBUG(
1234 		if (error) printf("While reading in `anononymous' udf_node : got error %s\n", strerror(error));
1235 	);
1236 	if (error) return error;
1237 
1238 	*udf_nodeptr = udf_node;
1239 
1240 	assert(udf_log_vol);
1241 	lb_size     = udf_log_vol->lb_size;
1242 
1243 	/* read in descriptor if not provided to us */
1244 	dscrptr   = NULL;
1245 	len       = lb_size;					/* nodes are defined in lb_size only (?) */
1246 	lb_num    = udf_rw32(udf_icbptr->loc.lb_num);
1247 	vpart_num = udf_rw16(udf_icbptr->loc.part_num);
1248 	if (!given_dscrptr) {
1249 		error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, lb_num, what, &dscrptr, NULL);
1250 		if (error) {
1251 			*udf_nodeptr = NULL;
1252 			return error;
1253 		}
1254 	} else {
1255 		dscrptr = given_dscrptr;
1256 	}
1257 
1258 	fe_tag = udf_rw16(dscrptr->tag.id);
1259 	if (fe_tag != TAGID_FENTRY && fe_tag != TAGID_EXTFENTRY) {
1260 		/* something wrong with this address; it doesn't start with a file entry */
1261 		printf("UDF: bad udf_node for %s; got a %d tag\n", what, fe_tag);
1262 		if (dscrptr != given_dscrptr) free(dscrptr);
1263 		udf_dispose_udf_node(udf_node);
1264 		*udf_nodeptr = NULL;
1265 		return EFAULT;
1266 	}
1267 
1268 	/* get as much info as possible */
1269 	udf_node_get_fileinfo(udf_node, dscrptr);
1270 
1271 	/* reset pending write count */
1272 	udf_node->v_numoutput = 0;
1273 
1274 	/* initialise various variables for extracting allocation information */
1275 	inf_len = 0; data_length = 0; lb_num = 0; len = 0; vpart_num = 0; pos = NULL;
1276 	data_space_avail = 0;
1277 
1278 	next_alloc = calloc(1, sizeof(struct udf_allocentry));
1279 	if (!next_alloc) {
1280 		if (dscrptr != given_dscrptr) free(dscrptr);
1281 		udf_dispose_udf_node(udf_node);
1282 		*udf_nodeptr = NULL;
1283 		return ENOMEM;
1284 	}
1285 	next_alloc->len       = lb_size;
1286 	next_alloc->lb_num    = udf_rw32(udf_icbptr->loc.lb_num);
1287 	next_alloc->vpart_num = udf_rw16(udf_icbptr->loc.part_num);
1288 
1289 	entries = 1;
1290 	calculated_len = 0;
1291 
1292 	error = 0;
1293 	addr_type = -1;
1294 	do {
1295 		cur_alloc = next_alloc;
1296 		next_alloc = calloc(1, sizeof(struct udf_allocentry));
1297 		if (!next_alloc) {
1298 			if (dscrptr != given_dscrptr) free(dscrptr);
1299 			udf_dispose_udf_node(udf_node);
1300 			*udf_nodeptr = NULL;
1301 			return ENOMEM;
1302 		}
1303 		memcpy(next_alloc, cur_alloc, sizeof(struct udf_allocentry));
1304 		TAILQ_INSERT_TAIL(&udf_node->dscr_allocs, cur_alloc, next_alloc);
1305 
1306 		/* process this allocation descriptor */
1307 		/* note that we don't store the file descriptors -> XXX impl. use stuff gets lost here */
1308 		fe_tag = udf_rw16(dscrptr->tag.id);
1309 		switch (fe_tag) {
1310 			case TAGID_FENTRY :
1311 				/* allocation descriptors follow this tag */
1312 				file_entry       = &dscrptr->fe;
1313 				entries          = udf_rw16(file_entry->icbtag.max_num_entries);
1314 				data_length      = udf_rw32(file_entry->l_ad);
1315 				pos              = &file_entry->data[0] + udf_rw32(file_entry->l_ea);
1316 				inf_len          = udf_rw64(file_entry->inf_len);
1317 				addr_type        = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
1318 				data_space_avail = lb_size - sizeof(struct file_entry) - udf_rw32(file_entry->l_ea);
1319 				/* process extended attributes */
1320 				/* keep a trace of the descriptors in this udf_node */
1321 				UDF_VERBOSE_MAX(udf_dump_file_entry(file_entry));
1322 				break;
1323 			case TAGID_EXTFENTRY :
1324 				/* allocation descriptors follow this tag */
1325 				extfile_entry    = &dscrptr->efe;
1326 				entries          = udf_rw16(extfile_entry->icbtag.max_num_entries);
1327 				data_length      = udf_rw32(extfile_entry->l_ad);
1328 				pos              = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea);
1329 				inf_len          = udf_rw64(extfile_entry->inf_len);
1330 				addr_type        = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
1331 				data_space_avail = lb_size - sizeof(struct extfile_entry) - udf_rw32(extfile_entry->l_ea);
1332 				/* process extended attributes */
1333 				/* keep a trace of the descriptors in this udf_node */
1334 				UDF_VERBOSE_MAX(udf_dump_extfile_entry(extfile_entry));
1335 				break;
1336 			case TAGID_ALLOCEXTENT :
1337 				/* allocation descriptors follow this tag; treat as if continuation of a (ext)file entry*/
1338 				alloc_ext_entry  = &dscrptr->aee;
1339 				data_length      = udf_rw32(alloc_ext_entry->l_ad);
1340 				pos		 = &alloc_ext_entry->data[0];
1341 				assert(addr_type >= 0);
1342 
1343 				/* keep a trace of the descriptors in this udf_node */
1344 				UDF_VERBOSE_MAX(udf_dump_alloc_extent(alloc_ext_entry, addr_type));
1345 				break;
1346 			case TAGID_INDIRECTENTRY :
1347 				printf("create_anon_udf_node called with indirect entry; following chain\n");
1348 				l_ad = &dscrptr->inde.indirect_icb;
1349 				next_alloc->len       = udf_rw32(l_ad->len);
1350 				next_alloc->lb_num    = udf_rw32(l_ad->loc.lb_num);
1351 				next_alloc->vpart_num = udf_rw16(l_ad->loc.part_num);
1352 				entries   = 1;		/* at least one more entry	*/
1353 				advance_sector = 0;	/* don't advance to next sector */
1354 
1355 				UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
1356 				break;
1357 			default:
1358 				printf("read_file_part_extents: i can't be here! (tag = %d) in ICB hiargy of %s\n", fe_tag, what);
1359 				udf_dump_descriptor(dscrptr);
1360 				return EFAULT;
1361 		}
1362 		if (fe_tag != TAGID_INDIRECTENTRY) {
1363 			udf_node->addr_type = addr_type;
1364 			if (addr_type == UDF_ICB_INTERN_ALLOC) {
1365 				udf_node->intern_len  = inf_len;
1366 				udf_node->intern_free = data_space_avail;
1367 				udf_node->intern_data = calloc(1, udf_node->intern_free);
1368 				if (udf_node->intern_data) {
1369 					memcpy(udf_node->intern_data, pos, inf_len);
1370 				} else {
1371 					error = ENOMEM;
1372 				}
1373 
1374 				if (dscrptr != given_dscrptr) free(dscrptr);
1375 				return error;
1376 			}
1377 
1378 			icb_len = 0;
1379 			switch (udf_node->addr_type) {
1380 				case UDF_ICB_SHORT_ALLOC :
1381 					icb_len   = sizeof(struct short_ad);
1382 					break;
1383 				case UDF_ICB_LONG_ALLOC  :
1384 					icb_len   = sizeof(struct long_ad);
1385 					break;
1386 				default :
1387 					printf("UDF encountered an unknown allocation type %d\n", udf_node->addr_type);
1388 					break;
1389 			}
1390 			udf_node->icb_len = icb_len;
1391 			advance_sector = 1;
1392 			while (icb_len && data_length) {
1393 				switch (udf_node->addr_type) {
1394 					case UDF_ICB_SHORT_ALLOC  :
1395 						s_ad = (struct short_ad *) pos;
1396 						len       = udf_rw32(s_ad->len);
1397 						lb_num    = udf_rw32(s_ad->lb_num);
1398 						vpart_num = cur_alloc->vpart_num;
1399 						break;
1400 					case UDF_ICB_LONG_ALLOC   :
1401 						l_ad = (struct long_ad *) pos;
1402 						len       = udf_rw32(l_ad->len);
1403 						lb_num    = udf_rw32(l_ad->loc.lb_num);
1404 						vpart_num = udf_rw16(l_ad->loc.part_num);
1405 						if (l_ad->impl.im_used.flags & UDF_ADIMP_FLAGS_EXTENT_ERASED) {
1406 							printf("UDF: got a `extent erased' flag in a file's long_ad; ignoring\n");
1407 						}
1408 						break;
1409 					default :
1410 						printf("UDF encountered an unknown allocation type %d\n", udf_node->addr_type);
1411 						break;
1412 				}
1413 				/* ecma-167 48.14.1.1 */
1414 				flags = (uint8_t) ((uint32_t) (len >> 30) & 3);
1415 				len   = len & ((1<<30)-1);
1416 				if (flags == UDF_SPACE_REDIRECT) {
1417 					/* fill in next extent */
1418 					next_alloc->len       = len;
1419 					next_alloc->lb_num    = lb_num;
1420 					next_alloc->vpart_num = vpart_num;
1421 					advance_sector = 0;	/* don't advance to next sector */
1422 					icb_len = data_length;	/* must be last */
1423 					printf("Continuing extent flagged at vpart = %d, lb_num = %d, len = %d\n", (int) vpart_num, (int) lb_num, (int) len);
1424 				} else {
1425 					if (len) {
1426 						alloc_entry = calloc(1, sizeof(struct udf_allocentry));
1427 						if (!alloc_entry) {
1428 							if (dscrptr != given_dscrptr) free(dscrptr);
1429 							return ENOMEM;
1430 						}
1431 						alloc_entry->len       = len;
1432 						alloc_entry->lb_num    = lb_num;
1433 						alloc_entry->vpart_num = vpart_num;
1434 						alloc_entry->flags     = flags;
1435 						TAILQ_INSERT_TAIL(&udf_node->alloc_entries, alloc_entry, next_alloc);
1436 					}
1437 					calculated_len += len;
1438 				}
1439 				data_length  -= icb_len;
1440 				pos          += icb_len;
1441 			} /* while */
1442 			if (advance_sector) {
1443 				/* Note: UDF descriptor length is maximised to one sector */
1444 				next_alloc->lb_num++;	/* advance one sector */
1445 				entries--;
1446 			}
1447 		} /* indirect ICB check */
1448 		if (entries) {
1449 			/* load in new dscrptr */
1450 			if (dscrptr != given_dscrptr) free(dscrptr);
1451 			error = udf_read_logvol_descriptor(udf_log_vol, next_alloc->vpart_num, next_alloc->lb_num, what, &dscrptr, NULL);
1452 		}
1453 	} while (entries && !error);
1454 
1455 	/* error from reading next sector in extent is not considered an error */
1456 	if (dscrptr != given_dscrptr && dscrptr) free(dscrptr);
1457 
1458 	if (calculated_len != (uint64_t) udf_node->stat.st_size) {
1459 		printf("UDF: create node length mismatch; stated as %g but calculated as %g bytes. fixing\n", (double) udf_node->stat.st_size, (double) calculated_len);
1460 		udf_node->stat.st_size = calculated_len;
1461 	}
1462 
1463 	return 0;
1464 }
1465 
1466 
udf_readin_udf_node(struct udf_node * dir_node,struct long_ad * udf_icbptr,struct fileid_desc * fid,struct udf_node ** res_sub_node)1467 int udf_readin_udf_node(struct udf_node *dir_node, struct long_ad *udf_icbptr, struct fileid_desc *fid, struct udf_node **res_sub_node) {
1468 	struct udf_node    *sub_node;
1469 	char               *fid_name;
1470 	char                entry_name[NAME_MAX];
1471 	uint32_t            bucket;
1472 	ino_t               hashkey;
1473 	int                 error;
1474 
1475 	assert(dir_node);
1476 	assert(udf_icbptr);
1477 	assert(fid);
1478 	assert(res_sub_node);
1479 
1480 	/* check if its allready in the logical volume's udf_node cache (inodes) */
1481 	hashkey = udf_calc_hash(udf_icbptr);
1482 	bucket  = hashkey & UDF_INODE_HASHMASK;
1483 
1484 	LIST_FOREACH(sub_node, &dir_node->udf_log_vol->udf_nodes[bucket], next_node) {
1485 		if (sub_node->hashkey == hashkey) {
1486 			*res_sub_node = sub_node;
1487 			DEBUG(printf("found node in hashlist\n"));
1488 
1489 			return 0;
1490 		}
1491 	}
1492 
1493 	/* dump the FID we are trying to read in */
1494 	UDF_VERBOSE_MAX(udf_dump_descriptor((union dscrptr *) fid));
1495 
1496 	fid_name = (char *) fid->data + udf_rw16(fid->l_iu);
1497 	udf_to_unix_name(entry_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset);
1498 
1499 	/* build missing vnode */
1500 	error = udf_readin_anon_udf_node(dir_node->udf_log_vol, NULL, udf_icbptr, entry_name, &sub_node);
1501 	if (error)
1502 		return error;
1503 
1504 	if (!sub_node) {
1505 		printf("sub_node = NULL? and no error? \n");
1506 	}
1507 	assert(sub_node);
1508 
1509 	/* link this UDF node to the mountpoint and remember its hash-key */
1510 	sub_node->mountpoint       = dir_node->mountpoint;
1511 	sub_node->hashkey          = hashkey;
1512 
1513 	/* XXX use file version number and filechar from fid ? */
1514 	sub_node->file_version_num = udf_rw16(fid->file_version_num);	/* user set */
1515 	sub_node->udf_filechar     = fid->file_char;
1516 
1517 	/* insert/replace in mountpoint's udfnode hashtable with optional check for doubles */
1518 if (0) {
1519 		struct udf_node *lookup;
1520 		LIST_FOREACH(lookup, &dir_node->udf_log_vol->udf_nodes[bucket], next_node) {
1521 			if (lookup->hashkey == sub_node->hashkey) printf("DOUBLE hashnode?\n");
1522 		}
1523 }
1524 
1525 	LIST_INSERT_HEAD(&dir_node->udf_log_vol->udf_nodes[bucket], sub_node, next_node);
1526 	DEBUG(printf("inserting hash node for hash = %d\n", (int) hashkey));
1527 
1528 	*res_sub_node = sub_node;
1529 	return 0;
1530 }
1531 
1532 
udf_syncnode_callback(int reason,struct udf_wrcallback * wrcallback,int error,uint8_t * sectordata)1533 void udf_syncnode_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) {
1534 	/* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */
1535 
1536 	wrcallback = wrcallback;	/* unused for now */
1537 	sectordata = sectordata;
1538 
1539 	if (reason == UDF_WRCALLBACK_REASON_PENDING) {
1540 		/* what to do? */
1541 		return;
1542 	}
1543 	if (reason == UDF_WRCALLBACK_REASON_ANULATE) {
1544 		/* what to do? */
1545 		return;
1546 	}
1547 	assert(reason == UDF_WRCALLBACK_REASON_WRITTEN);
1548 	if (error) {
1549 		printf("UDF error: syncnode writing failed, not fixing yet!\n");
1550 		return;
1551 	}
1552 }
1553 
1554 
1555 /* XXX This mark node dirty code will simplify if we store nodes in buffers? XXX */
udf_node_mark_dirty(struct udf_node * udf_node)1556 void udf_node_mark_dirty(struct udf_node *udf_node) {
1557 	struct udf_allocentry *alloc_entry, *my_entry, *tail_entry;
1558 	struct udf_node *search_node, *tail_node;
1559 
1560 	if (udf_node->dirty) return;
1561 
1562 	my_entry = TAILQ_FIRST(&udf_node->dscr_allocs);
1563 	assert(my_entry);
1564 
1565 	/* dscr locks ? */
1566 	UDF_MUTEX_LOCK(&udf_node->udf_log_vol->dirty_nodes_mutex);
1567 if (1) {
1568 		/* insertion sort :-S */
1569 		tail_node  = TAILQ_LAST(&udf_node->udf_log_vol->dirty_nodes, udf_node_list);
1570 		if (!tail_node) {
1571 			TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty);
1572 		} else {
1573 			tail_entry = TAILQ_FIRST(&tail_node->dscr_allocs);
1574 			if (tail_entry->lb_num < my_entry->lb_num) {
1575 				TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty);
1576 			} else {
1577 				/* find my place; could be done smarter */
1578 				TAILQ_FOREACH(search_node, &udf_node->udf_log_vol->dirty_nodes, next_dirty) {
1579 					alloc_entry = TAILQ_FIRST(&tail_node->dscr_allocs);
1580 					if (alloc_entry->lb_num > my_entry->lb_num) {
1581 						TAILQ_INSERT_BEFORE(search_node, udf_node, next_dirty);
1582 						break;	/* foreach */
1583 					}
1584 				}
1585 			}
1586 		}
1587 } else {
1588 		/* dumb */
1589 		TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty);
1590 }
1591 	UDF_MUTEX_UNLOCK(&udf_node->udf_log_vol->dirty_nodes_mutex);
1592 	udf_node->dirty = 1;
1593 }
1594 
1595 
udf_node_unmark_dirty(struct udf_node * udf_node)1596 static void udf_node_unmark_dirty(struct udf_node *udf_node) {
1597 	if (!udf_node->dirty) return;
1598 
1599 	/* remove me just in case; why were we called otherwise? */
1600 	UDF_MUTEX_LOCK(&udf_node->udf_log_vol->dirty_nodes_mutex);
1601 		TAILQ_REMOVE(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty);
1602 	UDF_MUTEX_UNLOCK(&udf_node->udf_log_vol->dirty_nodes_mutex);
1603 	udf_node->dirty = 0;
1604 }
1605 
1606 
1607 /* VOP_FSYNC : data FDATASYNC */
udf_sync_udf_node(struct udf_node * udf_node,char * why)1608 int udf_sync_udf_node(struct udf_node *udf_node, char *why) {
1609 
1610 	DEBUG(printf("Syncing udf_node `%"PRIu64"` because of %s\n", udf_node->unique_id, why));
1611 	DEBUG(printf("sync udf node: dirty = %d, v_numoutput = %d\n", udf_node->dirty, udf_node->v_numoutput));
1612 	if (!udf_node->dirty) {
1613 		/* Not dirty??!!! */
1614 		udf_node_unmark_dirty(udf_node);
1615 		return 0;
1616 	}
1617 
1618 	if (!udf_node->udf_log_vol->writable) {
1619 		fprintf(stderr, "encountered a dirty node on a read-only filingsystem!\n");
1620 		exit(1);
1621 	}
1622 
1623 	/*
1624 	 * We are really syncing disc but we are only continueing when the
1625 	 * node itself is clean... not breaking the semantics.
1626 	 */
1627 	/* XXX flushall flag magic XXX */
1628 	udf_bufcache->flushall = 1;
1629 	udf_purgethread_kick("Sync node");
1630 	fflush(stdout);
1631 
1632 	/* wait until all dirty bufs associated with this node are processed */
1633 	if (!udf_node->dirty) return 0;
1634 
1635 	if (udf_node->v_numoutput) {
1636 		usleep(100);
1637 	}
1638 	if (!udf_node->v_numoutput) return 0;
1639 
1640 	UDF_VERBOSE(printf("(wait on node)"));
1641 	while (udf_node->v_numoutput) {
1642 		usleep(100);
1643 	}
1644 
1645 	return 0;
1646 }
1647 
1648 
1649 extern void udf_merge_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size);
1650 
1651 /* VOP_FSYNC : metadata FFILESYNC */
1652 /* writeout the udf_node back to disc */
1653 /* TODO don't forget to writeout our extended attributes and write out the link to the associated streamdir as well */
udf_writeout_udf_node(struct udf_node * udf_node,char * why)1654 int udf_writeout_udf_node(struct udf_node *udf_node, char *why) {
1655 	struct udf_wrcallback   wr_callback;
1656 	struct udf_allocentry  *dscr_entry, *next_dscr_entry, *alloc_entry;
1657 	union dscrptr          *dscrptr;
1658 	struct file_entry      *fe;
1659 	struct extfile_entry   *efe;
1660 	struct alloc_ext_entry *aee;
1661 	struct lb_addr          parent_icb;
1662 	struct icb_tag         *icbtag;
1663 	struct long_ad         *l_ad;
1664 	struct short_ad        *s_ad;
1665 	uint32_t               *l_adptr;	/* points to length of alloc. descr. */
1666 	uint8_t                *pos;
1667 	char                   *what;
1668 	uint32_t                alloc_entries;
1669 	uint64_t                rest;		/* in bytes */
1670 	uint64_t                len;
1671 	uint64_t                logblks_rec;
1672 	uint32_t		lb_size, descr_ver;
1673 
1674 	if (!udf_node->udf_log_vol->writable) {
1675 		fprintf(stderr, "encountered a dirty node on a read-only filingsystem!\n");
1676 		exit(1);
1677 	}
1678 
1679 	lb_size     = udf_node->udf_log_vol->lb_size;
1680 
1681 	/* assure all file data is written out! and clean up */
1682 	udf_sync_udf_node(udf_node, why);
1683 
1684 	/* XXX node lock? XXX */
1685 
1686 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
1687 		/* clean up allocentry queue so we get a nice clean layout */
1688 		udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size);
1689 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1690 
1691 	/* allocate for descriptor */
1692 	dscrptr = calloc(1, lb_size);	/* not a bit biggish? */
1693 	if (!dscrptr) return ENOMEM;
1694 
1695 	/* calculate logical blocks recorded; zero for interns [UDF 2.3.6.5, ECMA 4/14.9.11, 4/14.6.8] */
1696 	logblks_rec = 0;
1697 	if (udf_node->addr_type != UDF_ICB_INTERN_ALLOC) {
1698 		UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
1699 			TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) {
1700 				if (alloc_entry->flags == UDF_SPACE_ALLOCATED) {
1701 					logblks_rec += (alloc_entry->len + lb_size-1) / lb_size;
1702 				}
1703 			}
1704 		UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1705 	}
1706 
1707 	/* fill in (ext)fentry descriptor */
1708 	/* copy descriptor version from the logvol's */
1709 
1710 	bzero(&parent_icb, sizeof(struct lb_addr));
1711 	descr_ver = udf_rw16(udf_node->udf_log_vol->log_vol->tag.descriptor_ver);
1712 	if (descr_ver == 3) {
1713 		efe = &dscrptr->efe;
1714 		efe->tag.id             = udf_rw16(TAGID_EXTFENTRY);
1715 		efe->tag.descriptor_ver = udf_rw16(descr_ver);
1716 		efe->ckpoint            = udf_rw32(1);			/* [ECMA 4/14.17.17] */
1717 		udf_set_imp_id(&efe->imp_id);
1718 		efe->logblks_rec = udf_rw64(logblks_rec);
1719 
1720 		/* set additional fileinfo (access, uid/gid) etc. */
1721 		udf_node_set_fileinfo(udf_node, dscrptr);
1722 		efe->obj_size           = efe->inf_len;			/* not true if there are streams [ECMA 4/48.17.11] */
1723 
1724 		icbtag = &efe->icbtag;
1725 	} else if (descr_ver == 2) {
1726 		fe = &dscrptr->fe;
1727 		fe->tag.id             = udf_rw16(TAGID_FENTRY);
1728 		fe->tag.descriptor_ver = udf_rw16(descr_ver);
1729 		fe->ckpoint            = udf_rw32(1);			/* [ECMA 4/14.17.17] */
1730 		udf_set_imp_id(&fe->imp_id);
1731 		fe->logblks_rec = udf_rw64(logblks_rec);
1732 
1733 		/* set additional fileinfo (access, uid/gid) etc. */
1734 		udf_node_set_fileinfo(udf_node, dscrptr);
1735 		/* fe->obj_size doesn't exist */
1736 
1737 		icbtag = &fe->icbtag;
1738 	} else {
1739 		printf("UDF: i don't know this descriptor version %d\n", descr_ver);
1740 		return EBADF;
1741 	}
1742 
1743 	/* update derived info */
1744 	udf_node->udf_icbtag_flags = (udf_node->udf_icbtag_flags & ~UDF_ICB_TAG_FLAGS_ALLOC_MASK) | udf_node->addr_type;
1745 
1746 	/* strategy 4 has no parent nodes */
1747 	/* XXX NO extended attributes recorded YET (!!) XXX (like device nodes !!! ) */
1748 
1749 	dscr_entry  = TAILQ_FIRST(&udf_node->dscr_allocs);
1750 
1751 	/* ensure allocation of (ext) file descriptor */
1752 	if (!dscr_entry) {
1753 		/* have to allocate one and add to queue ! */
1754 		printf("UDF: XXX no allocation of file descriptor entry yet in sync_udf_node\n");
1755 		return ENOENT;
1756 	}
1757 
1758 	/* XXX implement alloc entry walker? XXX */
1759 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
1760 	what = "UDF sync: File descriptor";
1761 	alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries);
1762 	do {
1763 		assert(dscr_entry->len <= lb_size);
1764 		if (icbtag) {
1765 			/* fill in ICB fields */			/* XXX we're only writing out strategy type 4 !!! XXX */
1766 			icbtag->prev_num_dirs   = udf_rw32(0);		/* prev_alloc_entries = 0 due to strategy type 4 XXX */
1767 			icbtag->strat_type      = udf_rw16(4);		/* default UDF strategy type 4 XXX what about 4096? */
1768 			icbtag->parent_icb      = parent_icb;
1769 			icbtag->file_type       = udf_node->udf_filetype;
1770 			icbtag->flags           = udf_rw16(udf_node->udf_icbtag_flags);
1771 			icbtag->max_num_entries = udf_rw16(1);		/* due to strategy type 4 ! XXX */
1772 		}
1773 
1774 		pos  = 0;
1775 		rest = 0;
1776 		l_adptr = NULL;		/* invalid */
1777 		switch (udf_rw16(dscrptr->tag.id)) {
1778 			case TAGID_FENTRY         :
1779 				/* not used now */
1780 				fe   = &dscrptr->fe;
1781 				pos  = &fe->data[0] + udf_rw32(fe->l_ea);
1782 				rest = dscr_entry->len - sizeof(struct file_entry) - udf_rw32(fe->l_ea);
1783 				l_adptr = &fe->l_ad;
1784 				break;
1785 			case TAGID_EXTFENTRY      :
1786 				efe  = &dscrptr->efe;
1787 				pos  = &efe->data[0] + udf_rw32(efe->l_ea);
1788 				rest = dscr_entry->len - sizeof(struct extfile_entry) - udf_rw32(efe->l_ea);
1789 				l_adptr = &efe->l_ad;
1790 				break;
1791 			case TAGID_ALLOCEXTENT    :
1792 				aee  = &dscrptr->aee;
1793 				pos  = &aee->data[0];
1794 				rest = dscr_entry->len - sizeof(struct alloc_ext_entry);
1795 				l_adptr = &aee->l_ad;
1796 				break;
1797 			case TAGID_INDIRECTENTRY :
1798 				/* do we even do these in strat 4 ? */
1799 				printf("UDF: sanity check; request for writeout of indirect entry\n");
1800 				free(dscrptr);
1801 				UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1802 				return ENOENT;	/* panic really */
1803 		}
1804 		assert(l_adptr);
1805 
1806 		/* fill in remaining allocation entries 	*/
1807 		/* remember to keep one SPARE for extending	*/
1808 
1809 		alloc_entries = 0;
1810 		DEBUG(printf("Allocated at "));
1811 
1812 		if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) {
1813 			/* internal allocation -> copy in data */
1814 			assert(udf_node->intern_len <= rest);
1815 
1816 			bzero(pos, rest);
1817 			memcpy(pos, udf_node->intern_data, udf_node->intern_len);
1818 
1819 			/* make sure the length for allocation entries is the same as the data it contains (4/8.8.2, 4/14.6.8) */
1820 			*l_adptr = udf_rw32(udf_node->intern_len);
1821 
1822 			/* alloc_entry is zero, so it'll fall trough */
1823 			pos	+= udf_node->intern_len;	/* advance pos for length calculation */
1824 			alloc_entry = NULL;			/* not applicable */
1825 		}
1826 
1827 		while ((rest > 2*udf_node->icb_len) && alloc_entry) {
1828 			assert(udf_node->icb_len);
1829 			DEBUG(printf("[%p, lb_num = %d, len = %d]   ", alloc_entry, (uint32_t) alloc_entry->lb_num, (uint32_t) alloc_entry->len));
1830 
1831 			/* XXX assumption: UDF_SPACE_* is equal to UDF flags XXX */
1832 			len = alloc_entry->len | (((uint32_t) alloc_entry->flags) << 30);
1833 			switch (udf_node->addr_type) {
1834 				case UDF_ICB_SHORT_ALLOC :
1835 					s_ad = (struct short_ad *) pos;
1836 					s_ad->len          = udf_rw32(len);
1837 					s_ad->lb_num       = udf_rw32(alloc_entry->lb_num);
1838 					assert(alloc_entry->vpart_num == 0);
1839 					if (alloc_entry->len   == 0)              s_ad->lb_num = udf_rw32(0);
1840 					if (alloc_entry->flags == UDF_SPACE_FREE) s_ad->lb_num = udf_rw32(0);
1841 					break;
1842 				case UDF_ICB_LONG_ALLOC  :
1843 					l_ad = (struct long_ad *) pos;
1844 					l_ad->len          = udf_rw32(len);
1845 					l_ad->loc.lb_num   = udf_rw32(alloc_entry->lb_num);
1846 					l_ad->loc.part_num = udf_rw16(alloc_entry->vpart_num);
1847 					l_ad->impl.im_used.unique_id = udf_rw64(udf_node->unique_id);
1848 					if (alloc_entry->len   == 0)              l_ad->loc.lb_num = udf_rw32(0);
1849 					if (alloc_entry->flags == UDF_SPACE_FREE) l_ad->loc.lb_num = udf_rw32(0);
1850 					break;
1851 			}
1852 			alloc_entries++;
1853 			*l_adptr = udf_rw32(alloc_entries * udf_node->icb_len);
1854 			alloc_entry = TAILQ_NEXT(alloc_entry, next_alloc);
1855 			pos  += udf_node->icb_len;
1856 			rest -= udf_node->icb_len;
1857 		}
1858 		DEBUG(printf("\nend alloc\n\n"));
1859 
1860 		next_dscr_entry = TAILQ_NEXT(dscr_entry, next_alloc);
1861 		if (alloc_entry) {
1862 			/* overflow */
1863 
1864 			/* ensure allocation of (ext) file descriptor */
1865 			if (!next_dscr_entry) {
1866 				/* have to allocate one and add to queue ! */
1867 				printf("UDF: XXX no allocation of allocation extent descriptor yet in sync_udf_node\n");
1868 				UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1869 				return ENOENT;
1870 			}
1871 			/* flag next extent being specified */
1872 			len = next_dscr_entry->len | ((uint32_t) UDF_SPACE_REDIRECT << 30);
1873 			switch (udf_node->addr_type) {
1874 				case UDF_ICB_SHORT_ALLOC :
1875 					s_ad = (struct short_ad *) pos;
1876 					s_ad->len          = udf_rw32(len);
1877 					s_ad->lb_num       = udf_rw32(next_dscr_entry->lb_num);
1878 					assert(next_dscr_entry->vpart_num == 0);
1879 					break;
1880 				case UDF_ICB_LONG_ALLOC  :
1881 					l_ad = (struct long_ad *) pos;
1882 					l_ad->len          = udf_rw32(len);
1883 					l_ad->loc.lb_num   = udf_rw32(next_dscr_entry->lb_num);
1884 					l_ad->loc.part_num = udf_rw16(next_dscr_entry->vpart_num);
1885 					l_ad->impl.im_used.unique_id = udf_rw64(udf_node->unique_id);
1886 					break;
1887 			}
1888 			alloc_entries++;
1889 			pos  += udf_node->icb_len;
1890 			rest -= udf_node->icb_len;
1891 		}
1892 		/* manage lengths */
1893 		dscrptr->tag.desc_crc_len = udf_rw16((pos - (uint8_t *) dscrptr) - UDF_DESC_TAG_LENGTH);
1894 
1895 		/* writeout */
1896 		wr_callback.function  = udf_syncnode_callback;
1897 #if 0
1898 		wr_callback.structure = (void *) udf_node;
1899 		wr_callback.vpart_num = dscr_entry->vpart_num;
1900 		wr_callback.lb_num    = dscr_entry->lb_num;
1901 		wr_callback.offset    = 0; /* ? */
1902 		wr_callback.length    = dscr_entry->len;
1903 #endif
1904 
1905 		UDF_VERBOSE_MAX(
1906 			udf_validate_tag_and_crc_sums(dscrptr);	/* for dumping */
1907 			udf_dump_descriptor(dscrptr);
1908 		);
1909 		errno = udf_write_logvol_descriptor(udf_node->udf_log_vol, dscr_entry->vpart_num, dscr_entry->lb_num, what, dscrptr, &wr_callback);
1910 
1911 		/* advance */
1912 		if (alloc_entry) {
1913 			dscr_entry = next_dscr_entry;
1914 			assert(dscr_entry);
1915 
1916 			/* allocate and initialise new allocation extent descriptor	*/
1917 			/* also flag no icbtag follows					*/
1918 			bzero(dscrptr, lb_size);
1919 			aee = &dscrptr->aee;
1920 			aee->tag.id             = udf_rw16(TAGID_ALLOCEXTENT);
1921 			aee->tag.descriptor_ver = udf_node->udf_log_vol->log_vol->tag.descriptor_ver;
1922 			icbtag = NULL;
1923 
1924 			what = "UDF sync: allocation extent";
1925 		}
1926 
1927 	} while (alloc_entry);
1928 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
1929 
1930 	/* XXX Free extra non used allocation extent descriptors XXX */
1931 
1932 	/* Mark me clean */
1933 	if (udf_node->mountpoint) {
1934 		/* remove me just in case; why were we called otherwise? */
1935 		udf_node_unmark_dirty(udf_node);
1936 	}
1937 
1938 	return 0;
1939 }
1940 
1941 
1942 /******************************************************************************************
1943  *
1944  * Space bitmap reader and writer
1945  *
1946  ******************************************************************************************/
1947 
1948 /* tested OK */
udf_read_in_space_bitmap(struct udf_alloc_entries * queue,struct space_bitmap_desc * sbd,uint32_t lb_size,uint64_t * freespace)1949 int udf_read_in_space_bitmap(struct udf_alloc_entries *queue, struct space_bitmap_desc *sbd, uint32_t lb_size, uint64_t *freespace) {
1950 	struct udf_allocentry *alloc_entry;
1951 	uint64_t bits, from, now, start, end;
1952 	uint8_t byte, bit, bitpos, state, *pos;
1953 	int cnt;
1954 
1955 	assert(udf_rw16(sbd->tag.id) == TAGID_SPACE_BITMAP);
1956 
1957 	DEBUG(printf("processing space bitmap : \n"););
1958 	bits = udf_rw32(sbd->num_bits);
1959 
1960 	/*
1961 	 * Mark the disc as completely full;
1962 	 * Bugallert: use `udf_mark_allocentry_queue()' for the extent might
1963 	 * not fit in just one alloc entry for bigger discs
1964 	 */
1965 	assert(TAILQ_EMPTY(queue));
1966 	udf_mark_allocentry_queue(queue, lb_size, 0, bits * lb_size, UDF_SPACE_ALLOCATED, NULL, NULL);
1967 
1968 	pos = sbd->data;
1969 	from = 0; now = 0; bitpos = 0; byte = *pos; state = byte & 1;
1970 	*freespace = 0;
1971 	while (now < bits) {
1972 		if (bitpos == 0) {
1973 			byte = *pos++;
1974 		}
1975 		bit = byte & 1;
1976 		if (bit != state) {
1977 			if (state) {
1978 				start = from;
1979 				end   = now-1;
1980 				/* printf("[%08d - %08d]", start, end); */
1981 				udf_mark_allocentry_queue(queue, lb_size, start*lb_size, (end-start+1)*lb_size, UDF_SPACE_FREE, NULL, NULL);
1982 				*freespace += (end-start+1)*lb_size;
1983 			}
1984 			from = now;
1985 			state = bit;
1986 		}
1987 		byte >>= 1;
1988 		bitpos = (bitpos+1) & 7;
1989 		now++;
1990 	}
1991 	if (state) {
1992 		start = from;
1993 		end   = now;
1994 		/* printf("[%08d - %08d]", start, end); */
1995 		udf_mark_allocentry_queue(queue, lb_size, start*lb_size, (end-start)*lb_size, UDF_SPACE_FREE, NULL, NULL);
1996 		*freespace += (end-start)*lb_size;
1997 	}
1998 
1999 	UDF_VERBOSE_TABLES(
2000 		printf("\t\tFree space found on this partition");
2001 		cnt = 0;
2002 		start = 0;
2003 		TAILQ_FOREACH(alloc_entry, queue, next_alloc) {
2004 			if (alloc_entry->flags == UDF_SPACE_ALLOCATED) {
2005 				/* printf("... "); */
2006 			} else {
2007 				if (cnt == 0) printf("\n\t\t\t");
2008 				printf("[%08"PRIu64" - %08"PRIu64"]   ", start / lb_size, ((start + alloc_entry->len) / lb_size)-1);
2009 				cnt++; if (cnt > 4) cnt = 0;
2010 			}
2011 			start += alloc_entry->len;
2012 		}
2013 		printf("\n");
2014 	);
2015 
2016 	/* merge is not nessisary */
2017 	return 0;
2018 }
2019 
2020 
2021 /* inverse of readin space bitmap; it synchronises the bitmap with the queue */
2022 /* tested OK */
udf_sync_space_bitmap(struct udf_alloc_entries * queue,struct space_bitmap_desc * sbd,uint32_t lb_size)2023 int udf_sync_space_bitmap(struct udf_alloc_entries *queue, struct space_bitmap_desc *sbd, uint32_t lb_size) {
2024 	struct udf_allocentry *alloc_entry;
2025 	uint32_t start, bits, total_bits;
2026 	uint32_t cnt, byte;
2027 	uint8_t  bit, bitmask, setting;
2028 	uint8_t *pos;
2029 
2030 	/* merge it just in case */
2031 	udf_merge_allocentry_queue(queue, lb_size);
2032 
2033 	total_bits = udf_rw32(sbd->num_bits);
2034 	DEBUG(printf("SYNC SPACE BITMAP DEBUG: total bits = %d\n", total_bits));
2035 
2036 	alloc_entry = TAILQ_FIRST(queue);
2037 	start = alloc_entry->lb_num;
2038 	assert(start == 0);
2039 
2040 	TAILQ_FOREACH(alloc_entry, queue, next_alloc) {
2041 		DEBUG(printf(" [%d : %d + %d]", alloc_entry->flags, alloc_entry->lb_num, alloc_entry->len));
2042 		bits  = alloc_entry->len / lb_size;
2043 		assert(bits*lb_size == alloc_entry->len);
2044 
2045 		byte = start / 8;
2046 		bit  = start - byte*8;
2047 
2048 		pos = sbd->data + byte;
2049 
2050 		if (byte*8 + bit + bits > total_bits) {		/* XXX > or >= ? */
2051 			/* this should NEVER happen */
2052 			printf("UDF: not enough space writing back space bitmap! HELP!\n");
2053 			return EBADF;
2054 		}
2055 
2056 		cnt = 0;
2057 		setting = (alloc_entry->flags != UDF_SPACE_FREE) ? 0 : 255;
2058 		while (cnt < bits) {
2059 			bitmask = (1 << bit);
2060 
2061 			/* simple sanity check */
2062 			if (byte*8 + bit >= total_bits) {
2063 				printf("IEEEE!!!! too big; %d instead of %d\n", (byte*8 + bit), total_bits);
2064 			}
2065 			*pos = (*pos & (~bitmask)) | (setting ? bitmask: 0);
2066 
2067 			cnt++;
2068 			bit++;
2069 			if (bit == 8) {
2070 				/* byte transition */
2071 				byte++; bit = 0;
2072 				pos++;
2073 #if 0
2074 				/* speedup by doing bytes at a time */
2075 				while (bits-cnt > 8) {
2076 					*pos = setting;
2077 					cnt += 8;
2078 					pos++; byte++;
2079 				}
2080 #endif
2081 			}
2082 		}
2083 		start += bits;
2084 	}
2085 	DEBUG(printf("\n\n"));
2086 	return 0;
2087 }
2088 
2089 
2090 
2091 /******************************************************************************************
2092  *
2093  * Filepart readers and writers
2094  *
2095  ******************************************************************************************/
2096 
2097 /* part of VOP_STRATEGY */
2098 /* internal function; reads in a new buffer */
2099 /* !!! bufcache lock ought to be held on entry !!! */
udf_readin_file_buffer(struct udf_node * udf_node,char * what,uint32_t sector,int cache_flags,struct udf_buf ** buf_entry_p)2100 int udf_readin_file_buffer(struct udf_node *udf_node, char *what, uint32_t sector, int cache_flags, struct udf_buf **buf_entry_p) {
2101 	struct udf_allocentry *alloc_entry;
2102 	struct udf_buf	*buf_entry;
2103 	uint64_t         cur_offset;
2104 	uint64_t         overlap_length, overlap_sectors, transfer_length;
2105 	uint32_t	 lb_size;
2106 	uint32_t         len, lb_num, vpart_num;
2107 	int32_t	         error;
2108 	uint8_t	         flags;
2109 
2110 	assert(udf_node);
2111 	assert(buf_entry_p);
2112 	assert(udf_bufcache->bufcache_lock.locked);
2113 
2114 	error = udf_get_buf_entry(udf_node, buf_entry_p);
2115 	if (error) return error;
2116 
2117 	buf_entry = *buf_entry_p;
2118 	lb_size   = udf_node->udf_log_vol->lb_size;
2119 
2120 	/* internal node? */
2121 	if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) {
2122 		buf_entry->b_lblk    = 0;
2123 		buf_entry->b_flags   = 0;				/* not dirty, not needing alloc */
2124 		buf_entry->b_bcount  = udf_node->intern_len;
2125 		buf_entry->b_resid   = lb_size - udf_node->intern_len;
2126 
2127 		memcpy(buf_entry->b_data, udf_node->intern_data, udf_node->intern_len);
2128 
2129 		UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2130 			udf_attach_buf_to_node(udf_node, buf_entry);
2131 		UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2132 		return error;
2133 	}
2134 
2135 	/* `normal' node */
2136 
2137 	/* find sector in the allocation space */
2138 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
2139 	cur_offset = 0;
2140 	error = EIO;	/* until proven readable */
2141 	TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) {
2142 		len       = alloc_entry->len;
2143 		lb_num    = alloc_entry->lb_num;
2144 		vpart_num = alloc_entry->vpart_num;
2145 		flags     = alloc_entry->flags;
2146 
2147 		/* check overlap with this alloc entry */
2148 		if (cur_offset + len > sector * lb_size) {
2149 			/* found an extent that fits */
2150 			assert(((sector * lb_size - cur_offset) % lb_size) == 0);	/* ought to be on sector boundary */
2151 			lb_num += sector - (cur_offset / lb_size);
2152 
2153 			overlap_length  = cur_offset + len - sector * lb_size;
2154 			overlap_sectors = (overlap_length + lb_size -1) / lb_size;
2155 			transfer_length = MIN(lb_size, overlap_length);			/* max one logical sector */
2156 
2157 			/* fill in new buf info */
2158 			buf_entry->b_lblk   = sector;
2159 			buf_entry->b_bcount = transfer_length;
2160 			buf_entry->b_resid  = lb_size - transfer_length;
2161 
2162 			/* sector transfered; mark valid */
2163 			buf_entry->b_flags  = 0;		/* not dirty and valid */
2164 
2165 			switch (flags) {
2166 				case UDF_SPACE_ALLOCATED :
2167 					/* on disc or in the write queue/cache to be written out; read one block at a time */
2168 					error = udf_read_logvol_sector(udf_node->udf_log_vol, vpart_num, lb_num, what, buf_entry->b_data, overlap_sectors, cache_flags);
2169 					break;
2170 				case UDF_SPACE_FREE :
2171 					/* fall trough */
2172 				case UDF_SPACE_ALLOCATED_BUT_NOT_USED :
2173 					error = 0;
2174 					bzero(buf_entry->b_data, lb_size);
2175 					break;
2176 				default :
2177 					fprintf(stderr, "Got an redirect flag, can't happen\n");
2178 					break;
2179 			}
2180 
2181 			if (error) {
2182 				fprintf(stderr, "\tgot error from read_logvol_sector : %s\n", strerror(error));
2183 				break;	/* FOREACH */
2184 			}
2185 
2186 			UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2187 				udf_attach_buf_to_node(udf_node, buf_entry);
2188 			UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2189 
2190 			UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2191 			return 0;
2192 
2193 		} /* looking for overlap */
2194 
2195 		cur_offset += len;
2196 	} /* FOREACH */
2197 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2198 
2199 	*buf_entry_p = NULL;
2200 
2201 	udf_mark_buf_clean(udf_node, buf_entry);	/* its destroyed so not dirty */
2202 	udf_mark_buf_allocated(udf_node, buf_entry);	/* i.e. taken care of */
2203 	udf_free_buf_entry(buf_entry);
2204 	return error;
2205 }
2206 
2207 
2208 /* internal function; shedule writing out of a buffer */
2209 /* part of VOP_STRATEGY */
udf_writeout_file_buffer(struct udf_node * udf_node,char * what,int cache_flags,struct udf_buf * buf_entry)2210 int udf_writeout_file_buffer(struct udf_node *udf_node, char *what, int cache_flags, struct udf_buf *buf_entry) {
2211 	struct udf_allocentry *from_alloc, *to_alloc, *alloc_entry;
2212 	uint32_t lb_num, lb_size, lblk;
2213 	uint16_t vpart_num;
2214 	int error;
2215 
2216 	what = what;	/* not used now */
2217 
2218 	if (!udf_node->udf_log_vol->writable) {
2219 		/* ieek */
2220 		fprintf(stderr, "write request from non writable file buffer?\n");
2221 	}
2222 
2223 	/* first get logical block offset and block size */
2224 	lblk = buf_entry->b_lblk;
2225 	lb_size = udf_node->udf_log_vol->lb_size;
2226 
2227 	error = 0;
2228 	UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2229 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
2230 	UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2231 		/* maybe a bit too strict locking; code is not winning the beauty contest  */
2232 
2233 		/* check if we can convert/save disc space */
2234 		if (udf_node->stat.st_size <= udf_node->intern_free) {
2235 			/* convert to internal alloc with backup storage (writing there) */
2236 			if (udf_node->addr_type != UDF_ICB_INTERN_ALLOC) {
2237 				DEBUG(printf("CONVERTING to intern alloc\n"));
2238 				/* first free all previously allocated sectors (if any) */
2239 				error = udf_node_release_extent(udf_node, 0, udf_node->stat.st_size);
2240 			}
2241 			assert(!error);
2242 			if (!udf_node->intern_data) {
2243 				udf_node->intern_data = calloc(1, udf_node->intern_free);
2244 			}
2245 			if (udf_node->intern_data) {
2246 				assert(buf_entry->b_bcount <= udf_node->intern_free);
2247 
2248 				memcpy(udf_node->intern_data, buf_entry->b_data, buf_entry->b_bcount);
2249 				udf_node->intern_len = buf_entry->b_bcount;
2250 				udf_node->addr_type = UDF_ICB_INTERN_ALLOC;
2251 
2252 				/* we don't write here: mark buffer clean */
2253 				udf_mark_buf_clean(udf_node, buf_entry);
2254 				udf_mark_buf_allocated(udf_node, buf_entry);		/* signal its allocated */
2255 				buf_entry->b_flags &= ~(B_ERROR);
2256 
2257 				/* check if all buffers are gone now and mark node for writeout to indicate state change */
2258 				assert(udf_node->v_numoutput == 0);
2259 				udf_node_mark_dirty(udf_node);
2260 
2261 				UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2262 				UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2263 				UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2264 				return 0;
2265 			}
2266 			/* fall trough ... for some reason it isn't converted */
2267 		} else {
2268 			if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) {
2269 				DEBUG(printf("CONVERTING to normal alloc\n"));
2270 				/* won't fit anymore, have to turn it into a `normal' alloced */
2271 				udf_node->intern_len = 0;
2272 				if (udf_node->intern_data)
2273 					free(udf_node->intern_data);
2274 				udf_node->intern_data = NULL;
2275 				udf_node->icb_len   = sizeof(struct long_ad);
2276 				udf_node->addr_type = UDF_ICB_LONG_ALLOC;
2277 
2278 				udf_node_mark_dirty(udf_node);
2279 
2280 				/* mark needalloc to make sure it gets an address */
2281 				udf_mark_buf_needing_allocate(udf_node, buf_entry);	/* signal it needs allocation */
2282 			}
2283 		}
2284 
2285 		/* merge queue first to get better performance */
2286 		udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size);
2287 
2288 		/* get extent that it represents */
2289 		udf_mark_allocentry_queue(&udf_node->alloc_entries, lb_size, (uint64_t) lblk*lb_size, buf_entry->b_bcount, UDF_SPACE_ALLOCATED, &from_alloc, &to_alloc);
2290 		alloc_entry = from_alloc;
2291 		if (buf_entry->b_flags & B_NEEDALLOC) {
2292 			/* need allocation */
2293 			error = udf_node_allocate_lbs(udf_node, /* num lb */ 1, &vpart_num, &lb_num, NULL);
2294 			assert(!error);
2295 			udf_mark_buf_allocated(udf_node, buf_entry);
2296 
2297 			alloc_entry->lb_num    = lb_num;
2298 			alloc_entry->vpart_num = vpart_num;
2299 		}
2300 		assert(TAILQ_NEXT(alloc_entry, next_alloc) == to_alloc || (alloc_entry == to_alloc));
2301 
2302 		lb_num    = alloc_entry->lb_num;
2303 		vpart_num = alloc_entry->vpart_num;
2304 	UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2305 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2306 	UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2307 
2308 	/* printf("writing out filebuffer vpart %d, lb_num %d for %s\n", vpart_num, lb_num, what); */
2309 	error = udf_write_logvol_sector(udf_node->udf_log_vol, vpart_num, lb_num, "File contents", buf_entry->b_data, cache_flags, NULL);
2310 
2311 	UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2312 	UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2313 		if (error) {
2314 			printf("YIKES error during writing of logvol_sector\n");
2315 			udf_mark_buf_needing_allocate(udf_node, buf_entry);
2316 			buf_entry->b_flags |= B_ERROR;
2317 			/* buf_entry->b_errno = error; */
2318 		} else {
2319 			udf_mark_buf_clean(udf_node, buf_entry);
2320 			buf_entry->b_flags &= ~(B_ERROR);
2321 		}
2322 	UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2323 	UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2324 
2325 	return error;
2326 }
2327 
2328 
2329 /* VOP_READ */
udf_read_file_part_uio(struct udf_node * udf_node,char * what,int content,struct uio * data_uio)2330 int udf_read_file_part_uio(struct udf_node *udf_node, char *what, int content, struct uio *data_uio) {
2331 	struct udf_buf	*buf_entry;
2332 	off_t  offset;
2333 	uint64_t  sector, lb_size, data_length;
2334 	uint8_t  *base;
2335 	int error, short_buf;
2336 
2337 	if (!udf_node) return EINVAL;
2338 
2339 	/* NOTE: we are NOT marking the node dirty only by reading it */
2340 	udf_set_timespec_now(&udf_node->stat.st_atimespec);
2341 
2342 	if (udf_node->stat.st_size == 0) {
2343 		if (data_uio->uio_resid) return EIO; /* reading past end by default */
2344 		return 0;
2345 	}
2346 
2347 	lb_size = udf_node->udf_log_vol->lb_size;
2348 	error = 0;
2349 	while (data_uio->uio_resid) {
2350 		error = 0;
2351 		short_buf = 0;
2352 		sector  = data_uio->uio_offset / lb_size;
2353 
2354 		/* lookup sector in buffer set */
2355 		UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2356 			udf_lookup_node_buf(udf_node, sector, &buf_entry);
2357 
2358 			if (!buf_entry || (buf_entry && (buf_entry->b_lblk != sector))) {
2359 				/* `page in' sector from file */
2360 				error = udf_readin_file_buffer(udf_node, what, sector, content, &buf_entry);
2361 			}
2362 
2363 			if (!error && buf_entry) {
2364 				offset = data_uio->uio_offset - (off_t) sector*lb_size;
2365 				base   = buf_entry->b_data;
2366 				if (offset >= 0) {
2367 					data_length = buf_entry->b_bcount - offset;
2368 					data_length = MIN(data_length, data_uio->uio_resid);
2369 					uiomove(base + offset, data_length, data_uio);
2370 				}
2371 				short_buf = (buf_entry->b_bcount < lb_size);	/* short buf -> none will follow */
2372 			}
2373 			assert(!error || (error && !buf_entry));
2374 		UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2375 		if (error) break; /* while */
2376 
2377 		if (data_uio->uio_resid == 0) return 0;		/* finished? */
2378 		if (short_buf) break;				/* while */
2379 	} /* while */
2380 
2381 	if (data_uio->uio_resid) {
2382 		printf("UDF: WARNING file is truncated; missing %d bytes while reading %s\n",
2383 				(int) data_uio->uio_resid, what);
2384 		return EIO;
2385 	}
2386 
2387 	return error;
2388 }
2389 
2390 
2391 /* XXX meaning is to be changed; kept for reference still XXX */
udf_filepart_write_callback(int reason,struct udf_wrcallback * wrcallback,int error,uint8_t * sectordata)2392 void udf_filepart_write_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) {
2393 	/* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */
2394 
2395 	wrcallback = wrcallback;	/* unused for now */
2396 	sectordata = sectordata;
2397 
2398 	if (reason == UDF_WRCALLBACK_REASON_PENDING) {
2399 		/* what to do? */
2400 		return;
2401 	}
2402 	if (reason == UDF_WRCALLBACK_REASON_ANULATE) {
2403 		/* what to do? */
2404 		return;
2405 	}
2406 	assert(reason == UDF_WRCALLBACK_REASON_WRITTEN);
2407 	if (error) {
2408 		printf("UDF error: file part write failed, not fixing yet!\n");
2409 		return;
2410 	}
2411 }
2412 
2413 
2414 /* VOP_TRUNCATE */
2415 /* doesn't lock udf_node */
udf_truncate_node(struct udf_node * udf_node,uint64_t length)2416 int udf_truncate_node(struct udf_node *udf_node, uint64_t length /* ,ioflags */) {
2417 	struct udf_log_vol    *udf_log_vol;
2418 	struct udf_allocentry *alloc_entry, *cut_point;
2419 	struct udf_buf        *buf_entry, *marker;
2420 	uint32_t lb_size;
2421 	uint64_t cur_extent, block_extent, new_extent, too_much;
2422 	uint32_t last_sector;
2423 	int32_t	 error;
2424 
2425 	if (!udf_node) return EINVAL;
2426 
2427 	if (udf_open_logvol(udf_node->udf_log_vol))
2428 		return EROFS;
2429 
2430 	udf_log_vol = udf_node->udf_log_vol;
2431 	lb_size     = udf_log_vol->lb_size;
2432 
2433 	/* we might change this node AND access times ... */
2434 	if (!udf_node->dirty) {
2435 		/* mark node as dirty */
2436 		udf_node_mark_dirty(udf_node);
2437 	}
2438 
2439 /* XXX lock node !!! XXX */
2440 
2441 	/* merge known allocation entry queue */
2442 	new_extent   = length;
2443 	block_extent = (uint64_t) lb_size * ((new_extent + lb_size-1) / lb_size);	/* inclusive */
2444 	too_much     = block_extent - new_extent;
2445 	assert(block_extent >= new_extent);
2446 
2447 	UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2448 	UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
2449 		udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size);
2450 
2451 		/* extend the file when nessisary */
2452 		if (new_extent > (uint64_t) udf_node->stat.st_size) {
2453 			if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) {
2454 				/* XXX to seperate function XXX */
2455 				/* grow intern node by converting it to a normal buffer first */
2456 				/* First lookup if the node already had a buffer associated */
2457 				udf_lookup_node_buf(udf_node, 0, &buf_entry);
2458 				if (!buf_entry) {
2459 					error = udf_get_buf_entry(udf_node, &buf_entry);
2460 					if (error) {
2461 						UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2462 						UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2463 						return error;
2464 					}
2465 					buf_entry->b_lblk   = 0;
2466 					buf_entry->b_flags  = 0;
2467 
2468 					UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2469 						udf_attach_buf_to_node(udf_node, buf_entry);
2470 					UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2471 				} else {
2472 					DEBUG(printf("found buffer associated with intern node!\n"));
2473 				}
2474 
2475 				buf_entry->b_bcount = MIN(lb_size, new_extent);
2476 				buf_entry->b_resid  = lb_size - buf_entry->b_bcount;
2477 
2478 				memcpy(buf_entry->b_data, udf_node->intern_data, udf_node->intern_len);
2479 				memset(buf_entry->b_data + udf_node->intern_len, 0, lb_size - udf_node->intern_len);
2480 
2481 				UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2482 					udf_mark_buf_dirty(udf_node, buf_entry);
2483 				UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2484 
2485 				udf_node->intern_len = 0;
2486 				if (udf_node->intern_data)
2487 					free(udf_node->intern_data);
2488 				udf_node->intern_data = NULL;
2489 				udf_node->icb_len   = sizeof(struct long_ad);
2490 				udf_node->addr_type = UDF_ICB_LONG_ALLOC;
2491 			}
2492 			udf_cut_allocentry_queue(&udf_node->alloc_entries, lb_size, block_extent);
2493 			if (new_extent < block_extent) {
2494 				alloc_entry = TAILQ_LAST(&udf_node->alloc_entries, udf_alloc_entries);
2495 				assert(alloc_entry->len > too_much);
2496 
2497 				alloc_entry->len -= too_much;
2498 			}
2499 			/* XXX Andrey suggested buffer extension? XXX */
2500 			udf_node->stat.st_size = new_extent;
2501 		}
2502 	UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2503 	UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2504 
2505 	/* `free' the extent when shrinking the extent */
2506 	if (new_extent < (uint64_t) udf_node->stat.st_size) {
2507 		DEBUG(printf("TRIMMING file %"PRIu64" from %d to %d\n", udf_node->unique_id, (int32_t) udf_node->stat.st_size, (uint32_t) length));
2508 
2509 		/* free file buffers that are not needed anymore */
2510 		/* XXX NetBSD kernel : uvm_vnp_setsize() XXX */
2511 		marker = calloc(1, sizeof(struct udf_buf));
2512 		if (!marker) return ENOMEM;
2513 
2514 		UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2515 		UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2516 			/* use marker as we are going to delete items in the list we are traversing */
2517 			last_sector = new_extent / lb_size;
2518 			TAILQ_INSERT_HEAD(&udf_node->vn_bufs, marker, b_vnbufs);
2519 			while ((buf_entry = TAILQ_NEXT(marker, b_vnbufs))) {
2520 				/* advance marker */
2521 				TAILQ_REMOVE(&udf_node->vn_bufs, marker, b_vnbufs);
2522 				TAILQ_INSERT_AFTER(&udf_node->vn_bufs, buf_entry, marker, b_vnbufs);
2523 
2524 				/* process buf_entry */
2525 				if (buf_entry->b_lblk > last_sector) {
2526 					udf_mark_buf_clean(udf_node, buf_entry);	/* its destroyed so not dirty */
2527 					udf_mark_buf_allocated(udf_node, buf_entry);	/* i.e. taken care of */
2528 					udf_detach_buf_from_node(udf_node, buf_entry);
2529 					udf_free_buf_entry(buf_entry);
2530 				}
2531 				/* trim last buffer entry */
2532 				/* XXX NetBSD kernel : uvm_vnp_zerorange(), vtruncbuf() XXX */
2533 				if (buf_entry->b_lblk == last_sector) {
2534 					buf_entry->b_bcount = udf_node->stat.st_size % lb_size;
2535 					buf_entry->b_resid  = buf_entry->b_bufsize - buf_entry->b_bcount;
2536 					/* still data to record? */
2537 					if (buf_entry->b_bcount == 0) {
2538 						/* marker not an issue here */
2539 						udf_mark_buf_clean(udf_node, buf_entry);	/* its destroyed so not dirty */
2540 						udf_mark_buf_allocated(udf_node, buf_entry);	/* i.e. taken care of */
2541 						udf_detach_buf_from_node(udf_node, buf_entry);
2542 						udf_free_buf_entry(buf_entry);
2543 					}
2544 				}
2545 			}
2546 			TAILQ_REMOVE(&udf_node->vn_bufs, marker, b_vnbufs);
2547 			free(marker);
2548 		UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2549 		UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2550 
2551 		UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
2552 			if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) {
2553 				/* shrink intern node */
2554 				too_much = udf_node->stat.st_size - new_extent;
2555 				udf_node->intern_len  -= too_much;
2556 				udf_node->intern_free += too_much;
2557 				memset(udf_node->intern_data + new_extent, 0, too_much);
2558 			} else {
2559 				/* shrink alloc entries _after_ deleting bufs to make sure we are not crossed */
2560 				error = udf_node_release_extent(udf_node, block_extent, udf_node->stat.st_size);
2561 
2562 				/* after `cleanup', trim now unused entries */
2563 				udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size);
2564 
2565 				if (new_extent == 0) {
2566 					/* remove all; most common case too */
2567 					while ((alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries))) {
2568 						TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc);
2569 						free(alloc_entry);
2570 					}
2571 					cur_extent = 0;
2572 				} else {
2573 					/* move code to udf_allocentries.c ? */
2574 					udf_cut_allocentry_queue(&udf_node->alloc_entries, lb_size, block_extent);
2575 
2576 					/* find cut-point */
2577 					cur_extent = 0;
2578 					TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) {
2579 						cur_extent += alloc_entry->len;
2580 						if (cur_extent == block_extent) break;
2581 					}
2582 					cut_point = alloc_entry;	/* all after this point need to be deleted */
2583 
2584 					assert(cut_point);
2585 					while ((alloc_entry = TAILQ_NEXT(cut_point, next_alloc))) {
2586 						TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc);
2587 						free(alloc_entry);
2588 					}
2589 
2590 					/* clip last entry to the correct size */
2591 					if (new_extent < block_extent) {
2592 						assert(too_much == block_extent - new_extent);
2593 
2594 						alloc_entry = TAILQ_LAST(&udf_node->alloc_entries, udf_alloc_entries);
2595 						assert(alloc_entry->len > too_much);
2596 
2597 						alloc_entry->len -= too_much;
2598 						cur_extent -= too_much;
2599 					}
2600 				}
2601 				assert(cur_extent == new_extent);
2602 			}
2603 			udf_node->stat.st_size = new_extent;
2604 		UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2605 	}
2606 
2607 	return 0;
2608 }
2609 
2610 
2611 /* VOP_WRITE */
udf_write_file_part_uio(struct udf_node * udf_node,char * what,int content,struct uio * data_uio)2612 int udf_write_file_part_uio(struct udf_node *udf_node, char *what, int content, struct uio *data_uio) {
2613 	struct udf_buf  *buf_entry;
2614 	off_t		 offset;
2615 	uint64_t	 new_possible_extent;
2616 	uint64_t	 start_extent, end_extent;
2617 	uint64_t	 lb_size, sector, data_length;
2618 	uint8_t		*base;
2619 	int		 error, appending, allocated;
2620 
2621 	if (!udf_node) return EINVAL;
2622 
2623 	if (udf_open_logvol(udf_node->udf_log_vol))
2624 		return EROFS;
2625 
2626 	/* write chanches both modification and file status times */
2627 	udf_set_timespec_now(&udf_node->stat.st_ctimespec);
2628 	udf_set_timespec_now(&udf_node->stat.st_mtimespec);
2629 
2630 	/* Zero length write -> finished */
2631 	if (data_uio->uio_resid == 0) return 0;
2632 
2633 	/* TODO lock node directly to avoid multiple writers entering */
2634 /*	pthread_rwlock_wrlock(&udf_node->udf_node_lock); */
2635 
2636 	if (!udf_node->dirty) {
2637 		udf_node_mark_dirty(udf_node);
2638 	}
2639 
2640 	/* auto-extent file */
2641 	appending = 0;
2642 	allocated = 0;
2643 	new_possible_extent = data_uio->uio_offset + data_uio->uio_resid;
2644 	if (new_possible_extent >= (uint64_t) udf_node->stat.st_size) {
2645 		/* BUGALERT: extra space can be pre-allocated AFTER file length */
2646 		error = udf_truncate_node(udf_node, new_possible_extent);
2647 		appending = 1;
2648 	}
2649 
2650 	lb_size = udf_node->udf_log_vol->lb_size;
2651 	while (data_uio->uio_resid) {
2652 		error = 0;
2653 		sector  = data_uio->uio_offset / lb_size;
2654 
2655 		/* lookup sector in buffer set */
2656 		UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock);
2657 			udf_lookup_node_buf(udf_node, sector, &buf_entry);
2658 
2659 			if (!buf_entry || (buf_entry && (buf_entry->b_lblk != sector))) {
2660 				/* not found in cache; `page in' sector from file BUT ONLY if we don't completely overwrite it anyway */
2661 				if ((data_uio->uio_resid < lb_size) && (!appending)) {
2662 					DEBUG(printf("Reading in file buffer for %s for %"PRIu64" bytes\n", what, (uint64_t) data_uio->uio_resid));
2663 					error = udf_readin_file_buffer(udf_node, what, sector, content, &buf_entry);
2664 				}
2665 
2666 				/* check if the extent is allocated; check assumption that the size of a buffer is a lb_size */
2667 				if (buf_entry)
2668 					assert(buf_entry->b_bufsize == lb_size);
2669 				UDF_MUTEX_LOCK(&udf_node->alloc_mutex);
2670 					start_extent = (uint64_t) lb_size * sector;
2671 					end_extent   = MIN((uint64_t) udf_node->stat.st_size, start_extent + lb_size);
2672 					error = udf_extent_properties(&udf_node->alloc_entries, lb_size, start_extent, end_extent, &allocated);
2673 				UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex);
2674 
2675 				/* check free space if space is to allocated */
2676 				if (!buf_entry || !allocated) {
2677 					/* be coulant on metadata here to avoid not to easy to solve resource problems */
2678 					if (content == UDF_C_USERDATA) {
2679 						/* check for space no space anymore for userdata (bit on the safe side really) */
2680 						assert(udf_node->udf_log_vol);
2681 						if (!udf_confirm_freespace(udf_node->udf_log_vol, content, lb_size)) {
2682 							UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2683 							return ENOSPC;
2684 						}
2685 					}
2686 				}
2687 				DEBUG(if (allocated) printf("Writing pre-allocated buffer\n"));
2688 
2689 				if (!buf_entry) {
2690 					/* create new buffer */
2691 					error = udf_get_buf_entry(udf_node, &buf_entry);
2692 					if (error) {
2693 						UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2694 						return error;
2695 					}
2696 
2697 					/* don't forget to set the relative block number! */
2698 					buf_entry->b_lblk   = sector;
2699 
2700 					/* add it to the buffer list */
2701 					UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2702 						udf_attach_buf_to_node(udf_node, buf_entry);
2703 					UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2704 
2705 				}
2706 				assert(buf_entry);
2707 
2708 				if (allocated) {
2709 					/*
2710 					 * we could free the old allocated extent and mark it needing allocation
2711 					 * again
2712 					 */
2713 				}
2714 				if (!allocated) {
2715 					/* mark it needs to be allocated, locks are not very nice here */
2716 					UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2717 						udf_mark_buf_needing_allocate(udf_node, buf_entry);
2718 					UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2719 				}
2720 			}
2721 			if (error) {
2722 				UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2723 				break; /* while */
2724 			}
2725 
2726 			assert(buf_entry);
2727 			offset = data_uio->uio_offset - (off_t) sector*lb_size;
2728 			base   = buf_entry->b_data;
2729 
2730 			assert(offset >= 0);
2731 			if (offset >= 0) {
2732 				UDF_MUTEX_LOCK(&udf_node->buf_mutex);
2733 					udf_mark_buf_dirty(udf_node, buf_entry);
2734 
2735 					data_length = buf_entry->b_bufsize - offset;
2736 					data_length = MIN(data_length, data_uio->uio_resid);
2737 
2738 					uiomove(base + offset, data_length, data_uio);
2739 
2740 					buf_entry->b_bcount = MAX(buf_entry->b_bcount, offset + data_length);
2741 					buf_entry->b_resid  = buf_entry->b_bufsize - buf_entry->b_bcount;
2742 				UDF_MUTEX_UNLOCK(&udf_node->buf_mutex);
2743 			}
2744 		UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock);
2745 
2746 		if (data_uio->uio_resid == 0) return 0;		/* finished? */
2747 	} /* while */
2748 
2749 	return 0;
2750 }
2751 
2752 
2753 /******************************************************************************************
2754  *
2755  * UDF volume and descriptor logic
2756  *
2757  ******************************************************************************************/
2758 
2759 
udf_search_volumeset(char * volset_id)2760 struct udf_volumeset *udf_search_volumeset(char *volset_id) {
2761 	struct udf_volumeset *volumeset;
2762 	struct udf_pri_vol   *primary;
2763 
2764 	/* XXX this is a bit ugly XXX */
2765 	SLIST_FOREACH(volumeset, &udf_volumeset_list, next_volumeset) {
2766 		primary = STAILQ_FIRST(&volumeset->primaries);
2767 		assert(primary->pri_vol);
2768 		if (memcmp(primary->pri_vol->volset_id, volset_id, 128) == 0) return volumeset;
2769 	}
2770 	return NULL;
2771 }
2772 
2773 
udf_search_primary(struct udf_volumeset * set,char * id)2774 struct udf_pri_vol *udf_search_primary(struct udf_volumeset *set, char *id) {
2775 	struct udf_pri_vol *primary;
2776 
2777 	STAILQ_FOREACH(primary, &set->primaries, next_primary) {
2778 		assert(primary->pri_vol);
2779 		if (memcmp(primary->pri_vol->vol_id, id, 32) == 0) return primary;
2780 	}
2781 	return NULL;
2782 }
2783 
2784 
udf_search_logical_volume_in_primary(struct udf_pri_vol * primary,char * logvol_id)2785 struct udf_log_vol *udf_search_logical_volume_in_primary(struct udf_pri_vol *primary, char *logvol_id) {
2786 	struct udf_log_vol *here;
2787 
2788 	SLIST_FOREACH(here, &primary->log_vols, next_logvol) {
2789 		if (memcmp(here->log_vol->logvol_id, logvol_id, 128) == 0) return here;
2790 	}
2791 	return NULL;
2792 }
2793 
2794 
2795 
2796 /* called not very often ... ; free incomming when not needed */
udf_proc_pri_vol(struct udf_session * udf_session,struct udf_pri_vol ** current,struct pri_vol_desc * incomming)2797 int udf_proc_pri_vol(struct udf_session *udf_session, struct udf_pri_vol **current, struct pri_vol_desc *incomming) {
2798 	struct udf_volumeset *volset;
2799 	struct udf_pri_vol   *primary;
2800 
2801 	assert(current);
2802 	volset = udf_search_volumeset(incomming->volset_id);
2803 	if (!volset) {
2804 		/* create a volume set */
2805 		volset = calloc(1, sizeof(struct udf_volumeset));
2806 		if (!volset) {
2807 			free(incomming);
2808 			return ENOMEM;
2809 		}
2810 
2811 		/* populate and link in */
2812 		volset->max_partnum = 0;
2813 		STAILQ_INIT(&volset->primaries);
2814 		SLIST_INSERT_HEAD(&udf_volumeset_list, volset, next_volumeset);
2815 	}
2816 	assert(volset);
2817 
2818 	primary = udf_search_primary(volset, incomming->vol_id);
2819 	*current = primary;
2820 
2821 	if (!primary) {
2822 		/* create a primary volume */
2823 		primary = calloc(1, sizeof(struct udf_pri_vol));
2824 		if (!primary) {
2825 			free(incomming);
2826 			return ENOMEM;
2827 		}
2828 
2829 		/* add to volset's primaries list */
2830 		STAILQ_INSERT_TAIL(&volset->primaries, primary, next_primary);
2831 
2832 		*current = primary;
2833 	} else {
2834 		/* mark as current */
2835 
2836 		/* ok ... we now need to check if this new descriptor is a newer version */
2837 		if (udf_rw32(incomming->seq_num) <= udf_rw32(primary->pri_vol->seq_num)) {
2838 			if (udf_session->session_num <= (*current)->udf_session->session_num) {
2839 				DEBUG(printf("UDF: DISCARDING primary descriptor for its the same but higher session number\n"));
2840 				/* its an older one; ignore */
2841 				free(incomming);
2842 				return 0;
2843 			}
2844 		}
2845 		DEBUG(printf("UPDATING primary descriptor for it has a higher session number\n"));
2846 	}
2847 
2848 	/* update the primary volume descriptor */
2849 	if (primary->pri_vol) free(primary->pri_vol);
2850 	primary->volumeset   = volset;
2851 	primary->pri_vol     = incomming;
2852 	primary->udf_session = udf_session;
2853 
2854 	return 0;
2855 }
2856 
2857 
2858 /* not called often ; free lvid when not used */
udf_proc_logvol_integrity(struct udf_log_vol * udf_log_vol,struct logvol_int_desc * new_lvid)2859 int udf_proc_logvol_integrity(struct udf_log_vol *udf_log_vol, struct logvol_int_desc *new_lvid) {
2860 	struct udf_logvol_info *impl;
2861 	uint64_t psize, pfree;
2862 	uint32_t *free_space_pos, *size_pos;
2863 	uint32_t lb_size, part_map;
2864 	uint32_t integrity;
2865 	int error, tagid;
2866 
2867 	error = udf_check_tag((union dscrptr *) new_lvid);
2868 	if (error) {
2869 		return error;	/* return error on faulty tag */
2870 	}
2871 
2872 	tagid = udf_rw16(new_lvid->tag.id);
2873 	/* getting a terminator tag or zero is an OK condition */
2874 	if ((tagid == TAGID_TERM) || (tagid == 0)) {
2875 		return 0;
2876 	}
2877 
2878 	/* not getting an logical volume itegrity volume descriptor is an error now */
2879 	if (tagid != TAGID_LOGVOL_INTEGRITY) {
2880 		printf("IEE! got a %d tag while searching for a logical volume integrity descriptor\n", tagid);
2881 		return EINVAL;	/* XXX error code? XXX */
2882 	}
2883 
2884 	/* check CRC on the contents of the logvol integrity */
2885 	error = udf_check_tag_payload((union dscrptr *) new_lvid);
2886 	if (error) {
2887 		return error;
2888 	}
2889 
2890 	/* check logvol integrity validity */
2891 	integrity = udf_rw32(new_lvid->integrity_type);
2892 	if ((integrity != UDF_INTEGRITY_OPEN) && (integrity != UDF_INTEGRITY_CLOSED))
2893 		return EINVAL;
2894 
2895 	/* allways go for the next in line; silly but thats Ecma-167/UDF */
2896 	/* process information contained in logical volume integrity descriptor */
2897 	udf_log_vol->logvol_state     = integrity;
2898 	udf_log_vol->integrity_serial = udf_rw16(new_lvid->tag.serial_num);
2899 	impl = (struct udf_logvol_info *) (new_lvid->tables + 2*udf_rw32(new_lvid->num_part));
2900 
2901 	udf_log_vol->min_udf_readver  = udf_rw16(impl->min_udf_readver);
2902 	udf_log_vol->min_udf_writever = udf_rw16(impl->min_udf_writever);
2903 	udf_log_vol->max_udf_writever = udf_rw16(impl->max_udf_writever);
2904 
2905 	udf_log_vol->num_files        = udf_rw32(impl->num_files);
2906 	udf_log_vol->num_directories  = udf_rw32(impl->num_directories);
2907 	udf_log_vol->next_unique_id   = udf_rw64(new_lvid->lvint_next_unique_id);
2908 
2909 	/* calculate free space from this integrity descritor */
2910 	lb_size = udf_log_vol->lb_size;
2911 
2912 	/* init start positions */
2913 	free_space_pos = &new_lvid->tables[0];
2914 	size_pos       = &new_lvid->tables[udf_log_vol->num_part_mappings];
2915 
2916 	/* init counters */
2917 	udf_log_vol->total_space = udf_log_vol->free_space = udf_log_vol->await_alloc_space = 0;
2918 	for (part_map = 0; part_map < udf_log_vol->num_part_mappings; part_map++) {
2919 		psize = udf_rw32(*size_pos); size_pos++;
2920 		pfree = udf_rw32(*free_space_pos); free_space_pos++;
2921 		if (pfree != UINT_MAX) {
2922 			/* if UINT_MAX, its not applicable like virtual space partitions */
2923 			udf_log_vol->total_space += (uint64_t) psize * lb_size;
2924 			udf_log_vol->free_space  += (uint64_t) pfree * lb_size;
2925 		}
2926 	}
2927 
2928 	UDF_VERBOSE(
2929 		if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) {
2930 			udf_dump_timestamp("\t\t\t\tmarked open   at ", &new_lvid->time);
2931 		} else {
2932 			udf_dump_timestamp("\t\t\t\tmarked closed at ", &new_lvid->time);
2933 		}
2934 	);
2935 	return 0;
2936 }
2937 
2938 
udf_derive_new_logvol_integrity(struct udf_log_vol * udf_log_vol)2939 void udf_derive_new_logvol_integrity(struct udf_log_vol *udf_log_vol) {
2940 	udf_log_vol->logvol_state     = UDF_INTEGRITY_OPEN;
2941 	udf_log_vol->integrity_serial = 1;
2942 
2943 	/* analyse the log vol to check out minimum and maximum read/write versions */
2944 	if (udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver) == 2) {
2945 		udf_log_vol->min_udf_readver  = 0x0102;
2946 		udf_log_vol->min_udf_writever = 0x0150;
2947 		udf_log_vol->max_udf_writever = 0x0150;
2948 	} else {
2949 		udf_log_vol->min_udf_readver  = 0x0201;
2950 		udf_log_vol->min_udf_writever = 0x0201;
2951 		udf_log_vol->max_udf_writever = 0x0201;		/* 2.50? */
2952 	}
2953 	udf_log_vol->num_files       = 0;
2954 	udf_log_vol->num_directories = 0;
2955 	udf_log_vol->next_unique_id  = 16;	/* zero first, rest 15/16+ minimum */
2956 }
2957 
2958 
udf_proc_logvol_integrity_sequence(struct udf_log_vol * udf_log_vol)2959 int udf_proc_logvol_integrity_sequence(struct udf_log_vol *udf_log_vol) {
2960 	union dscrptr	*dscr;
2961 	uint32_t	 sector, length, lvid_len, num_sectors;
2962 	uint32_t	 lb_size;
2963 	int		 error;
2964 
2965 	sector  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc);
2966 	length  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len);
2967 	lb_size = udf_log_vol->lb_size;
2968 
2969 	/* go for the default `open' integrity first as initialisation */
2970 	udf_derive_new_logvol_integrity(udf_log_vol);
2971 
2972 	if (!length) {
2973 		fprintf(stderr, "UDF: no volume integrity descriptor sequence space defined... OK for Ecma-167, not for UDF; rejecting\n");
2974 		return EBADF;
2975 	}
2976 
2977 	error = 0;
2978 	while (length) {
2979 		error = udf_read_session_descriptor(udf_log_vol->primary->udf_session, sector, "Logical volume integrity descriptor (LVID)", &dscr, &lvid_len);
2980 		if (error) {
2981 			if (dscr) free(dscr);
2982 			dscr = NULL;
2983 			break;
2984 		}
2985 
2986 		UDF_VERBOSE_MAX(udf_dump_descriptor(dscr));
2987 
2988 		error = udf_proc_logvol_integrity(udf_log_vol, &dscr->lvid);
2989 		if (error) break;
2990 		if (udf_rw16(dscr->tag.id) == TAGID_TERM) break;
2991 
2992 		num_sectors = (lvid_len + lb_size-1) / lb_size;
2993 		length -= num_sectors * lb_size;
2994 		sector += num_sectors;
2995 
2996 		if (udf_rw32(dscr->lvid.next_extent.len)) {
2997 			sector = udf_rw32(dscr->lvid.next_extent.loc);
2998 			length = udf_rw32(dscr->lvid.next_extent.len);
2999 		}
3000 		/* free consumed descriptor */
3001 		free(dscr);
3002 		dscr = NULL;
3003 	}
3004 	/* free dangling descriptor */
3005 	if (dscr) free(dscr);
3006 
3007 	/* either an error has occured or we have processed all descriptors */
3008 	if (error) {
3009 		fprintf(stderr, "WARNING: integrity sequence ended with a bad descriptor; creating new\n");
3010 		udf_derive_new_logvol_integrity(udf_log_vol);
3011 		return ENOENT;
3012 	}
3013 
3014 	/*
3015 	 * If its marked closed we hope/assume all is fine otherwise it may be
3016 	 * marked closed later on when we are using a VAT and its found and
3017 	 * correct
3018 	 */
3019 	return 0;
3020 }
3021 
3022 
3023 /* Add partition mapping to specified logvol descriptor */
udf_add_physical_to_logvol(struct logvol_desc * logvol,uint16_t vol_seq_num,uint16_t phys_part_num)3024 void udf_add_physical_to_logvol(struct logvol_desc *logvol, uint16_t vol_seq_num, uint16_t phys_part_num) {
3025 	union  udf_pmap *pmap;
3026 	uint8_t         *pmap_pos;
3027 
3028 	pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
3029 
3030 	pmap = (union udf_pmap *) pmap_pos;
3031 	pmap->pm1.type        = 1;
3032 	pmap->pm1.len         = sizeof(struct part_map_1);
3033 	pmap->pm1.vol_seq_num = udf_rw16(vol_seq_num);
3034 	pmap->pm1.part_num    = udf_rw16(phys_part_num);
3035 
3036 	/* increment partition mapping count */
3037 	logvol->n_pm = udf_rw32(udf_rw32(logvol->n_pm) + 1);
3038 	logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + sizeof(struct part_map_1));
3039 
3040 	logvol->tag.desc_crc_len = udf_rw16(udf_rw16(logvol->tag.desc_crc_len) + sizeof(struct part_map_1));
3041 }
3042 
3043 
3044 #if 0
3045 /* not yet */
3046 void udf_add_sparable_to_logvol(struct logvol_desc *logvol, uint16_t vol_seq_num, uint16_t phys_part_num, uint16_t packet_len, ) {
3047 	union  udf_pmap *pmap;
3048 	uint8_t         *pmap_pos;
3049 
3050 	pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
3051 
3052 	pmap = (union udf_pmap *) pmap_pos;
3053 	pmap->pm1.type        = 1;
3054 	pmap->pm1.len         = sizeof(struct part_map_1);
3055 	pmap->pm1.vol_seq_num = vol_seq_num;
3056 	pmap->pm1.part_num    = phys_part_num;
3057 
3058 	/* increment partition mapping count */
3059 	logvol->n_pm = udf_rw32(udf_rw32(logvol->n_pm) + 1);
3060 	logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + sizeof(struct part_map_1));
3061 
3062 	logvol->tag.desc_crc_len = udf_rw16(udf_rw16(logvol->tag.desc_crc_len) + sizeof(struct part_map_1));
3063 }
3064 #endif
3065 
3066 
3067 /* not called often; free incomming when not needed */
udf_proc_log_vol(struct udf_pri_vol * primary,struct udf_log_vol ** current,struct logvol_desc * incomming)3068 int udf_proc_log_vol(struct udf_pri_vol *primary, struct udf_log_vol **current, struct logvol_desc *incomming) {
3069 	struct udf_log_vol	 *logical;
3070 	struct udf_part_mapping	 *part_mapping, *data_part_mapping, *search_part_mapping;
3071 	union  udf_pmap		 *pmap;
3072 	uint32_t		  part_cnt, pmap_type, pmap_size;
3073 	uint32_t		  data_part_num;
3074 	uint8_t 		 *pmap_pos;
3075 
3076 	logical = udf_search_logical_volume_in_primary(primary, incomming->logvol_id);
3077 	if (!logical) {
3078 		/* create a logical volume */
3079 		logical = calloc(1, sizeof(struct udf_log_vol));
3080 		if (!logical) {
3081 			free(incomming);
3082 			return ENOMEM;
3083 		}
3084 
3085 		/* link in */
3086 		SLIST_INSERT_HEAD(&primary->log_vols, logical, next_logvol);
3087 	} else {
3088 		/* ok ... we now need to check if this new descriptor is a newer version */
3089 		if (udf_rw32(incomming->seq_num) < udf_rw32(logical->log_vol->seq_num)) {
3090 			/* its an older one; ignore */
3091 			free(incomming);
3092 			return 0;
3093 		}
3094 	}
3095 
3096 	/* update the logical volume descriptor and its mappings; first delete old partition mappings allocated before */
3097 	logical->primary  = primary;
3098 	if (current) *current = logical;
3099 
3100 	part_mapping = SLIST_FIRST(&logical->part_mappings);
3101 	while ((part_mapping = SLIST_FIRST(&logical->part_mappings))) {
3102 		/* TODO cleanup old cruft ? (XXX while mounted? i don't think so!) */
3103 		/*
3104 			free(part_mapping->sparing_table);
3105 			free(part_mapping->vat_file_entry);
3106 			free(part_mapping->vat);
3107 			free(part_mapping->meta_file);
3108 			free(part_mapping->meta_mirror_file);
3109 			free(part_mapping->meta_bitmap_file);
3110 		*/
3111 		SLIST_REMOVE_HEAD(&logical->part_mappings, next_mapping);
3112 		free(part_mapping);
3113 	}
3114 	SLIST_INIT(&logical->part_mappings);
3115 
3116 	/* use the new logical volume and preprocess it */
3117 	if (logical->log_vol) free(logical->log_vol);
3118 	logical->log_vol = incomming;
3119 	logical->lb_size     = udf_rw32(incomming->lb_size);
3120 	logical->sector_size = primary->udf_session->disc->sector_size;
3121 
3122 	/* build up the partion mappings */
3123 	logical->num_part_mappings = udf_rw32(incomming->n_pm);
3124 
3125 	/* process partition mappings */
3126 	pmap_pos = &logical->log_vol->maps[0];
3127 	for (part_cnt = 0; part_cnt < logical->num_part_mappings; part_cnt++) {
3128 		/* get a new part_mapping structure */
3129 		part_mapping = calloc(1, sizeof(struct udf_part_mapping));
3130 		assert(part_mapping);		/* XXX check with partition mapping destructor etc XXX */
3131 
3132 		/*
3133 		 * BUG alert: add to *tail* of list for dependencies sake.
3134 		 * Since this is the only place that its needed, I decided
3135 		 * against changing the SLIST to a TAILQ.
3136 		 */
3137 		if (SLIST_EMPTY(&logical->part_mappings))
3138 			SLIST_INSERT_HEAD(&logical->part_mappings, part_mapping, next_mapping);
3139 		else {
3140 			search_part_mapping = SLIST_FIRST(&logical->part_mappings);
3141 			while (SLIST_NEXT(search_part_mapping, next_mapping))
3142 				search_part_mapping = SLIST_NEXT(search_part_mapping, next_mapping);
3143 			SLIST_INSERT_AFTER(search_part_mapping, part_mapping, next_mapping);
3144 		}
3145 
3146 		/* process */
3147 		pmap = (union udf_pmap *) pmap_pos;
3148 		pmap_type = pmap->data[0];
3149 		pmap_size = pmap->data[1];
3150 
3151 		part_mapping->udf_virt_part_num = part_cnt;
3152 		part_mapping->udf_pmap = pmap;
3153 		switch (pmap_type) {
3154 			case 1:
3155 				part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_PHYSICAL;
3156 				part_mapping->vol_seq_num = udf_rw16(pmap->pm1.vol_seq_num);
3157 				part_mapping->udf_phys_part_num = udf_rw16(pmap->pm1.part_num);
3158 				break;
3159 			case 2:
3160 				part_mapping->vol_seq_num = udf_rw16(pmap->pm2.vol_seq_num);
3161 				part_mapping->udf_phys_part_num = udf_rw16(pmap->pm2.part_num);
3162 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Virtual Partition", UDF_REGID_ID_SIZE) == 0) {
3163 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_VIRTUAL;
3164 					break;
3165 				}
3166 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Sparable Partition", UDF_REGID_ID_SIZE) == 0) {
3167 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_SPARABLE;
3168 					break;
3169 				}
3170 				if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Metadata Partition", UDF_REGID_ID_SIZE) == 0) {
3171 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_META;
3172 					break;
3173 				}
3174 				printf("HELP ... found unsupported type 2 partition mapping id `%s`; marking broken\n", pmap->pm2.part_id.id);
3175 			default:
3176 				part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR;
3177 		}
3178 
3179 		pmap_pos += pmap_size;		/* variable length array :( */
3180 	}
3181 
3182 	/* flag all partion mappings data and metadata writable */
3183 	SLIST_FOREACH(part_mapping, &logical->part_mappings, next_mapping) {
3184 		part_mapping->data_writable     = 1;
3185 		part_mapping->metadata_writable = 1;
3186 	}
3187 
3188 	/* update writable flags depending on mapping type */
3189 	SLIST_FOREACH(part_mapping, &logical->part_mappings, next_mapping) {
3190 		switch (part_mapping->udf_part_mapping_type) {
3191 			case UDF_PART_MAPPING_ERROR :
3192 				part_mapping->data_writable     = 0;
3193 				part_mapping->metadata_writable = 0;
3194 				break;
3195 			case UDF_PART_MAPPING_PHYSICAL :
3196 				break;
3197 			case UDF_PART_MAPPING_VIRTUAL :
3198 			case UDF_PART_MAPPING_META :
3199 				/*
3200 				 * These are special in that there is a special metadata partition where no data
3201 				 * is meant to be written on and vice versa
3202 				 */
3203 
3204 				/* find the associated data partition */
3205 				data_part_num     = part_mapping->udf_phys_part_num;
3206 				SLIST_FOREACH(data_part_mapping, &logical->part_mappings, next_mapping) {
3207 					if (data_part_mapping->udf_phys_part_num == data_part_num) {
3208 						if (data_part_mapping != part_mapping) {
3209 							data_part_mapping->metadata_writable = 0;
3210 							break;
3211 						}
3212 					}
3213 				}
3214 				part_mapping->data_writable = 0;
3215 				break;
3216 			case UDF_PART_MAPPING_SPARABLE :
3217 				break;
3218 		}
3219 	}
3220 
3221 	TAILQ_INIT(&logical->dirty_nodes);
3222 	UDF_MUTEX_INIT(&logical->dirty_nodes_mutex);
3223 
3224 	return 0;
3225 }
3226 
3227 
3228 /* not called often; free incomming when not needed */
udf_proc_part(struct udf_pri_vol * primary,struct udf_partition ** current,struct part_desc * incomming)3229 int udf_proc_part(struct udf_pri_vol *primary, struct udf_partition **current, struct part_desc *incomming) {
3230 	struct udf_partition *udf_partition;
3231 	struct udf_volumeset *udf_volset;
3232 	uint32_t new_part_num, sector_size;
3233 
3234 	assert(primary);
3235 	assert(primary->pri_vol);
3236 
3237 	udf_volset = udf_search_volumeset(primary->pri_vol->volset_id);
3238 	assert(udf_volset);
3239 
3240 	new_part_num = udf_rw16(incomming->part_num);
3241 	/* check if its a partition type we recognize */
3242 	if (strncmp((char *) incomming->contents.id, "+NSR0", 5) != 0) {
3243 		fprintf(stderr, "Unrecognized partition content type %s encountered; ignoring\n", incomming->contents.id);
3244 		free(incomming);
3245 		return 0;
3246 	}
3247 
3248 	/* look if we allready got it */
3249 
3250 	SLIST_FOREACH(udf_partition, &udf_volset->parts, next_partition) {
3251 		if (udf_rw16(udf_partition->partition->part_num) == new_part_num) break;
3252 	}
3253 
3254 	/* we have space... now check if this is a newer one than the one known */
3255 	if (udf_partition) {
3256 		if (udf_rw32(incomming->seq_num) < udf_rw32(udf_partition->partition->seq_num)) {
3257 			/* its an older version */
3258 			free(incomming);
3259 			return 0;
3260 		}
3261 	} else {
3262 		/* get us a new udf_partition */
3263 		udf_partition = calloc(1, sizeof(struct udf_partition));
3264 		if (!udf_partition) {
3265 			free(incomming);
3266 			return ENOMEM;
3267 		}
3268 
3269 		/* link it in */
3270 		SLIST_INSERT_HEAD(&udf_volset->parts, udf_partition, next_partition);
3271 	}
3272 	assert(udf_partition);
3273 
3274 	/* copy this new partition descriptor in the list */
3275 	if (udf_partition->partition) free(udf_partition->partition);
3276 	udf_partition->partition   = incomming;
3277 	udf_partition->udf_session = primary->udf_session;
3278 	udf_volset->max_partnum = MAX(udf_volset->max_partnum, new_part_num+1);	/* REVIEW why +1? */
3279 
3280 	/* initialise */
3281 	sector_size = primary->udf_session->disc->sector_size;
3282 	UDF_MUTEX_INIT(&udf_partition->partition_space_mutex);
3283 	TAILQ_INIT(&udf_partition->unalloc_space_queue);
3284 	TAILQ_INIT(&udf_partition->freed_space_queue);
3285 	udf_partition->part_offset = udf_rw32(incomming->start_loc) * sector_size;
3286 	udf_partition->part_length = udf_rw32(incomming->part_len)  * sector_size;
3287 /*	udf_partition->access_type = udf_rw32(incomming->access_type); */
3288 
3289 	udf_partition->free_unalloc_space = udf_partition->free_freed_space = 0;
3290 
3291 	if (current) *current = udf_partition;
3292 
3293 	return 0;
3294 }
3295 
3296 
3297 /* not called often; free incomming when not needed */
udf_proc_filesetdesc(struct udf_log_vol * udf_log_vol,struct fileset_desc * incomming)3298 int udf_proc_filesetdesc(struct udf_log_vol *udf_log_vol, struct fileset_desc *incomming) {
3299 	struct udf_mountpoint *mp;
3300 
3301 	if (udf_rw16(incomming->tag.id) != TAGID_FSD) {
3302 		printf("IEEE! Encountered a non TAGID_FSD in this fileset descriptor sequence!!!\n");
3303 		free(incomming);
3304 		return EFAULT;
3305 	}
3306 
3307 	/* lookup fileset descriptor in this logical volume; interestingly fileset_num is KEY! */
3308 	SLIST_FOREACH(mp, &udf_log_vol->mountpoints, logvol_next) {
3309 		if (mp->fileset_desc->fileset_num == incomming->fileset_num) break;
3310 	}
3311 
3312 	if (!mp) {
3313 		/* add a new mountpoint! */
3314 		mp = calloc(1, sizeof(struct udf_mountpoint));
3315 		if (!mp) {
3316 			free(incomming);
3317 			return ENOMEM;
3318 		}
3319 		mp->fileset_desc = incomming;
3320 
3321 		/* insert into udf_log_vol and into mountables list */
3322 		SLIST_INSERT_HEAD(&udf_log_vol->mountpoints, mp, logvol_next);
3323 		SLIST_INSERT_HEAD(&udf_mountables, mp, all_next);
3324 	} else {
3325 		/* should we update mountpoint? */
3326 		if (udf_rw32(incomming->fileset_desc_num) <= udf_rw32(mp->fileset_desc->fileset_desc_num)) {
3327 			/* we allready got a newer one */
3328 			free(incomming);
3329 			return 0;
3330 		}
3331 
3332 		fprintf(stderr, "UDF DEBUG: would be updating mountpoint... HELP!\n");
3333 		/* FIXME delete all inode hash entries */
3334 		/* XXX how to do that? inodes OK but associated vnodes? XXX */
3335 #if 0
3336 		if (!SLIST_EMPTY(&mp->inodes)) {
3337 			printf("UDF: asked to delete mountpoint with inodes in hashtable!\n");
3338 			printf("Can't cope with that... aborting\n");
3339 			exit(1);
3340 		}
3341 #endif
3342 
3343 		/* free old information (allready in lists though!) */
3344 		free(mp->fileset_desc);
3345 		free(mp->mount_name);
3346 	}
3347 
3348 	mp->udf_log_vol  = udf_log_vol;
3349 	mp->fileset_desc = incomming;
3350 	mp->mount_name   = strdup(udf_get_compound_name(mp));
3351 
3352 	return 0;
3353 }
3354 
3355 
udf_retrieve_volume_space(struct udf_discinfo * disc,struct udf_session * udf_session,struct extent_ad * extent)3356 int udf_retrieve_volume_space(struct udf_discinfo *disc, struct udf_session *udf_session, struct extent_ad *extent) {
3357 	struct udf_pri_vol *udf_pri_vol;
3358 	struct udf_log_vol *udf_log_vol;
3359 	union dscrptr	*dscr;
3360 	uint32_t	 sector, length, dscr_len, num_sectors;
3361 	uint32_t	 sector_size;
3362 	int		 tag_id;
3363 	int		 error;
3364 
3365 	udf_pri_vol = NULL;
3366 
3367 	sector = udf_rw32(extent->loc);
3368 	length = udf_rw32(extent->len);
3369 	sector_size = disc->sector_size;
3370 
3371 	error = 0;	/* XXX zero length area's possible? XXX */
3372 	while (length) {
3373 		error = udf_read_session_descriptor(udf_session, sector, "volume descriptor", &dscr, &dscr_len);
3374 		if (error) {
3375 			if (dscr) free(dscr);
3376 			break;
3377 		}
3378 
3379 		tag_id = udf_rw16(dscr->tag.id);
3380 		num_sectors = (dscr_len + sector_size-1) / sector_size;
3381 
3382 		/* proc volume descriptor starting at sector `volume_sector' */
3383 		UDF_VERBOSE_MAX(udf_dump_descriptor(dscr));
3384 		switch (tag_id) {
3385 			case TAGID_PRI_VOL       :
3386 				error = udf_proc_pri_vol(udf_session, &udf_pri_vol, &dscr->pvd);
3387 				break;
3388 			case TAGID_PARTITION     :
3389 				error = udf_proc_part(udf_pri_vol, NULL, &dscr->pd);
3390 				break;
3391 			case TAGID_LOGVOL        :
3392 				error = udf_proc_log_vol(udf_pri_vol, &udf_log_vol, &dscr->lvd);
3393 				if (!error) {
3394 					/* first create empty integrity descriptor then modify it on input (for sanity) */
3395 					udf_derive_new_logvol_integrity(udf_log_vol);
3396 				}
3397 				break;
3398 			case TAGID_TERM          :
3399 				free(dscr);
3400 				return 0;	/* terminator */
3401 			case TAGID_UNALLOC_SPACE :
3402 				/* unallocated space descriptor */
3403 				/* Specifies space that is not claimed yet in partitions (!) */
3404 				UDF_VERBOSE(printf("\t\t`unallocated space descriptor' ignored\n"));
3405 				break;
3406 			case TAGID_IMP_VOL       :
3407 				/* implemenation use volume descriptor */
3408 				/* Specifies information relevant for the implementator */
3409 				UDF_VERBOSE_MAX(printf("\t\t`implementation use volume descriptor' ignored\n"));
3410 				break;
3411 			case TAGID_VOL           :
3412 				fprintf(stderr, "UDF : untested volume space extender encountered\n");
3413 				break;
3414 			default :
3415 				printf("XXX Unhandled volume sequence %d; freeing\n", tag_id);
3416 				free(dscr);
3417 				break;
3418 		}
3419 
3420 		length -= num_sectors * sector_size;
3421 		sector += num_sectors;
3422 
3423 		if (tag_id == TAGID_VOL) {
3424 			sector = udf_rw32(dscr->vdp.next_vds_ex.loc);
3425 			length = udf_rw32(dscr->vdp.next_vds_ex.len);
3426 			free(dscr);
3427 		}
3428 	}
3429 
3430 	return error;
3431 }
3432 
3433 
udf_get_filelength(union dscrptr * dscr,uint64_t * length)3434 int udf_get_filelength(union dscrptr *dscr, uint64_t *length) {
3435 	int32_t	fe_tag;
3436 
3437 	fe_tag = udf_rw16(dscr->tag.id);
3438 	if (fe_tag == TAGID_FENTRY) {
3439 		*length = udf_rw64(dscr->fe.inf_len);
3440 		return 0;
3441 	} else if (fe_tag == TAGID_EXTFENTRY) {
3442 		*length = udf_rw64(dscr->efe.inf_len);
3443 		return 0;
3444 	}
3445 	return ENOENT;
3446 }
3447 
3448 
3449 /* can be passed either a file_entry or an extfil_entry trough fentry! */
udf_check_for_vat(struct udf_log_vol * udf_log_vol,struct udf_part_mapping * part_mapping,uint32_t vat_lb,union dscrptr * dscr)3450 int udf_check_for_vat(struct udf_log_vol *udf_log_vol, struct udf_part_mapping *part_mapping, uint32_t vat_lb, union dscrptr *dscr) {
3451 	struct udf_part_mapping *s_part_mapping;
3452 	struct udf_node		*vat_udf_node;
3453 	struct long_ad		 udf_icbptr;
3454 	struct regid 		*regid;
3455 	struct uio		 vat_uio;
3456 	struct iovec		 vat_iovec;
3457 	struct icb_tag		*icbtag;
3458 	struct timestamp	*mtime;
3459 	uint64_t		 vat_length, vat_entries;
3460 	uint32_t		*vat_pos, vpart_num;
3461 	uint8_t			*vat;
3462 	int			 error, found;
3463 
3464 	/* prepare a `uio' structure for reading in complete VAT file */
3465 	error = udf_get_filelength(dscr, &vat_length);
3466 	if (error) return error;
3467 
3468 	if (vat_length == 0)
3469 		return EFAULT;
3470 
3471 	vat = malloc(vat_length);
3472 	if (!vat)
3473 		return ENOMEM;
3474 
3475 	/* move to uio_newuio(struct uio *uio) with fixed length uio_iovcnt? */
3476 	bzero(&vat_uio, sizeof(struct uio));
3477 	vat_uio.uio_rw     = UIO_WRITE;	/* WRITE into this space */
3478 	vat_uio.uio_iovcnt = 1;
3479 	vat_uio.uio_iov    = &vat_iovec;
3480 	vat_uio.uio_offset = 0;		/* begin at the start */
3481 	vat_uio.uio_resid  = vat_length;
3482 	/* fill in IO vector */
3483 	vat_uio.uio_iov->iov_base = vat;
3484 	vat_uio.uio_iov->iov_len  = vat_length;
3485 
3486 	/* find our virtual partition number corresponding to our physical partition number; this sucks */
3487 	found = 0;
3488 	vpart_num = 0;
3489 	SLIST_FOREACH(s_part_mapping, &udf_log_vol->part_mappings, next_mapping) {
3490 		if (s_part_mapping->udf_phys_part_num == part_mapping->udf_phys_part_num) {
3491 			if (s_part_mapping->udf_part_mapping_type == UDF_PART_MAPPING_PHYSICAL) {
3492 				/* found it ! */
3493 				found = 1;
3494 				vpart_num = s_part_mapping->udf_virt_part_num;
3495 			}
3496 		}
3497 	}
3498 	if (!found) {
3499 		printf("Can't find accompanied physical volume\n");
3500 		return ENOENT;
3501 	}
3502 
3503 	/* prepare udf_icbptr file node for easy file reading */
3504 	udf_icbptr.loc.part_num	= vpart_num;
3505 	udf_icbptr.loc.lb_num	= udf_rw32(vat_lb);
3506 	udf_icbptr.len		= udf_log_vol->lb_size;	/* not used, but may not be zero */
3507 
3508 	/*
3509 	 * this udf_node creation and disposing may look a bit inefficient but
3510 	 * its beneficiary for normal file access.  its only used once for
3511 	 * reading in the VAT.
3512 	 */
3513 
3514 	/* create the udf_vat_node; anonymous since it can't be in a mountpoint */
3515 	error = udf_readin_anon_udf_node(udf_log_vol, dscr, &udf_icbptr, "VAT", &vat_udf_node);
3516 	if (!error) {
3517 		DEBUG(printf("READ FILE PART UIO for VAT\n"));
3518 		error = udf_read_file_part_uio(vat_udf_node, "VAT contents", 0, &vat_uio);
3519 		DEBUG(printf("vat_uio rest %d\n", (uint32_t) vat_uio.uio_resid));
3520 	}
3521 
3522 	/* XXX allow for SHORT VAT's ? XXX */
3523 	if (!error) {
3524 		if (vat_uio.uio_resid) {
3525 			fprintf(stderr, "Warning: VAT file can't be read in completely\n");
3526 		}
3527 
3528 		part_mapping->vat_udf_node = vat_udf_node;
3529 		part_mapping->vat          = (struct udf_vat *) vat;
3530 		part_mapping->vat_length   = vat_length;
3531 
3532 		/* extract next unique file ID from the VAT file entry's unique ID incremented by one */
3533 		udf_log_vol->next_unique_id = vat_udf_node->unique_id;	/* ok? */
3534 		udf_increment_unique_id(udf_log_vol);
3535 
3536 		/* fentry is confirmed to be either an file_entry or an extfile_entry here */
3537 		if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3538 			icbtag = &dscr->fe.icbtag;
3539 			mtime  = &dscr->fe.mtime;
3540 
3541 		} else {
3542 			icbtag = &dscr->efe.icbtag;
3543 			mtime  = &dscr->efe.mtime;
3544 		}
3545 
3546 		if (icbtag->file_type == UDF_ICB_FILETYPE_VAT) {
3547 			/* we are in UDF 2.00+ userland */
3548 			part_mapping->vat_translation = ((uint8_t *) part_mapping->vat) + udf_rw16(part_mapping->vat->header_len);
3549 			part_mapping->vat_entries     = (vat_length - udf_rw16(part_mapping->vat->header_len))/4;
3550 			udf_log_vol->num_files        = udf_rw32(part_mapping->vat->num_files);
3551 			udf_log_vol->num_directories  = udf_rw32(part_mapping->vat->num_directories);
3552 			udf_log_vol->min_udf_readver  = udf_rw16(part_mapping->vat->min_udf_readver);
3553 			udf_log_vol->min_udf_writever = udf_rw16(part_mapping->vat->min_udf_writever);
3554 			udf_log_vol->max_udf_writever = udf_rw16(part_mapping->vat->max_udf_writever);
3555 
3556 			/* TODO update logvol name */
3557 		} else {
3558 			/* still in the old UDF 1.50 userland; update? its notoriously broken */
3559 			/* check the old UDF 1.50 VAT */
3560 			DEBUG(printf("CHECK UDF 1.50 VAT\n"));
3561 			vat_pos     = (uint32_t *) vat;
3562 			vat_entries = (vat_length-36)/4;	/* definition */
3563 
3564 			regid = (struct regid *) (vat_pos + vat_entries);
3565 			error = (strncmp((char *) regid->id, "*UDF Virtual Alloc Tbl", 22) == 0) ? 0 : ENOENT;
3566 			if (!error) {
3567 				part_mapping->vat_entries = vat_entries;
3568 				part_mapping->vat_translation = vat;
3569 				part_mapping->vat = NULL;
3570 
3571 				/* num files/dirs? */
3572 			}
3573 		}
3574 		if (!error) {
3575 			UDF_VERBOSE(udf_dump_timestamp("\t\t\t\tmarked closed at ", mtime));
3576 		}
3577 	}
3578 
3579 	/* clean up uio structure */
3580 	if (error) {
3581 		if (vat) free(vat);
3582 		if (vat_udf_node) udf_dispose_udf_node(vat_udf_node);
3583 		part_mapping->vat_udf_node = NULL;
3584 	}
3585 
3586 	return error;
3587 }
3588 
3589 
udf_retrieve_supporting_tables(struct udf_log_vol * udf_log_vol)3590 int udf_retrieve_supporting_tables(struct udf_log_vol *udf_log_vol) {
3591 	struct udf_partition	 *udf_partition;
3592 	struct udf_part_mapping	 *part_mapping, *s_part_mapping;
3593 	struct udf_session	 *udf_session;
3594 	struct long_ad		  udf_icbptr;
3595 	union  dscrptr		 *possible_vat_fe;
3596 	union  dscrptr		 *sparing_table_dscr;
3597 	uint32_t		  spar_loc;
3598 	uint64_t		  first_vat_loc, vat_loc, last_vat_loc;
3599 	uint32_t		  sector_size, lb_size;
3600 	uint32_t		  part_num, spar_num, data_part_num, vpart_num;
3601 	int			  session_num;
3602 	int			  error;
3603 
3604 	/*
3605 	 * if there are any virtual or sparable partition in this logical
3606 	 * volume, try to find their supporting tables so we can find the rest
3607 	 */
3608 	lb_size     = udf_log_vol->lb_size;
3609 	sector_size = udf_log_vol->sector_size;
3610 	SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) {
3611 		part_num = part_mapping->udf_virt_part_num;
3612 		udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition);
3613 
3614 		UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", part_num, part_mapping->udf_phys_part_num));
3615 		switch (part_mapping->udf_part_mapping_type) {
3616 			case UDF_PART_MAPPING_ERROR    :
3617 				/* nothing to be done for these */
3618 				break;
3619 			case UDF_PART_MAPPING_PHYSICAL :
3620 				/* nothing to be done for these; no supporting tables */
3621 				break;
3622 			case UDF_PART_MAPPING_VIRTUAL  :
3623 				/*
3624 				 * we have to find a good VAT at the END of the session. Since VAT's are
3625 				 * only to be used on WORM's and need to written as last, the strategy is
3626 				 * to go for the predicted end of this session and walk UP
3627 				 */
3628 				udf_session = udf_log_vol->primary->udf_session;
3629 				session_num = udf_session->session_num;
3630 
3631 				UDF_VERBOSE_TABLES(printf("\t\tSearching for the VAT :\n"));
3632 				if (udf_session->session_length == 0) {
3633 					UDF_VERBOSE(
3634 						printf("\t\tThis virtual partition is inaccessible since its its size is not known;\n");
3635 						printf("\t\tTry to insert the disc in a CD or DVD recordable device to access it.\n");
3636 					);
3637 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR;
3638 					continue;
3639 				}
3640 
3641 				if (udf_session->disc->next_writable[session_num]) {
3642 					last_vat_loc = udf_session->disc->next_writable[session_num];
3643 				} else {
3644 					last_vat_loc = udf_session->disc->session_end[session_num];
3645 				}
3646 				last_vat_loc += udf_session->disc->blockingnr;
3647 
3648 				 /* give some extra slack since sizes are not allways given up correctly */
3649 				first_vat_loc = last_vat_loc - 256; /* 8 blocks of 32 */
3650 				first_vat_loc = MAX(first_vat_loc, (uint64_t) udf_session->disc->session_start[session_num]);
3651 
3652 				/* try to find the fileid for the VAT; NOTE that we are reading backwards :( */
3653 				vat_loc = last_vat_loc;
3654 				do {
3655 					DEBUG(
3656 						printf("Trying VAT at sector %d in session\n", (int) vat_loc)
3657 					);
3658 					error = udf_read_session_descriptor(udf_session, vat_loc, "VAT file entry", &possible_vat_fe, NULL);
3659 					if (!error) {
3660 						error = udf_check_tag_presence(possible_vat_fe, TAGID_FENTRY);
3661 						if (error)
3662 							error = udf_check_tag_presence(possible_vat_fe, TAGID_EXTFENTRY);
3663 					}
3664 					if (!error) error = udf_check_tag_payload( possible_vat_fe);
3665 					if (!error) error = udf_check_for_vat(udf_log_vol, part_mapping, vat_loc, possible_vat_fe);
3666 					if (!error) {
3667 						break;
3668 					} else {
3669 						if (possible_vat_fe) free(possible_vat_fe);
3670 						vat_loc--;
3671 						if (vat_loc < first_vat_loc) error = EIO;
3672 					}
3673 				} while (error != EIO);
3674 
3675 				if (error) {
3676 					printf("WARNING: was looking for a VAT but didnt find it; marking logical volume broken\n");
3677 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR;
3678 					udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN;
3679 					udf_log_vol->broken = 1;
3680 					continue;
3681 				}
3682 				UDF_VERBOSE_TABLES(printf("\t\t\tfound VAT file-entry at device logical sector %d\n", (uint32_t) vat_loc));
3683 				UDF_VERBOSE_TABLES(printf("\t\t\tFound %d byte VAT descriptor+table\n", (uint32_t) part_mapping->vat_length));
3684 
3685 				UDF_VERBOSE_TABLES(udf_dump_descriptor(possible_vat_fe));
3686 				UDF_VERBOSE_MAX(udf_dump_vat_table(part_mapping));
3687 
3688 				if (part_mapping->vat_translation) {
3689 					/* the presence of a correct VAT means the logical volume is in a closed state */
3690 					udf_log_vol->logvol_state = UDF_INTEGRITY_CLOSED;
3691 					UDF_VERBOSE(printf("\t\t\t\tmarked closed due to presence of VAT\n"));
3692 
3693 					/* XXX update `free' space by requesting the device's free space? XXX */
3694 					udf_log_vol->free_space = udf_partition->part_offset + udf_partition->part_length - vat_loc*sector_size;
3695 				}
3696 
3697 				if (!udf_session->disc->sequential) {
3698 					UDF_VERBOSE(printf("\t\t\t\tenabling sequential media emulation\n"));
3699 					udf_session->disc->sequential = 1;
3700 				}
3701 				break;
3702 			case UDF_PART_MAPPING_SPARABLE :
3703 				/* we have to find a good sparing table; address are in device logical blocks */
3704 				udf_session = udf_log_vol->primary->udf_session;
3705 
3706 				for(spar_num = 0; spar_num < part_mapping->udf_pmap->pms.n_st; spar_num++) {
3707 					spar_loc = udf_rw32(part_mapping->udf_pmap->pms.st_loc[spar_num]);
3708 
3709 					/* fetch spar_loc's table ; on THIS session. */
3710 					error = udf_read_session_descriptor(udf_session, spar_loc, "Sparing table", &sparing_table_dscr, NULL);
3711 					if (!error) error = udf_check_tag_presence(sparing_table_dscr, TAGID_SPARING_TABLE);
3712 					if (!error) {
3713 						UDF_VERBOSE_TABLES(printf("\t\tFound the sparing table\n"));
3714 						part_mapping->sparing_table = &sparing_table_dscr->spt;
3715 						break;
3716 					} else {
3717 						if (sparing_table_dscr) free(sparing_table_dscr);
3718 					}
3719 				}
3720 				if (!part_mapping->sparing_table) {
3721 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR;
3722 				}
3723 				UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->sparing_table));
3724 				break;
3725 			case UDF_PART_MAPPING_META :
3726 				/*
3727 				 * set up common locator parts; the files are located inside the `part_num' partion where
3728 				 * this partition is a added layer on.
3729 				 */
3730 
3731 				/* find the associated data partition */
3732 				data_part_num     = udf_rw16(part_mapping->udf_pmap->pmm.part_num);
3733 
3734 				/* find our virtual partition number corresponding to our physical partition number; this sucks */
3735 				vpart_num = data_part_num;
3736 				SLIST_FOREACH(s_part_mapping, &udf_log_vol->part_mappings, next_mapping) {
3737 					if (s_part_mapping->udf_phys_part_num == data_part_num) {
3738 						if (s_part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_META) {
3739 							/* found it ! */
3740 							vpart_num = s_part_mapping->udf_virt_part_num;
3741 							break;
3742 						}
3743 					}
3744 				}
3745 				udf_icbptr.loc.part_num = vpart_num;
3746 				udf_icbptr.len          = lb_size;		/* defined as maximum size */
3747 
3748 				UDF_VERBOSE_TABLES(printf("Reading metadata partition filedescriptor\n"));
3749 				udf_icbptr.loc.lb_num   = udf_rw32(part_mapping->udf_pmap->pmm.meta_file_lbn);
3750 				error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition file descriptor", &part_mapping->meta_file);
3751 				if (error == 0)
3752 					UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_file));
3753 
3754 				udf_icbptr.loc.lb_num   = udf_rw32(part_mapping->udf_pmap->pmm.meta_mirror_file_lbn);
3755 				if ((error == 0) && (udf_icbptr.loc.lb_num != (uint32_t) -1)) {
3756 					UDF_VERBOSE_TABLES(printf("Reading metadata partition mirror filedescriptor\n"));
3757 					error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition mirror file descriptor", &part_mapping->meta_mirror_file);
3758 					if (error == 0)
3759 						UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_mirror_file));
3760 error = 0; /* XXX ignoring error code for now */
3761 				}
3762 
3763 				udf_icbptr.loc.lb_num   = udf_rw32(part_mapping->udf_pmap->pmm.meta_bitmap_file_lbn);
3764 				if ((error == 0) && (udf_icbptr.loc.lb_num != (uint32_t) -1)) {
3765 					UDF_VERBOSE_TABLES(printf("Reading metadata partition bitmap filedescriptor\n"));
3766 					error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition bitmap file descriptor", &part_mapping->meta_bitmap_file);
3767 					if (error == 0)
3768 						UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_bitmap_file));
3769 				}
3770 
3771 				/* if something is wrong, then mark it as a broken partition */
3772 				if (error) {
3773 					/* TODO handle read-errors on the meta data and meta data mirror file descriptors. */
3774 					part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR;
3775 				}
3776 				break;
3777 		}
3778 	}
3779 	UDF_VERBOSE_TABLES(printf("\n"));
3780 	if (udf_log_vol->broken) return EIO;
3781 
3782 	return 0;
3783 }
3784 
3785 
udf_retrieve_space_tables(struct udf_log_vol * udf_log_vol)3786 int udf_retrieve_space_tables(struct udf_log_vol *udf_log_vol) {
3787 	struct udf_partition	 *udf_partition;
3788 	struct udf_part_mapping  *part_mapping;
3789 	struct part_hdr_desc	 *part_hdr_desc;
3790 	union  dscrptr		 *dscrptr;
3791 	uint32_t		  sector;
3792 	uint32_t		  lb_size;
3793 	uint64_t		  length;
3794 	int			  vpart_num, ppart_num;
3795 	int			  error;
3796 
3797 	lb_size = udf_log_vol->lb_size;
3798 	SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) {
3799 		vpart_num = part_mapping->udf_virt_part_num;
3800 		ppart_num = part_mapping->udf_phys_part_num;
3801 		UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", vpart_num, ppart_num));
3802 
3803 		if ((part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_PHYSICAL) &&
3804 		    (part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_SPARABLE)) {
3805 			UDF_VERBOSE_TABLES(printf("\t\tDon't know how to load space tables for type %d\n", part_mapping->udf_part_mapping_type));
3806 			continue;
3807 		}
3808 
3809 		/* retrieve and process unallocated- and freed-space information for all used partitions of the logvol */
3810 		error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, NULL, &udf_partition);
3811 		assert(udf_partition);
3812 		part_hdr_desc = &udf_partition->partition->pd_part_hdr;
3813 
3814 		sector   = udf_rw32(part_hdr_desc->unalloc_space_table.lb_num);
3815 		length   = udf_rw32(part_hdr_desc->unalloc_space_table.len);		/* needed? */
3816 		if (length) {
3817 			error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Unallocated space table", &dscrptr, NULL);
3818 			UDF_VERBOSE_MAX(printf("\tUnalloced space table\n"));
3819 			UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
3820 			/* udf_process_space_table(&udf_partition->unalloc_space, dscrptr); */
3821 			free(dscrptr);
3822 		}
3823 
3824 		sector   = udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num);
3825 		length   = udf_rw32(part_hdr_desc->unalloc_space_bitmap.len);
3826 		if (length && (udf_partition->unalloc_space_bitmap == 0)) {
3827 			error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Unallocated space bitmap", &dscrptr, NULL);
3828 			if (!error) {
3829 				UDF_VERBOSE_MAX(printf("\tUnalloced space bitmap\n"));
3830 				UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
3831 				udf_read_in_space_bitmap(&udf_partition->unalloc_space_queue, &dscrptr->sbd, lb_size, &udf_partition->free_unalloc_space);
3832 				UDF_VERBOSE_TABLES(printf("\t\tPhysical partition's unallocated space : %"PRIu64"\n", udf_partition->free_unalloc_space));
3833 				udf_partition->unalloc_space_bitmap = &dscrptr->sbd;
3834 			} else {
3835 				printf("While reading in unallocated space bitmap : %s\n", strerror(error));
3836 				udf_partition->unalloc_space_bitmap = NULL;
3837 				/* TODO mark read-only logvol */
3838 			}
3839 		}
3840 
3841 		sector    = udf_rw32(part_hdr_desc->freed_space_table.lb_num);
3842 		length    = udf_rw32(part_hdr_desc->freed_space_table.len);
3843 		if (length) {
3844 			error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Freed space table", &dscrptr, NULL);
3845 			UDF_VERBOSE_MAX(printf("\tFreed space table\n"));
3846 			UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
3847 			/* udf_process_space_table(&udf_partition->freed_space, dscrptr); */
3848 			free(dscrptr);
3849 		}
3850 
3851 		sector    = udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num);
3852 		length    = udf_rw32(part_hdr_desc->freed_space_bitmap.len);
3853 		if (length && (udf_partition->freed_space_bitmap == NULL)) {
3854 			error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Freed space bitmap", &dscrptr, NULL);
3855 			if (!error) {
3856 				UDF_VERBOSE_MAX(printf("\tFreed space bitmap\n"));
3857 				UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
3858 				udf_read_in_space_bitmap(&udf_partition->freed_space_queue, &dscrptr->sbd, lb_size, &udf_partition->free_freed_space);
3859 				UDF_VERBOSE_TABLES(printf("\t\tPhysical partition's freed space : %"PRIu64"\n", udf_partition->free_unalloc_space));
3860 				udf_partition->freed_space_bitmap = &dscrptr->sbd;
3861 			} else {
3862 				printf("While reading in freed space bitmap : %s\n", strerror(error));
3863 				udf_partition->freed_space_bitmap = NULL;
3864 				/* TODO mark read-only logvol */
3865 			}
3866 		}
3867 	}
3868 	UDF_VERBOSE_TABLES(printf("\n"));
3869 
3870 	return 0;
3871 }
3872 
3873 
3874 /*
3875  * Fileset descriptors are on a logical volume's partitions; since virtual
3876  * partitions are then also possible its OK to use the VAT for redefining the
3877  * fileset descriptors.
3878  */
udf_retrieve_fileset_descriptor(struct udf_log_vol * udf_log_vol)3879 int udf_retrieve_fileset_descriptor(struct udf_log_vol *udf_log_vol) {
3880 	struct udf_mountpoint	*mountable;
3881 	struct long_ad		*fsd_loc;
3882 	struct fileset_desc	*new_fsd;
3883 	struct udf_node		*vnode;
3884 	uint32_t		 part_num, lb_num, length;
3885 	int32_t			 error;
3886 
3887 	error = 0; /* flag OK */
3888 
3889 	fsd_loc   = &udf_log_vol->log_vol->_lvd_use.fsd_loc;
3890 	part_num  = udf_rw16(fsd_loc->loc.part_num);
3891 	lb_num    = udf_rw32(fsd_loc->loc.lb_num);
3892 	length    = udf_rw32(fsd_loc->len);
3893 
3894 	while (length && !error) {
3895 		UDF_VERBOSE_TABLES(
3896 			printf("\tFileset descriptor extent at sector %d within partion %d for %d bytes\n", lb_num, part_num, length)
3897 		);
3898 
3899 		/* only go for ONE fsb at a time */
3900 		error = udf_read_logvol_descriptor(udf_log_vol, part_num, lb_num, "Fileset descriptor", (union dscrptr **) &new_fsd, NULL);
3901 		if (!error) error = udf_check_tag((union dscrptr *) new_fsd);
3902 
3903 		/* TODO need a clearer handling unrecorded blocks here */
3904 		if (error || (!new_fsd) || (new_fsd && (udf_rw16(new_fsd->tag.id) == TAGID_TERM))) {
3905 			/* end of sequence */
3906 			UDF_VERBOSE_TABLES(
3907 				printf("\t\t(Terminator) ");
3908 				if (!new_fsd || error) printf("; unrecorded"); else printf("; explicit");
3909 				printf("\n");
3910 			);
3911 			/* clear error to indicate end of sequence and free possible read in descriptor */
3912 			error = 0;
3913 			if (new_fsd) free(new_fsd);
3914 			break;
3915 		}
3916 
3917 		UDF_VERBOSE_MAX(udf_dump_descriptor((union dscrptr *) new_fsd));
3918 		udf_proc_filesetdesc(udf_log_vol, new_fsd);
3919 
3920 		if (udf_rw32(new_fsd->next_ex.len) == 0) {
3921 			/* next entry */
3922 			lb_num += 1;
3923 			length -= udf_log_vol->lb_size;
3924 		} else {
3925 			/* follow the next extent */
3926 			fsd_loc  = &new_fsd->next_ex;
3927 			part_num = udf_rw16(fsd_loc->loc.part_num);
3928 			lb_num   = udf_rw32(fsd_loc->loc.lb_num);
3929 			length   = udf_rw32(fsd_loc->len);
3930 		}
3931 	}
3932 	UDF_VERBOSE_TABLES(printf("\n"));
3933 
3934 	if (error) return error;
3935 
3936 	/* if no error occured, create rootdir udf_nodes */
3937 	SLIST_FOREACH(mountable, &udf_log_vol->mountpoints, logvol_next) {
3938 		/* errors are OK */
3939 		udf_readin_anon_udf_node(udf_log_vol, NULL, &mountable->fileset_desc->rootdir_icb,   "Rootdir",   &mountable->rootdir_node);
3940 		udf_readin_anon_udf_node(udf_log_vol, NULL, &mountable->fileset_desc->streamdir_icb, "Streamdir", &mountable->streamdir_node);
3941 
3942 		/* keep names the same ? (duplicate code ahead ... ) */
3943 		if (mountable->rootdir_node) {
3944 			vnode = mountable->rootdir_node;
3945 
3946 			vnode->mountpoint = mountable;
3947 			vnode->stat.st_uid = vnode->stat.st_gid = UINT_MAX;
3948 			vnode->stat.st_mode = 0777 | S_IFDIR;
3949 
3950 			udf_insert_node_in_hash(vnode);
3951 		}
3952 		if (mountable->streamdir_node) {
3953 			vnode = mountable->streamdir_node;
3954 
3955 			vnode->mountpoint = mountable;
3956 			vnode->stat.st_uid = vnode->stat.st_gid = UINT_MAX;
3957 			vnode->stat.st_mode = 0777 | S_IFDIR;
3958 
3959 			udf_insert_node_in_hash(vnode);
3960 		}
3961 	}
3962 
3963 	return 0;
3964 }
3965 
3966 
udf_check_writable_filesets(struct udf_log_vol * udf_log_vol,int mnt_flags)3967 int udf_check_writable_filesets(struct udf_log_vol *udf_log_vol, int mnt_flags) {
3968 	struct udf_mountpoint *mp;
3969 	struct udf_part_mapping *udf_part_mapping;
3970 	int writable;
3971 
3972 	writable = 1;
3973 	if (mnt_flags & UDF_MNT_RDONLY)
3974 		writable = 0;
3975 
3976 	if (mnt_flags & UDF_MNT_FORCE)
3977 		writable = 1;
3978 
3979 	if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) {
3980 		if (!(mnt_flags & UDF_MNT_FORCE)) {
3981 			/* we explicitly DISABLE writing */
3982 			/* XXX do we even reach here? XXX */
3983 			if (udf_verbose) {
3984 				printf("\t\t\t\tmounting READ-ONLY due to open integrity\n");
3985 			} else {
3986 				printf("WARNING: mounting logical volume READ-ONLY due to open integrity\n");
3987 			}
3988 			writable = 0;
3989 		} else {
3990 			printf("WARNING: ignoring open integrity\n");
3991 		}
3992 	}
3993 
3994 	SLIST_FOREACH(udf_part_mapping, &udf_log_vol->part_mappings, next_mapping) {
3995 		if (udf_part_mapping->udf_part_mapping_type == UDF_PART_MAPPING_META) {
3996 			writable = 0;
3997 			fprintf(stderr, "\t\t\t\t*** marked read-only due to read-only support for Metadata partition ***\n");
3998 		}
3999 	}
4000 
4001 	/* follow all mountpoints of this logical volume and set if they are writable */
4002 	SLIST_FOREACH(mp, &udf_log_vol->mountpoints, logvol_next) {
4003 		mp->writable = writable;
4004 	}
4005 	udf_log_vol->writable = writable;
4006 
4007 	/* WAS: */
4008 	/* udf_log_vol->primary->udf_session->writable = mark; */
4009 	return 0;
4010 }
4011 
4012 
4013 /*
4014  * udf_eliminate_predescessor_volumesets()
4015  *
4016  * We are faced with a curious problem : we are to examine the partitions and
4017  * determine which are successors of eachother.  This is propably most
4018  * relevant only on WORM media though. We could consider the following rules :
4019  * 	1) `glue' according to strict UDF level 1 rules ?
4020  * 	2) use heuristics info i.e. NERO, DirectCD and mkisofs quirks ?
4021  * 	3) use overlapping partitions to detect relationships ?
4022  *
4023  * Using 1 would imply no multi-volume discs and thus glue everything but that
4024  * could easily be wrong. Selecting by volumeset names is not possible for
4025  * Nero f.e. just creates random volumeset names every session and uses no
4026  * volume version information and thus also violates the UDF rules.
4027  *
4028  * Using 2 would be tricky; we know a few programs but what if more are
4029  * developped? We then would be at loss.
4030  *
4031  * Using 3 would imply some calculation but is fail-safe in both supporting
4032  * multiple volumes on one disc (they seperate) and in supporting
4033  * multi-session WORM media for these will refer to eachother. Offcource NERO
4034  * could faul this by just extending the zero partion to the whole disc in its
4035  * ignorance and thus create false overlapping over other independent
4036  * sessions. This is to be investigated. I don't know how NERO will react on
4037  * this situation.
4038  *
4039  * Propably method 3 would be good to try :
4040  *
4041  * Follow the disc and check for all sessions in order to mark the ones with
4042  * overlapping partitions as `inactive' and keep the latest one active.
4043  * Sessions with the `local' quirk are seperate allmost by default; should
4044  * be change the offsets? would not be too difficult but possible.
4045  */
4046 
udf_eliminate_predescessor_volumesets(struct udf_discinfo * disc)4047 void udf_eliminate_predescessor_volumesets(struct udf_discinfo *disc) {
4048 	struct udf_volumeset	*anc_vol_set;
4049 	struct udf_volumeset	*sib_vol_set;
4050 	struct pri_vol_desc	*anc_pri_vol;
4051 	struct pri_vol_desc	*sib_pri_vol;
4052 	struct udf_partition	*anc_part;
4053 	struct udf_partition	*sib_part;
4054 	int			 anc_partnum;
4055 	int			 sib_partnum;
4056 	uint32_t		 anc_start, anc_end;
4057 	uint32_t		 sib_start, sib_end;
4058 	uint32_t		 overlap_start, overlap_end;
4059 	uint32_t		 anc_session;
4060 	uint32_t		 sib_session;
4061 
4062 	SLIST_FOREACH(anc_vol_set, &udf_volumeset_list, next_volumeset) {
4063 		anc_pri_vol = STAILQ_FIRST(&anc_vol_set->primaries)->pri_vol;
4064 		sib_vol_set = SLIST_NEXT(anc_vol_set, next_volumeset);
4065 		while (sib_vol_set) {
4066 			sib_pri_vol = STAILQ_FIRST(&sib_vol_set->primaries)->pri_vol;
4067 			DEBUG(
4068 				printf("checking volset %s with volset %s\n", anc_pri_vol->volset_id+1, sib_pri_vol->volset_id+1)
4069 			);
4070 			/* compare these two volume sets but only process partitions on _this_ disc */
4071 			SLIST_FOREACH(anc_part, &anc_vol_set->parts, next_partition) {
4072 				if (anc_part->udf_session->disc != disc)  continue;
4073 
4074 				anc_session = anc_part->udf_session->session_num;
4075 				anc_start = 0;
4076 #if 0
4077 				if (disc->session_quirks[anc_session] & CD_SESS_QUIRK_SESSION_LOCAL)
4078 					anc_start += disc->session_start[anc_session];
4079 #endif
4080 				anc_start += udf_rw32(anc_part->partition->start_loc);
4081 				anc_end    = anc_start + udf_rw32(anc_part->partition->part_len);
4082 
4083 				SLIST_FOREACH(sib_part, &sib_vol_set->parts, next_partition) {
4084 					if (sib_part->udf_session->disc != disc)  continue;
4085 
4086 					sib_session = sib_part->udf_session->session_num;
4087 #if 0
4088 					/* can `session local' volumes even be considered part/successor ? */
4089 					if (disc->session_quirks[sib_session] & CD_SESS_QUIRK_SESSION_LOCAL) continue;
4090 #endif
4091 					sib_start = 0;
4092 #if 0
4093 					if (disc->session_quirks[sib_session] & CD_SESS_QUIRK_SESSION_LOCAL)
4094 						sib_start += disc->session_start[sib_session];
4095 #endif
4096 					sib_start += udf_rw32(sib_part->partition->start_loc);
4097 					sib_end    = sib_start + udf_rw32(sib_part->partition->part_len);
4098 DEBUG(
4099 anc_partnum = udf_rw16(anc_part->partition->part_num);
4100 sib_partnum = udf_rw16(sib_part->partition->part_num);
4101 printf("\t\tchecking partition %d with partition %d ([%d-%d] x [%d-%d])\n", anc_partnum, sib_partnum, anc_start, anc_end, sib_start, sib_end)
4102 );
4103 					overlap_start = MAX(sib_start, anc_start);
4104 					overlap_end   = MIN(sib_end,   sib_end);
4105 					if (overlap_start < overlap_end)  {
4106 DEBUG(
4107 printf("\t\t\tOVERLAP!\n")
4108 );
4109 						if (sib_session < anc_session) {
4110 							/* the sibbling is older */
4111 			UDF_VERBOSE_TABLES(
4112 				printf("\tVolume set ");
4113 				udf_dump_id(NULL, 128, anc_pri_vol->vol_id, &anc_pri_vol->desc_charset);
4114 				printf(" is a newer version of volume set ");
4115 				udf_dump_id(NULL, 128, sib_pri_vol->vol_id, &sib_pri_vol->desc_charset);
4116 				printf("\n");
4117 			);
4118 							sib_vol_set->obsolete = 1;
4119 							break;
4120 						}
4121 					} /* overlap */
4122 					if (sib_vol_set->obsolete) break;
4123 				} /* sibling partition */
4124 				if (sib_vol_set->obsolete) break;
4125 			} /* ancestor partition */
4126 			sib_vol_set = SLIST_NEXT(sib_vol_set, next_volumeset);
4127 		} /* sibling volume set */
4128 	} /* ancestor volume set */
4129 }
4130 
4131 
udf_add_session_to_discinfo(struct udf_discinfo * disc,int session,struct anchor_vdp * avdp,int error)4132 int udf_add_session_to_discinfo(struct udf_discinfo *disc, int session, struct anchor_vdp *avdp, int error) {
4133 	struct udf_session	*udf_session;
4134 
4135 	udf_session = calloc(1, sizeof(struct udf_session));
4136 	assert(udf_session);
4137 
4138 	if (!error) {
4139 		memcpy(&udf_session->anchor, avdp, sizeof(struct anchor_vdp));
4140 	}
4141 
4142 	udf_session->disc              = disc;
4143 	udf_session->session_num       = session;
4144 	udf_session->session_offset    = 0;
4145 	udf_session->session_length    = disc->session_end[session] - disc->session_start[session];
4146 	disc->session_quirks[session]  = 0;
4147 
4148 	/* writable session administration */
4149 	udf_session->writable = 0;		/* default off */
4150 	error = udf_init_session_caches(udf_session);
4151 
4152 	if (!error) {
4153 		/* detect quirks */
4154 		/* XXX session local disabled due to wrong heuristic XXX */
4155 #if 0
4156 		if (disc->session_start[session] > 0) {
4157 			if ((udf_session->anchor.main_vds_ex.loc < disc->session_start[session])) {
4158 				disc->session_quirks[session] |= CD_SESS_QUIRK_SESSION_LOCAL;
4159 				udf_session->session_offset = disc->session_start[session];
4160 			}
4161 		}
4162 #endif
4163 	}
4164 
4165 	/* add to tail of session list */
4166 	STAILQ_INSERT_TAIL(&disc->sessions, udf_session, next_session);
4167 
4168 	disc->num_udf_sessions++;
4169 
4170 	/* record status of this volume */
4171 	disc->session_is_UDF[session] = error ? 0 : 1;
4172 
4173 	return error;
4174 }
4175 
4176 
udf_get_anchors(struct udf_discinfo * disc)4177 int udf_get_anchors(struct udf_discinfo *disc) {
4178 	uint8_t			*sector;
4179 	union dscrptr		*dscr;
4180 	uint32_t		 session_start, session_end;
4181 	int			 session, error;
4182 
4183 	/* Get all anchors */
4184 	STAILQ_INIT(&disc->sessions);
4185 
4186 	sector = NULL;
4187 	for (session = 0; session < disc->num_sessions; session++) {
4188 		/* check for anchors ; no volume recognition data ? */
4189 		session_start = disc->session_start[session];
4190 		session_end   = disc->session_end  [session]-1;
4191 
4192 		sector = calloc(1, disc->sector_size);
4193 		if (!sector) return ENOMEM;
4194 
4195 		dscr = (union dscrptr *) sector;
4196 		error = udf_read_physical_sectors(disc, session_end, 1, "Anchor", sector);
4197 		if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR);
4198 		if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session end (%d)\n", session_end));
4199 		if (error) {
4200 			error = udf_read_physical_sectors(disc, session_end - 256, 1, "Anchor", sector);
4201 			if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR);
4202 			if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session end - 256 (%d)\n", session_end - 256));
4203 			if (error) {
4204 				error = udf_read_physical_sectors(disc, session_start + 256, 1, "Anchor", sector);
4205 				if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR);
4206 				if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session sector 256 (%d)\n", session_start + 256));
4207 				if (error) {
4208 					/* unclosed CD recordable case due to track reservation for iso9660 filesystems */
4209 					error = udf_read_physical_sectors(disc, session_start + 512, 1, "Anchor", sector);
4210 					if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR);
4211 					if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session sector 512 (%d)\n", session_start + 512));
4212 				}
4213 			}
4214 		}
4215 
4216 		if (!error) {
4217 			udf_add_session_to_discinfo(disc, session, (struct anchor_vdp *) sector, error);
4218 		} else {
4219 			free(sector);
4220 		}
4221 	}
4222 
4223 	return 0;
4224 }
4225 
4226 
udf_get_volumeset_space(struct udf_discinfo * disc)4227 int udf_get_volumeset_space(struct udf_discinfo *disc) {
4228 	struct udf_session *udf_session;
4229 	int one_good_found;
4230 	int error;
4231 
4232 	/* Rip all volume spaces */
4233 	one_good_found = 0;
4234 	UDF_VERBOSE(printf("\tretrieving volume space\n"));
4235 	STAILQ_FOREACH(udf_session, &disc->sessions, next_session) {
4236 		UDF_VERBOSE_MAX(printf("Session %d volumes : \n", udf_session->session_num));
4237 
4238 		error = udf_retrieve_volume_space(disc, udf_session, &udf_session->anchor.main_vds_ex);
4239 		if (error) {
4240 			printf("\nError retrieving session %d's volume space; prosessing reserve\n", udf_session->session_num);
4241 			error = udf_retrieve_volume_space(disc, udf_session, &udf_session->anchor.reserve_vds_ex);
4242 		}
4243 		if (!error)
4244 			one_good_found = 1;
4245 	}
4246 
4247 	return one_good_found ? 0 : ENOENT;
4248 }
4249 
4250 
udf_get_logical_volumes_supporting_tables(struct udf_discinfo * disc,int mnt_flags)4251 int udf_get_logical_volumes_supporting_tables(struct udf_discinfo *disc, int mnt_flags) {
4252 	struct udf_volumeset	*udf_volumeset;
4253 	struct udf_pri_vol	*udf_pri_vol;
4254 	struct udf_log_vol	*udf_log_vol;
4255 	int logvolint_error;
4256 	int one_good_found;
4257 	int error;
4258 
4259 	one_good_found = 0;
4260 	SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) {
4261 		if (!udf_volumeset->obsolete) {
4262 			STAILQ_FOREACH(udf_pri_vol, &udf_volumeset->primaries, next_primary) {
4263 				if (udf_pri_vol->udf_session->disc == disc) {
4264 					SLIST_FOREACH(udf_log_vol, &udf_pri_vol->log_vols, next_logvol) {
4265 						/* retrieving logical volume integrity sequence */
4266 						UDF_VERBOSE(udf_dump_volume_name("\t\tLogical volume ", udf_log_vol));
4267 						UDF_VERBOSE(printf("\t\t\tintegrity\n"));
4268 						logvolint_error = udf_proc_logvol_integrity_sequence(udf_log_vol);
4269 
4270 						/* load in supporting tables */
4271 						UDF_VERBOSE(printf("\t\t\tsupporting tables\n"));
4272 						error = udf_retrieve_supporting_tables(udf_log_vol);
4273 
4274 						/* if the state is still marked `open', its dirty and we mount read-only for safety */
4275 						if (logvolint_error) {
4276 							printf("\t\t\t*** marked read-only due to logvol integrity error ***\n");
4277 							mnt_flags |= UDF_MNT_RDONLY;
4278 						}
4279 						if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) {
4280 							printf("\t\t\t*** marked read-only due to open logical volume    ***\n");
4281 							mnt_flags |= UDF_MNT_RDONLY;
4282 						}
4283 
4284 						/* get fileset descriptors */
4285 						UDF_VERBOSE(printf("\t\t\tfileset(s)\n"));
4286 						if (!error) error = udf_retrieve_fileset_descriptor(udf_log_vol);
4287 
4288 						/* check if the logical volume is writable */
4289 						UDF_VERBOSE(printf("\t\t\tchecking writable filesets\n"));
4290 						if (!error) error = udf_check_writable_filesets(udf_log_vol, mnt_flags);
4291 
4292 						/* load in free/used space tables for writable volsets */
4293 						UDF_VERBOSE(printf("\t\t\tused/freed space tables\n"));
4294 						if (!error) error = udf_retrieve_space_tables(udf_log_vol);
4295 
4296 						if (error) {
4297 							udf_log_vol->broken = 1;
4298 						} else {
4299 							one_good_found = 1;
4300 						}
4301 					} /* logical */
4302 				} /* disc */
4303 			} /* primary */
4304 		} /* if */
4305 	} /* volumeset */
4306 
4307 	return one_good_found? 0 : ENOENT;
4308 }
4309 
4310 
4311 /******************************************************************************************
4312  *
4313  * Disc sync
4314  *
4315  ******************************************************************************************/
4316 
4317 
udf_sync_tables_callback(int reason,struct udf_wrcallback * wrcallback,int error,uint8_t * sectordata)4318 void udf_sync_tables_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) {
4319 	/* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */
4320 
4321 	wrcallback = wrcallback;	/* not used now */
4322 	sectordata = sectordata;
4323 
4324 	if (reason == UDF_WRCALLBACK_REASON_PENDING) {
4325 		/* what to do? */
4326 		return;
4327 	}
4328 	if (reason == UDF_WRCALLBACK_REASON_ANULATE) {
4329 		/* what to do? */
4330 		return;
4331 	}
4332 	assert(reason == UDF_WRCALLBACK_REASON_WRITTEN);
4333 	if (error) {
4334 		printf("UDF error: sync tables write errors in syncnode not fixed!\n");
4335 		return;
4336 	}
4337 }
4338 
4339 
4340 /* TODO space tables are not coupled on a logical volume but on a partition/disc, so call them on that instead of logvol */
udf_sync_space_tables(struct udf_log_vol * udf_log_vol)4341 int udf_sync_space_tables(struct udf_log_vol *udf_log_vol) {
4342 	struct udf_partition	 *udf_partition;
4343 	struct udf_part_mapping  *part_mapping;
4344 	struct part_hdr_desc	 *part_hdr_desc;
4345 	struct udf_wrcallback	  wr_callback;
4346 	union  dscrptr		 *dscrptr;
4347 	uint64_t		  length;
4348 	uint32_t		  sector;
4349 	uint32_t		  lb_size, part_len;
4350 	uint16_t		  dscr_ver;
4351 	int			  part_num;
4352 	int			  error;
4353 
4354 	lb_size = udf_log_vol->lb_size;
4355 
4356 	wr_callback.function = udf_sync_tables_callback;
4357 	SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) {
4358 		part_num = part_mapping->udf_virt_part_num;
4359 		UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", part_num, part_mapping->udf_phys_part_num));
4360 
4361 		/* retrieve and process unallocated- and freed-space information for all used partitions of the logvol */
4362 		error = udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition);
4363 		assert(udf_partition);
4364 
4365 		part_hdr_desc = &udf_partition->partition->pd_part_hdr;
4366 		// part_start    = udf_rw32(udf_partition->partition->start_loc);
4367 		part_len      = udf_rw32(udf_partition->partition->part_len);
4368 		dscr_ver      = udf_rw16(udf_partition->partition->tag.descriptor_ver);
4369 
4370 		sector   = udf_rw32(part_hdr_desc->unalloc_space_table.lb_num);
4371 		length   = udf_rw32(part_hdr_desc->unalloc_space_table.len);		/* needed? */
4372 		if (length) {
4373 			printf("UDF: Can't write space tables yet\n");
4374 #if 0
4375 			error = udf_read_logvol_descriptor(udf_log_vol, part_num, sector, "Unallocated space table", &dscrptr, NULL);
4376 			UDF_VERBOSE_MAX(printf("\tUnalloced space table\n"));
4377 			UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
4378 			//udf_process_space_table(&udf_partition->unalloc_space, dscrptr);
4379 			free(dscrptr);
4380 #endif
4381 		}
4382 
4383 		sector   = udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num);
4384 		length   = udf_rw32(part_hdr_desc->unalloc_space_bitmap.len);
4385 		/* printf("unalloc dscr at partition sector %d\n", sector); */
4386 		if (length) {
4387 			/* read it in and modify */
4388 			dscrptr = (union dscrptr *) udf_partition->unalloc_space_bitmap;
4389 			if (!dscrptr) {
4390 				printf("Warning: creating empty unallocated space bitmap for partition's is gone\n");
4391 				error = udf_create_empty_space_bitmap(lb_size, dscr_ver, /* num_lbs */ part_len, (struct space_bitmap_desc **) &dscrptr);
4392 				assert(!error);
4393 				assert(udf_calc_tag_malloc_size(dscrptr, lb_size) <= length);
4394 				udf_partition->unalloc_space_bitmap = &dscrptr->sbd;
4395 			}
4396 
4397 			udf_sync_space_bitmap(&udf_partition->unalloc_space_queue, &dscrptr->sbd, lb_size);
4398 			UDF_VERBOSE_MAX(printf("\tWriteout unallocated space bitmap\n"));
4399 			UDF_VERBOSE_MAX(udf_validate_tag_and_crc_sums((union dscrptr *) dscrptr); udf_dump_descriptor(dscrptr));
4400 			udf_write_partition_descriptor(udf_partition, sector, "Unallocated space bitmap", dscrptr, &wr_callback);	/* SESSION descriptor!! */
4401 		}
4402 
4403 		sector    = udf_rw32(part_hdr_desc->freed_space_table.lb_num);
4404 		length    = udf_rw32(part_hdr_desc->freed_space_table.len);
4405 		if (length) {
4406 			printf("UDF: Can't write space tables yet\n");
4407 #if 0
4408 			error = udf_read_logvol_descriptor(udf_log_vol, part_num, sector, "Freed space table", &dscrptr, NULL);
4409 			UDF_VERBOSE_MAX(printf("\tFreed space table\n"));
4410 			UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr));
4411 			//udf_process_space_table(&udf_partition->freed_space, dscrptr);
4412 			free(dscrptr);
4413 #endif
4414 		}
4415 
4416 		sector    = udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num);
4417 		length    = udf_rw32(part_hdr_desc->freed_space_bitmap.len);
4418 /* printf("freed dscr at partition sector %d\n", sector); */
4419 		if (length) {
4420 			/* read it in and modify */
4421 			dscrptr = (union dscrptr *) udf_partition->freed_space_bitmap;
4422 			if (!dscrptr) {
4423 				printf("Warning: creating empty freed space bitmap for partition's is gone\n");
4424 				error = udf_create_empty_space_bitmap(lb_size, dscr_ver, part_len, (struct space_bitmap_desc **) &dscrptr);
4425 				assert(!error);
4426 				assert(udf_calc_tag_malloc_size(dscrptr, lb_size) <= length);
4427 				udf_partition->freed_space_bitmap = &dscrptr->sbd;
4428 			}
4429 
4430 			udf_sync_space_bitmap(&udf_partition->freed_space_queue, &dscrptr->sbd, lb_size);
4431 			UDF_VERBOSE_MAX(printf("\tWriteout freed space bitmap\n"));
4432 			UDF_VERBOSE_MAX(udf_validate_tag_and_crc_sums((union dscrptr *) dscrptr); udf_dump_descriptor(dscrptr));
4433 			udf_write_partition_descriptor(udf_partition, sector, "Freed space bitmap", dscrptr, &wr_callback);	/* SESSION descriptor!! */
4434 		}
4435 	}
4436 	UDF_VERBOSE_TABLES(printf("\n"));
4437 
4438 	return 0;
4439 }
4440 
4441 
udf_writeout_LVID(struct udf_log_vol * udf_log_vol,int type)4442 int udf_writeout_LVID(struct udf_log_vol *udf_log_vol, int type) {
4443 	union  dscrptr	        *dscr;
4444 	struct logvol_int_desc  *intdesc;
4445 	struct udf_logvol_info  *impl;
4446 	struct udf_session      *session;
4447 	struct udf_partition    *udf_partition;
4448 	struct udf_part_mapping *part_mapping;
4449 	struct desc_tag         *terminator;
4450 	struct udf_wrcallback    wr_callback;
4451 	uint32_t sector, lvid_sector, term_sector;
4452 	uint32_t part_num, *free_space_pos, *size_pos, lb_size;
4453 	uint32_t len, length, lvid_len, num_sectors;
4454 	int error, dscr_ver, tagid;
4455 
4456 	/* create a new `fresh' logvol integrity */
4457 	session = udf_log_vol->primary->udf_session;
4458 	lb_size = udf_log_vol->lb_size;
4459 	num_sectors = lb_size / session->disc->sector_size;
4460 
4461 	intdesc = calloc(1, udf_log_vol->lb_size);
4462 	if (!intdesc)
4463 		return ENOMEM;
4464 
4465 	sector  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc);
4466 	length  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len);
4467 
4468 	if (!length)
4469 		return ENOENT;
4470 
4471 	/* search insertion place */
4472 	lvid_sector = 0;
4473 	term_sector = 0;
4474 	while (length) {
4475 		error = udf_read_session_descriptor(udf_log_vol->primary->udf_session, sector, "Logical volume integrity descriptor (LVID)", &dscr, &lvid_len);
4476 
4477 		/* getting a terminator tag or zero is an OK condition */
4478 		if (error) {
4479 			tagid = 0;
4480 		} else {
4481 			tagid = udf_rw16(dscr->tag.id);
4482 		}
4483 		if ((tagid == TAGID_TERM) || (tagid == 0)) {
4484 			lvid_sector = sector;
4485 			if (length > lb_size) {
4486 				/* space for a terminator */
4487 				term_sector = sector + num_sectors;
4488 			}
4489 			break;	/* while */
4490 		}
4491 		length -= lb_size;
4492 		sector += num_sectors;
4493 
4494 		if (udf_rw32(dscr->lvid.next_extent.len)) {
4495 			sector = udf_rw32(dscr->lvid.next_extent.loc);
4496 			length = udf_rw32(dscr->lvid.next_extent.len);
4497 		}
4498 		/* free consumed descriptor */
4499 		free(dscr);
4500 		dscr = NULL;
4501 	}
4502 	if (dscr) free(dscr);
4503 
4504 	if ((!lvid_sector) || (length == 0)) {
4505 		sector  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc);
4506 		length  = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len);
4507 		lvid_sector = sector;
4508 		if (length > lb_size) {
4509 			/* space for a terminator */
4510 			term_sector = lvid_sector + num_sectors;
4511 		}
4512 	}
4513 	assert(lvid_sector);
4514 
4515 	/* build up integrity descriptor and write it out */
4516 	dscr_ver = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver);
4517 	udf_init_desc_tag(&intdesc->tag, TAGID_LOGVOL_INTEGRITY, dscr_ver, udf_log_vol->integrity_serial);
4518 
4519 	udf_set_timestamp_now(&intdesc->time);
4520 	intdesc->integrity_type = udf_rw32(type);
4521 
4522 	intdesc->lvint_next_unique_id = udf_rw64(udf_log_vol->next_unique_id);
4523 
4524 	/* calculate and fill in free space */
4525 	intdesc->num_part = udf_rw32(udf_log_vol->num_part_mappings);
4526 	free_space_pos = &intdesc->tables[0];
4527 	size_pos       = &intdesc->tables[udf_log_vol->num_part_mappings];
4528 	SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) {
4529 		part_num = part_mapping->udf_virt_part_num;
4530 		udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition);
4531 		assert(udf_partition);
4532 
4533 		*size_pos++       = udf_partition->partition->part_len;
4534 		*free_space_pos++ = udf_rw32(udf_partition->free_unalloc_space / udf_log_vol->lb_size);
4535 	}
4536 
4537 	/* fill in UDF implementation use parameters */
4538 	impl = (struct udf_logvol_info *) (&intdesc->tables[2*udf_log_vol->num_part_mappings]);
4539 	udf_set_imp_id(&impl->impl_id);
4540 	impl->num_files        = udf_rw32(udf_log_vol->num_files);
4541 	impl->num_directories  = udf_rw32(udf_log_vol->num_directories);
4542 	impl->min_udf_readver  = udf_rw16(udf_log_vol->min_udf_readver);
4543 	impl->min_udf_writever = udf_rw16(udf_log_vol->min_udf_writever);
4544 	impl->max_udf_writever = udf_rw16(udf_log_vol->max_udf_writever);
4545 
4546 	intdesc->l_iu = udf_rw32(sizeof(struct udf_logvol_info));		/* ECMA 3/10.10.7, UDF 2.2.6.4. */
4547 	len  = sizeof(struct logvol_int_desc) - sizeof(uint32_t);		/* length of logvol_int_desc without the extra table entry */
4548 	len += sizeof(uint32_t) * 2 * udf_log_vol->num_part_mappings;		/* size and free space */
4549 	len += sizeof(struct udf_logvol_info);					/* extra implementation use area */
4550 	len -= UDF_DESC_TAG_LENGTH;						/* without header */
4551 	intdesc->tag.desc_crc_len = udf_rw16(len);
4552 
4553 	udf_write_session_descriptor(session, lvid_sector, "Logvol integrity descriptor (LVID)", (union dscrptr *) intdesc, &wr_callback);
4554 	if (session->disc->rewritable && term_sector) {
4555 		/* only when there is space and its a rewritable media add a terminor */
4556 		error = udf_create_empty_terminator_descriptor(lb_size, dscr_ver, &terminator);
4557 		if (!error) {
4558 			udf_write_session_descriptor(session, term_sector, "Logvol integrity sequence descriptor sequence terminator", (union dscrptr *) terminator, &wr_callback);
4559 			free(terminator);
4560 		}
4561 	}
4562 
4563 	free(intdesc);
4564 
4565 	return 0;
4566 }
4567 
4568 
4569 /* mark the logical volume `open'; for non-rewritables (CD-R/DVD+R/DVD-R) this is allmost a no-op */
udf_open_logvol(struct udf_log_vol * udf_log_vol)4570 int udf_open_logvol(struct udf_log_vol *udf_log_vol) {
4571 	int error;
4572 
4573 	if (!udf_log_vol->writable) {
4574 		udf_dump_volume_name("\nLogical volume marked read only: ", udf_log_vol);
4575 		return EROFS;
4576 	}
4577 
4578 	/* will return many times for each write */
4579 	if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN)
4580 		return 0;
4581 
4582 	/*
4583 	 * Opening and closing logical volumes is derived from the state of
4584 	 * the primaries disc.
4585 	 */
4586 	udf_dump_volume_name("Opening logical volume", udf_log_vol);
4587 	if (!udf_log_vol->primary->udf_session->disc->sequential) {
4588 		error  = udf_writeout_LVID(udf_log_vol, UDF_INTEGRITY_OPEN);
4589 		assert(!error);
4590 		/* sync caches to make sure all is written out */
4591 		udf_sync_caches(udf_log_vol);
4592 		/* FIXME (callback) XXX ought to wait until we get the ALL-OK signal from the writeout-LVID action XXX */
4593 	} else {
4594 		/* sequential recordable; any write just opens it; the descriptor is allready marked open */
4595 	}
4596 
4597 	/* mark it open */
4598 	udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN;
4599 
4600 	return 0;
4601 }
4602 
4603 
4604 /* mark the logical volume in a `closed' state; close the integrity when possible for recordables writeout VAT */
udf_close_logvol(struct udf_log_vol * udf_log_vol)4605 int udf_close_logvol(struct udf_log_vol *udf_log_vol) {
4606 	int error;
4607 
4608 	if (udf_log_vol->logvol_state == UDF_INTEGRITY_CLOSED) {
4609 		DEBUG(printf("close logvol: integrity allready closed\n"));
4610 		return 0;
4611 	}
4612 
4613 	/*
4614 	 * Opening and closing logical volumes is derived from the state of
4615 	 * the primaries disc.
4616 	 */
4617 	udf_dump_volume_name("Closing logical volume", udf_log_vol);
4618 	if (!udf_log_vol->primary->udf_session->disc->sequential) {
4619 		error  = udf_writeout_LVID(udf_log_vol, UDF_INTEGRITY_CLOSED);
4620 		assert(!error);
4621 	} else {
4622 		/* XXX TODO XXX */
4623 		fprintf(stderr, "write out virtual sectors, compile VAT and write out VAT : not implemented\n");
4624 		return EIO;
4625 	}
4626 
4627 	/* sync caches to make sure all is written out */
4628 	udf_sync_caches(udf_log_vol);
4629 	/* FIXME (callback) XXX ought to wait until we get the ALL-OK signal from the writeout-LVID action XXX */
4630 
4631 	/* mark it closed again */
4632 	udf_log_vol->logvol_state = UDF_INTEGRITY_CLOSED;
4633 	return 0;
4634 }
4635 
4636 
udf_sync_logvol(struct udf_log_vol * udf_log_vol)4637 int udf_sync_logvol(struct udf_log_vol *udf_log_vol) {
4638 	struct udf_node	*udf_node;
4639 	uint32_t num_dirty, count, prnt;
4640 	int error;
4641 
4642 	if (!udf_log_vol->writable)
4643 		return 0;
4644 
4645 	if (udf_log_vol->logvol_state == UDF_INTEGRITY_CLOSED) {
4646 		DEBUG(printf("close logvol: its closed so no sync nessisary\n"));
4647 		return 0;
4648 	}
4649 
4650 	UDF_VERBOSE(udf_dump_volume_name("\tsyncing ", udf_log_vol));
4651 
4652 	/* sync all nodes */
4653 	/* XXX syncing logvol sequential due to insertion sort in add node XXX */
4654 	num_dirty = 0;
4655 	TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) {
4656 		num_dirty++;
4657 	}
4658 
4659 	/*
4660 	 * Purge all data out first, this will speed things up later (not
4661 	 * strickly nessissary since syncing a node will wait for all the data
4662 	 * to be written out first anyway
4663 	 */
4664 	count = num_dirty;
4665 	prnt = 0;
4666 	UDF_VERBOSE(printf("\t\tsyncing data\n"));
4667 	TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) {
4668 		UDF_VERBOSE(printf("\r%8d", count); fflush(stdout));
4669 		udf_sync_udf_node(udf_node, "Sync Logvol");
4670 		count--;
4671 		prnt = 1;
4672 	}
4673 	if (prnt) UDF_VERBOSE(printf("\r                      \r"));
4674 
4675 	/*
4676 	 * Purge all nodes out... they ought to have no dirty buffers anymore
4677 	 * but they will write them out if deemed nessisary
4678 	 */
4679 	count = num_dirty;
4680 	prnt = 0;
4681 	UDF_VERBOSE(printf("\t\tsyncing nodes\n"));
4682 	TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) {
4683 		UDF_VERBOSE(printf("\r%8d", count); fflush(stdout));
4684 		DEBUG(printf("N"); fflush(stdout));
4685 		udf_writeout_udf_node(udf_node, "Sync Logvol");
4686 		count--;
4687 		prnt = 1;
4688 	}
4689 	if (prnt) UDF_VERBOSE(printf("\r                      \r"));
4690 
4691 	/* shouldn't be nessisary */
4692 	udf_bufcache->flushall = 1;
4693 	udf_purgethread_kick("Sync Logvol");
4694 	usleep(1);
4695 
4696 	if (udf_bufcache->lru_len_dirty_metadata + udf_bufcache->lru_len_dirty_data) {
4697 		printf("Warning: after syncing logvol dirty counts != 0 (%d, %d); please contact author.\n",
4698 				udf_bufcache->lru_len_dirty_metadata, udf_bufcache->lru_len_dirty_data);
4699 	}
4700 
4701 	/* sync free and used space tables for writable volsets */
4702 	UDF_VERBOSE(printf("\t\tused/freed space tables\n"));
4703 	error = udf_sync_space_tables(udf_log_vol);
4704 
4705 	/* close logical volume */
4706 	udf_close_logvol(udf_log_vol);
4707 
4708 	return error;
4709 }
4710 
4711 
4712 /* convenience routine */
udf_sync_disc(struct udf_discinfo * disc)4713 int udf_sync_disc(struct udf_discinfo *disc) {
4714 	struct udf_volumeset	*udf_volumeset;
4715 	struct udf_pri_vol	*udf_pri_vol;
4716 	struct udf_log_vol	*udf_log_vol;
4717 
4718 	SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) {
4719 		if (!udf_volumeset->obsolete) {
4720 			STAILQ_FOREACH(udf_pri_vol, &udf_volumeset->primaries, next_primary) {
4721 				if (udf_pri_vol->udf_session->disc == disc) {
4722 					SLIST_FOREACH(udf_log_vol, &udf_pri_vol->log_vols, next_logvol) {
4723 						udf_sync_logvol(udf_log_vol);
4724 					} /* logical */
4725 				} /* disc */
4726 			} /* primary */
4727 		} /* if */
4728 	} /* volumeset */
4729 
4730 	return 0;
4731 }
4732 
4733 
4734 /******************************************************************************************
4735  *
4736  * UDF descriptor buildup and update functions
4737  *
4738  ******************************************************************************************/
4739 
udf_init_desc_tag(struct desc_tag * tag,uint16_t id,uint16_t dscr_ver,uint16_t serial_num)4740 static void udf_init_desc_tag(struct desc_tag *tag, uint16_t id, uint16_t dscr_ver, uint16_t serial_num) {
4741 	bzero(tag, sizeof(struct desc_tag));
4742 	tag->id			= udf_rw16(id);
4743 	tag->descriptor_ver	= udf_rw16(dscr_ver);
4744 	tag->serial_num		= udf_rw16(serial_num);
4745 	/* the rest gets filled in when we write */
4746 }
4747 
4748 
udf_osta_charset(struct charspec * charspec)4749 static void udf_osta_charset(struct charspec *charspec) {
4750 	bzero(charspec, sizeof(struct charspec));
4751 	charspec->type = 0;
4752 	strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
4753 }
4754 
4755 
udf_encode_osta_id(char * osta_id,uint16_t len,char * text)4756 static void udf_encode_osta_id(char *osta_id, uint16_t len, char *text) {
4757 	uint16_t  u16_name[1024];
4758 	uint8_t  *pos;
4759 	uint16_t *pos16;
4760 
4761 	bzero(osta_id, len);
4762 	if (!text) return;
4763 
4764 	bzero(u16_name, sizeof(uint16_t) * 1023);
4765 	/* convert ascii to 16 bits unicode */
4766 	pos   = (uint8_t *) text;
4767 	pos16 = u16_name;
4768 	while (*pos) {
4769 		*pos16 = *pos;
4770 		pos++; pos16++;
4771 	}
4772 	*pos16 = 0;
4773 
4774 	udf_CompressUnicode(len, 8, (unicode_t *) u16_name, (byte *) osta_id);
4775 
4776 	/* Ecma 167/7.2.13 states that the length is recorded in the last byte */
4777 	osta_id[len-1] = strlen(text)+1;
4778 }
4779 
4780 
udf_set_app_id(struct regid * regid)4781 static void udf_set_app_id(struct regid *regid) {
4782 	bzero(regid, sizeof(struct regid));
4783 	regid->flags	= 0;						/* not dirty and not protected */
4784 	strcpy((char *) regid->id, APP_NAME);
4785 	regid->id_suffix[0] = APP_VERSION_MAIN;
4786 	regid->id_suffix[1] = APP_VERSION_SUB;
4787 }
4788 
4789 
udf_set_imp_id(struct regid * regid)4790 static void udf_set_imp_id(struct regid *regid) {
4791 	bzero(regid, sizeof(struct regid));
4792 	regid->flags	= 0;						/* not dirty and not protected */
4793 	strcpy((char *) regid->id, IMPL_NAME);
4794 	regid->id_suffix[0] = 4;	/* unix */
4795 	regid->id_suffix[1] = 0;	/* generic */
4796 #if   defined(__ANONYMOUSUDF__)
4797 #elif defined(__NetBSD__)
4798 	regid->id_suffix[1] = 8;	/* NetBSD */
4799 #elif defined(__FreeBSD__)
4800 	regid->id_suffix[1] = 7;	/* FreeBSD */
4801 #elif defined(LINUX)
4802 	regid->id_suffix[1] = 5;	/* Linux */
4803 #endif
4804 }
4805 
4806 
udf_set_entity_id(struct regid * regid,char * name,uint16_t UDF_version)4807 static void udf_set_entity_id(struct regid *regid, char *name, uint16_t UDF_version) {
4808 	uint16_t *ver;
4809 
4810 	bzero(regid, sizeof(struct regid));
4811 	regid->flags    = 0;						/* not dirty and not protected */
4812 	strcpy((char *) regid->id, name);
4813 	ver  = (uint16_t *) regid->id_suffix;
4814 	*ver = udf_rw16(UDF_version);
4815 	regid->id_suffix[2] = 4;	/* unix */
4816 	regid->id_suffix[3] = 0;	/* generic */
4817 #if   defined(__ANONYMOUSUDF__)
4818 #elif defined(__NetBSD__)
4819 	regid->id_suffix[3] = 8;	/* NetBSD */
4820 #elif defined(__FreeBSD__)
4821 	regid->id_suffix[3] = 7;	/* FreeBSD */
4822 #elif defined(LINUX)
4823 	regid->id_suffix[3] = 5;	/* Linux */
4824 #endif
4825 }
4826 
4827 
udf_set_contents_id(struct regid * regid,char * content_id)4828 void udf_set_contents_id(struct regid *regid, char *content_id) {
4829 	bzero(regid, sizeof(struct regid));
4830 	regid->flags    = 0;
4831 	strcpy((char *) regid->id, content_id);
4832 }
4833 
4834 
4835 /* XXX creators of empty descriptors could be externalised */
4836 
4837 /*
4838  * result can be further processed using modify functions if demanded and then
4839  * processed trough udf_proc_pri_vol
4840  * [ int udf_proc_pri_vol(struct udf_session *udf_session, struct udf_pri_vol **current, struct pri_vol_desc *incomming); ]
4841  *
4842  */
4843 
udf_create_empty_primary_volume_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint16_t serial,char * volset_id,char * privol_name,int vds_num,int max_vol_seq,struct pri_vol_desc ** dscrptr)4844 int udf_create_empty_primary_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *volset_id, char *privol_name, int vds_num, int max_vol_seq, struct pri_vol_desc **dscrptr) {
4845 	struct pri_vol_desc *dscr;
4846 
4847 	assert(dscrptr);
4848 	*dscrptr = NULL;
4849 
4850 	/* allocate and populate an empty primary volume descriptor */
4851 	dscr = malloc(sector_size);
4852 	if (!dscr) return ENOMEM;
4853 	bzero(dscr, sector_size);
4854 
4855 	udf_init_desc_tag(&dscr->tag, TAGID_PRI_VOL, dscr_ver, 1);
4856 	dscr->pvd_num		= udf_rw32(serial);
4857 	udf_encode_osta_id(dscr->vol_id, 32, privol_name);
4858 	dscr->vds_num		= udf_rw16(vds_num);
4859 	dscr->max_vol_seq	= udf_rw16(max_vol_seq);
4860 	if (max_vol_seq > 1) {
4861 		dscr->ichg_lvl		= udf_rw16(3);			/* signal its a single volume intended to be in a set */
4862 		dscr->max_ichg_lvl	= udf_rw16(3);			/* ,, */
4863 		dscr->flags		= udf_rw16(1);			/* signal relevance volumeset id */
4864 	} else {
4865 		dscr->ichg_lvl		= udf_rw16(2);			/* signal its volume intended not to be in a set */
4866 		dscr->max_ichg_lvl	= udf_rw16(2);			/* ,, */
4867 		dscr->flags		= udf_rw16(0);			/* signal relevance volumeset id */
4868 	}
4869 
4870 	dscr->charset_list		= udf_rw32(1);			/* only CS0 */
4871 	dscr->max_charset_list		= udf_rw32(1);
4872 	udf_encode_osta_id(dscr->volset_id, 128, volset_id);
4873 	udf_osta_charset(&dscr->desc_charset);
4874 	udf_osta_charset(&dscr->explanatory_charset);
4875 	udf_set_app_id(&dscr->app_id);
4876 	udf_set_imp_id(&dscr->imp_id);
4877 	udf_set_timestamp_now(&dscr->time);
4878 
4879 	dscr->tag.desc_crc_len = udf_rw16(sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH);
4880 
4881 	*dscrptr = dscr;
4882 	return 0;
4883 }
4884 
4885 
udf_create_empty_partition_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint16_t serial,uint16_t part_num,uint32_t access_type,uint32_t start_loc,uint32_t part_len,uint32_t space_bitmap_size,uint32_t unalloc_space_bitmap,struct part_desc ** dscrptr)4886 int udf_create_empty_partition_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, uint16_t part_num, uint32_t access_type, uint32_t start_loc, uint32_t part_len, uint32_t space_bitmap_size, uint32_t unalloc_space_bitmap, struct part_desc **dscrptr) {
4887 	struct part_desc     *dscr;
4888 	struct part_hdr_desc *part_hdr;
4889 
4890 	assert(dscrptr);
4891 	*dscrptr = NULL;
4892 
4893 	/* allocate and populate empty partition descriptor */
4894 	dscr = malloc(sector_size);					/* only descriptor, no bitmap! */
4895 	if (!dscr) return ENOMEM;
4896 	bzero(dscr, sector_size);
4897 
4898 	udf_init_desc_tag(&dscr->tag, TAGID_PARTITION, dscr_ver, 1);
4899 	dscr->seq_num  = udf_rw32(serial);
4900 	dscr->flags    = udf_rw16(1);					/* bit 0 : space is allocated */
4901 	dscr->part_num = udf_rw16(part_num);
4902 
4903 	if (dscr_ver == 2) udf_set_contents_id(&dscr->contents, "+NSR02");
4904 	if (dscr_ver == 3) udf_set_contents_id(&dscr->contents, "+NSR03");
4905 	part_hdr = &dscr->pd_part_hdr;
4906 	part_hdr->unalloc_space_bitmap.len    = udf_rw32(space_bitmap_size);
4907 	part_hdr->unalloc_space_bitmap.lb_num = udf_rw32(unalloc_space_bitmap);
4908 
4909 	dscr->access_type = udf_rw32(access_type);
4910 	dscr->start_loc   = udf_rw32(start_loc);
4911 	dscr->part_len    = udf_rw32(part_len);
4912 
4913 	udf_set_imp_id(&dscr->imp_id);					/* why is this ignored? */
4914 
4915 	dscr->tag.desc_crc_len = udf_rw16(sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH);
4916 
4917 	*dscrptr = dscr;
4918 	return 0;
4919 }
4920 
4921 
udf_create_empty_unallocated_space_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint16_t serial,struct unalloc_sp_desc ** dscrptr)4922 int udf_create_empty_unallocated_space_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, struct unalloc_sp_desc **dscrptr) {
4923 	struct unalloc_sp_desc *dscr;
4924 
4925 	assert(dscrptr);
4926 	*dscrptr = NULL;
4927 
4928 	/* allocate and populate an empty unallocated space descriptor */
4929 	dscr = malloc(sector_size);
4930 	if (!dscr) return ENOMEM;
4931 	bzero(dscr, sector_size);
4932 
4933 	udf_init_desc_tag(&dscr->tag, TAGID_UNALLOC_SPACE, dscr_ver, 1);
4934 	dscr->seq_num		= udf_rw32(serial);
4935 	dscr->tag.desc_crc_len	= udf_rw16(sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad) - UDF_DESC_TAG_LENGTH);
4936 
4937 	*dscrptr = dscr;
4938 
4939 	return 0;
4940 }
4941 
4942 
udf_create_empty_implementation_use_volume_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint16_t serial,char * logvol_name,struct impvol_desc ** dscrptr)4943 int udf_create_empty_implementation_use_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, struct impvol_desc **dscrptr) {
4944 	struct impvol_desc *dscr;
4945 	struct udf_lv_info *lv_info;
4946 
4947 	assert(dscrptr);
4948 	*dscrptr = NULL;
4949 
4950 	/* allocate and populate an empty implementation use volume descriptor */
4951 	dscr = malloc(sector_size);
4952 	if (!dscr) return ENOMEM;
4953 	bzero(dscr, sector_size);
4954 
4955 	udf_init_desc_tag(&dscr->tag, TAGID_IMP_VOL, dscr_ver, 1);
4956 	dscr->seq_num		= udf_rw32(serial);
4957 	udf_set_entity_id(&dscr->impl_id, "*UDF LV Info", 0x102);	/* just pick one; it'll be modifed later */
4958 
4959 	lv_info = &dscr->_impl_use.lv_info;
4960 	udf_osta_charset(&lv_info->lvi_charset);
4961 	udf_encode_osta_id(lv_info->logvol_id, 128, logvol_name);
4962 	udf_encode_osta_id(lv_info->lvinfo1, 36, NULL);
4963 	udf_encode_osta_id(lv_info->lvinfo2, 36, NULL);
4964 	udf_encode_osta_id(lv_info->lvinfo3, 36, NULL);
4965 	udf_set_imp_id(&lv_info->impl_id);
4966 
4967 	dscr->tag.desc_crc_len	= udf_rw16(sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH);
4968 
4969 	*dscrptr = dscr;
4970 
4971 	return 0;
4972 }
4973 
4974 
udf_create_empty_logical_volume_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint16_t serial,char * logvol_name,uint32_t lb_size,uint32_t integrity_start,uint32_t integrity_length,struct logvol_desc ** dscrptr)4975 int udf_create_empty_logical_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, uint32_t lb_size, uint32_t integrity_start, uint32_t integrity_length, struct logvol_desc **dscrptr) {
4976 	struct logvol_desc *dscr;
4977 
4978 	assert(dscrptr);
4979 	*dscrptr = NULL;
4980 
4981 	/* allocate and populate an empty logical volume descriptor */
4982 	dscr = malloc(sector_size);
4983 	if (!dscr) return ENOMEM;
4984 	bzero(dscr, sector_size);
4985 
4986 	udf_init_desc_tag(&dscr->tag, TAGID_LOGVOL, dscr_ver, 1);
4987 	dscr->seq_num		= udf_rw32(serial);
4988 	udf_osta_charset(&dscr->desc_charset);
4989 	udf_encode_osta_id(dscr->logvol_id, 128, logvol_name);
4990 	dscr->lb_size		= udf_rw32(lb_size);
4991 	udf_set_contents_id(&dscr->domain_id, "*OSTA UDF Compliant");
4992 
4993 	/* no fsd yet nor partition mapping */
4994 	udf_set_imp_id(&dscr->imp_id);
4995 	dscr->integrity_seq_loc.loc = udf_rw32(integrity_start);
4996 	dscr->integrity_seq_loc.len = udf_rw32(integrity_length * lb_size);
4997 
4998 	dscr->tag.desc_crc_len = udf_rw16(sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH);
4999 
5000 	*dscrptr = dscr;
5001 	return 0;
5002 }
5003 
5004 
udf_create_empty_space_bitmap(uint32_t sector_size,uint16_t dscr_ver,uint32_t num_lbs,struct space_bitmap_desc ** dscrptr)5005 int udf_create_empty_space_bitmap(uint32_t sector_size, uint16_t dscr_ver, uint32_t num_lbs, struct space_bitmap_desc **dscrptr) {
5006 	struct space_bitmap_desc *dscr;
5007 	uint64_t bits;
5008 	uint32_t bytes, space_bitmap_size;
5009 
5010 	assert(dscrptr);
5011 	*dscrptr = NULL;
5012 
5013 	/* reserve space for unallocated space bitmap */
5014 	bits  = num_lbs;
5015 	bytes = (bits + 7)/8;
5016 	space_bitmap_size = (bytes + sizeof(struct space_bitmap_desc)-1);
5017 
5018 	/* round space bitmap size to sector size */
5019 	space_bitmap_size = ((space_bitmap_size + sector_size - 1) / sector_size) * sector_size;
5020 
5021 	/* allocate and populate an empty space bitmap descriptor */
5022 	dscr = malloc(space_bitmap_size);
5023 	if (!dscr) return ENOMEM;
5024 	bzero(dscr, space_bitmap_size);
5025 
5026 	udf_init_desc_tag(&dscr->tag, TAGID_SPACE_BITMAP, dscr_ver, 1);
5027 	/* crc length 8 is recommended, UDF 2.3.1.2, 2.3.8.1, errata DCN-5108 for UDF 2.50 and lower. */
5028 	dscr->tag.desc_crc_len = udf_rw16(8);
5029 
5030 	dscr->num_bits  = udf_rw32(bits);
5031 	dscr->num_bytes = udf_rw32(bytes);
5032 
5033 	*dscrptr = dscr;
5034 	return 0;
5035 }
5036 
5037 
5038 /* FIXME: no rootdir setting yet */
5039 /* FIXME: fileset desc. is disc sector size or lb_size ? */
udf_create_empty_fileset_desc(uint32_t sector_size,uint16_t dscr_ver,uint32_t fileset_num,char * logvol_name,char * fileset_name,struct fileset_desc ** dscrptr)5040 int udf_create_empty_fileset_desc(uint32_t sector_size, uint16_t dscr_ver, uint32_t fileset_num, char *logvol_name, char *fileset_name, struct fileset_desc **dscrptr) {
5041 	struct fileset_desc *dscr;
5042 
5043 	assert(dscrptr);
5044 	*dscrptr = NULL;
5045 
5046 	/* allocate and populate an empty logical volume descriptor */
5047 	dscr = malloc(sector_size);
5048 	if (!dscr) return ENOMEM;
5049 	bzero(dscr, sector_size);
5050 
5051 	udf_init_desc_tag(&dscr->tag, TAGID_FSD, dscr_ver, 1);
5052 	udf_set_timestamp_now(&dscr->time);
5053 	dscr->ichg_lvl         = udf_rw16(3);	/* fixed? */
5054 	dscr->max_ichg_lvl     = udf_rw16(3);	/* fixed? */
5055 	dscr->charset_list     = udf_rw32(1);	/* only CS0 */
5056 	dscr->max_charset_list = udf_rw32(1);	/* only CS0 */
5057 	dscr->fileset_num      = udf_rw32(fileset_num);	/* key for fileset */
5058 	dscr->fileset_desc_num = udf_rw32(0);		/* fileset descriptor number as in copy # */
5059 
5060 	udf_osta_charset(&dscr->logvol_id_charset);
5061 	udf_encode_osta_id(dscr->logvol_id, 128, logvol_name);
5062 
5063 	udf_osta_charset(&dscr->fileset_charset);
5064 	udf_encode_osta_id(dscr->fileset_id, 32, fileset_name);
5065 
5066 	udf_encode_osta_id(dscr->copyright_file_id, 32, NULL);
5067 	udf_encode_osta_id(dscr->abstract_file_id,  32, NULL);
5068 
5069 	udf_set_contents_id(&dscr->domain_id, "*OSTA UDF Compliant");
5070 
5071 	dscr->tag.desc_crc_len = udf_rw16(sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH);
5072 
5073 	*dscrptr = dscr;
5074 	return 0;
5075 }
5076 
5077 
udf_create_empty_anchor_volume_descriptor(uint32_t sector_size,uint16_t dscr_ver,uint32_t main_vds_loc,uint32_t reserve_vds_loc,uint32_t length,struct anchor_vdp ** vdp)5078 int udf_create_empty_anchor_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint32_t main_vds_loc, uint32_t reserve_vds_loc, uint32_t length, struct anchor_vdp **vdp) {
5079 	assert(vdp);
5080 	assert(main_vds_loc - reserve_vds_loc >= length);
5081 
5082 	*vdp = malloc(sector_size);
5083 	if (!*vdp) return ENOMEM;
5084 	bzero(*vdp, sector_size);
5085 
5086 	udf_init_desc_tag(&(*vdp)->tag, TAGID_ANCHOR, dscr_ver, 1);
5087 	(*vdp)->main_vds_ex.loc    = udf_rw32(main_vds_loc);
5088 	(*vdp)->main_vds_ex.len    = udf_rw32(length * sector_size);
5089 	(*vdp)->reserve_vds_ex.loc = udf_rw32(reserve_vds_loc);
5090 	(*vdp)->reserve_vds_ex.len = udf_rw32(length * sector_size);
5091 
5092 	(*vdp)->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);		/* fixed size in Ecma */
5093 	return 0;
5094 }
5095 
5096 
udf_create_empty_terminator_descriptor(uint32_t sector_size,uint16_t dscr_ver,struct desc_tag ** tag)5097 int udf_create_empty_terminator_descriptor(uint32_t sector_size, uint16_t dscr_ver, struct desc_tag **tag) {
5098 	assert(tag);
5099 
5100 	*tag = malloc(sector_size);
5101 	if (!*tag) return ENOMEM;
5102 	bzero(*tag, sector_size);
5103 
5104 	udf_init_desc_tag(*tag, TAGID_TERM, dscr_ver, 1);
5105 
5106 	(*tag)->desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);		/* fixed size in Ecma */
5107 	return 0;
5108 }
5109 
5110 
5111 /******************************************************************************************
5112  *
5113  * Basic `open' and `close' disc functions
5114  *
5115  ******************************************************************************************/
5116 
5117 
udf_process_session_range(struct udf_discinfo * disc,int * enabled,int low,int high)5118 static void udf_process_session_range(struct udf_discinfo *disc, int *enabled, int low, int high) {
5119 	int session;
5120 
5121 	if (!disc) return;
5122 
5123 	high = MIN(high, disc->num_sessions-1);
5124 	session = low;
5125 
5126 	for (session = low; session <= high; session++) {
5127 		enabled[session] = 1;
5128 	}
5129 }
5130 
5131 
5132 /* range is specified in -3,5,7 or 5-6,8- etc */
udf_process_session_range_string(struct udf_discinfo * disc,char * range)5133 static int udf_process_session_range_string(struct udf_discinfo *disc, char *range) {
5134 	struct udf_session *udf_session, *next_udf_session;
5135 	char *pos, *nop;
5136 	int low, high, len, session;
5137 	int enabled[MAX_SESSIONS];
5138 
5139 	if (!range) return 0;
5140 	DEBUG(printf("UDF range debugging string '%s'\n", range));
5141 
5142 	if (disc) {
5143 		/* disable all */
5144 		for (session = 0; session < disc->num_sessions; session++) {
5145 			enabled[session] = 0;
5146 		}
5147 	}
5148 
5149 	/* parse string */
5150 	nop = strdup(range);
5151 	pos = range;
5152 	if (sscanf(pos, "-%u%n%s", &high, &len, nop) >= 1) {
5153 		DEBUG(printf("UDF range match till %d\n", high));
5154 		udf_process_session_range(disc, enabled, 0, high);
5155 		pos += len;
5156 	}
5157 	if (*pos && *pos == ',') pos++;
5158 	while (*pos) {
5159 		if (sscanf(pos, "%u%n%s", &low, &len, nop) >= 1) {
5160 			pos += len;
5161 			if (*pos == '-') {
5162 				pos++;
5163 				if (!*pos) {
5164 					DEBUG(printf("UDF range match from %d\n", low));
5165 					udf_process_session_range(disc, enabled, low, INT_MAX);
5166 					free(nop);
5167 					return 0;
5168 				}
5169 				if (sscanf(pos, "%u%n%s", &high, &len, nop) >= 1) {
5170 					pos += len;
5171 					DEBUG(printf("UDF range match from %d to %d\n", low, high));
5172 					udf_process_session_range(disc, enabled, low, high);
5173 				}
5174 			} else {
5175 				if (!*pos || (*pos == ',')) {
5176 					DEBUG(printf("UDF range match %d\n", low));
5177 					udf_process_session_range(disc, enabled, low, low);
5178 				}
5179 			}
5180 			if (*pos && (*pos != ',')) {
5181 				fprintf(stderr, "UDF range matching : ',' expected at %s\n", pos);
5182 				free(nop);
5183 				return ENOENT;
5184 			}
5185 			pos++;
5186 		} else {
5187 			fprintf(stderr, "UDF range matching : number expected at %s\n", pos);
5188 			free(nop);
5189 			return ENOENT;
5190 		}
5191 	}
5192 	free(nop);
5193 
5194 	DEBUG(printf("UDF range matching : all ok till the end\n"));
5195 	if (!disc) return 0;
5196 
5197 	udf_session = STAILQ_FIRST(&disc->sessions);
5198 	while (udf_session) {
5199 		next_udf_session = STAILQ_NEXT(udf_session, next_session);
5200 		session = udf_session->session_num;
5201 		if (!enabled[session]) {
5202 			/* remove this session */
5203 			fprintf(stderr, "UDF: disabling UDF session %d on request\n", session);
5204 			STAILQ_REMOVE(&disc->sessions, udf_session, udf_session, next_session);
5205 			free(udf_session);
5206 
5207 			disc->session_is_UDF[session] = 0;
5208 		}
5209 		udf_session = next_udf_session;
5210 	}
5211 
5212 	return 0;
5213 }
5214 
5215 
udf_check_session_range(char * range)5216 int udf_check_session_range(char *range) {
5217 	return udf_process_session_range_string(NULL, range);
5218 }
5219 
5220 
5221 void
udf_init(void)5222 udf_init(void)
5223 {
5224 	udf_unix_init();
5225 	udf_start_unix_thread();
5226 	dirhash_init();
5227 
5228 	SLIST_INIT(&udf_discs_list);
5229 }
5230 
5231 
udf_mount_disc(char * devname,char * range,uint32_t sector_size,int mnt_flags,struct udf_discinfo ** disc)5232 int udf_mount_disc(char *devname, char *range, uint32_t sector_size, int mnt_flags, struct udf_discinfo **disc) {
5233 	int discop_flags, error;
5234 
5235 	discop_flags = mnt_flags & UDF_MNT_BSWAP ? UDF_DISCOP_BSWAP : 0;
5236 	error = udf_open_disc(devname, discop_flags, disc);
5237 	if ((!error) && sector_size)
5238 		error = udf_discinfo_alter_perception(*disc, sector_size, 0);
5239 	if (error)
5240 		return error;
5241 
5242 	error = udf_get_anchors(*disc);
5243 	UDF_VERBOSE(udf_dump_disc_anchors(*disc));
5244 
5245 	if (range) {
5246 		UDF_VERBOSE(printf("Selecting UDF sessions '%s' as specified\n", range));
5247 		udf_process_session_range_string(*disc, range);
5248 		UDF_VERBOSE(udf_dump_disc_anchors(*disc));
5249 	}
5250 
5251 	/* no UDF partitions so bail out */
5252 	if ((*disc)->num_udf_sessions == 0) return 0;
5253 
5254 	UDF_VERBOSE(printf("Start mounting\n"));
5255 	error = udf_get_volumeset_space(*disc);
5256 	if (error) return error;
5257 
5258 	UDF_VERBOSE(printf("\teliminating predescessors\n"));
5259 	udf_eliminate_predescessor_volumesets(*disc);
5260 
5261 	UDF_VERBOSE_TABLES(udf_dump_alive_sets());
5262 
5263 	UDF_VERBOSE(printf("\tretrieving logical volume dependencies %p\n", *disc));
5264 	error = udf_get_logical_volumes_supporting_tables(*disc, mnt_flags);
5265 
5266 	UDF_VERBOSE_TABLES(udf_dump_alive_sets());
5267 
5268 	/* insert disc in the disc list */
5269 	SLIST_INSERT_HEAD(&udf_discs_list, *disc, next_disc);
5270 
5271 	return error;
5272 }
5273 
5274 
udf_dismount_disc(struct udf_discinfo * disc)5275 int udf_dismount_disc(struct udf_discinfo *disc) {
5276 	UDF_VERBOSE(printf("Dismounting disc\n"));
5277 	if (!disc->recordable) {
5278 		/* easy way out: it was a read-only system */
5279 		UDF_VERBOSE(printf("\tdismounting readonly disc\n"));
5280 		udf_stop_unix_thread();
5281 		udf_close_disc(disc);
5282 		return 0;
5283 	}
5284 
5285 	/* Sync disc before closing it */
5286 	UDF_VERBOSE(printf("\tsyncing disc\n"));
5287 	udf_sync_disc(disc);
5288 
5289 	/* wait for the disc to idle */
5290 	UDF_VERBOSE(printf("\twait for syncing disc to idle\n"));
5291 	while (!udf_discinfo_check_disc_ready(disc)) {
5292 		sleep(1);
5293 	}
5294 
5295 	/* stop threads and finish writing to it */
5296 	udf_stop_unix_thread();
5297 
5298 	UDF_VERBOSE(printf("\tsignal disc its finished with writing\n"));
5299 	udf_discinfo_finish_writing(disc);
5300 
5301 	/* wait for the disc to idle again */
5302 	UDF_VERBOSE(printf("\twait for final disc idling\n"));
5303 	while (!udf_discinfo_check_disc_ready(disc)) {
5304 		sleep(1);
5305 	}
5306 
5307 	UDF_VERBOSE(printf("\tclose device\n"));
5308 	udf_close_disc(disc);
5309 
5310 	return 0;
5311 }
5312 
5313 
5314 /******************************************************************************************
5315  *
5316  * Directory and other conversion UDF logic
5317  * Move to udf_unix.c / udf_vnops.c one day?
5318  *
5319  ******************************************************************************************/
5320 
udf_translate_icb_filetype_to_dirent_filetype(int udf_filetype)5321 static int udf_translate_icb_filetype_to_dirent_filetype(int udf_filetype) {
5322 	int d_type;
5323 
5324 	switch (udf_filetype) {
5325 		case UDF_ICB_FILETYPE_DIRECTORY :
5326 			d_type = DT_DIR;
5327 			break;
5328 		case UDF_ICB_FILETYPE_STREAMDIR :
5329 			d_type = DT_DIR;
5330 			break;
5331 		case UDF_ICB_FILETYPE_FIFO :
5332 			d_type = DT_FIFO;
5333 			break;
5334 		case UDF_ICB_FILETYPE_CHARDEVICE :
5335 			d_type = DT_CHR;
5336 			break;
5337 		case UDF_ICB_FILETYPE_BLOCKDEVICE :
5338 			d_type = DT_BLK;
5339 			break;
5340 		case UDF_ICB_FILETYPE_RANDOMACCESS :
5341 			d_type = DT_REG;
5342 			break;
5343 		case UDF_ICB_FILETYPE_SYMLINK :
5344 			d_type = DT_LNK;
5345 			break;
5346 		case UDF_ICB_FILETYPE_SOCKET :
5347 			d_type = DT_SOCK;
5348 			break;
5349 		default :
5350 			d_type = DT_UNKNOWN;
5351 			break;
5352 	}
5353 	return d_type;
5354 }
5355 
5356 
5357 /* VOP_GETATTR */
5358 /* allmost NOOP since we remember the stat in the inode */
udf_getattr(struct udf_node * udf_node,struct stat * stat)5359 int udf_getattr(struct udf_node *udf_node, struct stat *stat) {
5360 	*stat = udf_node->stat;
5361 
5362 	/* special: updatables */
5363 	stat->st_nlink   = udf_node->link_cnt;
5364 	stat->st_blocks  = (stat->st_size + 512 -1)/512;	/* blocks are hardcoded 512 bytes/sector in stat :-/ */
5365 	return 0;
5366 }
5367 
5368 
5369 /* VOP_SETATTR */
5370 /* allmost NOOP since we remember the stat in the inode */
5371 /* note VOP_SETATTR can selectively set attrs		*/
udf_setattr(struct udf_node * udf_node,struct stat * stat)5372 int udf_setattr(struct udf_node *udf_node, struct stat *stat) {
5373 	if (!udf_node) return ENOENT;
5374 
5375 	if (udf_open_logvol(udf_node->udf_log_vol))
5376 		return EROFS;
5377 
5378 	/* FIXME please don't just copy everything ... XXX */
5379 	udf_node->stat = *stat;
5380 
5381 	/* not attribute change time */
5382 	udf_set_timespec_now(&udf_node->stat.st_ctimespec);
5383 
5384 	udf_node_mark_dirty(udf_node);
5385 	return 0;
5386 }
5387 
5388 
udf_resync_fid_stream(uint8_t * buffer,uint32_t * pfid_pos,uint32_t max_fid_pos,int * phas_fids)5389 void udf_resync_fid_stream(uint8_t *buffer, uint32_t *pfid_pos, uint32_t max_fid_pos, int *phas_fids) {
5390 	struct fileid_desc *fid;
5391 	uint32_t fid_pos;
5392 	int has_fids;
5393 
5394 	assert(buffer);
5395 	assert(pfid_pos);
5396 	assert(phas_fids);
5397 
5398 	has_fids = 0;
5399 	fid_pos  = *pfid_pos;
5400 	while (!has_fids) {
5401 		while (fid_pos <= max_fid_pos) {
5402 			fid = (struct fileid_desc *) (buffer + fid_pos);
5403 			if (udf_rw16(fid->tag.id) == TAGID_FID)
5404 				break;
5405 			/* fid's can only exist 4 bytes aligned */
5406 			fid_pos += 4;
5407 		}
5408 		if (fid_pos > max_fid_pos) {
5409 			/* shouldn't happen ! to prevent chaos, do nothing */
5410 			/* XXX ought to give a warning? XXX */
5411 			has_fids = 0;
5412 			break;
5413 		} else {
5414 			/* check if we found a valid FID */
5415 			fid = (struct fileid_desc *) (buffer + fid_pos);
5416 			has_fids = (udf_check_tag((union dscrptr *) fid) == 0);
5417 			if (has_fids) {
5418 				assert(udf_rw16(fid->tag.id) == TAGID_FID);
5419 				break;
5420 			}
5421 		}
5422 	}
5423 	*pfid_pos  = fid_pos;
5424 	*phas_fids = has_fids;
5425 }
5426 
5427 
5428 /* read one fid and process it into a dirent and advance to the next */
5429 /* (*fid) has to be allocated a logical block in size, (*dirent) struct dirent length */
udf_read_fid_stream(struct udf_node * dir_node,uint64_t * offset,struct fileid_desc * fid,struct dirent * dirent)5430 int udf_read_fid_stream(struct udf_node *dir_node, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent) {
5431 	struct uio     dir_uio;
5432 	struct iovec   dir_iovec;
5433 	char          *fid_name;
5434 	uint32_t       entry_length, lb_size;
5435 	int            enough, error;
5436 
5437 	assert(fid);
5438 	assert(dirent);
5439 	assert(dir_node);
5440 	assert(offset);
5441 	assert(*offset != 1);
5442 
5443 	lb_size = dir_node->udf_log_vol->lb_size;
5444 	entry_length = 0;
5445 	bzero(dirent, sizeof(struct dirent));
5446 	bzero(fid, lb_size);
5447 
5448 	if (*offset >= (uint64_t) dir_node->stat.st_size)
5449 		return EINVAL;
5450 
5451 	bzero(&dir_uio, sizeof(struct uio));
5452 	dir_uio.uio_rw     = UIO_WRITE;	/* write into this space */
5453 	dir_uio.uio_iovcnt = 1;
5454 	dir_uio.uio_iov    = &dir_iovec;
5455 	dir_iovec.iov_base = fid;
5456 	dir_iovec.iov_len  = lb_size;
5457 	dir_uio.uio_offset = *offset;
5458 	dir_uio.uio_resid  = MIN(dir_node->stat.st_size - (*offset), lb_size);
5459 
5460 	error = udf_read_file_part_uio(dir_node, "file id" /* udf_node->dirent.d_name */, UDF_C_FIDS, &dir_uio);
5461 	if (error)
5462 		return error;
5463 
5464 	/*
5465 	 * Check if we got a whole descriptor.
5466 	 * XXX Try to `resync' directory stream when something is very wrong.
5467 	 *
5468 	 */
5469 	enough = (dir_uio.uio_offset - (*offset) >= UDF_FID_SIZE);
5470 	if (!enough) {
5471 		/* short dir ... */
5472 		return EIO;
5473 	}
5474 
5475 	error = udf_check_tag((union dscrptr *) fid);
5476 	if (!error) {
5477 		entry_length = udf_calc_tag_malloc_size((union dscrptr *) fid, lb_size);
5478 		enough = (dir_uio.uio_offset - (*offset) >= entry_length);
5479 	}
5480 	if (!enough) {
5481 		/* short dir ... */
5482 		return EIO;
5483 	}
5484 
5485 	if (!error) error = udf_check_tag_payload((union dscrptr *) fid);
5486 	if (error) {
5487 		printf("BROKEN DIRECTORY ENTRY\n");
5488 #if 0
5489 		// udf_dump_desc(&fid->tag);
5490 		// udf_dump_fileid(fid);
5491 #endif
5492 		/* RESYNC? */
5493 		/* TODO: use udf_resync_fid_stream */
5494 		return EIO;
5495 	}
5496 
5497 	/* we got a whole and valid descriptor */
5498 	/* create resulting dirent structure */
5499 	fid_name = (char *) fid->data + udf_rw16(fid->l_iu);
5500 	dirent->d_fileno = udf_rw32(fid->icb.impl.im_used.unique_id);	/* only 32 bits salvageable */
5501 #if !defined(__DragonFly__)
5502 	dirent->d_reclen = sizeof(struct dirent);
5503 #endif
5504 	dirent->d_type   = DT_UNKNOWN;
5505 	udf_to_unix_name(dirent->d_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset);
5506 #ifndef NO_DIRENT_NAMLEN
5507 	dirent->d_namlen = strlen(dirent->d_name);
5508 #endif
5509 
5510 	if (fid->file_char & UDF_FILE_CHAR_DIR) dirent->d_type = DT_DIR;
5511 	if (fid->file_char & UDF_FILE_CHAR_PAR) strcpy(dirent->d_name, "..");
5512 
5513 	/* advance */
5514 	*offset += entry_length;
5515 
5516 	return error;
5517 }
5518 
5519 
5520 /* VOP_READDIR */
5521 /* read in dirent's until the result_uio can't hold another */
udf_readdir(struct udf_node * dir_node,struct uio * result_uio,int * eof_res)5522 int udf_readdir(struct udf_node *dir_node, struct uio *result_uio, int *eof_res /* int *cookies, int ncookies */) {
5523 	struct fileid_desc *fid;
5524 	struct dirent  dirent;
5525 	uint64_t diroffset, transoffset;
5526 	uint32_t lb_size;
5527 	int      eof;
5528 	int      error;
5529 
5530 	assert(eof_res);
5531 	if (!dir_node)
5532 		return EINVAL;
5533 	if (!dir_node->udf_log_vol)
5534 		return EINVAL;
5535 
5536 	assert(result_uio->uio_resid >= sizeof(struct dirent));
5537 	lb_size = dir_node->udf_log_vol->lb_size;
5538 
5539 	fid = malloc(lb_size);
5540 	if (!fid) return ENOMEM;
5541 
5542 	/* check if we ought to insert dummy `.' node */
5543 	if (result_uio->uio_offset == 0) {
5544 		bzero(&dirent, sizeof(struct dirent));
5545 		strcpy(dirent.d_name, ".");
5546 		dirent.d_type   = DT_DIR;
5547 #ifndef NO_DIRENT_NAMLEN
5548 		dirent.d_namlen = 2;
5549 #endif
5550 		uiomove(&dirent, sizeof(struct dirent), result_uio);
5551 
5552 		/* mark with magic value (yeah it suxxs) that we have done the dummy */
5553 		result_uio->uio_offset = 1;
5554 	}
5555 
5556 	/* start directory reading */
5557 	diroffset   = result_uio->uio_offset;
5558 	transoffset = diroffset;
5559 	while (diroffset < (uint64_t) dir_node->stat.st_size) {
5560 		/* read just the offset when its flagged */
5561 		if (diroffset == 1) {
5562 			diroffset = result_uio->uio_offset = 0;
5563 		}
5564 
5565 		/* read in FIDs */
5566 		error = udf_read_fid_stream(dir_node, &diroffset, fid, &dirent);
5567 		if (error) {
5568 			printf("Error while reading directory file: %s\n", strerror(error));
5569 			free(fid);
5570 			return error;
5571 		}
5572 
5573 		/* if there is not enough space for the dirent break off read */
5574 		if (result_uio->uio_resid < sizeof(struct dirent))
5575 			break;
5576 
5577 		/* remember the last entry we transfered */
5578 		transoffset = diroffset;
5579 
5580 		/* skip deleted entries */
5581 		if (fid->file_char & UDF_FILE_CHAR_DEL)
5582 			continue;
5583 
5584 		/* skip not visible entries */
5585 		if (fid->file_char & UDF_FILE_CHAR_VIS)
5586 			continue;
5587 
5588 		uiomove(&dirent, sizeof(struct dirent), result_uio);
5589 	}
5590 
5591 	/* pass on last transfered offset */
5592 	result_uio->uio_offset = transoffset;
5593 
5594 	free(fid);
5595 
5596 	eof = (result_uio->uio_offset >= (int64_t) dir_node->stat.st_size);
5597 	if (eof_res) *eof_res = 1;
5598 		*eof_res = eof;
5599 
5600 	return 0;
5601 }
5602 
5603 
5604 static int
dirhash_fill(struct udf_node * dir_node)5605 dirhash_fill(struct udf_node *dir_node)
5606 {
5607 	struct dirhash *dirh;
5608 	struct fileid_desc *fid;
5609 	struct dirent *dirent;
5610 	uint64_t file_size, pre_diroffset, diroffset;
5611 	uint32_t lb_size;
5612 	int error;
5613 
5614 	/* make sure we have a dirhash to work on */
5615 	dirh = dir_node->dir_hash;
5616 	assert(dirh);
5617 	assert(dirh->refcnt > 0);
5618 
5619 	if (dirh->flags & DIRH_BROKEN)
5620 		return EIO;
5621 	if (dirh->flags & DIRH_COMPLETE)
5622 		return 0;
5623 
5624 	/* make sure we have a clean dirhash to add to */
5625 	dirhash_purge_entries(dirh);
5626 
5627 	/* get directory filesize */
5628 	file_size = dir_node->stat.st_size;
5629 
5630 	/* allocate temporary space for fid */
5631 	lb_size = dir_node->udf_log_vol->lb_size;
5632 	fid = malloc(lb_size);
5633 	assert(fid);
5634 
5635 	/* allocate temporary space for dirent */
5636 	dirent = malloc(sizeof(struct dirent));
5637 	assert(dirent);
5638 
5639 	error = 0;
5640 	diroffset = 0;
5641 	while (diroffset < file_size) {
5642 		/* transfer a new fid/dirent */
5643 		pre_diroffset = diroffset;
5644 		error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent);
5645 		if (error) {
5646 			/* TODO what to do? continue but not add? */
5647 			dirh->flags |= DIRH_BROKEN;
5648 			dirhash_purge_entries(dirh);
5649 			break;
5650 		}
5651 
5652 		if ((fid->file_char & UDF_FILE_CHAR_DEL)) {
5653 			/* register deleted extent for reuse */
5654 			dirhash_enter_freed(dirh, pre_diroffset,
5655 				udf_fidsize(fid));
5656 		} else {
5657 			/* append to the dirhash */
5658 			dirhash_enter(dirh, dirent, pre_diroffset,
5659 				udf_fidsize(fid), 0);
5660 
5661 			/* XXX speedup HACK: preread in our nodes to compensate for too lazy backend */
5662 			{
5663 				struct udf_node *res_node;
5664 				error = udf_readin_udf_node(dir_node, &fid->icb, fid, &res_node);
5665 			}
5666 		}
5667 	}
5668 	dirh->flags |= DIRH_COMPLETE;
5669 
5670 	free(fid);
5671 	free(dirent);
5672 
5673 	return error;
5674 }
5675 
5676 
5677 /* XXX yes, move namelen to unsigned int */
udf_lookup_name_in_dir(struct udf_node * dir_node,char * name,int namelen,struct long_ad * icb_loc,struct fileid_desc * fid,int * found)5678 int udf_lookup_name_in_dir(struct udf_node *dir_node, char *name, int namelen, struct long_ad *icb_loc, struct fileid_desc *fid, int *found) {
5679 	struct dirhash       *dirh;
5680 	struct dirhash_entry *dirh_ep;
5681 	struct dirent *dirent;
5682 	uint64_t diroffset;
5683 	int hit, error;
5684 
5685 	/* set default return */
5686 	*found = 0;
5687 
5688 	/* get our dirhash and make sure its read in */
5689 	dirhash_get(&dir_node->dir_hash);
5690 	error = dirhash_fill(dir_node);
5691 	if (error) {
5692 		dirhash_put(dir_node->dir_hash);
5693 		return error;
5694 	}
5695 	dirh = dir_node->dir_hash;
5696 
5697 	/* allocate temporary space for dirent */
5698 	dirent  = malloc(sizeof(struct dirent));
5699 	if (!dirent)
5700 		return ENOMEM;
5701 
5702 	DEBUG(printf("dirhash_lookup looking for `%*.*s`\n",
5703 		namelen, namelen, name));
5704 
5705 	/* search our dirhash hits */
5706 	memset(icb_loc, 0, sizeof(*icb_loc));
5707 	dirh_ep = NULL;
5708 	for (;;) {
5709 		hit = dirhash_lookup(dirh, name, namelen, &dirh_ep);
5710 		/* if no hit, abort the search */
5711 		if (!hit)
5712 			break;
5713 
5714 		/* check this hit */
5715 		diroffset = dirh_ep->offset;
5716 
5717 		/* transfer a new fid/dirent */
5718 		error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent);
5719 		if (error)
5720 			break;
5721 
5722 		DEBUG(printf("dirhash_lookup\tchecking `%*.*s`\n",
5723 			(int) DIRENT_NAMLEN(dirent),  (int) DIRENT_NAMLEN(dirent), dirent->d_name));
5724 
5725 		/* see if its our entry */
5726 		assert(DIRENT_NAMLEN(dirent) == (unsigned int) namelen);
5727 		if (strncmp(dirent->d_name, name, namelen) == 0) {
5728 			*found = 1;
5729 			*icb_loc = fid->icb;
5730 			break;
5731 		}
5732 	}
5733 	free(dirent);
5734 
5735 	dirhash_put(dir_node->dir_hash);
5736 
5737 	return error;
5738 }
5739 
5740 
udf_count_direntries(struct udf_node * dir_node,int count_dotdot,uint32_t * dir_entries)5741 static int udf_count_direntries(struct udf_node *dir_node, int count_dotdot, uint32_t *dir_entries) {
5742 	struct fileid_desc *fid;
5743 	struct dirent  dirent;
5744 	uint64_t pos;
5745 	uint32_t lb_size;
5746 	int      eof;
5747 	int      error;
5748 
5749 	if (!dir_node) return EINVAL;
5750 	lb_size = dir_node->udf_log_vol->lb_size;
5751 
5752 	/* count all directory entries with optional the dotdot too */
5753 	/* only defined in directories XXX DT_COMP also possible XXX */
5754 	if ((dir_node->stat.st_mode & S_IFDIR) == 0)
5755 		return ENOTDIR;
5756 
5757 	/* get space to read fid in */
5758 	fid = malloc(lb_size);
5759 	if (!fid) return ENOMEM;
5760 
5761 	/* start directory reading */
5762 	*dir_entries = 0;
5763 	pos = 0;
5764 
5765 	eof = (pos == (uint64_t) dir_node->stat.st_size);
5766 	while (!eof) {
5767 		/* read in FIDs */
5768 		error = udf_read_fid_stream(dir_node, &pos, fid, &dirent);
5769 		if (error) {
5770 			printf("Error while counting directory entries : %s\n", strerror(error));
5771 			free(fid);
5772 			return error;
5773 		}
5774 
5775 		/* process this FID/dirent */
5776 		if ((fid->file_char & UDF_FILE_CHAR_DEL) == 0) {
5777 			if (fid->file_char & UDF_FILE_CHAR_PAR) {
5778 				if (count_dotdot) *dir_entries = *dir_entries + 1;
5779 			} else {
5780 				*dir_entries = *dir_entries + 1;
5781 			}
5782 		}
5783 		/* pos is automatically advanced */
5784 		eof = (pos == (uint64_t) dir_node->stat.st_size);
5785 	}
5786 	/* end of directory */
5787 	free(fid);
5788 
5789 	return 0;
5790 }
5791 
5792 
udf_writeout_fid_info(struct udf_node * dir_node,struct fileid_desc * fid,uint64_t offset,uint16_t fid_len)5793 static int udf_writeout_fid_info(struct udf_node *dir_node, struct fileid_desc *fid, uint64_t offset, uint16_t fid_len) {
5794 	struct uio     uio;
5795 	struct iovec   iovec;
5796 	int flags;
5797 
5798 	bzero(&uio, sizeof(struct uio));
5799 	uio.uio_rw     = UIO_READ;	/* read from this space */
5800 	uio.uio_iovcnt = 1;
5801 	uio.uio_iov    = &iovec;
5802 	iovec.iov_base = fid;
5803 	iovec.iov_len  = fid_len;
5804 	uio.uio_offset = offset;
5805 	uio.uio_resid  = fid_len;
5806 
5807 	flags = UDF_C_FIDS;
5808 	return udf_write_file_part_uio(dir_node, "file id.", flags, &uio);
5809 }
5810 
5811 
5812 /* search for a space to record the fid in, not checking if it is allready in it ! */
5813 /* ALERT: not to be used to update a fid ... use writeout_fid_info for that        */
5814 /* ONLY used by udf_create_directory_entry */
udf_insert_fid_info(struct udf_node * dir_node,struct udf_node * udf_node,struct fileid_desc * i_fid,uint16_t fidsize)5815 static int udf_insert_fid_info(struct udf_node *dir_node, struct udf_node *udf_node, struct fileid_desc *i_fid, uint16_t fidsize) {
5816 	struct dirhash       *dirh;
5817 	struct dirhash_entry *dirh_ep;
5818 	struct fileid_desc   *fid;
5819 	struct dirent dirent;
5820 	uint64_t dir_size, fid_pos, chosen_fid_pos, end_fid_pos;
5821 	uint32_t this_fidsize, chosen_size;
5822 	uint32_t lb_size, lb_rest;
5823 	uint32_t  size_diff, chosen_size_diff;
5824 	char    *fid_name;
5825 	int      descr_ver, hit, error;
5826 
5827 	udf_node = udf_node;	/* passed only for printing diagnostic info if required */
5828 
5829 	if (!dir_node)
5830 		return EINVAL;
5831 
5832 	/* only defined in directories XXX DT_COMP also possible XXX */
5833 	if ((dir_node->stat.st_mode & S_IFDIR) == 0)
5834 		return ENOTDIR;
5835 
5836 	/* needs to be 4 bytes aligned to be legal! if not, something is seriously wrong so abort */
5837 	assert((fidsize & 3) == 0);
5838 
5839 	/* get our dirhash and make sure its read in */
5840 	dirhash_get(&dir_node->dir_hash);
5841 	error = dirhash_fill(dir_node);
5842 	if (error) {
5843 		dirhash_put(dir_node->dir_hash);
5844 		return error;
5845 	}
5846 	dirh = dir_node->dir_hash;
5847 
5848 	/* get info */
5849 	lb_size   = dir_node->udf_log_vol->lb_size;
5850 	dir_size  = dir_node->stat.st_size;
5851 	descr_ver = udf_rw16(dir_node->udf_log_vol->log_vol->tag.descriptor_ver);
5852 
5853 	/* get space to read fid in */
5854 	fid = malloc(lb_size);
5855 	if (!fid)
5856 		return ENOMEM;
5857 
5858 	/* find position that will fit the FID */
5859 	chosen_fid_pos   = dir_size;
5860 	chosen_size      = 0;
5861 	chosen_size_diff = UINT_MAX;
5862 
5863 	/* shut up gcc */
5864 #ifndef NO_DIRENT_NAMLEN
5865 	dirent.d_namlen = 0;
5866 #endif
5867 
5868 	/* search our dirhash hits */
5869 	error = 0;
5870 	dirh_ep = NULL;
5871 	for (;;) {
5872 		hit = dirhash_lookup_freed(dirh, fidsize, &dirh_ep);
5873 		/* if no hit, abort the search */
5874 		if (!hit)
5875 			break;
5876 
5877 		/* check this hit for size */
5878 		this_fidsize = dirh_ep->entry_size;
5879 
5880 		/* check this hit */
5881 		fid_pos     = dirh_ep->offset;
5882 		end_fid_pos = fid_pos + this_fidsize;
5883 		size_diff   = this_fidsize - fidsize;
5884 		lb_rest = lb_size - (end_fid_pos % lb_size);
5885 
5886 		/* select if not splitting the tag and its smaller */
5887 		if ((size_diff <= chosen_size_diff) &&
5888 			(lb_rest >= sizeof(struct desc_tag)))
5889 		{
5890 			/* UDF 2.3.4.2+3 specifies rules for iu size */
5891 			if ((size_diff == 0) || (size_diff >= 32)) {
5892 				chosen_fid_pos   = fid_pos;
5893 				chosen_size      = this_fidsize;
5894 				chosen_size_diff = size_diff;
5895 			}
5896 		}
5897 	}
5898 
5899 	/* extend directory if no other candidate found */
5900 	if (chosen_size == 0) {
5901 		chosen_fid_pos   = dir_size;
5902 		chosen_size      = fidsize;
5903 
5904 		/* special case UDF 2.00+ 2.3.4.4, no splitting up fid tag */
5905 		if (dir_node->addr_type == UDF_ICB_INTERN_ALLOC) {
5906 			/* pre-grow directory to see if we're to switch */
5907 			// udf_grow_node(dir_node, dir_size + chosen_size);
5908 			error = udf_truncate_node(dir_node, chosen_fid_pos + chosen_size);
5909 			assert(!error);
5910 		}
5911 
5912 		/* make sure the next fid desc_tag won't be splitted */
5913 		if (dir_node->addr_type != UDF_ICB_INTERN_ALLOC) {
5914 			end_fid_pos = chosen_fid_pos + chosen_size;
5915 			lb_rest = lb_size - (end_fid_pos % lb_size);
5916 
5917 			/* pad with implementation use regid if needed */
5918 			if (lb_rest < sizeof(struct desc_tag))
5919 				chosen_size += 32;
5920 		}
5921 	}
5922 	chosen_size_diff = chosen_size - fidsize;
5923 
5924 	/* populate the FID */
5925 	memset(fid, 0, lb_size);
5926 	udf_init_desc_tag(&fid->tag, TAGID_FID, descr_ver, 1);		/* tag serial number    */
5927 	fid->file_version_num    = i_fid->file_version_num;
5928 	fid->file_char           = i_fid->file_char;
5929 	fid->icb                 = i_fid->icb;
5930 	fid->l_iu                = udf_rw16(0);
5931 
5932 	if (chosen_size > fidsize) {
5933 		/* insert implementation-use regid to space it correctly */
5934 		fid->l_iu = udf_rw16(chosen_size_diff);
5935 
5936 		/* set implementation use */
5937 		udf_set_imp_id((struct regid *) fid->data);
5938 	}
5939 
5940 	/* copy name */
5941 	fid->l_fi = i_fid->l_fi;
5942 	memcpy(fid->data + udf_rw16(fid->l_iu), i_fid->data, fid->l_fi);
5943 
5944 	fid->tag.desc_crc_len = chosen_size - UDF_DESC_TAG_LENGTH;
5945 
5946 	/* writeout modified piece */
5947 	udf_validate_tag_and_crc_sums((union dscrptr *) fid);
5948 	error = udf_writeout_fid_info(dir_node, fid, chosen_fid_pos, chosen_size);
5949 	assert(!error);
5950 
5951 	/* append to the dirhash */
5952 	fid_name = (char *) fid->data + udf_rw16(fid->l_iu);
5953 	dirent.d_fileno = udf_rw32(fid->icb.impl.im_used.unique_id);	/* only 32 bits salvageable */
5954 #if !defined(__DragonFly__)
5955 	dirent.d_reclen = sizeof(struct dirent);
5956 #endif
5957 	dirent.d_type   = DT_UNKNOWN;
5958 	udf_to_unix_name(dirent.d_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset);
5959 #ifndef NO_DIRENT_NAMLEN
5960 	dirent.d_namlen = strlen(dirent.d_name);
5961 #endif
5962 
5963 	if (fid->file_char & UDF_FILE_CHAR_DIR) dirent.d_type = DT_DIR;
5964 	if (fid->file_char & UDF_FILE_CHAR_PAR) strcpy(dirent.d_name, "..");
5965 
5966 	dirhash_enter(dirh, &dirent, chosen_fid_pos, udf_fidsize(fid), 1);
5967 
5968 	free(fid);
5969 	dirhash_put(dir_node->dir_hash);
5970 
5971 	return error;
5972 }
5973 
5974 
5975 /* create a file in the given directory with the given name and attributes using udf's file_char and udf'd filetype */
5976 /* note
5977  * 1) that with `refering' node specified its effectively `link()'
5978  * 2) that with `refering' node specified, `filetype' is discarded as it ought to be the same as the `refering' one
5979  *
5980  * XXX this function needs to be splitted into node creation and directory
5981  * attachment; its now doing both in one go.
5982  */
udf_create_directory_entry(struct udf_node * dir_node,char * name,int filetype,int filechar,struct udf_node * refering,struct stat * stat,struct udf_node ** new_node)5983 int udf_create_directory_entry(struct udf_node *dir_node, char *name, int filetype, int filechar, struct udf_node *refering, struct stat *stat, struct udf_node **new_node) {
5984 	struct udf_allocentry *alloc_entry;
5985 	struct udf_log_vol    *udf_log_vol;
5986 	struct udf_node       *udf_node;
5987 	struct charspec        osta_charspec;
5988 	struct fileid_desc    *fid;
5989 	struct long_ad         icb_loc;
5990 	uint32_t     lb_num, lb_size;
5991 	uint16_t     vpart_num, descr_ver, len;
5992 	int          found, error;
5993 
5994 	assert(dir_node);
5995 	assert(name);
5996 	assert(dir_node->udf_log_vol);
5997 	udf_log_vol = dir_node->udf_log_vol;
5998 	lb_size     = udf_log_vol->lb_size;
5999 	descr_ver   = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver);
6000 
6001 	*new_node = NULL;
6002 
6003 	/* lookup if it allready exists (sanity mainly) */
6004 	fid = malloc(lb_size);
6005 	assert(fid);
6006 
6007 	error = udf_lookup_name_in_dir(dir_node, name, strlen(name), &icb_loc, fid, &found);
6008 	if (!error && found) {
6009 		/* it existed! allready there */
6010 		free(fid);
6011 		return EEXIST;
6012 	}
6013 
6014 	if (!refering) {
6015 		/*
6016 		 * Get ourselves an empty node and space to record file
6017 		 * descriptor in.
6018 		 */
6019 		error = udf_init_udf_node(dir_node->mountpoint, udf_log_vol, "New direntry", &udf_node);
6020 		if (error) {
6021 			free(fid);
6022 			return error;
6023 		}
6024 
6025 		udf_node->udf_filetype = filetype;
6026 		udf_node->udf_filechar = filechar;
6027 		udf_node->unique_id = udf_increment_unique_id(udf_log_vol);
6028 
6029 		/* snif */
6030 		error = udf_allocate_udf_node_on_disc(udf_node);
6031 		if (error) {
6032 			assert(udf_node != dir_node);
6033 			udf_dispose_udf_node(udf_node);
6034 			free(fid);
6035 			return error;
6036 		}
6037 
6038 		udf_node->stat = *stat;
6039 		/* note passed creation times; do sanitise them */
6040 #ifndef NO_STAT_BIRTHTIME
6041 		if (udf_insanetimespec(&stat->st_birthtimespec))
6042 			udf_set_timespec_now(&udf_node->stat.st_birthtimespec);
6043 #endif
6044 		if (udf_insanetimespec(&stat->st_ctimespec))
6045 			udf_set_timespec_now(&udf_node->stat.st_ctimespec);
6046 		if (udf_insanetimespec(&stat->st_atimespec))
6047 			udf_set_timespec_now(&udf_node->stat.st_atimespec);
6048 		if (udf_insanetimespec(&stat->st_mtimespec))
6049 			udf_set_timespec_now(&udf_node->stat.st_mtimespec);
6050 	} else {
6051 		/* refering->ignore passed stat info */
6052 		udf_node = refering;
6053 		filetype = udf_node->udf_filetype;
6054 
6055 		/* linking changes metadata modification */
6056 		udf_set_timespec_now(&udf_node->stat.st_ctimespec);
6057 	}
6058 	alloc_entry = TAILQ_FIRST(&udf_node->dscr_allocs);
6059 	vpart_num   = alloc_entry->vpart_num;
6060 	lb_num      = alloc_entry->lb_num;
6061 
6062 	/* build up new directory entry */
6063 	memset(fid, 0, lb_size);
6064 	udf_osta_charset(&osta_charspec);
6065 	udf_init_desc_tag(&fid->tag, TAGID_FID, descr_ver, 1);		/* tag serial number    */
6066 
6067 	if (filechar & UDF_FILE_CHAR_PAR) {
6068 		/* parent or `..' is not allowed to have a name length ... wierd but ok */
6069 		fid->l_fi = 0;
6070 	} else {
6071 		unix_to_udf_name((char *) fid->data, name, &fid->l_fi, &osta_charspec);
6072 	}
6073 	fid->file_version_num = udf_rw16(1);					/* new file/dir; version starts at 1 */
6074 	fid->file_char        = filechar;					/* what is it                        */
6075 	fid->l_iu             = udf_rw32(0);					/* no impl. use                      */
6076 	fid->icb.len          = udf_rw32(lb_size);				/* fill in location                  */
6077 	fid->icb.loc.part_num = udf_rw16(vpart_num);
6078 	fid->icb.loc.lb_num   = udf_rw32(lb_num);
6079 
6080 	/* fill in lower 32 bits of unique ID (UDF 3/3.2.2.1) in the impl use part of the FID's long_ad */
6081 	fid->icb.impl.im_used.unique_id = udf_rw32(((udf_node->unique_id << 32) >> 32));
6082 
6083 	/* calculate minimum size needed for directory entry */
6084 	len = UDF_FID_SIZE + fid->l_fi;
6085 	len = (len + 3) & ~3;
6086 	fid->tag.desc_crc_len = udf_rw16(len - UDF_DESC_TAG_LENGTH);
6087 
6088 	error = udf_insert_fid_info(dir_node, udf_node, fid, len);
6089 	free(fid);	/* Ahum... easily forgotten here */
6090 
6091 	if (error) {
6092 		fprintf(stderr, "UDF: fid insertion failed : %s\n", strerror(error));
6093 		if (!refering)
6094 			udf_dispose_udf_node(udf_node);
6095 		return error;
6096 	}
6097 
6098 	if (udf_node) {
6099 		/* only insert file in hashlist if its not an explicit reference */
6100 		if (!refering) {
6101 			udf_insert_node_in_hash(udf_node);
6102 		} else {
6103 			refering->link_cnt++;
6104 			udf_node_mark_dirty(refering);
6105 		}
6106 		udf_node_mark_dirty(udf_node);
6107 	}
6108 
6109 	*new_node = udf_node;
6110 	return error;
6111 }
6112 
6113 
6114 /*
6115  * Rename file from old_name to new_name. `present' is the file to be replaced
6116  * if found present allready.  Care should be taken that the directory tree is
6117  * kept intact. To prevent this no path should be possible from the new parent
6118  * to the node to be renamed if it considers a directory and the new_parent is
6119  * not equal to the old parent.
6120  */
6121 /*
6122  * VOP_RENAME(struct vnode *fdvp, struct vnode *vp,
6123  *     struct componentname *fcnp, struct componentname *tdvp,
6124  *     struct vnode *tvp, struct componentname *tcnp
6125  *     );
6126  */
udf_rename(struct udf_node * old_parent,struct udf_node * rename_me,char * old_name,struct udf_node * new_parent,struct udf_node * present,char * new_name)6127 int udf_rename(struct udf_node *old_parent, struct udf_node *rename_me, char *old_name, struct udf_node *new_parent, struct udf_node *present, char *new_name) {
6128 	struct udf_node *new_node;
6129 	int error;
6130 
6131 	/* sanity */
6132 	if (!old_parent) return ENOENT;
6133 	if (!new_parent) return ENOENT;
6134 	if (!rename_me)  return ENOENT;
6135 	if (!(old_parent->stat.st_mode & S_IFDIR)) return ENOTDIR;
6136 	if (!(new_parent->stat.st_mode & S_IFDIR)) return ENOTDIR;
6137 
6138 	if (udf_open_logvol(old_parent->udf_log_vol))
6139 		return EROFS;
6140 
6141 	if (udf_open_logvol(new_parent->udf_log_vol))
6142 		return EROFS;
6143 
6144 	if ((present && (present->stat.st_mode & S_IFDIR)) || (old_parent != new_parent)) {
6145 		/* cross directory moves */
6146 		fprintf(stderr, "Cross directory renaming is not implemented yet.\n");
6147 		return ENOTSUP;
6148 	}
6149 
6150 	/* if it was present, delete old contents; reference counting is done  */
6151 	if (present) {
6152 		/* TODO what about non dir, non file entries? */
6153 		if (present->stat.st_mode & S_IFDIR) {
6154 			error = udf_remove_directory(new_parent, present, new_name);
6155 		} else {
6156 			error = udf_remove_file(new_parent, present, new_name);
6157 		}
6158 		if (error)
6159 			return error;
6160 	}
6161 
6162 	/* insert new_name HARD-linked to the `rename_me' node */
6163 	error = udf_create_directory_entry(new_parent, new_name, rename_me->udf_filetype, rename_me->udf_filechar, rename_me, NULL, &new_node);
6164 	if (error) return error;
6165 
6166 	/* extra sanity */
6167 	if (!new_node) return ENOENT;
6168 
6169 	/* 3) remove old link and mark directories dirty */
6170 	error = udf_remove_directory_entry(old_parent, rename_me, old_name);
6171 	udf_node_mark_dirty(old_parent);
6172 	udf_node_mark_dirty(new_parent);
6173 
6174 	return error;
6175 }
6176 
6177 
6178 /* VOP_CREATE */
udf_create_file(struct udf_node * dir_node,char * componentname,struct stat * stat,struct udf_node ** new_node)6179 int udf_create_file(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node) {
6180 	struct udf_log_vol *udf_log_vol;
6181 	struct udf_node *udf_node;
6182 	uint32_t lb_size;
6183 	int error;
6184 
6185 	if (!dir_node) return EINVAL;
6186 
6187 	udf_log_vol = dir_node->udf_log_vol;
6188 	if (!udf_log_vol) return EINVAL;
6189 
6190 	lb_size = udf_log_vol->lb_size;
6191 	if (!udf_confirm_freespace(udf_log_vol, UDF_C_NODE, lb_size))
6192 		return ENOSPC;
6193 
6194 	if (udf_open_logvol(dir_node->udf_log_vol))
6195 		return EROFS;
6196 
6197 	error = udf_create_directory_entry(dir_node, componentname, UDF_ICB_FILETYPE_RANDOMACCESS, 0, NULL, stat, new_node);
6198 	if ((!error) && (*new_node)) {
6199 		udf_node = *new_node;
6200 		/* update sizes */
6201 		udf_node->stat.st_size    = 0;
6202 		udf_node->stat.st_blksize = dir_node->udf_log_vol->lb_size;
6203 		udf_node->stat.st_blocks  = 0;		/* not 1? */
6204 
6205 		udf_node->udf_log_vol->num_files++;
6206 
6207 		udf_node_mark_dirty(udf_node);
6208 	}
6209 	return error;
6210 }
6211 
6212 
6213 /* VOP_MKDIR */
udf_create_directory(struct udf_node * dir_node,char * componentname,struct stat * stat,struct udf_node ** new_node)6214 int udf_create_directory(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node) {
6215 	struct udf_log_vol *udf_log_vol;
6216 	struct udf_node *udf_node, *dummy_node;
6217 	uint32_t lb_size;
6218 	int error;
6219 
6220 	if (!dir_node) return EINVAL;
6221 
6222 	udf_log_vol = dir_node->udf_log_vol;
6223 	if (!udf_log_vol) return EINVAL;
6224 
6225 	lb_size = udf_log_vol->lb_size;
6226 	if (!udf_confirm_freespace(udf_log_vol, UDF_C_NODE, 2*lb_size))
6227 		return ENOSPC;
6228 
6229 	if (udf_open_logvol(dir_node->udf_log_vol))
6230 		return EROFS;
6231 
6232 	stat->st_mode |= S_IFDIR;
6233 	error = udf_create_directory_entry(dir_node, componentname, UDF_ICB_FILETYPE_DIRECTORY, UDF_FILE_CHAR_DIR, NULL, stat, new_node);
6234 	if ((!error) && (*new_node)) {
6235 		udf_node = *new_node;
6236 		/* update sizes */
6237 		udf_node->stat.st_size    = 0;
6238 		udf_node->stat.st_blksize = dir_node->udf_log_vol->lb_size;
6239 		udf_node->stat.st_blocks  = 0;		/* not 1? */
6240 
6241 		udf_node->udf_log_vol->num_directories++;
6242 
6243 		udf_node_mark_dirty(udf_node);
6244 
6245 		/* create `..' directory entry */
6246 		error = udf_create_directory_entry(udf_node, "..", UDF_ICB_FILETYPE_DIRECTORY, UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR, dir_node, stat, &dummy_node);
6247 		if (error) {
6248 			/* use of _prim for dir counting might not go well due to aborted creation */
6249 			error = udf_remove_directory_prim(dir_node, udf_node, componentname);
6250 		}
6251 	}
6252 	return error;
6253 }
6254 
6255 
6256 
6257 /* really deletes all space referenced to this udf node including descriptor spaces and removes it from the administration */
udf_unlink_node(struct udf_node * udf_node)6258 int udf_unlink_node(struct udf_node *udf_node) {
6259 	struct udf_allocentry *alloc_entry;
6260 	uint32_t lbnum, len;
6261 	uint16_t vpart;
6262 	int error;
6263 
6264 	/* just in case its called from outside */
6265 	if (udf_open_logvol(udf_node->udf_log_vol))
6266 		return EROFS;
6267 
6268 	/* unlinking changes metadata modification */
6269 	udf_set_timespec_now(&udf_node->stat.st_ctimespec);
6270 
6271 	udf_node->link_cnt--;
6272 	udf_node_mark_dirty(udf_node);
6273 	if (udf_node->link_cnt > 0)
6274 		return 0;
6275 
6276 	/* trunc node */
6277 	udf_truncate_node(udf_node, (uint64_t) 0);	/* get rid of file contents	*/
6278 
6279 	/* free descriptors from dscr_allocs queue */
6280 	TAILQ_FOREACH(alloc_entry, &udf_node->dscr_allocs, next_alloc) {
6281 		vpart = alloc_entry->vpart_num;
6282 		lbnum = alloc_entry->lb_num;
6283 		/* flags = alloc_entry->flags; */
6284 		len   = alloc_entry->len;
6285 
6286 		error = udf_release_lbs(udf_node->udf_log_vol, vpart, lbnum, len);
6287 		/* what if an error occures? */
6288 		assert(error == 0);
6289 	}
6290 
6291 	/* delete from administration */
6292 	udf_dispose_udf_node(udf_node);
6293 
6294 	return 0;
6295 }
6296 
6297 
6298 /* NOTE: Dont use the EXTENT erased part; its for non sequential WORM only */
6299 /*       UDF 2.3.10.1, ECMA 4/48.14.1.1 */
6300 /*       fid->icb.impl.im_used.flags = udf_rw16(UDF_ADIMP_FLAGS_EXTENT_ERASED); */
6301 
udf_remove_directory_entry(struct udf_node * dir_node,struct udf_node * udf_node,char * name)6302 static int udf_remove_directory_entry(struct udf_node *dir_node, struct udf_node *udf_node, char *name) {
6303 	struct dirhash       *dirh;
6304 	struct dirhash_entry *dirh_ep;
6305 	struct fileid_desc *fid;
6306 	struct dirent *dirent;
6307 	uint64_t diroffset;
6308 	uint32_t lb_size, namelen, fidsize;
6309 	int      hit, found;
6310 	int      error;
6311 
6312 	assert(dir_node);
6313 	assert(udf_node);
6314 	assert(udf_node->udf_log_vol);
6315 	assert(name);
6316 
6317 	namelen = strlen(name);
6318 	if (strncmp(name, "..", 3) == 0) {
6319 		printf("Asked to remove `..' parent directory identifier; not allowed!\n");
6320 		return ENOENT;
6321 	}
6322 
6323 	if (strncmp(name, ".", 2) == 0) {
6324 		printf("Asked to remove `.' current directory identifier; not allowed!\n");
6325 		return ENOENT;
6326 	}
6327 
6328 	/* only lookup in directories XXX DT_COMP also possible XXX */
6329 	if ((dir_node->stat.st_mode & S_IFDIR) == 0)
6330 		return ENOTDIR;
6331 
6332 	/* get our dirhash and make sure its read in */
6333 	dirhash_get(&dir_node->dir_hash);
6334 	error = dirhash_fill(dir_node);
6335 	if (error) {
6336 		dirhash_put(dir_node->dir_hash);
6337 		return error;
6338 	}
6339 	dirh = dir_node->dir_hash;
6340 
6341 	/* allocate temporary space for fid */
6342 	lb_size = udf_node->udf_log_vol->lb_size;
6343 	fid     = malloc(lb_size);
6344 	dirent  = malloc(sizeof(struct dirent));
6345 	if (!fid || !dirent) {
6346 		error = ENOMEM;
6347 		goto error_out;
6348 	}
6349 
6350 	/* search our dirhash hits */
6351 	found = 0;
6352 	dirh_ep = NULL;
6353 	for (;;) {
6354 		hit = dirhash_lookup(dirh, name, namelen, &dirh_ep);
6355 		/* if no hit, abort the search */
6356 		if (!hit)
6357 			break;
6358 
6359 		/* check this hit */
6360 		diroffset = dirh_ep->offset;
6361 
6362 		/* transfer a new fid/dirent */
6363 		error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent);
6364 		if (error)
6365 			break;
6366 
6367 		/* see if its our entry */
6368 		assert(DIRENT_NAMLEN(dirent) == namelen);
6369 		if (strncmp(dirent->d_name, name, namelen) == 0) {
6370 			found = 1;
6371 			break;
6372 		}
6373 	}
6374 
6375 	if (!found)
6376 		error = ENOENT;
6377 	if (error)
6378 		goto error_out;
6379 
6380 	/* get size of fid and compensate for the read_fid_stream advance */
6381 	fidsize    = udf_fidsize(fid);
6382 	diroffset -= fidsize;
6383 
6384 	/* mark fid as deleted */
6385 	fid->file_char |= UDF_FILE_CHAR_DEL;
6386 	bzero(&fid->icb, sizeof(struct long_ad));
6387 	udf_validate_tag_and_crc_sums((union dscrptr *) fid);
6388 	udf_writeout_fid_info(dir_node, fid, diroffset, fidsize);
6389 
6390 	/* remove from the dirhash */
6391 	dirhash_mark_freed(dirh, dirh_ep, dirent);
6392 
6393 	/* delete node and its administration if refcount indicates so */
6394 	udf_unlink_node(udf_node);
6395 
6396 error_out:
6397 	if (fid)
6398 		free(fid);
6399 	if (dirent)
6400 		free(dirent);
6401 
6402 	dirhash_put(dir_node->dir_hash);
6403 
6404 	return error;
6405 }
6406 
6407 
6408 
6409 /* VOP_REMOVE */
udf_remove_file(struct udf_node * dir_node,struct udf_node * udf_node,char * componentname)6410 int udf_remove_file(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) {
6411 	int error;
6412 
6413 	if (udf_open_logvol(dir_node->udf_log_vol))
6414 		return EROFS;
6415 
6416 	if (udf_node->stat.st_mode & S_IFDIR) {
6417 		/* only remove files with this call */
6418 		return EISDIR;
6419 	}
6420 
6421 	error = udf_remove_directory_entry(dir_node, udf_node, componentname);
6422 	if (!error) {
6423 		dir_node->udf_log_vol->num_files--;
6424 	}	/* else? */
6425 
6426 	return error;
6427 }
6428 
6429 
udf_remove_directory_prim(struct udf_node * dir_node,struct udf_node * udf_node,char * componentname)6430 static int udf_remove_directory_prim(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) {
6431 	int error;
6432 
6433 	if (udf_open_logvol(dir_node->udf_log_vol))
6434 		return EROFS;
6435 
6436 	/* remove the entry */
6437 	error = udf_remove_directory_entry(dir_node, udf_node, componentname);
6438 	if (!error) {
6439 		dir_node->link_cnt--;
6440 		udf_node_mark_dirty(dir_node);
6441 		dir_node->udf_log_vol->num_directories--;
6442 	} else {
6443 		/* whoah! something went wrong, mark the .. as present again */
6444 		printf("UDF warning: filesystem might by in compromised state\n");
6445 		assert(udf_node);
6446 		udf_node->link_cnt++;
6447 	}
6448 
6449 	return error;
6450 }
6451 
6452 
6453 /* VOP_RMDIR */
udf_remove_directory(struct udf_node * dir_node,struct udf_node * udf_node,char * componentname)6454 int udf_remove_directory(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) {
6455 	uint32_t num_nodes;
6456 	int error;
6457 
6458 	if (!(udf_node->stat.st_mode & S_IFDIR)) {
6459 		/* only remove directories with this call */
6460 		return ENOTDIR;
6461 	}
6462 
6463 	error = udf_count_direntries(udf_node, 0, &num_nodes);
6464 	if (error) return error;
6465 
6466 	if (num_nodes != 0) return ENOTEMPTY;
6467 
6468 	error = udf_remove_directory_prim(dir_node, udf_node, componentname);
6469 
6470 	return error;
6471 }
6472 
6473 
6474 /* end of udf.c */
6475 
6476