1 /* $NetBSD: udf_create.c,v 1.25 2015/06/16 23:18:55 christos Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2008 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
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.
26 *
27 */
28 #if HAVE_NBTOOL_CONFIG_H
29 #include "nbtool_config.h"
30 #endif
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: udf_create.c,v 1.25 2015/06/16 23:18:55 christos Exp $");
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <time.h>
41 #include <assert.h>
42 #include <err.h>
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include "unicode.h"
46 #include "udf_create.h"
47
48
49 #if 0
50 # ifndef DEBUG
51 # define DEBUG
52 # endif
53 #endif
54
55 /*
56 * NOTE that there is some overlap between this code and the udf kernel fs.
57 * This is intentially though it might better be factored out one day.
58 */
59
60 void
udf_init_create_context(void)61 udf_init_create_context(void)
62 {
63 /* clear */
64 memset(&context, 0, sizeof(struct udf_create_context));
65
66 /* fill with defaults currently known */
67 context.dscrver = 3;
68 context.min_udf = 0x0102;
69 context.max_udf = 0x0260;
70 context.serialnum = 1; /* default */
71
72 context.gmtoff = 0;
73 context.sector_size = 512; /* minimum for UDF */
74
75 context.logvol_name = NULL;
76 context.primary_name = NULL;
77 context.volset_name = NULL;
78 context.fileset_name = NULL;
79
80 /* most basic identification */
81 context.app_name = "*NetBSD";
82 context.app_version_main = 0;
83 context.app_version_sub = 0;
84 context.impl_name = "*NetBSD";
85
86 context.vds_seq = 0; /* first one starts with zero */
87
88 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
89 context.unique_id = 0x10;
90
91 context.num_files = 0;
92 context.num_directories = 0;
93
94 context.data_part = 0;
95 context.metadata_part = 0;
96 context.metadata_alloc_pos = 0;
97 context.data_alloc_pos = 0;
98 }
99
100
101 /* version can be specified as 0xabc or a.bc */
102 static int
parse_udfversion(const char * pos,uint32_t * version)103 parse_udfversion(const char *pos, uint32_t *version) {
104 int hex = 0;
105 char c1, c2, c3, c4;
106
107 *version = 0;
108 if (*pos == '0') {
109 pos++;
110 /* expect hex format */
111 hex = 1;
112 if (*pos++ != 'x')
113 return 1;
114 }
115
116 c1 = *pos++;
117 if (c1 < '0' || c1 > '9')
118 return 1;
119 c1 -= '0';
120
121 c2 = *pos++;
122 if (!hex) {
123 if (c2 != '.')
124 return 1;
125 c2 = *pos++;
126 }
127 if (c2 < '0' || c2 > '9')
128 return 1;
129 c2 -= '0';
130
131 c3 = *pos++;
132 if (c3 < '0' || c3 > '9')
133 return 1;
134 c3 -= '0';
135
136 c4 = *pos++;
137 if (c4 != 0)
138 return 1;
139
140 *version = c1 * 0x100 + c2 * 0x10 + c3;
141 return 0;
142 }
143
144
145 /* parse a given string for an udf version */
146 int
a_udf_version(const char * s,const char * id_type)147 a_udf_version(const char *s, const char *id_type)
148 {
149 uint32_t version;
150
151 if (parse_udfversion(s, &version))
152 errx(1, "unknown %s id %s; specify as hex or float", id_type, s);
153 return version;
154 }
155
156
157 static uint32_t
udf_space_bitmap_len(uint32_t part_size)158 udf_space_bitmap_len(uint32_t part_size)
159 {
160 return sizeof(struct space_bitmap_desc)-1 +
161 part_size/8;
162 }
163
164
165 static uint32_t
udf_bytes_to_sectors(uint64_t bytes)166 udf_bytes_to_sectors(uint64_t bytes)
167 {
168 uint32_t sector_size = layout.sector_size;
169 return (bytes + sector_size -1) / sector_size;
170 }
171
172
173 int
udf_calculate_disc_layout(int format_flags,int min_udf,uint32_t wrtrack_skew,uint32_t first_lba,uint32_t last_lba,uint32_t sector_size,uint32_t blockingnr,uint32_t sparable_blocks,float meta_fract)174 udf_calculate_disc_layout(int format_flags, int min_udf,
175 uint32_t wrtrack_skew,
176 uint32_t first_lba, uint32_t last_lba,
177 uint32_t sector_size, uint32_t blockingnr,
178 uint32_t sparable_blocks, float meta_fract)
179 {
180 uint64_t kbsize, bytes;
181 uint32_t sparable_blockingnr;
182 uint32_t align_blockingnr;
183 uint32_t pos, mpos;
184
185 /* clear */
186 memset(&layout, 0, sizeof(layout));
187
188 /* fill with parameters */
189 layout.wrtrack_skew = wrtrack_skew;
190 layout.first_lba = first_lba;
191 layout.last_lba = last_lba;
192 layout.sector_size = sector_size;
193 layout.blockingnr = blockingnr;
194 layout.sparable_blocks = sparable_blocks;
195
196 /* start disc layouting */
197
198 /*
199 * location of iso9660 vrs is defined as first sector AFTER 32kb,
200 * minimum `sector size' 2048
201 */
202 layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
203 + first_lba;
204
205 /* anchor starts at specified offset in sectors */
206 layout.anchors[0] = first_lba + 256;
207 if (format_flags & FORMAT_TRACK512)
208 layout.anchors[0] = first_lba + 512;
209 layout.anchors[1] = last_lba - 256;
210 layout.anchors[2] = last_lba;
211
212 /* update workable space */
213 first_lba = layout.anchors[0] + blockingnr;
214 last_lba = layout.anchors[1] - 1;
215
216 /* XXX rest of anchor packet can be added to unallocated space descr */
217
218 /* reserve space for VRS and VRS copy and associated tables */
219 layout.vds_size = MAX(16, blockingnr); /* UDF 2.2.3.1+2 */
220 layout.vds1 = first_lba;
221 first_lba += layout.vds_size; /* next packet */
222
223 if (format_flags & FORMAT_SEQUENTIAL) {
224 /* for sequential, append them ASAP */
225 layout.vds2 = first_lba;
226 first_lba += layout.vds_size;
227 } else {
228 layout.vds2 = layout.anchors[1] - layout.vds_size;
229 last_lba = layout.vds2 - 1; /* XXX -1 ?? */
230 }
231
232 /* reserve space for logvol integrity sequence */
233 layout.lvis_size = MAX(8192/sector_size, 2 * blockingnr);
234 if (format_flags & FORMAT_VAT)
235 layout.lvis_size = 2;
236 if (format_flags & FORMAT_WORM)
237 layout.lvis_size = 64 * blockingnr;
238
239 /* TODO skip bad blocks in LVID sequence; for now use f.e. */
240 //first_lba+=128;
241 layout.lvis = first_lba;
242 first_lba += layout.lvis_size;
243
244 /* initial guess of UDF partition size */
245 layout.part_start_lba = first_lba;
246 layout.part_size_lba = last_lba - layout.part_start_lba;
247
248 /* all non sequential media needs an unallocated space bitmap */
249 layout.alloc_bitmap_dscr_size = 0;
250 if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
251 bytes = udf_space_bitmap_len(layout.part_size_lba);
252 layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
253
254 /* XXX freed space map when applicable */
255 }
256
257 /*
258 * Note that for (bug) compatibility with version UDF 2.00 (fixed in
259 * 2.01 and higher) the blocking size needs to be 32 sectors otherwise
260 * the drive's blockingnr.
261 */
262
263 sparable_blockingnr = blockingnr;
264 if (min_udf <= 0x200)
265 sparable_blockingnr = 32;
266
267 align_blockingnr = blockingnr;
268 if (format_flags & (FORMAT_SPARABLE | FORMAT_META))
269 align_blockingnr = sparable_blockingnr;
270
271 layout.align_blockingnr = align_blockingnr;
272 layout.sparable_blockingnr = sparable_blockingnr;
273
274 /*
275 * Align partition LBA space to blocking granularity. Not strickly
276 * nessisary for non sparables but safer for the VRS data since it is
277 * not updated sporadically
278 */
279
280 if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
281 #ifdef DEBUG
282 printf("Lost %d slack sectors at start\n", UDF_ROUNDUP(
283 first_lba - wrtrack_skew, align_blockingnr) -
284 (first_lba - wrtrack_skew));
285 printf("Lost %d slack sectors at end\n",
286 (first_lba - wrtrack_skew) - UDF_ROUNDDOWN(
287 first_lba - wrtrack_skew, align_blockingnr));
288 #endif
289
290 first_lba = UDF_ROUNDUP( first_lba - wrtrack_skew,
291 align_blockingnr);
292 last_lba = UDF_ROUNDDOWN(last_lba - wrtrack_skew,
293 align_blockingnr);
294 }
295
296 if ((format_flags & FORMAT_SPARABLE) == 0)
297 layout.sparable_blocks = 0;
298
299 if (format_flags & FORMAT_SPARABLE) {
300 layout.sparable_area_size =
301 layout.sparable_blocks * sparable_blockingnr;
302
303 /* a sparing table descriptor is a whole blockingnr sectors */
304 layout.sparing_table_dscr_lbas = sparable_blockingnr;
305
306 /* place the descriptors at the start and end of the area */
307 layout.spt_1 = first_lba;
308 first_lba += layout.sparing_table_dscr_lbas;
309
310 layout.spt_2 = last_lba - layout.sparing_table_dscr_lbas;
311 last_lba -= layout.sparing_table_dscr_lbas;
312
313 /* allocate sparable section */
314 layout.sparable_area = first_lba;
315 first_lba += layout.sparable_area_size;
316 }
317
318 /* update guess of UDF partition size */
319 layout.part_start_lba = first_lba;
320 layout.part_size_lba = last_lba - layout.part_start_lba;
321
322 /* determine partition selection for data and metadata */
323 context.data_part = 0;
324 context.metadata_part = context.data_part;
325 if ((format_flags & FORMAT_VAT) || (format_flags & FORMAT_META))
326 context.metadata_part = context.data_part + 1;
327
328 /*
329 * Pick fixed logical space sector numbers for main FSD, rootdir and
330 * unallocated space. The reason for this pre-allocation is that they
331 * are referenced in the volume descriptor sequence and hence can't be
332 * allocated later.
333 */
334 pos = 0;
335 layout.unalloc_space = pos;
336 pos += layout.alloc_bitmap_dscr_size;
337
338 /* claim metadata descriptors and partition space [UDF 2.2.10] */
339 if (format_flags & FORMAT_META) {
340 /* note: all in backing partition space */
341 layout.meta_file = pos++;
342 layout.meta_bitmap = pos++;;
343 layout.meta_mirror = layout.part_size_lba-1;
344 layout.meta_alignment = MAX(blockingnr, sparable_blockingnr);
345 layout.meta_blockingnr = MAX(layout.meta_alignment, 32);
346
347 /* calculate our partition length and store in sectors */
348 layout.meta_part_size_lba = layout.part_size_lba * meta_fract;
349 layout.meta_part_size_lba = MAX(layout.meta_part_size_lba, 32);
350 layout.meta_part_size_lba =
351 UDF_ROUNDDOWN(layout.meta_part_size_lba, layout.meta_blockingnr);
352
353 /* calculate positions */
354 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
355 layout.meta_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
356
357 layout.meta_bitmap_space = pos;
358 pos += layout.meta_bitmap_dscr_size;
359
360 layout.meta_part_start_lba = UDF_ROUNDUP(pos, layout.meta_alignment);
361 }
362
363 mpos = (context.metadata_part == context.data_part) ? pos : 0;
364 layout.fsd = mpos; mpos += 1;
365 layout.rootdir = mpos; mpos += 1;
366 layout.vat = mpos; mpos += 1; /* if present */
367
368 #if 0
369 printf("Summary so far\n");
370 printf("\tiso9660_vrs\t\t%d\n", layout.iso9660_vrs);
371 printf("\tanchor0\t\t\t%d\n", layout.anchors[0]);
372 printf("\tanchor1\t\t\t%d\n", layout.anchors[1]);
373 printf("\tanchor2\t\t\t%d\n", layout.anchors[2]);
374 printf("\tvds_size\t\t%d\n", layout.vds_size);
375 printf("\tvds1\t\t\t%d\n", layout.vds1);
376 printf("\tvds2\t\t\t%d\n", layout.vds2);
377 printf("\tlvis_size\t\t%d\n", layout.lvis_size);
378 printf("\tlvis\t\t\t%d\n", layout.lvis);
379 if (format_flags & FORMAT_SPARABLE) {
380 printf("\tsparable size\t\t%d\n", layout.sparable_area_size);
381 printf("\tsparable\t\t%d\n", layout.sparable_area);
382 }
383 printf("\tpartition start lba\t%d\n", layout.part_start_lba);
384 printf("\tpartition size\t\t%d KiB, %d MiB\n",
385 (layout.part_size_lba * sector_size) / 1024,
386 (layout.part_size_lba * sector_size) / (1024*1024));
387 if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
388 printf("\tpart bitmap start\t%d\n", layout.unalloc_space);
389 printf("\t\tfor %d lba\n", layout.alloc_bitmap_dscr_size);
390 }
391 if (format_flags & FORMAT_META) {
392 printf("\tmeta blockingnr\t\t%d\n", layout.meta_blockingnr);
393 printf("\tmeta alignment\t\t%d\n", layout.meta_alignment);
394 printf("\tmeta size\t\t%d KiB, %d MiB\n",
395 (layout.meta_part_size_lba * sector_size) / 1024,
396 (layout.meta_part_size_lba * sector_size) / (1024*1024));
397 printf("\tmeta file\t\t%d\n", layout.meta_file);
398 printf("\tmeta mirror\t\t%d\n", layout.meta_mirror);
399 printf("\tmeta bitmap\t\t%d\n", layout.meta_bitmap);
400 printf("\tmeta bitmap start\t%d\n", layout.meta_bitmap_space);
401 printf("\t\tfor %d lba\n", layout.meta_bitmap_dscr_size);
402 printf("\tmeta space start\t%d\n", layout.meta_part_start_lba);
403 printf("\t\tfor %d lba\n", layout.meta_part_size_lba);
404 }
405 printf("\n");
406 #endif
407
408 kbsize = (uint64_t) last_lba * sector_size;
409 printf("Total space on this medium approx. "
410 "%"PRIu64" KiB, %"PRIu64" MiB\n",
411 kbsize/1024, kbsize/(1024*1024));
412 kbsize = (uint64_t)(layout.part_size_lba - layout.alloc_bitmap_dscr_size
413 - layout.meta_bitmap_dscr_size) * sector_size;
414 printf("Free space on this volume approx. "
415 "%"PRIu64" KiB, %"PRIu64" MiB\n\n",
416 kbsize/1024, kbsize/(1024*1024));
417
418 return 0;
419 }
420
421
422 int
udf_validate_tag_sum(union dscrptr * dscr)423 udf_validate_tag_sum(union dscrptr *dscr)
424 {
425 struct desc_tag *tag = &dscr->tag;
426 uint8_t *pos, sum, cnt;
427
428 /* calculate TAG header checksum */
429 pos = (uint8_t *) tag;
430 sum = 0;
431
432 for(cnt = 0; cnt < 16; cnt++) {
433 if (cnt != 4) sum += *pos;
434 pos++;
435 };
436 tag->cksum = sum; /* 8 bit */
437
438 return 0;
439 }
440
441
442 /* assumes sector number of descriptor to be allready present */
443 int
udf_validate_tag_and_crc_sums(union dscrptr * dscr)444 udf_validate_tag_and_crc_sums(union dscrptr *dscr)
445 {
446 struct desc_tag *tag = &dscr->tag;
447 uint16_t crc;
448
449 /* check payload CRC if applicable */
450 if (udf_rw16(tag->desc_crc_len) > 0) {
451 crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH,
452 udf_rw16(tag->desc_crc_len));
453 tag->desc_crc = udf_rw16(crc);
454 };
455
456 /* calculate TAG header checksum */
457 return udf_validate_tag_sum(dscr);
458 }
459
460
461 void
udf_inittag(struct desc_tag * tag,int tagid,uint32_t loc)462 udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc)
463 {
464 tag->id = udf_rw16(tagid);
465 tag->descriptor_ver = udf_rw16(context.dscrver);
466 tag->cksum = 0;
467 tag->reserved = 0;
468 tag->serial_num = udf_rw16(context.serialnum);
469 tag->tag_loc = udf_rw32(loc);
470 }
471
472
473 int
udf_create_anchor(int num)474 udf_create_anchor(int num)
475 {
476 struct anchor_vdp *avdp;
477 uint32_t vds_extent_len = layout.vds_size * context.sector_size;
478
479 if ((avdp = calloc(1, context.sector_size)) == NULL)
480 return ENOMEM;
481
482 udf_inittag(&avdp->tag, TAGID_ANCHOR, layout.anchors[num]);
483
484 avdp->main_vds_ex.loc = udf_rw32(layout.vds1);
485 avdp->main_vds_ex.len = udf_rw32(vds_extent_len);
486
487 avdp->reserve_vds_ex.loc = udf_rw32(layout.vds2);
488 avdp->reserve_vds_ex.len = udf_rw32(vds_extent_len);
489
490 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
491 avdp->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
492
493 context.anchors[num] = avdp;
494 return 0;
495 }
496
497
498 void
udf_create_terminator(union dscrptr * dscr,uint32_t loc)499 udf_create_terminator(union dscrptr *dscr, uint32_t loc)
500 {
501 memset(dscr, 0, context.sector_size);
502 udf_inittag(&dscr->tag, TAGID_TERM, loc);
503
504 /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
505 dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
506 }
507
508
509 void
udf_osta_charset(struct charspec * charspec)510 udf_osta_charset(struct charspec *charspec)
511 {
512 memset(charspec, 0, sizeof(*charspec));
513 charspec->type = 0;
514 strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
515 }
516
517
518 void
udf_encode_osta_id(char * osta_id,uint16_t len,char * text)519 udf_encode_osta_id(char *osta_id, uint16_t len, char *text)
520 {
521 uint16_t u16_name[1024];
522 uint8_t *pos;
523 uint16_t *pos16;
524
525 memset(osta_id, 0, len);
526 if (!text || (strlen(text) == 0)) return;
527
528 memset(u16_name, 0, sizeof(uint16_t) * 1023);
529
530 /* convert ascii to 16 bits unicode */
531 pos = (uint8_t *) text;
532 pos16 = u16_name;
533 while (*pos) {
534 *pos16 = *pos;
535 pos++; pos16++;
536 };
537 *pos16 = 0;
538
539 udf_CompressUnicode(len, 8, (unicode_t *) u16_name, (byte *) osta_id);
540
541 /* Ecma 167/7.2.13 states that length is recorded in the last byte */
542 osta_id[len-1] = strlen(text)+1;
543 }
544
545
546 /* first call udf_set_regid and then the suffix */
547 void
udf_set_regid(struct regid * regid,char const * name)548 udf_set_regid(struct regid *regid, char const *name)
549 {
550 memset(regid, 0, sizeof(*regid));
551 regid->flags = 0; /* not dirty and not protected */
552 strcpy((char *) regid->id, name);
553 }
554
555
556 void
udf_add_domain_regid(struct regid * regid)557 udf_add_domain_regid(struct regid *regid)
558 {
559 uint16_t *ver;
560
561 ver = (uint16_t *) regid->id_suffix;
562 *ver = udf_rw16(context.min_udf);
563 }
564
565
566 void
udf_add_udf_regid(struct regid * regid)567 udf_add_udf_regid(struct regid *regid)
568 {
569 uint16_t *ver;
570
571 ver = (uint16_t *) regid->id_suffix;
572 *ver = udf_rw16(context.min_udf);
573
574 regid->id_suffix[2] = 4; /* unix */
575 regid->id_suffix[3] = 8; /* NetBSD */
576 }
577
578
579 void
udf_add_impl_regid(struct regid * regid)580 udf_add_impl_regid(struct regid *regid)
581 {
582 regid->id_suffix[0] = 4; /* unix */
583 regid->id_suffix[1] = 8; /* NetBSD */
584 }
585
586
587 void
udf_add_app_regid(struct regid * regid)588 udf_add_app_regid(struct regid *regid)
589 {
590 regid->id_suffix[0] = context.app_version_main;
591 regid->id_suffix[1] = context.app_version_sub;
592 }
593
594
595 /*
596 * Fill in timestamp structure based on clock_gettime(). Time is reported back
597 * as a time_t accompanied with a nano second field.
598 *
599 * The husec, usec and csec could be relaxed in type.
600 */
601 static void
udf_timespec_to_timestamp(struct timespec * timespec,struct timestamp * timestamp)602 udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp)
603 {
604 struct tm tm;
605 uint64_t husec, usec, csec;
606
607 memset(timestamp, 0, sizeof(*timestamp));
608 gmtime_r(×pec->tv_sec, &tm);
609
610 /*
611 * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1.
612 *
613 * Lower 12 bits are two complement signed timezone offset if bit 12
614 * (method 1) is clear. Otherwise if bit 12 is set, specify timezone
615 * offset to -2047 i.e. unsigned `zero'
616 */
617
618 /* set method 1 for CUT/GMT */
619 timestamp->type_tz = udf_rw16((1<<12) + 0);
620 timestamp->year = udf_rw16(tm.tm_year + 1900);
621 timestamp->month = tm.tm_mon + 1; /* `tm' uses 0..11 for months */
622 timestamp->day = tm.tm_mday;
623 timestamp->hour = tm.tm_hour;
624 timestamp->minute = tm.tm_min;
625 timestamp->second = tm.tm_sec;
626
627 usec = (timespec->tv_nsec + 500) / 1000; /* round */
628 husec = usec / 100;
629 usec -= husec * 100; /* only 0-99 in usec */
630 csec = husec / 100; /* only 0-99 in csec */
631 husec -= csec * 100; /* only 0-99 in husec */
632
633 /* in rare cases there is overflow in csec */
634 csec = MIN(99, csec);
635 husec = MIN(99, husec);
636 usec = MIN(99, usec);
637
638 timestamp->centisec = csec;
639 timestamp->hund_usec = husec;
640 timestamp->usec = usec;
641 }
642
643
644 void
udf_set_timestamp_now(struct timestamp * timestamp)645 udf_set_timestamp_now(struct timestamp *timestamp)
646 {
647 struct timespec now;
648
649 #ifdef CLOCK_REALTIME
650 (void)clock_gettime(CLOCK_REALTIME, &now);
651 #else
652 struct timeval time_of_day;
653
654 (void)gettimeofday(&time_of_day, NULL);
655 now.tv_sec = time_of_day.tv_sec;
656 now.tv_nsec = time_of_day.tv_usec * 1000;
657 #endif
658 udf_timespec_to_timestamp(&now, timestamp);
659 }
660
661
662 /* some code copied from sys/fs/udf */
663
664 static void
udf_set_timestamp(struct timestamp * timestamp,time_t value)665 udf_set_timestamp(struct timestamp *timestamp, time_t value)
666 {
667 struct timespec t;
668
669 memset(&t, 0, sizeof(struct timespec));
670 t.tv_sec = value;
671 t.tv_nsec = 0;
672 udf_timespec_to_timestamp(&t, timestamp);
673 }
674
675
676 static uint32_t
unix_mode_to_udf_perm(mode_t mode)677 unix_mode_to_udf_perm(mode_t mode)
678 {
679 uint32_t perm;
680
681 perm = ((mode & S_IRWXO) );
682 perm |= ((mode & S_IRWXG) << 2);
683 perm |= ((mode & S_IRWXU) << 4);
684 perm |= ((mode & S_IWOTH) << 3);
685 perm |= ((mode & S_IWGRP) << 5);
686 perm |= ((mode & S_IWUSR) << 7);
687
688 return perm;
689 }
690
691 /* end of copied code */
692
693
694 int
udf_create_primaryd(void)695 udf_create_primaryd(void)
696 {
697 struct pri_vol_desc *pri;
698 uint16_t crclen;
699
700 pri = calloc(1, context.sector_size);
701 if (pri == NULL)
702 return ENOMEM;
703
704 memset(pri, 0, context.sector_size);
705 udf_inittag(&pri->tag, TAGID_PRI_VOL, /* loc */ 0);
706 pri->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
707
708 pri->pvd_num = udf_rw32(0); /* default serial */
709 udf_encode_osta_id(pri->vol_id, 32, context.primary_name);
710
711 /* set defaults for single disc volumes as UDF prescribes */
712 pri->vds_num = udf_rw16(1);
713 pri->max_vol_seq = udf_rw16(1);
714 pri->ichg_lvl = udf_rw16(2);
715 pri->max_ichg_lvl = udf_rw16(3);
716 pri->flags = udf_rw16(0);
717
718 pri->charset_list = udf_rw32(1); /* only CS0 */
719 pri->max_charset_list = udf_rw32(1); /* only CS0 */
720
721 udf_encode_osta_id(pri->volset_id, 128, context.volset_name);
722 udf_osta_charset(&pri->desc_charset);
723 udf_osta_charset(&pri->explanatory_charset);
724
725 udf_set_regid(&pri->app_id, context.app_name);
726 udf_add_app_regid(&pri->app_id);
727
728 udf_set_regid(&pri->imp_id, context.impl_name);
729 udf_add_impl_regid(&pri->imp_id);
730
731 udf_set_timestamp_now(&pri->time);
732
733 crclen = sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH;
734 pri->tag.desc_crc_len = udf_rw16(crclen);
735
736 context.primary_vol = pri;
737
738 return 0;
739 }
740
741
742 /* XXX no support for unallocated or freed space tables yet (!) */
743 int
udf_create_partitiond(int part_num,int part_accesstype)744 udf_create_partitiond(int part_num, int part_accesstype)
745 {
746 struct part_desc *pd;
747 struct part_hdr_desc *phd;
748 uint32_t sector_size, bitmap_bytes;
749 uint16_t crclen;
750
751 sector_size = context.sector_size;
752 bitmap_bytes = layout.alloc_bitmap_dscr_size * sector_size;
753
754 if (context.partitions[part_num]) {
755 printf("Internal error: partition %d allready defined\n",
756 part_num);
757 return EINVAL;
758 }
759
760 pd = calloc(1, context.sector_size);
761 if (pd == NULL)
762 return ENOMEM;
763 phd = &pd->_impl_use.part_hdr;
764
765 udf_inittag(&pd->tag, TAGID_PARTITION, /* loc */ 0);
766 pd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
767
768 pd->flags = udf_rw16(1); /* allocated */
769 pd->part_num = udf_rw16(part_num); /* only one physical partition */
770
771 if (context.dscrver == 2) {
772 udf_set_regid(&pd->contents, "+NSR02");
773 } else {
774 udf_set_regid(&pd->contents, "+NSR03");
775 }
776 udf_add_app_regid(&pd->contents);
777
778 phd->unalloc_space_bitmap.len = udf_rw32(bitmap_bytes);
779 phd->unalloc_space_bitmap.lb_num = udf_rw32(layout.unalloc_space);
780
781 if (layout.freed_space) {
782 phd->freed_space_bitmap.len = udf_rw32(bitmap_bytes);
783 phd->freed_space_bitmap.lb_num = udf_rw32(layout.freed_space);
784 }
785
786 pd->access_type = udf_rw32(part_accesstype);
787 pd->start_loc = udf_rw32(layout.part_start_lba);
788 pd->part_len = udf_rw32(layout.part_size_lba);
789
790 udf_set_regid(&pd->imp_id, context.impl_name);
791 udf_add_impl_regid(&pd->imp_id);
792
793 crclen = sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH;
794 pd->tag.desc_crc_len = udf_rw16(crclen);
795
796 context.partitions[part_num] = pd;
797
798 return 0;
799 }
800
801
802 int
udf_create_unalloc_spaced(void)803 udf_create_unalloc_spaced(void)
804 {
805 struct unalloc_sp_desc *usd;
806 uint16_t crclen;
807
808 usd = calloc(1, context.sector_size);
809 if (usd == NULL)
810 return ENOMEM;
811
812 udf_inittag(&usd->tag, TAGID_UNALLOC_SPACE, /* loc */ 0);
813 usd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
814
815 /* no default entries */
816 usd->alloc_desc_num = udf_rw32(0); /* no entries */
817
818 crclen = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad);
819 crclen -= UDF_DESC_TAG_LENGTH;
820 usd->tag.desc_crc_len = udf_rw16(crclen);
821
822 context.unallocated = usd;
823
824 return 0;
825 }
826
827
828 static int
udf_create_base_logical_dscr(void)829 udf_create_base_logical_dscr(void)
830 {
831 struct logvol_desc *lvd;
832 uint32_t sector_size;
833 uint16_t crclen;
834
835 sector_size = context.sector_size;
836
837 lvd = calloc(1, sector_size);
838 if (lvd == NULL)
839 return ENOMEM;
840
841 udf_inittag(&lvd->tag, TAGID_LOGVOL, /* loc */ 0);
842 lvd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
843
844 udf_osta_charset(&lvd->desc_charset);
845 udf_encode_osta_id(lvd->logvol_id, 128, context.logvol_name);
846 lvd->lb_size = udf_rw32(context.sector_size);
847
848 udf_set_regid(&lvd->domain_id, "*OSTA UDF Compliant");
849 udf_add_domain_regid(&lvd->domain_id);
850
851 /* no partition mappings/entries yet */
852 lvd->mt_l = udf_rw32(0);
853 lvd->n_pm = udf_rw32(0);
854
855 udf_set_regid(&lvd->imp_id, context.impl_name);
856 udf_add_impl_regid(&lvd->imp_id);
857
858 lvd->integrity_seq_loc.loc = udf_rw32(layout.lvis);
859 lvd->integrity_seq_loc.len = udf_rw32(layout.lvis_size * sector_size);
860
861 /* just one fsd for now */
862 lvd->lv_fsd_loc.len = udf_rw32(sector_size);
863 lvd->lv_fsd_loc.loc.part_num = udf_rw32(context.metadata_part);
864 lvd->lv_fsd_loc.loc.lb_num = udf_rw32(layout.fsd);
865
866 crclen = sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH;
867 lvd->tag.desc_crc_len = udf_rw16(crclen);
868
869 context.logical_vol = lvd;
870 context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
871 context.vtop_offset[UDF_VTOP_RAWPART] = 0;
872
873 return 0;
874 }
875
876
877 static void
udf_add_logvol_part_physical(uint16_t phys_part)878 udf_add_logvol_part_physical(uint16_t phys_part)
879 {
880 struct logvol_desc *logvol = context.logical_vol;
881 union udf_pmap *pmap;
882 uint8_t *pmap_pos;
883 uint16_t crclen;
884 uint32_t pmap1_size, log_part;
885
886 log_part = udf_rw32(logvol->n_pm);
887 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
888 pmap1_size = sizeof(struct part_map_1);
889
890 pmap = (union udf_pmap *) pmap_pos;
891 pmap->pm1.type = 1;
892 pmap->pm1.len = sizeof(struct part_map_1);
893 pmap->pm1.vol_seq_num = udf_rw16(1); /* no multi-volume */
894 pmap->pm1.part_num = udf_rw16(phys_part);
895
896 context.vtop [log_part] = phys_part;
897 context.vtop_tp [log_part] = UDF_VTOP_TYPE_PHYS;
898 context.vtop_offset[log_part] = layout.part_start_lba;
899 context.part_size[log_part] = layout.part_size_lba;
900 context.part_free[log_part] = layout.part_size_lba;
901
902 /* increment number of partitions and length */
903 logvol->n_pm = udf_rw32(log_part + 1);
904 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmap1_size);
905
906 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmap1_size;
907 logvol->tag.desc_crc_len = udf_rw16(crclen);
908 }
909
910
911 static void
udf_add_logvol_part_virtual(uint16_t phys_part)912 udf_add_logvol_part_virtual(uint16_t phys_part)
913 {
914 union udf_pmap *pmap;
915 struct logvol_desc *logvol = context.logical_vol;
916 uint8_t *pmap_pos;
917 uint16_t crclen;
918 uint32_t pmapv_size, log_part;
919
920 log_part = udf_rw32(logvol->n_pm);
921 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
922 pmapv_size = sizeof(struct part_map_2);
923
924 pmap = (union udf_pmap *) pmap_pos;
925 pmap->pmv.type = 2;
926 pmap->pmv.len = pmapv_size;
927
928 udf_set_regid(&pmap->pmv.id, "*UDF Virtual Partition");
929 udf_add_udf_regid(&pmap->pmv.id);
930
931 pmap->pmv.vol_seq_num = udf_rw16(1); /* no multi-volume */
932 pmap->pmv.part_num = udf_rw16(phys_part);
933
934 context.vtop [log_part] = phys_part;
935 context.vtop_tp [log_part] = UDF_VTOP_TYPE_VIRT;
936 context.vtop_offset[log_part] = context.vtop_offset[phys_part];
937 context.part_size[log_part] = 0xffffffff;
938 context.part_free[log_part] = 0xffffffff;
939
940 /* increment number of partitions and length */
941 logvol->n_pm = udf_rw32(log_part + 1);
942 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
943
944 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
945 logvol->tag.desc_crc_len = udf_rw16(crclen);
946 }
947
948
949 /* sparing table size is in bytes */
950 static void
udf_add_logvol_part_sparable(uint16_t phys_part)951 udf_add_logvol_part_sparable(uint16_t phys_part)
952 {
953 union udf_pmap *pmap;
954 struct logvol_desc *logvol = context.logical_vol;
955 uint32_t *st_pos, sparable_bytes, pmaps_size;
956 uint8_t *pmap_pos, num;
957 uint16_t crclen;
958 uint32_t log_part;
959
960 log_part = udf_rw32(logvol->n_pm);
961 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
962 pmaps_size = sizeof(struct part_map_2);
963 sparable_bytes = layout.sparable_area_size * context.sector_size;
964
965 pmap = (union udf_pmap *) pmap_pos;
966 pmap->pms.type = 2;
967 pmap->pms.len = pmaps_size;
968
969 udf_set_regid(&pmap->pmv.id, "*UDF Sparable Partition");
970 udf_add_udf_regid(&pmap->pmv.id);
971
972 pmap->pms.vol_seq_num = udf_rw16(1); /* no multi-volume */
973 pmap->pms.part_num = udf_rw16(phys_part);
974
975 pmap->pms.packet_len = udf_rw16(layout.sparable_blockingnr);
976 pmap->pms.st_size = udf_rw32(sparable_bytes);
977
978 /* enter spare tables */
979 st_pos = &pmap->pms.st_loc[0];
980 *st_pos++ = udf_rw32(layout.spt_1);
981 *st_pos++ = udf_rw32(layout.spt_2);
982
983 num = 2;
984 if (layout.spt_2 == 0) num--;
985 if (layout.spt_1 == 0) num--;
986 pmap->pms.n_st = num; /* 8 bit */
987
988 /* the vtop_offset needs to explicitly set since there is no phys. */
989 context.vtop [log_part] = phys_part;
990 context.vtop_tp [log_part] = UDF_VTOP_TYPE_SPARABLE;
991 context.vtop_offset[log_part] = layout.part_start_lba;
992 context.part_size[log_part] = layout.part_size_lba;
993 context.part_free[log_part] = layout.part_size_lba;
994
995 /* increment number of partitions and length */
996 logvol->n_pm = udf_rw32(log_part + 1);
997 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmaps_size);
998
999 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmaps_size;
1000 logvol->tag.desc_crc_len = udf_rw16(crclen);
1001 }
1002
1003
1004 int
udf_create_sparing_tabled(void)1005 udf_create_sparing_tabled(void)
1006 {
1007 struct udf_sparing_table *spt;
1008 struct spare_map_entry *sme;
1009 uint32_t loc, cnt;
1010 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1011
1012 spt = calloc(context.sector_size, layout.sparing_table_dscr_lbas);
1013 if (spt == NULL)
1014 return ENOMEM;
1015
1016 /* a sparing table descriptor is a whole sparable_blockingnr sectors */
1017 udf_inittag(&spt->tag, TAGID_SPARING_TABLE, /* loc */ 0);
1018
1019 udf_set_regid(&spt->id, "*UDF Sparing Table");
1020 udf_add_udf_regid(&spt->id);
1021
1022 spt->rt_l = udf_rw16(layout.sparable_blocks);
1023 spt->seq_num = udf_rw32(0); /* first generation */
1024
1025 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
1026 sme = &spt->entries[cnt];
1027 loc = layout.sparable_area + cnt * layout.sparable_blockingnr;
1028 sme->org = udf_rw32(0xffffffff); /* open for reloc */
1029 sme->map = udf_rw32(loc);
1030 }
1031
1032 /* calculate crc len for actual size */
1033 crclen = sizeof(struct udf_sparing_table) - UDF_DESC_TAG_LENGTH;
1034 crclen += (layout.sparable_blocks-1) * sizeof(struct spare_map_entry);
1035 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1036 spt->tag.desc_crc_len = udf_rw16((uint16_t)crclen);
1037
1038 context.sparing_table = spt;
1039
1040 return 0;
1041 }
1042
1043
1044 static void
udf_add_logvol_part_meta(uint16_t phys_part)1045 udf_add_logvol_part_meta(uint16_t phys_part)
1046 {
1047 union udf_pmap *pmap;
1048 struct logvol_desc *logvol = context.logical_vol;
1049 uint8_t *pmap_pos;
1050 uint32_t pmapv_size, log_part;
1051 uint16_t crclen;
1052
1053 log_part = udf_rw32(logvol->n_pm);
1054 pmap_pos = logvol->maps + udf_rw32(logvol->mt_l);
1055 pmapv_size = sizeof(struct part_map_2);
1056
1057 pmap = (union udf_pmap *) pmap_pos;
1058 pmap->pmm.type = 2;
1059 pmap->pmm.len = pmapv_size;
1060
1061 udf_set_regid(&pmap->pmm.id, "*UDF Metadata Partition");
1062 udf_add_udf_regid(&pmap->pmm.id);
1063
1064 pmap->pmm.vol_seq_num = udf_rw16(1); /* no multi-volume */
1065 pmap->pmm.part_num = udf_rw16(phys_part);
1066
1067 /* fill in meta data file(s) and alloc/alignment unit sizes */
1068 pmap->pmm.meta_file_lbn = udf_rw32(layout.meta_file);
1069 pmap->pmm.meta_mirror_file_lbn = udf_rw32(layout.meta_mirror);
1070 pmap->pmm.meta_bitmap_file_lbn = udf_rw32(layout.meta_bitmap);
1071 pmap->pmm.alloc_unit_size = udf_rw32(layout.meta_blockingnr);
1072 pmap->pmm.alignment_unit_size = udf_rw16(layout.meta_alignment);
1073 pmap->pmm.flags = 0; /* METADATA_DUPLICATED */
1074
1075 context.vtop [log_part] = phys_part;
1076 context.vtop_tp [log_part] = UDF_VTOP_TYPE_META;
1077 context.vtop_offset[log_part] =
1078 context.vtop_offset[phys_part] + layout.meta_part_start_lba;
1079 context.part_size[log_part] = layout.meta_part_size_lba;
1080 context.part_free[log_part] = layout.meta_part_size_lba;
1081
1082 /* increment number of partitions and length */
1083 logvol->n_pm = udf_rw32(log_part + 1);
1084 logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size);
1085
1086 crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size;
1087 logvol->tag.desc_crc_len = udf_rw16(crclen);
1088 }
1089
1090
1091 int
udf_create_logical_dscr(int format_flags)1092 udf_create_logical_dscr(int format_flags)
1093 {
1094 int error;
1095
1096 if ((error = udf_create_base_logical_dscr()))
1097 return error;
1098
1099 /* we pass data_part for there might be a read-only part one day */
1100 if (format_flags & FORMAT_SPARABLE) {
1101 /* sparable partition mapping has no physical mapping */
1102 udf_add_logvol_part_sparable(context.data_part);
1103 } else {
1104 udf_add_logvol_part_physical(context.data_part);
1105 }
1106
1107 if (format_flags & FORMAT_VAT) {
1108 /* add VAT virtual mapping; reflects on datapart */
1109 udf_add_logvol_part_virtual(context.data_part);
1110 }
1111 if (format_flags & FORMAT_META) {
1112 /* add META data mapping; reflects on datapart */
1113 udf_add_logvol_part_meta(context.data_part);
1114 }
1115
1116 return 0;
1117 }
1118
1119
1120 int
udf_create_impvold(char * field1,char * field2,char * field3)1121 udf_create_impvold(char *field1, char *field2, char *field3)
1122 {
1123 struct impvol_desc *ivd;
1124 struct udf_lv_info *lvi;
1125 uint16_t crclen;
1126
1127 ivd = calloc(1, context.sector_size);
1128 if (ivd == NULL)
1129 return ENOMEM;
1130 lvi = &ivd->_impl_use.lv_info;
1131
1132 udf_inittag(&ivd->tag, TAGID_IMP_VOL, /* loc */ 0);
1133 ivd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++;
1134
1135 udf_set_regid(&ivd->impl_id, "*UDF LV Info");
1136 udf_add_udf_regid(&ivd->impl_id);
1137
1138 /* fill in UDF specific part */
1139 udf_osta_charset(&lvi->lvi_charset);
1140 udf_encode_osta_id(lvi->logvol_id, 128, context.logvol_name);
1141
1142 udf_encode_osta_id(lvi->lvinfo1, 36, field1);
1143 udf_encode_osta_id(lvi->lvinfo2, 36, field2);
1144 udf_encode_osta_id(lvi->lvinfo3, 36, field3);
1145
1146 udf_set_regid(&lvi->impl_id, context.impl_name);
1147 udf_add_impl_regid(&lvi->impl_id);
1148
1149 crclen = sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH;
1150 ivd->tag.desc_crc_len = udf_rw16(crclen);
1151
1152 context.implementation = ivd;
1153
1154 return 0;
1155 }
1156
1157
1158 /* XXX might need to be sanitised a bit later */
1159 void
udf_update_lvintd(int type)1160 udf_update_lvintd(int type)
1161 {
1162 struct logvol_int_desc *lvid;
1163 struct udf_logvol_info *lvinfo;
1164 struct logvol_desc *logvol;
1165 uint32_t *pos;
1166 uint32_t cnt, l_iu, num_partmappings;
1167 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1168
1169 lvid = context.logvol_integrity;
1170 logvol = context.logical_vol;
1171
1172 assert(lvid);
1173 assert(logvol);
1174
1175 lvid->integrity_type = udf_rw32(type);
1176
1177 num_partmappings = udf_rw32(logvol->n_pm);
1178
1179 udf_set_timestamp_now(&lvid->time);
1180
1181 lvinfo = (struct udf_logvol_info *)
1182 (lvid->tables + num_partmappings * 2);
1183 udf_set_regid(&lvinfo->impl_id, context.impl_name);
1184 udf_add_impl_regid(&lvinfo->impl_id);
1185
1186 lvinfo->num_files = udf_rw32(context.num_files);
1187 lvinfo->num_directories = udf_rw32(context.num_directories);
1188
1189 lvid->lvint_next_unique_id = udf_rw64(context.unique_id);
1190
1191 /* XXX sane enough ? */
1192 lvinfo->min_udf_readver = udf_rw16(context.min_udf);
1193 lvinfo->min_udf_writever = udf_rw16(context.min_udf);
1194 lvinfo->max_udf_writever = udf_rw16(context.max_udf);
1195
1196 lvid->num_part = udf_rw32(num_partmappings);
1197
1198 /* no impl. use needed */
1199 l_iu = sizeof(struct udf_logvol_info);
1200 lvid->l_iu = udf_rw32(l_iu);
1201
1202 pos = &lvid->tables[0];
1203 for (cnt = 0; cnt < num_partmappings; cnt++) {
1204 *pos++ = udf_rw32(context.part_free[cnt]);
1205 }
1206 for (cnt = 0; cnt < num_partmappings; cnt++) {
1207 *pos++ = udf_rw32(context.part_size[cnt]);
1208 }
1209
1210 crclen = sizeof(struct logvol_int_desc) -4 -UDF_DESC_TAG_LENGTH + l_iu;
1211 crclen += num_partmappings * 2 * 4;
1212 /* XXX ensure crclen doesn't exceed UINT16_MAX ? */
1213 lvid->tag.desc_crc_len = udf_rw16(crclen);
1214
1215 context.logvol_info = lvinfo;
1216 }
1217
1218
1219 int
udf_create_lvintd(int type)1220 udf_create_lvintd(int type)
1221 {
1222 struct logvol_int_desc *lvid;
1223
1224 lvid = calloc(1, context.sector_size);
1225 if (lvid == NULL)
1226 return ENOMEM;
1227
1228 udf_inittag(&lvid->tag, TAGID_LOGVOL_INTEGRITY, /* loc */ 0);
1229
1230 context.logvol_integrity = lvid;
1231
1232 udf_update_lvintd(type);
1233
1234 return 0;
1235 }
1236
1237
1238 int
udf_create_fsd(void)1239 udf_create_fsd(void)
1240 {
1241 struct fileset_desc *fsd;
1242 uint16_t crclen;
1243
1244 fsd = calloc(1, context.sector_size);
1245 if (fsd == NULL)
1246 return ENOMEM;
1247
1248 udf_inittag(&fsd->tag, TAGID_FSD, /* loc */ 0);
1249
1250 udf_set_timestamp_now(&fsd->time);
1251 fsd->ichg_lvl = udf_rw16(3); /* UDF 2.3.2.1 */
1252 fsd->max_ichg_lvl = udf_rw16(3); /* UDF 2.3.2.2 */
1253
1254 fsd->charset_list = udf_rw32(1); /* only CS0 */
1255 fsd->max_charset_list = udf_rw32(1); /* only CS0 */
1256
1257 fsd->fileset_num = udf_rw32(0); /* only one fsd */
1258 fsd->fileset_desc_num = udf_rw32(0); /* origional */
1259
1260 udf_osta_charset(&fsd->logvol_id_charset);
1261 udf_encode_osta_id(fsd->logvol_id, 128, context.logvol_name);
1262
1263 udf_osta_charset(&fsd->fileset_charset);
1264 udf_encode_osta_id(fsd->fileset_id, 32, context.fileset_name);
1265
1266 /* copyright file and abstract file names obmitted */
1267
1268 fsd->rootdir_icb.len = udf_rw32(context.sector_size);
1269 fsd->rootdir_icb.loc.lb_num = udf_rw32(layout.rootdir);
1270 fsd->rootdir_icb.loc.part_num = udf_rw16(context.metadata_part);
1271
1272 udf_set_regid(&fsd->domain_id, "*OSTA UDF Compliant");
1273 udf_add_domain_regid(&fsd->domain_id);
1274
1275 /* next_ex stays zero */
1276 /* no system streamdirs yet */
1277
1278 crclen = sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH;
1279 fsd->tag.desc_crc_len = udf_rw16(crclen);
1280
1281 context.fileset_desc = fsd;
1282
1283 return 0;
1284 }
1285
1286
1287 int
udf_create_space_bitmap(uint32_t dscr_size,uint32_t part_size_lba,struct space_bitmap_desc ** sbdp)1288 udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba,
1289 struct space_bitmap_desc **sbdp)
1290 {
1291 struct space_bitmap_desc *sbd;
1292 uint32_t cnt;
1293 uint16_t crclen;
1294
1295 *sbdp = NULL;
1296 sbd = calloc(context.sector_size, dscr_size);
1297 if (sbd == NULL)
1298 return ENOMEM;
1299
1300 udf_inittag(&sbd->tag, TAGID_SPACE_BITMAP, /* loc */ 0);
1301
1302 sbd->num_bits = udf_rw32(part_size_lba);
1303 sbd->num_bytes = udf_rw32((part_size_lba + 7)/8);
1304
1305 /* fill space with 0xff to indicate free */
1306 for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
1307 sbd->data[cnt] = 0xff;
1308
1309 /* set crc to only cover the header (UDF 2.3.1.2, 2.3.8.1) */
1310 crclen = sizeof(struct space_bitmap_desc) -1 - UDF_DESC_TAG_LENGTH;
1311 sbd->tag.desc_crc_len = udf_rw16(crclen);
1312
1313 *sbdp = sbd;
1314 return 0;
1315 }
1316
1317
1318 /* --------------------------------------------------------------------- */
1319
1320 int
udf_register_bad_block(uint32_t location)1321 udf_register_bad_block(uint32_t location)
1322 {
1323 struct udf_sparing_table *spt;
1324 struct spare_map_entry *sme, *free_sme;
1325 uint32_t cnt;
1326
1327 spt = context.sparing_table;
1328 if (spt == NULL) {
1329 printf("internal error: adding bad block to non sparable\n");
1330 return EINVAL;
1331 }
1332
1333 /* find us a free spare map entry */
1334 free_sme = NULL;
1335 for (cnt = 0; cnt < layout.sparable_blocks; cnt++) {
1336 sme = &spt->entries[cnt];
1337 /* if we are allready in it, bail out */
1338 if (udf_rw32(sme->org) == location)
1339 return 0;
1340 if (udf_rw32(sme->org) == 0xffffffff) {
1341 free_sme = sme;
1342 break;
1343 }
1344 }
1345 if (free_sme == NULL) {
1346 printf("Disc relocation blocks full; disc too damanged\n");
1347 return EINVAL;
1348 }
1349 free_sme->org = udf_rw32(location);
1350
1351 return 0;
1352 }
1353
1354
1355 void
udf_mark_allocated(uint32_t start_lb,int partnr,uint32_t blocks)1356 udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks)
1357 {
1358 union dscrptr *dscr;
1359 uint8_t *bpos;
1360 uint32_t cnt, bit;
1361
1362 /* account for space used on underlying partition */
1363 context.part_free[partnr] -= blocks;
1364 #ifdef DEBUG
1365 printf("mark allocated : partnr %d, start_lb %d for %d blocks\n",
1366 partnr, start_lb, blocks);
1367 #endif
1368
1369 switch (context.vtop_tp[partnr]) {
1370 case UDF_VTOP_TYPE_VIRT:
1371 /* nothing */
1372 break;
1373 case UDF_VTOP_TYPE_PHYS:
1374 case UDF_VTOP_TYPE_SPARABLE:
1375 case UDF_VTOP_TYPE_META:
1376 if (context.part_unalloc_bits[context.vtop[partnr]] == NULL) {
1377 context.part_free[partnr] = 0;
1378 break;
1379 }
1380 #ifdef DEBUG
1381 printf("Marking %d+%d as used\n", start_lb, blocks);
1382 #endif
1383 dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]);
1384 for (cnt = start_lb; cnt < start_lb + blocks; cnt++) {
1385 bpos = &dscr->sbd.data[cnt / 8];
1386 bit = cnt % 8;
1387 *bpos &= ~(1<< bit);
1388 }
1389 break;
1390 default:
1391 printf("internal error: reality check in mapping type %d\n",
1392 context.vtop_tp[partnr]);
1393 exit(EXIT_FAILURE);
1394 }
1395 }
1396
1397
1398 void
udf_advance_uniqueid(void)1399 udf_advance_uniqueid(void)
1400 {
1401 /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
1402 context.unique_id++;
1403 if (context.unique_id < 0x10)
1404 context.unique_id = 0x10;
1405 }
1406
1407 /* --------------------------------------------------------------------- */
1408
1409 static void
unix_to_udf_name(char * result,uint8_t * result_len,char const * name,int name_len,struct charspec * chsp)1410 unix_to_udf_name(char *result, uint8_t *result_len,
1411 char const *name, int name_len, struct charspec *chsp)
1412 {
1413 uint16_t *raw_name;
1414 uint16_t *outchp;
1415 const char *inchp;
1416 const char *osta_id = "OSTA Compressed Unicode";
1417 int udf_chars, is_osta_typ0, bits;
1418 size_t cnt;
1419
1420 /* allocate temporary unicode-16 buffer */
1421 raw_name = malloc(1024);
1422 assert(raw_name);
1423
1424 /* convert utf8 to unicode-16 */
1425 *raw_name = 0;
1426 inchp = name;
1427 outchp = raw_name;
1428 bits = 8;
1429 for (cnt = name_len, udf_chars = 0; cnt;) {
1430 *outchp = wget_utf8(&inchp, &cnt);
1431 if (*outchp > 0xff)
1432 bits=16;
1433 outchp++;
1434 udf_chars++;
1435 }
1436 /* null terminate just in case */
1437 *outchp++ = 0;
1438
1439 is_osta_typ0 = (chsp->type == 0);
1440 is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
1441 if (is_osta_typ0) {
1442 udf_chars = udf_CompressUnicode(udf_chars, bits,
1443 (unicode_t *) raw_name,
1444 (byte *) result);
1445 } else {
1446 printf("unix to udf name: no CHSP0 ?\n");
1447 /* XXX assume 8bit char length byte latin-1 */
1448 *result++ = 8; udf_chars = 1;
1449 strncpy(result, name + 1, name_len);
1450 udf_chars += name_len;
1451 }
1452 *result_len = udf_chars;
1453 free(raw_name);
1454 }
1455
1456
1457 #define UDF_SYMLINKBUFLEN (64*1024) /* picked */
1458 int
udf_encode_symlink(uint8_t ** pathbufp,uint32_t * pathlenp,char * target)1459 udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target)
1460 {
1461 struct charspec osta_charspec;
1462 struct pathcomp pathcomp;
1463 char *pathbuf, *pathpos, *compnamepos;
1464 // char *mntonname;
1465 // int mntonnamelen;
1466 int pathlen, len, compnamelen;
1467 int error;
1468
1469 /* process `target' to an UDF structure */
1470 pathbuf = malloc(UDF_SYMLINKBUFLEN);
1471 assert(pathbuf);
1472
1473 *pathbufp = NULL;
1474 *pathlenp = 0;
1475
1476 pathpos = pathbuf;
1477 pathlen = 0;
1478 udf_osta_charset(&osta_charspec);
1479
1480 if (*target == '/') {
1481 /* symlink starts from the root */
1482 len = UDF_PATH_COMP_SIZE;
1483 memset(&pathcomp, 0, len);
1484 pathcomp.type = UDF_PATH_COMP_ROOT;
1485
1486 #if 0
1487 /* XXX how to check for in makefs? */
1488 /* check if its mount-point relative! */
1489 mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1490 mntonnamelen = strlen(mntonname);
1491 if (strlen(target) >= mntonnamelen) {
1492 if (strncmp(target, mntonname, mntonnamelen) == 0) {
1493 pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
1494 target += mntonnamelen;
1495 }
1496 } else {
1497 target++;
1498 }
1499 #else
1500 target++;
1501 #endif
1502
1503 memcpy(pathpos, &pathcomp, len);
1504 pathpos += len;
1505 pathlen += len;
1506 }
1507
1508 error = 0;
1509 while (*target) {
1510 /* ignore multiple '/' */
1511 while (*target == '/') {
1512 target++;
1513 }
1514 if (!*target)
1515 break;
1516
1517 /* extract component name */
1518 compnamelen = 0;
1519 compnamepos = target;
1520 while ((*target) && (*target != '/')) {
1521 target++;
1522 compnamelen++;
1523 }
1524
1525 /* just trunc if too long ?? (security issue) */
1526 if (compnamelen >= 127) {
1527 error = ENAMETOOLONG;
1528 break;
1529 }
1530
1531 /* convert unix name to UDF name */
1532 len = sizeof(struct pathcomp);
1533 memset(&pathcomp, 0, len);
1534 pathcomp.type = UDF_PATH_COMP_NAME;
1535 len = UDF_PATH_COMP_SIZE;
1536
1537 if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
1538 pathcomp.type = UDF_PATH_COMP_PARENTDIR;
1539 if ((compnamelen == 1) && (*compnamepos == '.'))
1540 pathcomp.type = UDF_PATH_COMP_CURDIR;
1541
1542 if (pathcomp.type == UDF_PATH_COMP_NAME) {
1543 unix_to_udf_name(
1544 (char *) &pathcomp.ident, &pathcomp.l_ci,
1545 compnamepos, compnamelen,
1546 &osta_charspec);
1547 len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
1548 }
1549
1550 if (pathlen + len >= UDF_SYMLINKBUFLEN) {
1551 error = ENAMETOOLONG;
1552 break;
1553 }
1554
1555 memcpy(pathpos, &pathcomp, len);
1556 pathpos += len;
1557 pathlen += len;
1558 }
1559
1560 if (error) {
1561 /* aparently too big */
1562 free(pathbuf);
1563 return error;
1564 }
1565
1566 /* return status of symlink contents writeout */
1567 *pathbufp = (uint8_t *) pathbuf;
1568 *pathlenp = pathlen;
1569
1570 return 0;
1571
1572 }
1573 #undef UDF_SYMLINKBUFLEN
1574
1575
1576 int
udf_fidsize(struct fileid_desc * fid)1577 udf_fidsize(struct fileid_desc *fid)
1578 {
1579 uint32_t size;
1580
1581 if (udf_rw16(fid->tag.id) != TAGID_FID)
1582 errx(EINVAL, "got udf_fidsize on non FID");
1583
1584 size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
1585 size = (size + 3) & ~3;
1586
1587 return size;
1588 }
1589
1590
1591 int
udf_create_parentfid(struct fileid_desc * fid,struct long_ad * parent)1592 udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent)
1593 {
1594 /* the size of an empty FID is 38 but needs to be a multiple of 4 */
1595 int fidsize = 40;
1596
1597 udf_inittag(&fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num));
1598 fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
1599 fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
1600 fid->icb = *parent;
1601 fid->icb.longad_uniqueid = parent->longad_uniqueid;
1602 fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1603
1604 /* we have to do the fid here explicitly for simplicity */
1605 udf_validate_tag_and_crc_sums((union dscrptr *) fid);
1606
1607 return fidsize;
1608 }
1609
1610
1611 void
udf_create_fid(uint32_t diroff,struct fileid_desc * fid,char * name,int file_char,struct long_ad * ref)1612 udf_create_fid(uint32_t diroff, struct fileid_desc *fid, char *name,
1613 int file_char, struct long_ad *ref)
1614 {
1615 struct charspec osta_charspec;
1616 uint32_t endfid;
1617 uint32_t fidsize, lb_rest;
1618
1619 memset(fid, 0, sizeof(*fid));
1620 udf_inittag(&fid->tag, TAGID_FID, udf_rw32(ref->loc.lb_num));
1621 fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
1622 fid->file_char = file_char;
1623 fid->l_iu = udf_rw16(0);
1624 fid->icb = *ref;
1625 fid->icb.longad_uniqueid = ref->longad_uniqueid;
1626
1627 udf_osta_charset(&osta_charspec);
1628 unix_to_udf_name((char *) fid->data, &fid->l_fi, name, strlen(name),
1629 &osta_charspec);
1630
1631 /*
1632 * OK, tricky part: we need to pad so the next descriptor header won't
1633 * cross the sector boundary
1634 */
1635 endfid = diroff + udf_fidsize(fid);
1636 lb_rest = context.sector_size - (endfid % context.sector_size);
1637 if (lb_rest < sizeof(struct desc_tag)) {
1638 /* add at least 32 */
1639 fid->l_iu = udf_rw16(32);
1640 udf_set_regid((struct regid *) fid->data, context.impl_name);
1641 udf_add_impl_regid((struct regid *) fid->data);
1642
1643 unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu),
1644 &fid->l_fi, name, strlen(name), &osta_charspec);
1645 }
1646
1647 fidsize = udf_fidsize(fid);
1648 fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1649
1650 /* make sure the header sums stays correct */
1651 udf_validate_tag_and_crc_sums((union dscrptr *)fid);
1652 }
1653
1654
1655 static void
udf_append_parentfid(union dscrptr * dscr,struct long_ad * parent_icb)1656 udf_append_parentfid(union dscrptr *dscr, struct long_ad *parent_icb)
1657 {
1658 struct file_entry *fe;
1659 struct extfile_entry *efe;
1660 struct fileid_desc *fid;
1661 uint32_t l_ea;
1662 uint32_t fidsize, crclen;
1663 uint8_t *bpos, *data;
1664
1665 fe = NULL;
1666 efe = NULL;
1667 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
1668 fe = &dscr->fe;
1669 data = fe->data;
1670 l_ea = udf_rw32(fe->l_ea);
1671 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
1672 efe = &dscr->efe;
1673 data = efe->data;
1674 l_ea = udf_rw32(efe->l_ea);
1675 } else {
1676 errx(1, "Bad tag passed to udf_append_parentfid");
1677 }
1678
1679 /* create '..' */
1680 bpos = data + l_ea;
1681 fid = (struct fileid_desc *) bpos;
1682 fidsize = udf_create_parentfid(fid, parent_icb);
1683
1684 /* record fidlength information */
1685 if (fe) {
1686 fe->inf_len = udf_rw64(fidsize);
1687 fe->l_ad = udf_rw32(fidsize);
1688 fe->logblks_rec = udf_rw64(0); /* intern */
1689 crclen = sizeof(struct file_entry);
1690 } else {
1691 efe->inf_len = udf_rw64(fidsize);
1692 efe->obj_size = udf_rw64(fidsize);
1693 efe->l_ad = udf_rw32(fidsize);
1694 efe->logblks_rec = udf_rw64(0); /* intern */
1695 crclen = sizeof(struct extfile_entry);
1696 }
1697 crclen -= 1 + UDF_DESC_TAG_LENGTH;
1698 crclen += l_ea + fidsize;
1699 dscr->tag.desc_crc_len = udf_rw16(crclen);
1700
1701 /* make sure the header sums stays correct */
1702 udf_validate_tag_and_crc_sums(dscr);
1703 }
1704
1705
1706
1707 /*
1708 * Order of extended attributes :
1709 * ECMA 167 EAs
1710 * Non block aligned Implementation Use EAs
1711 * Block aligned Implementation Use EAs (not in newfs_udf)
1712 * Application Use EAs (not in newfs_udf)
1713 *
1714 * no checks for doubles, must be called in-order
1715 */
1716 static void
udf_extattr_append_internal(union dscrptr * dscr,struct extattr_entry * extattr)1717 udf_extattr_append_internal(union dscrptr *dscr, struct extattr_entry *extattr)
1718 {
1719 struct file_entry *fe;
1720 struct extfile_entry *efe;
1721 struct extattrhdr_desc *extattrhdr;
1722 struct impl_extattr_entry *implext;
1723 uint32_t impl_attr_loc, appl_attr_loc, l_ea, a_l, exthdr_len;
1724 uint32_t *l_eap, l_ad;
1725 uint16_t *spos;
1726 uint8_t *bpos, *data;
1727
1728 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
1729 fe = &dscr->fe;
1730 data = fe->data;
1731 l_eap = &fe->l_ea;
1732 l_ad = udf_rw32(fe->l_ad);
1733 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
1734 efe = &dscr->efe;
1735 data = efe->data;
1736 l_eap = &efe->l_ea;
1737 l_ad = udf_rw32(efe->l_ad);
1738 } else {
1739 errx(1, "Bad tag passed to udf_extattr_append_internal");
1740 }
1741
1742 /* should have a header! */
1743 extattrhdr = (struct extattrhdr_desc *) data;
1744 l_ea = udf_rw32(*l_eap);
1745 if (l_ea == 0) {
1746 #if !defined(NDEBUG) && defined(__minix)
1747 assert(l_ad == 0);
1748 #else
1749 if (l_ad != 0) {
1750 printf("%s:%d: l_ad != 0\n", __func__, __LINE__);
1751 abort();
1752 }
1753 #endif /* !defined(NDEBUG) && defined(__minix) */
1754 /* create empty extended attribute header */
1755 exthdr_len = sizeof(struct extattrhdr_desc);
1756
1757 udf_inittag(&extattrhdr->tag, TAGID_EXTATTR_HDR, /* loc */ 0);
1758 extattrhdr->impl_attr_loc = udf_rw32(exthdr_len);
1759 extattrhdr->appl_attr_loc = udf_rw32(exthdr_len);
1760 extattrhdr->tag.desc_crc_len = udf_rw16(8);
1761
1762 /* record extended attribute header length */
1763 l_ea = exthdr_len;
1764 *l_eap = udf_rw32(l_ea);
1765 }
1766
1767 /* extract locations */
1768 impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc);
1769 appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc);
1770 if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1771 impl_attr_loc = l_ea;
1772 if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
1773 appl_attr_loc = l_ea;
1774
1775 /* Ecma 167 EAs */
1776 if (udf_rw32(extattr->type) < 2048) {
1777 assert(impl_attr_loc == l_ea);
1778 assert(appl_attr_loc == l_ea);
1779 }
1780
1781 /* implementation use extended attributes */
1782 if (udf_rw32(extattr->type) == 2048) {
1783 assert(appl_attr_loc == l_ea);
1784
1785 /* calculate and write extended attribute header checksum */
1786 implext = (struct impl_extattr_entry *) extattr;
1787 assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */
1788 spos = (uint16_t *) implext->data;
1789 *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
1790 }
1791
1792 /* application use extended attributes */
1793 assert(udf_rw32(extattr->type) != 65536);
1794 assert(appl_attr_loc == l_ea);
1795
1796 /* append the attribute at the end of the current space */
1797 bpos = data + udf_rw32(*l_eap);
1798 a_l = udf_rw32(extattr->a_l);
1799
1800 /* update impl. attribute locations */
1801 if (udf_rw32(extattr->type) < 2048) {
1802 impl_attr_loc = l_ea + a_l;
1803 appl_attr_loc = l_ea + a_l;
1804 }
1805 if (udf_rw32(extattr->type) == 2048) {
1806 appl_attr_loc = l_ea + a_l;
1807 }
1808
1809 /* copy and advance */
1810 memcpy(bpos, extattr, a_l);
1811 l_ea += a_l;
1812 *l_eap = udf_rw32(l_ea);
1813
1814 /* do the `dance` again backwards */
1815 if (context.dscrver != 2) {
1816 if (impl_attr_loc == l_ea)
1817 impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT;
1818 if (appl_attr_loc == l_ea)
1819 appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT;
1820 }
1821
1822 /* store offsets */
1823 extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc);
1824 extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc);
1825
1826 /* make sure the header sums stays correct */
1827 udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
1828 }
1829
1830
1831 int
udf_create_new_fe(struct file_entry ** fep,int file_type,struct stat * st)1832 udf_create_new_fe(struct file_entry **fep, int file_type, struct stat *st)
1833 {
1834 struct file_entry *fe;
1835 struct icb_tag *icb;
1836 struct timestamp birthtime;
1837 struct filetimes_extattr_entry *ft_extattr;
1838 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1839 uint16_t icbflags;
1840
1841 *fep = NULL;
1842 fe = calloc(1, context.sector_size);
1843 if (fe == NULL)
1844 return ENOMEM;
1845
1846 udf_inittag(&fe->tag, TAGID_FENTRY, /* loc */ 0);
1847 icb = &fe->icbtag;
1848
1849 /*
1850 * Always use strategy type 4 unless on WORM wich we don't support
1851 * (yet). Fill in defaults and set for internal allocation of data.
1852 */
1853 icb->strat_type = udf_rw16(4);
1854 icb->max_num_entries = udf_rw16(1);
1855 icb->file_type = file_type; /* 8 bit */
1856 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1857
1858 fe->perm = udf_rw32(0x7fff); /* all is allowed */
1859 fe->link_cnt = udf_rw16(0); /* explicit setting */
1860
1861 fe->ckpoint = udf_rw32(1); /* user supplied file version */
1862
1863 udf_set_timestamp_now(&birthtime);
1864 udf_set_timestamp_now(&fe->atime);
1865 udf_set_timestamp_now(&fe->attrtime);
1866 udf_set_timestamp_now(&fe->mtime);
1867
1868 /* set attributes */
1869 if (st) {
1870 #if !HAVE_NBTOOL_CONFIG_H
1871 udf_set_timestamp(&birthtime, st->st_birthtime);
1872 #else
1873 udf_set_timestamp(&birthtime, 0);
1874 #endif
1875 udf_set_timestamp(&fe->atime, st->st_atime);
1876 udf_set_timestamp(&fe->attrtime, st->st_ctime);
1877 udf_set_timestamp(&fe->mtime, st->st_mtime);
1878 fe->uid = udf_rw32(st->st_uid);
1879 fe->gid = udf_rw32(st->st_gid);
1880
1881 fe->perm = unix_mode_to_udf_perm(st->st_mode);
1882
1883 icbflags = udf_rw16(fe->icbtag.flags);
1884 icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
1885 icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
1886 icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
1887 if (st->st_mode & S_ISUID)
1888 icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
1889 if (st->st_mode & S_ISGID)
1890 icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
1891 if (st->st_mode & S_ISVTX)
1892 icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
1893 fe->icbtag.flags = udf_rw16(icbflags);
1894 }
1895
1896 udf_set_regid(&fe->imp_id, context.impl_name);
1897 udf_add_impl_regid(&fe->imp_id);
1898 fe->unique_id = udf_rw64(context.unique_id);
1899 udf_advance_uniqueid();
1900
1901 fe->l_ea = udf_rw32(0);
1902
1903 /* create extended attribute to record our creation time */
1904 ft_extattr = calloc(1, UDF_FILETIMES_ATTR_SIZE(1));
1905 ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO);
1906 ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */
1907 ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1));
1908 ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */
1909 ft_extattr->existence = UDF_FILETIMES_FILE_CREATION;
1910 ft_extattr->times[0] = birthtime;
1911
1912 udf_extattr_append_internal((union dscrptr *) fe,
1913 (struct extattr_entry *) ft_extattr);
1914 free(ft_extattr);
1915
1916 /* record fidlength information */
1917 fe->inf_len = udf_rw64(0);
1918 fe->l_ad = udf_rw32(0);
1919 fe->logblks_rec = udf_rw64(0); /* intern */
1920
1921 crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
1922 crclen += udf_rw32(fe->l_ea);
1923
1924 /* make sure the header sums stays correct */
1925 fe->tag.desc_crc_len = udf_rw16(crclen);
1926 udf_validate_tag_and_crc_sums((union dscrptr *) fe);
1927
1928 *fep = fe;
1929 return 0;
1930 }
1931
1932
1933 int
udf_create_new_efe(struct extfile_entry ** efep,int file_type,struct stat * st)1934 udf_create_new_efe(struct extfile_entry **efep, int file_type, struct stat *st)
1935 {
1936 struct extfile_entry *efe;
1937 struct icb_tag *icb;
1938 uint32_t crclen; /* XXX: should be 16; need to detect overflow */
1939 uint16_t icbflags;
1940
1941 *efep = NULL;
1942 efe = calloc(1, context.sector_size);
1943 if (efe == NULL)
1944 return ENOMEM;
1945
1946 udf_inittag(&efe->tag, TAGID_EXTFENTRY, /* loc */ 0);
1947 icb = &efe->icbtag;
1948
1949 /*
1950 * Always use strategy type 4 unless on WORM wich we don't support
1951 * (yet). Fill in defaults and set for internal allocation of data.
1952 */
1953 icb->strat_type = udf_rw16(4);
1954 icb->max_num_entries = udf_rw16(1);
1955 icb->file_type = file_type; /* 8 bit */
1956 icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1957
1958 efe->perm = udf_rw32(0x7fff); /* all is allowed */
1959 efe->link_cnt = udf_rw16(0); /* explicit setting */
1960
1961 efe->ckpoint = udf_rw32(1); /* user supplied file version */
1962
1963 udf_set_timestamp_now(&efe->ctime);
1964 udf_set_timestamp_now(&efe->atime);
1965 udf_set_timestamp_now(&efe->attrtime);
1966 udf_set_timestamp_now(&efe->mtime);
1967
1968 /* set attributes */
1969 if (st) {
1970 #if !HAVE_NBTOOL_CONFIG_H
1971 udf_set_timestamp(&efe->ctime, st->st_birthtime);
1972 #else
1973 udf_set_timestamp(&efe->ctime, 0);
1974 #endif
1975 udf_set_timestamp(&efe->atime, st->st_atime);
1976 udf_set_timestamp(&efe->attrtime, st->st_ctime);
1977 udf_set_timestamp(&efe->mtime, st->st_mtime);
1978 efe->uid = udf_rw32(st->st_uid);
1979 efe->gid = udf_rw32(st->st_gid);
1980
1981 efe->perm = unix_mode_to_udf_perm(st->st_mode);
1982
1983 icbflags = udf_rw16(efe->icbtag.flags);
1984 icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
1985 icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
1986 icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
1987 if (st->st_mode & S_ISUID)
1988 icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
1989 if (st->st_mode & S_ISGID)
1990 icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
1991 if (st->st_mode & S_ISVTX)
1992 icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
1993 efe->icbtag.flags = udf_rw16(icbflags);
1994 }
1995
1996 udf_set_regid(&efe->imp_id, context.impl_name);
1997 udf_add_impl_regid(&efe->imp_id);
1998
1999 efe->unique_id = udf_rw64(context.unique_id);
2000 udf_advance_uniqueid();
2001
2002 /* record fidlength information */
2003 efe->inf_len = udf_rw64(0);
2004 efe->obj_size = udf_rw64(0);
2005 efe->l_ad = udf_rw32(0);
2006 efe->logblks_rec = udf_rw64(0);
2007
2008 crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
2009
2010 /* make sure the header sums stays correct */
2011 efe->tag.desc_crc_len = udf_rw16(crclen);
2012 udf_validate_tag_and_crc_sums((union dscrptr *) efe);
2013
2014 *efep = efe;
2015 return 0;
2016 }
2017
2018 /* --------------------------------------------------------------------- */
2019
2020 /* for METADATA file appending only */
2021 static void
udf_append_meta_mapping_part_to_efe(struct extfile_entry * efe,struct short_ad * mapping)2022 udf_append_meta_mapping_part_to_efe(struct extfile_entry *efe,
2023 struct short_ad *mapping)
2024 {
2025 struct icb_tag *icb;
2026 uint64_t inf_len, obj_size, logblks_rec;
2027 uint32_t l_ad, l_ea;
2028 uint16_t crclen;
2029 uint8_t *bpos;
2030
2031 inf_len = udf_rw64(efe->inf_len);
2032 obj_size = udf_rw64(efe->obj_size);
2033 logblks_rec = udf_rw64(efe->logblks_rec);
2034 l_ad = udf_rw32(efe->l_ad);
2035 l_ea = udf_rw32(efe->l_ea);
2036 crclen = udf_rw16(efe->tag.desc_crc_len);
2037 icb = &efe->icbtag;
2038
2039 /* set our allocation to shorts if not already done */
2040 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC);
2041
2042 /* append short_ad */
2043 bpos = (uint8_t *) efe->data + l_ea + l_ad;
2044 memcpy(bpos, mapping, sizeof(struct short_ad));
2045
2046 l_ad += sizeof(struct short_ad);
2047 crclen += sizeof(struct short_ad);
2048 inf_len += UDF_EXT_LEN(udf_rw32(mapping->len));
2049 obj_size += UDF_EXT_LEN(udf_rw32(mapping->len));
2050 logblks_rec = UDF_ROUNDUP(inf_len, context.sector_size) /
2051 context.sector_size;
2052
2053 efe->l_ad = udf_rw32(l_ad);
2054 efe->inf_len = udf_rw64(inf_len);
2055 efe->obj_size = udf_rw64(obj_size);
2056 efe->logblks_rec = udf_rw64(logblks_rec);
2057 efe->tag.desc_crc_len = udf_rw16(crclen);
2058 }
2059
2060
2061 /* for METADATA file appending only */
2062 static void
udf_append_meta_mapping_to_efe(struct extfile_entry * efe,uint16_t partnr,uint32_t lb_num,uint64_t len)2063 udf_append_meta_mapping_to_efe(struct extfile_entry *efe,
2064 uint16_t partnr, uint32_t lb_num,
2065 uint64_t len)
2066 {
2067 struct short_ad mapping;
2068 uint64_t max_len, part_len;
2069
2070 /* calculate max length meta allocation sizes */
2071 max_len = UDF_EXT_MAXLEN / context.sector_size; /* in sectors */
2072 max_len = (max_len / layout.meta_blockingnr) * layout.meta_blockingnr;
2073 max_len = max_len * context.sector_size;
2074
2075 memset(&mapping, 0, sizeof(mapping));
2076 while (len) {
2077 part_len = MIN(len, max_len);
2078 mapping.lb_num = udf_rw32(lb_num);
2079 mapping.len = udf_rw32(part_len);
2080
2081 udf_append_meta_mapping_part_to_efe(efe, &mapping);
2082
2083 lb_num += part_len / context.sector_size;
2084 len -= part_len;
2085 }
2086 }
2087
2088
2089 int
udf_create_meta_files(void)2090 udf_create_meta_files(void)
2091 {
2092 struct extfile_entry *efe;
2093 struct long_ad meta_icb;
2094 uint64_t bytes;
2095 uint32_t sector_size;
2096 int filetype, error;
2097
2098 sector_size = context.sector_size;
2099
2100 memset(&meta_icb, 0, sizeof(meta_icb));
2101 meta_icb.len = udf_rw32(sector_size);
2102 meta_icb.loc.part_num = udf_rw16(context.data_part);
2103
2104 /* create metadata file */
2105 meta_icb.loc.lb_num = udf_rw32(layout.meta_file);
2106 filetype = UDF_ICB_FILETYPE_META_MAIN;
2107 error = udf_create_new_efe(&efe, filetype, NULL);
2108 if (error)
2109 return error;
2110 context.meta_file = efe;
2111
2112 /* create metadata mirror file */
2113 meta_icb.loc.lb_num = udf_rw32(layout.meta_mirror);
2114 filetype = UDF_ICB_FILETYPE_META_MIRROR;
2115 error = udf_create_new_efe(&efe, filetype, NULL);
2116 if (error)
2117 return error;
2118 context.meta_mirror = efe;
2119
2120 /* create metadata bitmap file */
2121 meta_icb.loc.lb_num = udf_rw32(layout.meta_bitmap);
2122 filetype = UDF_ICB_FILETYPE_META_BITMAP;
2123 error = udf_create_new_efe(&efe, filetype, NULL);
2124 if (error)
2125 return error;
2126 context.meta_bitmap = efe;
2127
2128 /* patch up files */
2129 context.meta_file->unique_id = udf_rw64(0);
2130 context.meta_mirror->unique_id = udf_rw64(0);
2131 context.meta_bitmap->unique_id = udf_rw64(0);
2132
2133 /* restart unique id */
2134 context.unique_id = 0x10;
2135
2136 /* XXX no support for metadata mirroring yet */
2137 /* insert extents */
2138 efe = context.meta_file;
2139 udf_append_meta_mapping_to_efe(efe, context.data_part,
2140 layout.meta_part_start_lba,
2141 (uint64_t) layout.meta_part_size_lba * sector_size);
2142
2143 efe = context.meta_mirror;
2144 udf_append_meta_mapping_to_efe(efe, context.data_part,
2145 layout.meta_part_start_lba,
2146 (uint64_t) layout.meta_part_size_lba * sector_size);
2147
2148 efe = context.meta_bitmap;
2149 bytes = udf_space_bitmap_len(layout.meta_part_size_lba);
2150 udf_append_meta_mapping_to_efe(efe, context.data_part,
2151 layout.meta_bitmap_space, bytes);
2152
2153 return 0;
2154 }
2155
2156
2157 /* --------------------------------------------------------------------- */
2158
2159 int
udf_create_new_rootdir(union dscrptr ** dscr)2160 udf_create_new_rootdir(union dscrptr **dscr)
2161 {
2162 struct file_entry *fe;
2163 struct extfile_entry *efe;
2164 struct long_ad root_icb;
2165 int filetype, error;
2166
2167 #if defined(__minix)
2168 /* LSC: -Werror=maybe-uninitialized when compiling with -O3 */
2169 fe = NULL;
2170 #endif /*defined(__minix) */
2171 memset(&root_icb, 0, sizeof(root_icb));
2172 root_icb.len = udf_rw32(context.sector_size);
2173 root_icb.loc.lb_num = udf_rw32(layout.rootdir);
2174 root_icb.loc.part_num = udf_rw16(context.metadata_part);
2175
2176 filetype = UDF_ICB_FILETYPE_DIRECTORY;
2177 if (context.dscrver == 2) {
2178 error = udf_create_new_fe(&fe, filetype, NULL);
2179 *dscr = (union dscrptr *) fe;
2180 } else {
2181 error = udf_create_new_efe(&efe, filetype, NULL);
2182 *dscr = (union dscrptr *) efe;
2183 }
2184 if (error)
2185 return error;
2186
2187 /* append '..' */
2188 udf_append_parentfid(*dscr, &root_icb);
2189
2190 /* rootdir has explicit only one link on creation; '..' is no link */
2191 if (context.dscrver == 2) {
2192 fe->link_cnt = udf_rw16(1);
2193 } else {
2194 efe->link_cnt = udf_rw16(1);
2195 }
2196
2197 context.num_directories++;
2198 assert(context.num_directories == 1);
2199
2200 return 0;
2201 }
2202
2203
2204 void
udf_prepend_VAT_file(void)2205 udf_prepend_VAT_file(void)
2206 {
2207 /* old style VAT has no prepend */
2208 if (context.dscrver == 2) {
2209 context.vat_start = 0;
2210 context.vat_size = 0;
2211 return;
2212 }
2213
2214 context.vat_start = offsetof(struct udf_vat, data);
2215 context.vat_size = offsetof(struct udf_vat, data);
2216 }
2217
2218
2219 void
udf_vat_update(uint32_t virt,uint32_t phys)2220 udf_vat_update(uint32_t virt, uint32_t phys)
2221 {
2222 uint32_t *vatpos;
2223 uint32_t new_size;
2224
2225 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
2226 return;
2227
2228 new_size = MAX(context.vat_size,
2229 (context.vat_start + (virt+1)*sizeof(uint32_t)));
2230
2231 if (new_size > context.vat_allocated) {
2232 context.vat_allocated =
2233 UDF_ROUNDUP(new_size, context.sector_size);
2234 context.vat_contents = realloc(context.vat_contents,
2235 context.vat_allocated);
2236 assert(context.vat_contents);
2237 /* XXX could also report error */
2238 }
2239 vatpos = (uint32_t *) (context.vat_contents + context.vat_start);
2240 vatpos[virt] = udf_rw32(phys);
2241
2242 context.vat_size = MAX(context.vat_size,
2243 (context.vat_start + (virt+1)*sizeof(uint32_t)));
2244 }
2245
2246
2247 int
udf_append_VAT_file(void)2248 udf_append_VAT_file(void)
2249 {
2250 struct udf_oldvat_tail *oldvat_tail;
2251 struct udf_vat *vathdr;
2252 int32_t len_diff;
2253
2254 /* new style VAT has VAT LVInt analog in front */
2255 if (context.dscrver == 3) {
2256 /* set up VATv2 descriptor */
2257 vathdr = (struct udf_vat *) context.vat_contents;
2258 vathdr->header_len = udf_rw16(sizeof(struct udf_vat) - 1);
2259 vathdr->impl_use_len = udf_rw16(0);
2260 memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
2261 vathdr->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2262 vathdr->num_files = udf_rw32(context.num_files);
2263 vathdr->num_directories = udf_rw32(context.num_directories);
2264
2265 vathdr->min_udf_readver = udf_rw16(context.min_udf);
2266 vathdr->min_udf_writever = udf_rw16(context.min_udf);
2267 vathdr->max_udf_writever = udf_rw16(context.max_udf);
2268
2269 return 0;
2270 }
2271
2272 /* old style VAT has identifier appended */
2273
2274 /* append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
2275 len_diff = context.vat_allocated - context.vat_size;
2276 assert(len_diff >= 0);
2277 if (len_diff < (int32_t) sizeof(struct udf_oldvat_tail)) {
2278 context.vat_allocated += context.sector_size;
2279 context.vat_contents = realloc(context.vat_contents,
2280 context.vat_allocated);
2281 assert(context.vat_contents);
2282 /* XXX could also report error */
2283 }
2284
2285 oldvat_tail = (struct udf_oldvat_tail *) (context.vat_contents +
2286 context.vat_size);
2287
2288 udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
2289 udf_add_udf_regid(&oldvat_tail->id);
2290 oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
2291
2292 context.vat_size += sizeof(struct udf_oldvat_tail);
2293
2294 return 0;
2295 }
2296
2297
2298 int
udf_create_VAT(union dscrptr ** vat_dscr)2299 udf_create_VAT(union dscrptr **vat_dscr)
2300 {
2301 struct file_entry *fe;
2302 struct extfile_entry *efe;
2303 struct impl_extattr_entry *implext;
2304 struct vatlvext_extattr_entry *vatlvext;
2305 struct long_ad dataloc, *allocpos;
2306 uint8_t *bpos, *extattr;
2307 uint32_t ea_len, inf_len, vat_len, blks;
2308 int filetype;
2309 int error;
2310
2311 assert((layout.rootdir < 2) && (layout.fsd < 2));
2312
2313 memset(&dataloc, 0, sizeof(dataloc));
2314 dataloc.len = udf_rw32(context.vat_size);
2315 dataloc.loc.part_num = udf_rw16(context.data_part);
2316 dataloc.loc.lb_num = udf_rw32(layout.vat);
2317
2318 if (context.dscrver == 2) {
2319 /* old style VAT */
2320 filetype = UDF_ICB_FILETYPE_UNKNOWN;
2321 error = udf_create_new_fe(&fe, filetype, NULL);
2322 if (error)
2323 return error;
2324
2325 /* append VAT LVExtension attribute */
2326 ea_len = sizeof(struct impl_extattr_entry) - 1 +
2327 sizeof(struct vatlvext_extattr_entry) + 4;
2328
2329 extattr = calloc(1, ea_len);
2330
2331 implext = (struct impl_extattr_entry *) extattr;
2332 implext->hdr.type = udf_rw32(2048); /* [4/48.10.8] */
2333 implext->hdr.subtype = 1; /* [4/48.10.8.2] */
2334 implext->hdr.a_l = udf_rw32(ea_len); /* VAT LVext EA size */
2335 /* use 4 bytes of imp use for UDF checksum [UDF 3.3.4.5] */
2336 implext->iu_l = udf_rw32(4);
2337 udf_set_regid(&implext->imp_id, "*UDF VAT LVExtension");
2338 udf_add_udf_regid(&implext->imp_id);
2339
2340 /* VAT LVExtension data follows UDF IU space */
2341 bpos = ((uint8_t *) implext->data) + 4;
2342 vatlvext = (struct vatlvext_extattr_entry *) bpos;
2343
2344 vatlvext->unique_id_chk = udf_rw64(fe->unique_id);
2345 vatlvext->num_files = udf_rw32(context.num_files);
2346 vatlvext->num_directories = udf_rw32(context.num_directories);
2347 memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id,128);
2348
2349 udf_extattr_append_internal((union dscrptr *) fe,
2350 (struct extattr_entry *) extattr);
2351
2352 free(extattr);
2353
2354 fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2355
2356 allocpos = (struct long_ad *) (fe->data + udf_rw32(fe->l_ea));
2357 *allocpos = dataloc;
2358
2359 /* set length */
2360 inf_len = context.vat_size;
2361 fe->inf_len = udf_rw64(inf_len);
2362 fe->l_ad = udf_rw32(sizeof(struct long_ad));
2363 blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2364 context.sector_size;
2365 fe->logblks_rec = udf_rw32(blks);
2366
2367 /* update vat descriptor's CRC length */
2368 vat_len = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
2369 vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea);
2370 fe->tag.desc_crc_len = udf_rw16(vat_len);
2371
2372 *vat_dscr = (union dscrptr *) fe;
2373 } else {
2374 /* new style VAT */
2375 filetype = UDF_ICB_FILETYPE_VAT;
2376 error = udf_create_new_efe(&efe, filetype, NULL);
2377 if (error)
2378 return error;
2379
2380 efe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
2381
2382 allocpos = (struct long_ad *) efe->data;
2383 *allocpos = dataloc;
2384
2385 /* set length */
2386 inf_len = context.vat_size;
2387 efe->inf_len = udf_rw64(inf_len);
2388 efe->obj_size = udf_rw64(inf_len);
2389 efe->l_ad = udf_rw32(sizeof(struct long_ad));
2390 blks = UDF_ROUNDUP(inf_len, context.sector_size) /
2391 context.sector_size;
2392 efe->logblks_rec = udf_rw32(blks);
2393
2394 vat_len = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH;
2395 vat_len += udf_rw32(efe->l_ad);
2396 efe->tag.desc_crc_len = udf_rw16(vat_len);
2397
2398 *vat_dscr = (union dscrptr *) efe;
2399 }
2400
2401 return 0;
2402 }
2403
2404