Sync some manuals from bin & sbin with NetBSD-8
[minix.git] / sbin / newfs_udf / udf_create.c
blobef92874af60700384cf6217714aa2ead24706dfb
1 /* $NetBSD: udf_create.c,v 1.25 2015/06/16 23:18:55 christos 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.
28 #if HAVE_NBTOOL_CONFIG_H
29 #include "nbtool_config.h"
30 #endif
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: udf_create.c,v 1.25 2015/06/16 23:18:55 christos Exp $");
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <time.h>
41 #include <assert.h>
42 #include <err.h>
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include "unicode.h"
46 #include "udf_create.h"
49 #if 0
50 # ifndef DEBUG
51 # define DEBUG
52 # endif
53 #endif
56 * NOTE that there is some overlap between this code and the udf kernel fs.
57 * This is intentially though it might better be factored out one day.
60 void
61 udf_init_create_context(void)
63 /* clear */
64 memset(&context, 0, sizeof(struct udf_create_context));
66 /* fill with defaults currently known */
67 context.dscrver = 3;
68 context.min_udf = 0x0102;
69 context.max_udf = 0x0260;
70 context.serialnum = 1; /* default */
72 context.gmtoff = 0;
73 context.sector_size = 512; /* minimum for UDF */
75 context.logvol_name = NULL;
76 context.primary_name = NULL;
77 context.volset_name = NULL;
78 context.fileset_name = NULL;
80 /* most basic identification */
81 context.app_name = "*NetBSD";
82 context.app_version_main = 0;
83 context.app_version_sub = 0;
84 context.impl_name = "*NetBSD";
86 context.vds_seq = 0; /* first one starts with zero */
88 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
89 context.unique_id = 0x10;
91 context.num_files = 0;
92 context.num_directories = 0;
94 context.data_part = 0;
95 context.metadata_part = 0;
96 context.metadata_alloc_pos = 0;
97 context.data_alloc_pos = 0;
101 /* version can be specified as 0xabc or a.bc */
102 static int
103 parse_udfversion(const char *pos, uint32_t *version) {
104 int hex = 0;
105 char c1, c2, c3, c4;
107 *version = 0;
108 if (*pos == '0') {
109 pos++;
110 /* expect hex format */
111 hex = 1;
112 if (*pos++ != 'x')
113 return 1;
116 c1 = *pos++;
117 if (c1 < '0' || c1 > '9')
118 return 1;
119 c1 -= '0';
121 c2 = *pos++;
122 if (!hex) {
123 if (c2 != '.')
124 return 1;
125 c2 = *pos++;
127 if (c2 < '0' || c2 > '9')
128 return 1;
129 c2 -= '0';
131 c3 = *pos++;
132 if (c3 < '0' || c3 > '9')
133 return 1;
134 c3 -= '0';
136 c4 = *pos++;
137 if (c4 != 0)
138 return 1;
140 *version = c1 * 0x100 + c2 * 0x10 + c3;
141 return 0;
145 /* parse a given string for an udf version */
147 a_udf_version(const char *s, const char *id_type)
149 uint32_t version;
151 if (parse_udfversion(s, &version))
152 errx(1, "unknown %s id %s; specify as hex or float", id_type, s);
153 return version;
157 static uint32_t
158 udf_space_bitmap_len(uint32_t part_size)
160 return sizeof(struct space_bitmap_desc)-1 +
161 part_size/8;
165 static uint32_t
166 udf_bytes_to_sectors(uint64_t bytes)
168 uint32_t sector_size = layout.sector_size;
169 return (bytes + sector_size -1) / sector_size;
174 udf_calculate_disc_layout(int format_flags, int min_udf,
175 uint32_t wrtrack_skew,
176 uint32_t first_lba, uint32_t last_lba,
177 uint32_t sector_size, uint32_t blockingnr,
178 uint32_t sparable_blocks, float meta_fract)
180 uint64_t kbsize, bytes;
181 uint32_t sparable_blockingnr;
182 uint32_t align_blockingnr;
183 uint32_t pos, mpos;
185 /* clear */
186 memset(&layout, 0, sizeof(layout));
188 /* fill with parameters */
189 layout.wrtrack_skew = wrtrack_skew;
190 layout.first_lba = first_lba;
191 layout.last_lba = last_lba;
192 layout.sector_size = sector_size;
193 layout.blockingnr = blockingnr;
194 layout.sparable_blocks = sparable_blocks;
196 /* start disc layouting */
199 * location of iso9660 vrs is defined as first sector AFTER 32kb,
200 * minimum `sector size' 2048
202 layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
203 + first_lba;
205 /* anchor starts at specified offset in sectors */
206 layout.anchors[0] = first_lba + 256;
207 if (format_flags & FORMAT_TRACK512)
208 layout.anchors[0] = first_lba + 512;
209 layout.anchors[1] = last_lba - 256;
210 layout.anchors[2] = last_lba;
212 /* update workable space */
213 first_lba = layout.anchors[0] + blockingnr;
214 last_lba = layout.anchors[1] - 1;
216 /* XXX rest of anchor packet can be added to unallocated space descr */
218 /* reserve space for VRS and VRS copy and associated tables */
219 layout.vds_size = MAX(16, blockingnr); /* UDF 2.2.3.1+2 */
220 layout.vds1 = first_lba;
221 first_lba += layout.vds_size; /* next packet */
223 if (format_flags & FORMAT_SEQUENTIAL) {
224 /* for sequential, append them ASAP */
225 layout.vds2 = first_lba;
226 first_lba += layout.vds_size;
227 } else {
228 layout.vds2 = layout.anchors[1] - layout.vds_size;
229 last_lba = layout.vds2 - 1; /* XXX -1 ?? */
232 /* reserve space for logvol integrity sequence */
233 layout.lvis_size = MAX(8192/sector_size, 2 * blockingnr);
234 if (format_flags & FORMAT_VAT)
235 layout.lvis_size = 2;
236 if (format_flags & FORMAT_WORM)
237 layout.lvis_size = 64 * blockingnr;
239 /* TODO skip bad blocks in LVID sequence; for now use f.e. */
240 //first_lba+=128;
241 layout.lvis = first_lba;
242 first_lba += layout.lvis_size;
244 /* initial guess of UDF partition size */
245 layout.part_start_lba = first_lba;
246 layout.part_size_lba = last_lba - layout.part_start_lba;
248 /* all non sequential media needs an unallocated space bitmap */
249 layout.alloc_bitmap_dscr_size = 0;
250 if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
251 bytes = udf_space_bitmap_len(layout.part_size_lba);
252 layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
254 /* XXX freed space map when applicable */
258 * Note that for (bug) compatibility with version UDF 2.00 (fixed in
259 * 2.01 and higher) the blocking size needs to be 32 sectors otherwise
260 * the drive's blockingnr.
263 sparable_blockingnr = blockingnr;
264 if (min_udf <= 0x200)
265 sparable_blockingnr = 32;
267 align_blockingnr = blockingnr;
268 if (format_flags & (FORMAT_SPARABLE | FORMAT_META))
269 align_blockingnr = sparable_blockingnr;
271 layout.align_blockingnr = align_blockingnr;
272 layout.sparable_blockingnr = sparable_blockingnr;
275 * Align partition LBA space to blocking granularity. Not strickly
276 * nessisary for non sparables but safer for the VRS data since it is
277 * not updated sporadically
280 if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
281 #ifdef DEBUG
282 printf("Lost %d slack sectors at start\n", UDF_ROUNDUP(
283 first_lba - wrtrack_skew, align_blockingnr) -
284 (first_lba - wrtrack_skew));
285 printf("Lost %d slack sectors at end\n",
286 (first_lba - wrtrack_skew) - UDF_ROUNDDOWN(
287 first_lba - wrtrack_skew, align_blockingnr));
288 #endif
290 first_lba = UDF_ROUNDUP( first_lba - wrtrack_skew,
291 align_blockingnr);
292 last_lba = UDF_ROUNDDOWN(last_lba - wrtrack_skew,
293 align_blockingnr);
296 if ((format_flags & FORMAT_SPARABLE) == 0)
297 layout.sparable_blocks = 0;
299 if (format_flags & FORMAT_SPARABLE) {
300 layout.sparable_area_size =
301 layout.sparable_blocks * sparable_blockingnr;
303 /* a sparing table descriptor is a whole blockingnr sectors */
304 layout.sparing_table_dscr_lbas = sparable_blockingnr;
306 /* place the descriptors at the start and end of the area */
307 layout.spt_1 = first_lba;
308 first_lba += layout.sparing_table_dscr_lbas;
310 layout.spt_2 = last_lba - layout.sparing_table_dscr_lbas;
311 last_lba -= layout.sparing_table_dscr_lbas;
313 /* allocate sparable section */
314 layout.sparable_area = first_lba;
315 first_lba += layout.sparable_area_size;
318 /* update guess of UDF partition size */
319 layout.part_start_lba = first_lba;
320 layout.part_size_lba = last_lba - layout.part_start_lba;
322 /* determine partition selection for data and metadata */
323 context.data_part = 0;
324 context.metadata_part = context.data_part;
325 if ((format_flags & FORMAT_VAT) || (format_flags & FORMAT_META))
326 context.metadata_part = context.data_part + 1;
329 * Pick fixed logical space sector numbers for main FSD, rootdir and
330 * unallocated space. The reason for this pre-allocation is that they
331 * are referenced in the volume descriptor sequence and hence can't be
332 * allocated later.
334 pos = 0;
335 layout.unalloc_space = pos;
336 pos += layout.alloc_bitmap_dscr_size;
338 /* claim metadata descriptors and partition space [UDF 2.2.10] */
339 if (format_flags & FORMAT_META) {
340 /* note: all in backing partition space */
341 layout.meta_file = pos++;
342 layout.meta_bitmap = pos++;;
343 layout.meta_mirror = layout.part_size_lba-1;
344 layout.meta_alignment = MAX(blockingnr, sparable_blockingnr);
345 layout.meta_blockingnr = MAX(layout.meta_alignment, 32);
347 /* calculate our partition length and store in sectors */
348 layout.meta_part_size_lba = layout.part_size_lba * meta_fract;
349 layout.meta_part_size_lba = MAX(layout.meta_part_size_lba, 32);
350 layout.meta_part_size_lba =
351 UDF_ROUNDDOWN(layout.meta_part_size_lba, layout.meta_blockingnr);
353 /* calculate positions */
354 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
355 layout.meta_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
357 layout.meta_bitmap_space = pos;
358 pos += layout.meta_bitmap_dscr_size;
360 layout.meta_part_start_lba = UDF_ROUNDUP(pos, layout.meta_alignment);
363 mpos = (context.metadata_part == context.data_part) ? pos : 0;
364 layout.fsd = mpos; mpos += 1;
365 layout.rootdir = mpos; mpos += 1;
366 layout.vat = mpos; mpos += 1; /* if present */
368 #if 0
369 printf("Summary so far\n");
370 printf("\tiso9660_vrs\t\t%d\n", layout.iso9660_vrs);
371 printf("\tanchor0\t\t\t%d\n", layout.anchors[0]);
372 printf("\tanchor1\t\t\t%d\n", layout.anchors[1]);
373 printf("\tanchor2\t\t\t%d\n", layout.anchors[2]);
374 printf("\tvds_size\t\t%d\n", layout.vds_size);
375 printf("\tvds1\t\t\t%d\n", layout.vds1);
376 printf("\tvds2\t\t\t%d\n", layout.vds2);
377 printf("\tlvis_size\t\t%d\n", layout.lvis_size);
378 printf("\tlvis\t\t\t%d\n", layout.lvis);
379 if (format_flags & FORMAT_SPARABLE) {
380 printf("\tsparable size\t\t%d\n", layout.sparable_area_size);
381 printf("\tsparable\t\t%d\n", layout.sparable_area);
383 printf("\tpartition start lba\t%d\n", layout.part_start_lba);
384 printf("\tpartition size\t\t%d KiB, %d MiB\n",
385 (layout.part_size_lba * sector_size) / 1024,
386 (layout.part_size_lba * sector_size) / (1024*1024));
387 if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
388 printf("\tpart bitmap start\t%d\n", layout.unalloc_space);
389 printf("\t\tfor %d lba\n", layout.alloc_bitmap_dscr_size);
391 if (format_flags & FORMAT_META) {
392 printf("\tmeta blockingnr\t\t%d\n", layout.meta_blockingnr);
393 printf("\tmeta alignment\t\t%d\n", layout.meta_alignment);
394 printf("\tmeta size\t\t%d KiB, %d MiB\n",
395 (layout.meta_part_size_lba * sector_size) / 1024,
396 (layout.meta_part_size_lba * sector_size) / (1024*1024));
397 printf("\tmeta file\t\t%d\n", layout.meta_file);
398 printf("\tmeta mirror\t\t%d\n", layout.meta_mirror);
399 printf("\tmeta bitmap\t\t%d\n", layout.meta_bitmap);
400 printf("\tmeta bitmap start\t%d\n", layout.meta_bitmap_space);
401 printf("\t\tfor %d lba\n", layout.meta_bitmap_dscr_size);
402 printf("\tmeta space start\t%d\n", layout.meta_part_start_lba);
403 printf("\t\tfor %d lba\n", layout.meta_part_size_lba);
405 printf("\n");
406 #endif
408 kbsize = (uint64_t) last_lba * sector_size;
409 printf("Total space on this medium approx. "
410 "%"PRIu64" KiB, %"PRIu64" MiB\n",
411 kbsize/1024, kbsize/(1024*1024));
412 kbsize = (uint64_t)(layout.part_size_lba - layout.alloc_bitmap_dscr_size
413 - layout.meta_bitmap_dscr_size) * sector_size;
414 printf("Free space on this volume approx. "
415 "%"PRIu64" KiB, %"PRIu64" MiB\n\n",
416 kbsize/1024, kbsize/(1024*1024));
418 return 0;
423 udf_validate_tag_sum(union dscrptr *dscr)
425 struct desc_tag *tag = &dscr->tag;
426 uint8_t *pos, sum, cnt;
428 /* calculate TAG header checksum */
429 pos = (uint8_t *) tag;
430 sum = 0;
432 for(cnt = 0; cnt < 16; cnt++) {
433 if (cnt != 4) sum += *pos;
434 pos++;
436 tag->cksum = sum; /* 8 bit */
438 return 0;
442 /* assumes sector number of descriptor to be allready present */
444 udf_validate_tag_and_crc_sums(union dscrptr *dscr)
446 struct desc_tag *tag = &dscr->tag;
447 uint16_t crc;
449 /* check payload CRC if applicable */
450 if (udf_rw16(tag->desc_crc_len) > 0) {
451 crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH,
452 udf_rw16(tag->desc_crc_len));
453 tag->desc_crc = udf_rw16(crc);
456 /* calculate TAG header checksum */
457 return udf_validate_tag_sum(dscr);
461 void
462 udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc)
464 tag->id = udf_rw16(tagid);
465 tag->descriptor_ver = udf_rw16(context.dscrver);
466 tag->cksum = 0;
467 tag->reserved = 0;
468 tag->serial_num = udf_rw16(context.serialnum);
469 tag->tag_loc = udf_rw32(loc);
474 udf_create_anchor(int num)
476 struct anchor_vdp *avdp;
477 uint32_t vds_extent_len = layout.vds_size * context.sector_size;
479 if ((avdp = calloc(1, context.sector_size)) == NULL)
480 return ENOMEM;
482 udf_inittag(&avdp->tag, TAGID_ANCHOR, layout.anchors[num]);
484 avdp->main_vds_ex.loc = udf_rw32(layout.vds1);
485 avdp->main_vds_ex.len = udf_rw32(vds_extent_len);
487 avdp->reserve_vds_ex.loc = udf_rw32(layout.vds2);
488 avdp->reserve_vds_ex.len = udf_rw32(vds_extent_len);
490 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
491 avdp->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
493 context.anchors[num] = avdp;
494 return 0;
498 void
499 udf_create_terminator(union dscrptr *dscr, uint32_t loc)
501 memset(dscr, 0, context.sector_size);
502 udf_inittag(&dscr->tag, TAGID_TERM, loc);
504 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
505 dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
509 void
510 udf_osta_charset(struct charspec *charspec)
512 memset(charspec, 0, sizeof(*charspec));
513 charspec->type = 0;
514 strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
518 void
519 udf_encode_osta_id(char *osta_id, uint16_t len, char *text)
521 uint16_t u16_name[1024];
522 uint8_t *pos;
523 uint16_t *pos16;
525 memset(osta_id, 0, len);
526 if (!text || (strlen(text) == 0)) return;
528 memset(u16_name, 0, sizeof(uint16_t) * 1023);
530 /* convert ascii to 16 bits unicode */
531 pos = (uint8_t *) text;
532 pos16 = u16_name;
533 while (*pos) {
534 *pos16 = *pos;
535 pos++; pos16++;
537 *pos16 = 0;
539 udf_CompressUnicode(len, 8, (unicode_t *) u16_name, (byte *) osta_id);
541 /* Ecma 167/7.2.13 states that length is recorded in the last byte */
542 osta_id[len-1] = strlen(text)+1;
546 /* first call udf_set_regid and then the suffix */
547 void
548 udf_set_regid(struct regid *regid, char const *name)
550 memset(regid, 0, sizeof(*regid));
551 regid->flags = 0; /* not dirty and not protected */
552 strcpy((char *) regid->id, name);
556 void
557 udf_add_domain_regid(struct regid *regid)
559 uint16_t *ver;
561 ver = (uint16_t *) regid->id_suffix;
562 *ver = udf_rw16(context.min_udf);
566 void
567 udf_add_udf_regid(struct regid *regid)
569 uint16_t *ver;
571 ver = (uint16_t *) regid->id_suffix;
572 *ver = udf_rw16(context.min_udf);
574 regid->id_suffix[2] = 4; /* unix */
575 regid->id_suffix[3] = 8; /* NetBSD */
579 void
580 udf_add_impl_regid(struct regid *regid)
582 regid->id_suffix[0] = 4; /* unix */
583 regid->id_suffix[1] = 8; /* NetBSD */
587 void
588 udf_add_app_regid(struct regid *regid)
590 regid->id_suffix[0] = context.app_version_main;
591 regid->id_suffix[1] = context.app_version_sub;
596 * Fill in timestamp structure based on clock_gettime(). Time is reported back
597 * as a time_t accompanied with a nano second field.
599 * The husec, usec and csec could be relaxed in type.
601 static void
602 udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp)
604 struct tm tm;
605 uint64_t husec, usec, csec;
607 memset(timestamp, 0, sizeof(*timestamp));
608 gmtime_r(&timespec->tv_sec, &tm);
611 * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1.
613 * Lower 12 bits are two complement signed timezone offset if bit 12
614 * (method 1) is clear. Otherwise if bit 12 is set, specify timezone
615 * offset to -2047 i.e. unsigned `zero'
618 /* set method 1 for CUT/GMT */
619 timestamp->type_tz = udf_rw16((1<<12) + 0);
620 timestamp->year = udf_rw16(tm.tm_year + 1900);
621 timestamp->month = tm.tm_mon + 1; /* `tm' uses 0..11 for months */
622 timestamp->day = tm.tm_mday;
623 timestamp->hour = tm.tm_hour;
624 timestamp->minute = tm.tm_min;
625 timestamp->second = tm.tm_sec;
627 usec = (timespec->tv_nsec + 500) / 1000; /* round */
628 husec = usec / 100;
629 usec -= husec * 100; /* only 0-99 in usec */
630 csec = husec / 100; /* only 0-99 in csec */
631 husec -= csec * 100; /* only 0-99 in husec */
633 /* in rare cases there is overflow in csec */
634 csec = MIN(99, csec);
635 husec = MIN(99, husec);
636 usec = MIN(99, usec);
638 timestamp->centisec = csec;
639 timestamp->hund_usec = husec;
640 timestamp->usec = usec;
644 void
645 udf_set_timestamp_now(struct timestamp *timestamp)
647 struct timespec now;
649 #ifdef CLOCK_REALTIME
650 (void)clock_gettime(CLOCK_REALTIME, &now);
651 #else
652 struct timeval time_of_day;
654 (void)gettimeofday(&time_of_day, NULL);
655 now.tv_sec = time_of_day.tv_sec;
656 now.tv_nsec = time_of_day.tv_usec * 1000;
657 #endif
658 udf_timespec_to_timestamp(&now, timestamp);
662 /* some code copied from sys/fs/udf */
664 static void
665 udf_set_timestamp(struct timestamp *timestamp, time_t value)
667 struct timespec t;
669 memset(&t, 0, sizeof(struct timespec));
670 t.tv_sec = value;
671 t.tv_nsec = 0;
672 udf_timespec_to_timestamp(&t, timestamp);
676 static uint32_t
677 unix_mode_to_udf_perm(mode_t mode)
679 uint32_t perm;
681 perm = ((mode & S_IRWXO) );
682 perm |= ((mode & S_IRWXG) << 2);
683 perm |= ((mode & S_IRWXU) << 4);
684 perm |= ((mode & S_IWOTH) << 3);
685 perm |= ((mode & S_IWGRP) << 5);
686 perm |= ((mode & S_IWUSR) << 7);
688 return perm;
691 /* end of copied code */
695 udf_create_primaryd(void)
697 struct pri_vol_desc *pri;
698 uint16_t crclen;
700 pri = calloc(1, context.sector_size);
701 if (pri == NULL)
702 return ENOMEM;
704 memset(pri, 0, context.sector_size);
705 udf_inittag(&pri->tag, TAGID_PRI_VOL, /* loc */ 0);
706 pri->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
708 pri->pvd_num = udf_rw32(0); /* default serial */
709 udf_encode_osta_id(pri->vol_id, 32, context.primary_name);
711 /* set defaults for single disc volumes as UDF prescribes */
712 pri->vds_num = udf_rw16(1);
713 pri->max_vol_seq = udf_rw16(1);
714 pri->ichg_lvl = udf_rw16(2);
715 pri->max_ichg_lvl = udf_rw16(3);
716 pri->flags = udf_rw16(0);
718 pri->charset_list = udf_rw32(1); /* only CS0 */
719 pri->max_charset_list = udf_rw32(1); /* only CS0 */
721 udf_encode_osta_id(pri->volset_id, 128, context.volset_name);
722 udf_osta_charset(&pri->desc_charset);
723 udf_osta_charset(&pri->explanatory_charset);
725 udf_set_regid(&pri->app_id, context.app_name);
726 udf_add_app_regid(&pri->app_id);
728 udf_set_regid(&pri->imp_id, context.impl_name);
729 udf_add_impl_regid(&pri->imp_id);
731 udf_set_timestamp_now(&pri->time);
733 crclen = sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH;
734 pri->tag.desc_crc_len = udf_rw16(crclen);
736 context.primary_vol = pri;
738 return 0;
742 /* XXX no support for unallocated or freed space tables yet (!) */
744 udf_create_partitiond(int part_num, int part_accesstype)
746 struct part_desc *pd;
747 struct part_hdr_desc *phd;
748 uint32_t sector_size, bitmap_bytes;
749 uint16_t crclen;
751 sector_size = context.sector_size;
752 bitmap_bytes = layout.alloc_bitmap_dscr_size * sector_size;
754 if (context.partitions[part_num]) {
755 printf("Internal error: partition %d allready defined\n",
756 part_num);
757 return EINVAL;
760 pd = calloc(1, context.sector_size);
761 if (pd == NULL)
762 return ENOMEM;
763 phd = &pd->_impl_use.part_hdr;
765 udf_inittag(&pd->tag, TAGID_PARTITION, /* loc */ 0);
766 pd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
768 pd->flags = udf_rw16(1); /* allocated */
769 pd->part_num = udf_rw16(part_num); /* only one physical partition */
771 if (context.dscrver == 2) {
772 udf_set_regid(&pd->contents, "+NSR02");
773 } else {
774 udf_set_regid(&pd->contents, "+NSR03");
776 udf_add_app_regid(&pd->contents);
778 phd->unalloc_space_bitmap.len = udf_rw32(bitmap_bytes);
779 phd->unalloc_space_bitmap.lb_num = udf_rw32(layout.unalloc_space);
781 if (layout.freed_space) {
782 phd->freed_space_bitmap.len = udf_rw32(bitmap_bytes);
783 phd->freed_space_bitmap.lb_num = udf_rw32(layout.freed_space);
786 pd->access_type = udf_rw32(part_accesstype);
787 pd->start_loc = udf_rw32(layout.part_start_lba);
788 pd->part_len = udf_rw32(layout.part_size_lba);
790 udf_set_regid(&pd->imp_id, context.impl_name);
791 udf_add_impl_regid(&pd->imp_id);
793 crclen = sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH;
794 pd->tag.desc_crc_len = udf_rw16(crclen);
796 context.partitions[part_num] = pd;
798 return 0;
803 udf_create_unalloc_spaced(void)
805 struct unalloc_sp_desc *usd;
806 uint16_t crclen;
808 usd = calloc(1, context.sector_size);
809 if (usd == NULL)
810 return ENOMEM;
812 udf_inittag(&usd->tag, TAGID_UNALLOC_SPACE, /* loc */ 0);
813 usd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
815 /* no default entries */
816 usd->alloc_desc_num = udf_rw32(0); /* no entries */
818 crclen = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad);
819 crclen -= UDF_DESC_TAG_LENGTH;
820 usd->tag.desc_crc_len = udf_rw16(crclen);
822 context.unallocated = usd;
824 return 0;
828 static int
829 udf_create_base_logical_dscr(void)
831 struct logvol_desc *lvd;
832 uint32_t sector_size;
833 uint16_t crclen;
835 sector_size = context.sector_size;
837 lvd = calloc(1, sector_size);
838 if (lvd == NULL)
839 return ENOMEM;
841 udf_inittag(&lvd->tag, TAGID_LOGVOL, /* loc */ 0);
842 lvd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
844 udf_osta_charset(&lvd->desc_charset);
845 udf_encode_osta_id(lvd->logvol_id, 128, context.logvol_name);
846 lvd->lb_size = udf_rw32(context.sector_size);
848 udf_set_regid(&lvd->domain_id, "*OSTA UDF Compliant");
849 udf_add_domain_regid(&lvd->domain_id);
851 /* no partition mappings/entries yet */
852 lvd->mt_l = udf_rw32(0);
853 lvd->n_pm = udf_rw32(0);
855 udf_set_regid(&lvd->imp_id, context.impl_name);
856 udf_add_impl_regid(&lvd->imp_id);
858 lvd->integrity_seq_loc.loc = udf_rw32(layout.lvis);
859 lvd->integrity_seq_loc.len = udf_rw32(layout.lvis_size * sector_size);
861 /* just one fsd for now */
862 lvd->lv_fsd_loc.len = udf_rw32(sector_size);
863 lvd->lv_fsd_loc.loc.part_num = udf_rw32(context.metadata_part);
864 lvd->lv_fsd_loc.loc.lb_num = udf_rw32(layout.fsd);
866 crclen = sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH;
867 lvd->tag.desc_crc_len = udf_rw16(crclen);
869 context.logical_vol = lvd;
870 context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
871 context.vtop_offset[UDF_VTOP_RAWPART] = 0;
873 return 0;
877 static void
878 udf_add_logvol_part_physical(uint16_t phys_part)
880 struct logvol_desc *logvol = context.logical_vol;
881 union udf_pmap *pmap;
882 uint8_t *pmap_pos;
883 uint16_t crclen;
884 uint32_t pmap1_size, log_part;
886 log_part = udf_rw32(logvol->n_pm);
887 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
888 pmap1_size = sizeof(struct part_map_1);
890 pmap = (union udf_pmap *) pmap_pos;
891 pmap->pm1.type = 1;
892 pmap->pm1.len = sizeof(struct part_map_1);
893 pmap->pm1.vol_seq_num = udf_rw16(1); /* no multi-volume */
894 pmap->pm1.part_num = udf_rw16(phys_part);
896 context.vtop [log_part] = phys_part;
897 context.vtop_tp [log_part] = UDF_VTOP_TYPE_PHYS;
898 context.vtop_offset[log_part] = layout.part_start_lba;
899 context.part_size[log_part] = layout.part_size_lba;
900 context.part_free[log_part] = layout.part_size_lba;
902 /* increment number of partitions and length */
903 logvol->n_pm = udf_rw32(log_part + 1);
904 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmap1_size);
906 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmap1_size;
907 logvol->tag.desc_crc_len = udf_rw16(crclen);
911 static void
912 udf_add_logvol_part_virtual(uint16_t phys_part)
914 union udf_pmap *pmap;
915 struct logvol_desc *logvol = context.logical_vol;
916 uint8_t *pmap_pos;
917 uint16_t crclen;
918 uint32_t pmapv_size, log_part;
920 log_part = udf_rw32(logvol->n_pm);
921 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
922 pmapv_size = sizeof(struct part_map_2);
924 pmap = (union udf_pmap *) pmap_pos;
925 pmap->pmv.type = 2;
926 pmap->pmv.len = pmapv_size;
928 udf_set_regid(&pmap->pmv.id, "*UDF Virtual Partition");
929 udf_add_udf_regid(&pmap->pmv.id);
931 pmap->pmv.vol_seq_num = udf_rw16(1); /* no multi-volume */
932 pmap->pmv.part_num = udf_rw16(phys_part);
934 context.vtop [log_part] = phys_part;
935 context.vtop_tp [log_part] = UDF_VTOP_TYPE_VIRT;
936 context.vtop_offset[log_part] = context.vtop_offset[phys_part];
937 context.part_size[log_part] = 0xffffffff;
938 context.part_free[log_part] = 0xffffffff;
940 /* increment number of partitions and length */
941 logvol->n_pm = udf_rw32(log_part + 1);
942 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
944 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
945 logvol->tag.desc_crc_len = udf_rw16(crclen);
949 /* sparing table size is in bytes */
950 static void
951 udf_add_logvol_part_sparable(uint16_t phys_part)
953 union udf_pmap *pmap;
954 struct logvol_desc *logvol = context.logical_vol;
955 uint32_t *st_pos, sparable_bytes, pmaps_size;
956 uint8_t *pmap_pos, num;
957 uint16_t crclen;
958 uint32_t log_part;
960 log_part = udf_rw32(logvol->n_pm);
961 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
962 pmaps_size = sizeof(struct part_map_2);
963 sparable_bytes = layout.sparable_area_size * context.sector_size;
965 pmap = (union udf_pmap *) pmap_pos;
966 pmap->pms.type = 2;
967 pmap->pms.len = pmaps_size;
969 udf_set_regid(&pmap->pmv.id, "*UDF Sparable Partition");
970 udf_add_udf_regid(&pmap->pmv.id);
972 pmap->pms.vol_seq_num = udf_rw16(1); /* no multi-volume */
973 pmap->pms.part_num = udf_rw16(phys_part);
975 pmap->pms.packet_len = udf_rw16(layout.sparable_blockingnr);
976 pmap->pms.st_size = udf_rw32(sparable_bytes);
978 /* enter spare tables */
979 st_pos = &pmap->pms.st_loc[0];
980 *st_pos++ = udf_rw32(layout.spt_1);
981 *st_pos++ = udf_rw32(layout.spt_2);
983 num = 2;
984 if (layout.spt_2 == 0) num--;
985 if (layout.spt_1 == 0) num--;
986 pmap->pms.n_st = num; /* 8 bit */
988 /* the vtop_offset needs to explicitly set since there is no phys. */
989 context.vtop [log_part] = phys_part;
990 context.vtop_tp [log_part] = UDF_VTOP_TYPE_SPARABLE;
991 context.vtop_offset[log_part] = layout.part_start_lba;
992 context.part_size[log_part] = layout.part_size_lba;
993 context.part_free[log_part] = layout.part_size_lba;
995 /* increment number of partitions and length */
996 logvol->n_pm = udf_rw32(log_part + 1);
997 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmaps_size);
999 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmaps_size;
1000 logvol->tag.desc_crc_len = udf_rw16(crclen);
1005 udf_create_sparing_tabled(void)
1007 struct udf_sparing_table *spt;
1008 struct spare_map_entry *sme;
1009 uint32_t loc, cnt;
1010 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1012 spt = calloc(context.sector_size, layout.sparing_table_dscr_lbas);
1013 if (spt == NULL)
1014 return ENOMEM;
1016 /* a sparing table descriptor is a whole sparable_blockingnr sectors */
1017 udf_inittag(&spt->tag, TAGID_SPARING_TABLE, /* loc */ 0);
1019 udf_set_regid(&spt->id, "*UDF Sparing Table");
1020 udf_add_udf_regid(&spt->id);
1022 spt->rt_l = udf_rw16(layout.sparable_blocks);
1023 spt->seq_num = udf_rw32(0); /* first generation */
1025 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
1026 sme = &spt->entries[cnt];
1027 loc = layout.sparable_area + cnt * layout.sparable_blockingnr;
1028 sme->org = udf_rw32(0xffffffff); /* open for reloc */
1029 sme->map = udf_rw32(loc);
1032 /* calculate crc len for actual size */
1033 crclen = sizeof(struct udf_sparing_table) - UDF_DESC_TAG_LENGTH;
1034 crclen += (layout.sparable_blocks-1) * sizeof(struct spare_map_entry);
1035 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1036 spt->tag.desc_crc_len = udf_rw16((uint16_t)crclen);
1038 context.sparing_table = spt;
1040 return 0;
1044 static void
1045 udf_add_logvol_part_meta(uint16_t phys_part)
1047 union udf_pmap *pmap;
1048 struct logvol_desc *logvol = context.logical_vol;
1049 uint8_t *pmap_pos;
1050 uint32_t pmapv_size, log_part;
1051 uint16_t crclen;
1053 log_part = udf_rw32(logvol->n_pm);
1054 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1055 pmapv_size = sizeof(struct part_map_2);
1057 pmap = (union udf_pmap *) pmap_pos;
1058 pmap->pmm.type = 2;
1059 pmap->pmm.len = pmapv_size;
1061 udf_set_regid(&pmap->pmm.id, "*UDF Metadata Partition");
1062 udf_add_udf_regid(&pmap->pmm.id);
1064 pmap->pmm.vol_seq_num = udf_rw16(1); /* no multi-volume */
1065 pmap->pmm.part_num = udf_rw16(phys_part);
1067 /* fill in meta data file(s) and alloc/alignment unit sizes */
1068 pmap->pmm.meta_file_lbn = udf_rw32(layout.meta_file);
1069 pmap->pmm.meta_mirror_file_lbn = udf_rw32(layout.meta_mirror);
1070 pmap->pmm.meta_bitmap_file_lbn = udf_rw32(layout.meta_bitmap);
1071 pmap->pmm.alloc_unit_size = udf_rw32(layout.meta_blockingnr);
1072 pmap->pmm.alignment_unit_size = udf_rw16(layout.meta_alignment);
1073 pmap->pmm.flags = 0; /* METADATA_DUPLICATED */
1075 context.vtop [log_part] = phys_part;
1076 context.vtop_tp [log_part] = UDF_VTOP_TYPE_META;
1077 context.vtop_offset[log_part] =
1078 context.vtop_offset[phys_part] + layout.meta_part_start_lba;
1079 context.part_size[log_part] = layout.meta_part_size_lba;
1080 context.part_free[log_part] = layout.meta_part_size_lba;
1082 /* increment number of partitions and length */
1083 logvol->n_pm = udf_rw32(log_part + 1);
1084 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
1086 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
1087 logvol->tag.desc_crc_len = udf_rw16(crclen);
1092 udf_create_logical_dscr(int format_flags)
1094 int error;
1096 if ((error = udf_create_base_logical_dscr()))
1097 return error;
1099 /* we pass data_part for there might be a read-only part one day */
1100 if (format_flags & FORMAT_SPARABLE) {
1101 /* sparable partition mapping has no physical mapping */
1102 udf_add_logvol_part_sparable(context.data_part);
1103 } else {
1104 udf_add_logvol_part_physical(context.data_part);
1107 if (format_flags & FORMAT_VAT) {
1108 /* add VAT virtual mapping; reflects on datapart */
1109 udf_add_logvol_part_virtual(context.data_part);
1111 if (format_flags & FORMAT_META) {
1112 /* add META data mapping; reflects on datapart */
1113 udf_add_logvol_part_meta(context.data_part);
1116 return 0;
1121 udf_create_impvold(char *field1, char *field2, char *field3)
1123 struct impvol_desc *ivd;
1124 struct udf_lv_info *lvi;
1125 uint16_t crclen;
1127 ivd = calloc(1, context.sector_size);
1128 if (ivd == NULL)
1129 return ENOMEM;
1130 lvi = &ivd->_impl_use.lv_info;
1132 udf_inittag(&ivd->tag, TAGID_IMP_VOL, /* loc */ 0);
1133 ivd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1135 udf_set_regid(&ivd->impl_id, "*UDF LV Info");
1136 udf_add_udf_regid(&ivd->impl_id);
1138 /* fill in UDF specific part */
1139 udf_osta_charset(&lvi->lvi_charset);
1140 udf_encode_osta_id(lvi->logvol_id, 128, context.logvol_name);
1142 udf_encode_osta_id(lvi->lvinfo1, 36, field1);
1143 udf_encode_osta_id(lvi->lvinfo2, 36, field2);
1144 udf_encode_osta_id(lvi->lvinfo3, 36, field3);
1146 udf_set_regid(&lvi->impl_id, context.impl_name);
1147 udf_add_impl_regid(&lvi->impl_id);
1149 crclen = sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH;
1150 ivd->tag.desc_crc_len = udf_rw16(crclen);
1152 context.implementation = ivd;
1154 return 0;
1158 /* XXX might need to be sanitised a bit later */
1159 void
1160 udf_update_lvintd(int type)
1162 struct logvol_int_desc *lvid;
1163 struct udf_logvol_info *lvinfo;
1164 struct logvol_desc *logvol;
1165 uint32_t *pos;
1166 uint32_t cnt, l_iu, num_partmappings;
1167 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1169 lvid = context.logvol_integrity;
1170 logvol = context.logical_vol;
1172 assert(lvid);
1173 assert(logvol);
1175 lvid->integrity_type = udf_rw32(type);
1177 num_partmappings = udf_rw32(logvol->n_pm);
1179 udf_set_timestamp_now(&lvid->time);
1181 lvinfo = (struct udf_logvol_info *)
1182 (lvid->tables + num_partmappings * 2);
1183 udf_set_regid(&lvinfo->impl_id, context.impl_name);
1184 udf_add_impl_regid(&lvinfo->impl_id);
1186 lvinfo->num_files = udf_rw32(context.num_files);
1187 lvinfo->num_directories = udf_rw32(context.num_directories);
1189 lvid->lvint_next_unique_id = udf_rw64(context.unique_id);
1191 /* XXX sane enough ? */
1192 lvinfo->min_udf_readver = udf_rw16(context.min_udf);
1193 lvinfo->min_udf_writever = udf_rw16(context.min_udf);
1194 lvinfo->max_udf_writever = udf_rw16(context.max_udf);
1196 lvid->num_part = udf_rw32(num_partmappings);
1198 /* no impl. use needed */
1199 l_iu = sizeof(struct udf_logvol_info);
1200 lvid->l_iu = udf_rw32(l_iu);
1202 pos = &lvid->tables[0];
1203 for (cnt = 0; cnt < num_partmappings; cnt++) {
1204 *pos++ = udf_rw32(context.part_free[cnt]);
1206 for (cnt = 0; cnt < num_partmappings; cnt++) {
1207 *pos++ = udf_rw32(context.part_size[cnt]);
1210 crclen = sizeof(struct logvol_int_desc) -4 -UDF_DESC_TAG_LENGTH + l_iu;
1211 crclen += num_partmappings * 2 * 4;
1212 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1213 lvid->tag.desc_crc_len = udf_rw16(crclen);
1215 context.logvol_info = lvinfo;
1220 udf_create_lvintd(int type)
1222 struct logvol_int_desc *lvid;
1224 lvid = calloc(1, context.sector_size);
1225 if (lvid == NULL)
1226 return ENOMEM;
1228 udf_inittag(&lvid->tag, TAGID_LOGVOL_INTEGRITY, /* loc */ 0);
1230 context.logvol_integrity = lvid;
1232 udf_update_lvintd(type);
1234 return 0;
1239 udf_create_fsd(void)
1241 struct fileset_desc *fsd;
1242 uint16_t crclen;
1244 fsd = calloc(1, context.sector_size);
1245 if (fsd == NULL)
1246 return ENOMEM;
1248 udf_inittag(&fsd->tag, TAGID_FSD, /* loc */ 0);
1250 udf_set_timestamp_now(&fsd->time);
1251 fsd->ichg_lvl = udf_rw16(3); /* UDF 2.3.2.1 */
1252 fsd->max_ichg_lvl = udf_rw16(3); /* UDF 2.3.2.2 */
1254 fsd->charset_list = udf_rw32(1); /* only CS0 */
1255 fsd->max_charset_list = udf_rw32(1); /* only CS0 */
1257 fsd->fileset_num = udf_rw32(0); /* only one fsd */
1258 fsd->fileset_desc_num = udf_rw32(0); /* origional */
1260 udf_osta_charset(&fsd->logvol_id_charset);
1261 udf_encode_osta_id(fsd->logvol_id, 128, context.logvol_name);
1263 udf_osta_charset(&fsd->fileset_charset);
1264 udf_encode_osta_id(fsd->fileset_id, 32, context.fileset_name);
1266 /* copyright file and abstract file names obmitted */
1268 fsd->rootdir_icb.len = udf_rw32(context.sector_size);
1269 fsd->rootdir_icb.loc.lb_num = udf_rw32(layout.rootdir);
1270 fsd->rootdir_icb.loc.part_num = udf_rw16(context.metadata_part);
1272 udf_set_regid(&fsd->domain_id, "*OSTA UDF Compliant");
1273 udf_add_domain_regid(&fsd->domain_id);
1275 /* next_ex stays zero */
1276 /* no system streamdirs yet */
1278 crclen = sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH;
1279 fsd->tag.desc_crc_len = udf_rw16(crclen);
1281 context.fileset_desc = fsd;
1283 return 0;
1288 udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba,
1289 struct space_bitmap_desc **sbdp)
1291 struct space_bitmap_desc *sbd;
1292 uint32_t cnt;
1293 uint16_t crclen;
1295 *sbdp = NULL;
1296 sbd = calloc(context.sector_size, dscr_size);
1297 if (sbd == NULL)
1298 return ENOMEM;
1300 udf_inittag(&sbd->tag, TAGID_SPACE_BITMAP, /* loc */ 0);
1302 sbd->num_bits = udf_rw32(part_size_lba);
1303 sbd->num_bytes = udf_rw32((part_size_lba + 7)/8);
1305 /* fill space with 0xff to indicate free */
1306 for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
1307 sbd->data[cnt] = 0xff;
1309 /* set crc to only cover the header (UDF 2.3.1.2, 2.3.8.1) */
1310 crclen = sizeof(struct space_bitmap_desc) -1 - UDF_DESC_TAG_LENGTH;
1311 sbd->tag.desc_crc_len = udf_rw16(crclen);
1313 *sbdp = sbd;
1314 return 0;
1318 /* --------------------------------------------------------------------- */
1320 int
1321 udf_register_bad_block(uint32_t location)
1323 struct udf_sparing_table *spt;
1324 struct spare_map_entry *sme, *free_sme;
1325 uint32_t cnt;
1327 spt = context.sparing_table;
1328 if (spt == NULL) {
1329 printf("internal error: adding bad block to non sparable\n");
1330 return EINVAL;
1333 /* find us a free spare map entry */
1334 free_sme = NULL;
1335 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
1336 sme = &spt->entries[cnt];
1337 /* if we are allready in it, bail out */
1338 if (udf_rw32(sme->org) == location)
1339 return 0;
1340 if (udf_rw32(sme->org) == 0xffffffff) {
1341 free_sme = sme;
1342 break;
1345 if (free_sme == NULL) {
1346 printf("Disc relocation blocks full; disc too damanged\n");
1347 return EINVAL;
1349 free_sme->org = udf_rw32(location);
1351 return 0;
1355 void
1356 udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks)
1358 union dscrptr *dscr;
1359 uint8_t *bpos;
1360 uint32_t cnt, bit;
1362 /* account for space used on underlying partition */
1363 context.part_free[partnr] -= blocks;
1364 #ifdef DEBUG
1365 printf("mark allocated : partnr %d, start_lb %d for %d blocks\n",
1366 partnr, start_lb, blocks);
1367 #endif
1369 switch (context.vtop_tp[partnr]) {
1370 case UDF_VTOP_TYPE_VIRT:
1371 /* nothing */
1372 break;
1373 case UDF_VTOP_TYPE_PHYS:
1374 case UDF_VTOP_TYPE_SPARABLE:
1375 case UDF_VTOP_TYPE_META:
1376 if (context.part_unalloc_bits[context.vtop[partnr]] == NULL) {
1377 context.part_free[partnr] = 0;
1378 break;
1380 #ifdef DEBUG
1381 printf("Marking %d+%d as used\n", start_lb, blocks);
1382 #endif
1383 dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]);
1384 for (cnt = start_lb; cnt < start_lb + blocks; cnt++) {
1385 bpos = &dscr->sbd.data[cnt / 8];
1386 bit = cnt % 8;
1387 *bpos &= ~(1<< bit);
1389 break;
1390 default:
1391 printf("internal error: reality check in mapping type %d\n",
1392 context.vtop_tp[partnr]);
1393 exit(EXIT_FAILURE);
1398 void
1399 udf_advance_uniqueid(void)
1401 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
1402 context.unique_id++;
1403 if (context.unique_id < 0x10)
1404 context.unique_id = 0x10;
1407 /* --------------------------------------------------------------------- */
1409 static void
1410 unix_to_udf_name(char *result, uint8_t *result_len,
1411 char const *name, int name_len, struct charspec *chsp)
1413 uint16_t *raw_name;
1414 uint16_t *outchp;
1415 const char *inchp;
1416 const char *osta_id = "OSTA Compressed Unicode";
1417 int udf_chars, is_osta_typ0, bits;
1418 size_t cnt;
1420 /* allocate temporary unicode-16 buffer */
1421 raw_name = malloc(1024);
1422 assert(raw_name);
1424 /* convert utf8 to unicode-16 */
1425 *raw_name = 0;
1426 inchp = name;
1427 outchp = raw_name;
1428 bits = 8;
1429 for (cnt = name_len, udf_chars = 0; cnt;) {
1430 *outchp = wget_utf8(&inchp, &cnt);
1431 if (*outchp > 0xff)
1432 bits=16;
1433 outchp++;
1434 udf_chars++;
1436 /* null terminate just in case */
1437 *outchp++ = 0;
1439 is_osta_typ0 = (chsp->type == 0);
1440 is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
1441 if (is_osta_typ0) {
1442 udf_chars = udf_CompressUnicode(udf_chars, bits,
1443 (unicode_t *) raw_name,
1444 (byte *) result);
1445 } else {
1446 printf("unix to udf name: no CHSP0 ?\n");
1447 /* XXX assume 8bit char length byte latin-1 */
1448 *result++ = 8; udf_chars = 1;
1449 strncpy(result, name + 1, name_len);
1450 udf_chars += name_len;
1452 *result_len = udf_chars;
1453 free(raw_name);
1457 #define UDF_SYMLINKBUFLEN (64*1024) /* picked */
1459 udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target)
1461 struct charspec osta_charspec;
1462 struct pathcomp pathcomp;
1463 char *pathbuf, *pathpos, *compnamepos;
1464 // char *mntonname;
1465 // int mntonnamelen;
1466 int pathlen, len, compnamelen;
1467 int error;
1469 /* process `target' to an UDF structure */
1470 pathbuf = malloc(UDF_SYMLINKBUFLEN);
1471 assert(pathbuf);
1473 *pathbufp = NULL;
1474 *pathlenp = 0;
1476 pathpos = pathbuf;
1477 pathlen = 0;
1478 udf_osta_charset(&osta_charspec);
1480 if (*target == '/') {
1481 /* symlink starts from the root */
1482 len = UDF_PATH_COMP_SIZE;
1483 memset(&pathcomp, 0, len);
1484 pathcomp.type = UDF_PATH_COMP_ROOT;
1486 #if 0
1487 /* XXX how to check for in makefs? */
1488 /* check if its mount-point relative! */
1489 mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1490 mntonnamelen = strlen(mntonname);
1491 if (strlen(target) >= mntonnamelen) {
1492 if (strncmp(target, mntonname, mntonnamelen) == 0) {
1493 pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
1494 target += mntonnamelen;
1496 } else {
1497 target++;
1499 #else
1500 target++;
1501 #endif
1503 memcpy(pathpos, &pathcomp, len);
1504 pathpos += len;
1505 pathlen += len;
1508 error = 0;
1509 while (*target) {
1510 /* ignore multiple '/' */
1511 while (*target == '/') {
1512 target++;
1514 if (!*target)
1515 break;
1517 /* extract component name */
1518 compnamelen = 0;
1519 compnamepos = target;
1520 while ((*target) && (*target != '/')) {
1521 target++;
1522 compnamelen++;
1525 /* just trunc if too long ?? (security issue) */
1526 if (compnamelen >= 127) {
1527 error = ENAMETOOLONG;
1528 break;
1531 /* convert unix name to UDF name */
1532 len = sizeof(struct pathcomp);
1533 memset(&pathcomp, 0, len);
1534 pathcomp.type = UDF_PATH_COMP_NAME;
1535 len = UDF_PATH_COMP_SIZE;
1537 if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
1538 pathcomp.type = UDF_PATH_COMP_PARENTDIR;
1539 if ((compnamelen == 1) && (*compnamepos == '.'))
1540 pathcomp.type = UDF_PATH_COMP_CURDIR;
1542 if (pathcomp.type == UDF_PATH_COMP_NAME) {
1543 unix_to_udf_name(
1544 (char *) &pathcomp.ident, &pathcomp.l_ci,
1545 compnamepos, compnamelen,
1546 &osta_charspec);
1547 len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
1550 if (pathlen + len >= UDF_SYMLINKBUFLEN) {
1551 error = ENAMETOOLONG;
1552 break;
1555 memcpy(pathpos, &pathcomp, len);
1556 pathpos += len;
1557 pathlen += len;
1560 if (error) {
1561 /* aparently too big */
1562 free(pathbuf);
1563 return error;
1566 /* return status of symlink contents writeout */
1567 *pathbufp = (uint8_t *) pathbuf;
1568 *pathlenp = pathlen;
1570 return 0;
1573 #undef UDF_SYMLINKBUFLEN
1577 udf_fidsize(struct fileid_desc *fid)
1579 uint32_t size;
1581 if (udf_rw16(fid->tag.id) != TAGID_FID)
1582 errx(EINVAL, "got udf_fidsize on non FID");
1584 size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
1585 size = (size + 3) & ~3;
1587 return size;
1592 udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent)
1594 /* the size of an empty FID is 38 but needs to be a multiple of 4 */
1595 int fidsize = 40;
1597 udf_inittag(&fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num));
1598 fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
1599 fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
1600 fid->icb = *parent;
1601 fid->icb.longad_uniqueid = parent->longad_uniqueid;
1602 fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1604 /* we have to do the fid here explicitly for simplicity */
1605 udf_validate_tag_and_crc_sums((union dscrptr *) fid);
1607 return fidsize;
1611 void
1612 udf_create_fid(uint32_t diroff, struct fileid_desc *fid, char *name,
1613 int file_char, struct long_ad *ref)
1615 struct charspec osta_charspec;
1616 uint32_t endfid;
1617 uint32_t fidsize, lb_rest;
1619 memset(fid, 0, sizeof(*fid));
1620 udf_inittag(&fid->tag, TAGID_FID, udf_rw32(ref->loc.lb_num));
1621 fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
1622 fid->file_char = file_char;
1623 fid->l_iu = udf_rw16(0);
1624 fid->icb = *ref;
1625 fid->icb.longad_uniqueid = ref->longad_uniqueid;
1627 udf_osta_charset(&osta_charspec);
1628 unix_to_udf_name((char *) fid->data, &fid->l_fi, name, strlen(name),
1629 &osta_charspec);
1632 * OK, tricky part: we need to pad so the next descriptor header won't
1633 * cross the sector boundary
1635 endfid = diroff + udf_fidsize(fid);
1636 lb_rest = context.sector_size - (endfid % context.sector_size);
1637 if (lb_rest < sizeof(struct desc_tag)) {
1638 /* add at least 32 */
1639 fid->l_iu = udf_rw16(32);
1640 udf_set_regid((struct regid *) fid->data, context.impl_name);
1641 udf_add_impl_regid((struct regid *) fid->data);
1643 unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu),
1644 &fid->l_fi, name, strlen(name), &osta_charspec);
1647 fidsize = udf_fidsize(fid);
1648 fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1650 /* make sure the header sums stays correct */
1651 udf_validate_tag_and_crc_sums((union dscrptr *)fid);
1655 static void
1656 udf_append_parentfid(union dscrptr *dscr, struct long_ad *parent_icb)
1658 struct file_entry *fe;
1659 struct extfile_entry *efe;
1660 struct fileid_desc *fid;
1661 uint32_t l_ea;
1662 uint32_t fidsize, crclen;
1663 uint8_t *bpos, *data;
1665 fe = NULL;
1666 efe = NULL;
1667 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
1668 fe = &dscr->fe;
1669 data = fe->data;
1670 l_ea = udf_rw32(fe->l_ea);
1671 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
1672 efe = &dscr->efe;
1673 data = efe->data;
1674 l_ea = udf_rw32(efe->l_ea);
1675 } else {
1676 errx(1, "Bad tag passed to udf_append_parentfid");
1679 /* create '..' */
1680 bpos = data + l_ea;
1681 fid = (struct fileid_desc *) bpos;
1682 fidsize = udf_create_parentfid(fid, parent_icb);
1684 /* record fidlength information */
1685 if (fe) {
1686 fe->inf_len = udf_rw64(fidsize);
1687 fe->l_ad = udf_rw32(fidsize);
1688 fe->logblks_rec = udf_rw64(0); /* intern */
1689 crclen = sizeof(struct file_entry);
1690 } else {
1691 efe->inf_len = udf_rw64(fidsize);
1692 efe->obj_size = udf_rw64(fidsize);
1693 efe->l_ad = udf_rw32(fidsize);
1694 efe->logblks_rec = udf_rw64(0); /* intern */
1695 crclen = sizeof(struct extfile_entry);
1697 crclen -= 1 + UDF_DESC_TAG_LENGTH;
1698 crclen += l_ea + fidsize;
1699 dscr->tag.desc_crc_len = udf_rw16(crclen);
1701 /* make sure the header sums stays correct */
1702 udf_validate_tag_and_crc_sums(dscr);
1708 * Order of extended attributes :
1709 * ECMA 167 EAs
1710 * Non block aligned Implementation Use EAs
1711 * Block aligned Implementation Use EAs (not in newfs_udf)
1712 * Application Use EAs (not in newfs_udf)
1714 * no checks for doubles, must be called in-order
1716 static void
1717 udf_extattr_append_internal(union dscrptr *dscr, struct extattr_entry *extattr)
1719 struct file_entry *fe;
1720 struct extfile_entry *efe;
1721 struct extattrhdr_desc *extattrhdr;
1722 struct impl_extattr_entry *implext;
1723 uint32_t impl_attr_loc, appl_attr_loc, l_ea, a_l, exthdr_len;
1724 uint32_t *l_eap, l_ad;
1725 uint16_t *spos;
1726 uint8_t *bpos, *data;
1728 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
1729 fe = &dscr->fe;
1730 data = fe->data;
1731 l_eap = &fe->l_ea;
1732 l_ad = udf_rw32(fe->l_ad);
1733 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
1734 efe = &dscr->efe;
1735 data = efe->data;
1736 l_eap = &efe->l_ea;
1737 l_ad = udf_rw32(efe->l_ad);
1738 } else {
1739 errx(1, "Bad tag passed to udf_extattr_append_internal");
1742 /* should have a header! */
1743 extattrhdr = (struct extattrhdr_desc *) data;
1744 l_ea = udf_rw32(*l_eap);
1745 if (l_ea == 0) {
1746 #if !defined(NDEBUG) && defined(__minix)
1747 assert(l_ad == 0);
1748 #else
1749 if (l_ad != 0) {
1750 printf("%s:%d: l_ad != 0\n", __func__, __LINE__);
1751 abort();
1753 #endif /* !defined(NDEBUG) && defined(__minix) */
1754 /* create empty extended attribute header */
1755 exthdr_len = sizeof(struct extattrhdr_desc);
1757 udf_inittag(&extattrhdr->tag, TAGID_EXTATTR_HDR, /* loc */ 0);
1758 extattrhdr->impl_attr_loc = udf_rw32(exthdr_len);
1759 extattrhdr->appl_attr_loc = udf_rw32(exthdr_len);
1760 extattrhdr->tag.desc_crc_len = udf_rw16(8);
1762 /* record extended attribute header length */
1763 l_ea = exthdr_len;
1764 *l_eap = udf_rw32(l_ea);
1767 /* extract locations */
1768 impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc);
1769 appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc);
1770 if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1771 impl_attr_loc = l_ea;
1772 if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1773 appl_attr_loc = l_ea;
1775 /* Ecma 167 EAs */
1776 if (udf_rw32(extattr->type) < 2048) {
1777 assert(impl_attr_loc == l_ea);
1778 assert(appl_attr_loc == l_ea);
1781 /* implementation use extended attributes */
1782 if (udf_rw32(extattr->type) == 2048) {
1783 assert(appl_attr_loc == l_ea);
1785 /* calculate and write extended attribute header checksum */
1786 implext = (struct impl_extattr_entry *) extattr;
1787 assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */
1788 spos = (uint16_t *) implext->data;
1789 *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
1792 /* application use extended attributes */
1793 assert(udf_rw32(extattr->type) != 65536);
1794 assert(appl_attr_loc == l_ea);
1796 /* append the attribute at the end of the current space */
1797 bpos = data + udf_rw32(*l_eap);
1798 a_l = udf_rw32(extattr->a_l);
1800 /* update impl. attribute locations */
1801 if (udf_rw32(extattr->type) < 2048) {
1802 impl_attr_loc = l_ea + a_l;
1803 appl_attr_loc = l_ea + a_l;
1805 if (udf_rw32(extattr->type) == 2048) {
1806 appl_attr_loc = l_ea + a_l;
1809 /* copy and advance */
1810 memcpy(bpos, extattr, a_l);
1811 l_ea += a_l;
1812 *l_eap = udf_rw32(l_ea);
1814 /* do the `dance` again backwards */
1815 if (context.dscrver != 2) {
1816 if (impl_attr_loc == l_ea)
1817 impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT;
1818 if (appl_attr_loc == l_ea)
1819 appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT;
1822 /* store offsets */
1823 extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc);
1824 extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc);
1826 /* make sure the header sums stays correct */
1827 udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
1832 udf_create_new_fe(struct file_entry **fep, int file_type, struct stat *st)
1834 struct file_entry *fe;
1835 struct icb_tag *icb;
1836 struct timestamp birthtime;
1837 struct filetimes_extattr_entry *ft_extattr;
1838 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1839 uint16_t icbflags;
1841 *fep = NULL;
1842 fe = calloc(1, context.sector_size);
1843 if (fe == NULL)
1844 return ENOMEM;
1846 udf_inittag(&fe->tag, TAGID_FENTRY, /* loc */ 0);
1847 icb = &fe->icbtag;
1850 * Always use strategy type 4 unless on WORM wich we don't support
1851 * (yet). Fill in defaults and set for internal allocation of data.
1853 icb->strat_type = udf_rw16(4);
1854 icb->max_num_entries = udf_rw16(1);
1855 icb->file_type = file_type; /* 8 bit */
1856 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1858 fe->perm = udf_rw32(0x7fff); /* all is allowed */
1859 fe->link_cnt = udf_rw16(0); /* explicit setting */
1861 fe->ckpoint = udf_rw32(1); /* user supplied file version */
1863 udf_set_timestamp_now(&birthtime);
1864 udf_set_timestamp_now(&fe->atime);
1865 udf_set_timestamp_now(&fe->attrtime);
1866 udf_set_timestamp_now(&fe->mtime);
1868 /* set attributes */
1869 if (st) {
1870 #if !HAVE_NBTOOL_CONFIG_H
1871 udf_set_timestamp(&birthtime, st->st_birthtime);
1872 #else
1873 udf_set_timestamp(&birthtime, 0);
1874 #endif
1875 udf_set_timestamp(&fe->atime, st->st_atime);
1876 udf_set_timestamp(&fe->attrtime, st->st_ctime);
1877 udf_set_timestamp(&fe->mtime, st->st_mtime);
1878 fe->uid = udf_rw32(st->st_uid);
1879 fe->gid = udf_rw32(st->st_gid);
1881 fe->perm = unix_mode_to_udf_perm(st->st_mode);
1883 icbflags = udf_rw16(fe->icbtag.flags);
1884 icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
1885 icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
1886 icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
1887 if (st->st_mode & S_ISUID)
1888 icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
1889 if (st->st_mode & S_ISGID)
1890 icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
1891 if (st->st_mode & S_ISVTX)
1892 icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
1893 fe->icbtag.flags = udf_rw16(icbflags);
1896 udf_set_regid(&fe->imp_id, context.impl_name);
1897 udf_add_impl_regid(&fe->imp_id);
1898 fe->unique_id = udf_rw64(context.unique_id);
1899 udf_advance_uniqueid();
1901 fe->l_ea = udf_rw32(0);
1903 /* create extended attribute to record our creation time */
1904 ft_extattr = calloc(1, UDF_FILETIMES_ATTR_SIZE(1));
1905 ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO);
1906 ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */
1907 ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1));
1908 ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */
1909 ft_extattr->existence = UDF_FILETIMES_FILE_CREATION;
1910 ft_extattr->times[0] = birthtime;
1912 udf_extattr_append_internal((union dscrptr *) fe,
1913 (struct extattr_entry *) ft_extattr);
1914 free(ft_extattr);
1916 /* record fidlength information */
1917 fe->inf_len = udf_rw64(0);
1918 fe->l_ad = udf_rw32(0);
1919 fe->logblks_rec = udf_rw64(0); /* intern */
1921 crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
1922 crclen += udf_rw32(fe->l_ea);
1924 /* make sure the header sums stays correct */
1925 fe->tag.desc_crc_len = udf_rw16(crclen);
1926 udf_validate_tag_and_crc_sums((union dscrptr *) fe);
1928 *fep = fe;
1929 return 0;
1934 udf_create_new_efe(struct extfile_entry **efep, int file_type, struct stat *st)
1936 struct extfile_entry *efe;
1937 struct icb_tag *icb;
1938 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1939 uint16_t icbflags;
1941 *efep = NULL;
1942 efe = calloc(1, context.sector_size);
1943 if (efe == NULL)
1944 return ENOMEM;
1946 udf_inittag(&efe->tag, TAGID_EXTFENTRY, /* loc */ 0);
1947 icb = &efe->icbtag;
1950 * Always use strategy type 4 unless on WORM wich we don't support
1951 * (yet). Fill in defaults and set for internal allocation of data.
1953 icb->strat_type = udf_rw16(4);
1954 icb->max_num_entries = udf_rw16(1);
1955 icb->file_type = file_type; /* 8 bit */
1956 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1958 efe->perm = udf_rw32(0x7fff); /* all is allowed */
1959 efe->link_cnt = udf_rw16(0); /* explicit setting */
1961 efe->ckpoint = udf_rw32(1); /* user supplied file version */
1963 udf_set_timestamp_now(&efe->ctime);
1964 udf_set_timestamp_now(&efe->atime);
1965 udf_set_timestamp_now(&efe->attrtime);
1966 udf_set_timestamp_now(&efe->mtime);
1968 /* set attributes */
1969 if (st) {
1970 #if !HAVE_NBTOOL_CONFIG_H
1971 udf_set_timestamp(&efe->ctime, st->st_birthtime);
1972 #else
1973 udf_set_timestamp(&efe->ctime, 0);
1974 #endif
1975 udf_set_timestamp(&efe->atime, st->st_atime);
1976 udf_set_timestamp(&efe->attrtime, st->st_ctime);
1977 udf_set_timestamp(&efe->mtime, st->st_mtime);
1978 efe->uid = udf_rw32(st->st_uid);
1979 efe->gid = udf_rw32(st->st_gid);
1981 efe->perm = unix_mode_to_udf_perm(st->st_mode);
1983 icbflags = udf_rw16(efe->icbtag.flags);
1984 icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
1985 icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
1986 icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
1987 if (st->st_mode & S_ISUID)
1988 icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
1989 if (st->st_mode & S_ISGID)
1990 icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
1991 if (st->st_mode & S_ISVTX)
1992 icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
1993 efe->icbtag.flags = udf_rw16(icbflags);
1996 udf_set_regid(&efe->imp_id, context.impl_name);
1997 udf_add_impl_regid(&efe->imp_id);
1999 efe->unique_id = udf_rw64(context.unique_id);
2000 udf_advance_uniqueid();
2002 /* record fidlength information */
2003 efe->inf_len = udf_rw64(0);
2004 efe->obj_size = udf_rw64(0);
2005 efe->l_ad = udf_rw32(0);
2006 efe->logblks_rec = udf_rw64(0);
2008 crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
2010 /* make sure the header sums stays correct */
2011 efe->tag.desc_crc_len = udf_rw16(crclen);
2012 udf_validate_tag_and_crc_sums((union dscrptr *) efe);
2014 *efep = efe;
2015 return 0;
2018 /* --------------------------------------------------------------------- */
2020 /* for METADATA file appending only */
2021 static void
2022 udf_append_meta_mapping_part_to_efe(struct extfile_entry *efe,
2023 struct short_ad *mapping)
2025 struct icb_tag *icb;
2026 uint64_t inf_len, obj_size, logblks_rec;
2027 uint32_t l_ad, l_ea;
2028 uint16_t crclen;
2029 uint8_t *bpos;
2031 inf_len = udf_rw64(efe->inf_len);
2032 obj_size = udf_rw64(efe->obj_size);
2033 logblks_rec = udf_rw64(efe->logblks_rec);
2034 l_ad = udf_rw32(efe->l_ad);
2035 l_ea = udf_rw32(efe->l_ea);
2036 crclen = udf_rw16(efe->tag.desc_crc_len);
2037 icb = &efe->icbtag;
2039 /* set our allocation to shorts if not already done */
2040 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC);
2042 /* append short_ad */
2043 bpos = (uint8_t *) efe->data + l_ea + l_ad;
2044 memcpy(bpos, mapping, sizeof(struct short_ad));
2046 l_ad += sizeof(struct short_ad);
2047 crclen += sizeof(struct short_ad);
2048 inf_len += UDF_EXT_LEN(udf_rw32(mapping->len));
2049 obj_size += UDF_EXT_LEN(udf_rw32(mapping->len));
2050 logblks_rec = UDF_ROUNDUP(inf_len, context.sector_size) /
2051 context.sector_size;
2053 efe->l_ad = udf_rw32(l_ad);
2054 efe->inf_len = udf_rw64(inf_len);
2055 efe->obj_size = udf_rw64(obj_size);
2056 efe->logblks_rec = udf_rw64(logblks_rec);
2057 efe->tag.desc_crc_len = udf_rw16(crclen);
2061 /* for METADATA file appending only */
2062 static void
2063 udf_append_meta_mapping_to_efe(struct extfile_entry *efe,
2064 uint16_t partnr, uint32_t lb_num,
2065 uint64_t len)
2067 struct short_ad mapping;
2068 uint64_t max_len, part_len;
2070 /* calculate max length meta allocation sizes */
2071 max_len = UDF_EXT_MAXLEN / context.sector_size; /* in sectors */
2072 max_len = (max_len / layout.meta_blockingnr) * layout.meta_blockingnr;
2073 max_len = max_len * context.sector_size;
2075 memset(&mapping, 0, sizeof(mapping));
2076 while (len) {
2077 part_len = MIN(len, max_len);
2078 mapping.lb_num = udf_rw32(lb_num);
2079 mapping.len = udf_rw32(part_len);
2081 udf_append_meta_mapping_part_to_efe(efe, &mapping);
2083 lb_num += part_len / context.sector_size;
2084 len -= part_len;
2090 udf_create_meta_files(void)
2092 struct extfile_entry *efe;
2093 struct long_ad meta_icb;
2094 uint64_t bytes;
2095 uint32_t sector_size;
2096 int filetype, error;
2098 sector_size = context.sector_size;
2100 memset(&meta_icb, 0, sizeof(meta_icb));
2101 meta_icb.len = udf_rw32(sector_size);
2102 meta_icb.loc.part_num = udf_rw16(context.data_part);
2104 /* create metadata file */
2105 meta_icb.loc.lb_num = udf_rw32(layout.meta_file);
2106 filetype = UDF_ICB_FILETYPE_META_MAIN;
2107 error = udf_create_new_efe(&efe, filetype, NULL);
2108 if (error)
2109 return error;
2110 context.meta_file = efe;
2112 /* create metadata mirror file */
2113 meta_icb.loc.lb_num = udf_rw32(layout.meta_mirror);
2114 filetype = UDF_ICB_FILETYPE_META_MIRROR;
2115 error = udf_create_new_efe(&efe, filetype, NULL);
2116 if (error)
2117 return error;
2118 context.meta_mirror = efe;
2120 /* create metadata bitmap file */
2121 meta_icb.loc.lb_num = udf_rw32(layout.meta_bitmap);
2122 filetype = UDF_ICB_FILETYPE_META_BITMAP;
2123 error = udf_create_new_efe(&efe, filetype, NULL);
2124 if (error)
2125 return error;
2126 context.meta_bitmap = efe;
2128 /* patch up files */
2129 context.meta_file->unique_id = udf_rw64(0);
2130 context.meta_mirror->unique_id = udf_rw64(0);
2131 context.meta_bitmap->unique_id = udf_rw64(0);
2133 /* restart unique id */
2134 context.unique_id = 0x10;
2136 /* XXX no support for metadata mirroring yet */
2137 /* insert extents */
2138 efe = context.meta_file;
2139 udf_append_meta_mapping_to_efe(efe, context.data_part,
2140 layout.meta_part_start_lba,
2141 (uint64_t) layout.meta_part_size_lba * sector_size);
2143 efe = context.meta_mirror;
2144 udf_append_meta_mapping_to_efe(efe, context.data_part,
2145 layout.meta_part_start_lba,
2146 (uint64_t) layout.meta_part_size_lba * sector_size);
2148 efe = context.meta_bitmap;
2149 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
2150 udf_append_meta_mapping_to_efe(efe, context.data_part,
2151 layout.meta_bitmap_space, bytes);
2153 return 0;
2157 /* --------------------------------------------------------------------- */
2160 udf_create_new_rootdir(union dscrptr **dscr)
2162 struct file_entry *fe;
2163 struct extfile_entry *efe;
2164 struct long_ad root_icb;
2165 int filetype, error;
2167 #if defined(__minix)
2168 /* LSC: -Werror=maybe-uninitialized when compiling with -O3 */
2169 fe = NULL;
2170 #endif /*defined(__minix) */
2171 memset(&root_icb, 0, sizeof(root_icb));
2172 root_icb.len = udf_rw32(context.sector_size);
2173 root_icb.loc.lb_num = udf_rw32(layout.rootdir);
2174 root_icb.loc.part_num = udf_rw16(context.metadata_part);
2176 filetype = UDF_ICB_FILETYPE_DIRECTORY;
2177 if (context.dscrver == 2) {
2178 error = udf_create_new_fe(&fe, filetype, NULL);
2179 *dscr = (union dscrptr *) fe;
2180 } else {
2181 error = udf_create_new_efe(&efe, filetype, NULL);
2182 *dscr = (union dscrptr *) efe;
2184 if (error)
2185 return error;
2187 /* append '..' */
2188 udf_append_parentfid(*dscr, &root_icb);
2190 /* rootdir has explicit only one link on creation; '..' is no link */
2191 if (context.dscrver == 2) {
2192 fe->link_cnt = udf_rw16(1);
2193 } else {
2194 efe->link_cnt = udf_rw16(1);
2197 context.num_directories++;
2198 assert(context.num_directories == 1);
2200 return 0;
2204 void
2205 udf_prepend_VAT_file(void)
2207 /* old style VAT has no prepend */
2208 if (context.dscrver == 2) {
2209 context.vat_start = 0;
2210 context.vat_size = 0;
2211 return;
2214 context.vat_start = offsetof(struct udf_vat, data);
2215 context.vat_size = offsetof(struct udf_vat, data);
2219 void
2220 udf_vat_update(uint32_t virt, uint32_t phys)
2222 uint32_t *vatpos;
2223 uint32_t new_size;
2225 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
2226 return;
2228 new_size = MAX(context.vat_size,
2229 (context.vat_start + (virt+1)*sizeof(uint32_t)));
2231 if (new_size > context.vat_allocated) {
2232 context.vat_allocated =
2233 UDF_ROUNDUP(new_size, context.sector_size);
2234 context.vat_contents = realloc(context.vat_contents,
2235 context.vat_allocated);
2236 assert(context.vat_contents);
2237 /* XXX could also report error */
2239 vatpos = (uint32_t *) (context.vat_contents + context.vat_start);
2240 vatpos[virt] = udf_rw32(phys);
2242 context.vat_size = MAX(context.vat_size,
2243 (context.vat_start + (virt+1)*sizeof(uint32_t)));
2248 udf_append_VAT_file(void)
2250 struct udf_oldvat_tail *oldvat_tail;
2251 struct udf_vat *vathdr;
2252 int32_t len_diff;
2254 /* new style VAT has VAT LVInt analog in front */
2255 if (context.dscrver == 3) {
2256 /* set up VATv2 descriptor */
2257 vathdr = (struct udf_vat *) context.vat_contents;
2258 vathdr->header_len = udf_rw16(sizeof(struct udf_vat) - 1);
2259 vathdr->impl_use_len = udf_rw16(0);
2260 memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
2261 vathdr->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2262 vathdr->num_files = udf_rw32(context.num_files);
2263 vathdr->num_directories = udf_rw32(context.num_directories);
2265 vathdr->min_udf_readver = udf_rw16(context.min_udf);
2266 vathdr->min_udf_writever = udf_rw16(context.min_udf);
2267 vathdr->max_udf_writever = udf_rw16(context.max_udf);
2269 return 0;
2272 /* old style VAT has identifier appended */
2274 /* append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
2275 len_diff = context.vat_allocated - context.vat_size;
2276 assert(len_diff >= 0);
2277 if (len_diff < (int32_t) sizeof(struct udf_oldvat_tail)) {
2278 context.vat_allocated += context.sector_size;
2279 context.vat_contents = realloc(context.vat_contents,
2280 context.vat_allocated);
2281 assert(context.vat_contents);
2282 /* XXX could also report error */
2285 oldvat_tail = (struct udf_oldvat_tail *) (context.vat_contents +
2286 context.vat_size);
2288 udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
2289 udf_add_udf_regid(&oldvat_tail->id);
2290 oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2292 context.vat_size += sizeof(struct udf_oldvat_tail);
2294 return 0;
2299 udf_create_VAT(union dscrptr **vat_dscr)
2301 struct file_entry *fe;
2302 struct extfile_entry *efe;
2303 struct impl_extattr_entry *implext;
2304 struct vatlvext_extattr_entry *vatlvext;
2305 struct long_ad dataloc, *allocpos;
2306 uint8_t *bpos, *extattr;
2307 uint32_t ea_len, inf_len, vat_len, blks;
2308 int filetype;
2309 int error;
2311 assert((layout.rootdir < 2) && (layout.fsd < 2));
2313 memset(&dataloc, 0, sizeof(dataloc));
2314 dataloc.len = udf_rw32(context.vat_size);
2315 dataloc.loc.part_num = udf_rw16(context.data_part);
2316 dataloc.loc.lb_num = udf_rw32(layout.vat);
2318 if (context.dscrver == 2) {
2319 /* old style VAT */
2320 filetype = UDF_ICB_FILETYPE_UNKNOWN;
2321 error = udf_create_new_fe(&fe, filetype, NULL);
2322 if (error)
2323 return error;
2325 /* append VAT LVExtension attribute */
2326 ea_len = sizeof(struct impl_extattr_entry) - 1 +
2327 sizeof(struct vatlvext_extattr_entry) + 4;
2329 extattr = calloc(1, ea_len);
2331 implext = (struct impl_extattr_entry *) extattr;
2332 implext->hdr.type = udf_rw32(2048); /* [4/48.10.8] */
2333 implext->hdr.subtype = 1; /* [4/48.10.8.2] */
2334 implext->hdr.a_l = udf_rw32(ea_len); /* VAT LVext EA size */
2335 /* use 4 bytes of imp use for UDF checksum [UDF 3.3.4.5] */
2336 implext->iu_l = udf_rw32(4);
2337 udf_set_regid(&implext->imp_id, "*UDF VAT LVExtension");
2338 udf_add_udf_regid(&implext->imp_id);
2340 /* VAT LVExtension data follows UDF IU space */
2341 bpos = ((uint8_t *) implext->data) + 4;
2342 vatlvext = (struct vatlvext_extattr_entry *) bpos;
2344 vatlvext->unique_id_chk = udf_rw64(fe->unique_id);
2345 vatlvext->num_files = udf_rw32(context.num_files);
2346 vatlvext->num_directories = udf_rw32(context.num_directories);
2347 memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id,128);
2349 udf_extattr_append_internal((union dscrptr *) fe,
2350 (struct extattr_entry *) extattr);
2352 free(extattr);
2354 fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2356 allocpos = (struct long_ad *) (fe->data + udf_rw32(fe->l_ea));
2357 *allocpos = dataloc;
2359 /* set length */
2360 inf_len = context.vat_size;
2361 fe->inf_len = udf_rw64(inf_len);
2362 fe->l_ad = udf_rw32(sizeof(struct long_ad));
2363 blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2364 context.sector_size;
2365 fe->logblks_rec = udf_rw32(blks);
2367 /* update vat descriptor's CRC length */
2368 vat_len = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
2369 vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea);
2370 fe->tag.desc_crc_len = udf_rw16(vat_len);
2372 *vat_dscr = (union dscrptr *) fe;
2373 } else {
2374 /* new style VAT */
2375 filetype = UDF_ICB_FILETYPE_VAT;
2376 error = udf_create_new_efe(&efe, filetype, NULL);
2377 if (error)
2378 return error;
2380 efe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2382 allocpos = (struct long_ad *) efe->data;
2383 *allocpos = dataloc;
2385 /* set length */
2386 inf_len = context.vat_size;
2387 efe->inf_len = udf_rw64(inf_len);
2388 efe->obj_size = udf_rw64(inf_len);
2389 efe->l_ad = udf_rw32(sizeof(struct long_ad));
2390 blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2391 context.sector_size;
2392 efe->logblks_rec = udf_rw32(blks);
2394 vat_len = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH;
2395 vat_len += udf_rw32(efe->l_ad);
2396 efe->tag.desc_crc_len = udf_rw16(vat_len);
2398 *vat_dscr = (union dscrptr *) efe;
2401 return 0;