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(×pec->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