Annotation of src/sbin/newfs_udf/udf_core.c, Revision 1.4
1.4 ! reinoud 1: /* $NetBSD: udf_core.c,v 1.3 2022/04/22 20:56:46 reinoud Exp $ */
1.1 reinoud 2:
3: /*
4: * Copyright (c) 2006, 2008, 2021, 2022 Reinoud Zandijk
5: * All rights reserved.
1.2 riastrad 6: *
1.1 reinoud 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.
1.2 riastrad 15: *
1.1 reinoud 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.
1.2 riastrad 26: *
1.1 reinoud 27: */
28: #if HAVE_NBTOOL_CONFIG_H
29: #include "nbtool_config.h"
30: #endif
31:
32: #include <sys/cdefs.h>
1.4 ! reinoud 33: __RCSID("$NetBSD: udf_core.c,v 1.3 2022/04/22 20:56:46 reinoud Exp $");
1.1 reinoud 34:
35: #include <stdio.h>
36: #include <stdlib.h>
37: #include <stddef.h>
38: #include <string.h>
39: #include <strings.h>
40: #include <unistd.h>
41: #include <errno.h>
42: #include <time.h>
43: #include <assert.h>
44: #include <err.h>
45: #include <fcntl.h>
46: #include <util.h>
47: #include <sys/types.h>
48: #include <sys/param.h>
49: #include <sys/ioctl.h>
50: #include <sys/queue.h>
51: #include "newfs_udf.h"
52: #include "unicode.h"
53: #include "udf_core.h"
54:
55:
56: /* disk partition support */
57: #if !HAVE_NBTOOL_CONFIG_H
58: #include "../fsck/partutil.h"
59: #include "../fsck/partutil.c"
60: #endif
61:
62:
63: /* queue for temporary storage of sectors to be written out */
64: struct wrpacket {
65: uint64_t start_sectornr;
66: uint8_t *packet_data;
67: uint64_t present;
68: TAILQ_ENTRY(wrpacket) next;
69: };
70:
71:
72: /* global variables describing disc and format requests */
73: struct udf_create_context context;
74: struct udf_disclayout layout;
75:
76:
77: int dev_fd_rdonly; /* device: open readonly! */
78: int dev_fd; /* device: file descriptor */
79: struct stat dev_fd_stat; /* device: last stat info */
80: char *dev_name; /* device: name */
81: int emul_mmc_profile; /* for files */
82: int emul_packetsize; /* for discs and files */
83: int emul_sectorsize; /* for files */
84: off_t emul_size; /* for files */
85:
86: struct mmc_discinfo mmc_discinfo; /* device: disc info */
87: union dscrptr *terminator_dscr; /* generic terminator descriptor*/
88:
89:
90: /* write queue and track blocking skew */
91: TAILQ_HEAD(wrpacket_list, wrpacket) write_queue;
92: int write_queuelen;
93: int write_queue_suspend;
94: uint32_t wrtrack_skew; /* offset for writing sector0 */
95:
96: static void udf_init_writequeue(int write_strategy);
97: static int udf_writeout_writequeue(bool complete);
98:
99: /*
100: * NOTE that there is some overlap between this code and the udf kernel fs.
101: * This is intentionally though it might better be factored out one day.
102: */
103:
104: void
105: udf_init_create_context(void)
106: {
107: /* clear */
108: memset(&context, 0, sizeof(struct udf_create_context));
109:
110: /* fill with defaults currently known */
111: context.dscrver = 3;
112: context.min_udf = 0x0102;
113: context.max_udf = 0x0250;
114: context.serialnum = 1; /* default */
115:
116: context.gmtoff = 0;
117: context.meta_perc = UDF_META_PERC;
118: context.check_surface = 0;
119: context.create_new_session = 0;
120:
121: context.sector_size = 512; /* minimum for UDF */
122: context.media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;
123: context.format_flags = FORMAT_INVALID;
124: context.write_strategy = UDF_WRITE_PACKET;
125:
126: context.logvol_name = NULL;
127: context.primary_name = NULL;
128: context.volset_name = NULL;
129: context.fileset_name = NULL;
130:
131: /* most basic identification */
132: context.app_name = "*NetBSD";
133: context.app_version_main = 0;
134: context.app_version_sub = 0;
135: context.impl_name = "*NetBSD";
136:
137: context.vds_seq = 0; /* first one starts with zero */
138:
139: /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
140: context.unique_id = 0x10;
141:
142: context.num_files = 0;
143: context.num_directories = 0;
144:
145: context.data_part = 0;
146: context.metadata_part = 0;
147: }
148:
149:
150: /* version can be specified as 0xabc or a.bc */
151: static int
152: parse_udfversion(const char *pos, uint32_t *version) {
153: int hex = 0;
154: char c1, c2, c3, c4;
155:
156: *version = 0;
157: if (*pos == '0') {
158: pos++;
159: /* expect hex format */
160: hex = 1;
161: if (*pos++ != 'x')
162: return 1;
163: }
164:
165: c1 = *pos++;
166: if (c1 < '0' || c1 > '9')
167: return 1;
168: c1 -= '0';
169:
170: c2 = *pos++;
171: if (!hex) {
172: if (c2 != '.')
173: return 1;
174: c2 = *pos++;
175: }
176: if (c2 < '0' || c2 > '9')
177: return 1;
178: c2 -= '0';
179:
180: c3 = *pos++;
181: if (c3 < '0' || c3 > '9')
182: return 1;
183: c3 -= '0';
184:
185: c4 = *pos++;
186: if (c4 != 0)
187: return 1;
188:
189: *version = c1 * 0x100 + c2 * 0x10 + c3;
190: return 0;
191: }
192:
193:
194: /*
195: * Parse a given string for an udf version.
196: * May exit.
197: */
198: int
199: a_udf_version(const char *s, const char *id_type)
200: {
201: uint32_t version;
202:
203: if (parse_udfversion(s, &version))
204: errx(1, "unknown %s version %s; specify as hex or float", id_type, s);
205: switch (version) {
206: case 0x102:
207: case 0x150:
208: case 0x200:
209: case 0x201:
210: case 0x250:
211: break;
212: case 0x260:
213: /* we don't support this one */
214: errx(1, "UDF version 0x260 is not supported");
215: break;
216: default:
217: errx(1, "unknown %s version %s, choose from "
218: "0x102, 0x150, 0x200, 0x201, 0x250",
219: id_type, s);
220: }
221: return version;
222: }
223:
224:
225: static uint32_t
226: udf_space_bitmap_len(uint32_t part_size)
227: {
228: return sizeof(struct space_bitmap_desc)-1 +
229: part_size/8;
230: }
231:
232:
233: uint32_t
234: udf_bytes_to_sectors(uint64_t bytes)
235: {
236: uint32_t sector_size = context.sector_size;
237: return (bytes + sector_size -1) / sector_size;
238: }
239:
240:
241: void
242: udf_dump_layout(void) {
243: #ifdef DEBUG
244: int format_flags = context.format_flags;
245: int sector_size = context.sector_size;
246:
247: printf("Summary so far\n");
248: printf("\tiso9660_vrs\t\t%d\n", layout.iso9660_vrs);
249: printf("\tanchor0\t\t\t%d\n", layout.anchors[0]);
250: printf("\tanchor1\t\t\t%d\n", layout.anchors[1]);
251: printf("\tanchor2\t\t\t%d\n", layout.anchors[2]);
252: printf("\tvds1_size\t\t%d\n", layout.vds1_size);
253: printf("\tvds2_size\t\t%d\n", layout.vds2_size);
254: printf("\tvds1\t\t\t%d\n", layout.vds1);
255: printf("\tvds2\t\t\t%d\n", layout.vds2);
256: printf("\tlvis_size\t\t%d\n", layout.lvis_size);
257: printf("\tlvis\t\t\t%d\n", layout.lvis);
258: if (format_flags & FORMAT_SPAREABLE) {
259: printf("\tspareable size\t\t%d\n", layout.spareable_area_size);
260: printf("\tspareable\t\t%d\n", layout.spareable_area);
261: }
262: printf("\tpartition start lba\t%d\n", layout.part_start_lba);
263: printf("\tpartition size\t\t%ld KiB, %ld MiB\n",
264: ((uint64_t) layout.part_size_lba * sector_size) / 1024,
265: ((uint64_t) layout.part_size_lba * sector_size) / (1024*1024));
266: if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
267: printf("\tpart bitmap start\t%d\n", layout.unalloc_space);
268: printf("\t\tfor %d lba\n", layout.alloc_bitmap_dscr_size);
269: }
270: if (format_flags & FORMAT_META) {
271: printf("\tmeta blockingnr\t\t%d\n", layout.meta_blockingnr);
272: printf("\tmeta alignment\t\t%d\n", layout.meta_alignment);
273: printf("\tmeta size\t\t%ld KiB, %ld MiB\n",
274: ((uint64_t) layout.meta_part_size_lba * sector_size) / 1024,
275: ((uint64_t) layout.meta_part_size_lba * sector_size) / (1024*1024));
276: printf("\tmeta file\t\t%d\n", layout.meta_file);
277: printf("\tmeta mirror\t\t%d\n", layout.meta_mirror);
278: printf("\tmeta bitmap\t\t%d\n", layout.meta_bitmap);
279: printf("\tmeta bitmap start\t%d\n", layout.meta_bitmap_space);
280: printf("\t\tfor %d lba\n", layout.meta_bitmap_dscr_size);
281: printf("\tmeta space start\t%d\n", layout.meta_part_start_lba);
282: printf("\t\tfor %d lba\n", layout.meta_part_size_lba);
283: }
284: printf("\n");
285: #endif
286: }
287:
288:
289: int
290: udf_calculate_disc_layout(int min_udf,
291: uint32_t first_lba, uint32_t last_lba,
292: uint32_t sector_size, uint32_t blockingnr)
293: {
294: uint64_t kbsize, bytes;
295: uint32_t spareable_blockingnr;
296: uint32_t align_blockingnr;
297: uint32_t pos, mpos;
298: int format_flags = context.format_flags;
299:
300: /* clear */
301: memset(&layout, 0, sizeof(layout));
302:
303: /* fill with parameters */
304: layout.wrtrack_skew = wrtrack_skew;
305: layout.first_lba = first_lba;
306: layout.last_lba = last_lba;
307: layout.blockingnr = blockingnr;
308: layout.spareable_blocks = udf_spareable_blocks();
309:
310: /* start disc layouting */
311:
312: /*
313: * location of iso9660 vrs is defined as first sector AFTER 32kb,
314: * minimum `sector size' 2048
315: */
316: layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
317: + first_lba;
318:
319: /* anchor starts at specified offset in sectors */
320: layout.anchors[0] = first_lba + 256;
321: if (format_flags & FORMAT_TRACK512)
322: layout.anchors[0] = first_lba + 512;
323: layout.anchors[1] = last_lba - 256;
324: layout.anchors[2] = last_lba;
325:
326: /* update workable space */
327: first_lba = layout.anchors[0] + blockingnr;
328: last_lba = layout.anchors[1] - 1;
329:
330: /* XXX rest of anchor packet can be added to unallocated space descr */
331:
332: /* reserve space for VRS and VRS copy and associated tables */
333: layout.vds1_size = MAX(16, blockingnr); /* UDF 2.2.3.1+2 */
334: layout.vds1 = first_lba;
335: first_lba += layout.vds1_size; /* next packet */
336:
337: layout.vds2_size = layout.vds1_size;
338: if (format_flags & FORMAT_SEQUENTIAL) {
339: /* for sequential, append them ASAP */
340: layout.vds2 = first_lba;
341: first_lba += layout.vds2_size;
342: } else {
343: layout.vds2 = layout.anchors[1] +1 - layout.vds2_size;
344: last_lba = layout.vds2 - 1;
345: }
346:
347: /*
348: * Reserve space for logvol integrity sequence, at least 8192 bytes
349: * for overwritable and rewritable media UDF 2.2.4.6, ECMA 3/10.6.12.
350: */
351: layout.lvis_size = MAX(8192.0/sector_size, 2 * blockingnr);
352: if (layout.lvis_size * sector_size < 8192)
353: layout.lvis_size++;
354: if (format_flags & FORMAT_VAT)
355: layout.lvis_size = 2;
356: if (format_flags & FORMAT_WORM)
357: layout.lvis_size = 64 * blockingnr;
358:
359: /* TODO skip bad blocks in LVID sequence */
360: layout.lvis = first_lba;
361: first_lba += layout.lvis_size;
362:
363: /* initial guess of UDF partition size */
364: layout.part_start_lba = first_lba;
365: layout.part_size_lba = last_lba - layout.part_start_lba;
366:
367: /* all non sequential media needs an unallocated space bitmap */
368: layout.alloc_bitmap_dscr_size = 0;
369: if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
370: bytes = udf_space_bitmap_len(layout.part_size_lba);
371: layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
372:
373: /* XXX freed space map when applicable */
374: }
375:
376: spareable_blockingnr = udf_spareable_blockingnr();
377: align_blockingnr = blockingnr;
378:
379: if (format_flags & (FORMAT_SPAREABLE | FORMAT_META))
380: align_blockingnr = spareable_blockingnr;
381:
382: layout.align_blockingnr = align_blockingnr;
383: layout.spareable_blockingnr = spareable_blockingnr;
384:
385: /*
386: * Align partition LBA space to blocking granularity. Not strictly
387: * necessary for non spareables but safer for the VRS data since it is
388: * updated sporadically
389: */
390:
391: #ifdef DEBUG
392: printf("Lost %lu slack sectors at start\n", UDF_ROUNDUP(
393: first_lba, align_blockingnr) -
394: first_lba);
395: printf("Lost %lu slack sectors at end\n",
396: last_lba - UDF_ROUNDDOWN(
397: last_lba, align_blockingnr));
398: #endif
399:
400: first_lba = UDF_ROUNDUP(first_lba, align_blockingnr);
401: last_lba = UDF_ROUNDDOWN(last_lba, align_blockingnr);
402:
403: if ((format_flags & FORMAT_SPAREABLE) == 0)
404: layout.spareable_blocks = 0;
405:
406: if (format_flags & FORMAT_SPAREABLE) {
407: layout.spareable_area_size =
408: layout.spareable_blocks * spareable_blockingnr;
409:
410: /* a sparing table descriptor is a whole blockingnr sectors */
411: layout.sparing_table_dscr_lbas = spareable_blockingnr;
412:
413: /* place the descriptors at the start and end of the area */
414: layout.spt_1 = first_lba;
415: first_lba += layout.sparing_table_dscr_lbas;
416:
417: layout.spt_2 = last_lba - layout.sparing_table_dscr_lbas;
418: last_lba -= layout.sparing_table_dscr_lbas;
419:
420: /* allocate spareable section */
421: layout.spareable_area = first_lba;
422: first_lba += layout.spareable_area_size;
423: }
424:
425: /* update guess of UDF partition size */
426: layout.part_start_lba = first_lba;
427: layout.part_size_lba = last_lba - layout.part_start_lba;
428:
429: /* determine partition selection for data and metadata */
430: context.data_part = 0;
431: context.metadata_part = context.data_part;
432: if ((format_flags & FORMAT_VAT) || (format_flags & FORMAT_META))
433: context.metadata_part = context.data_part + 1;
434: context.fids_part = context.metadata_part;
435: if (format_flags & FORMAT_VAT)
436: context.fids_part = context.data_part;
437:
438: /*
439: * Pick fixed logical space sector numbers for main FSD, rootdir and
440: * unallocated space. The reason for this pre-allocation is that they
441: * are referenced in the volume descriptor sequence and hence can't be
442: * allocated later.
443: */
444: pos = 0;
445: layout.unalloc_space = pos;
446: pos += layout.alloc_bitmap_dscr_size;
447:
448: /* claim metadata descriptors and partition space [UDF 2.2.10] */
449: if (format_flags & FORMAT_META) {
450: /* note: all in backing partition space */
451: layout.meta_file = pos++;
452: layout.meta_bitmap = 0xffffffff;
453: if (!(context.format_flags & FORMAT_READONLY))
454: layout.meta_bitmap = pos++;
455: layout.meta_mirror = layout.part_size_lba-1;
456: layout.meta_alignment = MAX(blockingnr, spareable_blockingnr);
457: layout.meta_blockingnr = MAX(layout.meta_alignment, 32);
458:
459: /* calculate our partition length and store in sectors */
460: layout.meta_part_size_lba = layout.part_size_lba *
461: ((float) context.meta_perc / 100.0);
462: layout.meta_part_size_lba = MAX(layout.meta_part_size_lba, 32);
463: layout.meta_part_size_lba =
464: UDF_ROUNDDOWN(layout.meta_part_size_lba, layout.meta_blockingnr);
465:
466: if (!(context.format_flags & FORMAT_READONLY)) {
467: /* metadata partition free space bitmap */
468: bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
469: layout.meta_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
470:
471: layout.meta_bitmap_space = pos;
472: pos += layout.meta_bitmap_dscr_size;
473: }
474:
475: layout.meta_part_start_lba = UDF_ROUNDUP(pos, layout.meta_alignment);
476: pos = layout.meta_part_start_lba + layout.meta_part_size_lba;
477: }
478:
479: if (context.metadata_part == context.data_part) {
480: mpos = pos;
481: layout.fsd = mpos; mpos += 1;
482: layout.rootdir = mpos;
483: pos = mpos;
484: } else {
485: mpos = 0;
486: layout.fsd = mpos; mpos += 1;
487: layout.rootdir = mpos;
488: }
489:
490: /* pos and mpos now refer to the rootdir block */
491: context.alloc_pos[context.data_part] = pos;
492: context.alloc_pos[context.metadata_part] = mpos;
493:
494: udf_dump_layout();
495:
496: kbsize = (uint64_t) last_lba * sector_size;
497: printf("Total space on this medium approx. "
498: "%"PRIu64" KiB, %"PRIu64" MiB\n",
499: kbsize/1024, kbsize/(1024*1024));
500: kbsize = (uint64_t)(layout.part_size_lba - layout.alloc_bitmap_dscr_size
501: - layout.meta_bitmap_dscr_size) * sector_size;
502: printf("Recordable free space on this volume approx. "
503: "%"PRIu64" KiB, %"PRIu64" MiB\n\n",
504: kbsize/1024, kbsize/(1024*1024));
505:
506: return 0;
507: }
508:
509:
510: /*
511: * Check if the blob starts with a good UDF tag. Tags are protected by a
512: * checksum over the header, except one byte at position 4 that is the
513: * checksum itself.
514: */
515: int
516: udf_check_tag(void *blob)
517: {
518: struct desc_tag *tag = blob;
519: uint8_t *pos, sum, cnt;
520:
521: /* check TAG header checksum */
522: pos = (uint8_t *) tag;
523: sum = 0;
524:
525: for(cnt = 0; cnt < 16; cnt++) {
526: if (cnt != 4)
527: sum += *pos;
528: pos++;
529: }
530: if (sum != tag->cksum) {
531: /* bad tag header checksum; this is not a valid tag */
532: return EINVAL;
533: }
534:
535: return 0;
536: }
537:
538:
539: /*
540: * check tag payload will check descriptor CRC as specified.
541: * If the descriptor is too long, it will return EIO otherwise EINVAL.
542: */
543: int
544: udf_check_tag_payload(void *blob, uint32_t max_length)
545: {
546: struct desc_tag *tag = blob;
547: uint16_t crc, crc_len;
548:
549: crc_len = udf_rw16(tag->desc_crc_len);
550:
551: /* check payload CRC if applicable */
552: if (crc_len == 0)
553: return 0;
554:
555: if (crc_len > max_length)
556: return EIO;
557:
558: crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, crc_len);
559: if (crc != udf_rw16(tag->desc_crc)) {
560: /* bad payload CRC; this is a broken tag */
561: return EINVAL;
562: }
563:
564: return 0;
565: }
566:
567:
568: int
569: udf_check_tag_and_location(void *blob, uint32_t location)
570: {
571: struct desc_tag *tag = blob;
572:
573: if (udf_check_tag(blob))
574: return 1;
575: if (udf_rw32(tag->tag_loc) != location)
576: return 1;
577: return 0;
578: }
579:
580:
581: int
582: udf_validate_tag_sum(union dscrptr *dscr)
583: {
584: struct desc_tag *tag = &dscr->tag;
585: uint8_t *pos, sum, cnt;
586:
587: /* calculate TAG header checksum */
588: pos = (uint8_t *) tag;
589: sum = 0;
590:
591: for (cnt = 0; cnt < 16; cnt++) {
592: if (cnt != 4) sum += *pos;
593: pos++;
594: };
595: tag->cksum = sum; /* 8 bit */
596:
597: return 0;
598: }
599:
600:
601: /* assumes sector number of descriptor to be already present */
602: int
603: udf_validate_tag_and_crc_sums(union dscrptr *dscr)
604: {
605: struct desc_tag *tag = &dscr->tag;
606: uint16_t crc;
607:
608: /* check payload CRC if applicable */
609: if (udf_rw16(tag->desc_crc_len) > 0) {
610: crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH,
611: udf_rw16(tag->desc_crc_len));
612: tag->desc_crc = udf_rw16(crc);
613: };
614:
615: /* calculate TAG header checksum */
616: return udf_validate_tag_sum(dscr);
617: }
618:
619:
620: void
621: udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc)
622: {
623: tag->id = udf_rw16(tagid);
624: tag->descriptor_ver = udf_rw16(context.dscrver);
625: tag->cksum = 0;
626: tag->reserved = 0;
627: tag->serial_num = udf_rw16(context.serialnum);
628: tag->tag_loc = udf_rw32(loc);
629: }
630:
631:
632: int
633: udf_create_anchor(int num)
634: {
635: struct anchor_vdp *avdp;
636: uint32_t vds1_extent_len = layout.vds1_size * context.sector_size;
637: uint32_t vds2_extent_len = layout.vds2_size * context.sector_size;
638:
639: avdp = context.anchors[num];
640: if (!avdp)
641: if ((avdp = calloc(1, context.sector_size)) == NULL)
642: return ENOMEM;
643:
644: udf_inittag(&avdp->tag, TAGID_ANCHOR, layout.anchors[num]);
645:
646: avdp->main_vds_ex.loc = udf_rw32(layout.vds1);
647: avdp->main_vds_ex.len = udf_rw32(vds1_extent_len);
648:
649: avdp->reserve_vds_ex.loc = udf_rw32(layout.vds2);
650: avdp->reserve_vds_ex.len = udf_rw32(vds2_extent_len);
651:
652: /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
653: avdp->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
654:
655: context.anchors[num] = avdp;
656: return 0;
657: }
658:
659:
660: void
661: udf_create_terminator(union dscrptr *dscr, uint32_t loc)
662: {
663: memset(dscr, 0, context.sector_size);
664: udf_inittag(&dscr->tag, TAGID_TERM, loc);
665:
666: /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
667: dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
668: }
669:
670:
671: void
672: udf_osta_charset(struct charspec *charspec)
673: {
674: memset(charspec, 0, sizeof(*charspec));
675: charspec->type = 0;
676: strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
677: }
678:
679:
680: /* ---- shared from kernel's udf_subr.c, slightly modified ---- */
681: void
682: udf_to_unix_name(char *result, int result_len, char *id, int len,
683: struct charspec *chsp)
684: {
685: uint16_t *raw_name, *unix_name;
686: uint16_t *inchp, ch;
687: char *outchp;
688: const char *osta_id = "OSTA Compressed Unicode";
689: int ucode_chars, nice_uchars, is_osta_typ0, nout;
690:
691: raw_name = malloc(2048 * sizeof(uint16_t));
692: assert(raw_name);
693:
694: unix_name = raw_name + 1024; /* split space in half */
695: assert(sizeof(char) == sizeof(uint8_t));
696: outchp = result;
697:
698: is_osta_typ0 = (chsp->type == 0);
699: is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
700: if (is_osta_typ0) {
701: /* TODO clean up */
702: *raw_name = *unix_name = 0;
703: ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name);
704: ucode_chars = MIN(ucode_chars, UnicodeLength((unicode_t *) raw_name));
705: nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars);
706: /* output UTF8 */
707: for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) {
708: ch = *inchp;
709: nout = wput_utf8(outchp, result_len, ch);
710: outchp += nout; result_len -= nout;
711: if (!ch) break;
712: }
713: *outchp++ = 0;
714: } else {
715: /* assume 8bit char length byte latin-1 */
716: assert(*id == 8);
717: assert(strlen((char *) (id+1)) <= NAME_MAX);
718: memcpy((char *) result, (char *) (id+1), strlen((char *) (id+1)));
719: }
720: free(raw_name);
721: }
722:
723:
724: void
725: unix_to_udf_name(char *result, uint8_t *result_len, char const *name, int name_len,
726: struct charspec *chsp)
727: {
728: uint16_t *raw_name;
729: uint16_t *outchp;
730: const char *inchp;
731: const char *osta_id = "OSTA Compressed Unicode";
732: int udf_chars, is_osta_typ0, bits;
733: size_t cnt;
734:
735: /* allocate temporary unicode-16 buffer */
736: raw_name = malloc(1024);
737: assert(raw_name);
738:
739: /* convert utf8 to unicode-16 */
740: *raw_name = 0;
741: inchp = name;
742: outchp = raw_name;
743: bits = 8;
744: for (cnt = name_len, udf_chars = 0; cnt;) {
745: *outchp = wget_utf8(&inchp, &cnt);
746: if (*outchp > 0xff)
747: bits=16;
748: outchp++;
749: udf_chars++;
750: }
751: /* null terminate just in case */
752: *outchp++ = 0;
753:
754: is_osta_typ0 = (chsp->type == 0);
755: is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
756: if (is_osta_typ0) {
757: udf_chars = udf_CompressUnicode(udf_chars, bits,
758: (unicode_t *) raw_name,
759: (byte *) result);
760: } else {
761: printf("unix to udf name: no CHSP0 ?\n");
762: /* XXX assume 8bit char length byte latin-1 */
763: *result++ = 8; udf_chars = 1;
764: strncpy(result, name + 1, name_len);
765: udf_chars += name_len;
766: }
767: *result_len = udf_chars;
768: free(raw_name);
769: }
770:
771:
772: /* first call udf_set_regid and then the suffix */
773: void
774: udf_set_regid(struct regid *regid, char const *name)
775: {
776: memset(regid, 0, sizeof(*regid));
777: regid->flags = 0; /* not dirty and not protected */
778: strcpy((char *) regid->id, name);
779: }
780:
781:
782: void
783: udf_add_domain_regid(struct regid *regid)
784: {
785: uint16_t *ver;
786:
787: ver = (uint16_t *) regid->id_suffix;
788: *ver = udf_rw16(context.min_udf);
789: }
790:
791:
792: void
793: udf_add_udf_regid(struct regid *regid)
794: {
795: uint16_t *ver;
796:
797: ver = (uint16_t *) regid->id_suffix;
798: *ver = udf_rw16(context.min_udf);
799:
800: regid->id_suffix[2] = 4; /* unix */
801: regid->id_suffix[3] = 8; /* NetBSD */
802: }
803:
804:
805: void
806: udf_add_impl_regid(struct regid *regid)
807: {
808: regid->id_suffix[0] = 4; /* unix */
809: regid->id_suffix[1] = 8; /* NetBSD */
810: }
811:
812:
813: void
814: udf_add_app_regid(struct regid *regid)
815: {
816: regid->id_suffix[0] = context.app_version_main;
817: regid->id_suffix[1] = context.app_version_sub;
818: }
819:
820:
1.2 riastrad 821: /*
1.1 reinoud 822: * Timestamp to timespec conversion code is taken with small modifications
823: * from FreeBSD /sys/fs/udf by Scott Long <scottl@freebsd.org>
824: */
825:
826: static int mon_lens[2][12] = {
827: {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
828: {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
829: };
830:
831:
832: static int
833: udf_isaleapyear(int year)
1.2 riastrad 834: {
1.1 reinoud 835: int i;
1.2 riastrad 836:
1.1 reinoud 837: i = (year % 4) ? 0 : 1;
838: i &= (year % 100) ? 1 : 0;
839: i |= (year % 400) ? 0 : 1;
1.2 riastrad 840:
1.1 reinoud 841: return i;
842: }
843:
844:
845: void
846: udf_timestamp_to_timespec(struct timestamp *timestamp, struct timespec *timespec)
847: {
848: uint32_t usecs, secs, nsecs;
849: uint16_t tz;
850: int i, lpyear, daysinyear, year;
851:
852: timespec->tv_sec = secs = 0;
853: timespec->tv_nsec = nsecs = 0;
854:
855: /*
856: * DirectCD seems to like using bogus year values.
857: * Distrust time->month especially, since it will be used for an array
858: * index.
859: */
860: year = udf_rw16(timestamp->year);
861: if ((year < 1970) || (timestamp->month > 12)) {
862: return;
863: }
1.2 riastrad 864:
1.1 reinoud 865: /* Calculate the time and day */
866: usecs = timestamp->usec + 100*timestamp->hund_usec + 10000*timestamp->centisec;
867: nsecs = usecs * 1000;
1.2 riastrad 868: secs = timestamp->second;
1.1 reinoud 869: secs += timestamp->minute * 60;
870: secs += timestamp->hour * 3600;
871: secs += (timestamp->day-1) * 3600 * 24; /* day : 1-31 */
1.2 riastrad 872:
1.1 reinoud 873: /* Calclulate the month */
874: lpyear = udf_isaleapyear(year);
875: for (i = 1; i < timestamp->month; i++)
876: secs += mon_lens[lpyear][i-1] * 3600 * 24; /* month: 1-12 */
1.2 riastrad 877:
878: for (i = 1970; i < year; i++) {
1.1 reinoud 879: daysinyear = udf_isaleapyear(i) + 365 ;
880: secs += daysinyear * 3600 * 24;
881: }
882:
883: /*
884: * Calculate the time zone. The timezone is 12 bit signed 2's
885: * compliment, so we gotta do some extra magic to handle it right.
886: */
887: tz = udf_rw16(timestamp->type_tz);
888: tz &= 0x0fff; /* only lower 12 bits are significant */
889: if (tz & 0x0800) /* sign extention */
890: tz |= 0xf000;
891:
892: /* TODO check timezone conversion */
893: #if 1
894: /* check if we are specified a timezone to convert */
895: if (udf_rw16(timestamp->type_tz) & 0x1000)
896: if ((int16_t) tz != -2047)
897: secs -= (int16_t) tz * 60;
898: #endif
899: timespec->tv_sec = secs;
900: timespec->tv_nsec = nsecs;
901: }
902:
903:
904: /*
905: * Fill in timestamp structure based on clock_gettime(). Time is reported back
906: * as a time_t accompanied with a nano second field.
907: *
908: * The husec, usec and csec could be relaxed in type.
909: */
910: void
911: udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp)
912: {
913: struct tm tm;
914: uint64_t husec, usec, csec;
915:
916: memset(timestamp, 0, sizeof(*timestamp));
917: gmtime_r(×pec->tv_sec, &tm);
918:
919: /*
920: * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1.
921: *
922: * Lower 12 bits are two complement signed timezone offset if bit 12
923: * (method 1) is clear. Otherwise if bit 12 is set, specify timezone
924: * offset to -2047 i.e. unsigned `zero'
925: */
926:
927: /* set method 1 for CUT/GMT */
928: timestamp->type_tz = udf_rw16((1<<12) + 0);
929: timestamp->year = udf_rw16(tm.tm_year + 1900);
930: timestamp->month = tm.tm_mon + 1; /* `tm' uses 0..11 for months */
931: timestamp->day = tm.tm_mday;
932: timestamp->hour = tm.tm_hour;
933: timestamp->minute = tm.tm_min;
934: timestamp->second = tm.tm_sec;
935:
936: usec = (timespec->tv_nsec + 500) / 1000; /* round */
937: husec = usec / 100;
938: usec -= husec * 100; /* only 0-99 in usec */
939: csec = husec / 100; /* only 0-99 in csec */
940: husec -= csec * 100; /* only 0-99 in husec */
941:
942: /* in rare cases there is overflow in csec */
943: csec = MIN(99, csec);
944: husec = MIN(99, husec);
945: usec = MIN(99, usec);
946:
947: timestamp->centisec = csec;
948: timestamp->hund_usec = husec;
949: timestamp->usec = usec;
950: }
951:
952:
953: static void
954: udf_set_timestamp(struct timestamp *timestamp, time_t value)
955: {
956: struct timespec t;
957:
958: memset(&t, 0, sizeof(struct timespec));
959: t.tv_sec = value;
960: t.tv_nsec = 0;
961: udf_timespec_to_timestamp(&t, timestamp);
962: }
963:
964:
965: static uint32_t
966: unix_mode_to_udf_perm(mode_t mode)
967: {
968: uint32_t perm;
1.2 riastrad 969:
1.1 reinoud 970: perm = ((mode & S_IRWXO) );
971: perm |= ((mode & S_IRWXG) << 2);
972: perm |= ((mode & S_IRWXU) << 4);
973: perm |= ((mode & S_IWOTH) << 3);
974: perm |= ((mode & S_IWGRP) << 5);
975: perm |= ((mode & S_IWUSR) << 7);
976:
977: return perm;
978: }
979:
980: /* end of copied code */
981:
982:
983: void
984: udf_encode_osta_id(char *osta_id, uint16_t len, char *text)
985: {
986: struct charspec osta_charspec;
987: uint8_t result_len;
988:
989: memset(osta_id, 0, len);
990: if (!text || (strlen(text) == 0)) return;
991:
992: udf_osta_charset(&osta_charspec);
993: unix_to_udf_name(osta_id, &result_len, text, strlen(text),
994: &osta_charspec);
995:
996: /* Ecma 167/7.2.13 states that length is recorded in the last byte */
997: osta_id[len-1] = strlen(text)+1;
998: }
999:
1000:
1001: void
1002: udf_set_timestamp_now(struct timestamp *timestamp)
1003: {
1004: struct timespec now;
1005:
1006: #ifdef CLOCK_REALTIME
1007: (void)clock_gettime(CLOCK_REALTIME, &now);
1008: #else
1009: struct timeval time_of_day;
1010:
1011: (void)gettimeofday(&time_of_day, NULL);
1012: now.tv_sec = time_of_day.tv_sec;
1013: now.tv_nsec = time_of_day.tv_usec * 1000;
1014: #endif
1015: udf_timespec_to_timestamp(&now, timestamp);
1016: }
1017:
1018:
1019: int
1020: udf_create_primaryd(void)
1021: {
1022: struct pri_vol_desc *pri;
1023: uint16_t crclen;
1024:
1025: pri = calloc(1, context.sector_size);
1026: if (pri == NULL)
1027: return ENOMEM;
1028:
1029: memset(pri, 0, context.sector_size);
1030: udf_inittag(&pri->tag, TAGID_PRI_VOL, /* loc */ 0);
1031: pri->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1032:
1033: pri->pvd_num = udf_rw32(0); /* default serial */
1034: udf_encode_osta_id(pri->vol_id, 32, context.primary_name);
1035:
1036: /* set defaults for single disc volumes as UDF prescribes */
1037: pri->vds_num = udf_rw16(1);
1038: pri->max_vol_seq = udf_rw16(1);
1039: pri->ichg_lvl = udf_rw16(2);
1040: pri->max_ichg_lvl = udf_rw16(3);
1041: pri->flags = udf_rw16(0);
1042:
1043: pri->charset_list = udf_rw32(1); /* only CS0 */
1044: pri->max_charset_list = udf_rw32(1); /* only CS0 */
1045:
1046: udf_encode_osta_id(pri->volset_id, 128, context.volset_name);
1047: udf_osta_charset(&pri->desc_charset);
1048: udf_osta_charset(&pri->explanatory_charset);
1049:
1050: udf_set_regid(&pri->app_id, context.app_name);
1051: udf_add_app_regid(&pri->app_id);
1052:
1053: udf_set_regid(&pri->imp_id, context.impl_name);
1054: udf_add_impl_regid(&pri->imp_id);
1055:
1056: udf_set_timestamp_now(&pri->time);
1057:
1058: crclen = sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH;
1059: pri->tag.desc_crc_len = udf_rw16(crclen);
1060:
1061: context.primary_vol = pri;
1062:
1063: return 0;
1064: }
1065:
1066:
1067: /*
1068: * BUGALERT: some rogue implementations use random physical partition
1069: * numbers to break other implementations so lookup the number.
1070: */
1071:
1072: uint16_t
1073: udf_find_raw_phys(uint16_t raw_phys_part)
1074: {
1075: struct part_desc *part;
1076: uint16_t phys_part;
1077:
1078: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1079: part = context.partitions[phys_part];
1080: if (part == NULL)
1081: break;
1082: if (udf_rw16(part->part_num) == raw_phys_part)
1083: break;
1084: }
1085: return phys_part;
1086: }
1087:
1088:
1089: /* XXX no support for unallocated or freed space tables yet (!) */
1090: int
1091: udf_create_partitiond(int part_num)
1092: {
1093: struct part_desc *pd;
1094: struct part_hdr_desc *phd;
1095: uint32_t sector_size, bitmap_bytes;
1096: uint16_t crclen;
1097: int part_accesstype = context.media_accesstype;
1098:
1099: sector_size = context.sector_size;
1100: bitmap_bytes = layout.alloc_bitmap_dscr_size * sector_size;
1101:
1102: if (context.partitions[part_num])
1103: errx(1, "internal error, partition %d already defined in %s",
1104: part_num, __func__);
1105:
1106: pd = calloc(1, context.sector_size);
1107: if (pd == NULL)
1108: return ENOMEM;
1109: phd = &pd->_impl_use.part_hdr;
1110:
1111: udf_inittag(&pd->tag, TAGID_PARTITION, /* loc */ 0);
1112: pd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1113:
1114: pd->flags = udf_rw16(1); /* allocated */
1115: pd->part_num = udf_rw16(part_num); /* only one physical partition */
1116:
1117: if (context.dscrver == 2) {
1118: udf_set_regid(&pd->contents, "+NSR02");
1119: } else {
1120: udf_set_regid(&pd->contents, "+NSR03");
1121: }
1122: udf_add_app_regid(&pd->contents);
1123:
1124: phd->unalloc_space_bitmap.len = udf_rw32(bitmap_bytes);
1125: phd->unalloc_space_bitmap.lb_num = udf_rw32(layout.unalloc_space);
1126:
1127: if (layout.freed_space) {
1128: phd->freed_space_bitmap.len = udf_rw32(bitmap_bytes);
1129: phd->freed_space_bitmap.lb_num = udf_rw32(layout.freed_space);
1130: }
1131:
1132: pd->access_type = udf_rw32(part_accesstype);
1133: pd->start_loc = udf_rw32(layout.part_start_lba);
1134: pd->part_len = udf_rw32(layout.part_size_lba);
1135:
1136: udf_set_regid(&pd->imp_id, context.impl_name);
1137: udf_add_impl_regid(&pd->imp_id);
1138:
1139: crclen = sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH;
1140: pd->tag.desc_crc_len = udf_rw16(crclen);
1141:
1142: context.partitions[part_num] = pd;
1143:
1144: return 0;
1145: }
1146:
1147:
1148: int
1149: udf_create_unalloc_spaced(void)
1150: {
1151: struct unalloc_sp_desc *usd;
1152: uint16_t crclen;
1153:
1154: usd = calloc(1, context.sector_size);
1155: if (usd == NULL)
1156: return ENOMEM;
1157:
1158: udf_inittag(&usd->tag, TAGID_UNALLOC_SPACE, /* loc */ 0);
1159: usd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1160:
1161: /* no default entries */
1162: usd->alloc_desc_num = udf_rw32(0); /* no entries */
1163:
1164: crclen = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad);
1165: crclen -= UDF_DESC_TAG_LENGTH;
1166: usd->tag.desc_crc_len = udf_rw16(crclen);
1167:
1168: context.unallocated = usd;
1169:
1170: return 0;
1171: }
1172:
1173:
1174: static int
1175: udf_create_base_logical_dscr(void)
1176: {
1177: struct logvol_desc *lvd;
1178: uint32_t sector_size;
1179: uint16_t crclen;
1180:
1181: sector_size = context.sector_size;
1182:
1183: lvd = calloc(1, sector_size);
1184: if (lvd == NULL)
1185: return ENOMEM;
1186:
1187: udf_inittag(&lvd->tag, TAGID_LOGVOL, /* loc */ 0);
1188: lvd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1189:
1190: udf_osta_charset(&lvd->desc_charset);
1191: udf_encode_osta_id(lvd->logvol_id, 128, context.logvol_name);
1192: lvd->lb_size = udf_rw32(sector_size);
1193:
1194: udf_set_regid(&lvd->domain_id, "*OSTA UDF Compliant");
1195: udf_add_domain_regid(&lvd->domain_id);
1196:
1197: /* no partition mappings/entries yet */
1198: lvd->mt_l = udf_rw32(0);
1199: lvd->n_pm = udf_rw32(0);
1200:
1201: udf_set_regid(&lvd->imp_id, context.impl_name);
1202: udf_add_impl_regid(&lvd->imp_id);
1203:
1204: lvd->integrity_seq_loc.loc = udf_rw32(layout.lvis);
1205: lvd->integrity_seq_loc.len = udf_rw32(layout.lvis_size * sector_size);
1206:
1207: /* just one fsd for now */
1208: lvd->lv_fsd_loc.len = udf_rw32(sector_size);
1209: lvd->lv_fsd_loc.loc.part_num = udf_rw32(context.metadata_part);
1210: lvd->lv_fsd_loc.loc.lb_num = udf_rw32(layout.fsd);
1211:
1212: crclen = sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH;
1213: lvd->tag.desc_crc_len = udf_rw16(crclen);
1214:
1215: context.logical_vol = lvd;
1216: context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
1217:
1218: return 0;
1219: }
1220:
1221:
1.2 riastrad 1222: static void
1.1 reinoud 1223: udf_add_logvol_part_physical(uint16_t phys_part)
1224: {
1225: struct logvol_desc *logvol = context.logical_vol;
1226: union udf_pmap *pmap;
1227: uint8_t *pmap_pos;
1228: uint16_t crclen;
1229: uint32_t pmap1_size, log_part;
1230:
1231: log_part = udf_rw32(logvol->n_pm);
1232: pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1233: pmap1_size = sizeof(struct part_map_1);
1234:
1235: pmap = (union udf_pmap *) pmap_pos;
1236: pmap->pm1.type = 1;
1237: pmap->pm1.len = sizeof(struct part_map_1);
1238: pmap->pm1.vol_seq_num = udf_rw16(1); /* no multi-volume */
1239: pmap->pm1.part_num = udf_rw16(phys_part);
1240:
1241: context.vtop [log_part] = phys_part;
1242: context.vtop_tp [log_part] = UDF_VTOP_TYPE_PHYS;
1243: context.part_size[log_part] = layout.part_size_lba;
1244: context.part_free[log_part] = layout.part_size_lba;
1245:
1246: /* increment number of partitions and length */
1247: logvol->n_pm = udf_rw32(log_part + 1);
1248: logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmap1_size);
1249:
1250: crclen = udf_rw16(logvol->tag.desc_crc_len) + pmap1_size;
1251: logvol->tag.desc_crc_len = udf_rw16(crclen);
1252: }
1253:
1254:
1255: static void
1256: udf_add_logvol_part_virtual(uint16_t phys_part)
1257: {
1258: union udf_pmap *pmap;
1259: struct logvol_desc *logvol = context.logical_vol;
1260: uint8_t *pmap_pos;
1261: uint16_t crclen;
1262: uint32_t pmapv_size, log_part;
1263:
1264: log_part = udf_rw32(logvol->n_pm);
1265: pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1266: pmapv_size = sizeof(struct part_map_2);
1267:
1268: pmap = (union udf_pmap *) pmap_pos;
1269: pmap->pmv.type = 2;
1270: pmap->pmv.len = pmapv_size;
1271:
1272: udf_set_regid(&pmap->pmv.id, "*UDF Virtual Partition");
1273: udf_add_udf_regid(&pmap->pmv.id);
1274:
1275: pmap->pmv.vol_seq_num = udf_rw16(1); /* no multi-volume */
1276: pmap->pmv.part_num = udf_rw16(phys_part);
1277:
1278: context.vtop [log_part] = phys_part;
1279: context.vtop_tp [log_part] = UDF_VTOP_TYPE_VIRT;
1280: context.part_size[log_part] = 0xffffffff;
1281: context.part_free[log_part] = 0xffffffff;
1282:
1283: /* increment number of partitions and length */
1284: logvol->n_pm = udf_rw32(log_part + 1);
1285: logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
1286:
1287: crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
1288: logvol->tag.desc_crc_len = udf_rw16(crclen);
1289: }
1290:
1291:
1292: /* sparing table size is in bytes */
1293: static void
1294: udf_add_logvol_part_spareable(uint16_t phys_part)
1295: {
1296: union udf_pmap *pmap;
1297: struct logvol_desc *logvol = context.logical_vol;
1298: uint32_t *st_pos, spareable_bytes, pmaps_size;
1299: uint8_t *pmap_pos, num;
1300: uint16_t crclen;
1301: uint32_t log_part;
1302:
1303: log_part = udf_rw32(logvol->n_pm);
1304: pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1305: pmaps_size = sizeof(struct part_map_2);
1306: spareable_bytes = layout.spareable_area_size * context.sector_size;
1307:
1308: pmap = (union udf_pmap *) pmap_pos;
1309: pmap->pms.type = 2;
1310: pmap->pms.len = pmaps_size;
1311:
1312: udf_set_regid(&pmap->pmv.id, "*UDF Sparable Partition");
1313: udf_add_udf_regid(&pmap->pmv.id);
1314:
1315: pmap->pms.vol_seq_num = udf_rw16(1); /* no multi-volume */
1316: pmap->pms.part_num = udf_rw16(phys_part);
1317:
1318: pmap->pms.packet_len = udf_rw16(layout.spareable_blockingnr);
1319: pmap->pms.st_size = udf_rw32(spareable_bytes);
1320:
1321: /* enter spare tables */
1322: st_pos = &pmap->pms.st_loc[0];
1323: *st_pos++ = udf_rw32(layout.spt_1);
1324: *st_pos++ = udf_rw32(layout.spt_2);
1325:
1326: num = 2;
1327: if (layout.spt_2 == 0) num--;
1328: if (layout.spt_1 == 0) num--;
1329: pmap->pms.n_st = num; /* 8 bit */
1330:
1331: context.vtop [log_part] = phys_part;
1332: context.vtop_tp [log_part] = UDF_VTOP_TYPE_SPAREABLE;
1333: context.part_size[log_part] = layout.part_size_lba;
1334: context.part_free[log_part] = layout.part_size_lba;
1335:
1336: /* increment number of partitions and length */
1337: logvol->n_pm = udf_rw32(log_part + 1);
1338: logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmaps_size);
1339:
1340: crclen = udf_rw16(logvol->tag.desc_crc_len) + pmaps_size;
1341: logvol->tag.desc_crc_len = udf_rw16(crclen);
1342: }
1343:
1344:
1345: int
1346: udf_create_sparing_tabled(void)
1347: {
1348: struct udf_sparing_table *spt;
1349: struct spare_map_entry *sme;
1350: uint32_t loc, cnt;
1351: uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1352:
1353: spt = calloc(context.sector_size, layout.sparing_table_dscr_lbas);
1354: if (spt == NULL)
1355: return ENOMEM;
1356:
1357: /* a sparing table descriptor is a whole spareable_blockingnr sectors */
1358: udf_inittag(&spt->tag, TAGID_SPARING_TABLE, /* loc */ 0);
1359:
1360: udf_set_regid(&spt->id, "*UDF Sparing Table");
1361: udf_add_udf_regid(&spt->id);
1362:
1363: spt->rt_l = udf_rw16(layout.spareable_blocks);
1364: spt->seq_num = udf_rw32(0); /* first generation */
1365:
1366: for (cnt = 0; cnt < layout.spareable_blocks; cnt++) {
1367: sme = &spt->entries[cnt];
1368: loc = layout.spareable_area + cnt * layout.spareable_blockingnr;
1369: sme->org = udf_rw32(0xffffffff); /* open for reloc */
1370: sme->map = udf_rw32(loc);
1371: }
1372:
1373: /* calculate crc len for actual size */
1374: crclen = sizeof(struct udf_sparing_table) - UDF_DESC_TAG_LENGTH;
1375: crclen += (layout.spareable_blocks-1) * sizeof(struct spare_map_entry);
1376:
1377: assert(crclen <= UINT16_MAX);
1378: spt->tag.desc_crc_len = udf_rw16((uint16_t)crclen);
1379:
1380: context.sparing_table = spt;
1381:
1382: return 0;
1383: }
1384:
1385:
1386: static void
1387: udf_add_logvol_part_meta(uint16_t phys_part)
1388: {
1389: union udf_pmap *pmap;
1390: struct logvol_desc *logvol = context.logical_vol;
1391: uint8_t *pmap_pos;
1392: uint32_t pmapv_size, log_part;
1393: uint16_t crclen;
1394:
1395: log_part = udf_rw32(logvol->n_pm);
1396: pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1397: pmapv_size = sizeof(struct part_map_2);
1398:
1399: pmap = (union udf_pmap *) pmap_pos;
1400: pmap->pmm.type = 2;
1401: pmap->pmm.len = pmapv_size;
1402:
1403: udf_set_regid(&pmap->pmm.id, "*UDF Metadata Partition");
1404: udf_add_udf_regid(&pmap->pmm.id);
1405:
1406: pmap->pmm.vol_seq_num = udf_rw16(1); /* no multi-volume */
1407: pmap->pmm.part_num = udf_rw16(phys_part);
1408:
1409: /* fill in meta data file(s) and alloc/alignment unit sizes */
1410: pmap->pmm.meta_file_lbn = udf_rw32(layout.meta_file);
1411: pmap->pmm.meta_mirror_file_lbn = udf_rw32(layout.meta_mirror);
1412: pmap->pmm.meta_bitmap_file_lbn = udf_rw32(layout.meta_bitmap);
1413: pmap->pmm.alloc_unit_size = udf_rw32(layout.meta_blockingnr);
1414: pmap->pmm.alignment_unit_size = udf_rw16(layout.meta_alignment);
1415: pmap->pmm.flags = 0; /* METADATA_DUPLICATED */
1416:
1417: context.vtop [log_part] = phys_part;
1418: context.vtop_tp [log_part] = UDF_VTOP_TYPE_META;
1419: context.part_size[log_part] = layout.meta_part_size_lba;
1420: context.part_free[log_part] = layout.meta_part_size_lba;
1421:
1422: /* increment number of partitions and length */
1423: logvol->n_pm = udf_rw32(log_part + 1);
1424: logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
1425:
1426: crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
1427: logvol->tag.desc_crc_len = udf_rw16(crclen);
1428: }
1429:
1430:
1431: int
1432: udf_create_logical_dscr(void)
1433: {
1434: int error;
1435:
1436: if ((error = udf_create_base_logical_dscr()))
1437: return error;
1438:
1439: /* we pass data_part for there might be a read-only part one day */
1440: if (context.format_flags & FORMAT_SPAREABLE) {
1441: /* spareable partition mapping has no physical mapping */
1442: udf_add_logvol_part_spareable(context.data_part);
1443: } else {
1444: udf_add_logvol_part_physical(context.data_part);
1445: }
1446:
1447: if (context.format_flags & FORMAT_VAT) {
1448: /* add VAT virtual mapping; reflects on datapart */
1449: udf_add_logvol_part_virtual(context.data_part);
1450: }
1451: if (context.format_flags & FORMAT_META) {
1452: /* add META data mapping; reflects on datapart */
1453: udf_add_logvol_part_meta(context.data_part);
1454: }
1455:
1456: return 0;
1457: }
1458:
1459:
1460: int
1461: udf_create_impvold(char *field1, char *field2, char *field3)
1462: {
1463: struct impvol_desc *ivd;
1464: struct udf_lv_info *lvi;
1465: uint16_t crclen;
1466:
1467: ivd = calloc(1, context.sector_size);
1468: if (ivd == NULL)
1469: return ENOMEM;
1470: lvi = &ivd->_impl_use.lv_info;
1471:
1472: udf_inittag(&ivd->tag, TAGID_IMP_VOL, /* loc */ 0);
1473: ivd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1474:
1475: udf_set_regid(&ivd->impl_id, "*UDF LV Info");
1476: udf_add_udf_regid(&ivd->impl_id);
1477:
1478: /* fill in UDF specific part */
1479: udf_osta_charset(&lvi->lvi_charset);
1480: udf_encode_osta_id(lvi->logvol_id, 128, context.logvol_name);
1481:
1482: udf_encode_osta_id(lvi->lvinfo1, 36, field1);
1483: udf_encode_osta_id(lvi->lvinfo2, 36, field2);
1484: udf_encode_osta_id(lvi->lvinfo3, 36, field3);
1485:
1486: udf_set_regid(&lvi->impl_id, context.impl_name);
1487: udf_add_impl_regid(&lvi->impl_id);
1488:
1489: crclen = sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH;
1490: ivd->tag.desc_crc_len = udf_rw16(crclen);
1491:
1492: context.implementation = ivd;
1493:
1494: return 0;
1495: }
1496:
1497:
1498: /* XXX might need to be sanitised a bit */
1499: void
1500: udf_update_lvintd(int type)
1501: {
1502: struct logvol_int_desc *lvid;
1503: struct udf_logvol_info *lvinfo;
1504: struct logvol_desc *logvol;
1505: uint32_t *pos;
1506: uint32_t cnt, num_partmappings;
1507: uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1508:
1509: lvid = context.logvol_integrity;
1510: logvol = context.logical_vol;
1511: assert(lvid);
1512: assert(logvol);
1513:
1514: lvid->integrity_type = udf_rw32(type);
1515: udf_set_timestamp_now(&lvid->time);
1516:
1517: /* initialise lvinfo just in case its not set yet */
1518: num_partmappings = udf_rw32(logvol->n_pm);
1519: assert(num_partmappings > 0);
1520:
1521: lvinfo = (struct udf_logvol_info *)
1522: (lvid->tables + num_partmappings * 2);
1523: context.logvol_info = lvinfo;
1524:
1525: udf_set_regid(&lvinfo->impl_id, context.impl_name);
1526: udf_add_impl_regid(&lvinfo->impl_id);
1527:
1528: if (type == UDF_INTEGRITY_CLOSED) {
1529: lvinfo->num_files = udf_rw32(context.num_files);
1530: lvinfo->num_directories = udf_rw32(context.num_directories);
1531:
1532: lvid->lvint_next_unique_id = udf_rw64(context.unique_id);
1533: }
1534:
1535: /* sane enough? */
1536: if (udf_rw16(lvinfo->min_udf_readver) < context.min_udf)
1537: lvinfo->min_udf_readver = udf_rw16(context.min_udf);
1538: if (udf_rw16(lvinfo->min_udf_writever) < context.min_udf)
1539: lvinfo->min_udf_writever = udf_rw16(context.min_udf);
1540: if (udf_rw16(lvinfo->max_udf_writever) < context.max_udf)
1541: lvinfo->max_udf_writever = udf_rw16(context.max_udf);
1542:
1543: lvid->num_part = udf_rw32(num_partmappings);
1544:
1545: pos = &lvid->tables[0];
1546: for (cnt = 0; cnt < num_partmappings; cnt++) {
1547: *pos++ = udf_rw32(context.part_free[cnt]);
1548: }
1549: for (cnt = 0; cnt < num_partmappings; cnt++) {
1550: *pos++ = udf_rw32(context.part_size[cnt]);
1551: }
1552:
1553: crclen = sizeof(struct logvol_int_desc) -4 -UDF_DESC_TAG_LENGTH +
1554: udf_rw32(lvid->l_iu);
1555: crclen += num_partmappings * 2 * 4;
1556:
1557: assert(crclen <= UINT16_MAX);
1558: if (lvid->tag.desc_crc_len == 0)
1559: lvid->tag.desc_crc_len = udf_rw16(crclen);
1560:
1561: context.logvol_info = lvinfo;
1562: }
1563:
1564:
1565: int
1566: udf_create_lvintd(int type)
1567: {
1568: struct logvol_int_desc *lvid;
1569: int l_iu;
1570:
1571: lvid = calloc(1, context.sector_size);
1572: if (lvid == NULL)
1573: return ENOMEM;
1574:
1575: udf_inittag(&lvid->tag, TAGID_LOGVOL_INTEGRITY, /* loc */ 0);
1576: context.logvol_integrity = lvid;
1577:
1578: /* only set for standard UDF info, no extra impl. use needed */
1579: l_iu = sizeof(struct udf_logvol_info);
1580: lvid->l_iu = udf_rw32(l_iu);
1581:
1582: udf_update_lvintd(type);
1583:
1584: return 0;
1585: }
1586:
1587:
1588: int
1589: udf_create_fsd(void)
1590: {
1591: struct fileset_desc *fsd;
1592: uint16_t crclen;
1593:
1594: fsd = calloc(1, context.sector_size);
1595: if (fsd == NULL)
1596: return ENOMEM;
1597:
1598: udf_inittag(&fsd->tag, TAGID_FSD, /* loc */ 0);
1599:
1600: udf_set_timestamp_now(&fsd->time);
1601: fsd->ichg_lvl = udf_rw16(3); /* UDF 2.3.2.1 */
1602: fsd->max_ichg_lvl = udf_rw16(3); /* UDF 2.3.2.2 */
1603:
1604: fsd->charset_list = udf_rw32(1); /* only CS0 */
1605: fsd->max_charset_list = udf_rw32(1); /* only CS0 */
1606:
1607: fsd->fileset_num = udf_rw32(0); /* only one fsd */
1608: fsd->fileset_desc_num = udf_rw32(0); /* original */
1609:
1610: udf_osta_charset(&fsd->logvol_id_charset);
1611: udf_encode_osta_id(fsd->logvol_id, 128, context.logvol_name);
1612:
1613: udf_osta_charset(&fsd->fileset_charset);
1614: udf_encode_osta_id(fsd->fileset_id, 32, context.fileset_name);
1615:
1616: /* copyright file and abstract file names obmitted */
1617:
1618: fsd->rootdir_icb.len = udf_rw32(context.sector_size);
1619: fsd->rootdir_icb.loc.lb_num = udf_rw32(layout.rootdir);
1620: fsd->rootdir_icb.loc.part_num = udf_rw16(context.metadata_part);
1621:
1622: udf_set_regid(&fsd->domain_id, "*OSTA UDF Compliant");
1623: udf_add_domain_regid(&fsd->domain_id);
1624:
1625: /* next_ex stays zero */
1626: /* no system streamdirs yet */
1627:
1628: crclen = sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH;
1629: fsd->tag.desc_crc_len = udf_rw16(crclen);
1630:
1631: context.fileset_desc = fsd;
1632:
1633: return 0;
1634: }
1635:
1636:
1637: int
1638: udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba,
1639: struct space_bitmap_desc **sbdp)
1640: {
1641: struct space_bitmap_desc *sbd;
1642: uint32_t cnt;
1643: uint16_t crclen;
1644:
1645: *sbdp = NULL;
1646: sbd = calloc(context.sector_size, dscr_size);
1647: if (sbd == NULL)
1648: return ENOMEM;
1649:
1650: udf_inittag(&sbd->tag, TAGID_SPACE_BITMAP, /* loc */ 0);
1651:
1652: sbd->num_bits = udf_rw32(part_size_lba);
1653: sbd->num_bytes = udf_rw32((part_size_lba + 7)/8);
1654:
1655: /* fill space with 0xff to indicate free */
1656: for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
1657: sbd->data[cnt] = 0xff;
1658:
1659: /* set crc to only cover the header (UDF 2.3.1.2, 2.3.8.1) */
1660: crclen = sizeof(struct space_bitmap_desc) -1 - UDF_DESC_TAG_LENGTH;
1661: sbd->tag.desc_crc_len = udf_rw16(crclen);
1662:
1663: *sbdp = sbd;
1664: return 0;
1665: }
1666:
1667: /* --------------------------------------------------------------------- */
1668:
1.2 riastrad 1669: int
1.1 reinoud 1670: udf_register_bad_block(uint32_t location)
1671: {
1672: struct udf_sparing_table *spt;
1673: struct spare_map_entry *sme, *free_sme;
1674: uint32_t cnt;
1675:
1676: spt = context.sparing_table;
1677: if (spt == NULL)
1678: errx(1, "internal error, adding bad block to "
1679: "non spareable in %s", __func__);
1680:
1681: /* find us a free spare map entry */
1682: free_sme = NULL;
1683: for (cnt = 0; cnt < layout.spareable_blocks; cnt++) {
1684: sme = &spt->entries[cnt];
1685: /* if we are allready in it, bail out */
1686: if (udf_rw32(sme->org) == location)
1687: return 0;
1688: if (udf_rw32(sme->org) == 0xffffffff) {
1689: free_sme = sme;
1690: break;
1691: }
1692: }
1693: if (free_sme == NULL) {
1694: warnx("disc relocation blocks full; disc too damaged");
1695: return EINVAL;
1696: }
1697: free_sme->org = udf_rw32(location);
1698:
1699: return 0;
1700: }
1701:
1702:
1703: void
1704: udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks)
1705: {
1706: union dscrptr *dscr;
1707: uint8_t *bpos;
1708: uint32_t cnt, bit;
1709:
1710: /* account for space used on underlying partition */
1711: #ifdef DEBUG
1712: printf("mark allocated : partnr %d, start_lb %d for %d blocks\n",
1713: partnr, start_lb, blocks);
1714: #endif
1715:
1716: switch (context.vtop_tp[partnr]) {
1717: case UDF_VTOP_TYPE_VIRT:
1718: /* nothing */
1719: break;
1720: case UDF_VTOP_TYPE_PHYS:
1721: case UDF_VTOP_TYPE_SPAREABLE:
1722: case UDF_VTOP_TYPE_META:
1723: if (context.part_unalloc_bits[context.vtop[partnr]] == NULL) {
1724: context.part_free[partnr] = 0;
1725: break;
1726: }
1727: #ifdef DEBUG
1728: printf("marking %d+%d as used\n", start_lb, blocks);
1729: #endif
1730: dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]);
1731: for (cnt = start_lb; cnt < start_lb + blocks; cnt++) {
1732: bpos = &dscr->sbd.data[cnt / 8];
1733: bit = cnt % 8;
1734: /* only account for bits marked free */
1735: if ((*bpos & (1 << bit)))
1736: context.part_free[partnr] -= 1;
1737: *bpos &= ~(1<< bit);
1738: }
1739: break;
1740: default:
1741: errx(1, "internal error: bad mapping type %d in %s",
1742: context.vtop_tp[partnr], __func__);
1743: }
1744: }
1745:
1746:
1747: void
1748: udf_advance_uniqueid(void)
1749: {
1750: /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
1751: context.unique_id++;
1752: if (context.unique_id < 0x10)
1753: context.unique_id = 0x10;
1754: }
1755:
1756: /* --------------------------------------------------------------------- */
1757:
1758: /* XXX implement the using of the results */
1759: int
1760: udf_surface_check(void)
1761: {
1762: uint32_t loc, block_bytes;
1763: uint32_t sector_size, blockingnr, bpos;
1764: uint8_t *buffer;
1765: int error, num_errors;
1766:
1767: if (mmc_discinfo.mmc_class == MMC_CLASS_DISC)
1768: return 0;
1769:
1770: sector_size = context.sector_size;
1771: blockingnr = layout.blockingnr;
1772:
1773: block_bytes = layout.blockingnr * sector_size;
1774: if ((buffer = malloc(block_bytes)) == NULL)
1775: return ENOMEM;
1776:
1777: /* set all one to not kill Flash memory? */
1778: for (bpos = 0; bpos < block_bytes; bpos++)
1779: buffer[bpos] = 0x00;
1780:
1781: printf("\nChecking disc surface : phase 1 - writing\n");
1782: num_errors = 0;
1783: loc = layout.first_lba;
1784: while (loc <= layout.last_lba) {
1785: /* write blockingnr sectors */
1786: error = pwrite(dev_fd, buffer, block_bytes,
1787: (uint64_t) loc*sector_size);
1788: printf(" %08d + %d (%02d %%)\r", loc, blockingnr,
1789: (int)((100.0 * loc)/layout.last_lba));
1790: fflush(stdout);
1791: if (error == -1) {
1792: /* block is bad */
1793: printf("BAD block at %08d + %d \n",
1794: loc, layout.blockingnr);
1795: if ((error = udf_register_bad_block(loc))) {
1796: free(buffer);
1797: return error;
1798: }
1799: num_errors ++;
1800: }
1801: loc += layout.blockingnr;
1802: }
1803:
1804: printf("\nChecking disc surface : phase 2 - reading\n");
1805: num_errors = 0;
1806: loc = layout.first_lba;
1807: while (loc <= layout.last_lba) {
1808: /* read blockingnr sectors */
1809: error = pread(dev_fd, buffer, block_bytes, loc*sector_size);
1810: printf(" %08d + %d (%02d %%)\r", loc, blockingnr,
1811: (int)((100.0 * loc)/layout.last_lba));
1812: fflush(stdout);
1813: if (error == -1) {
1814: /* block is bad */
1815: printf("BAD block at %08d + %d \n",
1816: loc, layout.blockingnr);
1817: if ((error = udf_register_bad_block(loc))) {
1818: free(buffer);
1819: return error;
1820: }
1821: num_errors ++;
1822: }
1823: loc += layout.blockingnr;
1824: }
1825: printf("Scan complete : %d bad blocks found\n", num_errors);
1826: free(buffer);
1827:
1828: return 0;
1829: }
1830:
1831: /* --------------------------------------------------------------------- */
1832:
1833: #define UDF_SYMLINKBUFLEN (64*1024) /* picked */
1834: int
1835: udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target)
1836: {
1837: struct charspec osta_charspec;
1838: struct pathcomp pathcomp;
1839: char *pathbuf, *pathpos, *compnamepos;
1840: // char *mntonname;
1841: // int mntonnamelen;
1842: int pathlen, len, compnamelen;
1843: int error;
1844:
1845: /* process `target' to an UDF structure */
1846: pathbuf = malloc(UDF_SYMLINKBUFLEN);
1847: assert(pathbuf);
1848:
1849: *pathbufp = NULL;
1850: *pathlenp = 0;
1851:
1852: pathpos = pathbuf;
1853: pathlen = 0;
1854: udf_osta_charset(&osta_charspec);
1855:
1856: if (*target == '/') {
1857: /* symlink starts from the root */
1858: len = UDF_PATH_COMP_SIZE;
1859: memset(&pathcomp, 0, len);
1860: pathcomp.type = UDF_PATH_COMP_ROOT;
1861:
1862: #if 0
1863: /* XXX how to check for in makefs? */
1864: /* check if its mount-point relative! */
1865: mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1866: mntonnamelen = strlen(mntonname);
1867: if (strlen(target) >= mntonnamelen) {
1868: if (strncmp(target, mntonname, mntonnamelen) == 0) {
1869: pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
1870: target += mntonnamelen;
1871: }
1872: } else {
1873: target++;
1874: }
1875: #else
1876: target++;
1877: #endif
1878:
1879: memcpy(pathpos, &pathcomp, len);
1880: pathpos += len;
1881: pathlen += len;
1882: }
1883:
1884: error = 0;
1885: while (*target) {
1886: /* ignore multiple '/' */
1887: while (*target == '/') {
1888: target++;
1889: }
1890: if (!*target)
1891: break;
1892:
1893: /* extract component name */
1894: compnamelen = 0;
1895: compnamepos = target;
1896: while ((*target) && (*target != '/')) {
1897: target++;
1898: compnamelen++;
1899: }
1900:
1901: /* just trunc if too long ?? (security issue) */
1902: if (compnamelen >= 127) {
1903: error = ENAMETOOLONG;
1904: break;
1905: }
1906:
1907: /* convert unix name to UDF name */
1908: len = sizeof(struct pathcomp);
1909: memset(&pathcomp, 0, len);
1910: pathcomp.type = UDF_PATH_COMP_NAME;
1911: len = UDF_PATH_COMP_SIZE;
1912:
1913: if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
1914: pathcomp.type = UDF_PATH_COMP_PARENTDIR;
1915: if ((compnamelen == 1) && (*compnamepos == '.'))
1916: pathcomp.type = UDF_PATH_COMP_CURDIR;
1917:
1918: if (pathcomp.type == UDF_PATH_COMP_NAME) {
1919: unix_to_udf_name(
1920: (char *) &pathcomp.ident, &pathcomp.l_ci,
1921: compnamepos, compnamelen,
1922: &osta_charspec);
1923: len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
1924: }
1925:
1926: if (pathlen + len >= UDF_SYMLINKBUFLEN) {
1927: error = ENAMETOOLONG;
1928: break;
1929: }
1930:
1931: memcpy(pathpos, &pathcomp, len);
1932: pathpos += len;
1933: pathlen += len;
1934: }
1935:
1936: if (error) {
1937: /* aparently too big */
1938: free(pathbuf);
1939: return error;
1940: }
1941:
1942: /* return status of symlink contents writeout */
1943: *pathbufp = (uint8_t *) pathbuf;
1944: *pathlenp = pathlen;
1945:
1946: return 0;
1947:
1948: }
1949: #undef UDF_SYMLINKBUFLEN
1950:
1951:
1952: /*
1953: * XXX note the different semantics from udfclient: for FIDs it still rounds
1954: * up to sectors. Use udf_fidsize() for a correct length.
1955: */
1956: uint32_t
1957: udf_tagsize(union dscrptr *dscr, uint32_t lb_size)
1958: {
1959: uint32_t size, tag_id, num_lb, elmsz;
1960:
1961: tag_id = udf_rw16(dscr->tag.id);
1962:
1963: switch (tag_id) {
1964: case TAGID_LOGVOL :
1965: size = sizeof(struct logvol_desc) - 1;
1966: size += udf_rw32(dscr->lvd.mt_l);
1967: break;
1968: case TAGID_UNALLOC_SPACE :
1969: elmsz = sizeof(struct extent_ad);
1970: size = sizeof(struct unalloc_sp_desc) - elmsz;
1971: size += udf_rw32(dscr->usd.alloc_desc_num) * elmsz;
1972: break;
1973: case TAGID_FID :
1974: size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu);
1975: size = (size + 3) & ~3;
1976: break;
1977: case TAGID_LOGVOL_INTEGRITY :
1978: size = sizeof(struct logvol_int_desc) - sizeof(uint32_t);
1979: size += udf_rw32(dscr->lvid.l_iu);
1980: size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t));
1981: break;
1982: case TAGID_SPACE_BITMAP :
1983: size = sizeof(struct space_bitmap_desc) - 1;
1984: size += udf_rw32(dscr->sbd.num_bytes);
1985: break;
1986: case TAGID_SPARING_TABLE :
1987: elmsz = sizeof(struct spare_map_entry);
1988: size = sizeof(struct udf_sparing_table) - elmsz;
1989: size += udf_rw16(dscr->spt.rt_l) * elmsz;
1990: break;
1991: case TAGID_FENTRY :
1992: size = sizeof(struct file_entry);
1993: size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1;
1994: break;
1995: case TAGID_EXTFENTRY :
1996: size = sizeof(struct extfile_entry);
1997: size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1;
1998: break;
1999: case TAGID_FSD :
2000: size = sizeof(struct fileset_desc);
2001: break;
2002: default :
2003: size = sizeof(union dscrptr);
2004: break;
2005: }
2006:
2007: if ((size == 0) || (lb_size == 0))
2008: return 0;
2009:
2010: if (lb_size == 1)
2011: return size;
2012:
2013: /* round up in sectors */
2014: num_lb = (size + lb_size -1) / lb_size;
2015: return num_lb * lb_size;
2016: }
2017:
2018:
2019: int
2020: udf_fidsize(struct fileid_desc *fid)
2021: {
2022: uint32_t size;
2023:
2024: if (udf_rw16(fid->tag.id) != TAGID_FID)
2025: errx(1, "internal error, bad tag in %s", __func__);
2026:
1.3 reinoud 2027: size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
1.1 reinoud 2028: size = (size + 3) & ~3;
2029:
2030: return size;
2031: }
2032:
2033:
2034: int
2035: udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent)
2036: {
2037: /* the size of an empty FID is 38 but needs to be a multiple of 4 */
2038: int fidsize = 40;
2039:
2040: udf_inittag(&fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num));
2041: fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
2042: fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
2043: fid->icb = *parent;
2044: fid->icb.longad_uniqueid = parent->longad_uniqueid;
2045: fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
2046:
2047: /* we have to do the fid here explicitly for simplicity */
2048: udf_validate_tag_and_crc_sums((union dscrptr *) fid);
2049:
2050: return fidsize;
2051: }
2052:
2053:
2054: void
2055: udf_create_fid(uint32_t diroff, struct fileid_desc *fid, char *name,
2056: int file_char, struct long_ad *ref)
2057: {
2058: struct charspec osta_charspec;
2059: uint32_t endfid;
2060: uint32_t fidsize, lb_rest;
2061:
2062: memset(fid, 0, sizeof(*fid));
2063: udf_inittag(&fid->tag, TAGID_FID, udf_rw32(ref->loc.lb_num));
2064: fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
2065: fid->file_char = file_char;
2066: fid->l_iu = udf_rw16(0);
2067: fid->icb = *ref;
2068: fid->icb.longad_uniqueid = ref->longad_uniqueid;
2069:
2070: udf_osta_charset(&osta_charspec);
2071: unix_to_udf_name((char *) fid->data, &fid->l_fi, name, strlen(name),
2072: &osta_charspec);
2073:
2074: /*
2075: * OK, tricky part: we need to pad so the next descriptor header won't
2076: * cross the sector boundary
2077: */
2078: endfid = diroff + udf_fidsize(fid);
2079: lb_rest = context.sector_size - (endfid % context.sector_size);
2080: if (lb_rest < sizeof(struct desc_tag)) {
2081: /* add at least 32 */
2082: fid->l_iu = udf_rw16(32);
2083: udf_set_regid((struct regid *) fid->data, context.impl_name);
2084: udf_add_impl_regid((struct regid *) fid->data);
2085:
2086: unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu),
2087: &fid->l_fi, name, strlen(name), &osta_charspec);
2088: }
2089:
2090: fidsize = udf_fidsize(fid);
2091: fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
2092:
2093: /* make sure the header sums stays correct */
2094: udf_validate_tag_and_crc_sums((union dscrptr *)fid);
2095: }
2096:
2097:
2098: static void
2099: udf_append_parentfid(union dscrptr *dscr, struct long_ad *parent_icb)
2100: {
2101: struct file_entry *fe;
2102: struct extfile_entry *efe;
2103: struct fileid_desc *fid;
2104: uint32_t l_ea;
2105: uint32_t fidsize, crclen;
2106: uint8_t *bpos, *data;
2107:
2108: fe = NULL;
2109: efe = NULL;
2110: if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
2111: fe = &dscr->fe;
2112: data = fe->data;
2113: l_ea = udf_rw32(fe->l_ea);
2114: } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
2115: efe = &dscr->efe;
2116: data = efe->data;
2117: l_ea = udf_rw32(efe->l_ea);
2118: } else {
2119: errx(1, "internal error, bad tag in %s", __func__);
2120: }
2121:
2122: /* create '..' */
2123: bpos = data + l_ea;
2124: fid = (struct fileid_desc *) bpos;
2125: fidsize = udf_create_parentfid(fid, parent_icb);
2126:
2127: /* record fidlength information */
2128: if (fe) {
2129: fe->inf_len = udf_rw64(fidsize);
2130: fe->l_ad = udf_rw32(fidsize);
2131: fe->logblks_rec = udf_rw64(0); /* intern */
2132: crclen = sizeof(struct file_entry);
2133: } else {
2134: efe->inf_len = udf_rw64(fidsize);
2135: efe->obj_size = udf_rw64(fidsize);
2136: efe->l_ad = udf_rw32(fidsize);
2137: efe->logblks_rec = udf_rw64(0); /* intern */
2138: crclen = sizeof(struct extfile_entry);
2139: }
2140: crclen -= 1 + UDF_DESC_TAG_LENGTH;
2141: crclen += l_ea + fidsize;
2142: dscr->tag.desc_crc_len = udf_rw16(crclen);
2143:
2144: /* make sure the header sums stays correct */
2145: udf_validate_tag_and_crc_sums(dscr);
2146: }
2147:
2148: /* --------------------------------------------------------------------- */
2149:
2150: /*
2151: * Extended attribute support. UDF knows of 3 places for extended attributes:
2152: *
2153: * (a) inside the file's (e)fe in the length of the extended attribute area
2154: * before the allocation descriptors/filedata
2155: *
2156: * (b) in a file referenced by (e)fe->ext_attr_icb and
2157: *
2158: * (c) in the e(fe)'s associated stream directory that can hold various
2159: * sub-files. In the stream directory a few fixed named subfiles are reserved
2160: * for NT/Unix ACL's and OS/2 attributes.
2161: *
2162: * NOTE: Extended attributes are read randomly but always written
2163: * *atomically*. For ACL's this interface is probably different but not known
2164: * to me yet.
2165: *
2166: * Order of extended attributes in a space:
2167: * ECMA 167 EAs
2168: * Non block aligned Implementation Use EAs
2169: * Block aligned Implementation Use EAs
2170: * Application Use EAs
2171: */
2172:
2173: int
2174: udf_impl_extattr_check(struct impl_extattr_entry *implext)
2175: {
2176: uint16_t *spos;
2177:
2178: if (strncmp((char *) implext->imp_id.id, "*UDF", 4) == 0) {
2179: /* checksum valid? */
2180: spos = (uint16_t *) implext->data;
2181: if (udf_rw16(*spos) != udf_ea_cksum((uint8_t *) implext))
2182: return EINVAL;
2183: }
2184: return 0;
2185: }
2186:
2187: void
2188: udf_calc_impl_extattr_checksum(struct impl_extattr_entry *implext)
2189: {
2190: uint16_t *spos;
2191:
2192: if (strncmp((char *) implext->imp_id.id, "*UDF", 4) == 0) {
2193: /* set checksum */
2194: spos = (uint16_t *) implext->data;
2195: *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
2196: }
2197: }
2198:
2199:
2200: int
2201: udf_extattr_search_intern(union dscrptr *dscr,
2202: uint32_t sattr, char const *sattrname,
2203: uint32_t *offsetp, uint32_t *lengthp)
2204: {
2205: struct extattrhdr_desc *eahdr;
2206: struct extattr_entry *attrhdr;
2207: struct impl_extattr_entry *implext;
2208: uint32_t offset, a_l, sector_size;
2209: uint32_t l_ea;
2210: uint8_t *pos;
2211: int tag_id, error;
2212:
2213: sector_size = context.sector_size;
2214:
2215: /* get information from fe/efe */
2216: tag_id = udf_rw16(dscr->tag.id);
2217: if (tag_id == TAGID_FENTRY) {
2218: l_ea = udf_rw32(dscr->fe.l_ea);
2219: eahdr = (struct extattrhdr_desc *) dscr->fe.data;
2220: } else {
2221: assert(tag_id == TAGID_EXTFENTRY);
2222: l_ea = udf_rw32(dscr->efe.l_ea);
2223: eahdr = (struct extattrhdr_desc *) dscr->efe.data;
2224: }
2225:
2226: /* something recorded here? */
2227: if (l_ea == 0)
2228: return ENOENT;
2229:
2230: /* check extended attribute tag; what to do if it fails? */
2231: error = udf_check_tag(eahdr);
2232: if (error)
2233: return EINVAL;
2234: if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR)
2235: return EINVAL;
2236: error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
2237: if (error)
2238: return EINVAL;
2239:
2240: /* looking for Ecma-167 attributes? */
2241: offset = sizeof(struct extattrhdr_desc);
2242:
2243: /* looking for either implementation use or application use */
2244: if (sattr == 2048) { /* [4/48.10.8] */
2245: offset = udf_rw32(eahdr->impl_attr_loc);
2246: if (offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2247: return ENOENT;
2248: }
2249: if (sattr == 65536) { /* [4/48.10.9] */
2250: offset = udf_rw32(eahdr->appl_attr_loc);
2251: if (offset == UDF_APPL_ATTR_LOC_NOT_PRESENT)
2252: return ENOENT;
2253: }
2254:
2255: /* paranoia check offset and l_ea */
2256: if (l_ea + offset >= sector_size - sizeof(struct extattr_entry))
2257: return EINVAL;
2258:
2259: /* find our extended attribute */
2260: l_ea -= offset;
2261: pos = (uint8_t *) eahdr + offset;
2262:
2263: while (l_ea >= sizeof(struct extattr_entry)) {
2264: attrhdr = (struct extattr_entry *) pos;
2265: implext = (struct impl_extattr_entry *) pos;
2266:
2267: /* get complete attribute length and check for roque values */
2268: a_l = udf_rw32(attrhdr->a_l);
2269: if ((a_l == 0) || (a_l > l_ea))
2270: return EINVAL;
2271:
1.4 ! reinoud 2272: if (udf_rw32(attrhdr->type) != sattr)
1.1 reinoud 2273: goto next_attribute;
2274:
2275: /* we might have found it! */
1.4 ! reinoud 2276: if (udf_rw32(attrhdr->type) < 2048) { /* Ecma-167 attribute */
1.1 reinoud 2277: *offsetp = offset;
2278: *lengthp = a_l;
2279: return 0; /* success */
2280: }
2281:
2282: /*
2283: * Implementation use and application use extended attributes
2284: * have a name to identify. They share the same structure only
2285: * UDF implementation use extended attributes have a checksum
2286: * we need to check
2287: */
2288:
2289: if (strcmp((char *) implext->imp_id.id, sattrname) == 0) {
2290: /* we have found our appl/implementation attribute */
2291: *offsetp = offset;
2292: *lengthp = a_l;
2293: return 0; /* success */
2294: }
2295:
2296: next_attribute:
2297: /* next attribute */
2298: pos += a_l;
2299: l_ea -= a_l;
2300: offset += a_l;
2301: }
2302: /* not found */
2303: return ENOENT;
2304: }
2305:
2306:
2307: static void
2308: udf_extattr_insert_internal(union dscrptr *dscr, struct extattr_entry *extattr)
2309: {
2310: struct file_entry *fe;
2311: struct extfile_entry *efe;
2312: struct extattrhdr_desc *extattrhdr;
2313: struct impl_extattr_entry *implext;
2314: uint32_t impl_attr_loc, appl_attr_loc, l_ea, l_ad, a_l;
2315: uint16_t *spos;
2316: uint8_t *bpos, *data;
2317: void *l_eap;
2318:
2319: if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
2320: fe = &dscr->fe;
2321: data = fe->data;
2322: l_eap = &fe->l_ea;
2323: l_ad = udf_rw32(fe->l_ad);
2324: } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
2325: efe = &dscr->efe;
2326: data = efe->data;
2327: l_eap = &efe->l_ea;
2328: l_ad = udf_rw32(efe->l_ad);
2329: } else {
2330: errx(1, "internal error, bad tag in %s", __func__);
2331: }
2332:
2333: /* should have a header! */
2334: extattrhdr = (struct extattrhdr_desc *) data;
2335: memcpy(&l_ea, l_eap, sizeof(l_ea));
2336: l_ea = udf_rw32(l_ea);
2337: if (l_ea == 0) {
2338: uint32_t exthdr_len;
2339: assert(l_ad == 0);
2340: /* create empty extended attribute header */
2341: l_ea = sizeof(struct extattrhdr_desc);
2342: exthdr_len = udf_rw32(l_ea);
2343:
2344: udf_inittag(&extattrhdr->tag, TAGID_EXTATTR_HDR, /* loc */ 0);
2345: extattrhdr->impl_attr_loc = exthdr_len;
2346: extattrhdr->appl_attr_loc = exthdr_len;
2347: extattrhdr->tag.desc_crc_len = udf_rw16(8);
2348:
2349: /* record extended attribute header length */
2350: memcpy(l_eap, &exthdr_len, sizeof(exthdr_len));
2351: }
2352:
2353: /* extract locations */
2354: impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc);
2355: appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc);
2356: if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2357: impl_attr_loc = l_ea;
2358: if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2359: appl_attr_loc = l_ea;
2360:
2361: /* Ecma 167 EAs */
2362: if (udf_rw32(extattr->type) < 2048) {
2363: assert(impl_attr_loc == l_ea);
2364: assert(appl_attr_loc == l_ea);
2365: }
2366:
2367: /* implementation use extended attributes */
2368: if (udf_rw32(extattr->type) == 2048) {
2369: assert(appl_attr_loc == l_ea);
2370:
2371: /* calculate and write extended attribute header checksum */
2372: implext = (struct impl_extattr_entry *) extattr;
2373: assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */
2374: spos = (uint16_t *) implext->data;
2375: *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
2376: }
2377:
2378: /* application use extended attributes */
2379: assert(udf_rw32(extattr->type) != 65536);
2380: assert(appl_attr_loc == l_ea);
2381:
2382: /* append the attribute at the end of the current space */
2383: bpos = data + l_ea;
2384: a_l = udf_rw32(extattr->a_l);
2385:
2386: /* update impl. attribute locations */
2387: if (udf_rw32(extattr->type) < 2048) {
2388: impl_attr_loc = l_ea + a_l;
2389: appl_attr_loc = l_ea + a_l;
2390: }
2391: if (udf_rw32(extattr->type) == 2048) {
2392: appl_attr_loc = l_ea + a_l;
2393: }
2394:
2395: /* copy and advance */
2396: memcpy(bpos, extattr, a_l);
2397: l_ea += a_l;
2398: l_ea = udf_rw32(l_ea);
2399: memcpy(l_eap, &l_ea, sizeof(l_ea));
2400:
2401: /* do the `dance` again backwards */
2402: if (context.dscrver != 2) {
2403: if (impl_attr_loc == l_ea)
2404: impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT;
2405: if (appl_attr_loc == l_ea)
2406: appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT;
2407: }
2408:
2409: /* store offsets */
2410: extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc);
2411: extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc);
2412:
2413: /* make sure the header sums stays correct */
2414: udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
2415: }
2416:
2417: /* --------------------------------------------------------------------- */
2418:
2419: int
2420: udf_create_new_fe(struct file_entry **fep, int file_type, struct stat *st)
2421: {
2422: struct file_entry *fe;
2423: struct icb_tag *icb;
2424: struct timestamp birthtime;
2425: struct filetimes_extattr_entry *ft_extattr;
2426: uint32_t crclen; /* XXX: should be 16; need to detect overflow */
2427: uint16_t icbflags;
2428:
2429: *fep = NULL;
2430: fe = calloc(1, context.sector_size);
2431: if (fe == NULL)
2432: return ENOMEM;
2433:
2434: udf_inittag(&fe->tag, TAGID_FENTRY, /* loc */ 0);
2435: icb = &fe->icbtag;
2436:
2437: /*
2438: * Always use strategy type 4 unless on WORM wich we don't support
2439: * (yet). Fill in defaults and set for internal allocation of data.
2440: */
2441: icb->strat_type = udf_rw16(4);
2442: icb->max_num_entries = udf_rw16(1);
2443: icb->file_type = file_type; /* 8 bit */
2444: icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
2445:
2446: fe->perm = udf_rw32(0x7fff); /* all is allowed */
2447: fe->link_cnt = udf_rw16(0); /* explicit setting */
2448:
2449: fe->ckpoint = udf_rw32(1); /* user supplied file version */
2450:
2451: udf_set_timestamp_now(&birthtime);
2452: udf_set_timestamp_now(&fe->atime);
2453: udf_set_timestamp_now(&fe->attrtime);
2454: udf_set_timestamp_now(&fe->mtime);
2455:
2456: /* set attributes */
2457: if (st) {
2458: #if !HAVE_NBTOOL_CONFIG_H
2459: udf_set_timestamp(&birthtime, st->st_birthtime);
2460: #else
2461: udf_set_timestamp(&birthtime, 0);
2462: #endif
2463: udf_set_timestamp(&fe->atime, st->st_atime);
2464: udf_set_timestamp(&fe->attrtime, st->st_ctime);
2465: udf_set_timestamp(&fe->mtime, st->st_mtime);
2466: fe->uid = udf_rw32(st->st_uid);
2467: fe->gid = udf_rw32(st->st_gid);
2468:
2469: fe->perm = unix_mode_to_udf_perm(st->st_mode);
2470:
2471: icbflags = udf_rw16(fe->icbtag.flags);
2472: icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
2473: icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
2474: icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
2475: if (st->st_mode & S_ISUID)
2476: icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
2477: if (st->st_mode & S_ISGID)
2478: icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
2479: if (st->st_mode & S_ISVTX)
2480: icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
2481: fe->icbtag.flags = udf_rw16(icbflags);
2482: }
2483:
2484: udf_set_regid(&fe->imp_id, context.impl_name);
2485: udf_add_impl_regid(&fe->imp_id);
2486: fe->unique_id = udf_rw64(context.unique_id);
2487: udf_advance_uniqueid();
2488:
2489: fe->l_ea = udf_rw32(0);
2490:
2491: /* create extended attribute to record our creation time */
2492: ft_extattr = calloc(1, UDF_FILETIMES_ATTR_SIZE(1));
2493: ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO);
2494: ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */
2495: ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1));
2496: ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */
2497: ft_extattr->existence = UDF_FILETIMES_FILE_CREATION;
2498: ft_extattr->times[0] = birthtime;
2499:
2500: udf_extattr_insert_internal((union dscrptr *) fe,
2501: (struct extattr_entry *) ft_extattr);
2502: free(ft_extattr);
2503:
2504: /* record fidlength information */
2505: fe->inf_len = udf_rw64(0);
2506: fe->l_ad = udf_rw32(0);
2507: fe->logblks_rec = udf_rw64(0); /* intern */
2508:
2509: crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
2510: crclen += udf_rw32(fe->l_ea);
2511:
2512: /* make sure the header sums stays correct */
2513: fe->tag.desc_crc_len = udf_rw16(crclen);
2514: udf_validate_tag_and_crc_sums((union dscrptr *) fe);
2515:
2516: *fep = fe;
2517: return 0;
2518: }
2519:
2520:
2521: int
2522: udf_create_new_efe(struct extfile_entry **efep, int file_type, struct stat *st)
2523: {
2524: struct extfile_entry *efe;
2525: struct icb_tag *icb;
2526: uint32_t crclen; /* XXX: should be 16; need to detect overflow */
2527: uint16_t icbflags;
2528:
2529: *efep = NULL;
2530: efe = calloc(1, context.sector_size);
2531: if (efe == NULL)
2532: return ENOMEM;
2533:
2534: udf_inittag(&efe->tag, TAGID_EXTFENTRY, /* loc */ 0);
2535: icb = &efe->icbtag;
2536:
2537: /*
2538: * Always use strategy type 4 unless on WORM wich we don't support
2539: * (yet). Fill in defaults and set for internal allocation of data.
2540: */
2541: icb->strat_type = udf_rw16(4);
2542: icb->max_num_entries = udf_rw16(1);
2543: icb->file_type = file_type; /* 8 bit */
2544: icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
2545:
2546: efe->perm = udf_rw32(0x7fff); /* all is allowed */
2547: efe->link_cnt = udf_rw16(0); /* explicit setting */
2548:
2549: efe->ckpoint = udf_rw32(1); /* user supplied file version */
2550:
2551: udf_set_timestamp_now(&efe->ctime);
2552: udf_set_timestamp_now(&efe->atime);
2553: udf_set_timestamp_now(&efe->attrtime);
2554: udf_set_timestamp_now(&efe->mtime);
2555:
2556: /* set attributes */
2557: if (st) {
2558: #if !HAVE_NBTOOL_CONFIG_H
2559: udf_set_timestamp(&efe->ctime, st->st_birthtime);
2560: #else
2561: udf_set_timestamp(&efe->ctime, 0);
2562: #endif
2563: udf_set_timestamp(&efe->atime, st->st_atime);
2564: udf_set_timestamp(&efe->attrtime, st->st_ctime);
2565: udf_set_timestamp(&efe->mtime, st->st_mtime);
2566: efe->uid = udf_rw32(st->st_uid);
2567: efe->gid = udf_rw32(st->st_gid);
2568:
2569: efe->perm = unix_mode_to_udf_perm(st->st_mode);
2570:
2571: icbflags = udf_rw16(efe->icbtag.flags);
2572: icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
2573: icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
2574: icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
2575: if (st->st_mode & S_ISUID)
2576: icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
2577: if (st->st_mode & S_ISGID)
2578: icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
2579: if (st->st_mode & S_ISVTX)
2580: icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
2581: efe->icbtag.flags = udf_rw16(icbflags);
2582: }
2583:
2584: udf_set_regid(&efe->imp_id, context.impl_name);
2585: udf_add_impl_regid(&efe->imp_id);
2586:
2587: efe->unique_id = udf_rw64(context.unique_id);
2588: udf_advance_uniqueid();
2589:
2590: /* record fidlength information */
2591: efe->inf_len = udf_rw64(0);
2592: efe->obj_size = udf_rw64(0);
2593: efe->l_ad = udf_rw32(0);
2594: efe->logblks_rec = udf_rw64(0);
2595:
2596: crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
2597:
2598: /* make sure the header sums stays correct */
2599: efe->tag.desc_crc_len = udf_rw16(crclen);
2600: udf_validate_tag_and_crc_sums((union dscrptr *) efe);
2601:
2602: *efep = efe;
2603: return 0;
2604: }
2605:
2606: /* --------------------------------------------------------------------- */
2607:
2608: /* for METADATA file appending only */
2609: static void
2610: udf_append_meta_mapping_part_to_efe(struct extfile_entry *efe,
2611: struct short_ad *mapping)
2612: {
2613: struct icb_tag *icb;
2614: uint64_t inf_len, obj_size, logblks_rec;
2615: uint32_t l_ad, l_ea;
2616: uint16_t crclen;
2617: uintptr_t bpos;
2618:
2619: inf_len = udf_rw64(efe->inf_len);
2620: obj_size = udf_rw64(efe->obj_size);
2621: logblks_rec = udf_rw64(efe->logblks_rec);
2622: l_ad = udf_rw32(efe->l_ad);
2623: l_ea = udf_rw32(efe->l_ea);
2624: crclen = udf_rw16(efe->tag.desc_crc_len);
2625: icb = &efe->icbtag;
2626:
2627: /* set our allocation to shorts if not already done */
2628: icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC);
2629:
2630: /* append short_ad */
2631: bpos = (uintptr_t)efe->data + l_ea + l_ad;
2632: memcpy((void *)bpos, mapping, sizeof(struct short_ad));
2633:
2634: l_ad += sizeof(struct short_ad);
2635: crclen += sizeof(struct short_ad);
2636: inf_len += UDF_EXT_LEN(udf_rw32(mapping->len));
2637: obj_size += UDF_EXT_LEN(udf_rw32(mapping->len));
2638: logblks_rec = UDF_ROUNDUP(inf_len, context.sector_size) /
2639: context.sector_size;
2640:
2641: efe->l_ad = udf_rw32(l_ad);
2642: efe->inf_len = udf_rw64(inf_len);
2643: efe->obj_size = udf_rw64(obj_size);
2644: efe->logblks_rec = udf_rw64(logblks_rec);
2645: efe->tag.desc_crc_len = udf_rw16(crclen);
2646: }
2647:
2648:
2649: /* for METADATA file appending only */
2650: static void
2651: udf_append_meta_mapping_to_efe(struct extfile_entry *efe,
2652: uint16_t partnr, uint32_t lb_num,
2653: uint64_t len)
2654: {
2655: struct short_ad mapping;
2656: uint64_t max_len, part_len;
2657:
2658: /* calculate max length meta allocation sizes */
2659: max_len = UDF_EXT_MAXLEN / context.sector_size; /* in sectors */
2660: max_len = (max_len / layout.meta_blockingnr) * layout.meta_blockingnr;
2661: max_len = max_len * context.sector_size;
2662:
2663: memset(&mapping, 0, sizeof(mapping));
2664: while (len) {
2665: part_len = MIN(len, max_len);
2666: mapping.lb_num = udf_rw32(lb_num);
2667: mapping.len = udf_rw32(part_len);
2668:
2669: udf_append_meta_mapping_part_to_efe(efe, &mapping);
2670:
2671: lb_num += part_len / context.sector_size;
2672: len -= part_len;
2673: }
2674: }
2675:
2676:
2677: int
2678: udf_create_meta_files(void)
2679: {
2680: struct extfile_entry *efe;
2681: struct long_ad meta_icb;
2682: uint64_t bytes;
2683: uint32_t sector_size;
2684: int filetype, error;
2685:
2686: sector_size = context.sector_size;
2687:
2688: memset(&meta_icb, 0, sizeof(meta_icb));
2689: meta_icb.len = udf_rw32(sector_size);
2690: meta_icb.loc.part_num = udf_rw16(context.data_part);
2691:
2692: /* create metadata file */
2693: meta_icb.loc.lb_num = udf_rw32(layout.meta_file);
2694: filetype = UDF_ICB_FILETYPE_META_MAIN;
2695: error = udf_create_new_efe(&efe, filetype, NULL);
2696: if (error)
2697: return error;
2698: context.meta_file = efe;
2699: context.meta_file->unique_id = udf_rw64(0);
2700:
2701: /* create metadata mirror file */
2702: meta_icb.loc.lb_num = udf_rw32(layout.meta_mirror);
2703: filetype = UDF_ICB_FILETYPE_META_MIRROR;
2704: error = udf_create_new_efe(&efe, filetype, NULL);
2705: if (error)
2706: return error;
2707: context.meta_mirror = efe;
2708: context.meta_mirror->unique_id = udf_rw64(0);
2709:
2710: if (!(context.format_flags & FORMAT_READONLY)) {
2711: /* create metadata bitmap file */
2712: meta_icb.loc.lb_num = udf_rw32(layout.meta_bitmap);
2713: filetype = UDF_ICB_FILETYPE_META_BITMAP;
2714: error = udf_create_new_efe(&efe, filetype, NULL);
2715: if (error)
2716: return error;
2717: context.meta_bitmap = efe;
2718: context.meta_bitmap->unique_id = udf_rw64(0);
2719: }
2720:
2721: /* restart unique id */
2722: context.unique_id = 0x10;
2723:
2724: /* XXX no support for metadata mirroring yet */
2725: /* insert extents */
2726: efe = context.meta_file;
2727: udf_append_meta_mapping_to_efe(efe, context.data_part,
2728: layout.meta_part_start_lba,
2729: (uint64_t) layout.meta_part_size_lba * sector_size);
2730:
2731: efe = context.meta_mirror;
2732: udf_append_meta_mapping_to_efe(efe, context.data_part,
2733: layout.meta_part_start_lba,
2734: (uint64_t) layout.meta_part_size_lba * sector_size);
2735:
2736: if (context.meta_bitmap) {
2737: efe = context.meta_bitmap;
2738: bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
2739: udf_append_meta_mapping_to_efe(efe, context.data_part,
2740: layout.meta_bitmap_space, bytes);
2741: }
2742:
2743: return 0;
2744: }
2745:
2746:
2747: /* --------------------------------------------------------------------- */
2748:
2749: int
2750: udf_create_new_rootdir(union dscrptr **dscr)
2751: {
2752: struct file_entry *fe;
2753: struct extfile_entry *efe;
2754: struct long_ad root_icb;
2755: int filetype, error;
2756:
2757: memset(&root_icb, 0, sizeof(root_icb));
2758: root_icb.len = udf_rw32(context.sector_size);
2759: root_icb.loc.lb_num = udf_rw32(layout.rootdir);
2760: root_icb.loc.part_num = udf_rw16(context.metadata_part);
2761:
2762: filetype = UDF_ICB_FILETYPE_DIRECTORY;
2763: if (context.dscrver == 2) {
2764: error = udf_create_new_fe(&fe, filetype, NULL);
2765: *dscr = (union dscrptr *) fe;
2766: } else {
2767: error = udf_create_new_efe(&efe, filetype, NULL);
2768: *dscr = (union dscrptr *) efe;
2769: }
2770: if (error)
2771: return error;
2772:
2773: /* append '..' */
2774: udf_append_parentfid(*dscr, &root_icb);
2775:
2776: /* rootdir has explicit only one link on creation; '..' is no link */
2777: if (context.dscrver == 2) {
2778: fe->link_cnt = udf_rw16(1);
2779: } else {
2780: efe->link_cnt = udf_rw16(1);
2781: }
2782:
2783: context.num_directories++;
2784: assert(context.num_directories == 1);
2785:
2786: return 0;
2787: }
2788:
2789:
2790: void
2791: udf_prepend_VAT_file(void)
2792: {
2793: /* old style VAT has no prepend */
2794: if (context.dscrver == 2) {
2795: context.vat_start = 0;
2796: context.vat_size = 0;
2797: return;
2798: }
2799:
2800: context.vat_start = offsetof(struct udf_vat, data);
2801: context.vat_size = offsetof(struct udf_vat, data);
2802: }
2803:
2804:
2805: void
2806: udf_vat_update(uint32_t virt, uint32_t phys)
2807: {
2808: uint32_t *vatpos;
2809: uint32_t new_size;
2810:
2811: if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
2812: return;
1.2 riastrad 2813:
1.1 reinoud 2814: new_size = MAX(context.vat_size,
2815: (context.vat_start + (virt+1)*sizeof(uint32_t)));
2816:
2817: if (new_size > context.vat_allocated) {
1.2 riastrad 2818: context.vat_allocated =
1.1 reinoud 2819: UDF_ROUNDUP(new_size, context.sector_size);
2820: context.vat_contents = realloc(context.vat_contents,
2821: context.vat_allocated);
2822: assert(context.vat_contents);
2823: /* XXX could also report error */
2824: }
2825: vatpos = (uint32_t *) (context.vat_contents + context.vat_start);
2826: vatpos[virt] = udf_rw32(phys);
2827:
2828: context.vat_size = MAX(context.vat_size,
2829: (context.vat_start + (virt+1)*sizeof(uint32_t)));
2830: }
2831:
2832:
2833: int
2834: udf_append_VAT_file(void)
2835: {
2836: struct udf_oldvat_tail *oldvat_tail;
2837: struct udf_vat *vathdr;
2838: int32_t len_diff;
2839:
2840: /* new style VAT has VAT LVInt analog in front */
2841: if (context.dscrver == 3) {
2842: /* set up VATv2 descriptor */
2843: vathdr = (struct udf_vat *) context.vat_contents;
2844: vathdr->header_len = udf_rw16(sizeof(struct udf_vat) - 1);
2845: vathdr->impl_use_len = udf_rw16(0);
2846: memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
2847: vathdr->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2848: vathdr->num_files = udf_rw32(context.num_files);
2849: vathdr->num_directories = udf_rw32(context.num_directories);
2850:
2851: vathdr->min_udf_readver = udf_rw16(context.min_udf);
2852: vathdr->min_udf_writever = udf_rw16(context.min_udf);
2853: vathdr->max_udf_writever = udf_rw16(context.max_udf);
2854:
2855: return 0;
2856: }
2857:
2858: /* old style VAT has identifier appended */
2859:
2860: /* append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
2861: len_diff = context.vat_allocated - context.vat_size;
2862: assert(len_diff >= 0);
2863: if (len_diff < (int32_t) sizeof(struct udf_oldvat_tail)) {
2864: context.vat_allocated += context.sector_size;
2865: context.vat_contents = realloc(context.vat_contents,
2866: context.vat_allocated);
2867: assert(context.vat_contents);
2868: /* XXX could also report error */
2869: }
2870:
2871: oldvat_tail = (struct udf_oldvat_tail *) (context.vat_contents +
2872: context.vat_size);
2873:
2874: udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
2875: udf_add_udf_regid(&oldvat_tail->id);
2876: oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2877:
2878: context.vat_size += sizeof(struct udf_oldvat_tail);
2879:
2880: return 0;
2881: }
2882:
2883:
2884: int
2885: udf_create_VAT(union dscrptr **vat_dscr, struct long_ad *vatdata_loc)
2886: {
2887: struct impl_extattr_entry *implext;
2888: struct vatlvext_extattr_entry *vatlvext;
2889: struct long_ad *allocpos;
2890: uint8_t *bpos, *extattr;
2891: uint32_t ea_len, inf_len, vat_len, blks;
2892: int filetype;
2893: int error;
2894:
2895: assert((layout.rootdir < 2) && (layout.fsd < 2));
2896:
2897: if (context.dscrver == 2) {
2898: struct file_entry *fe;
2899:
2900: /* old style VAT */
2901: filetype = UDF_ICB_FILETYPE_UNKNOWN;
2902: error = udf_create_new_fe(&fe, filetype, NULL);
2903: if (error)
2904: return error;
2905:
2906: /* append VAT LVExtension attribute */
2907: ea_len = sizeof(struct impl_extattr_entry) - 2 + 4 +
2908: sizeof(struct vatlvext_extattr_entry);
2909:
2910: extattr = calloc(1, ea_len);
2911:
2912: implext = (struct impl_extattr_entry *) extattr;
2913: implext->hdr.type = udf_rw32(2048); /* [4/48.10.8] */
2914: implext->hdr.subtype = 1; /* [4/48.10.8.2] */
2915: implext->hdr.a_l = udf_rw32(ea_len); /* VAT LVext EA size */
2916: /* use 4 bytes of imp use for UDF checksum [UDF 3.3.4.5] */
2917: implext->iu_l = udf_rw32(4);
2918: udf_set_regid(&implext->imp_id, "*UDF VAT LVExtension");
2919: udf_add_udf_regid(&implext->imp_id);
2920:
2921: /* VAT LVExtension data follows UDF IU space */
2922: bpos = ((uint8_t *) implext->data) + 4;
2923: vatlvext = (struct vatlvext_extattr_entry *) bpos;
2924:
2925: vatlvext->unique_id_chk = udf_rw64(fe->unique_id);
2926: vatlvext->num_files = udf_rw32(context.num_files);
2927: vatlvext->num_directories = udf_rw32(context.num_directories);
2928: memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id,128);
2929:
2930: udf_extattr_insert_internal((union dscrptr *) fe,
2931: (struct extattr_entry *) extattr);
2932:
2933: free(extattr);
2934:
2935: fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2936:
2937: allocpos = (struct long_ad *) (fe->data + udf_rw32(fe->l_ea));
2938: *allocpos = *vatdata_loc;
2939:
2940: /* set length */
2941: inf_len = context.vat_size;
2942: fe->inf_len = udf_rw64(inf_len);
2943: allocpos->len = udf_rw32(inf_len);
2944: fe->l_ad = udf_rw32(sizeof(struct long_ad));
2945: blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2946: context.sector_size;
2947: fe->logblks_rec = udf_rw32(blks);
2948:
2949: /* update vat descriptor's CRC length */
2950: vat_len = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
2951: vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea);
2952: fe->tag.desc_crc_len = udf_rw16(vat_len);
2953:
2954: *vat_dscr = (union dscrptr *) fe;
2955: } else {
2956: /* the choice is between an EFE or an FE as VAT */
2957: #if 1
2958: struct extfile_entry *efe;
2959:
2960: /* new style VAT on FE */
2961: filetype = UDF_ICB_FILETYPE_VAT;
2962: error = udf_create_new_efe(&efe, filetype, NULL);
2963: if (error)
2964: return error;
2965:
2966: efe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2967:
2968: allocpos = (struct long_ad *) efe->data;
2969: *allocpos = *vatdata_loc;
2970:
2971: /* set length */
2972: inf_len = context.vat_size;
2973: efe->inf_len = udf_rw64(inf_len);
2974: allocpos->len = udf_rw32(inf_len);
2975: efe->obj_size = udf_rw64(inf_len);
2976: efe->l_ad = udf_rw32(sizeof(struct long_ad));
2977: blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2978: context.sector_size;
2979: efe->logblks_rec = udf_rw32(blks);
2980:
2981: vat_len = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH;
2982: vat_len += udf_rw32(efe->l_ad);
2983: efe->tag.desc_crc_len = udf_rw16(vat_len);
2984:
2985: *vat_dscr = (union dscrptr *) efe;
2986: #else
2987: struct file_entry *fe;
2988: uint32_t l_ea;
2989:
2990: /* new style VAT on EFE */
2991: filetype = UDF_ICB_FILETYPE_VAT;
2992: error = udf_create_new_fe(&fe, filetype, NULL);
2993: if (error)
2994: return error;
2995:
2996: fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2997:
2998: l_ea = udf_rw32(fe->l_ea);
2999: allocpos = (struct long_ad *) (fe->data + l_ea);
3000: *allocpos = *vatdata_loc;
3001:
3002: /* set length */
3003: inf_len = context.vat_size;
3004: fe->inf_len = udf_rw64(inf_len);
3005: allocpos->len = udf_rw32(inf_len);
3006: fe->l_ad = udf_rw32(sizeof(struct long_ad));
3007: blks = UDF_ROUNDUP(inf_len, context.sector_size) /
3008: context.sector_size;
3009: fe->logblks_rec = udf_rw32(blks);
3010:
3011: vat_len = sizeof(struct file_entry)-1 - UDF_DESC_TAG_LENGTH;
3012: vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea);
3013: fe->tag.desc_crc_len = udf_rw16(vat_len);
3014:
3015: *vat_dscr = (union dscrptr *) fe;
3016: #endif
3017: }
1.2 riastrad 3018:
1.1 reinoud 3019: return 0;
3020: }
3021:
3022:
3023: int
3024: udf_writeout_VAT(void)
3025: {
3026: union dscrptr *vat_dscr;
3027: struct long_ad vatdata;
3028: uint32_t loc, phys, ext, sects;
3029: int rel_block, rest_block, error;
3030:
3031: vat_dscr = NULL;
3032: /* update lvint to reflect the newest values (no writeout) */
3033: udf_update_lvintd(UDF_INTEGRITY_CLOSED);
3034:
3035: error = udf_append_VAT_file();
3036: if (error)
3037: return error;
3038:
3039: /* write out VAT data */
3040: sects = UDF_ROUNDUP(context.vat_size, context.sector_size) /
3041: context.sector_size;
3042: layout.vat = context.alloc_pos[context.data_part];
3043: udf_data_alloc(sects, &vatdata);
3044: //printf("layout.vat %d\n", layout.vat + udf_rw32(context.partitions[context.data_part]->start_loc));
3045:
3046: loc = udf_rw32(vatdata.loc.lb_num);
3047: udf_translate_vtop(loc, context.data_part, &phys, &ext);
3048:
3049: error = udf_write_phys(context.vat_contents, phys, sects);
3050: if (error)
3051: return error;
3052: loc += sects;
3053:
3054: /* create new VAT descriptor */
3055: error = udf_create_VAT(&vat_dscr, &vatdata);
3056: if (error)
3057: return error;
3058:
3059: //printf("VAT data at %d\n", vatdata.loc.lb_num);
3060: //printf("VAT itself at %d\n", loc + udf_rw32(context.partitions[context.data_part]->start_loc));
3061:
3062: /* at least one */
3063: error = udf_write_dscr_virt(vat_dscr, loc, context.data_part, 1);
3064: loc++;
3065:
3066: error = udf_translate_vtop(loc, context.data_part, &phys, &ext);
3067: assert(!error);
3068:
3069: rel_block = phys - (UDF_ROUNDDOWN(phys, layout.blockingnr) + wrtrack_skew);
3070: rest_block = layout.blockingnr - rel_block;
3071:
3072: for (int i = 0; i < rest_block; i++) {
3073: error = udf_write_dscr_virt(vat_dscr, loc, context.data_part, 1);
3074: loc++;
3075: }
3076: free(vat_dscr);
3077:
3078: return error;
3079: }
3080:
3081:
3082: /* --------------------------------------------------------------------- */
3083: /*
3084: * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main
3085: * code in sys/fs/udf/
3086: */
3087:
3088: void
3089: udf_dump_discinfo(struct mmc_discinfo *di)
3090: {
3091: #ifdef DEBUG
3092: char bits[128];
3093:
3094: printf("Device/media info :\n");
3095: printf("\tMMC profile 0x%02x\n", di->mmc_profile);
3096: printf("\tderived class %d\n", di->mmc_class);
3097: printf("\tsector size %d\n", di->sector_size);
3098: printf("\tdisc state %d\n", di->disc_state);
3099: printf("\tlast ses state %d\n", di->last_session_state);
3100: printf("\tbg format state %d\n", di->bg_format_state);
3101: printf("\tfrst track %d\n", di->first_track);
3102: printf("\tfst on last ses %d\n", di->first_track_last_session);
3103: printf("\tlst on last ses %d\n", di->last_track_last_session);
3104: printf("\tlink block penalty %d\n", di->link_block_penalty);
3105: snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, (uint64_t) di->disc_flags);
3106: printf("\tdisc flags %s\n", bits);
3107: printf("\tdisc id %x\n", di->disc_id);
3108: printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode);
3109:
3110: printf("\tnum sessions %d\n", di->num_sessions);
3111: printf("\tnum tracks %d\n", di->num_tracks);
3112:
3113: snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur);
3114: printf("\tcapabilities cur %s\n", bits);
3115: snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap);
3116: printf("\tcapabilities cap %s\n", bits);
3117: printf("\n");
3118: printf("\tlast_possible_lba %d\n", di->last_possible_lba);
3119: printf("\n");
3120: #endif
3121: }
3122:
3123:
3124: void
3125: udf_synchronise_caches(void)
3126: {
3127: #if !HAVE_NBTOOL_CONFIG_H
3128: struct mmc_op mmc_op;
3129:
3130: bzero(&mmc_op, sizeof(struct mmc_op));
3131: mmc_op.operation = MMC_OP_SYNCHRONISECACHE;
3132:
3133: /* this device might not know this ioct, so just be ignorant */
3134: (void) ioctl(dev_fd, MMCOP, &mmc_op);
3135: #endif
3136: }
3137:
3138:
3139: /*
3140: * General Idea:
3141: *
3142: * stat the dev_fd
3143: *
3144: * If a S_ISREG(), we emulate using the emul_* settings.
3145: *
3146: * If its a device :
3147: * try the MMCGETDISCINFO ioctl() and be done.
3148: *
3149: * If that fails, its a regular disc and set the type to disc media.
3150: *
3151: */
3152:
3153:
3154: int
3155: udf_update_discinfo(void)
3156: {
3157: off_t size, last_sector, secsize;
3158: int error;
3159:
3160: memset(&mmc_discinfo, 0, sizeof(struct mmc_discinfo));
3161:
3162: #if !HAVE_NBTOOL_CONFIG_H
3163: /* check if we're on a MMC capable device, i.e. CD/DVD */
3164: error = ioctl(dev_fd, MMCGETDISCINFO, &mmc_discinfo);
3165: if (error == 0) {
3166: if ((emul_mmc_profile != -1) &&
3167: (emul_mmc_profile != mmc_discinfo.mmc_profile)) {
3168: errno = EINVAL;
3169: perror("media and specified disc type mismatch");
3170: return errno;
3171: }
3172: emul_size = 0;
3173: return 0;
3174: }
3175: #endif
3176:
3177: if (S_ISREG(dev_fd_stat.st_mode)) {
3178: /* file support; we pick the minimum sector size allowed */
3179: if (emul_mmc_profile < 0)
3180: emul_mmc_profile = 0x01;
3181: if (emul_size == 0)
3182: emul_size = dev_fd_stat.st_size;
3183: size = emul_size;
3184: secsize = emul_sectorsize;
3185: last_sector = (size / secsize) - 1;
3186: if (ftruncate(dev_fd, size)) {
3187: perror("can't resize file");
3188: return EXIT_FAILURE;
3189: }
3190: } else {
3191: #if !HAVE_NBTOOL_CONFIG_H
3192: struct disk_geom geo;
3193: struct dkwedge_info dkw;
3194:
3195: /* sanity */
3196: if (emul_mmc_profile <= 0)
3197: emul_mmc_profile = 0x01;
3198: if (emul_mmc_profile != 0x01) {
3199: warnx("format incompatible with disc partition");
1.2 riastrad 3200: return EXIT_FAILURE;
1.1 reinoud 3201: }
3202:
3203: /* get our disc info */
3204: error = getdiskinfo(dev_name, dev_fd, NULL, &geo, &dkw);
3205: if (error) {
3206: warn("retrieving disc info failed");
3207: return EXIT_FAILURE;
3208: }
3209: secsize = emul_sectorsize;
3210: last_sector = (dkw.dkw_size - 1) * geo.dg_secsize / secsize;
3211: #else
3212: warnx("disk partitions only usable outside tools");
3213: return EIO;
3214: #endif
3215: }
3216:
3217: /* commons */
3218: mmc_discinfo.mmc_profile = emul_mmc_profile;
3219: mmc_discinfo.disc_state = MMC_STATE_CLOSED;
3220: mmc_discinfo.last_session_state = MMC_STATE_CLOSED;
3221: mmc_discinfo.bg_format_state = MMC_BGFSTATE_COMPLETED;
3222: mmc_discinfo.link_block_penalty = 0;
3223:
3224: mmc_discinfo.disc_flags = MMC_DFLAGS_UNRESTRICTED;
3225:
3226: mmc_discinfo.last_possible_lba = last_sector;
3227: mmc_discinfo.sector_size = secsize;
3228:
3229: mmc_discinfo.num_sessions = 1;
3230: mmc_discinfo.num_tracks = 1;
3231:
3232: mmc_discinfo.first_track = 1;
3233: mmc_discinfo.first_track_last_session = mmc_discinfo.last_track_last_session = 1;
3234:
3235: mmc_discinfo.mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_ZEROLINKBLK;
3236: switch (emul_mmc_profile) {
3237: case 0x00: /* unknown, treat as CDROM */
3238: case 0x08: /* CDROM */
3239: case 0x10: /* DVDROM */
3240: case 0x40: /* BDROM */
3241: /* FALLTHROUGH */
3242: case 0x01: /* disc */
3243: /* set up a disc info profile for partitions/files */
3244: mmc_discinfo.mmc_class = MMC_CLASS_DISC;
3245: mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE;
3246: break;
3247: case 0x09: /* CD-R */
3248: mmc_discinfo.mmc_class = MMC_CLASS_CD;
3249: mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL;
3250: mmc_discinfo.disc_state = MMC_STATE_EMPTY;
3251: break;
3252: case 0x0a: /* CD-RW + CD-MRW (regretably) */
3253: mmc_discinfo.mmc_class = MMC_CLASS_CD;
3254: mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE;
3255: break;
3256: case 0x13: /* DVD-RW */
3257: case 0x1a: /* DVD+RW */
3258: mmc_discinfo.mmc_class = MMC_CLASS_DVD;
3259: mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE;
3260: break;
3261: case 0x11: /* DVD-R */
3262: case 0x14: /* DVD-RW sequential */
3263: case 0x1b: /* DVD+R */
3264: case 0x2b: /* DVD+R DL */
3265: case 0x51: /* HD DVD-R */
3266: mmc_discinfo.mmc_class = MMC_CLASS_DVD;
3267: mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL;
3268: mmc_discinfo.disc_state = MMC_STATE_EMPTY;
3269: break;
3270: case 0x41: /* BD-R */
3271: mmc_discinfo.mmc_class = MMC_CLASS_BD;
3272: mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL | MMC_CAP_HW_DEFECTFREE;
3273: mmc_discinfo.disc_state = MMC_STATE_EMPTY;
3274: break;
3275: case 0x43: /* BD-RE */
3276: mmc_discinfo.mmc_class = MMC_CLASS_BD;
3277: mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE;
3278: break;
3279: default:
3280: errno = EINVAL;
3281: perror("unknown or unimplemented device type");
3282: return errno;
3283: }
3284: mmc_discinfo.mmc_cap = mmc_discinfo.mmc_cur;
3285:
3286: return 0;
3287: }
3288:
3289:
3290: int
3291: udf_update_trackinfo(struct mmc_trackinfo *ti)
3292: {
3293: int error, class;
3294:
3295: #if !HAVE_NBTOOL_CONFIG_H
3296: class = mmc_discinfo.mmc_class;
3297: if (class != MMC_CLASS_DISC) {
3298: /* tracknr specified in struct ti */
3299: error = ioctl(dev_fd, MMCGETTRACKINFO, ti);
3300: if (!error)
3301: return 0;
3302: }
3303: #endif
3304:
3305: /* discs partition support */
3306: if (ti->tracknr != 1)
3307: return EIO;
3308:
3309: /* create fake ti (TODO check for resized vnds) */
3310: ti->sessionnr = 1;
3311:
3312: ti->track_mode = 0; /* XXX */
3313: ti->data_mode = 0; /* XXX */
3314: ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
3315:
3316: ti->track_start = 0;
3317: ti->packet_size = emul_packetsize;
3318:
3319: /* TODO support for resizable vnd */
3320: ti->track_size = mmc_discinfo.last_possible_lba;
3321: ti->next_writable = mmc_discinfo.last_possible_lba + 1; //0;
3322: ti->last_recorded = ti->next_writable;
3323: ti->free_blocks = 0;
3324:
3325: return 0;
3326: }
3327:
3328:
3329: int
3330: udf_opendisc(const char *device, int open_flags)
3331: {
3332: /* set global variable to the passed name */
3333: dev_name = strdup(device);
3334:
3335: /* open device */
3336: if (open_flags & O_RDONLY) {
3337: dev_fd_rdonly = 1;
3338: if ((dev_fd = open(dev_name, O_RDONLY, 0)) == -1) {
3339: warn("device/image not found");
3340: return EXIT_FAILURE;
3341: }
3342: } else {
3343: dev_fd_rdonly = 0;
3344: if ((dev_fd = open(dev_name, O_RDWR, 0)) == -1) {
3345: /* check if we need to create a file */
3346: dev_fd = open(dev_name, O_RDONLY, 0);
3347: if (dev_fd > 0) {
3348: warn("device is there but can't be opened for "
3349: "read/write");
3350: return EXIT_FAILURE;
3351: }
3352: if ((open_flags & O_CREAT) == 0) {
3353: warnx("device/image not found");
3354: return EXIT_FAILURE;
3355: }
3356: /* need to create a file */
3357: dev_fd = open(dev_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
3358: if (dev_fd == -1) {
3359: warn("can't create image file");
3360: return EXIT_FAILURE;
3361: }
3362: }
3363: }
3364:
3365: /* stat the device/image */
3366: if (fstat(dev_fd, &dev_fd_stat) != 0) {
3367: warn("can't stat the disc image");
3368: return EXIT_FAILURE;
3369: }
3370:
3371: /* sanity check and resizing of file */
3372: if (S_ISREG(dev_fd_stat.st_mode)) {
3373: if (emul_size == 0)
3374: emul_size = dev_fd_stat.st_size;
3375: /* sanitise arguments */
3376: emul_sectorsize &= ~511;
3377: if (emul_size & (emul_sectorsize-1)) {
3378: warnx("size of file is not a multiple of sector size, "
3379: "shrinking");
3380: emul_size -= emul_size & (emul_sectorsize-1);
3381: }
3382:
3383: /* grow the image */
3384: if (ftruncate(dev_fd, emul_size)) {
3385: warn("can't resize file");
3386: return EXIT_FAILURE;
3387: }
3388: /* restat the device/image */
3389: if (fstat(dev_fd, &dev_fd_stat) != 0) {
3390: warn("can't re-stat the disc image");
3391: return EXIT_FAILURE;
3392: }
3393: } else {
3394: if (!S_ISCHR(dev_fd_stat.st_mode)) {
3395: warnx("%s is not a raw device", dev_name);
3396: return EXIT_FAILURE;
3397: }
3398: }
3399:
3400: /* just in case something went wrong, synchronise the drive's cache */
3401: udf_synchronise_caches();
3402: if (udf_update_discinfo()) {
3403: warnx("update discinfo failed");
3404: return EXIT_FAILURE;
3405: }
3406:
3407: /* honour minimum sector size of the device */
3408: if (mmc_discinfo.sector_size > context.sector_size)
3409: context.sector_size = mmc_discinfo.sector_size;
3410:
3411: if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL)
3412: udf_init_writequeue(UDF_WRITE_SEQUENTIAL);
3413: else {
3414: udf_init_writequeue(UDF_WRITE_PACKET);
3415: }
3416: return 0;
3417: }
3418:
3419:
3420: void
3421: udf_closedisc(void)
3422: {
3423: if (!write_queue_suspend) {
3424: udf_writeout_writequeue(true);
3425: assert(write_queuelen == 0);
3426: }
3427:
3428: udf_synchronise_caches();
3429: if (dev_fd)
3430: close(dev_fd);
3431: }
3432:
3433: /* --------------------------------------------------------------------- */
3434:
3435: static int
3436: udf_setup_writeparams(void)
3437: {
3438: #if !HAVE_NBTOOL_CONFIG_H
3439: struct mmc_writeparams mmc_writeparams;
3440: int error;
3441:
3442: if (mmc_discinfo.mmc_class == MMC_CLASS_DISC)
3443: return 0;
3444:
3445: if (S_ISREG(dev_fd_stat.st_mode))
3446: return 0;
3447:
3448: /*
3449: * only CD burning normally needs setting up, but other disc types
3450: * might need other settings to be made. The MMC framework will set up
3451: * the necessary recording parameters according to the disc
3452: * characteristics read in. Modifications can be made in the discinfo
3453: * structure passed to change the nature of the disc.
3454: */
3455: memset(&mmc_writeparams, 0, sizeof(struct mmc_writeparams));
3456: mmc_writeparams.mmc_class = mmc_discinfo.mmc_class;
3457: mmc_writeparams.mmc_cur = mmc_discinfo.mmc_cur;
3458:
3459: /*
3460: * UDF dictates first track to determine track mode for the whole
3461: * disc. [UDF 1.50/6.10.1.1, UDF 1.50/6.10.2.1]
3462: * To prevent problems with a `reserved' track in front we start with
3463: * the 2nd track and if that is not valid, go for the 1st.
3464: */
3465: mmc_writeparams.tracknr = 2;
3466: mmc_writeparams.data_mode = MMC_DATAMODE_DEFAULT; /* XA disc */
3467: mmc_writeparams.track_mode = MMC_TRACKMODE_DEFAULT; /* data */
3468:
3469: error = ioctl(dev_fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
3470: if (error) {
3471: mmc_writeparams.tracknr = 1;
3472: error = ioctl(dev_fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
3473: }
3474: return error;
3475: #else
3476: return 0;
3477: #endif
3478: }
3479:
3480:
3481: /*
3482: * On sequential recordable media, we might need to close the last session to
3483: * be able to write new anchors/new fs.
3484: */
3485: static int
3486: udf_open_new_session(void)
3487: {
3488: #if !HAVE_NBTOOL_CONFIG_H
3489: struct mmc_trackinfo ti;
3490: struct mmc_op op;
3491: int tracknr, error;
3492:
3493: /* if the drive is not sequential, we're done */
3494: if ((mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) == 0)
3495: return 0;
3496:
3497: /* close the last session if its still open */
3498: if (mmc_discinfo.last_session_state == MMC_STATE_INCOMPLETE) {
3499: /*
3500: * Leave the disc alone if force format is not set, it will
3501: * error out later
3502: */
3503: if (!context.create_new_session)
3504: return 0;
3505:
3506: // printf("Closing last open session if present\n");
3507: /* close all associated tracks */
3508: tracknr = mmc_discinfo.first_track_last_session;
3509: while (tracknr <= mmc_discinfo.last_track_last_session) {
3510: ti.tracknr = tracknr;
3511: error = udf_update_trackinfo(&ti);
3512: if (error)
3513: return error;
3514: // printf("\tClosing open track %d\n", tracknr);
3515: memset(&op, 0, sizeof(op));
3516: op.operation = MMC_OP_CLOSETRACK;
3517: op.mmc_profile = mmc_discinfo.mmc_profile;
3518: op.tracknr = tracknr;
3519: error = ioctl(dev_fd, MMCOP, &op);
3520: if (error)
3521: return error;
3522: tracknr ++;
3523: }
3524: // printf("Closing session\n");
3525: memset(&op, 0, sizeof(op));
3526: op.operation = MMC_OP_CLOSESESSION;
3527: op.mmc_profile = mmc_discinfo.mmc_profile;
3528: op.sessionnr = mmc_discinfo.num_sessions;
3529: error = ioctl(dev_fd, MMCOP, &op);
3530: if (error)
3531: return error;
3532:
3533: /* update discinfo since it changed by the operations */
3534: error = udf_update_discinfo();
3535: if (error)
3536: return error;
3537: }
3538: #endif
3539: return 0;
3540: }
3541:
3542:
3543: /* bit paranoid but tracks may need repair before they can be written to */
3544: static void
3545: udf_repair_tracks(void)
3546: {
3547: #if !HAVE_NBTOOL_CONFIG_H
3548: struct mmc_trackinfo ti;
3549: struct mmc_op op;
3550: int tracknr, error;
3551:
3552: tracknr = mmc_discinfo.first_track_last_session;
3553: while (tracknr <= mmc_discinfo.last_track_last_session) {
3554: ti.tracknr = tracknr;
3555: error = udf_update_trackinfo(&ti);
3556: if (error) {
3557: warnx("error updating track information for track %d",
3558: tracknr);
3559: /* resume */
3560: tracknr++;
3561: continue;
3562: }
3563:
3564: if (ti.flags & MMC_TRACKINFO_DAMAGED) {
3565: /*
3566: * Need to repair last track before anything can be done.
3567: * this is an optional command, so ignore its error but report
3568: * warning.
3569: */
3570: memset(&op, 0, sizeof(op));
3571: op.operation = MMC_OP_REPAIRTRACK;
3572: op.mmc_profile = mmc_discinfo.mmc_profile;
3573: op.tracknr = ti.tracknr;
3574: error = ioctl(dev_fd, MMCOP, &op);
3575:
3576: if (error)
3577: warnx("drive notifies it can't explicitly repair "
3578: "damaged track, but it might autorepair\n");
3579: }
3580: tracknr++;
3581: }
3582: /* tracks (if any) might not be damaged now, operations are ok now */
3583: #endif
3584: }
3585:
3586:
3587: int
3588: udf_prepare_disc(void)
3589: {
3590: #if !HAVE_NBTOOL_CONFIG_H
3591: int error;
3592:
3593: /* setup write parameters from discinfo */
3594: error = udf_setup_writeparams();
3595: if (error)
3596: return error;
3597:
3598: udf_repair_tracks();
3599:
3600: /* open new session if needed */
3601: return udf_open_new_session();
3602: #endif
3603: return 0;
3604: }
3605:
3606:
3607: /* --------------------------------------------------------------------- */
3608:
3609: /*
3610: * write queue implementation
3611: */
3612:
3613: void
3614: udf_suspend_writing(void)
3615: {
3616: write_queue_suspend = 1;
3617: }
3618:
3619:
3620: void
3621: udf_allow_writing(void)
3622: {
3623: write_queue_suspend = 0;
3624: }
3625:
3626:
3627: static void
3628: udf_init_writequeue(int write_strategy)
3629: {
3630: context.write_strategy = write_strategy;
3631: write_queue_suspend = 0;
3632:
3633: /* setup sector writeout queue's */
3634: TAILQ_INIT(&write_queue);
3635: write_queuelen = 0;
3636: }
3637:
3638:
3639: int
3640: udf_write_sector(void *sector, uint64_t location)
3641: {
3642: struct wrpacket *packet, *found_packet;
3643: uint64_t rel_loc;
3644: uint64_t blockingnr = layout.blockingnr;
3645: int error;
3646:
3647: assert(!dev_fd_rdonly);
3648: assert(blockingnr >= 1);
3649: assert(blockingnr <= 64);
3650:
3651: /*
3652: * We have a write strategy but in practice packet writing is
3653: * preferable for all media types.
3654: */
3655:
3656: again:
3657: /* search location */
3658: found_packet = NULL;
3659: TAILQ_FOREACH_REVERSE(packet, &write_queue, wrpacket_list, next) {
3660: if (packet->start_sectornr <= location) {
3661: found_packet = packet;
3662: break;
3663: }
3664: }
3665:
3666: /* are we in a current packet? */
3667: if (found_packet) {
3668: uint64_t base = found_packet->start_sectornr;
3669: if ((location >= base) && (location -base < blockingnr)) {
3670: /* fill in existing packet */
3671: rel_loc = location - base;
3672: memcpy(found_packet->packet_data +
3673: rel_loc * context.sector_size,
3674: sector, context.sector_size);
3675: found_packet->present |= ((uint64_t) 1 << rel_loc);
3676: return 0;
3677: }
3678: }
3679:
3680: if ((write_queuelen > UDF_MAX_QUEUELEN) && !write_queue_suspend) {
3681: /* we purge the queue and reset found_packet! */
3682: error = udf_writeout_writequeue(false);
3683: if (error)
3684: return error;
3685: goto again;
3686: }
3687:
3688: /* create new packet */
3689: packet = calloc(1, sizeof(struct wrpacket));
3690: if (packet == NULL)
3691: return errno;
3692: packet->packet_data = calloc(1, context.sector_size * blockingnr);
3693: if (packet->packet_data == NULL) {
3694: free(packet);
3695: return errno;
3696: }
3697: packet->start_sectornr =
3698: UDF_ROUNDDOWN(location, blockingnr) + wrtrack_skew;
3699: rel_loc = location - packet->start_sectornr;
3700:
3701: memcpy(packet->packet_data +
3702: rel_loc * context.sector_size,
3703: sector, context.sector_size);
3704: packet->present = ((uint64_t) 1 << rel_loc);
3705:
3706: if (found_packet) {
3707: TAILQ_INSERT_AFTER(&write_queue, found_packet, packet, next);
3708: } else {
3709: TAILQ_INSERT_HEAD(&write_queue, packet, next);
3710: }
3711: write_queuelen++;
3712:
3713: return 0;
3714: }
3715:
3716:
3717: int
3718: udf_read_sector(void *sector, uint64_t location)
3719: {
3720: struct wrpacket *packet, *found_packet;
3721: ssize_t ret;
3722: uint64_t rpos, rel_loc;
3723: uint64_t blockingnr = layout.blockingnr;
3724:
3725: rpos = (uint64_t) location * context.sector_size;
3726:
3727: /* search location */
3728: found_packet = NULL;
3729: TAILQ_FOREACH_REVERSE(packet, &write_queue, wrpacket_list, next) {
3730: if (packet->start_sectornr <= location) {
3731: found_packet = packet;
3732: break;
3733: }
3734: }
3735:
3736: /* are we in a current packet? */
3737: if (found_packet) {
3738: uint64_t base = found_packet->start_sectornr;
3739: if ((location >= base) && (location -base < blockingnr)) {
3740: /* fill in existing packet */
3741: rel_loc = location - base;
3742: if (found_packet->present & ((uint64_t) 1 << rel_loc)) {
3743: memcpy(sector, found_packet->packet_data +
3744: rel_loc * context.sector_size,
3745: context.sector_size);
3746: } else {
3747: ret = pread(dev_fd, sector, context.sector_size, rpos);
3748: if (ret == -1)
3749: return errno;
3750: if (ret < (int) context.sector_size)
3751: return EIO;
3752: memcpy(found_packet->packet_data +
3753: rel_loc * context.sector_size,
3754: sector, context.sector_size);
3755: found_packet->present |= ((uint64_t) 1 << rel_loc);
3756: return 0;
3757: }
3758: }
3759: }
3760: /* don't create a packet just for we read something */
3761: ret = pread(dev_fd, sector, context.sector_size, rpos);
3762: if (ret == -1)
3763: return errno;
3764: if (ret < (int) context.sector_size)
3765: return EIO;
3766: return 0;
3767: }
3768:
3769:
3770: /*
3771: * Now all write requests are queued in the TAILQ, write them out to the
3772: * disc/file image. Special care needs to be taken for devices that are only
3773: * strict overwritable i.e. only in packet size chunks
3774: *
3775: * XXX support for growing vnd?
3776: */
3777:
3778: static int
3779: udf_writeout_writequeue(bool complete)
3780: {
3781: struct wrpacket *packet, *next_packet;
3782: int blockingnr = layout.blockingnr;
3783: int linesize, offset, ret;
3784: uint8_t *linebuf;
3785: uint64_t present, all_present = -1;
3786: uint64_t rpos, wpos;
3787: static int t = 0;
3788:
3789: if (write_queuelen == 0)
3790: return 0;
3791:
3792: if (blockingnr < 64)
3793: all_present = ((uint64_t) 1 << blockingnr) -1;
3794: linesize = blockingnr * context.sector_size;
3795: linebuf = calloc(1, linesize);
3796: assert(linebuf);
3797:
3798: /* fill in blanks if needed */
3799: if (complete && (context.write_strategy != UDF_WRITE_SEQUENTIAL)) {
3800: TAILQ_FOREACH(packet, &write_queue, next) {
3801: present = packet->present;
3802: if (present != all_present) {
3803: printf("%c", "\\|/-"[t++ % 4]); fflush(stdout);fflush(stderr);
3804: //printf("%16lu : readin %08lx\n", packet->start_sectornr, packet->present ^ all_present);
3805: rpos = (uint64_t) packet->start_sectornr * context.sector_size;
3806: ret = pread(dev_fd, linebuf, linesize, rpos);
3807: if (ret == -1) {
3808: printf("\b");
3809: warn("error reading in blanks, "
3810: "could indicate bad disc");
3811: printf(" ");
3812: }
3813: for (int i = 0; i < blockingnr; i++) {
3814: //printf("present %08lx, testing bit %08lx, value %08lx\n", present, ((uint64_t) 1 << i), (present & ((uint64_t) 1 << i)));
3815: if ((present & ((uint64_t) 1 << i)) > 0)
3816: continue;
3817: //printf("NOT PRESENT\n");
3818: offset = i * context.sector_size;
3819: memcpy(packet->packet_data + offset,
3820: linebuf + offset,
3821: context.sector_size);
3822: packet->present |= ((uint64_t) 1<<i);
3823: }
3824: printf("\b");
3825: }
3826: assert(packet->present == all_present);
3827: }
3828: }
3829:
3830: /* writeout */
3831: TAILQ_FOREACH(packet, &write_queue, next) {
3832: if (complete || (packet->present == all_present)) {
3833: printf("%c", "\\|/-"[t++ % 4]); fflush(stdout);fflush(stderr);
3834: //printf("write %lu + %d\n", packet->start_sectornr, linesize / context.sector_size);
3835: wpos = (uint64_t) packet->start_sectornr * context.sector_size;
3836: ret = pwrite(dev_fd, packet->packet_data, linesize, wpos);
3837: printf("\b");
3838: if (ret == -1)
3839: warn("error writing packet, "
3840: "could indicate bad disc");
3841: }
3842: }
3843:
3844: /* removing completed packets */
3845: TAILQ_FOREACH_SAFE(packet, &write_queue, next, next_packet) {
3846: if (complete || (packet->present == all_present)) {
3847: TAILQ_REMOVE(&write_queue, packet, next);
3848: free(packet->packet_data);
3849: free(packet);
3850: write_queuelen--;
3851: }
3852: }
3853: if (complete) {
3854: assert(TAILQ_EMPTY(&write_queue));
3855: write_queuelen = 0;
3856: }
3857:
3858: free(linebuf);
3859: return 0;
3860: }
3861:
3862:
3863: /* --------------------------------------------------------------------- */
3864:
3865: /* simplified version of kernel routine */
3866: int
3867: udf_translate_vtop(uint32_t lb_num, uint16_t vpart,
3868: uint32_t *lb_numres, uint32_t *extres)
3869: {
3870: struct part_desc *pdesc;
3871: struct spare_map_entry *sme;
3872: struct short_ad *short_ad;
3873: struct extfile_entry *efe;
3874: uint32_t ext, len, lb_rel, lb_packet, vat_off;
3875: uint32_t start_lb, lb_offset, end_lb_offset;
3876: uint32_t udf_rw32_lbmap;
3877: uint32_t flags;
3878: uint8_t *vat_pos, *data_pos;
3879: int dscr_size, l_ea, l_ad, icbflags, addr_type;
3880: int rel, part;
3881:
3882: if (vpart > UDF_VTOP_RAWPART)
3883: return EINVAL;
3884:
3885: ext = INT_MAX;
3886: translate_again:
3887: part = context.vtop[vpart];
3888: pdesc = context.partitions[part];
3889:
3890: switch (context.vtop_tp[vpart]) {
3891: case UDF_VTOP_TYPE_RAW :
3892: /* 1:1 to the end of the device */
3893: *lb_numres = lb_num;
3894: *extres = MIN(ext, INT_MAX);
3895: return 0;
3896: case UDF_VTOP_TYPE_PHYS :
3897: /* transform into its disc logical block */
3898: if (lb_num > udf_rw32(pdesc->part_len))
3899: return EINVAL;
3900: *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
3901:
3902: /* extent from here to the end of the partition */
3903: *extres = MIN(ext, udf_rw32(pdesc->part_len) - lb_num);
3904: if (*extres == 0)
3905: return EINVAL;
3906: return 0;
3907: case UDF_VTOP_TYPE_VIRT :
3908: /* only maps one logical block, lookup in VAT */
3909: if (lb_num * 4 >= context.vat_size)
3910: return EINVAL;
3911: vat_off = context.vat_start + lb_num * 4;
3912: vat_pos = context.vat_contents + vat_off;
3913: udf_rw32_lbmap = *((uint32_t *) vat_pos);
3914:
3915: if (vat_off >= context.vat_size) /* XXX > or >= ? */
3916: return EINVAL;
3917: lb_num = udf_rw32(udf_rw32_lbmap);
3918:
3919: /* transform into its disc logical block */
3920: if (lb_num > udf_rw32(pdesc->part_len))
3921: return EINVAL;
3922: *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
3923:
3924: /* just one logical block */
3925: *extres = 1;
3926: return 0;
3927: case UDF_VTOP_TYPE_SPAREABLE :
3928: /* check if the packet containing the lb_num is remapped */
3929: lb_packet = lb_num / layout.spareable_blockingnr;
3930: lb_rel = lb_num % layout.spareable_blockingnr;
3931:
3932: for (rel = 0; rel < udf_rw16(context.sparing_table->rt_l); rel++) {
3933: sme = &context.sparing_table->entries[rel];
3934: if (lb_packet == udf_rw32(sme->org)) {
3935: /* NOTE maps to absolute disc logical block! */
3936: *lb_numres = udf_rw32(sme->map) + lb_rel;
3937: *extres = layout.spareable_blockingnr - lb_rel;
3938: return 0;
3939: }
3940: }
3941:
3942: /* transform into its disc logical block */
3943: if (lb_num > udf_rw32(pdesc->part_len))
3944: return EINVAL;
3945: *lb_numres = lb_num + udf_rw32(pdesc->start_loc);
3946:
3947: /* rest of block */
3948: *extres = MIN(ext, layout.spareable_blockingnr - lb_rel);
3949: return 0;
3950: case UDF_VTOP_TYPE_META :
3951: /* we have to look into the file's allocation descriptors */
3952:
3953: /* get first overlapping extent */
3954: efe = context.meta_file;
3955: dscr_size = sizeof(struct extfile_entry) - 1;
3956: l_ea = udf_rw32(efe->l_ea);
3957: l_ad = udf_rw32(efe->l_ad);
3958:
3959: icbflags = udf_rw16(efe->icbtag.flags);
3960: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
3961: if (addr_type != UDF_ICB_SHORT_ALLOC) {
3962: warnx("specification violation: metafile not using"
3963: "short allocs");
3964: return EINVAL;
3965: }
3966:
3967: data_pos = (uint8_t *) context.meta_file + dscr_size + l_ea;
3968: short_ad = (struct short_ad *) data_pos;
3969: lb_offset = 0;
3970: while (l_ad > 0) {
3971: len = udf_rw32(short_ad->len);
3972: start_lb = udf_rw32(short_ad->lb_num);
3973: flags = UDF_EXT_FLAGS(len);
3974: len = UDF_EXT_LEN(len);
3975: if (flags == UDF_EXT_REDIRECT) {
3976: warnx("implementation limit: no support for "
3977: "extent redirection in metadata file");
3978: return EINVAL;
3979: }
3980: end_lb_offset = lb_offset + len / context.sector_size;
3981: /* overlap? */
3982: if (end_lb_offset > lb_num)
3983: break;
3984: short_ad++;
3985: lb_offset = end_lb_offset;
3986: l_ad -= sizeof(struct short_ad);
3987: }
3988: if (l_ad <= 0) {
3989: warnx("looking up outside metadata partition!");
3990: return EINVAL;
3991: }
3992: lb_num = start_lb + (lb_num - lb_offset);
3993: vpart = part;
3994: ext = end_lb_offset - lb_num;
3995: /*
3996: * vpart and lb_num are updated, translate again since we
3997: * might be mapped on spareable media
3998: */
3999: goto translate_again;
4000: default:
4001: printf("UDF vtop translation scheme %d unimplemented yet\n",
4002: context.vtop_tp[vpart]);
4003: }
4004:
4005: return EINVAL;
4006: }
4007:
4008: /* --------------------------------------------------------------------- */
4009:
4010: int
4011: udf_read_phys(void *blob, uint32_t location, uint32_t sects)
4012: {
4013: uint32_t phys, cnt;
4014: uint8_t *bpos;
4015: int error;
4016:
4017: for (cnt = 0; cnt < sects; cnt++) {
4018: bpos = (uint8_t *) blob;
4019: bpos += context.sector_size * cnt;
4020:
4021: phys = location + cnt;
4022: error = udf_read_sector(bpos, phys);
4023: if (error)
4024: return error;
4025: }
4026: return 0;
4027: }
4028:
4029:
4030: int
4031: udf_write_phys(void *blob, uint32_t location, uint32_t sects)
4032: {
4033: uint32_t phys, cnt;
4034: uint8_t *bpos;
4035: int error;
4036:
4037: for (cnt = 0; cnt < sects; cnt++) {
4038: bpos = (uint8_t *) blob;
4039: bpos += context.sector_size * cnt;
4040:
4041: phys = location + cnt;
4042: error = udf_write_sector(bpos, phys);
4043: if (error)
4044: return error;
4045: }
4046: return 0;
4047: }
4048:
4049:
4050: int
4051: udf_read_virt(void *blob, uint32_t location, uint16_t vpart,
4052: uint32_t sectors)
4053: {
4054: uint32_t phys, ext;
4055: uint8_t *data;
4056: int error;
4057:
4058: /* determine physical location */
4059: data = (uint8_t *) blob;
4060: while (sectors) {
4061: if (udf_translate_vtop(location, vpart, &phys, &ext)) {
4062: // warnx("internal error: bad translation");
4063: return EINVAL;
4064: }
4065: ext = MIN(sectors, ext);
4066: error = udf_read_phys(data, phys, ext);
4067: if (error)
4068: return error;
4069: location += ext;
4070: data += ext * context.sector_size;
4071: sectors -= ext;
4072: }
4073: return 0;
4074: }
4075:
4076:
4077: int
4078: udf_write_virt(void *blob, uint32_t location, uint16_t vpart,
4079: uint32_t sectors)
4080: {
4081: uint32_t phys, ext, alloc_pos;
4082: uint8_t *data;
4083: int error;
4084:
4085: /* determine physical location */
4086: if (context.vtop_tp[vpart] == UDF_VTOP_TYPE_VIRT) {
4087: assert(sectors == 1);
4088: alloc_pos = context.alloc_pos[context.data_part];
4089: udf_vat_update(location, alloc_pos);
4090: udf_translate_vtop(alloc_pos, context.vtop[vpart], &phys, &ext);
4091: context.alloc_pos[context.data_part]++;
4092: return udf_write_phys(blob, phys, sectors);
4093: }
4094:
4095: data = (uint8_t *) blob;
4096: while (sectors) {
4097: if (udf_translate_vtop(location, vpart, &phys, &ext)) {
4098: warnx("internal error: bad translation");
4099: return EINVAL;
4100: }
4101: ext = MIN(sectors, ext);
4102: error = udf_write_phys(data, phys, ext);
4103: if (error)
4104: return error;
4105: location += ext;
4106: data += ext * context.sector_size;
4107: sectors -= ext;
4108: }
4109: return 0;
4110: }
4111:
4112:
4113: int
4114: udf_read_dscr_phys(uint32_t sector, union dscrptr **dstp)
4115: {
4116: union dscrptr *dst, *new_dst;
4117: uint8_t *pos;
4118: uint32_t sectors, dscrlen, sector_size;
4119: int error;
4120:
4121: sector_size = context.sector_size;
4122:
4123: *dstp = dst = NULL;
4124: dscrlen = sector_size;
4125:
4126: /* read initial piece */
4127: dst = malloc(sector_size);
4128: assert(dst);
4129: error = udf_read_sector(dst, sector);
4130: // if (error)
4131: // warn("read error");
4132:
4133: if (!error) {
4134: /* check if its an empty block */
4135: if (is_zero(dst, sector_size)) {
4136: /* return no error but with no dscrptr */
4137: /* dispose first block */
4138: free(dst);
4139: return 0;
4140: }
4141: /* check if its a valid tag */
4142: error = udf_check_tag(dst);
4143: if (error) {
4144: free(dst);
4145: return 0;
4146: }
4147: /* calculate descriptor size */
4148: dscrlen = udf_tagsize(dst, sector_size);
4149: }
4150:
4151: if (!error && (dscrlen > sector_size)) {
4152: /* read the rest of descriptor */
4153:
4154: new_dst = realloc(dst, dscrlen);
4155: if (new_dst == NULL) {
4156: free(dst);
4157: return ENOMEM;
4158: }
4159: dst = new_dst;
4160:
4161: sectors = dscrlen / sector_size;
4162: pos = (uint8_t *) dst + sector_size;
4163: error = udf_read_phys(pos, sector + 1, sectors-1);
4164: if (error)
4165: warnx("read error");
4166: }
4167: if (!error)
4168: error = udf_check_tag_payload(dst, dscrlen);
4169: if (error && dst) {
4170: free(dst);
4171: dst = NULL;
4172: }
4173: *dstp = dst;
4174:
4175: return error;
4176: }
4177:
4178:
4179: int
4180: udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,
4181: uint32_t sectors)
4182: {
4183: dscr->tag.tag_loc = udf_rw32(location);
4184: (void) udf_validate_tag_and_crc_sums(dscr);
4185:
4186: assert(sectors == udf_tagsize(dscr, context.sector_size) / context.sector_size);
4187: return udf_write_phys(dscr, location, sectors);
4188: }
4189:
4190:
4191: int
4192: udf_read_dscr_virt(uint32_t sector, uint16_t vpart, union dscrptr **dstp)
4193: {
4194: union dscrptr *dst, *new_dst;
4195: uint8_t *pos;
4196: uint32_t sectors, dscrlen, sector_size;
4197: int error;
4198:
4199: sector_size = context.sector_size;
4200:
4201: *dstp = dst = NULL;
4202: dscrlen = sector_size;
4203:
4204: /* read initial piece */
4205: dst = calloc(1, sector_size);
4206: assert(dst);
4207: error = udf_read_virt(dst, sector, vpart, 1);
4208: if (error)
4209: return error;
4210:
4211: if (!error) {
4212: /* check if its a valid tag */
4213: error = udf_check_tag(dst);
4214: if (error) {
4215: /* check if its an empty block */
4216: if (is_zero(dst, sector_size)) {
4217: /* return no error but with no dscrptr */
4218: /* dispose first block */
4219: free(dst);
4220: return 0;
4221: }
4222: }
4223: /* calculate descriptor size */
4224: dscrlen = udf_tagsize(dst, sector_size);
4225: }
4226:
4227: if (!error && (dscrlen > sector_size)) {
4228: /* read the rest of descriptor */
4229:
4230: new_dst = realloc(dst, dscrlen);
4231: if (new_dst == NULL) {
4232: free(dst);
4233: return ENOMEM;
4234: }
4235: dst = new_dst;
4236:
4237: sectors = dscrlen / sector_size;
4238: pos = (uint8_t *) dst + sector_size;
4239: error = udf_read_virt(pos, sector + 1, vpart, sectors-1);
4240: if (error)
4241: warn("read error");
4242: }
4243: if (!error)
4244: error = udf_check_tag_payload(dst, dscrlen);
4245: if (error && dst) {
4246: free(dst);
4247: dst = NULL;
4248: }
4249: *dstp = dst;
4250:
4251: return error;
4252: }
4253:
4254:
4255: int
4256: udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint16_t vpart,
4257: uint32_t sectors)
4258: {
4259: struct file_entry *fe;
4260: struct extfile_entry *efe;
4261: struct extattrhdr_desc *extattrhdr;
4262:
4263: extattrhdr = NULL;
4264: if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
4265: fe = (struct file_entry *) dscr;
4266: if (udf_rw32(fe->l_ea) > 0)
4267: extattrhdr = (struct extattrhdr_desc *) fe->data;
4268: }
4269: if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
4270: efe = (struct extfile_entry *) dscr;
4271: if (udf_rw32(efe->l_ea) > 0)
4272: extattrhdr = (struct extattrhdr_desc *) efe->data;
4273: }
4274: if (extattrhdr) {
4275: extattrhdr->tag.tag_loc = udf_rw32(location);
4276: udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
4277: }
4278:
4279: dscr->tag.tag_loc = udf_rw32(location);
4280: udf_validate_tag_and_crc_sums(dscr);
4281:
4282: assert(sectors >= (udf_tagsize(dscr, context.sector_size) / context.sector_size));
4283: return udf_write_virt(dscr, location, vpart, sectors);
4284: }
4285:
4286:
4287: int
4288: is_zero(void *blob, int size) {
4289: uint8_t *p = blob;
4290: for (int i = 0; i < size; i++, p++)
4291: if (*p)
4292: return 0;
4293: return 1;
4294: }
4295:
4296: /* --------------------------------------------------------------------- */
4297:
4298: static void
4299: udf_partition_alloc(int nblk, int vpart, struct long_ad *pos)
4300: {
4301: memset(pos, 0, sizeof(*pos));
4302: pos->len = udf_rw32(nblk * context.sector_size);
4303: pos->loc.lb_num = udf_rw32(context.alloc_pos[vpart]);
4304: pos->loc.part_num = udf_rw16(vpart);
4305:
4306: udf_mark_allocated(context.alloc_pos[vpart], vpart, nblk);
4307: context.alloc_pos[vpart] += nblk;
4308: }
4309:
4310:
4311: void
4312: udf_metadata_alloc(int nblk, struct long_ad *pos)
4313: {
4314: udf_partition_alloc(nblk, context.metadata_part, pos);
4315: }
4316:
4317:
4318: void
4319: udf_data_alloc(int nblk, struct long_ad *pos)
4320: {
4321: udf_partition_alloc(nblk, context.data_part, pos);
4322: }
4323:
4324:
4325: void
4326: udf_fids_alloc(int nblk, struct long_ad *pos)
4327: {
4328: udf_partition_alloc(nblk, context.fids_part, pos);
4329: }
4330:
4331:
4332: /* --------------------------------------------------------------------- */
4333:
4334: /*
4335: * udf_derive_format derives the format_flags from the disc's mmc_discinfo.
4336: * The resulting flags uniquely define a disc format. Note there are at least
4337: * 7 distinct format types defined in UDF.
4338: */
4339:
4340: #define UDF_VERSION(a) \
4341: (((a) == 0x102) || ((a) == 0x150) || ((a) == 0x200) || \
4342: ((a) == 0x201) || ((a) == 0x250) || ((a) == 0x260))
4343:
4344: int
4345: udf_derive_format(int req_enable, int req_disable)
4346: {
4347: int format_flags;
4348: int media_accesstype;
4349:
4350: /* disc writability, formatted, appendable */
4351: if ((mmc_discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
4352: warnx("can't newfs readonly device");
4353: return EROFS;
4354: }
4355: if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
4356: /* sequentials need sessions appended */
4357: if (mmc_discinfo.disc_state == MMC_STATE_CLOSED) {
4358: warnx("can't append session to a closed disc");
4359: return EROFS;
4360: }
4361: if ((mmc_discinfo.disc_state != MMC_STATE_EMPTY) &&
4362: !context.create_new_session) {
4363: warnx("disc not empty! Use -F to force "
4364: "initialisation");
4365: return EROFS;
4366: }
4367: } else {
4368: /* check if disc (being) formatted or has been started on */
4369: if (mmc_discinfo.disc_state == MMC_STATE_EMPTY) {
4370: warnx("disc is not formatted");
4371: return EROFS;
4372: }
4373: }
4374:
4375: /* determine UDF format */
4376: format_flags = 0;
4377: if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
4378: /* all rewritable media */
4379: format_flags |= FORMAT_REWRITABLE;
4380: if (context.min_udf >= 0x0250) {
4381: /* standard dictates meta as default */
4382: format_flags |= FORMAT_META;
4383: }
4384:
4385: if ((mmc_discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) == 0) {
4386: /* spareables for defect management */
4387: if (context.min_udf >= 0x150)
4388: format_flags |= FORMAT_SPAREABLE;
4389: }
4390: } else {
4391: /* all once recordable media */
4392: format_flags |= FORMAT_WRITEONCE;
4393: if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
4394: format_flags |= FORMAT_SEQUENTIAL;
4395:
4396: if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {
4397: /* logical overwritable */
4398: format_flags |= FORMAT_LOW;
4399: } else {
4400: /* have to use VAT for overwriting */
4401: format_flags |= FORMAT_VAT;
4402: }
4403: } else {
4404: /* rare WORM devices, but BluRay has one, strat4096 */
4405: format_flags |= FORMAT_WORM;
4406: }
4407: }
4408:
4409: /* enable/disable requests */
4410: if (req_disable & FORMAT_META) {
4411: format_flags &= ~(FORMAT_META | FORMAT_LOW);
4412: req_disable &= ~FORMAT_META;
4413: }
4414: if ((format_flags & FORMAT_VAT) & UDF_512_TRACK)
4415: format_flags |= FORMAT_TRACK512;
4416:
4417: if (req_enable & FORMAT_READONLY) {
4418: format_flags |= FORMAT_READONLY;
4419: }
4420:
4421: /* determine partition/media access type */
4422: media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;
4423: if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
4424: media_accesstype = UDF_ACCESSTYPE_OVERWRITABLE;
4425: if (mmc_discinfo.mmc_cur & MMC_CAP_ERASABLE)
4426: media_accesstype = UDF_ACCESSTYPE_REWRITEABLE;
4427: } else {
4428: /* all once recordable media */
4429: media_accesstype = UDF_ACCESSTYPE_WRITE_ONCE;
4430: }
4431: if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE)
4432: media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE;
4433:
4434: /* patch up media accesstype */
4435: if (req_enable & FORMAT_READONLY) {
4436: /* better now */
4437: media_accesstype = UDF_ACCESSTYPE_READ_ONLY;
4438: }
4439:
4440: /* adjust minimum version limits */
4441: if (format_flags & FORMAT_VAT)
4442: context.min_udf = MAX(context.min_udf, 0x0150);
4443: if (format_flags & FORMAT_SPAREABLE)
4444: context.min_udf = MAX(context.min_udf, 0x0150);
4445: if (format_flags & FORMAT_META)
4446: context.min_udf = MAX(context.min_udf, 0x0250);
4447: if (format_flags & FORMAT_LOW)
4448: context.min_udf = MAX(context.min_udf, 0x0260);
4449:
4450: /* adjust maximum version limits not to tease or break things */
4451: if (!(format_flags & (FORMAT_META | FORMAT_LOW | FORMAT_VAT)) &&
4452: (context.max_udf > 0x200))
4453: context.max_udf = 0x201;
4454:
4455: if ((format_flags & (FORMAT_VAT | FORMAT_SPAREABLE)) == 0)
4456: if (context.max_udf <= 0x150)
4457: context.min_udf = 0x102;
4458:
4459: /* limit Ecma 167 descriptor if possible/needed */
4460: context.dscrver = 3;
4461: if ((context.min_udf < 0x200) || (context.max_udf < 0x200)) {
4462: context.dscrver = 2;
4463: context.max_udf = 0x150; /* last version < 0x200 */
4464: }
4465:
4466: /* is it possible ? */
4467: if (context.min_udf > context.max_udf) {
4468: warnx("initialisation prohibited by specified maximum "
4469: "UDF version 0x%04x. Minimum version required 0x%04x",
4470: context.max_udf, context.min_udf);
4471: return EPERM;
4472: }
4473:
4474: if (!UDF_VERSION(context.min_udf) || !UDF_VERSION(context.max_udf)) {
4475: warnx("internal error, invalid min/max udf versionsi in %s",
4476: __func__);
4477: return EPERM;
4478: }
4479: context.format_flags = format_flags;
4480: context.media_accesstype = media_accesstype;
4481:
4482: return 0;
4483: }
4484:
4485: #undef UDF_VERSION
4486:
4487:
4488: /* --------------------------------------------------------------------- */
4489:
4490: int
4491: udf_proces_names(void)
4492: {
4493: struct timeval time_of_day;
4494: uint32_t primary_nr;
4495: uint64_t volset_nr;
4496:
4497: if (context.logvol_name == NULL)
4498: context.logvol_name = strdup("anonymous");
4499: if (context.primary_name == NULL) {
4500: if (mmc_discinfo.disc_flags & MMC_DFLAGS_DISCIDVALID) {
4501: primary_nr = mmc_discinfo.disc_id;
4502: } else {
4503: primary_nr = (uint32_t) random();
4504: }
4505: context.primary_name = calloc(32, 1);
4506: sprintf(context.primary_name, "%08"PRIx32, primary_nr);
4507: }
4508: if (context.volset_name == NULL) {
4509: if (mmc_discinfo.disc_flags & MMC_DFLAGS_BARCODEVALID) {
4510: volset_nr = mmc_discinfo.disc_barcode;
4511: } else {
4512: (void)gettimeofday(&time_of_day, NULL);
4513: volset_nr = (uint64_t) random();
4514: volset_nr |= ((uint64_t) time_of_day.tv_sec) << 32;
4515: }
4516: context.volset_name = calloc(128,1);
4517: sprintf(context.volset_name, "%016"PRIx64, volset_nr);
4518: }
4519: if (context.fileset_name == NULL)
4520: context.fileset_name = strdup("anonymous");
4521:
4522: /* check passed/created identifiers */
4523: if (strlen(context.logvol_name) > 128) {
4524: warnx("logical volume name too long");
4525: return EINVAL;
4526: }
4527: if (strlen(context.primary_name) > 32) {
4528: warnx("primary volume name too long");
4529: return EINVAL;
4530: }
4531: if (strlen(context.volset_name) > 128) {
4532: warnx("volume set name too long");
4533: return EINVAL;
4534: }
4535: if (strlen(context.fileset_name) > 32) {
4536: warnx("fileset name too long");
4537: return EINVAL;
4538: }
4539:
4540: /* signal all OK */
4541: return 0;
4542: }
4543:
4544: /* --------------------------------------------------------------------- */
4545:
4546: int
4547: udf_write_iso9660_vrs(void)
4548: {
4549: struct vrs_desc *iso9660_vrs_desc;
4550: uint32_t pos;
4551: int error, cnt, dpos;
4552:
4553: /* create ISO/Ecma-167 identification descriptors */
4554: if ((iso9660_vrs_desc = calloc(1, context.sector_size)) == NULL)
4555: return ENOMEM;
4556:
4557: /*
4558: * All UDF formats should have their ISO/Ecma-167 descriptors written
4559: * except when not possible due to track reservation in the case of
4560: * VAT
4561: */
4562: if ((context.format_flags & FORMAT_TRACK512) == 0) {
4563: dpos = (2048 + context.sector_size - 1) / context.sector_size;
4564:
4565: /* wipe at least 6 times 2048 byte `sectors' */
4566: for (cnt = 0; cnt < 6 *dpos; cnt++) {
4567: pos = layout.iso9660_vrs + cnt;
4568: if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
4569: free(iso9660_vrs_desc);
4570: return error;
4571: }
4572: }
4573:
4574: /* common VRS fields in all written out ISO descriptors */
4575: iso9660_vrs_desc->struct_type = 0;
4576: iso9660_vrs_desc->version = 1;
4577: pos = layout.iso9660_vrs;
4578:
4579: /* BEA01, NSR[23], TEA01 */
4580: memcpy(iso9660_vrs_desc->identifier, "BEA01", 5);
4581: if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
4582: free(iso9660_vrs_desc);
4583: return error;
4584: }
4585: pos += dpos;
4586:
4587: if (context.dscrver == 2)
4588: memcpy(iso9660_vrs_desc->identifier, "NSR02", 5);
4589: else
4590: memcpy(iso9660_vrs_desc->identifier, "NSR03", 5);
4591: ;
4592: if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
4593: free(iso9660_vrs_desc);
4594: return error;
4595: }
4596: pos += dpos;
4597:
4598: memcpy(iso9660_vrs_desc->identifier, "TEA01", 5);
4599: if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {
4600: free(iso9660_vrs_desc);
4601: return error;
4602: }
4603: }
4604:
4605: free(iso9660_vrs_desc);
4606: /* return success */
4607: return 0;
4608: }
4609:
4610:
4611: /* --------------------------------------------------------------------- */
4612:
4613: int
4614: udf_get_blockingnr(struct mmc_trackinfo *ti)
4615: {
4616: int blockingnr;
4617:
4618: /* determine blockingnr */
4619: blockingnr = ti->packet_size;
4620: if (blockingnr <= 1) {
4621: /* paranoia on blockingnr */
4622: switch (mmc_discinfo.mmc_profile) {
4623: case 0x01 : /* DISC */
4624: blockingnr = 64;
4625: break;
4626: case 0x08 : /* CDROM */
4627: case 0x09 : /* CD-R */
4628: case 0x0a : /* CD-RW */
4629: blockingnr = 32; /* UDF requirement */
4630: break;
4631: case 0x10 : /* DVDROM */
4632: case 0x11 : /* DVD-R (DL) */
4633: case 0x12 : /* DVD-RAM */
4634: case 0x1b : /* DVD+R */
4635: case 0x2b : /* DVD+R Dual layer */
4636: case 0x13 : /* DVD-RW restricted overwrite */
4637: case 0x14 : /* DVD-RW sequential */
4638: case 0x1a : /* DVD+RW */
4639: blockingnr = 16; /* SCSI definition */
4640: break;
4641: case 0x40 : /* BDROM */
4642: case 0x41 : /* BD-R Sequential recording (SRM) */
4643: case 0x42 : /* BD-R Random recording (RRM) */
4644: case 0x43 : /* BD-RE */
4645: case 0x51 : /* HD DVD-R */
4646: case 0x52 : /* HD DVD-RW */
4647: blockingnr = 32; /* SCSI definition */
4648: break;
4649: default:
4650: break;
4651: }
4652: }
4653: return blockingnr;
4654: }
4655:
4656:
4657: int
4658: udf_spareable_blocks(void)
4659: {
4660: if (mmc_discinfo.mmc_class == MMC_CLASS_CD) {
4661: /* not too much for CD-RW, still 20MiB */
4662: return 32;
4663: } else {
4664: /* take a value for DVD*RW mainly, BD is `defect free' */
4665: return 512;
4666: }
4667: }
4668:
4669:
4670: int
4671: udf_spareable_blockingnr(void)
4672: {
4673: struct mmc_trackinfo ti;
4674: int spareable_blockingnr;
4675: int error;
4676:
4677: /* determine span/size */
4678: ti.tracknr = mmc_discinfo.first_track_last_session;
4679: error = udf_update_trackinfo(&ti);
4680: spareable_blockingnr = udf_get_blockingnr(&ti);
4681: if (error)
4682: spareable_blockingnr = 32;
4683:
4684: /*
4685: * Note that for (bug) compatibility with version UDF 2.00
4686: * (fixed in 2.01 and higher) the blocking size needs to be 32
4687: * sectors otherwise the drive's blockingnr.
4688: */
4689: if (context.min_udf <= 0x200)
4690: spareable_blockingnr = 32;
4691: return spareable_blockingnr;
4692: }
4693:
4694:
4695: /*
4696: * Main function that creates and writes out disc contents based on the
4697: * format_flags's that uniquely define the type of disc to create.
4698: */
4699:
4700: int
4701: udf_do_newfs_prefix(void)
4702: {
4703: union dscrptr *zero_dscr;
4704: union dscrptr *dscr;
4705: struct mmc_trackinfo ti;
4706: uint32_t blockingnr;
4707: uint32_t cnt, loc, len;
4708: int sectcopy;
4709: int error, integrity_type;
4710: int data_part, metadata_part;
4711: int format_flags;
4712:
4713: /* init */
4714: format_flags = context.format_flags;
4715:
4716: /* determine span/size */
4717: ti.tracknr = mmc_discinfo.first_track_last_session;
4718: error = udf_update_trackinfo(&ti);
4719: if (error)
4720: return error;
4721:
4722: if (mmc_discinfo.sector_size > context.sector_size) {
4723: warnx("impossible to format: "
4724: "sector size %d too small for media sector size %d",
4725: context.sector_size, mmc_discinfo.sector_size);
4726: return EIO;
4727: }
4728:
4729: /* determine blockingnr */
4730: blockingnr = udf_get_blockingnr(&ti);
4731: if (blockingnr <= 0) {
4732: warnx("can't fixup blockingnumber for device "
4733: "type %d", mmc_discinfo.mmc_profile);
4734: warnx("device is not returning valid blocking"
4735: " number and media type is unknown");
4736: return EINVAL;
4737: }
4738:
4739: wrtrack_skew = 0;
4740: if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL)
4741: wrtrack_skew = ti.next_writable % blockingnr;
4742:
4743: /* get layout */
4744: error = udf_calculate_disc_layout(context.min_udf,
4745: ti.track_start, mmc_discinfo.last_possible_lba,
4746: context.sector_size, blockingnr);
4747:
4748: /* cache partition for we need it often */
4749: data_part = context.data_part;
4750: metadata_part = context.metadata_part;
4751:
4752: /* Create sparing table descriptor if applicable */
4753: if (format_flags & FORMAT_SPAREABLE) {
4754: if ((error = udf_create_sparing_tabled()))
4755: return error;
4756:
4757: if (context.check_surface) {
4758: if ((error = udf_surface_check()))
4759: return error;
4760: }
4761: }
4762:
4763: /* Create a generic terminator descriptor (later reused) */
4764: terminator_dscr = calloc(1, context.sector_size);
4765: if (terminator_dscr == NULL)
4766: return ENOMEM;
4767: udf_create_terminator(terminator_dscr, 0);
4768:
1.2 riastrad 4769: /*
1.1 reinoud 4770: * Create the two Volume Descriptor Sets (VDS) each containing the
4771: * following descriptors : primary volume, partition space,
4772: * unallocated space, logical volume, implementation use and the
4773: * terminator
4774: */
4775:
4776: /* start of volume recognition sequence building */
4777: context.vds_seq = 0;
4778:
4779: /* Create primary volume descriptor */
4780: if ((error = udf_create_primaryd()))
4781: return error;
4782:
4783: /* Create partition descriptor */
4784: if ((error = udf_create_partitiond(context.data_part)))
4785: return error;
4786:
4787: /* Create unallocated space descriptor */
4788: if ((error = udf_create_unalloc_spaced()))
4789: return error;
4790:
4791: /* Create logical volume descriptor */
4792: if ((error = udf_create_logical_dscr()))
4793: return error;
4794:
4795: /* Create implementation use descriptor */
4796: /* TODO input of fields 1,2,3 and passing them */
4797: if ((error = udf_create_impvold(NULL, NULL, NULL)))
4798: return error;
4799:
4800: /* Create anchors */
4801: for (cnt = 0; cnt < 3; cnt++) {
4802: if ((error = udf_create_anchor(cnt))) {
4803: return error;
4804: }
4805: }
4806:
4807: /*
4808: * Write out what we've created so far.
4809: *
4810: * Start with wipeout of VRS1 upto start of partition. This allows
1.2 riastrad 4811: * formatting for sequentials with the track reservation and it
1.1 reinoud 4812: * cleans old rubbish on rewritables. For sequentials without the
4813: * track reservation all is wiped from track start.
4814: */
4815: if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
4816: return ENOMEM;
4817:
4818: loc = (format_flags & FORMAT_TRACK512) ? layout.vds1 : ti.track_start;
4819: for (; loc < layout.part_start_lba; loc++) {
4820: if ((error = udf_write_sector(zero_dscr, loc))) {
4821: free(zero_dscr);
4822: return error;
4823: }
4824: }
4825: free(zero_dscr);
4826:
4827: /* writeout iso9660 vrs */
4828: if ((error = udf_write_iso9660_vrs()))
4829: return error;
4830:
4831: /* Writeout anchors */
4832: for (cnt = 0; cnt < 3; cnt++) {
4833: dscr = (union dscrptr *) context.anchors[cnt];
4834: loc = layout.anchors[cnt];
4835: if ((error = udf_write_dscr_phys(dscr, loc, 1))) {
4836: err(1, "ERR!");
4837: return error;
4838: }
4839:
4840: /* sequential media has only one anchor */
4841: if (format_flags & FORMAT_SEQUENTIAL)
4842: break;
4843: }
4844:
4845: /* write out main and secondary VRS */
4846: for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
4847: loc = (sectcopy == 1) ? layout.vds1 : layout.vds2;
4848:
4849: /* primary volume descriptor */
4850: dscr = (union dscrptr *) context.primary_vol;
4851: error = udf_write_dscr_phys(dscr, loc, 1);
4852: if (error)
4853: return error;
4854: loc++;
4855:
4856: /* partition descriptor(s) */
4857: for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
4858: dscr = (union dscrptr *) context.partitions[cnt];
4859: if (dscr) {
4860: error = udf_write_dscr_phys(dscr, loc, 1);
4861: if (error)
4862: return error;
4863: loc++;
4864: }
4865: }
4866:
4867: /* unallocated space descriptor */
4868: dscr = (union dscrptr *) context.unallocated;
4869: error = udf_write_dscr_phys(dscr, loc, 1);
4870: if (error)
4871: return error;
4872: loc++;
4873:
4874: /* logical volume descriptor */
4875: dscr = (union dscrptr *) context.logical_vol;
4876: error = udf_write_dscr_phys(dscr, loc, 1);
4877: if (error)
4878: return error;
4879: loc++;
4880:
4881: /* implementation use descriptor */
4882: dscr = (union dscrptr *) context.implementation;
4883: error = udf_write_dscr_phys(dscr, loc, 1);
4884: if (error)
4885: return error;
4886: loc++;
4887:
4888: /* terminator descriptor */
4889: error = udf_write_dscr_phys(terminator_dscr, loc, 1);
4890: if (error)
4891: return error;
4892: loc++;
4893: }
4894:
4895: /* writeout the two spareable table descriptors (if needed) */
4896: if (format_flags & FORMAT_SPAREABLE) {
4897: for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
4898: loc = (sectcopy == 1) ? layout.spt_1 : layout.spt_2;
4899: dscr = (union dscrptr *) context.sparing_table;
4900: len = udf_tagsize(dscr, context.sector_size) /
4901: context.sector_size;
4902:
4903: /* writeout */
4904: error = udf_write_dscr_phys(dscr, loc, len);
4905: if (error)
4906: return error;
4907: }
4908: }
4909:
4910: /*
4911: * Create unallocated space bitmap descriptor. Sequential recorded
4912: * media report their own free/used space; no free/used space tables
4913: * should be recorded for these.
4914: */
4915: if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
4916: error = udf_create_space_bitmap(
4917: layout.alloc_bitmap_dscr_size,
4918: layout.part_size_lba,
4919: &context.part_unalloc_bits[data_part]);
4920: if (error)
4921: return error;
4922: /* TODO: freed space bitmap if applicable */
4923:
4924: /* mark space allocated for the unallocated space bitmap */
4925: udf_mark_allocated(layout.unalloc_space, data_part,
4926: layout.alloc_bitmap_dscr_size);
4927: }
4928:
4929: /*
4930: * Create metadata partition file entries and allocate and init their
4931: * space and free space maps.
4932: */
4933: if (format_flags & FORMAT_META) {
4934: error = udf_create_meta_files();
4935: if (error)
4936: return error;
4937:
4938: /* mark space allocated for meta partition and its bitmap */
4939: udf_mark_allocated(layout.meta_file, data_part, 1);
4940: udf_mark_allocated(layout.meta_mirror, data_part, 1);
4941: udf_mark_allocated(layout.meta_part_start_lba, data_part,
4942: layout.meta_part_size_lba);
4943:
4944: if (context.meta_bitmap) {
4945: /* metadata bitmap creation and accounting */
4946: error = udf_create_space_bitmap(
4947: layout.meta_bitmap_dscr_size,
4948: layout.meta_part_size_lba,
4949: &context.part_unalloc_bits[metadata_part]);
4950: if (error)
4951: return error;
1.2 riastrad 4952:
1.1 reinoud 4953: udf_mark_allocated(layout.meta_bitmap, data_part, 1);
4954: /* mark space allocated for the unallocated space bitmap */
4955: udf_mark_allocated(layout.meta_bitmap_space,
4956: data_part,
4957: layout.meta_bitmap_dscr_size);
4958: }
4959: }
4960:
4961: /* create logical volume integrity descriptor */
4962: context.num_files = 0;
4963: context.num_directories = 0;
4964: integrity_type = UDF_INTEGRITY_OPEN;
4965: if ((error = udf_create_lvintd(integrity_type)))
4966: return error;
4967:
4968: /* writeout initial open integrity sequence + terminator */
4969: loc = layout.lvis;
4970: dscr = (union dscrptr *) context.logvol_integrity;
4971: error = udf_write_dscr_phys(dscr, loc, 1);
4972: if (error)
4973: return error;
4974: loc++;
4975: error = udf_write_dscr_phys(terminator_dscr, loc, 1);
4976: if (error)
4977: return error;
4978:
4979: /* create VAT if needed */
4980: if (format_flags & FORMAT_VAT) {
4981: context.vat_allocated = context.sector_size;
4982: context.vat_contents = malloc(context.vat_allocated);
4983: assert(context.vat_contents);
4984:
4985: udf_prepend_VAT_file();
4986: }
4987:
4988: /* create FSD and writeout */
4989: if ((error = udf_create_fsd()))
4990: return error;
4991: udf_mark_allocated(layout.fsd, metadata_part, 1);
4992:
4993: dscr = (union dscrptr *) context.fileset_desc;
4994: error = udf_write_dscr_virt(dscr, layout.fsd, metadata_part, 1);
4995:
4996: return error;
4997: }
4998:
4999:
5000: /* specific routine for newfs to create empty rootdirectory */
5001: int
5002: udf_do_rootdir(void)
5003: {
5004: union dscrptr *root_dscr;
5005: int error;
5006:
5007: /* create root directory and write out */
5008: assert(context.unique_id == 0x10);
5009: context.unique_id = 0;
5010: if ((error = udf_create_new_rootdir(&root_dscr)))
5011: return error;
5012: udf_mark_allocated(layout.rootdir, context.metadata_part, 1);
5013:
5014: error = udf_write_dscr_virt(root_dscr,
5015: layout.rootdir, context.metadata_part, 1);
5016:
5017: free(root_dscr);
5018:
5019: return error;
5020: }
5021:
5022:
5023: int
5024: udf_do_newfs_postfix(void)
5025: {
5026: union dscrptr *dscr;
5027: uint32_t loc, len;
5028: int data_part, metadata_part;
5029: int format_flags = context.format_flags;
5030: int error;
5031:
5032: /* cache partition for we need it often */
5033: data_part = context.data_part;
5034: metadata_part = context.metadata_part;
5035:
5036: if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
5037: /* update lvint and mark it closed */
5038: udf_update_lvintd(UDF_INTEGRITY_CLOSED);
5039:
5040: /* overwrite initial terminator */
5041: loc = layout.lvis+1;
5042: dscr = (union dscrptr *) context.logvol_integrity;
5043: error = udf_write_dscr_phys(dscr, loc, 1);
5044: if (error)
5045: return error;
5046: loc++;
5047:
5048: /* mark end of integrity descriptor sequence again */
5049: error = udf_write_dscr_phys(terminator_dscr, loc, 1);
5050: if (error)
5051: return error;
5052: }
5053:
5054: /* write out unallocated space bitmap on non sequential media */
5055: if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
5056: /* writeout unallocated space bitmap */
5057: loc = layout.unalloc_space;
5058: dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]);
5059: len = layout.alloc_bitmap_dscr_size;
5060: error = udf_write_dscr_virt(dscr, loc, data_part, len);
5061: if (error)
5062: return error;
5063: }
5064:
5065: if (format_flags & FORMAT_META) {
5066: loc = layout.meta_file;
5067: dscr = (union dscrptr *) context.meta_file;
5068: error = udf_write_dscr_virt(dscr, loc, data_part, 1);
5069: if (error)
5070: return error;
1.2 riastrad 5071:
1.1 reinoud 5072: loc = layout.meta_mirror;
5073: dscr = (union dscrptr *) context.meta_mirror;
5074: error = udf_write_dscr_virt(dscr, loc, data_part, 1);
5075: if (error)
5076: return error;
5077:
5078: if (context.meta_bitmap) {
5079: loc = layout.meta_bitmap;
5080: dscr = (union dscrptr *) context.meta_bitmap;
5081: error = udf_write_dscr_virt(dscr, loc, data_part, 1);
5082: if (error)
5083: return error;
5084:
5085: /* writeout unallocated space bitmap */
5086: loc = layout.meta_bitmap_space;
5087: dscr = (union dscrptr *)
5088: (context.part_unalloc_bits[metadata_part]);
5089: len = layout.meta_bitmap_dscr_size;
5090: error = udf_write_dscr_virt(dscr, loc, data_part, len);
5091: if (error)
5092: return error;
5093: }
5094: }
5095:
5096: /* create and writeout a VAT */
5097: if (format_flags & FORMAT_VAT)
5098: udf_writeout_VAT();
5099:
5100: /* done */
5101: return 0;
5102: }
CVSweb <webmaster@jp.NetBSD.org>