Sync usage with man page.
[netbsd-mini2440.git] / sbin / newfs_udf / udf_create.c
blob5fb09e70f657cfd25b467ded46bb80dd125600a1
1 /* $NetBSD: udf_create.c,v 1.16 2009/05/19 12:13:02 reinoud Exp $ */
3 /*
4 * Copyright (c) 2006, 2008 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: udf_create.c,v 1.16 2009/05/19 12:13:02 reinoud Exp $");
32 #endif /* not lint */
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <time.h>
39 #include <assert.h>
40 #include <err.h>
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include "udf_create.h"
46 #if 0
47 # ifndef DEBUG
48 # define DEBUG
49 # endif
50 #endif
53 void
54 udf_init_create_context(void)
56 /* clear */
57 memset(&context, 0, sizeof(struct udf_create_context));
59 /* fill with defaults currently known */
60 context.dscrver = 3;
61 context.min_udf = 0x0102;
62 context.max_udf = 0x0260;
63 context.serialnum = 1; /* default */
65 context.gmtoff = 0;
66 context.sector_size = 512; /* minimum for UDF */
68 context.logvol_name = NULL;
69 context.primary_name = NULL;
70 context.volset_name = NULL;
71 context.fileset_name = NULL;
73 context.app_name = "*NetBSD newfs";
74 context.app_version_main = __NetBSD_Version__ / 100000000;
75 context.app_version_sub = (__NetBSD_Version__ / 1000000) % 100;
76 context.impl_name = "*NetBSD kernel UDF";
78 context.vds_seq = 0; /* first one starts with zero */
80 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
81 context.unique_id = 0x10;
83 context.num_files = 0;
84 context.num_directories = 0;
88 static uint32_t
89 udf_space_bitmap_len(uint32_t part_size)
91 return sizeof(struct space_bitmap_desc)-1 +
92 part_size/8;
96 static uint32_t
97 udf_bytes_to_sectors(uint64_t bytes)
99 uint32_t sector_size = layout.sector_size;
100 return (bytes + sector_size -1) / sector_size;
105 udf_calculate_disc_layout(int format_flags, int min_udf,
106 uint32_t wrtrack_skew,
107 uint32_t first_lba, uint32_t last_lba,
108 uint32_t sector_size, uint32_t blockingnr,
109 uint32_t sparable_blocks, float meta_fract)
111 uint64_t kbsize, bytes;
112 uint32_t sparable_blockingnr;
113 uint32_t align_blockingnr;
114 uint32_t pos, mpos;
116 /* clear */
117 bzero(&layout, sizeof(struct udf_disclayout));
119 /* fill with parameters */
120 layout.wrtrack_skew = wrtrack_skew;
121 layout.first_lba = first_lba;
122 layout.last_lba = last_lba;
123 layout.sector_size = sector_size;
124 layout.blockingnr = blockingnr;
125 layout.sparable_blocks = sparable_blocks;
127 /* start disc layouting */
130 * location of iso9660 vrs is defined as first sector AFTER 32kb,
131 * minimum `sector size' 2048
133 layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
134 + first_lba;
136 /* anchor starts at specified offset in sectors */
137 layout.anchors[0] = first_lba + 256;
138 if (format_flags & FORMAT_TRACK512)
139 layout.anchors[0] = first_lba + 512;
140 layout.anchors[1] = last_lba - 256;
141 layout.anchors[2] = last_lba;
143 /* update workable space */
144 first_lba = layout.anchors[0] + blockingnr;
145 last_lba = layout.anchors[1] - 1;
147 /* XXX rest of anchor packet can be added to unallocated space descr */
149 /* reserve space for VRS and VRS copy and associated tables */
150 layout.vds_size = MAX(16, blockingnr); /* UDF 2.2.3.1+2 */
151 layout.vds1 = first_lba;
152 first_lba += layout.vds_size; /* next packet */
154 if (format_flags & FORMAT_SEQUENTIAL) {
155 /* for sequential, append them ASAP */
156 layout.vds2 = first_lba;
157 first_lba += layout.vds_size;
158 } else {
159 layout.vds2 = layout.anchors[1] - layout.vds_size;
160 last_lba = layout.vds2 - 1; /* XXX -1 ?? */
163 /* reserve space for logvol integrity sequence */
164 layout.lvis_size = MAX(8192/sector_size, 2 * blockingnr);
165 if (format_flags & FORMAT_VAT)
166 layout.lvis_size = 2;
167 if (format_flags & FORMAT_WORM)
168 layout.lvis_size = 64 * blockingnr;
170 /* TODO skip bad blocks in LVID sequence; for now use f.e. */
171 //first_lba+=128;
172 layout.lvis = first_lba;
173 first_lba += layout.lvis_size;
175 /* initial guess of UDF partition size */
176 layout.part_start_lba = first_lba;
177 layout.part_size_lba = last_lba - layout.part_start_lba;
179 /* all non sequential media needs an unallocated space bitmap */
180 layout.alloc_bitmap_dscr_size = 0;
181 if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
182 bytes = udf_space_bitmap_len(layout.part_size_lba);
183 layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
185 /* XXX freed space map when applicable */
189 * Note that for (bug) compatibility with version UDF 2.00 (fixed in
190 * 2.01 and higher) the blocking size needs to be 32 sectors otherwise
191 * the drive's blockingnr.
194 sparable_blockingnr = blockingnr;
195 if (min_udf <= 0x200)
196 sparable_blockingnr = 32;
198 align_blockingnr = blockingnr;
199 if (format_flags & (FORMAT_SPARABLE | FORMAT_META))
200 align_blockingnr = sparable_blockingnr;
202 layout.align_blockingnr = align_blockingnr;
203 layout.sparable_blockingnr = sparable_blockingnr;
206 * Align partition LBA space to blocking granularity. Not strickly
207 * nessisary for non sparables but safer for the VRS data since it is
208 * not updated sporadically
211 if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
212 #ifdef DEBUG
213 printf("Lost %d slack sectors at start\n", UDF_ROUNDUP(
214 first_lba - wrtrack_skew, align_blockingnr) -
215 (first_lba - wrtrack_skew));
216 printf("Lost %d slack sectors at end\n",
217 (first_lba - wrtrack_skew) - UDF_ROUNDDOWN(
218 first_lba - wrtrack_skew, align_blockingnr));
219 #endif
221 first_lba = UDF_ROUNDUP( first_lba - wrtrack_skew, align_blockingnr);
222 last_lba = UDF_ROUNDDOWN(last_lba - wrtrack_skew, align_blockingnr);
225 if ((format_flags & FORMAT_SPARABLE) == 0)
226 layout.sparable_blocks = 0;
228 if (format_flags & FORMAT_SPARABLE) {
229 layout.sparable_area_size =
230 layout.sparable_blocks * sparable_blockingnr;
232 /* a sparing table descriptor is a whole blockingnr sectors */
233 layout.sparing_table_dscr_lbas = sparable_blockingnr;
235 /* place the descriptors at the start and end of the area */
236 layout.spt_1 = first_lba;
237 first_lba += layout.sparing_table_dscr_lbas;
239 layout.spt_2 = last_lba - layout.sparing_table_dscr_lbas;
240 last_lba -= layout.sparing_table_dscr_lbas;
242 /* allocate sparable section */
243 layout.sparable_area = first_lba;
244 first_lba += layout.sparable_area_size;
247 /* update guess of UDF partition size */
248 layout.part_start_lba = first_lba;
249 layout.part_size_lba = last_lba - layout.part_start_lba;
251 /* determine partition selection for data and metadata */
252 context.data_part = 0;
253 context.metadata_part = context.data_part;
254 if ((format_flags & FORMAT_VAT) || (format_flags & FORMAT_META))
255 context.metadata_part = context.data_part + 1;
258 * Pick fixed logical space sector numbers for main FSD, rootdir and
259 * unallocated space. The reason for this pre-allocation is that they
260 * are referenced in the volume descriptor sequence and hence can't be
261 * allocated later.
263 pos = 0;
264 layout.unalloc_space = pos;
265 pos += layout.alloc_bitmap_dscr_size;
267 /* claim metadata descriptors and partition space [UDF 2.2.10] */
268 if (format_flags & FORMAT_META) {
269 /* note: all in backing partition space */
270 layout.meta_file = pos++;
271 layout.meta_bitmap = pos++;;
272 layout.meta_mirror = layout.part_size_lba-1;
273 layout.meta_alignment = MAX(blockingnr, sparable_blockingnr);
274 layout.meta_blockingnr = MAX(layout.meta_alignment, 32);
276 /* calculate our partition length and store in sectors */
277 layout.meta_part_size_lba = layout.part_size_lba * meta_fract;
278 layout.meta_part_size_lba = MAX(layout.meta_part_size_lba, 32);
279 layout.meta_part_size_lba =
280 UDF_ROUNDDOWN(layout.meta_part_size_lba, layout.meta_blockingnr);
282 /* calculate positions */
283 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
284 layout.meta_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
286 layout.meta_bitmap_space = pos;
287 pos += layout.meta_bitmap_dscr_size;
289 layout.meta_part_start_lba = UDF_ROUNDUP(pos, layout.meta_alignment);
292 mpos = (context.metadata_part == context.data_part) ? pos : 0;
293 layout.fsd = mpos; mpos += 1;
294 layout.rootdir = mpos; mpos += 1;
295 layout.vat = mpos; mpos += 1; /* if present */
297 #if 0
298 printf("Summary so far\n");
299 printf("\tiso9660_vrs\t\t%d\n", layout.iso9660_vrs);
300 printf("\tanchor0\t\t\t%d\n", layout.anchors[0]);
301 printf("\tanchor1\t\t\t%d\n", layout.anchors[1]);
302 printf("\tanchor2\t\t\t%d\n", layout.anchors[2]);
303 printf("\tvds_size\t\t%d\n", layout.vds_size);
304 printf("\tvds1\t\t\t%d\n", layout.vds1);
305 printf("\tvds2\t\t\t%d\n", layout.vds2);
306 printf("\tlvis_size\t\t%d\n", layout.lvis_size);
307 printf("\tlvis\t\t\t%d\n", layout.lvis);
308 if (format_flags & FORMAT_SPARABLE) {
309 printf("\tsparable size\t\t%d\n", layout.sparable_area_size);
310 printf("\tsparable\t\t%d\n", layout.sparable_area);
312 printf("\tpartition start lba\t%d\n", layout.part_start_lba);
313 printf("\tpartition size\t\t%d KiB, %d MiB\n",
314 (layout.part_size_lba * sector_size) / 1024,
315 (layout.part_size_lba * sector_size) / (1024*1024));
316 if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
317 printf("\tpart bitmap start\t%d\n", layout.unalloc_space);
318 printf("\t\tfor %d lba\n", layout.alloc_bitmap_dscr_size);
320 if (format_flags & FORMAT_META) {
321 printf("\tmeta blockingnr\t\t%d\n", layout.meta_blockingnr);
322 printf("\tmeta alignment\t\t%d\n", layout.meta_alignment);
323 printf("\tmeta size\t\t%d KiB, %d MiB\n",
324 (layout.meta_part_size_lba * sector_size) / 1024,
325 (layout.meta_part_size_lba * sector_size) / (1024*1024));
326 printf("\tmeta file\t\t%d\n", layout.meta_file);
327 printf("\tmeta mirror\t\t%d\n", layout.meta_mirror);
328 printf("\tmeta bitmap\t\t%d\n", layout.meta_bitmap);
329 printf("\tmeta bitmap start\t%d\n", layout.meta_bitmap_space);
330 printf("\t\tfor %d lba\n", layout.meta_bitmap_dscr_size);
331 printf("\tmeta space start\t%d\n", layout.meta_part_start_lba);
332 printf("\t\tfor %d lba\n", layout.meta_part_size_lba);
334 printf("\n");
335 #endif
337 kbsize = (uint64_t) last_lba * sector_size;
338 printf("Total space on this medium approx. %"PRIu64" KiB, %"PRIu64" MiB\n",
339 kbsize/1024, kbsize/(1024*1024));
340 kbsize = (uint64_t) (layout.part_size_lba - layout.alloc_bitmap_dscr_size
341 - layout.meta_bitmap_dscr_size) * sector_size;
342 printf("Free space on this volume approx. %"PRIu64" KiB, %"PRIu64" MiB\n\n",
343 kbsize/1024, kbsize/(1024*1024));
345 return 0;
350 udf_validate_tag_sum(union dscrptr *dscr)
352 struct desc_tag *tag = &dscr->tag;
353 uint8_t *pos, sum, cnt;
355 /* calculate TAG header checksum */
356 pos = (uint8_t *) tag;
357 sum = 0;
359 for(cnt = 0; cnt < 16; cnt++) {
360 if (cnt != 4) sum += *pos;
361 pos++;
363 tag->cksum = sum; /* 8 bit */
365 return 0;
369 /* assumes sector number of descriptor to be allready present */
371 udf_validate_tag_and_crc_sums(union dscrptr *dscr)
373 struct desc_tag *tag = &dscr->tag;
374 uint16_t crc;
376 /* check payload CRC if applicable */
377 if (udf_rw16(tag->desc_crc_len) > 0) {
378 crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH,
379 udf_rw16(tag->desc_crc_len));
380 tag->desc_crc = udf_rw16(crc);
383 /* calculate TAG header checksum */
384 return udf_validate_tag_sum(dscr);
388 void
389 udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc)
391 tag->id = udf_rw16(tagid);
392 tag->descriptor_ver = udf_rw16(context.dscrver);
393 tag->cksum = 0;
394 tag->reserved = 0;
395 tag->serial_num = udf_rw16(context.serialnum);
396 tag->tag_loc = udf_rw32(loc);
401 udf_create_anchor(int num)
403 struct anchor_vdp *avdp;
404 uint32_t vds_extent_len = layout.vds_size * context.sector_size;
406 if ((avdp = calloc(1, context.sector_size)) == NULL)
407 return ENOMEM;
409 udf_inittag(&avdp->tag, TAGID_ANCHOR, layout.anchors[num]);
411 avdp->main_vds_ex.loc = udf_rw32(layout.vds1);
412 avdp->main_vds_ex.len = udf_rw32(vds_extent_len);
414 avdp->reserve_vds_ex.loc = udf_rw32(layout.vds2);
415 avdp->reserve_vds_ex.len = udf_rw32(vds_extent_len);
417 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
418 avdp->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
420 context.anchors[num] = avdp;
421 return 0;
425 void
426 udf_create_terminator(union dscrptr *dscr, uint32_t loc)
428 bzero(dscr, context.sector_size);
429 udf_inittag(&dscr->tag, TAGID_TERM, loc);
431 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
432 dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
436 void
437 udf_osta_charset(struct charspec *charspec)
439 bzero(charspec, sizeof(struct charspec));
440 charspec->type = 0;
441 strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
445 void
446 udf_encode_osta_id(char *osta_id, uint16_t len, char *text)
448 uint16_t u16_name[1024];
449 uint8_t *pos;
450 uint16_t *pos16;
452 bzero(osta_id, len);
453 if (!text || (strlen(text) == 0)) return;
455 bzero(u16_name, sizeof(uint16_t) * 1023);
457 /* convert ascii to 16 bits unicode */
458 pos = (uint8_t *) text;
459 pos16 = u16_name;
460 while (*pos) {
461 *pos16 = *pos;
462 pos++; pos16++;
464 *pos16 = 0;
466 udf_CompressUnicode(len, 8, (unicode_t *) u16_name, (byte *) osta_id);
468 /* Ecma 167/7.2.13 states that length is recorded in the last byte */
469 osta_id[len-1] = strlen(text)+1;
473 /* first call udf_set_regid and then the suffix */
474 void
475 udf_set_regid(struct regid *regid, char const *name)
477 bzero(regid, sizeof(struct regid));
478 regid->flags = 0; /* not dirty and not protected */
479 strcpy((char *) regid->id, name);
483 void
484 udf_add_domain_regid(struct regid *regid)
486 uint16_t *ver;
488 ver = (uint16_t *) regid->id_suffix;
489 *ver = udf_rw16(context.min_udf);
493 void
494 udf_add_udf_regid(struct regid *regid)
496 uint16_t *ver;
498 ver = (uint16_t *) regid->id_suffix;
499 *ver = udf_rw16(context.min_udf);
501 regid->id_suffix[2] = 4; /* unix */
502 regid->id_suffix[3] = 8; /* NetBSD */
506 void
507 udf_add_impl_regid(struct regid *regid)
509 regid->id_suffix[0] = 4; /* unix */
510 regid->id_suffix[1] = 8; /* NetBSD */
514 void
515 udf_add_app_regid(struct regid *regid)
517 regid->id_suffix[0] = context.app_version_main;
518 regid->id_suffix[1] = context.app_version_sub;
523 * Fill in timestamp structure based on clock_gettime(). Time is reported back as a time_t
524 * accompanied with a nano second field.
526 * The husec, usec and csec could be relaxed in type.
528 static void
529 udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp)
531 struct tm tm;
532 uint64_t husec, usec, csec;
534 bzero(timestamp, sizeof(struct timestamp));
535 gmtime_r(&timespec->tv_sec, &tm);
538 * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1.
540 * Lower 12 bits are two complement signed timezone offset if bit 12
541 * (method 1) is clear. Otherwise if bit 12 is set, specify timezone
542 * offset to -2047 i.e. unsigned `zero'
545 /* set method 1 for CUT/GMT */
546 timestamp->type_tz = udf_rw16((1<<12) + 0);
547 timestamp->year = udf_rw16(tm.tm_year + 1900);
548 timestamp->month = tm.tm_mon + 1; /* `tm' uses 0..11 for months */
549 timestamp->day = tm.tm_mday;
550 timestamp->hour = tm.tm_hour;
551 timestamp->minute = tm.tm_min;
552 timestamp->second = tm.tm_sec;
554 usec = (timespec->tv_nsec + 500) / 1000; /* round */
555 husec = usec / 100;
556 usec -= husec * 100; /* only 0-99 in usec */
557 csec = husec / 100; /* only 0-99 in csec */
558 husec -= csec * 100; /* only 0-99 in husec */
560 timestamp->centisec = csec;
561 timestamp->hund_usec = husec;
562 timestamp->usec = usec;
567 void
568 udf_set_timestamp_now(struct timestamp *timestamp)
570 struct timespec now;
572 clock_gettime(CLOCK_REALTIME, &now);
573 udf_timespec_to_timestamp(&now, timestamp);
578 udf_create_primaryd(void)
580 struct pri_vol_desc *pri;
581 uint16_t crclen;
583 pri = calloc(1, context.sector_size);
584 if (pri == NULL)
585 return ENOMEM;
587 bzero(pri, context.sector_size);
588 udf_inittag(&pri->tag, TAGID_PRI_VOL, /* loc */ 0);
589 pri->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
591 pri->pvd_num = udf_rw32(0); /* default serial */
592 udf_encode_osta_id(pri->vol_id, 32, context.primary_name);
594 /* set defaults for single disc volumes as UDF prescribes */
595 pri->vds_num = udf_rw16(1);
596 pri->max_vol_seq = udf_rw16(1);
597 pri->ichg_lvl = udf_rw16(2);
598 pri->max_ichg_lvl = udf_rw16(3);
599 pri->flags = udf_rw16(0);
601 pri->charset_list = udf_rw32(1); /* only CS0 */
602 pri->max_charset_list = udf_rw32(1); /* only CS0 */
604 udf_encode_osta_id(pri->volset_id, 128, context.volset_name);
605 udf_osta_charset(&pri->desc_charset);
606 udf_osta_charset(&pri->explanatory_charset);
608 udf_set_regid(&pri->app_id, context.app_name);
609 udf_add_app_regid(&pri->app_id);
611 udf_set_regid(&pri->imp_id, context.impl_name);
612 udf_add_impl_regid(&pri->imp_id);
614 udf_set_timestamp_now(&pri->time);
616 crclen = sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH;
617 pri->tag.desc_crc_len = udf_rw16(crclen);
619 context.primary_vol = pri;
621 return 0;
625 /* XXX no support for unallocated or freed space tables yet (!) */
627 udf_create_partitiond(int part_num, int part_accesstype)
629 struct part_desc *pd;
630 struct part_hdr_desc *phd;
631 uint32_t sector_size, bitmap_bytes;
632 uint16_t crclen;
634 sector_size = context.sector_size;
635 bitmap_bytes = layout.alloc_bitmap_dscr_size * sector_size;
637 if (context.partitions[part_num]) {
638 printf("Internal error: partition %d allready defined\n",
639 part_num);
640 return EINVAL;
643 pd = calloc(1, context.sector_size);
644 if (pd == NULL)
645 return ENOMEM;
646 phd = &pd->_impl_use.part_hdr;
648 udf_inittag(&pd->tag, TAGID_PARTITION, /* loc */ 0);
649 pd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
651 pd->flags = udf_rw16(1); /* allocated */
652 pd->part_num = udf_rw16(part_num); /* only one physical partition */
654 if (context.dscrver == 2) {
655 udf_set_regid(&pd->contents, "+NSR02");
656 } else {
657 udf_set_regid(&pd->contents, "+NSR03");
659 udf_add_app_regid(&pd->contents);
661 phd->unalloc_space_bitmap.len = udf_rw32(bitmap_bytes);
662 phd->unalloc_space_bitmap.lb_num = udf_rw32(layout.unalloc_space);
664 if (layout.freed_space) {
665 phd->freed_space_bitmap.len = udf_rw32(bitmap_bytes);
666 phd->freed_space_bitmap.lb_num = udf_rw32(layout.freed_space);
669 pd->access_type = udf_rw32(part_accesstype);
670 pd->start_loc = udf_rw32(layout.part_start_lba);
671 pd->part_len = udf_rw32(layout.part_size_lba);
673 udf_set_regid(&pd->imp_id, context.impl_name);
674 udf_add_impl_regid(&pd->imp_id);
676 crclen = sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH;
677 pd->tag.desc_crc_len = udf_rw16(crclen);
679 context.partitions[part_num] = pd;
681 return 0;
686 udf_create_unalloc_spaced(void)
688 struct unalloc_sp_desc *usd;
689 uint16_t crclen;
691 usd = calloc(1, context.sector_size);
692 if (usd == NULL)
693 return ENOMEM;
695 udf_inittag(&usd->tag, TAGID_UNALLOC_SPACE, /* loc */ 0);
696 usd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
698 /* no default entries */
699 usd->alloc_desc_num = udf_rw32(0); /* no entries */
701 crclen = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad);
702 crclen -= UDF_DESC_TAG_LENGTH;
703 usd->tag.desc_crc_len = udf_rw16(crclen);
705 context.unallocated = usd;
707 return 0;
711 static int
712 udf_create_base_logical_dscr(void)
714 struct logvol_desc *lvd;
715 uint32_t sector_size;
716 uint16_t crclen;
718 sector_size = context.sector_size;
720 lvd = calloc(1, sector_size);
721 if (lvd == NULL)
722 return ENOMEM;
724 udf_inittag(&lvd->tag, TAGID_LOGVOL, /* loc */ 0);
725 lvd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
727 udf_osta_charset(&lvd->desc_charset);
728 udf_encode_osta_id(lvd->logvol_id, 128, context.logvol_name);
729 lvd->lb_size = udf_rw32(context.sector_size);
731 udf_set_regid(&lvd->domain_id, "*OSTA UDF Compliant");
732 udf_add_domain_regid(&lvd->domain_id);
734 /* no partition mappings/entries yet */
735 lvd->mt_l = udf_rw32(0);
736 lvd->n_pm = udf_rw32(0);
738 udf_set_regid(&lvd->imp_id, context.impl_name);
739 udf_add_impl_regid(&lvd->imp_id);
741 lvd->integrity_seq_loc.loc = udf_rw32(layout.lvis);
742 lvd->integrity_seq_loc.len = udf_rw32(layout.lvis_size * sector_size);
744 /* just one fsd for now */
745 lvd->lv_fsd_loc.len = udf_rw32(sector_size);
746 lvd->lv_fsd_loc.loc.part_num = udf_rw32(context.metadata_part);
747 lvd->lv_fsd_loc.loc.lb_num = udf_rw32(layout.fsd);
749 crclen = sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH;
750 lvd->tag.desc_crc_len = udf_rw16(crclen);
752 context.logical_vol = lvd;
753 context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
754 context.vtop_offset[UDF_VTOP_RAWPART] = 0;
756 return 0;
760 static void
761 udf_add_logvol_part_physical(uint16_t phys_part)
763 struct logvol_desc *logvol = context.logical_vol;
764 union udf_pmap *pmap;
765 uint8_t *pmap_pos;
766 uint16_t crclen;
767 uint32_t pmap1_size, log_part;
769 log_part = udf_rw32(logvol->n_pm);
770 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
771 pmap1_size = sizeof(struct part_map_1);
773 pmap = (union udf_pmap *) pmap_pos;
774 pmap->pm1.type = 1;
775 pmap->pm1.len = sizeof(struct part_map_1);
776 pmap->pm1.vol_seq_num = udf_rw16(1); /* no multi-volume */
777 pmap->pm1.part_num = udf_rw16(phys_part);
779 context.vtop [log_part] = phys_part;
780 context.vtop_tp [log_part] = UDF_VTOP_TYPE_PHYS;
781 context.vtop_offset[log_part] = layout.part_start_lba;
782 context.part_size[log_part] = layout.part_size_lba;
783 context.part_free[log_part] = layout.part_size_lba;
785 /* increment number of partitions and length */
786 logvol->n_pm = udf_rw32(log_part + 1);
787 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmap1_size);
789 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmap1_size;
790 logvol->tag.desc_crc_len = udf_rw16(crclen);
794 static void
795 udf_add_logvol_part_virtual(uint16_t phys_part)
797 union udf_pmap *pmap;
798 struct logvol_desc *logvol = context.logical_vol;
799 uint8_t *pmap_pos;
800 uint16_t crclen;
801 uint32_t pmapv_size, log_part;
803 log_part = udf_rw32(logvol->n_pm);
804 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
805 pmapv_size = sizeof(struct part_map_2);
807 pmap = (union udf_pmap *) pmap_pos;
808 pmap->pmv.type = 2;
809 pmap->pmv.len = pmapv_size;
811 udf_set_regid(&pmap->pmv.id, "*UDF Virtual Partition");
812 udf_add_udf_regid(&pmap->pmv.id);
814 pmap->pmv.vol_seq_num = udf_rw16(1); /* no multi-volume */
815 pmap->pmv.part_num = udf_rw16(phys_part);
817 context.vtop [log_part] = phys_part;
818 context.vtop_tp [log_part] = UDF_VTOP_TYPE_VIRT;
819 context.vtop_offset[log_part] = context.vtop_offset[phys_part];
820 context.part_size[log_part] = 0xffffffff;
821 context.part_free[log_part] = 0xffffffff;
823 /* increment number of partitions and length */
824 logvol->n_pm = udf_rw32(log_part + 1);
825 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
827 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
828 logvol->tag.desc_crc_len = udf_rw16(crclen);
832 /* sparing table size is in bytes */
833 static void
834 udf_add_logvol_part_sparable(uint16_t phys_part)
836 union udf_pmap *pmap;
837 struct logvol_desc *logvol = context.logical_vol;
838 uint32_t *st_pos, sparable_bytes, pmaps_size;
839 uint8_t *pmap_pos, num;
840 uint16_t crclen;
841 uint32_t log_part;
843 log_part = udf_rw32(logvol->n_pm);
844 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
845 pmaps_size = sizeof(struct part_map_2);
846 sparable_bytes = layout.sparable_area_size * context.sector_size;
848 pmap = (union udf_pmap *) pmap_pos;
849 pmap->pms.type = 2;
850 pmap->pms.len = pmaps_size;
852 udf_set_regid(&pmap->pmv.id, "*UDF Sparable Partition");
853 udf_add_udf_regid(&pmap->pmv.id);
855 pmap->pms.vol_seq_num = udf_rw16(1); /* no multi-volume */
856 pmap->pms.part_num = udf_rw16(phys_part);
858 pmap->pms.packet_len = udf_rw16(layout.sparable_blockingnr);
859 pmap->pms.st_size = udf_rw32(sparable_bytes);
861 /* enter spare tables */
862 st_pos = &pmap->pms.st_loc[0];
863 *st_pos++ = udf_rw32(layout.spt_1);
864 *st_pos++ = udf_rw32(layout.spt_2);
866 num = 2;
867 if (layout.spt_2 == 0) num--;
868 if (layout.spt_1 == 0) num--;
869 pmap->pms.n_st = num; /* 8 bit */
871 /* the vtop_offset needs to explicitly set since there is no phys. */
872 context.vtop [log_part] = phys_part;
873 context.vtop_tp [log_part] = UDF_VTOP_TYPE_SPARABLE;
874 context.vtop_offset[log_part] = layout.part_start_lba;
875 context.part_size[log_part] = layout.part_size_lba;
876 context.part_free[log_part] = layout.part_size_lba;
878 /* increment number of partitions and length */
879 logvol->n_pm = udf_rw32(log_part + 1);
880 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmaps_size);
882 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmaps_size;
883 logvol->tag.desc_crc_len = udf_rw16(crclen);
888 udf_create_sparing_tabled(void)
890 struct udf_sparing_table *spt;
891 struct spare_map_entry *sme;
892 uint32_t loc, cnt;
893 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
895 spt = calloc(context.sector_size, layout.sparing_table_dscr_lbas);
896 if (spt == NULL)
897 return ENOMEM;
899 /* a sparing table descriptor is a whole sparable_blockingnr sectors */
900 udf_inittag(&spt->tag, TAGID_SPARING_TABLE, /* loc */ 0);
902 udf_set_regid(&spt->id, "*UDF Sparing Table");
903 udf_add_udf_regid(&spt->id);
905 spt->rt_l = udf_rw16(layout.sparable_blocks);
906 spt->seq_num = udf_rw32(0); /* first generation */
908 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
909 sme = &spt->entries[cnt];
910 loc = layout.sparable_area + cnt * layout.sparable_blockingnr;
911 sme->org = udf_rw32(0xffffffff); /* open for reloc */
912 sme->map = udf_rw32(loc);
915 /* calculate crc len for actual size */
916 crclen = sizeof(struct udf_sparing_table) - UDF_DESC_TAG_LENGTH;
917 crclen += (layout.sparable_blocks-1) * sizeof(struct spare_map_entry);
918 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
919 spt->tag.desc_crc_len = udf_rw16((uint16_t)crclen);
921 context.sparing_table = spt;
923 return 0;
927 static void
928 udf_add_logvol_part_meta(uint16_t phys_part)
930 union udf_pmap *pmap;
931 struct logvol_desc *logvol = context.logical_vol;
932 uint8_t *pmap_pos;
933 uint32_t pmapv_size, log_part;
934 uint16_t crclen;
936 log_part = udf_rw32(logvol->n_pm);
937 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
938 pmapv_size = sizeof(struct part_map_2);
940 pmap = (union udf_pmap *) pmap_pos;
941 pmap->pmm.type = 2;
942 pmap->pmm.len = pmapv_size;
944 udf_set_regid(&pmap->pmm.id, "*UDF Metadata Partition");
945 udf_add_udf_regid(&pmap->pmm.id);
947 pmap->pmm.vol_seq_num = udf_rw16(1); /* no multi-volume */
948 pmap->pmm.part_num = udf_rw16(phys_part);
950 /* fill in meta data file(s) and alloc/alignment unit sizes */
951 pmap->pmm.meta_file_lbn = udf_rw32(layout.meta_file);
952 pmap->pmm.meta_mirror_file_lbn = udf_rw32(layout.meta_mirror);
953 pmap->pmm.meta_bitmap_file_lbn = udf_rw32(layout.meta_bitmap);
954 pmap->pmm.alloc_unit_size = udf_rw32(layout.meta_blockingnr);
955 pmap->pmm.alignment_unit_size = udf_rw16(layout.meta_alignment);
956 pmap->pmm.flags = 0; /* METADATA_DUPLICATED */
958 context.vtop [log_part] = phys_part;
959 context.vtop_tp [log_part] = UDF_VTOP_TYPE_META;
960 context.vtop_offset[log_part] =
961 context.vtop_offset[phys_part] + layout.meta_part_start_lba;
962 context.part_size[log_part] = layout.meta_part_size_lba;
963 context.part_free[log_part] = layout.meta_part_size_lba;
965 /* increment number of partitions and length */
966 logvol->n_pm = udf_rw32(log_part + 1);
967 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
969 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
970 logvol->tag.desc_crc_len = udf_rw16(crclen);
975 udf_create_logical_dscr(int format_flags)
977 int error;
979 if ((error = udf_create_base_logical_dscr()))
980 return error;
982 /* we pass data_part for there might be a read-only part one day */
983 if (format_flags & FORMAT_SPARABLE) {
984 /* sparable partition mapping has no physical mapping */
985 udf_add_logvol_part_sparable(context.data_part);
986 } else {
987 udf_add_logvol_part_physical(context.data_part);
990 if (format_flags & FORMAT_VAT) {
991 /* add VAT virtual mapping; reflects on datapart */
992 udf_add_logvol_part_virtual(context.data_part);
994 if (format_flags & FORMAT_META) {
995 /* add META data mapping; reflects on datapart */
996 udf_add_logvol_part_meta(context.data_part);
999 return 0;
1004 udf_create_impvold(char *field1, char *field2, char *field3)
1006 struct impvol_desc *ivd;
1007 struct udf_lv_info *lvi;
1008 uint16_t crclen;
1010 ivd = calloc(1, context.sector_size);
1011 if (ivd == NULL)
1012 return ENOMEM;
1013 lvi = &ivd->_impl_use.lv_info;
1015 udf_inittag(&ivd->tag, TAGID_IMP_VOL, /* loc */ 0);
1016 ivd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1018 udf_set_regid(&ivd->impl_id, "*UDF LV Info");
1019 udf_add_udf_regid(&ivd->impl_id);
1021 /* fill in UDF specific part */
1022 udf_osta_charset(&lvi->lvi_charset);
1023 udf_encode_osta_id(lvi->logvol_id, 128, context.logvol_name);
1025 udf_encode_osta_id(lvi->lvinfo1, 36, field1);
1026 udf_encode_osta_id(lvi->lvinfo2, 36, field2);
1027 udf_encode_osta_id(lvi->lvinfo3, 36, field3);
1029 udf_set_regid(&lvi->impl_id, context.impl_name);
1030 udf_add_impl_regid(&lvi->impl_id);
1032 crclen = sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH;
1033 ivd->tag.desc_crc_len = udf_rw16(crclen);
1035 context.implementation = ivd;
1037 return 0;
1041 /* XXX might need to be sanitised a bit later */
1042 void
1043 udf_update_lvintd(int type)
1045 struct logvol_int_desc *lvid;
1046 struct udf_logvol_info *lvinfo;
1047 struct logvol_desc *logvol;
1048 uint32_t *pos;
1049 uint32_t cnt, l_iu, num_partmappings;
1050 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1052 lvid = context.logvol_integrity;
1053 logvol = context.logical_vol;
1055 assert(lvid);
1056 assert(logvol);
1058 lvid->integrity_type = udf_rw32(type);
1060 num_partmappings = udf_rw32(logvol->n_pm);
1062 udf_set_timestamp_now(&lvid->time);
1064 lvinfo = (struct udf_logvol_info *)
1065 (lvid->tables + num_partmappings * 2);
1066 udf_set_regid(&lvinfo->impl_id, context.impl_name);
1067 udf_add_impl_regid(&lvinfo->impl_id);
1069 lvinfo->num_files = udf_rw32(context.num_files);
1070 lvinfo->num_directories = udf_rw32(context.num_directories);
1072 lvid->lvint_next_unique_id = udf_rw64(context.unique_id);
1074 /* XXX sane enough ? */
1075 lvinfo->min_udf_readver = udf_rw16(context.min_udf);
1076 lvinfo->min_udf_writever = udf_rw16(context.min_udf);
1077 lvinfo->max_udf_writever = udf_rw16(context.max_udf);
1079 lvid->num_part = udf_rw32(num_partmappings);
1081 /* no impl. use needed */
1082 l_iu = sizeof(struct udf_logvol_info);
1083 lvid->l_iu = udf_rw32(l_iu);
1085 pos = &lvid->tables[0];
1086 for (cnt = 0; cnt < num_partmappings; cnt++) {
1087 *pos++ = udf_rw32(context.part_free[cnt]);
1089 for (cnt = 0; cnt < num_partmappings; cnt++) {
1090 *pos++ = udf_rw32(context.part_size[cnt]);
1093 crclen = sizeof(struct logvol_int_desc) -4 -UDF_DESC_TAG_LENGTH + l_iu;
1094 crclen += num_partmappings * 2 * 4;
1095 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1096 lvid->tag.desc_crc_len = udf_rw16(crclen);
1098 context.logvol_info = lvinfo;
1103 udf_create_lvintd(int type)
1105 struct logvol_int_desc *lvid;
1107 lvid = calloc(1, context.sector_size);
1108 if (lvid == NULL)
1109 return ENOMEM;
1111 udf_inittag(&lvid->tag, TAGID_LOGVOL_INTEGRITY, /* loc */ 0);
1113 context.logvol_integrity = lvid;
1115 udf_update_lvintd(type);
1117 return 0;
1122 udf_create_fsd(void)
1124 struct fileset_desc *fsd;
1125 uint16_t crclen;
1127 fsd = calloc(1, context.sector_size);
1128 if (fsd == NULL)
1129 return ENOMEM;
1131 udf_inittag(&fsd->tag, TAGID_FSD, /* loc */ 0);
1133 udf_set_timestamp_now(&fsd->time);
1134 fsd->ichg_lvl = udf_rw16(3); /* UDF 2.3.2.1 */
1135 fsd->max_ichg_lvl = udf_rw16(3); /* UDF 2.3.2.2 */
1137 fsd->charset_list = udf_rw32(1); /* only CS0 */
1138 fsd->max_charset_list = udf_rw32(1); /* only CS0 */
1140 fsd->fileset_num = udf_rw32(0); /* only one fsd */
1141 fsd->fileset_desc_num = udf_rw32(0); /* origional */
1143 udf_osta_charset(&fsd->logvol_id_charset);
1144 udf_encode_osta_id(fsd->logvol_id, 128, context.logvol_name);
1146 udf_osta_charset(&fsd->fileset_charset);
1147 udf_encode_osta_id(fsd->fileset_id, 32, context.fileset_name);
1149 /* copyright file and abstract file names obmitted */
1151 fsd->rootdir_icb.len = udf_rw32(context.sector_size);
1152 fsd->rootdir_icb.loc.lb_num = udf_rw32(layout.rootdir);
1153 fsd->rootdir_icb.loc.part_num = udf_rw16(context.metadata_part);
1155 udf_set_regid(&fsd->domain_id, "*OSTA UDF Compliant");
1156 udf_add_domain_regid(&fsd->domain_id);
1158 /* next_ex stays zero */
1159 /* no system streamdirs yet */
1161 crclen = sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH;
1162 fsd->tag.desc_crc_len = udf_rw16(crclen);
1164 context.fileset_desc = fsd;
1166 return 0;
1171 udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba,
1172 struct space_bitmap_desc **sbdp)
1174 struct space_bitmap_desc *sbd;
1175 uint32_t cnt;
1176 uint16_t crclen;
1178 *sbdp = NULL;
1179 sbd = calloc(context.sector_size, dscr_size);
1180 if (sbd == NULL)
1181 return ENOMEM;
1183 udf_inittag(&sbd->tag, TAGID_SPACE_BITMAP, /* loc */ 0);
1185 sbd->num_bits = udf_rw32(part_size_lba);
1186 sbd->num_bytes = udf_rw32((part_size_lba + 7)/8);
1188 /* fill space with 0xff to indicate free */
1189 for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
1190 sbd->data[cnt] = 0xff;
1192 /* set crc to only cover the header (UDF 2.3.1.2, 2.3.8.1) */
1193 crclen = sizeof(struct space_bitmap_desc) -1 - UDF_DESC_TAG_LENGTH;
1194 sbd->tag.desc_crc_len = udf_rw16(crclen);
1196 *sbdp = sbd;
1197 return 0;
1201 /* --------------------------------------------------------------------- */
1203 int
1204 udf_register_bad_block(uint32_t location)
1206 struct udf_sparing_table *spt;
1207 struct spare_map_entry *sme, *free_sme;
1208 uint32_t cnt;
1210 spt = context.sparing_table;
1211 if (spt == NULL) {
1212 printf("internal error: adding bad block to non sparable\n");
1213 return EINVAL;
1216 /* find us a free spare map entry */
1217 free_sme = NULL;
1218 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
1219 sme = &spt->entries[cnt];
1220 /* if we are allready in it, bail out */
1221 if (udf_rw32(sme->org) == location)
1222 return 0;
1223 if (udf_rw32(sme->org) == 0xffffffff) {
1224 free_sme = sme;
1225 break;
1228 if (free_sme == NULL) {
1229 printf("Disc relocation blocks full; disc too damanged\n");
1230 return EINVAL;
1232 free_sme->org = udf_rw32(location);
1234 return 0;
1238 void
1239 udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks)
1241 union dscrptr *dscr;
1242 uint8_t *bpos;
1243 uint32_t cnt, bit;
1245 /* make not on space used on underlying partition */
1246 context.part_free[partnr] -= blocks;
1247 #ifdef DEBUG
1248 printf("mark allocated : partnr %d, start_lb %d for %d blocks\n",
1249 partnr, start_lb, blocks);
1250 #endif
1252 switch (context.vtop_tp[partnr]) {
1253 case UDF_VTOP_TYPE_VIRT:
1254 /* nothing */
1255 break;
1256 case UDF_VTOP_TYPE_PHYS:
1257 case UDF_VTOP_TYPE_SPARABLE:
1258 case UDF_VTOP_TYPE_META:
1259 #ifdef DEBUG
1260 printf("Marking %d+%d as used\n", start_lb, blocks);
1261 #endif
1262 dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]);
1263 for (cnt = start_lb; cnt < start_lb + blocks; cnt++) {
1264 bpos = &dscr->sbd.data[cnt / 8];
1265 bit = cnt % 8;
1266 *bpos &= ~(1<< bit);
1268 break;
1269 default:
1270 printf("internal error: reality check in mapping type %d\n",
1271 context.vtop_tp[partnr]);
1272 exit(EXIT_FAILURE);
1277 /* --------------------------------------------------------------------- */
1279 static void
1280 udf_advance_uniqueid(void)
1282 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
1283 context.unique_id++;
1284 if (context.unique_id < 0x10)
1285 context.unique_id = 0x10;
1289 static int
1290 udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent,
1291 uint64_t unique_id)
1293 /* the size of an empty FID is 38 but needs to be a multiple of 4 */
1294 int fidsize = 40;
1296 udf_inittag(&fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num));
1297 fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
1298 fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
1299 fid->icb = *parent;
1300 fid->icb.longad_uniqueid = udf_rw32((uint32_t) unique_id);
1301 fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1303 /* we have to do the fid here explicitly for simplicity */
1304 udf_validate_tag_and_crc_sums((union dscrptr *) fid);
1306 return fidsize;
1311 * Order of extended attributes :
1312 * ECMA 167 EAs
1313 * Non block aligned Implementation Use EAs
1314 * Block aligned Implementation Use EAs (not in newfs_udf)
1315 * Application Use EAs (not in newfs_udf)
1317 * no checks for doubles, must be called in-order
1319 static void
1320 udf_extattr_append_internal(union dscrptr *dscr, struct extattr_entry *extattr)
1322 struct file_entry *fe;
1323 struct extfile_entry *efe;
1324 struct extattrhdr_desc *extattrhdr;
1325 struct impl_extattr_entry *implext;
1326 uint32_t impl_attr_loc, appl_attr_loc, l_ea, a_l, exthdr_len;
1327 uint32_t *l_eap, l_ad;
1328 uint16_t *spos;
1329 uint8_t *bpos, *data;
1331 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
1332 fe = &dscr->fe;
1333 data = fe->data;
1334 l_eap = &fe->l_ea;
1335 l_ad = udf_rw32(fe->l_ad);
1336 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
1337 efe = &dscr->efe;
1338 data = efe->data;
1339 l_eap = &efe->l_ea;
1340 l_ad = udf_rw32(efe->l_ad);
1341 } else {
1342 errx(1, "Bad tag passed to udf_extattr_append_internal");
1345 /* should have a header! */
1346 extattrhdr = (struct extattrhdr_desc *) data;
1347 l_ea = udf_rw32(*l_eap);
1348 if (l_ea == 0) {
1349 assert(l_ad == 0);
1350 /* create empty extended attribute header */
1351 exthdr_len = sizeof(struct extattrhdr_desc);
1353 udf_inittag(&extattrhdr->tag, TAGID_EXTATTR_HDR, /* loc */ 0);
1354 extattrhdr->impl_attr_loc = udf_rw32(exthdr_len);
1355 extattrhdr->appl_attr_loc = udf_rw32(exthdr_len);
1356 extattrhdr->tag.desc_crc_len = udf_rw16(8);
1358 /* record extended attribute header length */
1359 l_ea = exthdr_len;
1360 *l_eap = udf_rw32(l_ea);
1363 /* extract locations */
1364 impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc);
1365 appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc);
1366 if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1367 impl_attr_loc = l_ea;
1368 if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1369 appl_attr_loc = l_ea;
1371 /* Ecma 167 EAs */
1372 if (udf_rw32(extattr->type) < 2048) {
1373 assert(impl_attr_loc == l_ea);
1374 assert(appl_attr_loc == l_ea);
1377 /* implementation use extended attributes */
1378 if (udf_rw32(extattr->type) == 2048) {
1379 assert(appl_attr_loc == l_ea);
1381 /* calculate and write extended attribute header checksum */
1382 implext = (struct impl_extattr_entry *) extattr;
1383 assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */
1384 spos = (uint16_t *) implext->data;
1385 *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
1388 /* application use extended attributes */
1389 assert(udf_rw32(extattr->type) != 65536);
1390 assert(appl_attr_loc == l_ea);
1392 /* append the attribute at the end of the current space */
1393 bpos = data + udf_rw32(*l_eap);
1394 a_l = udf_rw32(extattr->a_l);
1396 /* update impl. attribute locations */
1397 if (udf_rw32(extattr->type) < 2048) {
1398 impl_attr_loc = l_ea + a_l;
1399 appl_attr_loc = l_ea + a_l;
1401 if (udf_rw32(extattr->type) == 2048) {
1402 appl_attr_loc = l_ea + a_l;
1405 /* copy and advance */
1406 memcpy(bpos, extattr, a_l);
1407 l_ea += a_l;
1408 *l_eap = udf_rw32(l_ea);
1410 /* do the `dance` again backwards */
1411 if (context.dscrver != 2) {
1412 if (impl_attr_loc == l_ea)
1413 impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT;
1414 if (appl_attr_loc == l_ea)
1415 appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT;
1418 /* store offsets */
1419 extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc);
1420 extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc);
1422 /* make sure the header sums stays correct */
1423 udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
1428 udf_create_new_fe(struct file_entry **fep, int file_type,
1429 struct long_ad *parent_icb)
1431 struct file_entry *fe;
1432 struct icb_tag *icb;
1433 struct timestamp birthtime;
1434 struct filetimes_extattr_entry *ft_extattr;
1435 uint32_t fidsize;
1436 uint8_t *bpos;
1437 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1439 *fep = NULL;
1440 fe = calloc(1, context.sector_size);
1441 if (fe == NULL)
1442 return ENOMEM;
1444 udf_inittag(&fe->tag, TAGID_FENTRY, /* loc */ 0);
1445 icb = &fe->icbtag;
1448 * Always use strategy type 4 unless on WORM wich we don't support
1449 * (yet). Fill in defaults and set for internal allocation of data.
1451 icb->strat_type = udf_rw16(4);
1452 icb->max_num_entries = udf_rw16(1);
1453 icb->file_type = file_type; /* 8 bit */
1454 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1456 fe->perm = udf_rw32(0x7fff); /* all is allowed */
1457 fe->link_cnt = udf_rw16(0); /* explicit setting */
1459 fe->ckpoint = udf_rw32(1); /* user supplied file version */
1460 udf_set_timestamp_now(&birthtime);
1461 udf_set_timestamp_now(&fe->atime);
1462 udf_set_timestamp_now(&fe->attrtime);
1463 udf_set_timestamp_now(&fe->mtime);
1465 udf_set_regid(&fe->imp_id, context.impl_name);
1466 udf_add_impl_regid(&fe->imp_id);
1467 fe->unique_id = udf_rw64(context.unique_id);
1468 fe->l_ea = udf_rw32(0);
1470 /* create extended attribute to record our creation time */
1471 ft_extattr = calloc(1, UDF_FILETIMES_ATTR_SIZE(1));
1472 ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO);
1473 ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */
1474 ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1));
1475 ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */
1476 ft_extattr->existence = UDF_FILETIMES_FILE_CREATION;
1477 ft_extattr->times[0] = birthtime;
1479 udf_extattr_append_internal((union dscrptr *) fe,
1480 (struct extattr_entry *) ft_extattr);
1481 free(ft_extattr);
1483 /* if its a directory, create '..' */
1484 bpos = (uint8_t *) fe->data + udf_rw32(fe->l_ea);
1485 fidsize = 0;
1486 if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
1487 fidsize = udf_create_parentfid((struct fileid_desc *) bpos,
1488 parent_icb, context.unique_id);
1490 udf_advance_uniqueid();
1492 /* record fidlength information */
1493 fe->inf_len = udf_rw64(fidsize);
1494 fe->l_ad = udf_rw32(fidsize);
1495 fe->logblks_rec = udf_rw64(0); /* intern */
1497 crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
1498 crclen += udf_rw32(fe->l_ea) + fidsize;
1499 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1500 fe->tag.desc_crc_len = udf_rw16(crclen);
1502 *fep = fe;
1503 return 0;
1508 udf_create_new_efe(struct extfile_entry **efep, int file_type,
1509 struct long_ad *parent_icb)
1511 struct extfile_entry *efe;
1512 struct icb_tag *icb;
1513 uint32_t fidsize;
1514 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1516 *efep = NULL;
1517 efe = calloc(1, context.sector_size);
1518 if (efe == NULL)
1519 return ENOMEM;
1521 udf_inittag(&efe->tag, TAGID_EXTFENTRY, /* loc */ 0);
1522 icb = &efe->icbtag;
1525 * Always use strategy type 4 unless on WORM wich we don't support
1526 * (yet). Fill in defaults and set for internal allocation of data.
1528 icb->strat_type = udf_rw16(4);
1529 icb->max_num_entries = udf_rw16(1);
1530 icb->file_type = file_type; /* 8 bit */
1531 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1533 efe->perm = udf_rw32(0x7fff); /* all is allowed */
1534 efe->link_cnt = udf_rw16(0); /* explicit setting */
1536 efe->ckpoint = udf_rw32(1); /* user supplied file version */
1537 udf_set_timestamp_now(&efe->ctime);
1538 udf_set_timestamp_now(&efe->atime);
1539 udf_set_timestamp_now(&efe->attrtime);
1540 udf_set_timestamp_now(&efe->mtime);
1542 udf_set_regid(&efe->imp_id, context.impl_name);
1543 udf_add_impl_regid(&efe->imp_id);
1545 fidsize = 0;
1546 efe->unique_id = udf_rw64(context.unique_id);
1547 if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
1548 fidsize = udf_create_parentfid((struct fileid_desc *) efe->data,
1549 parent_icb, context.unique_id);
1551 udf_advance_uniqueid();
1553 /* record fidlength information */
1554 efe->inf_len = udf_rw64(fidsize);
1555 efe->obj_size = udf_rw64(fidsize);
1556 efe->l_ad = udf_rw32(fidsize);
1557 efe->logblks_rec = udf_rw64(0);
1559 crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
1560 crclen += fidsize;
1561 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1562 efe->tag.desc_crc_len = udf_rw16(crclen);
1564 *efep = efe;
1565 return 0;
1568 /* --------------------------------------------------------------------- */
1570 static void
1571 udf_append_mapping_part_to_efe(struct extfile_entry *efe, struct short_ad *mapping)
1573 struct icb_tag *icb;
1574 uint64_t inf_len, obj_size, logblks_rec;
1575 uint32_t l_ad, l_ea;
1576 uint16_t crclen;
1577 uint8_t *bpos;
1579 inf_len = udf_rw64(efe->inf_len);
1580 obj_size = udf_rw64(efe->obj_size);
1581 logblks_rec = udf_rw64(efe->logblks_rec);
1582 l_ad = udf_rw32(efe->l_ad);
1583 l_ea = udf_rw32(efe->l_ea);
1584 crclen = udf_rw16(efe->tag.desc_crc_len);
1585 icb = &efe->icbtag;
1587 /* set our allocation to shorts if not already done */
1588 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC);
1590 /* append short_ad */
1591 bpos = (uint8_t *) efe->data + l_ea + l_ad;
1592 memcpy(bpos, mapping, sizeof(struct short_ad));
1594 l_ad += sizeof(struct short_ad);
1595 crclen += sizeof(struct short_ad);
1596 inf_len += UDF_EXT_LEN(udf_rw32(mapping->len));
1597 obj_size += UDF_EXT_LEN(udf_rw32(mapping->len));
1598 logblks_rec = UDF_ROUNDUP(inf_len, context.sector_size) /
1599 context.sector_size;
1601 efe->l_ad = udf_rw32(l_ad);
1602 efe->inf_len = udf_rw64(inf_len);
1603 efe->obj_size = udf_rw64(obj_size);
1604 efe->logblks_rec = udf_rw64(logblks_rec);
1605 efe->tag.desc_crc_len = udf_rw16(crclen);
1609 static void
1610 udf_append_meta_mapping_to_efe(struct extfile_entry *efe, uint16_t partnr, uint32_t lb_num,
1611 uint64_t len)
1613 struct short_ad mapping;
1614 uint64_t max_len, part_len;
1616 /* calculate max length meta allocation sizes */
1617 max_len = UDF_EXT_MAXLEN / context.sector_size; /* in sectors */
1618 max_len = (max_len / layout.meta_blockingnr) * layout.meta_blockingnr;
1619 max_len = max_len * context.sector_size;
1621 memset(&mapping, 0, sizeof(struct short_ad));
1622 while (len) {
1623 part_len = MIN(len, max_len);
1624 mapping.lb_num = udf_rw32(lb_num);
1625 mapping.len = udf_rw32(part_len);
1627 udf_append_mapping_part_to_efe(efe, &mapping);
1629 lb_num += part_len / context.sector_size;
1630 len -= part_len;
1636 udf_create_meta_files(void)
1638 struct extfile_entry *efe;
1639 struct long_ad meta_icb;
1640 uint64_t bytes;
1641 uint32_t sector_size;
1642 int filetype, error;
1644 sector_size = context.sector_size;
1646 bzero(&meta_icb, sizeof(struct long_ad));
1647 meta_icb.len = udf_rw32(sector_size);
1648 meta_icb.loc.part_num = udf_rw16(context.data_part);
1650 /* create metadata file */
1651 meta_icb.loc.lb_num = udf_rw32(layout.meta_file);
1652 filetype = UDF_ICB_FILETYPE_META_MAIN;
1653 error = udf_create_new_efe(&efe, filetype, &meta_icb);
1654 if (error)
1655 return error;
1656 context.meta_file = efe;
1658 /* create metadata mirror file */
1659 meta_icb.loc.lb_num = udf_rw32(layout.meta_mirror);
1660 filetype = UDF_ICB_FILETYPE_META_MIRROR;
1661 error = udf_create_new_efe(&efe, filetype, &meta_icb);
1662 if (error)
1663 return error;
1664 context.meta_mirror = efe;
1666 /* create metadata bitmap file */
1667 meta_icb.loc.lb_num = udf_rw32(layout.meta_bitmap);
1668 filetype = UDF_ICB_FILETYPE_META_BITMAP;
1669 error = udf_create_new_efe(&efe, filetype, &meta_icb);
1670 if (error)
1671 return error;
1672 context.meta_bitmap = efe;
1674 /* patch up files */
1675 context.meta_file->unique_id = udf_rw64(0);
1676 context.meta_mirror->unique_id = udf_rw64(0);
1677 context.meta_bitmap->unique_id = udf_rw64(0);
1679 /* restart unique id */
1680 context.unique_id = 0x10;
1682 /* XXX no support for metadata mirroring yet */
1683 /* insert extents */
1684 efe = context.meta_file;
1685 udf_append_meta_mapping_to_efe(efe, context.data_part,
1686 layout.meta_part_start_lba,
1687 (uint64_t) layout.meta_part_size_lba * sector_size);
1689 efe = context.meta_mirror;
1690 udf_append_meta_mapping_to_efe(efe, context.data_part,
1691 layout.meta_part_start_lba,
1692 (uint64_t) layout.meta_part_size_lba * sector_size);
1694 efe = context.meta_bitmap;
1695 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
1696 udf_append_meta_mapping_to_efe(efe, context.data_part,
1697 layout.meta_bitmap_space, bytes);
1699 return 0;
1703 /* --------------------------------------------------------------------- */
1706 udf_create_new_rootdir(union dscrptr **dscr)
1708 struct file_entry *fe;
1709 struct extfile_entry *efe;
1710 struct long_ad root_icb;
1711 int filetype, error;
1713 bzero(&root_icb, sizeof(struct long_ad));
1714 root_icb.len = udf_rw32(context.sector_size);
1715 root_icb.loc.lb_num = udf_rw32(layout.rootdir);
1716 root_icb.loc.part_num = udf_rw16(context.metadata_part);
1718 filetype = UDF_ICB_FILETYPE_DIRECTORY;
1719 if (context.dscrver == 2) {
1720 error = udf_create_new_fe(&fe, filetype, &root_icb);
1721 *dscr = (union dscrptr *) fe;
1722 } else {
1723 error = udf_create_new_efe(&efe, filetype, &root_icb);
1724 *dscr = (union dscrptr *) efe;
1726 if (error)
1727 return error;
1729 /* Rootdir has explicit only one link on creation; '..' is no link */
1730 if (context.dscrver == 2) {
1731 fe->link_cnt = udf_rw16(1);
1732 } else {
1733 efe->link_cnt = udf_rw16(1);
1736 context.num_directories++;
1737 assert(context.num_directories == 1);
1739 return 0;
1744 udf_create_new_VAT(union dscrptr **vat_dscr)
1746 struct file_entry *fe;
1747 struct extfile_entry *efe;
1748 struct impl_extattr_entry *implext;
1749 struct vatlvext_extattr_entry *vatlvext;
1750 struct udf_oldvat_tail *oldvat_tail;
1751 struct udf_vat *vathdr;
1752 uint32_t *vat_pos;
1753 uint8_t *bpos, *extattr;
1754 uint32_t ea_len, inf_len, vat_len;
1755 int filetype;
1756 int error;
1758 assert((layout.rootdir < 2) && (layout.fsd < 2));
1759 if (context.dscrver == 2) {
1760 /* old style VAT */
1761 filetype = UDF_ICB_FILETYPE_UNKNOWN;
1762 error = udf_create_new_fe(&fe, filetype, NULL);
1763 if (error)
1764 return error;
1766 /* append VAT LVExtension attribute */
1767 ea_len = sizeof(struct impl_extattr_entry) - 1 +
1768 sizeof(struct vatlvext_extattr_entry) + 4;
1770 extattr = calloc(1, ea_len);
1772 implext = (struct impl_extattr_entry *) extattr;
1773 implext->hdr.type = udf_rw32(2048); /* [4/48.10.8] */
1774 implext->hdr.subtype = 1; /* [4/48.10.8.2] */
1775 implext->hdr.a_l = udf_rw32(ea_len); /* VAT LVext EA size */
1776 /* use 4 bytes of imp use for UDF checksum [UDF 3.3.4.5] */
1777 implext->iu_l = udf_rw32(4);
1778 udf_set_regid(&implext->imp_id, "*UDF VAT LVExtension");
1779 udf_add_udf_regid(&implext->imp_id);
1781 /* VAT LVExtension data follows UDF IU space */
1782 bpos = ((uint8_t *) implext->data) + 4;
1783 vatlvext = (struct vatlvext_extattr_entry *) bpos;
1785 vatlvext->unique_id_chk = udf_rw64(fe->unique_id);
1786 vatlvext->num_files = udf_rw32(context.num_files);
1787 vatlvext->num_directories = udf_rw32(context.num_directories);
1788 memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id, 128);
1790 udf_extattr_append_internal((union dscrptr *) fe,
1791 (struct extattr_entry *) extattr);
1793 free(extattr);
1795 /* writeout VAT locations (partition offsets) */
1796 vat_pos = (uint32_t *) (fe->data + udf_rw32(fe->l_ea));
1797 vat_pos[layout.rootdir] = udf_rw32(layout.rootdir);
1798 vat_pos[layout.fsd ] = udf_rw32(layout.fsd);
1800 /* Append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
1801 oldvat_tail = (struct udf_oldvat_tail *) (vat_pos + 2);
1802 udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
1803 udf_add_udf_regid(&oldvat_tail->id);
1804 oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
1806 /* set length */
1807 inf_len = 2 * 4 + sizeof(struct udf_oldvat_tail);
1808 fe->inf_len = udf_rw64(inf_len);
1809 fe->l_ad = udf_rw32(inf_len);
1811 /* update vat descriptor's CRC length */
1812 vat_len = inf_len + udf_rw32(fe->l_ea) +
1813 sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
1814 fe->tag.desc_crc_len = udf_rw16(vat_len);
1816 *vat_dscr = (union dscrptr *) fe;
1817 } else {
1818 /* new style VAT */
1819 filetype = UDF_ICB_FILETYPE_VAT;
1820 error = udf_create_new_efe(&efe, filetype, NULL);
1821 if (error)
1822 return error;
1824 /* set up VATv2 descriptor */
1825 vathdr = (struct udf_vat *) efe->data;
1826 vathdr->header_len = udf_rw16(sizeof(struct udf_vat) - 1);
1827 vathdr->impl_use_len = udf_rw16(0);
1828 memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
1829 vathdr->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
1830 vathdr->num_files = udf_rw32(context.num_files);
1831 vathdr->num_directories = udf_rw32(context.num_directories);
1833 vathdr->min_udf_readver = udf_rw16(context.min_udf);
1834 vathdr->min_udf_writever = udf_rw16(context.min_udf);
1835 vathdr->max_udf_writever = udf_rw16(context.max_udf);
1837 /* writeout VAT locations */
1838 vat_pos = (uint32_t *) vathdr->data;
1839 vat_pos[layout.rootdir] = udf_rw32(layout.rootdir);
1840 vat_pos[layout.fsd ] = udf_rw32(layout.fsd);
1842 /* set length */
1843 inf_len = 2 * 4 + sizeof(struct udf_vat) - 1;
1844 efe->inf_len = udf_rw64(inf_len);
1845 efe->obj_size = udf_rw64(inf_len);
1846 efe->l_ad = udf_rw32(inf_len);
1847 efe->logblks_rec = udf_rw32(0);
1849 vat_len = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH;
1850 vat_len += inf_len;
1851 efe->tag.desc_crc_len = udf_rw16(vat_len);
1853 *vat_dscr = (union dscrptr *) efe;
1856 return 0;