Annotation of src/sys/fs/udf/udf_subr.c, Revision 1.166
1.166 ! andvar 1: /* $NetBSD: udf_subr.c,v 1.165 2022/01/25 22:01:35 andvar Exp $ */
1.1 reinoud 2:
3: /*
1.45 reinoud 4: * Copyright (c) 2006, 2008 Reinoud Zandijk
1.1 reinoud 5: * All rights reserved.
1.152 skrll 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.152 skrll 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.152 skrll 26: *
1.1 reinoud 27: */
28:
29:
30: #include <sys/cdefs.h>
31: #ifndef lint
1.166 ! andvar 32: __KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.165 2022/01/25 22:01:35 andvar Exp $");
1.1 reinoud 33: #endif /* not lint */
34:
35:
36: #if defined(_KERNEL_OPT)
37: #include "opt_compat_netbsd.h"
38: #endif
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/sysctl.h>
43: #include <sys/namei.h>
44: #include <sys/proc.h>
45: #include <sys/kernel.h>
46: #include <sys/vnode.h>
47: #include <miscfs/genfs/genfs_node.h>
48: #include <sys/mount.h>
49: #include <sys/buf.h>
50: #include <sys/file.h>
51: #include <sys/device.h>
52: #include <sys/disklabel.h>
53: #include <sys/ioctl.h>
54: #include <sys/malloc.h>
55: #include <sys/dirent.h>
56: #include <sys/stat.h>
57: #include <sys/conf.h>
1.8 christos 58: #include <sys/kauth.h>
1.48 reinoud 59: #include <fs/unicode.h>
1.30 reinoud 60: #include <dev/clock_subr.h>
1.1 reinoud 61:
62: #include <fs/udf/ecma167-udf.h>
63: #include <fs/udf/udf_mount.h>
1.73 reinoud 64: #include <sys/dirhash.h>
1.1 reinoud 65:
66: #include "udf.h"
67: #include "udf_subr.h"
68: #include "udf_bswap.h"
69:
70:
1.45 reinoud 71: #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
72:
73: #define UDF_SET_SYSTEMFILE(vp) \
74: /* XXXAD Is the vnode locked? */ \
75: (vp)->v_vflag |= VV_SYSTEM; \
1.109 reinoud 76: vref((vp)); \
77: vput((vp)); \
1.1 reinoud 78:
1.45 reinoud 79: extern int syncer_maxdelay; /* maximum delay time */
80: extern int (**udf_vnodeop_p)(void *);
1.1 reinoud 81:
1.45 reinoud 82: /* --------------------------------------------------------------------- */
1.1 reinoud 83:
1.45 reinoud 84: //#ifdef DEBUG
85: #if 1
1.1 reinoud 86:
87: #if 0
1.45 reinoud 88: static void
89: udf_dumpblob(boid *blob, uint32_t dlen)
1.1 reinoud 90: {
1.45 reinoud 91: int i, j;
1.1 reinoud 92:
93: printf("blob = %p\n", blob);
94: printf("dump of %d bytes\n", dlen);
95:
96: for (i = 0; i < dlen; i+ = 16) {
97: printf("%04x ", i);
98: for (j = 0; j < 16; j++) {
99: if (i+j < dlen) {
100: printf("%02x ", blob[i+j]);
101: } else {
102: printf(" ");
1.9 christos 103: }
104: }
1.1 reinoud 105: for (j = 0; j < 16; j++) {
106: if (i+j < dlen) {
107: if (blob[i+j]>32 && blob[i+j]! = 127) {
108: printf("%c", blob[i+j]);
109: } else {
110: printf(".");
1.9 christos 111: }
112: }
113: }
1.1 reinoud 114: printf("\n");
1.9 christos 115: }
1.1 reinoud 116: printf("\n");
1.45 reinoud 117: Debugger();
1.9 christos 118: }
1.1 reinoud 119: #endif
120:
121: static void
122: udf_dump_discinfo(struct udf_mount *ump)
123: {
124: char bits[128];
125: struct mmc_discinfo *di = &ump->discinfo;
126:
127: if ((udf_verbose & UDF_DEBUG_VOLUMES) == 0)
128: return;
129:
130: printf("Device/media info :\n");
131: printf("\tMMC profile 0x%02x\n", di->mmc_profile);
132: printf("\tderived class %d\n", di->mmc_class);
133: printf("\tsector size %d\n", di->sector_size);
134: printf("\tdisc state %d\n", di->disc_state);
135: printf("\tlast ses state %d\n", di->last_session_state);
136: printf("\tbg format state %d\n", di->bg_format_state);
137: printf("\tfrst track %d\n", di->first_track);
138: printf("\tfst on last ses %d\n", di->first_track_last_session);
139: printf("\tlst on last ses %d\n", di->last_track_last_session);
140: printf("\tlink block penalty %d\n", di->link_block_penalty);
1.80 christos 141: snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, di->disc_flags);
1.1 reinoud 142: printf("\tdisc flags %s\n", bits);
143: printf("\tdisc id %x\n", di->disc_id);
144: printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode);
145:
146: printf("\tnum sessions %d\n", di->num_sessions);
147: printf("\tnum tracks %d\n", di->num_tracks);
148:
1.80 christos 149: snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur);
1.1 reinoud 150: printf("\tcapabilities cur %s\n", bits);
1.80 christos 151: snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap);
1.1 reinoud 152: printf("\tcapabilities cap %s\n", bits);
153: }
1.85 reinoud 154:
155: static void
156: udf_dump_trackinfo(struct mmc_trackinfo *trackinfo)
157: {
158: char bits[128];
159:
160: if ((udf_verbose & UDF_DEBUG_VOLUMES) == 0)
161: return;
162:
163: printf("Trackinfo for track %d:\n", trackinfo->tracknr);
164: printf("\tsessionnr %d\n", trackinfo->sessionnr);
165: printf("\ttrack mode %d\n", trackinfo->track_mode);
166: printf("\tdata mode %d\n", trackinfo->data_mode);
167: snprintb(bits, sizeof(bits), MMC_TRACKINFO_FLAGBITS, trackinfo->flags);
168: printf("\tflags %s\n", bits);
169:
170: printf("\ttrack start %d\n", trackinfo->track_start);
171: printf("\tnext_writable %d\n", trackinfo->next_writable);
172: printf("\tfree_blocks %d\n", trackinfo->free_blocks);
173: printf("\tpacket_size %d\n", trackinfo->packet_size);
174: printf("\ttrack size %d\n", trackinfo->track_size);
175: printf("\tlast recorded block %d\n", trackinfo->last_recorded);
176: }
177:
1.1 reinoud 178: #else
179: #define udf_dump_discinfo(a);
1.85 reinoud 180: #define udf_dump_trackinfo(a);
1.1 reinoud 181: #endif
182:
1.45 reinoud 183:
184: /* --------------------------------------------------------------------- */
185:
1.1 reinoud 186: /* not called often */
187: int
188: udf_update_discinfo(struct udf_mount *ump)
189: {
190: struct vnode *devvp = ump->devvp;
1.118 christos 191: uint64_t psize;
192: unsigned secsize;
1.1 reinoud 193: struct mmc_discinfo *di;
194: int error;
195:
196: DPRINTF(VOLUMES, ("read/update disc info\n"));
197: di = &ump->discinfo;
198: memset(di, 0, sizeof(struct mmc_discinfo));
199:
200: /* check if we're on a MMC capable device, i.e. CD/DVD */
1.41 pooka 201: error = VOP_IOCTL(devvp, MMCGETDISCINFO, di, FKIOCTL, NOCRED);
1.1 reinoud 202: if (error == 0) {
203: udf_dump_discinfo(ump);
204: return 0;
1.9 christos 205: }
1.1 reinoud 206:
207: /* disc partition support */
1.118 christos 208: error = getdisksize(devvp, &psize, &secsize);
1.1 reinoud 209: if (error)
1.118 christos 210: return error;
1.1 reinoud 211:
212: /* set up a disc info profile for partitions */
213: di->mmc_profile = 0x01; /* disc type */
214: di->mmc_class = MMC_CLASS_DISC;
215: di->disc_state = MMC_STATE_CLOSED;
216: di->last_session_state = MMC_STATE_CLOSED;
217: di->bg_format_state = MMC_BGFSTATE_COMPLETED;
218: di->link_block_penalty = 0;
219:
220: di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE |
1.4 reinoud 221: MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE;
1.1 reinoud 222: di->mmc_cap = di->mmc_cur;
223: di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
224:
225: /* TODO problem with last_possible_lba on resizable VND; request */
1.118 christos 226: di->last_possible_lba = psize;
227: di->sector_size = secsize;
1.1 reinoud 228:
229: di->num_sessions = 1;
230: di->num_tracks = 1;
231:
232: di->first_track = 1;
233: di->first_track_last_session = di->last_track_last_session = 1;
234:
235: udf_dump_discinfo(ump);
236: return 0;
237: }
238:
239:
240: int
241: udf_update_trackinfo(struct udf_mount *ump, struct mmc_trackinfo *ti)
242: {
243: struct vnode *devvp = ump->devvp;
244: struct mmc_discinfo *di = &ump->discinfo;
245: int error, class;
246:
247: DPRINTF(VOLUMES, ("read track info\n"));
248:
249: class = di->mmc_class;
250: if (class != MMC_CLASS_DISC) {
251: /* tracknr specified in struct ti */
1.41 pooka 252: error = VOP_IOCTL(devvp, MMCGETTRACKINFO, ti, FKIOCTL, NOCRED);
1.1 reinoud 253: return error;
1.9 christos 254: }
1.1 reinoud 255:
256: /* disc partition support */
257: if (ti->tracknr != 1)
258: return EIO;
259:
260: /* create fake ti (TODO check for resized vnds) */
261: ti->sessionnr = 1;
262:
263: ti->track_mode = 0; /* XXX */
264: ti->data_mode = 0; /* XXX */
265: ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
266:
267: ti->track_start = 0;
268: ti->packet_size = 1;
269:
270: /* TODO support for resizable vnd */
271: ti->track_size = di->last_possible_lba;
272: ti->next_writable = di->last_possible_lba;
273: ti->last_recorded = ti->next_writable;
274: ti->free_blocks = 0;
275:
276: return 0;
277: }
278:
279:
1.45 reinoud 280: int
281: udf_setup_writeparams(struct udf_mount *ump)
1.1 reinoud 282: {
1.45 reinoud 283: struct mmc_writeparams mmc_writeparams;
284: int error;
285:
286: if (ump->discinfo.mmc_class == MMC_CLASS_DISC)
287: return 0;
288:
289: /*
290: * only CD burning normally needs setting up, but other disc types
291: * might need other settings to be made. The MMC framework will set up
1.155 andvar 292: * the necessary recording parameters according to the disc
1.45 reinoud 293: * characteristics read in. Modifications can be made in the discinfo
294: * structure passed to change the nature of the disc.
295: */
296:
297: memset(&mmc_writeparams, 0, sizeof(struct mmc_writeparams));
298: mmc_writeparams.mmc_class = ump->discinfo.mmc_class;
299: mmc_writeparams.mmc_cur = ump->discinfo.mmc_cur;
300:
301: /*
302: * UDF dictates first track to determine track mode for the whole
303: * disc. [UDF 1.50/6.10.1.1, UDF 1.50/6.10.2.1]
304: * To prevent problems with a `reserved' track in front we start with
305: * the 2nd track and if that is not valid, go for the 1st.
306: */
307: mmc_writeparams.tracknr = 2;
308: mmc_writeparams.data_mode = MMC_DATAMODE_DEFAULT; /* XA disc */
309: mmc_writeparams.track_mode = MMC_TRACKMODE_DEFAULT; /* data */
310:
311: error = VOP_IOCTL(ump->devvp, MMCSETUPWRITEPARAMS, &mmc_writeparams,
312: FKIOCTL, NOCRED);
313: if (error) {
314: mmc_writeparams.tracknr = 1;
315: error = VOP_IOCTL(ump->devvp, MMCSETUPWRITEPARAMS,
316: &mmc_writeparams, FKIOCTL, NOCRED);
317: }
318: return error;
319: }
320:
321:
1.138 reinoud 322: void
323: udf_mmc_synchronise_caches(struct udf_mount *ump)
1.45 reinoud 324: {
325: struct mmc_op mmc_op;
326:
1.138 reinoud 327: DPRINTF(CALL, ("udf_mcc_synchronise_caches()\n"));
1.45 reinoud 328:
329: if (ump->vfs_mountp->mnt_flag & MNT_RDONLY)
1.138 reinoud 330: return;
1.45 reinoud 331:
332: /* discs are done now */
333: if (ump->discinfo.mmc_class == MMC_CLASS_DISC)
1.138 reinoud 334: return;
1.45 reinoud 335:
1.87 cegger 336: memset(&mmc_op, 0, sizeof(struct mmc_op));
1.45 reinoud 337: mmc_op.operation = MMC_OP_SYNCHRONISECACHE;
338:
339: /* ignore return code */
340: (void) VOP_IOCTL(ump->devvp, MMCOP, &mmc_op, FKIOCTL, NOCRED);
341: }
342:
343: /* --------------------------------------------------------------------- */
344:
345: /* track/session searching for mounting */
346: int
347: udf_search_tracks(struct udf_mount *ump, struct udf_args *args,
348: int *first_tracknr, int *last_tracknr)
349: {
350: struct mmc_trackinfo trackinfo;
351: uint32_t tracknr, start_track, num_tracks;
1.1 reinoud 352: int error;
353:
354: /* if negative, sessionnr is relative to last session */
355: if (args->sessionnr < 0) {
356: args->sessionnr += ump->discinfo.num_sessions;
1.9 christos 357: }
1.1 reinoud 358:
359: /* sanity */
1.45 reinoud 360: if (args->sessionnr < 0)
361: args->sessionnr = 0;
1.1 reinoud 362: if (args->sessionnr > ump->discinfo.num_sessions)
363: args->sessionnr = ump->discinfo.num_sessions;
364:
365: /* search the tracks for this session, zero session nr indicates last */
1.42 reinoud 366: if (args->sessionnr == 0)
1.1 reinoud 367: args->sessionnr = ump->discinfo.num_sessions;
1.42 reinoud 368: if (ump->discinfo.last_session_state == MMC_STATE_EMPTY)
369: args->sessionnr--;
370:
1.45 reinoud 371: /* sanity again */
372: if (args->sessionnr < 0)
373: args->sessionnr = 0;
1.1 reinoud 374:
375: /* search the first and last track of the specified session */
376: num_tracks = ump->discinfo.num_tracks;
377: start_track = ump->discinfo.first_track;
378:
379: /* search for first track of this session */
380: for (tracknr = start_track; tracknr <= num_tracks; tracknr++) {
381: /* get track info */
382: trackinfo.tracknr = tracknr;
383: error = udf_update_trackinfo(ump, &trackinfo);
384: if (error)
385: return error;
386:
387: if (trackinfo.sessionnr == args->sessionnr)
388: break;
389: }
390: *first_tracknr = tracknr;
391:
392: /* search for last track of this session */
393: for (;tracknr <= num_tracks; tracknr++) {
394: /* get track info */
395: trackinfo.tracknr = tracknr;
396: error = udf_update_trackinfo(ump, &trackinfo);
397: if (error || (trackinfo.sessionnr != args->sessionnr)) {
398: tracknr--;
399: break;
1.9 christos 400: }
401: }
1.1 reinoud 402: if (tracknr > num_tracks)
403: tracknr--;
404:
405: *last_tracknr = tracknr;
406:
1.45 reinoud 407: if (*last_tracknr < *first_tracknr) {
408: printf( "udf_search_tracks: sanity check on drive+disc failed, "
409: "drive returned garbage\n");
410: return EINVAL;
411: }
412:
1.1 reinoud 413: assert(*last_tracknr >= *first_tracknr);
414: return 0;
415: }
416:
417:
1.45 reinoud 418: /*
419: * NOTE: this is the only routine in this file that directly peeks into the
420: * metadata file but since its at a larval state of the mount it can't hurt.
421: *
422: * XXX candidate for udf_allocation.c
423: * XXX clean me up!, change to new node reading code.
424: */
425:
426: static void
427: udf_check_track_metadata_overlap(struct udf_mount *ump,
428: struct mmc_trackinfo *trackinfo)
1.1 reinoud 429: {
1.45 reinoud 430: struct part_desc *part;
431: struct file_entry *fe;
432: struct extfile_entry *efe;
433: struct short_ad *s_ad;
434: struct long_ad *l_ad;
435: uint32_t track_start, track_end;
436: uint32_t phys_part_start, phys_part_end, part_start, part_end;
437: uint32_t sector_size, len, alloclen, plb_num;
438: uint8_t *pos;
1.121 christos 439: int addr_type, icblen, icbflags;
1.1 reinoud 440:
1.45 reinoud 441: /* get our track extents */
442: track_start = trackinfo->track_start;
443: track_end = track_start + trackinfo->track_size;
444:
445: /* get our base partition extent */
1.71 reinoud 446: KASSERT(ump->node_part == ump->fids_part);
1.112 reinoud 447: part = ump->partitions[ump->vtop[ump->node_part]];
1.45 reinoud 448: phys_part_start = udf_rw32(part->start_loc);
449: phys_part_end = phys_part_start + udf_rw32(part->part_len);
1.1 reinoud 450:
1.45 reinoud 451: /* no use if its outside the physical partition */
452: if ((phys_part_start >= track_end) || (phys_part_end < track_start))
453: return;
1.1 reinoud 454:
1.45 reinoud 455: /*
456: * now follow all extents in the fe/efe to see if they refer to this
457: * track
458: */
1.1 reinoud 459:
1.45 reinoud 460: sector_size = ump->discinfo.sector_size;
1.1 reinoud 461:
1.45 reinoud 462: /* XXX should we claim exclusive access to the metafile ? */
463: /* TODO: move to new node read code */
464: fe = ump->metadata_node->fe;
465: efe = ump->metadata_node->efe;
466: if (fe) {
467: alloclen = udf_rw32(fe->l_ad);
468: pos = &fe->data[0] + udf_rw32(fe->l_ea);
469: icbflags = udf_rw16(fe->icbtag.flags);
470: } else {
471: assert(efe);
472: alloclen = udf_rw32(efe->l_ad);
473: pos = &efe->data[0] + udf_rw32(efe->l_ea);
474: icbflags = udf_rw16(efe->icbtag.flags);
1.9 christos 475: }
1.45 reinoud 476: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
477:
478: while (alloclen) {
479: if (addr_type == UDF_ICB_SHORT_ALLOC) {
480: icblen = sizeof(struct short_ad);
481: s_ad = (struct short_ad *) pos;
482: len = udf_rw32(s_ad->len);
483: plb_num = udf_rw32(s_ad->lb_num);
484: } else {
485: /* should not be present, but why not */
486: icblen = sizeof(struct long_ad);
487: l_ad = (struct long_ad *) pos;
488: len = udf_rw32(l_ad->len);
489: plb_num = udf_rw32(l_ad->loc.lb_num);
490: /* pvpart_num = udf_rw16(l_ad->loc.part_num); */
491: }
492: /* process extent */
493: len = UDF_EXT_LEN(len);
1.1 reinoud 494:
1.45 reinoud 495: part_start = phys_part_start + plb_num;
496: part_end = part_start + (len / sector_size);
1.1 reinoud 497:
1.45 reinoud 498: if ((part_start >= track_start) && (part_end <= track_end)) {
499: /* extent is enclosed within this track */
500: ump->metadata_track = *trackinfo;
501: return;
502: }
1.1 reinoud 503:
1.45 reinoud 504: pos += icblen;
505: alloclen -= icblen;
1.9 christos 506: }
1.45 reinoud 507: }
508:
1.1 reinoud 509:
1.45 reinoud 510: int
511: udf_search_writing_tracks(struct udf_mount *ump)
512: {
1.82 reinoud 513: struct vnode *devvp = ump->devvp;
1.45 reinoud 514: struct mmc_trackinfo trackinfo;
1.85 reinoud 515: struct mmc_op mmc_op;
1.45 reinoud 516: struct part_desc *part;
517: uint32_t tracknr, start_track, num_tracks;
518: uint32_t track_start, track_end, part_start, part_end;
1.71 reinoud 519: int node_alloc, error;
1.1 reinoud 520:
1.45 reinoud 521: /*
522: * in the CD/(HD)DVD/BD recordable device model a few tracks within
523: * the last session might be open but in the UDF device model at most
524: * three tracks can be open: a reserved track for delayed ISO VRS
525: * writing, a data track and a metadata track. We search here for the
526: * data track and the metadata track. Note that the reserved track is
527: * troublesome but can be detected by its small size of < 512 sectors.
528: */
1.1 reinoud 529:
1.85 reinoud 530: /* update discinfo since it might have changed */
531: error = udf_update_discinfo(ump);
532: if (error)
533: return error;
534:
1.45 reinoud 535: num_tracks = ump->discinfo.num_tracks;
536: start_track = ump->discinfo.first_track;
1.1 reinoud 537:
1.45 reinoud 538: /* fetch info on first and possibly only track */
539: trackinfo.tracknr = start_track;
540: error = udf_update_trackinfo(ump, &trackinfo);
541: if (error)
542: return error;
1.13 reinoud 543:
1.45 reinoud 544: /* copy results to our mount point */
545: ump->data_track = trackinfo;
546: ump->metadata_track = trackinfo;
1.1 reinoud 547:
1.45 reinoud 548: /* if not sequential, we're done */
549: if (num_tracks == 1)
550: return 0;
1.1 reinoud 551:
1.45 reinoud 552: for (tracknr = start_track;tracknr <= num_tracks; tracknr++) {
553: /* get track info */
554: trackinfo.tracknr = tracknr;
555: error = udf_update_trackinfo(ump, &trackinfo);
556: if (error)
557: return error;
1.1 reinoud 558:
1.82 reinoud 559: /*
560: * If this track is marked damaged, ask for repair. This is an
561: * optional command, so ignore its error but report warning.
562: */
563: if (trackinfo.flags & MMC_TRACKINFO_DAMAGED) {
1.85 reinoud 564: memset(&mmc_op, 0, sizeof(mmc_op));
565: mmc_op.operation = MMC_OP_REPAIRTRACK;
566: mmc_op.mmc_profile = ump->discinfo.mmc_profile;
567: mmc_op.tracknr = tracknr;
568: error = VOP_IOCTL(devvp, MMCOP, &mmc_op, FKIOCTL, NOCRED);
1.82 reinoud 569: if (error)
570: (void)printf("Drive can't explicitly repair "
571: "damaged track %d, but it might "
572: "autorepair\n", tracknr);
573:
574: /* reget track info */
575: error = udf_update_trackinfo(ump, &trackinfo);
576: if (error)
577: return error;
578: }
1.45 reinoud 579: if ((trackinfo.flags & MMC_TRACKINFO_NWA_VALID) == 0)
580: continue;
1.85 reinoud 581:
1.45 reinoud 582: track_start = trackinfo.track_start;
583: track_end = track_start + trackinfo.track_size;
1.1 reinoud 584:
1.45 reinoud 585: /* check for overlap on data partition */
586: part = ump->partitions[ump->data_part];
587: part_start = udf_rw32(part->start_loc);
588: part_end = part_start + udf_rw32(part->part_len);
589: if ((part_start < track_end) && (part_end > track_start)) {
590: ump->data_track = trackinfo;
591: /* TODO check if UDF partition data_part is writable */
592: }
593:
594: /* check for overlap on metadata partition */
1.71 reinoud 595: node_alloc = ump->vtop_alloc[ump->node_part];
596: if ((node_alloc == UDF_ALLOC_METASEQUENTIAL) ||
597: (node_alloc == UDF_ALLOC_METABITMAP)) {
1.45 reinoud 598: udf_check_track_metadata_overlap(ump, &trackinfo);
599: } else {
600: ump->metadata_track = trackinfo;
1.9 christos 601: }
1.45 reinoud 602: }
1.1 reinoud 603:
1.45 reinoud 604: if ((ump->data_track.flags & MMC_TRACKINFO_NWA_VALID) == 0)
605: return EROFS;
1.1 reinoud 606:
1.45 reinoud 607: if ((ump->metadata_track.flags & MMC_TRACKINFO_NWA_VALID) == 0)
608: return EROFS;
1.1 reinoud 609:
610: return 0;
611: }
612:
613: /* --------------------------------------------------------------------- */
614:
1.45 reinoud 615: /*
616: * Check if the blob starts with a good UDF tag. Tags are protected by a
1.162 reinoud 617: * checksum over the header except one byte at position 4 that is the checksum
1.45 reinoud 618: * itself.
619: */
620:
621: int
622: udf_check_tag(void *blob)
1.1 reinoud 623: {
1.45 reinoud 624: struct desc_tag *tag = blob;
625: uint8_t *pos, sum, cnt;
1.1 reinoud 626:
1.45 reinoud 627: /* check TAG header checksum */
628: pos = (uint8_t *) tag;
629: sum = 0;
630:
631: for(cnt = 0; cnt < 16; cnt++) {
632: if (cnt != 4)
633: sum += *pos;
634: pos++;
635: }
636: if (sum != tag->cksum) {
637: /* bad tag header checksum; this is not a valid tag */
638: return EINVAL;
639: }
640:
641: return 0;
642: }
643:
644:
645: /*
646: * check tag payload will check descriptor CRC as specified.
647: * If the descriptor is too long, it will return EIO otherwise EINVAL.
648: */
1.1 reinoud 649:
1.45 reinoud 650: int
651: udf_check_tag_payload(void *blob, uint32_t max_length)
652: {
653: struct desc_tag *tag = blob;
654: uint16_t crc, crc_len;
1.1 reinoud 655:
1.45 reinoud 656: crc_len = udf_rw16(tag->desc_crc_len);
1.1 reinoud 657:
1.45 reinoud 658: /* check payload CRC if applicable */
659: if (crc_len == 0)
660: return 0;
1.1 reinoud 661:
1.45 reinoud 662: if (crc_len > max_length)
663: return EIO;
1.1 reinoud 664:
1.45 reinoud 665: crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, crc_len);
666: if (crc != udf_rw16(tag->desc_crc)) {
667: /* bad payload CRC; this is a broken tag */
668: return EINVAL;
1.9 christos 669: }
1.1 reinoud 670:
1.45 reinoud 671: return 0;
1.1 reinoud 672: }
673:
674:
1.45 reinoud 675: void
676: udf_validate_tag_sum(void *blob)
1.1 reinoud 677: {
1.45 reinoud 678: struct desc_tag *tag = blob;
679: uint8_t *pos, sum, cnt;
1.1 reinoud 680:
1.45 reinoud 681: /* calculate TAG header checksum */
682: pos = (uint8_t *) tag;
683: sum = 0;
1.1 reinoud 684:
1.45 reinoud 685: for(cnt = 0; cnt < 16; cnt++) {
686: if (cnt != 4) sum += *pos;
687: pos++;
688: }
689: tag->cksum = sum; /* 8 bit */
690: }
1.1 reinoud 691:
692:
1.45 reinoud 693: /* assumes sector number of descriptor to be saved already present */
694: void
695: udf_validate_tag_and_crc_sums(void *blob)
696: {
697: struct desc_tag *tag = blob;
698: uint8_t *btag = (uint8_t *) tag;
699: uint16_t crc, crc_len;
1.1 reinoud 700:
1.45 reinoud 701: crc_len = udf_rw16(tag->desc_crc_len);
1.1 reinoud 702:
1.45 reinoud 703: /* check payload CRC if applicable */
704: if (crc_len > 0) {
705: crc = udf_cksum(btag + UDF_DESC_TAG_LENGTH, crc_len);
706: tag->desc_crc = udf_rw16(crc);
1.9 christos 707: }
1.1 reinoud 708:
1.45 reinoud 709: /* calculate TAG header checksum */
710: udf_validate_tag_sum(blob);
1.1 reinoud 711: }
712:
713: /* --------------------------------------------------------------------- */
714:
715: /*
1.45 reinoud 716: * XXX note the different semantics from udfclient: for FIDs it still rounds
717: * up to sectors. Use udf_fidsize() for a correct length.
1.1 reinoud 718: */
719:
1.45 reinoud 720: int
721: udf_tagsize(union dscrptr *dscr, uint32_t lb_size)
1.1 reinoud 722: {
1.45 reinoud 723: uint32_t size, tag_id, num_lb, elmsz;
1.1 reinoud 724:
1.45 reinoud 725: tag_id = udf_rw16(dscr->tag.id);
1.1 reinoud 726:
1.45 reinoud 727: switch (tag_id) {
728: case TAGID_LOGVOL :
729: size = sizeof(struct logvol_desc) - 1;
730: size += udf_rw32(dscr->lvd.mt_l);
731: break;
732: case TAGID_UNALLOC_SPACE :
733: elmsz = sizeof(struct extent_ad);
734: size = sizeof(struct unalloc_sp_desc) - elmsz;
735: size += udf_rw32(dscr->usd.alloc_desc_num) * elmsz;
736: break;
737: case TAGID_FID :
738: size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu);
739: size = (size + 3) & ~3;
740: break;
741: case TAGID_LOGVOL_INTEGRITY :
742: size = sizeof(struct logvol_int_desc) - sizeof(uint32_t);
743: size += udf_rw32(dscr->lvid.l_iu);
744: size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t));
745: break;
746: case TAGID_SPACE_BITMAP :
747: size = sizeof(struct space_bitmap_desc) - 1;
748: size += udf_rw32(dscr->sbd.num_bytes);
749: break;
750: case TAGID_SPARING_TABLE :
751: elmsz = sizeof(struct spare_map_entry);
752: size = sizeof(struct udf_sparing_table) - elmsz;
753: size += udf_rw16(dscr->spt.rt_l) * elmsz;
754: break;
755: case TAGID_FENTRY :
756: size = sizeof(struct file_entry);
757: size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1;
758: break;
759: case TAGID_EXTFENTRY :
760: size = sizeof(struct extfile_entry);
761: size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1;
762: break;
763: case TAGID_FSD :
764: size = sizeof(struct fileset_desc);
765: break;
766: default :
767: size = sizeof(union dscrptr);
768: break;
769: }
1.1 reinoud 770:
1.70 reinoud 771: if ((size == 0) || (lb_size == 0))
772: return 0;
773:
774: if (lb_size == 1)
775: return size;
1.1 reinoud 776:
1.45 reinoud 777: /* round up in sectors */
778: num_lb = (size + lb_size -1) / lb_size;
779: return num_lb * lb_size;
780: }
1.1 reinoud 781:
782:
1.45 reinoud 783: int
784: udf_fidsize(struct fileid_desc *fid)
785: {
786: uint32_t size;
1.3 reinoud 787:
1.45 reinoud 788: if (udf_rw16(fid->tag.id) != TAGID_FID)
789: panic("got udf_fidsize on non FID\n");
1.1 reinoud 790:
1.45 reinoud 791: size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
792: size = (size + 3) & ~3;
1.1 reinoud 793:
1.45 reinoud 794: return size;
1.1 reinoud 795: }
796:
797: /* --------------------------------------------------------------------- */
798:
1.45 reinoud 799: void
800: udf_lock_node(struct udf_node *udf_node, int flag, char const *fname, const int lineno)
801: {
802: int ret;
803:
804: mutex_enter(&udf_node->node_mutex);
805: /* wait until free */
806: while (udf_node->i_flags & IN_LOCKED) {
807: ret = cv_timedwait(&udf_node->node_lock, &udf_node->node_mutex, hz/8);
808: /* TODO check if we should return error; abort */
809: if (ret == EWOULDBLOCK) {
810: DPRINTF(LOCKING, ( "udf_lock_node: udf_node %p would block "
811: "wanted at %s:%d, previously locked at %s:%d\n",
1.152 skrll 812: udf_node, fname, lineno,
1.45 reinoud 813: udf_node->lock_fname, udf_node->lock_lineno));
814: }
815: }
816: /* grab */
817: udf_node->i_flags |= IN_LOCKED | flag;
818: /* debug */
819: udf_node->lock_fname = fname;
820: udf_node->lock_lineno = lineno;
821:
822: mutex_exit(&udf_node->node_mutex);
823: }
824:
1.1 reinoud 825:
1.45 reinoud 826: void
827: udf_unlock_node(struct udf_node *udf_node, int flag)
1.22 christos 828: {
1.45 reinoud 829: mutex_enter(&udf_node->node_mutex);
830: udf_node->i_flags &= ~(IN_LOCKED | flag);
831: cv_broadcast(&udf_node->node_lock);
832: mutex_exit(&udf_node->node_mutex);
833: }
1.1 reinoud 834:
835:
1.45 reinoud 836: /* --------------------------------------------------------------------- */
1.1 reinoud 837:
1.45 reinoud 838: static int
839: udf_read_anchor(struct udf_mount *ump, uint32_t sector, struct anchor_vdp **dst)
840: {
841: int error;
842:
843: error = udf_read_phys_dscr(ump, sector, M_UDFVOLD,
844: (union dscrptr **) dst);
845: if (!error) {
846: /* blank terminator blocks are not allowed here */
847: if (*dst == NULL)
848: return ENOENT;
849: if (udf_rw16((*dst)->tag.id) != TAGID_ANCHOR) {
850: error = ENOENT;
851: free(*dst, M_UDFVOLD);
852: *dst = NULL;
853: DPRINTF(VOLUMES, ("Not an anchor\n"));
854: }
855: }
856:
857: return error;
858: }
859:
860:
861: int
862: udf_read_anchors(struct udf_mount *ump)
863: {
864: struct udf_args *args = &ump->mount_args;
865: struct mmc_trackinfo first_track;
866: struct mmc_trackinfo second_track;
867: struct mmc_trackinfo last_track;
868: struct anchor_vdp **anchorsp;
869: uint32_t track_start;
870: uint32_t track_end;
871: uint32_t positions[4];
872: int first_tracknr, last_tracknr;
873: int error, anch, ok, first_anchor;
874:
875: /* search the first and last track of the specified session */
876: error = udf_search_tracks(ump, args, &first_tracknr, &last_tracknr);
877: if (!error) {
878: first_track.tracknr = first_tracknr;
879: error = udf_update_trackinfo(ump, &first_track);
880: }
881: if (!error) {
882: last_track.tracknr = last_tracknr;
883: error = udf_update_trackinfo(ump, &last_track);
884: }
885: if ((!error) && (first_tracknr != last_tracknr)) {
886: second_track.tracknr = first_tracknr+1;
887: error = udf_update_trackinfo(ump, &second_track);
888: }
889: if (error) {
890: printf("UDF mount: reading disc geometry failed\n");
891: return 0;
892: }
893:
894: track_start = first_track.track_start;
1.1 reinoud 895:
1.45 reinoud 896: /* `end' is not as straitforward as start. */
897: track_end = last_track.track_start
898: + last_track.track_size - last_track.free_blocks - 1;
1.1 reinoud 899:
1.45 reinoud 900: if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
901: /* end of track is not straitforward here */
902: if (last_track.flags & MMC_TRACKINFO_LRA_VALID)
903: track_end = last_track.last_recorded;
904: else if (last_track.flags & MMC_TRACKINFO_NWA_VALID)
905: track_end = last_track.next_writable
906: - ump->discinfo.link_block_penalty;
1.9 christos 907: }
1.1 reinoud 908:
1.45 reinoud 909: /* its no use reading a blank track */
910: first_anchor = 0;
911: if (first_track.flags & MMC_TRACKINFO_BLANK)
912: first_anchor = 1;
913:
914: /* get our packet size */
915: ump->packet_size = first_track.packet_size;
916: if (first_track.flags & MMC_TRACKINFO_BLANK)
917: ump->packet_size = second_track.packet_size;
918:
919: if (ump->packet_size <= 1) {
920: /* take max, but not bigger than 64 */
921: ump->packet_size = MAXPHYS / ump->discinfo.sector_size;
922: ump->packet_size = MIN(ump->packet_size, 64);
1.9 christos 923: }
1.45 reinoud 924: KASSERT(ump->packet_size >= 1);
1.1 reinoud 925:
1.45 reinoud 926: /* read anchors start+256, start+512, end-256, end */
927: positions[0] = track_start+256;
928: positions[1] = track_end-256;
929: positions[2] = track_end;
930: positions[3] = track_start+512; /* [UDF 2.60/6.11.2] */
1.151 skrll 931: /* XXX shouldn't +512 be preferred over +256 for compat with Roxio CD */
1.1 reinoud 932:
1.45 reinoud 933: ok = 0;
934: anchorsp = ump->anchors;
935: for (anch = first_anchor; anch < 4; anch++) {
936: DPRINTF(VOLUMES, ("Read anchor %d at sector %d\n", anch,
937: positions[anch]));
938: error = udf_read_anchor(ump, positions[anch], anchorsp);
939: if (!error) {
940: anchorsp++;
941: ok++;
942: }
943: }
1.1 reinoud 944:
1.45 reinoud 945: /* VATs are only recorded on sequential media, but initialise */
946: ump->first_possible_vat_location = track_start + 2;
1.137 reinoud 947: ump->last_possible_vat_location = track_end;
1.1 reinoud 948:
1.45 reinoud 949: return ok;
950: }
1.1 reinoud 951:
1.45 reinoud 952: /* --------------------------------------------------------------------- */
1.1 reinoud 953:
1.95 reinoud 954: int
955: udf_get_c_type(struct udf_node *udf_node)
956: {
957: int isdir, what;
958:
959: isdir = (udf_node->vnode->v_type == VDIR);
960: what = isdir ? UDF_C_FIDS : UDF_C_USERDATA;
961:
962: if (udf_node->ump)
963: if (udf_node == udf_node->ump->metadatabitmap_node)
964: what = UDF_C_METADATA_SBM;
965:
966: return what;
967: }
968:
969:
970: int
971: udf_get_record_vpart(struct udf_mount *ump, int udf_c_type)
972: {
973: int vpart_num;
974:
975: vpart_num = ump->data_part;
976: if (udf_c_type == UDF_C_NODE)
977: vpart_num = ump->node_part;
978: if (udf_c_type == UDF_C_FIDS)
979: vpart_num = ump->fids_part;
980:
981: return vpart_num;
982: }
983:
1.111 reinoud 984:
1.152 skrll 985: /*
1.111 reinoud 986: * BUGALERT: some rogue implementations use random physical partition
987: * numbers to break other implementations so lookup the number.
988: */
989:
990: static uint16_t
991: udf_find_raw_phys(struct udf_mount *ump, uint16_t raw_phys_part)
992: {
993: struct part_desc *part;
994: uint16_t phys_part;
995:
996: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
997: part = ump->partitions[phys_part];
998: if (part == NULL)
999: break;
1000: if (udf_rw16(part->part_num) == raw_phys_part)
1001: break;
1002: }
1003: return phys_part;
1004: }
1005:
1.95 reinoud 1006: /* --------------------------------------------------------------------- */
1007:
1.45 reinoud 1008: /* we dont try to be smart; we just record the parts */
1009: #define UDF_UPDATE_DSCR(name, dscr) \
1010: if (name) \
1011: free(name, M_UDFVOLD); \
1012: name = dscr;
1.1 reinoud 1013:
1.45 reinoud 1014: static int
1015: udf_process_vds_descriptor(struct udf_mount *ump, union dscrptr *dscr)
1016: {
1017: uint16_t phys_part, raw_phys_part;
1.1 reinoud 1018:
1.45 reinoud 1019: DPRINTF(VOLUMES, ("\tprocessing VDS descr %d\n",
1020: udf_rw16(dscr->tag.id)));
1021: switch (udf_rw16(dscr->tag.id)) {
1022: case TAGID_PRI_VOL : /* primary partition */
1023: UDF_UPDATE_DSCR(ump->primary_vol, &dscr->pvd);
1024: break;
1025: case TAGID_LOGVOL : /* logical volume */
1026: UDF_UPDATE_DSCR(ump->logical_vol, &dscr->lvd);
1027: break;
1028: case TAGID_UNALLOC_SPACE : /* unallocated space */
1029: UDF_UPDATE_DSCR(ump->unallocated, &dscr->usd);
1030: break;
1031: case TAGID_IMP_VOL : /* implementation */
1032: /* XXX do we care about multiple impl. descr ? */
1033: UDF_UPDATE_DSCR(ump->implementation, &dscr->ivd);
1034: break;
1035: case TAGID_PARTITION : /* physical partition */
1036: /* not much use if its not allocated */
1037: if ((udf_rw16(dscr->pd.flags) & UDF_PART_FLAG_ALLOCATED) == 0) {
1038: free(dscr, M_UDFVOLD);
1.1 reinoud 1039: break;
1.9 christos 1040: }
1.1 reinoud 1041:
1.33 reinoud 1042: /*
1043: * BUGALERT: some rogue implementations use random physical
1.100 mbalmer 1044: * partition numbers to break other implementations so lookup
1.33 reinoud 1045: * the number.
1046: */
1.45 reinoud 1047: raw_phys_part = udf_rw16(dscr->pd.part_num);
1.111 reinoud 1048: phys_part = udf_find_raw_phys(ump, raw_phys_part);
1049:
1.45 reinoud 1050: if (phys_part == UDF_PARTITIONS) {
1051: free(dscr, M_UDFVOLD);
1.1 reinoud 1052: return EINVAL;
1.45 reinoud 1053: }
1.1 reinoud 1054:
1.45 reinoud 1055: UDF_UPDATE_DSCR(ump->partitions[phys_part], &dscr->pd);
1056: break;
1057: case TAGID_VOL : /* volume space extender; rare */
1058: DPRINTF(VOLUMES, ("VDS extender ignored\n"));
1059: free(dscr, M_UDFVOLD);
1060: break;
1061: default :
1062: DPRINTF(VOLUMES, ("Unhandled VDS type %d\n",
1063: udf_rw16(dscr->tag.id)));
1064: free(dscr, M_UDFVOLD);
1.9 christos 1065: }
1.1 reinoud 1066:
1.45 reinoud 1067: return 0;
1068: }
1069: #undef UDF_UPDATE_DSCR
1.1 reinoud 1070:
1.45 reinoud 1071: /* --------------------------------------------------------------------- */
1.1 reinoud 1072:
1.45 reinoud 1073: static int
1074: udf_read_vds_extent(struct udf_mount *ump, uint32_t loc, uint32_t len)
1075: {
1076: union dscrptr *dscr;
1077: uint32_t sector_size, dscr_size;
1078: int error;
1.1 reinoud 1079:
1.45 reinoud 1080: sector_size = ump->discinfo.sector_size;
1.1 reinoud 1081:
1.45 reinoud 1082: /* loc is sectornr, len is in bytes */
1083: error = EIO;
1084: while (len) {
1085: error = udf_read_phys_dscr(ump, loc, M_UDFVOLD, &dscr);
1086: if (error)
1087: return error;
1088:
1089: /* blank block is a terminator */
1090: if (dscr == NULL)
1091: return 0;
1092:
1093: /* TERM descriptor is a terminator */
1094: if (udf_rw16(dscr->tag.id) == TAGID_TERM) {
1095: free(dscr, M_UDFVOLD);
1096: return 0;
1097: }
1098:
1099: /* process all others */
1100: dscr_size = udf_tagsize(dscr, sector_size);
1101: error = udf_process_vds_descriptor(ump, dscr);
1102: if (error) {
1103: free(dscr, M_UDFVOLD);
1104: break;
1105: }
1106: assert((dscr_size % sector_size) == 0);
1107:
1108: len -= dscr_size;
1109: loc += dscr_size / sector_size;
1110: }
1111:
1112: return error;
1113: }
1114:
1115:
1116: int
1117: udf_read_vds_space(struct udf_mount *ump)
1118: {
1119: /* struct udf_args *args = &ump->mount_args; */
1120: struct anchor_vdp *anchor, *anchor2;
1121: size_t size;
1122: uint32_t main_loc, main_len;
1123: uint32_t reserve_loc, reserve_len;
1124: int error;
1125:
1126: /*
1127: * read in VDS space provided by the anchors; if one descriptor read
1128: * fails, try the mirror sector.
1129: *
1130: * check if 2nd anchor is different from 1st; if so, go for 2nd. This
1131: * avoids the `compatibility features' of DirectCD that may confuse
1132: * stuff completely.
1133: */
1134:
1135: anchor = ump->anchors[0];
1136: anchor2 = ump->anchors[1];
1137: assert(anchor);
1138:
1139: if (anchor2) {
1140: size = sizeof(struct extent_ad);
1141: if (memcmp(&anchor->main_vds_ex, &anchor2->main_vds_ex, size))
1142: anchor = anchor2;
1143: /* reserve is specified to be a literal copy of main */
1144: }
1145:
1146: main_loc = udf_rw32(anchor->main_vds_ex.loc);
1147: main_len = udf_rw32(anchor->main_vds_ex.len);
1148:
1149: reserve_loc = udf_rw32(anchor->reserve_vds_ex.loc);
1150: reserve_len = udf_rw32(anchor->reserve_vds_ex.len);
1151:
1152: error = udf_read_vds_extent(ump, main_loc, main_len);
1153: if (error) {
1154: printf("UDF mount: reading in reserve VDS extent\n");
1155: error = udf_read_vds_extent(ump, reserve_loc, reserve_len);
1156: }
1157:
1158: return error;
1159: }
1160:
1161: /* --------------------------------------------------------------------- */
1162:
1163: /*
1164: * Read in the logical volume integrity sequence pointed to by our logical
1165: * volume descriptor. Its a sequence that can be extended using fields in the
1166: * integrity descriptor itself. On sequential media only one is found, on
1167: * rewritable media a sequence of descriptors can be found as a form of
1168: * history keeping and on non sequential write-once media the chain is vital
1169: * to allow more and more descriptors to be written. The last descriptor
1170: * written in an extent needs to claim space for a new extent.
1171: */
1172:
1173: static int
1174: udf_retrieve_lvint(struct udf_mount *ump)
1175: {
1176: union dscrptr *dscr;
1177: struct logvol_int_desc *lvint;
1178: struct udf_lvintq *trace;
1179: uint32_t lb_size, lbnum, len;
1180: int dscr_type, error, trace_len;
1181:
1182: lb_size = udf_rw32(ump->logical_vol->lb_size);
1183: len = udf_rw32(ump->logical_vol->integrity_seq_loc.len);
1184: lbnum = udf_rw32(ump->logical_vol->integrity_seq_loc.loc);
1185:
1186: /* clean trace */
1187: memset(ump->lvint_trace, 0,
1188: UDF_LVDINT_SEGMENTS * sizeof(struct udf_lvintq));
1189:
1190: trace_len = 0;
1191: trace = ump->lvint_trace;
1192: trace->start = lbnum;
1193: trace->end = lbnum + len/lb_size;
1194: trace->pos = 0;
1195: trace->wpos = 0;
1196:
1197: lvint = NULL;
1198: dscr = NULL;
1199: error = 0;
1200: while (len) {
1201: trace->pos = lbnum - trace->start;
1202: trace->wpos = trace->pos + 1;
1203:
1204: /* read in our integrity descriptor */
1205: error = udf_read_phys_dscr(ump, lbnum, M_UDFVOLD, &dscr);
1206: if (!error) {
1207: if (dscr == NULL) {
1208: trace->wpos = trace->pos;
1209: break; /* empty terminates */
1210: }
1211: dscr_type = udf_rw16(dscr->tag.id);
1212: if (dscr_type == TAGID_TERM) {
1213: trace->wpos = trace->pos;
1214: break; /* clean terminator */
1215: }
1216: if (dscr_type != TAGID_LOGVOL_INTEGRITY) {
1217: /* fatal... corrupt disc */
1218: error = ENOENT;
1219: break;
1220: }
1221: if (lvint)
1222: free(lvint, M_UDFVOLD);
1223: lvint = &dscr->lvid;
1224: dscr = NULL;
1225: } /* else hope for the best... maybe the next is ok */
1226:
1227: DPRINTFIF(VOLUMES, lvint, ("logvol integrity read, state %s\n",
1228: udf_rw32(lvint->integrity_type) ? "CLOSED" : "OPEN"));
1229:
1230: /* proceed sequential */
1231: lbnum += 1;
1232: len -= lb_size;
1233:
1234: /* are we linking to a new piece? */
1235: if (dscr && lvint->next_extent.len) {
1.142 reinoud 1236: len = udf_rw32(lvint->next_extent.len);
1.45 reinoud 1237: lbnum = udf_rw32(lvint->next_extent.loc);
1238:
1239: if (trace_len >= UDF_LVDINT_SEGMENTS-1) {
1240: /* IEK! segment link full... */
1241: DPRINTF(VOLUMES, ("lvdint segments full\n"));
1242: error = EINVAL;
1243: } else {
1244: trace++;
1245: trace_len++;
1246:
1247: trace->start = lbnum;
1248: trace->end = lbnum + len/lb_size;
1249: trace->pos = 0;
1250: trace->wpos = 0;
1251: }
1252: }
1253: }
1254:
1255: /* clean up the mess, esp. when there is an error */
1256: if (dscr)
1257: free(dscr, M_UDFVOLD);
1258:
1259: if (error && lvint) {
1260: free(lvint, M_UDFVOLD);
1261: lvint = NULL;
1262: }
1263:
1264: if (!lvint)
1265: error = ENOENT;
1266:
1267: ump->logvol_integrity = lvint;
1268: return error;
1269: }
1270:
1271:
1272: static int
1273: udf_loose_lvint_history(struct udf_mount *ump)
1274: {
1275: union dscrptr **bufs, *dscr, *last_dscr;
1276: struct udf_lvintq *trace, *in_trace, *out_trace;
1277: struct logvol_int_desc *lvint;
1278: uint32_t in_ext, in_pos, in_len;
1279: uint32_t out_ext, out_wpos, out_len;
1.121 christos 1280: uint32_t lb_num;
1.45 reinoud 1281: uint32_t len, start;
1.142 reinoud 1282: int ext, sumext, extlen, cnt, cpy_len, dscr_type;
1.45 reinoud 1283: int losing;
1284: int error;
1285:
1286: DPRINTF(VOLUMES, ("need to lose some lvint history\n"));
1287:
1288: /* search smallest extent */
1289: trace = &ump->lvint_trace[0];
1.142 reinoud 1290: sumext = trace->end - trace->start;
1.45 reinoud 1291: for (ext = 1; ext < UDF_LVDINT_SEGMENTS; ext++) {
1292: trace = &ump->lvint_trace[ext];
1293: extlen = trace->end - trace->start;
1294: if (extlen == 0)
1295: break;
1.142 reinoud 1296: sumext += extlen;
1.45 reinoud 1297: }
1.142 reinoud 1298:
1299: /* just one element? its not legal but be bug compatible */
1300: if (sumext == 1) {
1301: /* overwrite the only entry */
1302: DPRINTF(VOLUMES, ("\tLinux bugcompat overwriting sole entry\n"));
1303: trace = &ump->lvint_trace[0];
1304: trace->wpos = 0;
1305: return 0;
1306: }
1307:
1308: losing = MIN(sumext, UDF_LVINT_LOSSAGE);
1309:
1310: /* no sense wiping too much */
1311: if (sumext == UDF_LVINT_LOSSAGE)
1312: losing = UDF_LVINT_LOSSAGE/2;
1.45 reinoud 1313:
1314: DPRINTF(VOLUMES, ("\tlosing %d entries\n", losing));
1315:
1316: /* get buffer for pieces */
1317: bufs = malloc(UDF_LVDINT_SEGMENTS * sizeof(void *), M_TEMP, M_WAITOK);
1318:
1319: in_ext = 0;
1320: in_pos = losing;
1321: in_trace = &ump->lvint_trace[in_ext];
1322: in_len = in_trace->end - in_trace->start;
1323: out_ext = 0;
1324: out_wpos = 0;
1325: out_trace = &ump->lvint_trace[out_ext];
1326: out_len = out_trace->end - out_trace->start;
1327:
1328: last_dscr = NULL;
1329: for(;;) {
1330: out_trace->pos = out_wpos;
1331: out_trace->wpos = out_trace->pos;
1332: if (in_pos >= in_len) {
1333: in_ext++;
1334: in_pos = 0;
1335: in_trace = &ump->lvint_trace[in_ext];
1336: in_len = in_trace->end - in_trace->start;
1337: }
1338: if (out_wpos >= out_len) {
1339: out_ext++;
1340: out_wpos = 0;
1341: out_trace = &ump->lvint_trace[out_ext];
1342: out_len = out_trace->end - out_trace->start;
1343: }
1344: /* copy overlap contents */
1345: cpy_len = MIN(in_len - in_pos, out_len - out_wpos);
1346: cpy_len = MIN(cpy_len, in_len - in_trace->pos);
1347: if (cpy_len == 0)
1348: break;
1349:
1350: /* copy */
1351: DPRINTF(VOLUMES, ("\treading %d lvid descriptors\n", cpy_len));
1352: for (cnt = 0; cnt < cpy_len; cnt++) {
1353: /* read in our integrity descriptor */
1354: lb_num = in_trace->start + in_pos + cnt;
1355: error = udf_read_phys_dscr(ump, lb_num, M_UDFVOLD,
1356: &dscr);
1357: if (error) {
1358: /* copy last one */
1359: dscr = last_dscr;
1360: }
1361: bufs[cnt] = dscr;
1362: if (!error) {
1363: if (dscr == NULL) {
1364: out_trace->pos = out_wpos + cnt;
1365: out_trace->wpos = out_trace->pos;
1366: break; /* empty terminates */
1367: }
1368: dscr_type = udf_rw16(dscr->tag.id);
1369: if (dscr_type == TAGID_TERM) {
1370: out_trace->pos = out_wpos + cnt;
1371: out_trace->wpos = out_trace->pos;
1372: break; /* clean terminator */
1373: }
1374: if (dscr_type != TAGID_LOGVOL_INTEGRITY) {
1375: panic( "UDF integrity sequence "
1376: "corrupted while mounted!\n");
1377: }
1378: last_dscr = dscr;
1379: }
1380: }
1381:
1382: /* patch up if first entry was on error */
1383: if (bufs[0] == NULL) {
1384: for (cnt = 0; cnt < cpy_len; cnt++)
1385: if (bufs[cnt] != NULL)
1386: break;
1387: last_dscr = bufs[cnt];
1388: for (; cnt > 0; cnt--) {
1389: bufs[cnt] = last_dscr;
1390: }
1391: }
1392:
1393: /* glue + write out */
1394: DPRINTF(VOLUMES, ("\twriting %d lvid descriptors\n", cpy_len));
1395: for (cnt = 0; cnt < cpy_len; cnt++) {
1396: lb_num = out_trace->start + out_wpos + cnt;
1397: lvint = &bufs[cnt]->lvid;
1398:
1399: /* set continuation */
1400: len = 0;
1401: start = 0;
1402: if (out_wpos + cnt == out_len) {
1403: /* get continuation */
1404: trace = &ump->lvint_trace[out_ext+1];
1405: len = trace->end - trace->start;
1406: start = trace->start;
1407: }
1408: lvint->next_extent.len = udf_rw32(len);
1409: lvint->next_extent.loc = udf_rw32(start);
1410:
1411: lb_num = trace->start + trace->wpos;
1412: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_DSCR,
1413: bufs[cnt], lb_num, lb_num);
1414: DPRINTFIF(VOLUMES, error,
1415: ("error writing lvint lb_num\n"));
1416: }
1417:
1418: /* free non repeating descriptors */
1419: last_dscr = NULL;
1420: for (cnt = 0; cnt < cpy_len; cnt++) {
1421: if (bufs[cnt] != last_dscr)
1422: free(bufs[cnt], M_UDFVOLD);
1423: last_dscr = bufs[cnt];
1424: }
1425:
1426: /* advance */
1427: in_pos += cpy_len;
1428: out_wpos += cpy_len;
1429: }
1430:
1431: free(bufs, M_TEMP);
1432:
1433: return 0;
1434: }
1435:
1436:
1437: static int
1438: udf_writeout_lvint(struct udf_mount *ump, int lvflag)
1439: {
1440: struct udf_lvintq *trace;
1441: struct timeval now_v;
1442: struct timespec now_s;
1443: uint32_t sector;
1444: int logvol_integrity;
1445: int space, error;
1446:
1447: DPRINTF(VOLUMES, ("writing out logvol integrity descriptor\n"));
1448:
1449: /* get free space in last chunk */
1450: trace = ump->lvint_trace;
1451: while (trace->wpos > (trace->end - trace->start)) {
1452: DPRINTF(VOLUMES, ("skip : start = %d, end = %d, pos = %d, "
1453: "wpos = %d\n", trace->start, trace->end,
1454: trace->pos, trace->wpos));
1455: trace++;
1456: }
1457:
1458: /* check if there is space to append */
1459: space = (trace->end - trace->start) - trace->wpos;
1460: DPRINTF(VOLUMES, ("write start = %d, end = %d, pos = %d, wpos = %d, "
1461: "space = %d\n", trace->start, trace->end, trace->pos,
1462: trace->wpos, space));
1463:
1464: /* get state */
1465: logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
1466: if (logvol_integrity == UDF_INTEGRITY_CLOSED) {
1467: if ((space < 3) && (lvflag & UDF_APPENDONLY_LVINT)) {
1468: /* TODO extent LVINT space if possible */
1469: return EROFS;
1470: }
1471: }
1472:
1473: if (space < 1) {
1474: if (lvflag & UDF_APPENDONLY_LVINT)
1475: return EROFS;
1.142 reinoud 1476:
1.45 reinoud 1477: /* loose history by re-writing extents */
1478: error = udf_loose_lvint_history(ump);
1479: if (error)
1480: return error;
1.142 reinoud 1481:
1482: trace = ump->lvint_trace;
1483: while (trace->wpos > (trace->end - trace->start))
1484: trace++;
1485: space = (trace->end - trace->start) - trace->wpos;
1486: DPRINTF(VOLUMES, ("new try: write start = %d, end = %d, "
1487: "pos = %d, wpos = %d, "
1488: "space = %d\n", trace->start, trace->end,
1489: trace->pos, trace->wpos, space));
1.45 reinoud 1490: }
1491:
1492: /* update our integrity descriptor to identify us and timestamp it */
1493: DPRINTF(VOLUMES, ("updating integrity descriptor\n"));
1494: microtime(&now_v);
1495: TIMEVAL_TO_TIMESPEC(&now_v, &now_s);
1496: udf_timespec_to_timestamp(&now_s, &ump->logvol_integrity->time);
1497: udf_set_regid(&ump->logvol_info->impl_id, IMPL_NAME);
1498: udf_add_impl_regid(ump, &ump->logvol_info->impl_id);
1499:
1500: /* writeout integrity descriptor */
1501: sector = trace->start + trace->wpos;
1502: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_DSCR,
1503: (union dscrptr *) ump->logvol_integrity,
1504: sector, sector);
1505: DPRINTF(VOLUMES, ("writeout lvint : error = %d\n", error));
1506: if (error)
1507: return error;
1508:
1509: /* advance write position */
1510: trace->wpos++; space--;
1511: if (space >= 1) {
1512: /* append terminator */
1513: sector = trace->start + trace->wpos;
1514: error = udf_write_terminator(ump, sector);
1515:
1516: DPRINTF(VOLUMES, ("write terminator : error = %d\n", error));
1517: }
1518:
1519: space = (trace->end - trace->start) - trace->wpos;
1520: DPRINTF(VOLUMES, ("write start = %d, end = %d, pos = %d, wpos = %d, "
1521: "space = %d\n", trace->start, trace->end, trace->pos,
1522: trace->wpos, space));
1523: DPRINTF(VOLUMES, ("finished writing out logvol integrity descriptor "
1.158 andvar 1524: "successfully\n"));
1.45 reinoud 1525:
1526: return error;
1527: }
1528:
1529: /* --------------------------------------------------------------------- */
1530:
1531: static int
1.68 reinoud 1532: udf_read_physical_partition_spacetables(struct udf_mount *ump)
1.45 reinoud 1533: {
1534: union dscrptr *dscr;
1535: /* struct udf_args *args = &ump->mount_args; */
1536: struct part_desc *partd;
1537: struct part_hdr_desc *parthdr;
1538: struct udf_bitmap *bitmap;
1539: uint32_t phys_part;
1540: uint32_t lb_num, len;
1541: int error, dscr_type;
1542:
1543: /* unallocated space map */
1544: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1545: partd = ump->partitions[phys_part];
1546: if (partd == NULL)
1547: continue;
1548: parthdr = &partd->_impl_use.part_hdr;
1549:
1550: lb_num = udf_rw32(partd->start_loc);
1551: lb_num += udf_rw32(parthdr->unalloc_space_bitmap.lb_num);
1552: len = udf_rw32(parthdr->unalloc_space_bitmap.len);
1553: if (len == 0)
1554: continue;
1555:
1556: DPRINTF(VOLUMES, ("Read unalloc. space bitmap %d\n", lb_num));
1557: error = udf_read_phys_dscr(ump, lb_num, M_UDFVOLD, &dscr);
1558: if (!error && dscr) {
1559: /* analyse */
1560: dscr_type = udf_rw16(dscr->tag.id);
1561: if (dscr_type == TAGID_SPACE_BITMAP) {
1562: DPRINTF(VOLUMES, ("Accepting space bitmap\n"));
1563: ump->part_unalloc_dscr[phys_part] = &dscr->sbd;
1564:
1565: /* fill in ump->part_unalloc_bits */
1566: bitmap = &ump->part_unalloc_bits[phys_part];
1567: bitmap->blob = (uint8_t *) dscr;
1568: bitmap->bits = dscr->sbd.data;
1569: bitmap->max_offset = udf_rw32(dscr->sbd.num_bits);
1570: bitmap->pages = NULL; /* TODO */
1571: bitmap->data_pos = 0;
1572: bitmap->metadata_pos = 0;
1573: } else {
1574: free(dscr, M_UDFVOLD);
1575:
1576: printf( "UDF mount: error reading unallocated "
1577: "space bitmap\n");
1578: return EROFS;
1579: }
1580: } else {
1581: /* blank not allowed */
1582: printf("UDF mount: blank unallocated space bitmap\n");
1583: return EROFS;
1584: }
1585: }
1586:
1587: /* unallocated space table (not supported) */
1588: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1589: partd = ump->partitions[phys_part];
1590: if (partd == NULL)
1591: continue;
1592: parthdr = &partd->_impl_use.part_hdr;
1.152 skrll 1593:
1.45 reinoud 1594: len = udf_rw32(parthdr->unalloc_space_table.len);
1595: if (len) {
1596: printf("UDF mount: space tables not supported\n");
1597: return EROFS;
1598: }
1599: }
1600:
1601: /* freed space map */
1602: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1603: partd = ump->partitions[phys_part];
1604: if (partd == NULL)
1605: continue;
1606: parthdr = &partd->_impl_use.part_hdr;
1607:
1608: /* freed space map */
1609: lb_num = udf_rw32(partd->start_loc);
1610: lb_num += udf_rw32(parthdr->freed_space_bitmap.lb_num);
1611: len = udf_rw32(parthdr->freed_space_bitmap.len);
1612: if (len == 0)
1613: continue;
1614:
1615: DPRINTF(VOLUMES, ("Read unalloc. space bitmap %d\n", lb_num));
1616: error = udf_read_phys_dscr(ump, lb_num, M_UDFVOLD, &dscr);
1617: if (!error && dscr) {
1618: /* analyse */
1619: dscr_type = udf_rw16(dscr->tag.id);
1620: if (dscr_type == TAGID_SPACE_BITMAP) {
1621: DPRINTF(VOLUMES, ("Accepting space bitmap\n"));
1622: ump->part_freed_dscr[phys_part] = &dscr->sbd;
1623:
1624: /* fill in ump->part_freed_bits */
1625: bitmap = &ump->part_unalloc_bits[phys_part];
1626: bitmap->blob = (uint8_t *) dscr;
1627: bitmap->bits = dscr->sbd.data;
1628: bitmap->max_offset = udf_rw32(dscr->sbd.num_bits);
1629: bitmap->pages = NULL; /* TODO */
1630: bitmap->data_pos = 0;
1631: bitmap->metadata_pos = 0;
1632: } else {
1633: free(dscr, M_UDFVOLD);
1634:
1635: printf( "UDF mount: error reading freed "
1636: "space bitmap\n");
1637: return EROFS;
1638: }
1639: } else {
1640: /* blank not allowed */
1641: printf("UDF mount: blank freed space bitmap\n");
1642: return EROFS;
1643: }
1644: }
1645:
1646: /* freed space table (not supported) */
1647: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1648: partd = ump->partitions[phys_part];
1649: if (partd == NULL)
1650: continue;
1651: parthdr = &partd->_impl_use.part_hdr;
1.152 skrll 1652:
1.45 reinoud 1653: len = udf_rw32(parthdr->freed_space_table.len);
1654: if (len) {
1655: printf("UDF mount: space tables not supported\n");
1656: return EROFS;
1657: }
1658: }
1659:
1660: return 0;
1661: }
1662:
1663:
1664: /* TODO implement async writeout */
1665: int
1.68 reinoud 1666: udf_write_physical_partition_spacetables(struct udf_mount *ump, int waitfor)
1.45 reinoud 1667: {
1668: union dscrptr *dscr;
1669: /* struct udf_args *args = &ump->mount_args; */
1670: struct part_desc *partd;
1671: struct part_hdr_desc *parthdr;
1672: uint32_t phys_part;
1673: uint32_t lb_num, len, ptov;
1674: int error_all, error;
1675:
1676: error_all = 0;
1677: /* unallocated space map */
1678: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1679: partd = ump->partitions[phys_part];
1680: if (partd == NULL)
1681: continue;
1682: parthdr = &partd->_impl_use.part_hdr;
1683:
1684: ptov = udf_rw32(partd->start_loc);
1685: lb_num = udf_rw32(parthdr->unalloc_space_bitmap.lb_num);
1686: len = udf_rw32(parthdr->unalloc_space_bitmap.len);
1687: if (len == 0)
1688: continue;
1689:
1690: DPRINTF(VOLUMES, ("Write unalloc. space bitmap %d\n",
1691: lb_num + ptov));
1692: dscr = (union dscrptr *) ump->part_unalloc_dscr[phys_part];
1.142 reinoud 1693:
1694: /* force a sane minimum for descriptors CRC length */
1695: /* see UDF 2.3.1.2 and 2.3.8.1 */
1696: KASSERT(udf_rw16(dscr->sbd.tag.id) == TAGID_SPACE_BITMAP);
1697: if (udf_rw16(dscr->sbd.tag.desc_crc_len) == 0)
1698: dscr->sbd.tag.desc_crc_len = udf_rw16(8);
1699:
1700: /* write out space bitmap */
1.45 reinoud 1701: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_DSCR,
1702: (union dscrptr *) dscr,
1703: ptov + lb_num, lb_num);
1704: if (error) {
1705: DPRINTF(VOLUMES, ("\tfailed!! (error %d)\n", error));
1706: error_all = error;
1707: }
1708: }
1709:
1710: /* freed space map */
1711: for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
1712: partd = ump->partitions[phys_part];
1713: if (partd == NULL)
1714: continue;
1715: parthdr = &partd->_impl_use.part_hdr;
1716:
1717: /* freed space map */
1718: ptov = udf_rw32(partd->start_loc);
1719: lb_num = udf_rw32(parthdr->freed_space_bitmap.lb_num);
1720: len = udf_rw32(parthdr->freed_space_bitmap.len);
1721: if (len == 0)
1722: continue;
1723:
1724: DPRINTF(VOLUMES, ("Write freed space bitmap %d\n",
1725: lb_num + ptov));
1726: dscr = (union dscrptr *) ump->part_freed_dscr[phys_part];
1.142 reinoud 1727:
1728: /* force a sane minimum for descriptors CRC length */
1729: /* see UDF 2.3.1.2 and 2.3.8.1 */
1730: KASSERT(udf_rw16(dscr->sbd.tag.id) == TAGID_SPACE_BITMAP);
1731: if (udf_rw16(dscr->sbd.tag.desc_crc_len) == 0)
1732: dscr->sbd.tag.desc_crc_len = udf_rw16(8);
1733:
1734: /* write out space bitmap */
1.45 reinoud 1735: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_DSCR,
1736: (union dscrptr *) dscr,
1737: ptov + lb_num, lb_num);
1738: if (error) {
1739: DPRINTF(VOLUMES, ("\tfailed!! (error %d)\n", error));
1740: error_all = error;
1741: }
1742: }
1743:
1744: return error_all;
1745: }
1746:
1.70 reinoud 1747:
1748: static int
1749: udf_read_metadata_partition_spacetable(struct udf_mount *ump)
1750: {
1751: struct udf_node *bitmap_node;
1752: union dscrptr *dscr;
1753: struct udf_bitmap *bitmap;
1754: uint64_t inflen;
1755: int error, dscr_type;
1756:
1757: bitmap_node = ump->metadatabitmap_node;
1758:
1759: /* only read in when metadata bitmap node is read in */
1760: if (bitmap_node == NULL)
1761: return 0;
1762:
1763: if (bitmap_node->fe) {
1764: inflen = udf_rw64(bitmap_node->fe->inf_len);
1765: } else {
1766: KASSERT(bitmap_node->efe);
1767: inflen = udf_rw64(bitmap_node->efe->inf_len);
1768: }
1769:
1770: DPRINTF(VOLUMES, ("Reading metadata space bitmap for "
1771: "%"PRIu64" bytes\n", inflen));
1772:
1773: /* allocate space for bitmap */
1.144 jdolecek 1774: dscr = malloc(inflen, M_UDFVOLD, M_WAITOK);
1.70 reinoud 1775: if (!dscr)
1776: return ENOMEM;
1777:
1778: /* set vnode type to regular file or we can't read from it! */
1779: bitmap_node->vnode->v_type = VREG;
1780:
1781: /* read in complete metadata bitmap file */
1782: error = vn_rdwr(UIO_READ, bitmap_node->vnode,
1783: dscr,
1784: inflen, 0,
1785: UIO_SYSSPACE,
1.109 reinoud 1786: IO_SYNC | IO_ALTSEMANTICS, FSCRED,
1.70 reinoud 1787: NULL, NULL);
1788: if (error) {
1789: DPRINTF(VOLUMES, ("Error reading metadata space bitmap\n"));
1790: goto errorout;
1791: }
1792:
1793: /* analyse */
1794: dscr_type = udf_rw16(dscr->tag.id);
1795: if (dscr_type == TAGID_SPACE_BITMAP) {
1796: DPRINTF(VOLUMES, ("Accepting metadata space bitmap\n"));
1797: ump->metadata_unalloc_dscr = &dscr->sbd;
1798:
1799: /* fill in bitmap bits */
1800: bitmap = &ump->metadata_unalloc_bits;
1801: bitmap->blob = (uint8_t *) dscr;
1802: bitmap->bits = dscr->sbd.data;
1803: bitmap->max_offset = udf_rw32(dscr->sbd.num_bits);
1804: bitmap->pages = NULL; /* TODO */
1805: bitmap->data_pos = 0;
1806: bitmap->metadata_pos = 0;
1807: } else {
1808: DPRINTF(VOLUMES, ("No valid bitmap found!\n"));
1809: goto errorout;
1810: }
1811:
1812: return 0;
1813:
1814: errorout:
1815: free(dscr, M_UDFVOLD);
1816: printf( "UDF mount: error reading unallocated "
1817: "space bitmap for metadata partition\n");
1818: return EROFS;
1819: }
1820:
1821:
1822: int
1823: udf_write_metadata_partition_spacetable(struct udf_mount *ump, int waitfor)
1824: {
1825: struct udf_node *bitmap_node;
1826: union dscrptr *dscr;
1.121 christos 1827: uint64_t new_inflen;
1.70 reinoud 1828: int dummy, error;
1829:
1830: bitmap_node = ump->metadatabitmap_node;
1831:
1832: /* only write out when metadata bitmap node is known */
1833: if (bitmap_node == NULL)
1834: return 0;
1835:
1.121 christos 1836: if (!bitmap_node->fe) {
1.70 reinoud 1837: KASSERT(bitmap_node->efe);
1838: }
1839:
1840: /* reduce length to zero */
1841: dscr = (union dscrptr *) ump->metadata_unalloc_dscr;
1842: new_inflen = udf_tagsize(dscr, 1);
1843:
1.125 reinoud 1844: DPRINTF(VOLUMES, ("Resize and write out metadata space bitmap "
1845: " for %"PRIu64" bytes\n", new_inflen));
1.70 reinoud 1846:
1.71 reinoud 1847: error = udf_resize_node(bitmap_node, new_inflen, &dummy);
1.70 reinoud 1848: if (error)
1849: printf("Error resizing metadata space bitmap\n");
1850:
1851: error = vn_rdwr(UIO_WRITE, bitmap_node->vnode,
1852: dscr,
1853: new_inflen, 0,
1854: UIO_SYSSPACE,
1.109 reinoud 1855: IO_ALTSEMANTICS, FSCRED,
1.70 reinoud 1856: NULL, NULL);
1857:
1858: bitmap_node->i_flags |= IN_MODIFIED;
1.119 chs 1859: error = vflushbuf(bitmap_node->vnode, FSYNC_WAIT);
1.114 hannken 1860: if (error == 0)
1861: error = VOP_FSYNC(bitmap_node->vnode,
1862: FSCRED, FSYNC_WAIT, 0, 0);
1.70 reinoud 1863:
1864: if (error)
1865: printf( "Error writing out metadata partition unalloced "
1866: "space bitmap!\n");
1867:
1868: return error;
1869: }
1870:
1871:
1872: /* --------------------------------------------------------------------- */
1873:
1.45 reinoud 1874: /*
1875: * Checks if ump's vds information is correct and complete
1876: */
1877:
1878: int
1879: udf_process_vds(struct udf_mount *ump) {
1880: union udf_pmap *mapping;
1881: /* struct udf_args *args = &ump->mount_args; */
1882: struct logvol_int_desc *lvint;
1883: struct udf_logvol_info *lvinfo;
1.121 christos 1884: uint32_t n_pm;
1.45 reinoud 1885: uint8_t *pmap_pos;
1886: char *domain_name, *map_name;
1887: const char *check_name;
1888: char bits[128];
1889: int pmap_stype, pmap_size;
1.71 reinoud 1890: int pmap_type, log_part, phys_part, raw_phys_part, maps_on;
1.45 reinoud 1891: int n_phys, n_virt, n_spar, n_meta;
1.121 christos 1892: int len;
1.45 reinoud 1893:
1894: if (ump == NULL)
1895: return ENOENT;
1896:
1897: /* we need at least an anchor (trivial, but for safety) */
1898: if (ump->anchors[0] == NULL)
1899: return EINVAL;
1900:
1901: /* we need at least one primary and one logical volume descriptor */
1902: if ((ump->primary_vol == NULL) || (ump->logical_vol) == NULL)
1903: return EINVAL;
1904:
1905: /* we need at least one partition descriptor */
1906: if (ump->partitions[0] == NULL)
1907: return EINVAL;
1908:
1909: /* check logical volume sector size verses device sector size */
1910: if (udf_rw32(ump->logical_vol->lb_size) != ump->discinfo.sector_size) {
1911: printf("UDF mount: format violation, lb_size != sector size\n");
1912: return EINVAL;
1913: }
1914:
1915: /* check domain name */
1916: domain_name = ump->logical_vol->domain_id.id;
1917: if (strncmp(domain_name, "*OSTA UDF Compliant", 20)) {
1918: printf("mount_udf: disc not OSTA UDF Compliant, aborting\n");
1919: return EINVAL;
1920: }
1921:
1922: /* retrieve logical volume integrity sequence */
1.121 christos 1923: (void)udf_retrieve_lvint(ump);
1.45 reinoud 1924:
1925: /*
1926: * We need at least one logvol integrity descriptor recorded. Note
1927: * that its OK to have an open logical volume integrity here. The VAT
1928: * will close/update the integrity.
1929: */
1930: if (ump->logvol_integrity == NULL)
1931: return EINVAL;
1932:
1933: /* process derived structures */
1934: n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
1935: lvint = ump->logvol_integrity;
1936: lvinfo = (struct udf_logvol_info *) (&lvint->tables[2 * n_pm]);
1937: ump->logvol_info = lvinfo;
1938:
1939: /* TODO check udf versions? */
1940:
1941: /*
1942: * check logvol mappings: effective virt->log partmap translation
1943: * check and recording of the mapping results. Saves expensive
1944: * strncmp() in tight places.
1945: */
1946: DPRINTF(VOLUMES, ("checking logvol mappings\n"));
1947: n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
1948: pmap_pos = ump->logical_vol->maps;
1949:
1950: if (n_pm > UDF_PMAPS) {
1951: printf("UDF mount: too many mappings\n");
1952: return EINVAL;
1953: }
1954:
1.71 reinoud 1955: /* count types and set partition numbers */
1956: ump->data_part = ump->node_part = ump->fids_part = 0;
1.45 reinoud 1957: n_phys = n_virt = n_spar = n_meta = 0;
1958: for (log_part = 0; log_part < n_pm; log_part++) {
1959: mapping = (union udf_pmap *) pmap_pos;
1960: pmap_stype = pmap_pos[0];
1961: pmap_size = pmap_pos[1];
1962: switch (pmap_stype) {
1963: case 1: /* physical mapping */
1964: /* volseq = udf_rw16(mapping->pm1.vol_seq_num); */
1965: raw_phys_part = udf_rw16(mapping->pm1.part_num);
1966: pmap_type = UDF_VTOP_TYPE_PHYS;
1967: n_phys++;
1.71 reinoud 1968: ump->data_part = log_part;
1969: ump->node_part = log_part;
1970: ump->fids_part = log_part;
1.45 reinoud 1971: break;
1972: case 2: /* virtual/sparable/meta mapping */
1973: map_name = mapping->pm2.part_id.id;
1974: /* volseq = udf_rw16(mapping->pm2.vol_seq_num); */
1975: raw_phys_part = udf_rw16(mapping->pm2.part_num);
1976: pmap_type = UDF_VTOP_TYPE_UNKNOWN;
1977: len = UDF_REGID_ID_SIZE;
1978:
1979: check_name = "*UDF Virtual Partition";
1980: if (strncmp(map_name, check_name, len) == 0) {
1981: pmap_type = UDF_VTOP_TYPE_VIRT;
1982: n_virt++;
1.71 reinoud 1983: ump->node_part = log_part;
1.45 reinoud 1984: break;
1985: }
1986: check_name = "*UDF Sparable Partition";
1987: if (strncmp(map_name, check_name, len) == 0) {
1988: pmap_type = UDF_VTOP_TYPE_SPARABLE;
1989: n_spar++;
1.71 reinoud 1990: ump->data_part = log_part;
1991: ump->node_part = log_part;
1992: ump->fids_part = log_part;
1.45 reinoud 1993: break;
1994: }
1995: check_name = "*UDF Metadata Partition";
1996: if (strncmp(map_name, check_name, len) == 0) {
1997: pmap_type = UDF_VTOP_TYPE_META;
1998: n_meta++;
1.71 reinoud 1999: ump->node_part = log_part;
2000: ump->fids_part = log_part;
1.45 reinoud 2001: break;
2002: }
2003: break;
2004: default:
2005: return EINVAL;
2006: }
2007:
2008: /*
2009: * BUGALERT: some rogue implementations use random physical
1.100 mbalmer 2010: * partition numbers to break other implementations so lookup
1.45 reinoud 2011: * the number.
2012: */
1.111 reinoud 2013: phys_part = udf_find_raw_phys(ump, raw_phys_part);
1.45 reinoud 2014:
2015: DPRINTF(VOLUMES, ("\t%d -> %d(%d) type %d\n", log_part,
2016: raw_phys_part, phys_part, pmap_type));
1.152 skrll 2017:
1.45 reinoud 2018: if (phys_part == UDF_PARTITIONS)
2019: return EINVAL;
2020: if (pmap_type == UDF_VTOP_TYPE_UNKNOWN)
2021: return EINVAL;
2022:
2023: ump->vtop [log_part] = phys_part;
2024: ump->vtop_tp[log_part] = pmap_type;
2025:
2026: pmap_pos += pmap_size;
2027: }
2028: /* not winning the beauty contest */
2029: ump->vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
2030:
2031: /* test some basic UDF assertions/requirements */
2032: if ((n_virt > 1) || (n_spar > 1) || (n_meta > 1))
2033: return EINVAL;
2034:
2035: if (n_virt) {
2036: if ((n_phys == 0) || n_spar || n_meta)
2037: return EINVAL;
2038: }
2039: if (n_spar + n_phys == 0)
2040: return EINVAL;
2041:
1.71 reinoud 2042: /* select allocation type for each logical partition */
2043: for (log_part = 0; log_part < n_pm; log_part++) {
2044: maps_on = ump->vtop[log_part];
2045: switch (ump->vtop_tp[log_part]) {
2046: case UDF_VTOP_TYPE_PHYS :
2047: assert(maps_on == log_part);
2048: ump->vtop_alloc[log_part] = UDF_ALLOC_SPACEMAP;
2049: break;
2050: case UDF_VTOP_TYPE_VIRT :
2051: ump->vtop_alloc[log_part] = UDF_ALLOC_VAT;
2052: ump->vtop_alloc[maps_on] = UDF_ALLOC_SEQUENTIAL;
2053: break;
2054: case UDF_VTOP_TYPE_SPARABLE :
2055: assert(maps_on == log_part);
2056: ump->vtop_alloc[log_part] = UDF_ALLOC_SPACEMAP;
2057: break;
2058: case UDF_VTOP_TYPE_META :
2059: ump->vtop_alloc[log_part] = UDF_ALLOC_METABITMAP;
2060: if (ump->discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {
2061: /* special case for UDF 2.60 */
2062: ump->vtop_alloc[log_part] = UDF_ALLOC_METASEQUENTIAL;
2063: ump->vtop_alloc[maps_on] = UDF_ALLOC_SEQUENTIAL;
2064: }
2065: break;
2066: default:
1.159 msaitoh 2067: panic("bad allocation type in udf's ump->vtop\n");
1.45 reinoud 2068: }
2069: }
2070:
2071: /* determine logical volume open/closure actions */
2072: if (n_virt) {
2073: ump->lvopen = 0;
1.85 reinoud 2074: if (ump->discinfo.last_session_state == MMC_STATE_EMPTY)
1.45 reinoud 2075: ump->lvopen |= UDF_OPEN_SESSION ;
2076: ump->lvclose = UDF_WRITE_VAT;
2077: if (ump->mount_args.udfmflags & UDFMNT_CLOSESESSION)
2078: ump->lvclose |= UDF_CLOSE_SESSION;
2079: } else {
2080: /* `normal' rewritable or non sequential media */
2081: ump->lvopen = UDF_WRITE_LVINT;
2082: ump->lvclose = UDF_WRITE_LVINT;
2083: if ((ump->discinfo.mmc_cur & MMC_CAP_REWRITABLE) == 0)
1.113 reinoud 2084: ump->lvopen |= UDF_APPENDONLY_LVINT;
2085: if ((ump->discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE))
2086: ump->lvopen &= ~UDF_APPENDONLY_LVINT;
1.45 reinoud 2087: }
2088:
2089: /*
1.100 mbalmer 2090: * Determine sheduler error behaviour. For virtual partitions, update
1.45 reinoud 2091: * the trackinfo; for sparable partitions replace a whole block on the
1.154 andvar 2092: * sparable table. Always requeue.
1.45 reinoud 2093: */
2094: ump->lvreadwrite = 0;
2095: if (n_virt)
2096: ump->lvreadwrite = UDF_UPDATE_TRACKINFO;
2097: if (n_spar)
2098: ump->lvreadwrite = UDF_REMAP_BLOCK;
2099:
2100: /*
2101: * Select our sheduler
2102: */
2103: ump->strategy = &udf_strat_rmw;
2104: if (n_virt || (ump->discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE))
2105: ump->strategy = &udf_strat_sequential;
2106: if ((ump->discinfo.mmc_class == MMC_CLASS_DISC) ||
2107: (ump->discinfo.mmc_class == MMC_CLASS_UNKN))
2108: ump->strategy = &udf_strat_direct;
2109: if (n_spar)
2110: ump->strategy = &udf_strat_rmw;
2111:
1.75 reinoud 2112: #if 0
2113: /* read-only access won't benefit from the other shedulers */
2114: if (ump->vfs_mountp->mnt_flag & MNT_RDONLY)
2115: ump->strategy = &udf_strat_direct;
2116: #endif
2117:
1.45 reinoud 2118: /* print results */
1.71 reinoud 2119: DPRINTF(VOLUMES, ("\tdata partition %d\n", ump->data_part));
2120: DPRINTF(VOLUMES, ("\t\talloc scheme %d\n", ump->vtop_alloc[ump->data_part]));
2121: DPRINTF(VOLUMES, ("\tnode partition %d\n", ump->node_part));
2122: DPRINTF(VOLUMES, ("\t\talloc scheme %d\n", ump->vtop_alloc[ump->node_part]));
2123: DPRINTF(VOLUMES, ("\tfids partition %d\n", ump->fids_part));
2124: DPRINTF(VOLUMES, ("\t\talloc scheme %d\n", ump->vtop_alloc[ump->fids_part]));
1.45 reinoud 2125:
1.80 christos 2126: snprintb(bits, sizeof(bits), UDFLOGVOL_BITS, ump->lvopen);
1.45 reinoud 2127: DPRINTF(VOLUMES, ("\tactions on logvol open %s\n", bits));
1.80 christos 2128: snprintb(bits, sizeof(bits), UDFLOGVOL_BITS, ump->lvclose);
1.45 reinoud 2129: DPRINTF(VOLUMES, ("\tactions on logvol close %s\n", bits));
1.80 christos 2130: snprintb(bits, sizeof(bits), UDFONERROR_BITS, ump->lvreadwrite);
1.45 reinoud 2131: DPRINTF(VOLUMES, ("\tactions on logvol errors %s\n", bits));
2132:
1.152 skrll 2133: DPRINTF(VOLUMES, ("\tselected sheduler `%s`\n",
1.45 reinoud 2134: (ump->strategy == &udf_strat_direct) ? "Direct" :
2135: (ump->strategy == &udf_strat_sequential) ? "Sequential" :
2136: (ump->strategy == &udf_strat_rmw) ? "RMW" : "UNKNOWN!"));
2137:
2138: /* signal its OK for now */
2139: return 0;
2140: }
2141:
2142: /* --------------------------------------------------------------------- */
2143:
2144: /*
2145: * Update logical volume name in all structures that keep a record of it. We
2146: * use memmove since each of them might be specified as a source.
2147: *
2148: * Note that it doesn't update the VAT structure!
2149: */
2150:
2151: static void
2152: udf_update_logvolname(struct udf_mount *ump, char *logvol_id)
2153: {
2154: struct logvol_desc *lvd = NULL;
2155: struct fileset_desc *fsd = NULL;
2156: struct udf_lv_info *lvi = NULL;
2157:
2158: DPRINTF(VOLUMES, ("Updating logical volume name\n"));
2159: lvd = ump->logical_vol;
2160: fsd = ump->fileset_desc;
2161: if (ump->implementation)
2162: lvi = &ump->implementation->_impl_use.lv_info;
2163:
2164: /* logvol's id might be specified as origional so use memmove here */
2165: memmove(lvd->logvol_id, logvol_id, 128);
2166: if (fsd)
2167: memmove(fsd->logvol_id, logvol_id, 128);
2168: if (lvi)
2169: memmove(lvi->logvol_id, logvol_id, 128);
2170: }
2171:
2172: /* --------------------------------------------------------------------- */
2173:
1.55 reinoud 2174: void
1.51 reinoud 2175: udf_inittag(struct udf_mount *ump, struct desc_tag *tag, int tagid,
2176: uint32_t sector)
2177: {
2178: assert(ump->logical_vol);
2179:
2180: tag->id = udf_rw16(tagid);
2181: tag->descriptor_ver = ump->logical_vol->tag.descriptor_ver;
2182: tag->cksum = 0;
2183: tag->reserved = 0;
2184: tag->serial_num = ump->logical_vol->tag.serial_num;
2185: tag->tag_loc = udf_rw32(sector);
2186: }
2187:
2188:
2189: uint64_t
2190: udf_advance_uniqueid(struct udf_mount *ump)
2191: {
2192: uint64_t unique_id;
2193:
2194: mutex_enter(&ump->logvol_mutex);
2195: unique_id = udf_rw64(ump->logvol_integrity->lvint_next_unique_id);
2196: if (unique_id < 0x10)
2197: unique_id = 0x10;
2198: ump->logvol_integrity->lvint_next_unique_id = udf_rw64(unique_id + 1);
2199: mutex_exit(&ump->logvol_mutex);
2200:
2201: return unique_id;
2202: }
2203:
2204:
2205: static void
2206: udf_adjust_filecount(struct udf_node *udf_node, int sign)
2207: {
2208: struct udf_mount *ump = udf_node->ump;
2209: uint32_t num_dirs, num_files;
2210: int udf_file_type;
2211:
2212: /* get file type */
2213: if (udf_node->fe) {
2214: udf_file_type = udf_node->fe->icbtag.file_type;
2215: } else {
2216: udf_file_type = udf_node->efe->icbtag.file_type;
2217: }
2218:
2219: /* adjust file count */
2220: mutex_enter(&ump->allocate_mutex);
2221: if (udf_file_type == UDF_ICB_FILETYPE_DIRECTORY) {
2222: num_dirs = udf_rw32(ump->logvol_info->num_directories);
2223: ump->logvol_info->num_directories =
2224: udf_rw32((num_dirs + sign));
2225: } else {
2226: num_files = udf_rw32(ump->logvol_info->num_files);
2227: ump->logvol_info->num_files =
2228: udf_rw32((num_files + sign));
2229: }
2230: mutex_exit(&ump->allocate_mutex);
2231: }
2232:
2233:
2234: void
2235: udf_osta_charset(struct charspec *charspec)
2236: {
1.87 cegger 2237: memset(charspec, 0, sizeof(struct charspec));
1.51 reinoud 2238: charspec->type = 0;
2239: strcpy((char *) charspec->inf, "OSTA Compressed Unicode");
2240: }
2241:
2242:
2243: /* first call udf_set_regid and then the suffix */
2244: void
2245: udf_set_regid(struct regid *regid, char const *name)
2246: {
1.87 cegger 2247: memset(regid, 0, sizeof(struct regid));
1.51 reinoud 2248: regid->flags = 0; /* not dirty and not protected */
2249: strcpy((char *) regid->id, name);
2250: }
2251:
2252:
2253: void
2254: udf_add_domain_regid(struct udf_mount *ump, struct regid *regid)
2255: {
2256: uint16_t *ver;
2257:
2258: ver = (uint16_t *) regid->id_suffix;
2259: *ver = ump->logvol_info->min_udf_readver;
2260: }
2261:
2262:
2263: void
2264: udf_add_udf_regid(struct udf_mount *ump, struct regid *regid)
2265: {
2266: uint16_t *ver;
2267:
2268: ver = (uint16_t *) regid->id_suffix;
2269: *ver = ump->logvol_info->min_udf_readver;
2270:
2271: regid->id_suffix[2] = 4; /* unix */
2272: regid->id_suffix[3] = 8; /* NetBSD */
2273: }
2274:
2275:
2276: void
2277: udf_add_impl_regid(struct udf_mount *ump, struct regid *regid)
2278: {
2279: regid->id_suffix[0] = 4; /* unix */
2280: regid->id_suffix[1] = 8; /* NetBSD */
2281: }
2282:
2283:
2284: void
2285: udf_add_app_regid(struct udf_mount *ump, struct regid *regid)
2286: {
2287: regid->id_suffix[0] = APP_VERSION_MAIN;
2288: regid->id_suffix[1] = APP_VERSION_SUB;
2289: }
2290:
2291: static int
2292: udf_create_parentfid(struct udf_mount *ump, struct fileid_desc *fid,
2293: struct long_ad *parent, uint64_t unique_id)
2294: {
2295: /* the size of an empty FID is 38 but needs to be a multiple of 4 */
2296: int fidsize = 40;
2297:
2298: udf_inittag(ump, &fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num));
2299: fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
2300: fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
2301: fid->icb = *parent;
2302: fid->icb.longad_uniqueid = udf_rw32((uint32_t) unique_id);
1.88 reinoud 2303: fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
1.51 reinoud 2304: (void) udf_validate_tag_and_crc_sums((union dscrptr *) fid);
2305:
2306: return fidsize;
2307: }
2308:
2309: /* --------------------------------------------------------------------- */
2310:
1.45 reinoud 2311: /*
1.51 reinoud 2312: * Extended attribute support. UDF knows of 3 places for extended attributes:
1.45 reinoud 2313: *
1.51 reinoud 2314: * (a) inside the file's (e)fe in the length of the extended attribute area
2315: * before the allocation descriptors/filedata
1.45 reinoud 2316: *
1.152 skrll 2317: * (b) in a file referenced by (e)fe->ext_attr_icb and
1.45 reinoud 2318: *
2319: * (c) in the e(fe)'s associated stream directory that can hold various
2320: * sub-files. In the stream directory a few fixed named subfiles are reserved
2321: * for NT/Unix ACL's and OS/2 attributes.
1.152 skrll 2322: *
1.154 andvar 2323: * NOTE: Extended attributes are read randomly but always written
2324: * *atomically*. For ACL's this interface is probably different but not known
1.45 reinoud 2325: * to me yet.
1.51 reinoud 2326: *
1.154 andvar 2327: * Order of extended attributes in a space:
1.51 reinoud 2328: * ECMA 167 EAs
2329: * Non block aligned Implementation Use EAs
2330: * Block aligned Implementation Use EAs
2331: * Application Use EAs
1.45 reinoud 2332: */
2333:
2334: static int
2335: udf_impl_extattr_check(struct impl_extattr_entry *implext)
2336: {
2337: uint16_t *spos;
2338:
2339: if (strncmp(implext->imp_id.id, "*UDF", 4) == 0) {
2340: /* checksum valid? */
2341: DPRINTF(EXTATTR, ("checking UDF impl. attr checksum\n"));
2342: spos = (uint16_t *) implext->data;
2343: if (udf_rw16(*spos) != udf_ea_cksum((uint8_t *) implext))
2344: return EINVAL;
2345: }
2346: return 0;
2347: }
2348:
2349: static void
2350: udf_calc_impl_extattr_checksum(struct impl_extattr_entry *implext)
2351: {
2352: uint16_t *spos;
2353:
2354: if (strncmp(implext->imp_id.id, "*UDF", 4) == 0) {
2355: /* set checksum */
2356: spos = (uint16_t *) implext->data;
2357: *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
2358: }
2359: }
2360:
2361:
2362: int
2363: udf_extattr_search_intern(struct udf_node *node,
2364: uint32_t sattr, char const *sattrname,
2365: uint32_t *offsetp, uint32_t *lengthp)
2366: {
2367: struct extattrhdr_desc *eahdr;
2368: struct extattr_entry *attrhdr;
2369: struct impl_extattr_entry *implext;
2370: uint32_t offset, a_l, sector_size;
2371: int32_t l_ea;
2372: uint8_t *pos;
2373: int error;
2374:
2375: /* get mountpoint */
2376: sector_size = node->ump->discinfo.sector_size;
2377:
2378: /* get information from fe/efe */
2379: if (node->fe) {
2380: l_ea = udf_rw32(node->fe->l_ea);
2381: eahdr = (struct extattrhdr_desc *) node->fe->data;
2382: } else {
2383: assert(node->efe);
2384: l_ea = udf_rw32(node->efe->l_ea);
2385: eahdr = (struct extattrhdr_desc *) node->efe->data;
2386: }
2387:
2388: /* something recorded here? */
2389: if (l_ea == 0)
2390: return ENOENT;
2391:
2392: /* check extended attribute tag; what to do if it fails? */
2393: error = udf_check_tag(eahdr);
2394: if (error)
2395: return EINVAL;
2396: if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR)
2397: return EINVAL;
2398: error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
2399: if (error)
2400: return EINVAL;
2401:
2402: DPRINTF(EXTATTR, ("Found %d bytes of extended attributes\n", l_ea));
2403:
2404: /* looking for Ecma-167 attributes? */
2405: offset = sizeof(struct extattrhdr_desc);
2406:
1.163 msaitoh 2407: /* looking for either implementation use or application use */
1.45 reinoud 2408: if (sattr == 2048) { /* [4/48.10.8] */
2409: offset = udf_rw32(eahdr->impl_attr_loc);
2410: if (offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2411: return ENOENT;
2412: }
2413: if (sattr == 65536) { /* [4/48.10.9] */
2414: offset = udf_rw32(eahdr->appl_attr_loc);
2415: if (offset == UDF_APPL_ATTR_LOC_NOT_PRESENT)
2416: return ENOENT;
2417: }
2418:
2419: /* paranoia check offset and l_ea */
2420: if (l_ea + offset >= sector_size - sizeof(struct extattr_entry))
2421: return EINVAL;
2422:
2423: DPRINTF(EXTATTR, ("Starting at offset %d\n", offset));
2424:
2425: /* find our extended attribute */
2426: l_ea -= offset;
2427: pos = (uint8_t *) eahdr + offset;
2428:
2429: while (l_ea >= sizeof(struct extattr_entry)) {
2430: DPRINTF(EXTATTR, ("%d extended attr bytes left\n", l_ea));
2431: attrhdr = (struct extattr_entry *) pos;
2432: implext = (struct impl_extattr_entry *) pos;
2433:
2434: /* get complete attribute length and check for roque values */
2435: a_l = udf_rw32(attrhdr->a_l);
2436: DPRINTF(EXTATTR, ("attribute %d:%d, len %d/%d\n",
2437: udf_rw32(attrhdr->type),
2438: attrhdr->subtype, a_l, l_ea));
2439: if ((a_l == 0) || (a_l > l_ea))
2440: return EINVAL;
2441:
2442: if (attrhdr->type != sattr)
2443: goto next_attribute;
2444:
2445: /* we might have found it! */
2446: if (attrhdr->type < 2048) { /* Ecma-167 attribute */
2447: *offsetp = offset;
2448: *lengthp = a_l;
2449: return 0; /* success */
2450: }
2451:
2452: /*
2453: * Implementation use and application use extended attributes
2454: * have a name to identify. They share the same structure only
2455: * UDF implementation use extended attributes have a checksum
2456: * we need to check
2457: */
2458:
2459: DPRINTF(EXTATTR, ("named attribute %s\n", implext->imp_id.id));
2460: if (strcmp(implext->imp_id.id, sattrname) == 0) {
2461: /* we have found our appl/implementation attribute */
2462: *offsetp = offset;
2463: *lengthp = a_l;
2464: return 0; /* success */
2465: }
2466:
2467: next_attribute:
2468: /* next attribute */
2469: pos += a_l;
2470: l_ea -= a_l;
2471: offset += a_l;
2472: }
2473: /* not found */
2474: return ENOENT;
2475: }
2476:
2477:
1.51 reinoud 2478: static void
2479: udf_extattr_insert_internal(struct udf_mount *ump, union dscrptr *dscr,
2480: struct extattr_entry *extattr)
2481: {
2482: struct file_entry *fe;
2483: struct extfile_entry *efe;
2484: struct extattrhdr_desc *extattrhdr;
2485: struct impl_extattr_entry *implext;
2486: uint32_t impl_attr_loc, appl_attr_loc, l_ea, a_l, exthdr_len;
2487: uint32_t *l_eap, l_ad;
2488: uint16_t *spos;
2489: uint8_t *bpos, *data;
2490:
2491: if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
2492: fe = &dscr->fe;
2493: data = fe->data;
2494: l_eap = &fe->l_ea;
2495: l_ad = udf_rw32(fe->l_ad);
2496: } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
2497: efe = &dscr->efe;
2498: data = efe->data;
2499: l_eap = &efe->l_ea;
2500: l_ad = udf_rw32(efe->l_ad);
2501: } else {
2502: panic("Bad tag passed to udf_extattr_insert_internal");
2503: }
2504:
2505: /* can't append already written to file descriptors yet */
2506: assert(l_ad == 0);
1.124 christos 2507: __USE(l_ad);
1.51 reinoud 2508:
2509: /* should have a header! */
2510: extattrhdr = (struct extattrhdr_desc *) data;
2511: l_ea = udf_rw32(*l_eap);
2512: if (l_ea == 0) {
2513: /* create empty extended attribute header */
2514: exthdr_len = sizeof(struct extattrhdr_desc);
2515:
2516: udf_inittag(ump, &extattrhdr->tag, TAGID_EXTATTR_HDR,
2517: /* loc */ 0);
2518: extattrhdr->impl_attr_loc = udf_rw32(exthdr_len);
2519: extattrhdr->appl_attr_loc = udf_rw32(exthdr_len);
2520: extattrhdr->tag.desc_crc_len = udf_rw16(8);
2521:
2522: /* record extended attribute header length */
2523: l_ea = exthdr_len;
2524: *l_eap = udf_rw32(l_ea);
2525: }
2526:
2527: /* extract locations */
2528: impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc);
2529: appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc);
2530: if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2531: impl_attr_loc = l_ea;
2532: if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
2533: appl_attr_loc = l_ea;
2534:
2535: /* Ecma 167 EAs */
2536: if (udf_rw32(extattr->type) < 2048) {
2537: assert(impl_attr_loc == l_ea);
2538: assert(appl_attr_loc == l_ea);
2539: }
2540:
2541: /* implementation use extended attributes */
2542: if (udf_rw32(extattr->type) == 2048) {
2543: assert(appl_attr_loc == l_ea);
2544:
2545: /* calculate and write extended attribute header checksum */
2546: implext = (struct impl_extattr_entry *) extattr;
2547: assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */
2548: spos = (uint16_t *) implext->data;
2549: *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext));
2550: }
2551:
2552: /* application use extended attributes */
2553: assert(udf_rw32(extattr->type) != 65536);
2554: assert(appl_attr_loc == l_ea);
2555:
2556: /* append the attribute at the end of the current space */
2557: bpos = data + udf_rw32(*l_eap);
2558: a_l = udf_rw32(extattr->a_l);
2559:
2560: /* update impl. attribute locations */
2561: if (udf_rw32(extattr->type) < 2048) {
2562: impl_attr_loc = l_ea + a_l;
2563: appl_attr_loc = l_ea + a_l;
2564: }
2565: if (udf_rw32(extattr->type) == 2048) {
2566: appl_attr_loc = l_ea + a_l;
2567: }
2568:
2569: /* copy and advance */
2570: memcpy(bpos, extattr, a_l);
2571: l_ea += a_l;
2572: *l_eap = udf_rw32(l_ea);
2573:
2574: /* do the `dance` again backwards */
2575: if (udf_rw16(ump->logical_vol->tag.descriptor_ver) != 2) {
2576: if (impl_attr_loc == l_ea)
2577: impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT;
2578: if (appl_attr_loc == l_ea)
2579: appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT;
2580: }
2581:
2582: /* store offsets */
2583: extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc);
2584: extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc);
2585: }
2586:
1.45 reinoud 2587:
2588: /* --------------------------------------------------------------------- */
2589:
1.152 skrll 2590: static int
1.45 reinoud 2591: udf_update_lvid_from_vat_extattr(struct udf_node *vat_node)
2592: {
2593: struct udf_mount *ump;
2594: struct udf_logvol_info *lvinfo;
2595: struct impl_extattr_entry *implext;
2596: struct vatlvext_extattr_entry lvext;
2597: const char *extstr = "*UDF VAT LVExtension";
2598: uint64_t vat_uniqueid;
2599: uint32_t offset, a_l;
2600: uint8_t *ea_start, *lvextpos;
2601: int error;
2602:
2603: /* get mountpoint and lvinfo */
2604: ump = vat_node->ump;
2605: lvinfo = ump->logvol_info;
2606:
2607: /* get information from fe/efe */
2608: if (vat_node->fe) {
2609: vat_uniqueid = udf_rw64(vat_node->fe->unique_id);
2610: ea_start = vat_node->fe->data;
2611: } else {
2612: vat_uniqueid = udf_rw64(vat_node->efe->unique_id);
2613: ea_start = vat_node->efe->data;
2614: }
2615:
2616: error = udf_extattr_search_intern(vat_node, 2048, extstr, &offset, &a_l);
2617: if (error)
2618: return error;
2619:
2620: implext = (struct impl_extattr_entry *) (ea_start + offset);
2621: error = udf_impl_extattr_check(implext);
2622: if (error)
2623: return error;
2624:
2625: /* paranoia */
1.143 reinoud 2626: if (a_l != sizeof(*implext) -2 + udf_rw32(implext->iu_l) + sizeof(lvext)) {
1.45 reinoud 2627: DPRINTF(VOLUMES, ("VAT LVExtension size doesn't compute\n"));
2628: return EINVAL;
2629: }
2630:
2631: /*
2632: * we have found our "VAT LVExtension attribute. BUT due to a
2633: * bug in the specification it might not be word aligned so
2634: * copy first to avoid panics on some machines (!!)
2635: */
2636: DPRINTF(VOLUMES, ("Found VAT LVExtension attr\n"));
2637: lvextpos = implext->data + udf_rw32(implext->iu_l);
2638: memcpy(&lvext, lvextpos, sizeof(lvext));
2639:
2640: /* check if it was updated the last time */
2641: if (udf_rw64(lvext.unique_id_chk) == vat_uniqueid) {
2642: lvinfo->num_files = lvext.num_files;
2643: lvinfo->num_directories = lvext.num_directories;
2644: udf_update_logvolname(ump, lvext.logvol_id);
2645: } else {
2646: DPRINTF(VOLUMES, ("VAT LVExtension out of date\n"));
2647: /* replace VAT LVExt by free space EA */
2648: memset(implext->imp_id.id, 0, UDF_REGID_ID_SIZE);
2649: strcpy(implext->imp_id.id, "*UDF FreeEASpace");
2650: udf_calc_impl_extattr_checksum(implext);
2651: }
2652:
2653: return 0;
2654: }
2655:
2656:
1.152 skrll 2657: static int
1.45 reinoud 2658: udf_update_vat_extattr_from_lvid(struct udf_node *vat_node)
2659: {
2660: struct udf_mount *ump;
2661: struct udf_logvol_info *lvinfo;
2662: struct impl_extattr_entry *implext;
2663: struct vatlvext_extattr_entry lvext;
2664: const char *extstr = "*UDF VAT LVExtension";
2665: uint64_t vat_uniqueid;
2666: uint32_t offset, a_l;
1.153 mrg 2667: uint8_t *ea_start;
2668: uintptr_t lvextpos;
1.45 reinoud 2669: int error;
2670:
2671: /* get mountpoint and lvinfo */
2672: ump = vat_node->ump;
2673: lvinfo = ump->logvol_info;
2674:
2675: /* get information from fe/efe */
2676: if (vat_node->fe) {
2677: vat_uniqueid = udf_rw64(vat_node->fe->unique_id);
2678: ea_start = vat_node->fe->data;
2679: } else {
2680: vat_uniqueid = udf_rw64(vat_node->efe->unique_id);
2681: ea_start = vat_node->efe->data;
2682: }
2683:
2684: error = udf_extattr_search_intern(vat_node, 2048, extstr, &offset, &a_l);
2685: if (error)
2686: return error;
2687: /* found, it existed */
2688:
2689: /* paranoia */
2690: implext = (struct impl_extattr_entry *) (ea_start + offset);
2691: error = udf_impl_extattr_check(implext);
2692: if (error) {
2693: DPRINTF(VOLUMES, ("VAT LVExtension bad on update\n"));
2694: return error;
2695: }
2696: /* it is correct */
2697:
2698: /*
2699: * we have found our "VAT LVExtension attribute. BUT due to a
2700: * bug in the specification it might not be word aligned so
2701: * copy first to avoid panics on some machines (!!)
2702: */
2703: DPRINTF(VOLUMES, ("Updating VAT LVExtension attr\n"));
1.153 mrg 2704: lvextpos = (uintptr_t)implext->data + udf_rw32(implext->iu_l);
1.45 reinoud 2705:
2706: lvext.unique_id_chk = vat_uniqueid;
2707: lvext.num_files = lvinfo->num_files;
2708: lvext.num_directories = lvinfo->num_directories;
2709: memmove(lvext.logvol_id, ump->logical_vol->logvol_id, 128);
2710:
1.153 mrg 2711: memcpy((void *)lvextpos, &lvext, sizeof(lvext));
1.45 reinoud 2712:
2713: return 0;
2714: }
2715:
2716: /* --------------------------------------------------------------------- */
2717:
2718: int
2719: udf_vat_read(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset)
2720: {
2721: struct udf_mount *ump = vat_node->ump;
2722:
2723: if (offset + size > ump->vat_offset + ump->vat_entries * 4)
2724: return EINVAL;
2725:
2726: memcpy(blob, ump->vat_table + offset, size);
2727: return 0;
2728: }
2729:
2730: int
2731: udf_vat_write(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset)
2732: {
2733: struct udf_mount *ump = vat_node->ump;
2734: uint32_t offset_high;
2735: uint8_t *new_vat_table;
2736:
2737: /* extent VAT allocation if needed */
2738: offset_high = offset + size;
2739: if (offset_high >= ump->vat_table_alloc_len) {
2740: /* realloc */
2741: new_vat_table = realloc(ump->vat_table,
2742: ump->vat_table_alloc_len + UDF_VAT_CHUNKSIZE,
1.144 jdolecek 2743: M_UDFVOLD, M_WAITOK);
1.45 reinoud 2744: if (!new_vat_table) {
2745: printf("udf_vat_write: can't extent VAT, out of mem\n");
2746: return ENOMEM;
2747: }
2748: ump->vat_table = new_vat_table;
2749: ump->vat_table_alloc_len += UDF_VAT_CHUNKSIZE;
2750: }
2751: ump->vat_table_len = MAX(ump->vat_table_len, offset_high);
2752:
2753: memcpy(ump->vat_table + offset, blob, size);
2754: return 0;
2755: }
2756:
2757: /* --------------------------------------------------------------------- */
2758:
2759: /* TODO support previous VAT location writeout */
2760: static int
2761: udf_update_vat_descriptor(struct udf_mount *ump)
2762: {
2763: struct udf_node *vat_node = ump->vat_node;
2764: struct udf_logvol_info *lvinfo = ump->logvol_info;
2765: struct icb_tag *icbtag;
2766: struct udf_oldvat_tail *oldvat_tl;
2767: struct udf_vat *vat;
1.161 reinoud 2768: struct regid *regid;
1.45 reinoud 2769: uint64_t unique_id;
2770: uint32_t lb_size;
2771: uint8_t *raw_vat;
1.161 reinoud 2772: int vat_length, impl_use_len, filetype, error;
1.45 reinoud 2773:
2774: KASSERT(vat_node);
2775: KASSERT(lvinfo);
2776: lb_size = udf_rw32(ump->logical_vol->lb_size);
2777:
2778: /* get our new unique_id */
2779: unique_id = udf_advance_uniqueid(ump);
2780:
2781: /* get information from fe/efe */
2782: if (vat_node->fe) {
2783: icbtag = &vat_node->fe->icbtag;
2784: vat_node->fe->unique_id = udf_rw64(unique_id);
2785: } else {
2786: icbtag = &vat_node->efe->icbtag;
2787: vat_node->efe->unique_id = udf_rw64(unique_id);
2788: }
2789:
2790: /* Check icb filetype! it has to be 0 or UDF_ICB_FILETYPE_VAT */
2791: filetype = icbtag->file_type;
2792: KASSERT((filetype == 0) || (filetype == UDF_ICB_FILETYPE_VAT));
2793:
2794: /* allocate piece to process head or tail of VAT file */
2795: raw_vat = malloc(lb_size, M_TEMP, M_WAITOK);
2796:
2797: if (filetype == 0) {
2798: /*
2799: * Update "*UDF VAT LVExtension" extended attribute from the
2800: * lvint if present.
2801: */
2802: udf_update_vat_extattr_from_lvid(vat_node);
2803:
2804: /* setup identifying regid */
2805: oldvat_tl = (struct udf_oldvat_tail *) raw_vat;
2806: memset(oldvat_tl, 0, sizeof(struct udf_oldvat_tail));
2807:
2808: udf_set_regid(&oldvat_tl->id, "*UDF Virtual Alloc Tbl");
2809: udf_add_udf_regid(ump, &oldvat_tl->id);
2810: oldvat_tl->prev_vat = udf_rw32(0xffffffff);
2811:
2812: /* write out new tail of virtual allocation table file */
2813: error = udf_vat_write(vat_node, raw_vat,
2814: sizeof(struct udf_oldvat_tail), ump->vat_entries * 4);
2815: } else {
2816: /* compose the VAT2 header */
1.161 reinoud 2817: vat_length = sizeof(struct udf_vat);
1.45 reinoud 2818: vat = (struct udf_vat *) raw_vat;
2819:
1.161 reinoud 2820: error = udf_vat_read(vat_node, raw_vat, vat_length, 0);
2821: if (error)
2822: goto errout;
2823:
2824: impl_use_len = udf_rw16(vat->impl_use_len);
2825: vat_length += impl_use_len;
2826:
2827: error = udf_vat_read(vat_node, raw_vat, vat_length, 0);
2828: if (error)
2829: goto errout;
2830:
1.45 reinoud 2831: memmove(vat->logvol_id, ump->logical_vol->logvol_id, 128);
2832: vat->prev_vat = udf_rw32(0xffffffff);
2833: vat->num_files = lvinfo->num_files;
2834: vat->num_directories = lvinfo->num_directories;
2835: vat->min_udf_readver = lvinfo->min_udf_readver;
2836: vat->min_udf_writever = lvinfo->min_udf_writever;
2837: vat->max_udf_writever = lvinfo->max_udf_writever;
2838:
1.161 reinoud 2839: if (impl_use_len >= sizeof(struct regid)) {
2840: /* insert our implementation identification */
2841: memset(vat->data, 0, impl_use_len);
2842: regid = (struct regid *) vat->data;
2843: udf_set_regid(regid, IMPL_NAME);
2844: udf_add_app_regid(ump, regid);
2845: } else {
2846: if (impl_use_len)
2847: memset(vat->data, 0, impl_use_len);
2848: vat->impl_use_len = 0;
2849: }
2850: error = udf_vat_write(vat_node, raw_vat, vat_length, 0);
1.45 reinoud 2851: }
1.161 reinoud 2852: errout:
1.45 reinoud 2853: free(raw_vat, M_TEMP);
2854:
2855: return error; /* success! */
2856: }
2857:
2858:
2859: int
2860: udf_writeout_vat(struct udf_mount *ump)
2861: {
2862: struct udf_node *vat_node = ump->vat_node;
2863: int error;
2864:
2865: KASSERT(vat_node);
2866:
2867: DPRINTF(CALL, ("udf_writeout_vat\n"));
2868:
1.95 reinoud 2869: // mutex_enter(&ump->allocate_mutex);
1.45 reinoud 2870: udf_update_vat_descriptor(ump);
2871:
2872: /* write out the VAT contents ; TODO intelligent writing */
2873: error = vn_rdwr(UIO_WRITE, vat_node->vnode,
2874: ump->vat_table, ump->vat_table_len, 0,
1.109 reinoud 2875: UIO_SYSSPACE, 0, FSCRED, NULL, NULL);
1.45 reinoud 2876: if (error) {
2877: printf("udf_writeout_vat: failed to write out VAT contents\n");
2878: goto out;
2879: }
2880:
1.95 reinoud 2881: // mutex_exit(&ump->allocate_mutex);
1.45 reinoud 2882:
1.119 chs 2883: error = vflushbuf(ump->vat_node->vnode, FSYNC_WAIT);
1.114 hannken 2884: if (error)
2885: goto out;
1.45 reinoud 2886: error = VOP_FSYNC(ump->vat_node->vnode,
2887: FSCRED, FSYNC_WAIT, 0, 0);
2888: if (error)
2889: printf("udf_writeout_vat: error writing VAT node!\n");
2890: out:
2891: return error;
2892: }
2893:
2894: /* --------------------------------------------------------------------- */
2895:
2896: /*
2897: * Read in relevant pieces of VAT file and check if its indeed a VAT file
2898: * descriptor. If OK, read in complete VAT file.
2899: */
2900:
2901: static int
2902: udf_check_for_vat(struct udf_node *vat_node)
2903: {
2904: struct udf_mount *ump;
2905: struct icb_tag *icbtag;
2906: struct timestamp *mtime;
2907: struct udf_vat *vat;
2908: struct udf_oldvat_tail *oldvat_tl;
2909: struct udf_logvol_info *lvinfo;
2910: uint64_t unique_id;
2911: uint32_t vat_length;
2912: uint32_t vat_offset, vat_entries, vat_table_alloc_len;
2913: uint32_t sector_size;
2914: uint32_t *raw_vat;
2915: uint8_t *vat_table;
2916: char *regid_name;
2917: int filetype;
2918: int error;
2919:
2920: /* vat_length is really 64 bits though impossible */
2921:
2922: DPRINTF(VOLUMES, ("Checking for VAT\n"));
2923: if (!vat_node)
2924: return ENOENT;
2925:
2926: /* get mount info */
2927: ump = vat_node->ump;
2928: sector_size = udf_rw32(ump->logical_vol->lb_size);
2929:
2930: /* check assertions */
2931: assert(vat_node->fe || vat_node->efe);
2932: assert(ump->logvol_integrity);
2933:
2934: /* set vnode type to regular file or we can't read from it! */
2935: vat_node->vnode->v_type = VREG;
2936:
2937: /* get information from fe/efe */
2938: if (vat_node->fe) {
2939: vat_length = udf_rw64(vat_node->fe->inf_len);
2940: icbtag = &vat_node->fe->icbtag;
2941: mtime = &vat_node->fe->mtime;
2942: unique_id = udf_rw64(vat_node->fe->unique_id);
2943: } else {
2944: vat_length = udf_rw64(vat_node->efe->inf_len);
2945: icbtag = &vat_node->efe->icbtag;
2946: mtime = &vat_node->efe->mtime;
2947: unique_id = udf_rw64(vat_node->efe->unique_id);
2948: }
2949:
2950: /* Check icb filetype! it has to be 0 or UDF_ICB_FILETYPE_VAT */
2951: filetype = icbtag->file_type;
2952: if ((filetype != 0) && (filetype != UDF_ICB_FILETYPE_VAT))
2953: return ENOENT;
2954:
2955: DPRINTF(VOLUMES, ("\tPossible VAT length %d\n", vat_length));
2956:
2957: vat_table_alloc_len =
2958: ((vat_length + UDF_VAT_CHUNKSIZE-1) / UDF_VAT_CHUNKSIZE)
2959: * UDF_VAT_CHUNKSIZE;
2960:
1.144 jdolecek 2961: vat_table = malloc(vat_table_alloc_len, M_UDFVOLD, M_WAITOK);
1.45 reinoud 2962: if (vat_table == NULL) {
2963: printf("allocation of %d bytes failed for VAT\n",
2964: vat_table_alloc_len);
2965: return ENOMEM;
2966: }
2967:
2968: /* allocate piece to read in head or tail of VAT file */
2969: raw_vat = malloc(sector_size, M_TEMP, M_WAITOK);
2970:
2971: /*
2972: * check contents of the file if its the old 1.50 VAT table format.
2973: * Its notoriously broken and allthough some implementations support an
1.157 andvar 2974: * extension as defined in the UDF 1.50 errata document, its doubtful
1.45 reinoud 2975: * to be useable since a lot of implementations don't maintain it.
2976: */
2977: lvinfo = ump->logvol_info;
2978:
2979: if (filetype == 0) {
2980: /* definition */
2981: vat_offset = 0;
2982: vat_entries = (vat_length-36)/4;
2983:
2984: /* read in tail of virtual allocation table file */
2985: error = vn_rdwr(UIO_READ, vat_node->vnode,
2986: (uint8_t *) raw_vat,
2987: sizeof(struct udf_oldvat_tail),
2988: vat_entries * 4,
2989: UIO_SYSSPACE, IO_SYNC | IO_NODELOCKED, FSCRED,
2990: NULL, NULL);
2991: if (error)
2992: goto out;
2993:
2994: /* check 1.50 VAT */
2995: oldvat_tl = (struct udf_oldvat_tail *) raw_vat;
2996: regid_name = (char *) oldvat_tl->id.id;
2997: error = strncmp(regid_name, "*UDF Virtual Alloc Tbl", 22);
2998: if (error) {
2999: DPRINTF(VOLUMES, ("VAT format 1.50 rejected\n"));
3000: error = ENOENT;
3001: goto out;
3002: }
3003:
3004: /*
3005: * update LVID from "*UDF VAT LVExtension" extended attribute
3006: * if present.
3007: */
3008: udf_update_lvid_from_vat_extattr(vat_node);
3009: } else {
3010: /* read in head of virtual allocation table file */
3011: error = vn_rdwr(UIO_READ, vat_node->vnode,
3012: (uint8_t *) raw_vat,
3013: sizeof(struct udf_vat), 0,
3014: UIO_SYSSPACE, IO_SYNC | IO_NODELOCKED, FSCRED,
3015: NULL, NULL);
3016: if (error)
3017: goto out;
3018:
3019: /* definition */
3020: vat = (struct udf_vat *) raw_vat;
1.161 reinoud 3021: vat_offset = udf_rw16(vat->header_len);
1.45 reinoud 3022: vat_entries = (vat_length - vat_offset)/4;
3023:
3024: assert(lvinfo);
3025: lvinfo->num_files = vat->num_files;
3026: lvinfo->num_directories = vat->num_directories;
3027: lvinfo->min_udf_readver = vat->min_udf_readver;
3028: lvinfo->min_udf_writever = vat->min_udf_writever;
3029: lvinfo->max_udf_writever = vat->max_udf_writever;
1.152 skrll 3030:
1.45 reinoud 3031: udf_update_logvolname(ump, vat->logvol_id);
3032: }
3033:
3034: /* read in complete VAT file */
3035: error = vn_rdwr(UIO_READ, vat_node->vnode,
3036: vat_table,
3037: vat_length, 0,
3038: UIO_SYSSPACE, IO_SYNC | IO_NODELOCKED, FSCRED,
3039: NULL, NULL);
3040: if (error)
3041: printf("read in of complete VAT file failed (error %d)\n",
3042: error);
3043: if (error)
3044: goto out;
3045:
3046: DPRINTF(VOLUMES, ("VAT format accepted, marking it closed\n"));
1.90 reinoud 3047: ump->logvol_integrity->lvint_next_unique_id = udf_rw64(unique_id);
1.45 reinoud 3048: ump->logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
3049: ump->logvol_integrity->time = *mtime;
3050:
1.137 reinoud 3051: /* if we're updating, free old allocated space */
3052: if (ump->vat_table)
3053: free(ump->vat_table, M_UDFVOLD);
3054:
1.45 reinoud 3055: ump->vat_table_len = vat_length;
3056: ump->vat_table_alloc_len = vat_table_alloc_len;
3057: ump->vat_table = vat_table;
3058: ump->vat_offset = vat_offset;
3059: ump->vat_entries = vat_entries;
3060: ump->vat_last_free_lb = 0; /* start at beginning */
3061:
3062: out:
3063: if (error) {
3064: if (vat_table)
3065: free(vat_table, M_UDFVOLD);
3066: }
3067: free(raw_vat, M_TEMP);
3068:
3069: return error;
3070: }
3071:
3072: /* --------------------------------------------------------------------- */
3073:
3074: static int
3075: udf_search_vat(struct udf_mount *ump, union udf_pmap *mapping)
3076: {
1.137 reinoud 3077: struct udf_node *vat_node, *accepted_vat_node;
1.45 reinoud 3078: struct long_ad icb_loc;
1.137 reinoud 3079: uint32_t early_vat_loc, late_vat_loc, vat_loc;
1.45 reinoud 3080: int error;
3081:
3082: /* mapping info not needed */
3083: mapping = mapping;
3084:
1.137 reinoud 3085: DPRINTF(VOLUMES, ("Searching VAT\n"));
1.152 skrll 3086:
1.137 reinoud 3087: /*
3088: * Start reading forward in blocks from the first possible vat
3089: * location. If not found in this block, start again a bit before
3090: * until we get a hit.
3091: */
3092: late_vat_loc = ump->last_possible_vat_location;
3093: early_vat_loc = MAX(late_vat_loc - 64, ump->first_possible_vat_location);
1.152 skrll 3094:
1.137 reinoud 3095: DPRINTF(VOLUMES, ("\tfull range %d to %d\n", early_vat_loc, late_vat_loc));
3096: accepted_vat_node = NULL;
3097: do {
3098: vat_loc = early_vat_loc;
3099: DPRINTF(VOLUMES, ("\tchecking range %d to %d\n",
3100: early_vat_loc, late_vat_loc));
3101: do {
3102: DPRINTF(VOLUMES, ("\t\tChecking for VAT at sector %d\n",
3103: vat_loc));
3104: icb_loc.loc.part_num = udf_rw16(UDF_VTOP_RAWPART);
3105: icb_loc.loc.lb_num = udf_rw32(vat_loc);
1.45 reinoud 3106:
1.148 ad 3107: error = udf_get_node(ump, &icb_loc, &vat_node,
3108: LK_EXCLUSIVE);
1.137 reinoud 3109: if (!error) {
3110: error = udf_check_for_vat(vat_node);
3111: vat_node->i_flags = 0; /* reset access */
3112: }
3113: if (!error) {
3114: DPRINTFIF(VOLUMES, !error,
3115: ("VAT candidate accepted at %d\n",
3116: vat_loc));
3117: if (accepted_vat_node)
3118: vput(accepted_vat_node->vnode);
3119: accepted_vat_node = vat_node;
3120: accepted_vat_node->i_flags |= IN_NO_DELETE;
3121: vat_node = NULL;
3122: }
3123: if (vat_node)
3124: vput(vat_node->vnode);
3125: vat_loc++; /* walk forward */
1.160 reinoud 3126: } while (vat_loc <= late_vat_loc);
1.137 reinoud 3127: if (accepted_vat_node)
3128: break;
3129:
3130: early_vat_loc = MAX(early_vat_loc - 64, ump->first_possible_vat_location);
3131: late_vat_loc = MIN(early_vat_loc + 64, ump->last_possible_vat_location);
3132: } while (late_vat_loc > ump->first_possible_vat_location);
3133:
3134: /* keep our last accepted VAT node around */
3135: if (accepted_vat_node) {
3136: /* revert no delete flag again to avoid potential side effects */
3137: accepted_vat_node->i_flags &= ~IN_NO_DELETE;
1.45 reinoud 3138:
1.137 reinoud 3139: UDF_SET_SYSTEMFILE(accepted_vat_node->vnode);
3140: ump->vat_node = accepted_vat_node;
3141: return 0;
1.45 reinoud 3142: }
3143:
3144: return error;
3145: }
3146:
3147: /* --------------------------------------------------------------------- */
3148:
3149: static int
3150: udf_read_sparables(struct udf_mount *ump, union udf_pmap *mapping)
3151: {
3152: union dscrptr *dscr;
3153: struct part_map_spare *pms = &mapping->pms;
3154: uint32_t lb_num;
3155: int spar, error;
3156:
3157: /*
3158: * The partition mapping passed on to us specifies the information we
3159: * need to locate and initialise the sparable partition mapping
3160: * information we need.
3161: */
3162:
3163: DPRINTF(VOLUMES, ("Read sparable table\n"));
3164: ump->sparable_packet_size = udf_rw16(pms->packet_len);
3165: KASSERT(ump->sparable_packet_size >= ump->packet_size); /* XXX */
3166:
3167: for (spar = 0; spar < pms->n_st; spar++) {
3168: lb_num = pms->st_loc[spar];
3169: DPRINTF(VOLUMES, ("Checking for sparing table %d\n", lb_num));
3170: error = udf_read_phys_dscr(ump, lb_num, M_UDFVOLD, &dscr);
3171: if (!error && dscr) {
3172: if (udf_rw16(dscr->tag.id) == TAGID_SPARING_TABLE) {
3173: if (ump->sparing_table)
3174: free(ump->sparing_table, M_UDFVOLD);
3175: ump->sparing_table = &dscr->spt;
3176: dscr = NULL;
3177: DPRINTF(VOLUMES,
3178: ("Sparing table accepted (%d entries)\n",
3179: udf_rw16(ump->sparing_table->rt_l)));
3180: break; /* we're done */
3181: }
3182: }
3183: if (dscr)
3184: free(dscr, M_UDFVOLD);
3185: }
3186:
3187: if (ump->sparing_table)
3188: return 0;
3189:
3190: return ENOENT;
3191: }
3192:
3193: /* --------------------------------------------------------------------- */
3194:
3195: static int
3196: udf_read_metadata_nodes(struct udf_mount *ump, union udf_pmap *mapping)
3197: {
3198: struct part_map_meta *pmm = &mapping->pmm;
3199: struct long_ad icb_loc;
3200: struct vnode *vp;
1.111 reinoud 3201: uint16_t raw_phys_part, phys_part;
1.45 reinoud 3202: int error;
3203:
1.111 reinoud 3204: /*
3205: * BUGALERT: some rogue implementations use random physical
3206: * partition numbers to break other implementations so lookup
3207: * the number.
3208: */
3209:
1.102 reinoud 3210: /* extract our allocation parameters set up on format */
1.103 reinoud 3211: ump->metadata_alloc_unit_size = udf_rw32(mapping->pmm.alloc_unit_size);
3212: ump->metadata_alignment_unit_size = udf_rw16(mapping->pmm.alignment_unit_size);
3213: ump->metadata_flags = mapping->pmm.flags;
1.102 reinoud 3214:
1.45 reinoud 3215: DPRINTF(VOLUMES, ("Reading in Metadata files\n"));
1.111 reinoud 3216: raw_phys_part = udf_rw16(pmm->part_num);
3217: phys_part = udf_find_raw_phys(ump, raw_phys_part);
3218:
3219: icb_loc.loc.part_num = udf_rw16(phys_part);
3220:
3221: DPRINTF(VOLUMES, ("Metadata file\n"));
1.45 reinoud 3222: icb_loc.loc.lb_num = pmm->meta_file_lbn;
1.148 ad 3223: error = udf_get_node(ump, &icb_loc, &ump->metadata_node,
3224: LK_EXCLUSIVE);
1.45 reinoud 3225: if (ump->metadata_node) {
3226: vp = ump->metadata_node->vnode;
3227: UDF_SET_SYSTEMFILE(vp);
3228: }
3229:
3230: icb_loc.loc.lb_num = pmm->meta_mirror_file_lbn;
3231: if (icb_loc.loc.lb_num != -1) {
3232: DPRINTF(VOLUMES, ("Metadata copy file\n"));
1.148 ad 3233: error = udf_get_node(ump, &icb_loc, &ump->metadatamirror_node,
3234: LK_EXCLUSIVE);
1.45 reinoud 3235: if (ump->metadatamirror_node) {
3236: vp = ump->metadatamirror_node->vnode;
3237: UDF_SET_SYSTEMFILE(vp);
3238: }
3239: }
3240:
3241: icb_loc.loc.lb_num = pmm->meta_bitmap_file_lbn;
3242: if (icb_loc.loc.lb_num != -1) {
3243: DPRINTF(VOLUMES, ("Metadata bitmap file\n"));
1.148 ad 3244: error = udf_get_node(ump, &icb_loc, &ump->metadatabitmap_node,
3245: LK_EXCLUSIVE);
1.45 reinoud 3246: if (ump->metadatabitmap_node) {
3247: vp = ump->metadatabitmap_node->vnode;
3248: UDF_SET_SYSTEMFILE(vp);
3249: }
3250: }
3251:
3252: /* if we're mounting read-only we relax the requirements */
3253: if (ump->vfs_mountp->mnt_flag & MNT_RDONLY) {
3254: error = EFAULT;
3255: if (ump->metadata_node)
3256: error = 0;
3257: if ((ump->metadata_node == NULL) && (ump->metadatamirror_node)) {
3258: printf( "udf mount: Metadata file not readable, "
3259: "substituting Metadata copy file\n");
3260: ump->metadata_node = ump->metadatamirror_node;
3261: ump->metadatamirror_node = NULL;
3262: error = 0;
3263: }
3264: } else {
3265: /* mounting read/write */
1.70 reinoud 3266: /* XXX DISABLED! metadata writing is not working yet XXX */
1.71 reinoud 3267: if (error)
1.53 reinoud 3268: error = EROFS;
1.45 reinoud 3269: }
3270: DPRINTFIF(VOLUMES, error, ("udf mount: failed to read "
3271: "metadata files\n"));
3272: return error;
3273: }
3274:
3275: /* --------------------------------------------------------------------- */
3276:
3277: int
3278: udf_read_vds_tables(struct udf_mount *ump)
3279: {
3280: union udf_pmap *mapping;
3281: /* struct udf_args *args = &ump->mount_args; */
1.121 christos 3282: uint32_t n_pm;
1.45 reinoud 3283: uint32_t log_part;
3284: uint8_t *pmap_pos;
3285: int pmap_size;
3286: int error;
3287:
1.69 reinoud 3288: /* Iterate (again) over the part mappings for locations */
1.45 reinoud 3289: n_pm = udf_rw32(ump->logical_vol->n_pm); /* num partmaps */
3290: pmap_pos = ump->logical_vol->maps;
3291:
3292: for (log_part = 0; log_part < n_pm; log_part++) {
3293: mapping = (union udf_pmap *) pmap_pos;
3294: switch (ump->vtop_tp[log_part]) {
3295: case UDF_VTOP_TYPE_PHYS :
3296: /* nothing */
3297: break;
3298: case UDF_VTOP_TYPE_VIRT :
3299: /* search and load VAT */
3300: error = udf_search_vat(ump, mapping);
3301: if (error)
3302: return ENOENT;
3303: break;
3304: case UDF_VTOP_TYPE_SPARABLE :
3305: /* load one of the sparable tables */
3306: error = udf_read_sparables(ump, mapping);
3307: if (error)
3308: return ENOENT;
3309: break;
3310: case UDF_VTOP_TYPE_META :
3311: /* load the associated file descriptors */
3312: error = udf_read_metadata_nodes(ump, mapping);
3313: if (error)
3314: return ENOENT;
3315: break;
3316: default:
3317: break;
3318: }
3319: pmap_size = pmap_pos[1];
3320: pmap_pos += pmap_size;
3321: }
3322:
1.70 reinoud 3323: /* read in and check unallocated and free space info if writing */
3324: if ((ump->vfs_mountp->mnt_flag & MNT_RDONLY) == 0) {
3325: error = udf_read_physical_partition_spacetables(ump);
3326: if (error)
3327: return error;
3328:
1.100 mbalmer 3329: /* also read in metadata partition spacebitmap if defined */
1.70 reinoud 3330: error = udf_read_metadata_partition_spacetable(ump);
3331: return error;
3332: }
3333:
1.45 reinoud 3334: return 0;
3335: }
3336:
3337: /* --------------------------------------------------------------------- */
3338:
3339: int
3340: udf_read_rootdirs(struct udf_mount *ump)
3341: {
3342: union dscrptr *dscr;
3343: /* struct udf_args *args = &ump->mount_args; */
3344: struct udf_node *rootdir_node, *streamdir_node;
3345: struct long_ad fsd_loc, *dir_loc;
3346: uint32_t lb_num, dummy;
3347: uint32_t fsd_len;
3348: int dscr_type;
3349: int error;
3350:
3351: /* TODO implement FSD reading in separate function like integrity? */
3352: /* get fileset descriptor sequence */
3353: fsd_loc = ump->logical_vol->lv_fsd_loc;
3354: fsd_len = udf_rw32(fsd_loc.len);
3355:
3356: dscr = NULL;
3357: error = 0;
3358: while (fsd_len || error) {
3359: DPRINTF(VOLUMES, ("fsd_len = %d\n", fsd_len));
3360: /* translate fsd_loc to lb_num */
3361: error = udf_translate_vtop(ump, &fsd_loc, &lb_num, &dummy);
3362: if (error)
3363: break;
3364: DPRINTF(VOLUMES, ("Reading FSD at lb %d\n", lb_num));
3365: error = udf_read_phys_dscr(ump, lb_num, M_UDFVOLD, &dscr);
3366: /* end markers */
3367: if (error || (dscr == NULL))
3368: break;
3369:
3370: /* analyse */
3371: dscr_type = udf_rw16(dscr->tag.id);
3372: if (dscr_type == TAGID_TERM)
3373: break;
3374: if (dscr_type != TAGID_FSD) {
3375: free(dscr, M_UDFVOLD);
3376: return ENOENT;
3377: }
3378:
3379: /*
3380: * TODO check for multiple fileset descriptors; its only
3381: * picking the last now. Also check for FSD
3382: * correctness/interpretability
3383: */
3384:
3385: /* update */
3386: if (ump->fileset_desc) {
3387: free(ump->fileset_desc, M_UDFVOLD);
3388: }
3389: ump->fileset_desc = &dscr->fsd;
3390: dscr = NULL;
3391:
3392: /* continue to the next fsd */
3393: fsd_len -= ump->discinfo.sector_size;
3394: fsd_loc.loc.lb_num = udf_rw32(udf_rw32(fsd_loc.loc.lb_num)+1);
3395:
3396: /* follow up to fsd->next_ex (long_ad) if its not null */
3397: if (udf_rw32(ump->fileset_desc->next_ex.len)) {
3398: DPRINTF(VOLUMES, ("follow up FSD extent\n"));
3399: fsd_loc = ump->fileset_desc->next_ex;
3400: fsd_len = udf_rw32(ump->fileset_desc->next_ex.len);
3401: }
3402: }
3403: if (dscr)
3404: free(dscr, M_UDFVOLD);
3405:
3406: /* there has to be one */
3407: if (ump->fileset_desc == NULL)
3408: return ENOENT;
3409:
3410: DPRINTF(VOLUMES, ("FSD read in fine\n"));
3411: DPRINTF(VOLUMES, ("Updating fsd logical volume id\n"));
3412: udf_update_logvolname(ump, ump->logical_vol->logvol_id);
3413:
3414: /*
3415: * Now the FSD is known, read in the rootdirectory and if one exists,
3416: * the system stream dir. Some files in the system streamdir are not
3417: * wanted in this implementation since they are not maintained. If
3418: * writing is enabled we'll delete these files if they exist.
3419: */
3420:
3421: rootdir_node = streamdir_node = NULL;
3422: dir_loc = NULL;
3423:
3424: /* try to read in the rootdir */
3425: dir_loc = &ump->fileset_desc->rootdir_icb;
1.148 ad 3426: error = udf_get_node(ump, dir_loc, &rootdir_node, LK_EXCLUSIVE);
1.45 reinoud 3427: if (error)
3428: return ENOENT;
3429:
1.166 ! andvar 3430: /* apparently it reads in fine */
1.45 reinoud 3431:
3432: /*
3433: * Try the system stream directory; not very likely in the ones we
3434: * test, but for completeness.
3435: */
3436: dir_loc = &ump->fileset_desc->streamdir_icb;
3437: if (udf_rw32(dir_loc->len)) {
3438: printf("udf_read_rootdirs: streamdir defined ");
1.148 ad 3439: error = udf_get_node(ump, dir_loc, &streamdir_node,
3440: LK_EXCLUSIVE);
1.45 reinoud 3441: if (error) {
3442: printf("but error in streamdir reading\n");
1.1 reinoud 3443: } else {
1.45 reinoud 3444: printf("but ignored\n");
3445: /*
3446: * TODO process streamdir `baddies' i.e. files we dont
3447: * want if R/W
3448: */
3449: }
3450: }
3451:
3452: DPRINTF(VOLUMES, ("Rootdir(s) read in fine\n"));
3453:
3454: /* release the vnodes again; they'll be auto-recycled later */
3455: if (streamdir_node) {
3456: vput(streamdir_node->vnode);
3457: }
3458: if (rootdir_node) {
3459: vput(rootdir_node->vnode);
3460: }
3461:
3462: return 0;
3463: }
3464:
3465: /* --------------------------------------------------------------------- */
3466:
3467: /* To make absolutely sure we are NOT returning zero, add one :) */
3468:
3469: long
1.98 reinoud 3470: udf_get_node_id(const struct long_ad *icbptr)
1.45 reinoud 3471: {
3472: /* ought to be enough since each mountpoint has its own chain */
3473: return udf_rw32(icbptr->loc.lb_num) + 1;
3474: }
3475:
3476:
1.96 reinoud 3477: int
1.98 reinoud 3478: udf_compare_icb(const struct long_ad *a, const struct long_ad *b)
1.96 reinoud 3479: {
1.98 reinoud 3480: if (udf_rw16(a->loc.part_num) < udf_rw16(b->loc.part_num))
3481: return -1;
3482: if (udf_rw16(a->loc.part_num) > udf_rw16(b->loc.part_num))
3483: return 1;
3484:
3485: if (udf_rw32(a->loc.lb_num) < udf_rw32(b->loc.lb_num))
3486: return -1;
3487: if (udf_rw32(a->loc.lb_num) > udf_rw32(b->loc.lb_num))
3488: return 1;
3489:
3490: return 0;
1.96 reinoud 3491: }
3492:
3493:
1.98 reinoud 3494: static int
1.108 rmind 3495: udf_compare_rbnodes(void *ctx, const void *a, const void *b)
1.45 reinoud 3496: {
1.108 rmind 3497: const struct udf_node *a_node = a;
3498: const struct udf_node *b_node = b;
1.98 reinoud 3499:
3500: return udf_compare_icb(&a_node->loc, &b_node->loc);
3501: }
1.45 reinoud 3502:
3503:
1.98 reinoud 3504: static int
1.108 rmind 3505: udf_compare_rbnode_icb(void *ctx, const void *a, const void *key)
1.98 reinoud 3506: {
1.108 rmind 3507: const struct udf_node *a_node = a;
1.98 reinoud 3508: const struct long_ad * const icb = key;
1.45 reinoud 3509:
1.98 reinoud 3510: return udf_compare_icb(&a_node->loc, icb);
1.45 reinoud 3511: }
3512:
3513:
1.108 rmind 3514: static const rb_tree_ops_t udf_node_rbtree_ops = {
1.98 reinoud 3515: .rbto_compare_nodes = udf_compare_rbnodes,
1.108 rmind 3516: .rbto_compare_key = udf_compare_rbnode_icb,
3517: .rbto_node_offset = offsetof(struct udf_node, rbnode),
3518: .rbto_context = NULL
1.98 reinoud 3519: };
3520:
3521:
3522: void
3523: udf_init_nodes_tree(struct udf_mount *ump)
1.45 reinoud 3524: {
1.108 rmind 3525:
1.98 reinoud 3526: rb_tree_init(&ump->udf_node_tree, &udf_node_rbtree_ops);
3527: }
1.45 reinoud 3528:
3529:
3530: /* --------------------------------------------------------------------- */
3531:
1.85 reinoud 3532: static int
3533: udf_validate_session_start(struct udf_mount *ump)
3534: {
3535: struct mmc_trackinfo trackinfo;
3536: struct vrs_desc *vrs;
3537: uint32_t tracknr, sessionnr, sector, sector_size;
3538: uint32_t iso9660_vrs, write_track_start;
3539: uint8_t *buffer, *blank, *pos;
3540: int blks, max_sectors, vrs_len;
3541: int error;
3542:
3543: /* disc appendable? */
3544: if (ump->discinfo.disc_state == MMC_STATE_FULL)
3545: return EROFS;
3546:
3547: /* already written here? if so, there should be an ISO VDS */
3548: if (ump->discinfo.last_session_state == MMC_STATE_INCOMPLETE)
3549: return 0;
3550:
3551: /*
3552: * Check if the first track of the session is blank and if so, copy or
3553: * create a dummy ISO descriptor so the disc is valid again.
3554: */
3555:
3556: tracknr = ump->discinfo.first_track_last_session;
3557: memset(&trackinfo, 0, sizeof(struct mmc_trackinfo));
3558: trackinfo.tracknr = tracknr;
3559: error = udf_update_trackinfo(ump, &trackinfo);
3560: if (error)
3561: return error;
3562:
3563: udf_dump_trackinfo(&trackinfo);
3564: KASSERT(trackinfo.flags & (MMC_TRACKINFO_BLANK | MMC_TRACKINFO_RESERVED));
3565: KASSERT(trackinfo.sessionnr > 1);
3566:
3567: KASSERT(trackinfo.flags & MMC_TRACKINFO_NWA_VALID);
3568: write_track_start = trackinfo.next_writable;
3569:
3570: /* we have to copy the ISO VRS from a former session */
3571: DPRINTF(VOLUMES, ("validate_session_start: "
3572: "blank or reserved track, copying VRS\n"));
3573:
3574: /* sessionnr should be the session we're mounting */
3575: sessionnr = ump->mount_args.sessionnr;
3576:
3577: /* start at the first track */
3578: tracknr = ump->discinfo.first_track;
3579: while (tracknr <= ump->discinfo.num_tracks) {
3580: trackinfo.tracknr = tracknr;
3581: error = udf_update_trackinfo(ump, &trackinfo);
3582: if (error) {
3583: DPRINTF(VOLUMES, ("failed to get trackinfo; aborting\n"));
3584: return error;
3585: }
3586: if (trackinfo.sessionnr == sessionnr)
3587: break;
3588: tracknr++;
3589: }
3590: if (trackinfo.sessionnr != sessionnr) {
3591: DPRINTF(VOLUMES, ("failed to get trackinfo; aborting\n"));
3592: return ENOENT;
3593: }
3594:
3595: DPRINTF(VOLUMES, ("found possible former ISO VRS at\n"));
3596: udf_dump_trackinfo(&trackinfo);
3597:
3598: /*
3599: * location of iso9660 vrs is defined as first sector AFTER 32kb,
3600: * minimum ISO `sector size' 2048
3601: */
3602: sector_size = ump->discinfo.sector_size;
3603: iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
3604: + trackinfo.track_start;
3605:
3606: buffer = malloc(UDF_ISO_VRS_SIZE, M_TEMP, M_WAITOK);
3607: max_sectors = UDF_ISO_VRS_SIZE / sector_size;
3608: blks = MAX(1, 2048 / sector_size);
3609:
3610: error = 0;
3611: for (sector = 0; sector < max_sectors; sector += blks) {
3612: pos = buffer + sector * sector_size;
3613: error = udf_read_phys_sectors(ump, UDF_C_DSCR, pos,
3614: iso9660_vrs + sector, blks);
3615: if (error)
3616: break;
3617: /* check this ISO descriptor */
3618: vrs = (struct vrs_desc *) pos;
3619: DPRINTF(VOLUMES, ("got VRS id `%4s`\n", vrs->identifier));
3620: if (strncmp(vrs->identifier, VRS_CD001, 5) == 0)
3621: continue;
3622: if (strncmp(vrs->identifier, VRS_CDW02, 5) == 0)
3623: continue;
3624: if (strncmp(vrs->identifier, VRS_BEA01, 5) == 0)
3625: continue;
3626: if (strncmp(vrs->identifier, VRS_NSR02, 5) == 0)
3627: continue;
3628: if (strncmp(vrs->identifier, VRS_NSR03, 5) == 0)
3629: continue;
3630: if (strncmp(vrs->identifier, VRS_TEA01, 5) == 0)
3631: break;
3632: /* now what? for now, end of sequence */
3633: break;
3634: }
3635: vrs_len = sector + blks;
3636: if (error) {
3637: DPRINTF(VOLUMES, ("error reading old ISO VRS\n"));
3638: DPRINTF(VOLUMES, ("creating minimal ISO VRS\n"));
3639:
3640: memset(buffer, 0, UDF_ISO_VRS_SIZE);
3641:
3642: vrs = (struct vrs_desc *) (buffer);
3643: vrs->struct_type = 0;
3644: vrs->version = 1;
3645: memcpy(vrs->identifier,VRS_BEA01, 5);
3646:
3647: vrs = (struct vrs_desc *) (buffer + 2048);
3648: vrs->struct_type = 0;
3649: vrs->version = 1;
1.90 reinoud 3650: if (udf_rw16(ump->logical_vol->tag.descriptor_ver) == 2) {
1.85 reinoud 3651: memcpy(vrs->identifier,VRS_NSR02, 5);
3652: } else {
3653: memcpy(vrs->identifier,VRS_NSR03, 5);
3654: }
3655:
3656: vrs = (struct vrs_desc *) (buffer + 4096);
3657: vrs->struct_type = 0;
3658: vrs->version = 1;
3659: memcpy(vrs->identifier, VRS_TEA01, 5);
3660:
3661: vrs_len = 3*blks;
3662: }
3663:
3664: DPRINTF(VOLUMES, ("Got VRS of %d sectors long\n", vrs_len));
3665:
3666: /*
3667: * location of iso9660 vrs is defined as first sector AFTER 32kb,
3668: * minimum ISO `sector size' 2048
3669: */
3670: sector_size = ump->discinfo.sector_size;
3671: iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
3672: + write_track_start;
3673:
3674: /* write out 32 kb */
3675: blank = malloc(sector_size, M_TEMP, M_WAITOK);
3676: memset(blank, 0, sector_size);
3677: error = 0;
3678: for (sector = write_track_start; sector < iso9660_vrs; sector ++) {
3679: error = udf_write_phys_sectors(ump, UDF_C_ABSOLUTE,
3680: blank, sector, 1);
3681: if (error)
3682: break;
3683: }
3684: if (!error) {
3685: /* write out our ISO VRS */
3686: KASSERT(sector == iso9660_vrs);
3687: error = udf_write_phys_sectors(ump, UDF_C_ABSOLUTE, buffer,
3688: sector, vrs_len);
3689: sector += vrs_len;
3690: }
3691: if (!error) {
3692: /* fill upto the first anchor at S+256 */
3693: for (; sector < write_track_start+256; sector++) {
3694: error = udf_write_phys_sectors(ump, UDF_C_ABSOLUTE,
3695: blank, sector, 1);
3696: if (error)
3697: break;
3698: }
3699: }
3700: if (!error) {
3701: /* write out anchor; write at ABSOLUTE place! */
3702: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_ABSOLUTE,
3703: (union dscrptr *) ump->anchors[0], sector, sector);
3704: if (error)
3705: printf("writeout of anchor failed!\n");
3706: }
3707:
3708: free(blank, M_TEMP);
3709: free(buffer, M_TEMP);
3710:
3711: if (error)
3712: printf("udf_open_session: error writing iso vrs! : "
3713: "leaving disc in compromised state!\n");
3714:
3715: /* synchronise device caches */
3716: (void) udf_synchronise_caches(ump);
3717:
3718: return error;
3719: }
3720:
3721:
1.45 reinoud 3722: int
3723: udf_open_logvol(struct udf_mount *ump)
3724: {
3725: int logvol_integrity;
3726: int error;
3727:
3728: /* already/still open? */
3729: logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
3730: if (logvol_integrity == UDF_INTEGRITY_OPEN)
3731: return 0;
3732:
3733: /* can we open it ? */
3734: if (ump->vfs_mountp->mnt_flag & MNT_RDONLY)
3735: return EROFS;
3736:
3737: /* setup write parameters */
3738: DPRINTF(VOLUMES, ("Setting up write parameters\n"));
3739: if ((error = udf_setup_writeparams(ump)) != 0)
3740: return error;
3741:
3742: /* determine data and metadata tracks (most likely same) */
3743: error = udf_search_writing_tracks(ump);
3744: if (error) {
3745: /* most likely lack of space */
3746: printf("udf_open_logvol: error searching writing tracks\n");
3747: return EROFS;
3748: }
3749:
3750: /* writeout/update lvint on disc or only in memory */
3751: DPRINTF(VOLUMES, ("Opening logical volume\n"));
3752: if (ump->lvopen & UDF_OPEN_SESSION) {
1.85 reinoud 3753: /* TODO optional track reservation opening */
3754: error = udf_validate_session_start(ump);
3755: if (error)
3756: return error;
1.45 reinoud 3757:
3758: /* determine data and metadata tracks again */
3759: error = udf_search_writing_tracks(ump);
1.137 reinoud 3760:
3761: if (ump->lvclose & UDF_WRITE_VAT) {
3762: /*
3763: * we writeout the VAT to get a self-sustained session
3764: * for fsck
3765: */
3766: DPRINTF(VOLUMES, ("lvclose & UDF_WRITE_VAT\n"));
3767:
3768: /* write out the VAT data and all its descriptors */
3769: DPRINTF(VOLUMES, ("writeout vat_node\n"));
3770: udf_writeout_vat(ump);
3771:
1.138 reinoud 3772: /* force everything to be synchronized on the device */
3773: (void) udf_synchronise_caches(ump);
1.137 reinoud 3774: }
1.45 reinoud 3775: }
3776:
3777: /* mark it open */
3778: ump->logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_OPEN);
3779:
3780: /* do we need to write it out? */
3781: if (ump->lvopen & UDF_WRITE_LVINT) {
3782: error = udf_writeout_lvint(ump, ump->lvopen);
3783: /* if we couldn't write it mark it closed again */
3784: if (error) {
3785: ump->logvol_integrity->integrity_type =
3786: udf_rw32(UDF_INTEGRITY_CLOSED);
3787: return error;
3788: }
3789: }
3790:
3791: return 0;
3792: }
3793:
3794:
3795: int
3796: udf_close_logvol(struct udf_mount *ump, int mntflags)
3797: {
1.85 reinoud 3798: struct vnode *devvp = ump->devvp;
3799: struct mmc_op mmc_op;
1.45 reinoud 3800: int logvol_integrity;
1.70 reinoud 3801: int error = 0, error1 = 0, error2 = 0;
1.85 reinoud 3802: int tracknr;
3803: int nvats, n, nok;
1.45 reinoud 3804:
3805: /* already/still closed? */
3806: logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
3807: if (logvol_integrity == UDF_INTEGRITY_CLOSED)
3808: return 0;
3809:
3810: /* writeout/update lvint or write out VAT */
1.85 reinoud 3811: DPRINTF(VOLUMES, ("udf_close_logvol: closing logical volume\n"));
3812: #ifdef DIAGNOSTIC
3813: if (ump->lvclose & UDF_CLOSE_SESSION)
3814: KASSERT(ump->lvclose & UDF_WRITE_VAT);
3815: #endif
3816:
1.45 reinoud 3817: if (ump->lvclose & UDF_WRITE_VAT) {
3818: DPRINTF(VOLUMES, ("lvclose & UDF_WRITE_VAT\n"));
3819:
1.85 reinoud 3820: /* write out the VAT data and all its descriptors */
1.45 reinoud 3821: DPRINTF(VOLUMES, ("writeout vat_node\n"));
1.71 reinoud 3822: udf_writeout_vat(ump);
1.85 reinoud 3823:
3824: /* at least two DVD packets and 3 CD-R packets */
3825: nvats = 32;
3826:
3827: #if notyet
3828: /*
3829: * TODO calculate the available space and if the disc is
1.165 andvar 3830: * almost full, write out till end-256-1 with banks, write
1.85 reinoud 3831: * AVDP and fill up with VATs, then close session and close
3832: * disc.
3833: */
3834: if (ump->lvclose & UDF_FINALISE_DISC) {
3835: error = udf_write_phys_dscr_sync(ump, NULL,
3836: UDF_C_FLOAT_DSCR,
3837: (union dscrptr *) ump->anchors[0],
3838: 0, 0);
3839: if (error)
3840: printf("writeout of anchor failed!\n");
3841:
3842: /* pad space with VAT ICBs */
3843: nvats = 256;
3844: }
3845: #endif
3846:
3847: /* write out a number of VAT nodes */
3848: nok = 0;
3849: for (n = 0; n < nvats; n++) {
3850: /* will now only write last FE/EFE */
1.45 reinoud 3851: ump->vat_node->i_flags |= IN_MODIFIED;
3852: error = VOP_FSYNC(ump->vat_node->vnode,
3853: FSCRED, FSYNC_WAIT, 0, 0);
1.85 reinoud 3854: if (!error)
3855: nok++;
3856: }
1.138 reinoud 3857: /* force everything to be synchronized on the device */
3858: (void) udf_synchronise_caches(ump);
3859:
1.85 reinoud 3860: if (nok < 14) {
3861: /* arbitrary; but at least one or two CD frames */
3862: printf("writeout of at least 14 VATs failed\n");
3863: return error;
3864: }
3865: }
3866:
3867: /* NOTE the disc is in a (minimal) valid state now; no erroring out */
3868:
3869: /* finish closing of session */
3870: if (ump->lvclose & UDF_CLOSE_SESSION) {
1.138 reinoud 3871: DPRINTF(VOLUMES, ("udf_close_logvol: closing session "
3872: "as requested\n"));
1.85 reinoud 3873: error = udf_validate_session_start(ump);
3874: if (error)
3875: return error;
3876:
1.99 reinoud 3877: (void) udf_synchronise_caches(ump);
3878:
1.85 reinoud 3879: /* close all associated tracks */
3880: tracknr = ump->discinfo.first_track_last_session;
3881: error = 0;
3882: while (tracknr <= ump->discinfo.last_track_last_session) {
3883: DPRINTF(VOLUMES, ("\tclosing possible open "
3884: "track %d\n", tracknr));
3885: memset(&mmc_op, 0, sizeof(mmc_op));
3886: mmc_op.operation = MMC_OP_CLOSETRACK;
3887: mmc_op.mmc_profile = ump->discinfo.mmc_profile;
3888: mmc_op.tracknr = tracknr;
3889: error = VOP_IOCTL(devvp, MMCOP, &mmc_op,
3890: FKIOCTL, NOCRED);
3891: if (error)
3892: printf("udf_close_logvol: closing of "
3893: "track %d failed\n", tracknr);
3894: tracknr ++;
3895: }
3896: if (!error) {
3897: DPRINTF(VOLUMES, ("closing session\n"));
3898: memset(&mmc_op, 0, sizeof(mmc_op));
3899: mmc_op.operation = MMC_OP_CLOSESESSION;
3900: mmc_op.mmc_profile = ump->discinfo.mmc_profile;
3901: mmc_op.sessionnr = ump->discinfo.num_sessions;
3902: error = VOP_IOCTL(devvp, MMCOP, &mmc_op,
3903: FKIOCTL, NOCRED);
3904: if (error)
3905: printf("udf_close_logvol: closing of session"
3906: "failed\n");
1.45 reinoud 3907: }
1.85 reinoud 3908: if (!error)
3909: ump->lvopen |= UDF_OPEN_SESSION;
1.45 reinoud 3910: if (error) {
1.85 reinoud 3911: printf("udf_close_logvol: leaving disc as it is\n");
3912: ump->lvclose &= ~UDF_FINALISE_DISC;
1.45 reinoud 3913: }
3914: }
3915:
1.85 reinoud 3916: if (ump->lvclose & UDF_FINALISE_DISC) {
3917: memset(&mmc_op, 0, sizeof(mmc_op));
3918: mmc_op.operation = MMC_OP_FINALISEDISC;
3919: mmc_op.mmc_profile = ump->discinfo.mmc_profile;
3920: mmc_op.sessionnr = ump->discinfo.num_sessions;
3921: error = VOP_IOCTL(devvp, MMCOP, &mmc_op,
3922: FKIOCTL, NOCRED);
3923: if (error)
3924: printf("udf_close_logvol: finalising disc"
3925: "failed\n");
3926: }
3927:
3928: /* write out partition bitmaps if requested */
1.45 reinoud 3929: if (ump->lvclose & UDF_WRITE_PART_BITMAPS) {
1.70 reinoud 3930: /* sync writeout metadata spacetable if existing */
3931: error1 = udf_write_metadata_partition_spacetable(ump, true);
3932: if (error1)
3933: printf( "udf_close_logvol: writeout of metadata space "
3934: "bitmap failed\n");
3935:
1.68 reinoud 3936: /* sync writeout partition spacetables */
1.70 reinoud 3937: error2 = udf_write_physical_partition_spacetables(ump, true);
3938: if (error2)
1.45 reinoud 3939: printf( "udf_close_logvol: writeout of space tables "
3940: "failed\n");
1.70 reinoud 3941:
3942: if (error1 || error2)
3943: return (error1 | error2);
3944:
1.45 reinoud 3945: ump->lvclose &= ~UDF_WRITE_PART_BITMAPS;
3946: }
3947:
1.104 reinoud 3948: /* write out metadata partition nodes if requested */
3949: if (ump->lvclose & UDF_WRITE_METAPART_NODES) {
3950: /* sync writeout metadata descriptor node */
3951: error1 = udf_writeout_node(ump->metadata_node, FSYNC_WAIT);
3952: if (error1)
3953: printf( "udf_close_logvol: writeout of metadata partition "
3954: "node failed\n");
3955:
3956: /* duplicate metadata partition descriptor if needed */
3957: udf_synchronise_metadatamirror_node(ump);
3958:
3959: /* sync writeout metadatamirror descriptor node */
3960: error2 = udf_writeout_node(ump->metadatamirror_node, FSYNC_WAIT);
3961: if (error2)
3962: printf( "udf_close_logvol: writeout of metadata partition "
3963: "mirror node failed\n");
3964:
3965: if (error1 || error2)
3966: return (error1 | error2);
3967:
3968: ump->lvclose &= ~UDF_WRITE_METAPART_NODES;
3969: }
3970:
1.45 reinoud 3971: /* mark it closed */
3972: ump->logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
3973:
1.85 reinoud 3974: /* do we need to write out the logical volume integrity? */
1.45 reinoud 3975: if (ump->lvclose & UDF_WRITE_LVINT)
3976: error = udf_writeout_lvint(ump, ump->lvopen);
3977: if (error) {
3978: /* HELP now what? mark it open again for now */
3979: ump->logvol_integrity->integrity_type =
3980: udf_rw32(UDF_INTEGRITY_OPEN);
3981: return error;
1.9 christos 3982: }
1.1 reinoud 3983:
1.45 reinoud 3984: (void) udf_synchronise_caches(ump);
1.1 reinoud 3985:
3986: return 0;
3987: }
3988:
3989: /* --------------------------------------------------------------------- */
3990:
3991: /*
1.45 reinoud 3992: * Genfs interfacing
3993: *
3994: * static const struct genfs_ops udf_genfsops = {
3995: * .gop_size = genfs_size,
3996: * size of transfers
3997: * .gop_alloc = udf_gop_alloc,
3998: * allocate len bytes at offset
3999: * .gop_write = genfs_gop_write,
4000: * putpages interface code
4001: * .gop_markupdate = udf_gop_markupdate,
4002: * set update/modify flags etc.
4003: * }
4004: */
4005:
4006: /*
4007: * Genfs interface. These four functions are the only ones defined though not
4008: * documented... great....
1.1 reinoud 4009: */
4010:
1.45 reinoud 4011: /*
1.95 reinoud 4012: * Called for allocating an extent of the file either by VOP_WRITE() or by
4013: * genfs filling up gaps.
1.45 reinoud 4014: */
1.1 reinoud 4015: static int
1.45 reinoud 4016: udf_gop_alloc(struct vnode *vp, off_t off,
4017: off_t len, int flags, kauth_cred_t cred)
4018: {
4019: struct udf_node *udf_node = VTOI(vp);
4020: struct udf_mount *ump = udf_node->ump;
1.95 reinoud 4021: uint64_t lb_start, lb_end;
1.45 reinoud 4022: uint32_t lb_size, num_lb;
1.95 reinoud 4023: int udf_c_type, vpart_num, can_fail;
4024: int error;
4025:
4026: DPRINTF(ALLOC, ("udf_gop_alloc called for offset %"PRIu64" for %"PRIu64" bytes, %s\n",
4027: off, len, flags? "SYNC":"NONE"));
4028:
4029: /*
4030: * request the pages of our vnode and see how many pages will need to
4031: * be allocated and reserve that space
4032: */
4033: lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
4034: lb_start = off / lb_size;
4035: lb_end = (off + len + lb_size -1) / lb_size;
4036: num_lb = lb_end - lb_start;
4037:
4038: udf_c_type = udf_get_c_type(udf_node);
4039: vpart_num = udf_get_record_vpart(ump, udf_c_type);
4040:
4041: /* all requests can fail */
4042: can_fail = true;
4043:
4044: /* fid's (directories) can't fail */
4045: if (udf_c_type == UDF_C_FIDS)
4046: can_fail = false;
4047:
4048: /* system files can't fail */
4049: if (vp->v_vflag & VV_SYSTEM)
4050: can_fail = false;
4051:
4052: error = udf_reserve_space(ump, udf_node, udf_c_type,
4053: vpart_num, num_lb, can_fail);
1.45 reinoud 4054:
1.95 reinoud 4055: DPRINTF(ALLOC, ("\tlb_start %"PRIu64", lb_end %"PRIu64", num_lb %d\n",
4056: lb_start, lb_end, num_lb));
1.45 reinoud 4057:
1.95 reinoud 4058: return error;
1.45 reinoud 4059: }
4060:
4061:
4062: /*
4063: * callback from genfs to update our flags
4064: */
4065: static void
4066: udf_gop_markupdate(struct vnode *vp, int flags)
4067: {
4068: struct udf_node *udf_node = VTOI(vp);
4069: u_long mask = 0;
4070:
4071: if ((flags & GOP_UPDATE_ACCESSED) != 0) {
4072: mask = IN_ACCESS;
4073: }
4074: if ((flags & GOP_UPDATE_MODIFIED) != 0) {
4075: if (vp->v_type == VREG) {
4076: mask |= IN_CHANGE | IN_UPDATE;
4077: } else {
4078: mask |= IN_MODIFY;
4079: }
4080: }
4081: if (mask) {
4082: udf_node->i_flags |= mask;
4083: }
4084: }
4085:
4086:
4087: static const struct genfs_ops udf_genfsops = {
4088: .gop_size = genfs_size,
4089: .gop_alloc = udf_gop_alloc,
4090: .gop_write = genfs_gop_write_rwmap,
4091: .gop_markupdate = udf_gop_markupdate,
1.140 chs 4092: .gop_putrange = genfs_gop_putrange,
1.45 reinoud 4093: };
4094:
4095:
4096: /* --------------------------------------------------------------------- */
4097:
4098: int
4099: udf_write_terminator(struct udf_mount *ump, uint32_t sector)
1.1 reinoud 4100: {
1.45 reinoud 4101: union dscrptr *dscr;
1.1 reinoud 4102: int error;
4103:
1.83 cegger 4104: dscr = malloc(ump->discinfo.sector_size, M_TEMP, M_WAITOK|M_ZERO);
1.45 reinoud 4105: udf_inittag(ump, &dscr->tag, TAGID_TERM, sector);
4106:
4107: /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */
4108: dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH);
4109: (void) udf_validate_tag_and_crc_sums(dscr);
4110:
4111: error = udf_write_phys_dscr_sync(ump, NULL, UDF_C_DSCR,
4112: dscr, sector, sector);
4113:
4114: free(dscr, M_TEMP);
4115:
4116: return error;
4117: }
4118:
4119:
4120: /* --------------------------------------------------------------------- */
4121:
4122: /* UDF<->unix converters */
4123:
4124: /* --------------------------------------------------------------------- */
4125:
4126: static mode_t
4127: udf_perm_to_unix_mode(uint32_t perm)
4128: {
4129: mode_t mode;
4130:
4131: mode = ((perm & UDF_FENTRY_PERM_USER_MASK) );
4132: mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK ) >> 2);
4133: mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
4134:
4135: return mode;
4136: }
4137:
4138: /* --------------------------------------------------------------------- */
4139:
4140: static uint32_t
4141: unix_mode_to_udf_perm(mode_t mode)
4142: {
4143: uint32_t perm;
1.152 skrll 4144:
1.45 reinoud 4145: perm = ((mode & S_IRWXO) );
4146: perm |= ((mode & S_IRWXG) << 2);
4147: perm |= ((mode & S_IRWXU) << 4);
4148: perm |= ((mode & S_IWOTH) << 3);
4149: perm |= ((mode & S_IWGRP) << 5);
4150: perm |= ((mode & S_IWUSR) << 7);
4151:
4152: return perm;
4153: }
4154:
4155: /* --------------------------------------------------------------------- */
4156:
4157: static uint32_t
4158: udf_icb_to_unix_filetype(uint32_t icbftype)
4159: {
4160: switch (icbftype) {
4161: case UDF_ICB_FILETYPE_DIRECTORY :
4162: case UDF_ICB_FILETYPE_STREAMDIR :
4163: return S_IFDIR;
4164: case UDF_ICB_FILETYPE_FIFO :
4165: return S_IFIFO;
4166: case UDF_ICB_FILETYPE_CHARDEVICE :
4167: return S_IFCHR;
4168: case UDF_ICB_FILETYPE_BLOCKDEVICE :
4169: return S_IFBLK;
4170: case UDF_ICB_FILETYPE_RANDOMACCESS :
4171: case UDF_ICB_FILETYPE_REALTIME :
4172: return S_IFREG;
4173: case UDF_ICB_FILETYPE_SYMLINK :
4174: return S_IFLNK;
4175: case UDF_ICB_FILETYPE_SOCKET :
4176: return S_IFSOCK;
4177: }
4178: /* no idea what this is */
4179: return 0;
4180: }
1.1 reinoud 4181:
1.45 reinoud 4182: /* --------------------------------------------------------------------- */
1.1 reinoud 4183:
1.45 reinoud 4184: void
1.48 reinoud 4185: udf_to_unix_name(char *result, int result_len, char *id, int len,
4186: struct charspec *chsp)
1.45 reinoud 4187: {
4188: uint16_t *raw_name, *unix_name;
4189: uint16_t *inchp, ch;
4190: uint8_t *outchp;
4191: const char *osta_id = "OSTA Compressed Unicode";
1.48 reinoud 4192: int ucode_chars, nice_uchars, is_osta_typ0, nout;
1.1 reinoud 4193:
1.45 reinoud 4194: raw_name = malloc(2048 * sizeof(uint16_t), M_UDFTEMP, M_WAITOK);
4195: unix_name = raw_name + 1024; /* split space in half */
4196: assert(sizeof(char) == sizeof(uint8_t));
4197: outchp = (uint8_t *) result;
1.1 reinoud 4198:
1.45 reinoud 4199: is_osta_typ0 = (chsp->type == 0);
4200: is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
4201: if (is_osta_typ0) {
1.48 reinoud 4202: /* TODO clean up */
1.45 reinoud 4203: *raw_name = *unix_name = 0;
4204: ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name);
4205: ucode_chars = MIN(ucode_chars, UnicodeLength((unicode_t *) raw_name));
4206: nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars);
1.48 reinoud 4207: /* output UTF8 */
1.45 reinoud 4208: for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) {
4209: ch = *inchp;
1.48 reinoud 4210: nout = wput_utf8(outchp, result_len, ch);
4211: outchp += nout; result_len -= nout;
1.45 reinoud 4212: if (!ch) break;
4213: }
4214: *outchp++ = 0;
1.1 reinoud 4215: } else {
1.45 reinoud 4216: /* assume 8bit char length byte latin-1 */
4217: assert(*id == 8);
1.117 christos 4218: assert(strlen((char *) (id+1)) <= NAME_MAX);
1.45 reinoud 4219: strncpy((char *) result, (char *) (id+1), strlen((char *) (id+1)));
1.9 christos 4220: }
1.45 reinoud 4221: free(raw_name, M_UDFTEMP);
4222: }
4223:
4224: /* --------------------------------------------------------------------- */
1.1 reinoud 4225:
1.45 reinoud 4226: void
4227: unix_to_udf_name(char *result, uint8_t *result_len, char const *name, int name_len,
4228: struct charspec *chsp)
4229: {
4230: uint16_t *raw_name;
4231: uint16_t *outchp;
4232: const char *inchp;
4233: const char *osta_id = "OSTA Compressed Unicode";
1.49 christos 4234: int udf_chars, is_osta_typ0, bits;
4235: size_t cnt;
1.1 reinoud 4236:
1.45 reinoud 4237: /* allocate temporary unicode-16 buffer */
4238: raw_name = malloc(1024, M_UDFTEMP, M_WAITOK);
1.1 reinoud 4239:
1.48 reinoud 4240: /* convert utf8 to unicode-16 */
1.45 reinoud 4241: *raw_name = 0;
4242: inchp = name;
4243: outchp = raw_name;
1.48 reinoud 4244: bits = 8;
4245: for (cnt = name_len, udf_chars = 0; cnt;) {
4246: *outchp = wget_utf8(&inchp, &cnt);
4247: if (*outchp > 0xff)
4248: bits=16;
4249: outchp++;
4250: udf_chars++;
1.45 reinoud 4251: }
1.48 reinoud 4252: /* null terminate just in case */
4253: *outchp++ = 0;
1.1 reinoud 4254:
1.45 reinoud 4255: is_osta_typ0 = (chsp->type == 0);
4256: is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
4257: if (is_osta_typ0) {
1.48 reinoud 4258: udf_chars = udf_CompressUnicode(udf_chars, bits,
1.45 reinoud 4259: (unicode_t *) raw_name,
4260: (byte *) result);
4261: } else {
1.48 reinoud 4262: printf("unix to udf name: no CHSP0 ?\n");
1.45 reinoud 4263: /* XXX assume 8bit char length byte latin-1 */
4264: *result++ = 8; udf_chars = 1;
4265: strncpy(result, name + 1, name_len);
4266: udf_chars += name_len;
1.9 christos 4267: }
1.45 reinoud 4268: *result_len = udf_chars;
4269: free(raw_name, M_UDFTEMP);
4270: }
4271:
4272: /* --------------------------------------------------------------------- */
4273:
4274: void
4275: udf_timestamp_to_timespec(struct udf_mount *ump,
4276: struct timestamp *timestamp,
4277: struct timespec *timespec)
4278: {
4279: struct clock_ymdhms ymdhms;
4280: uint32_t usecs, secs, nsecs;
4281: uint16_t tz;
4282:
4283: /* fill in ymdhms structure from timestamp */
4284: memset(&ymdhms, 0, sizeof(ymdhms));
4285: ymdhms.dt_year = udf_rw16(timestamp->year);
4286: ymdhms.dt_mon = timestamp->month;
4287: ymdhms.dt_day = timestamp->day;
4288: ymdhms.dt_wday = 0; /* ? */
4289: ymdhms.dt_hour = timestamp->hour;
4290: ymdhms.dt_min = timestamp->minute;
4291: ymdhms.dt_sec = timestamp->second;
4292:
4293: secs = clock_ymdhms_to_secs(&ymdhms);
4294: usecs = timestamp->usec +
4295: 100*timestamp->hund_usec + 10000*timestamp->centisec;
4296: nsecs = usecs * 1000;
1.1 reinoud 4297:
4298: /*
1.45 reinoud 4299: * Calculate the time zone. The timezone is 12 bit signed 2's
4300: * compliment, so we gotta do some extra magic to handle it right.
1.1 reinoud 4301: */
1.45 reinoud 4302: tz = udf_rw16(timestamp->type_tz);
4303: tz &= 0x0fff; /* only lower 12 bits are significant */
1.157 andvar 4304: if (tz & 0x0800) /* sign extension */
1.45 reinoud 4305: tz |= 0xf000;
1.1 reinoud 4306:
1.45 reinoud 4307: /* TODO check timezone conversion */
4308: /* check if we are specified a timezone to convert */
4309: if (udf_rw16(timestamp->type_tz) & 0x1000) {
4310: if ((int16_t) tz != -2047)
4311: secs -= (int16_t) tz * 60;
1.1 reinoud 4312: } else {
1.45 reinoud 4313: secs -= ump->mount_args.gmtoff;
4314: }
1.1 reinoud 4315:
1.45 reinoud 4316: timespec->tv_sec = secs;
4317: timespec->tv_nsec = nsecs;
4318: }
1.1 reinoud 4319:
4320:
1.45 reinoud 4321: void
4322: udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp)
4323: {
4324: struct clock_ymdhms ymdhms;
4325: uint32_t husec, usec, csec;
1.1 reinoud 4326:
1.45 reinoud 4327: (void) clock_secs_to_ymdhms(timespec->tv_sec, &ymdhms);
1.1 reinoud 4328:
1.58 reinoud 4329: usec = timespec->tv_nsec / 1000;
4330: husec = usec / 100;
4331: usec -= husec * 100; /* only 0-99 in usec */
4332: csec = husec / 100; /* only 0-99 in csec */
4333: husec -= csec * 100; /* only 0-99 in husec */
1.45 reinoud 4334:
4335: /* set method 1 for CUT/GMT */
4336: timestamp->type_tz = udf_rw16((1<<12) + 0);
4337: timestamp->year = udf_rw16(ymdhms.dt_year);
4338: timestamp->month = ymdhms.dt_mon;
4339: timestamp->day = ymdhms.dt_day;
4340: timestamp->hour = ymdhms.dt_hour;
4341: timestamp->minute = ymdhms.dt_min;
4342: timestamp->second = ymdhms.dt_sec;
4343: timestamp->centisec = csec;
4344: timestamp->hund_usec = husec;
4345: timestamp->usec = usec;
1.1 reinoud 4346: }
4347:
4348: /* --------------------------------------------------------------------- */
4349:
1.45 reinoud 4350: /*
4351: * Attribute and filetypes converters with get/set pairs
4352: */
4353:
4354: uint32_t
4355: udf_getaccessmode(struct udf_node *udf_node)
1.1 reinoud 4356: {
1.101 mbalmer 4357: struct file_entry *fe = udf_node->fe;
1.45 reinoud 4358: struct extfile_entry *efe = udf_node->efe;
4359: uint32_t udf_perm, icbftype;
4360: uint32_t mode, ftype;
4361: uint16_t icbflags;
1.1 reinoud 4362:
1.45 reinoud 4363: UDF_LOCK_NODE(udf_node, 0);
4364: if (fe) {
4365: udf_perm = udf_rw32(fe->perm);
4366: icbftype = fe->icbtag.file_type;
4367: icbflags = udf_rw16(fe->icbtag.flags);
4368: } else {
4369: assert(udf_node->efe);
4370: udf_perm = udf_rw32(efe->perm);
4371: icbftype = efe->icbtag.file_type;
4372: icbflags = udf_rw16(efe->icbtag.flags);
4373: }
1.1 reinoud 4374:
1.45 reinoud 4375: mode = udf_perm_to_unix_mode(udf_perm);
4376: ftype = udf_icb_to_unix_filetype(icbftype);
1.1 reinoud 4377:
1.45 reinoud 4378: /* set suid, sgid, sticky from flags in fe/efe */
4379: if (icbflags & UDF_ICB_TAG_FLAGS_SETUID)
4380: mode |= S_ISUID;
4381: if (icbflags & UDF_ICB_TAG_FLAGS_SETGID)
4382: mode |= S_ISGID;
4383: if (icbflags & UDF_ICB_TAG_FLAGS_STICKY)
4384: mode |= S_ISVTX;
1.1 reinoud 4385:
1.45 reinoud 4386: UDF_UNLOCK_NODE(udf_node, 0);
1.1 reinoud 4387:
1.45 reinoud 4388: return mode | ftype;
1.1 reinoud 4389: }
4390:
4391:
1.45 reinoud 4392: void
4393: udf_setaccessmode(struct udf_node *udf_node, mode_t mode)
1.1 reinoud 4394: {
1.45 reinoud 4395: struct file_entry *fe = udf_node->fe;
4396: struct extfile_entry *efe = udf_node->efe;
4397: uint32_t udf_perm;
4398: uint16_t icbflags;
4399:
4400: UDF_LOCK_NODE(udf_node, 0);
4401: udf_perm = unix_mode_to_udf_perm(mode & ALLPERMS);
4402: if (fe) {
4403: icbflags = udf_rw16(fe->icbtag.flags);
4404: } else {
4405: icbflags = udf_rw16(efe->icbtag.flags);
4406: }
1.1 reinoud 4407:
1.45 reinoud 4408: icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
4409: icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
4410: icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
4411: if (mode & S_ISUID)
4412: icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
4413: if (mode & S_ISGID)
4414: icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
4415: if (mode & S_ISVTX)
4416: icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
1.1 reinoud 4417:
1.45 reinoud 4418: if (fe) {
4419: fe->perm = udf_rw32(udf_perm);
4420: fe->icbtag.flags = udf_rw16(icbflags);
4421: } else {
4422: efe->perm = udf_rw32(udf_perm);
4423: efe->icbtag.flags = udf_rw16(icbflags);
1.9 christos 4424: }
1.1 reinoud 4425:
1.45 reinoud 4426: UDF_UNLOCK_NODE(udf_node, 0);
1.1 reinoud 4427: }
4428:
4429:
1.45 reinoud 4430: void
4431: udf_getownership(struct udf_node *udf_node, uid_t *uidp, gid_t *gidp)
1.26 reinoud 4432: {
1.45 reinoud 4433: struct udf_mount *ump = udf_node->ump;
4434: struct file_entry *fe = udf_node->fe;
4435: struct extfile_entry *efe = udf_node->efe;
4436: uid_t uid;
4437: gid_t gid;
1.26 reinoud 4438:
1.45 reinoud 4439: UDF_LOCK_NODE(udf_node, 0);
4440: if (fe) {
4441: uid = (uid_t)udf_rw32(fe->uid);
4442: gid = (gid_t)udf_rw32(fe->gid);
4443: } else {
4444: assert(udf_node->efe);
4445: uid = (uid_t)udf_rw32(efe->uid);
4446: gid = (gid_t)udf_rw32(efe->gid);
4447: }
1.152 skrll 4448:
1.45 reinoud 4449: /* do the uid/gid translation game */
1.76 reinoud 4450: if (uid == (uid_t) -1)
1.45 reinoud 4451: uid = ump->mount_args.anon_uid;
1.76 reinoud 4452: if (gid == (gid_t) -1)
1.45 reinoud 4453: gid = ump->mount_args.anon_gid;
1.76 reinoud 4454:
1.45 reinoud 4455: *uidp = uid;
4456: *gidp = gid;
4457:
4458: UDF_UNLOCK_NODE(udf_node, 0);
4459: }
1.26 reinoud 4460:
4461:
1.45 reinoud 4462: void
4463: udf_setownership(struct udf_node *udf_node, uid_t uid, gid_t gid)
4464: {
4465: struct udf_mount *ump = udf_node->ump;
4466: struct file_entry *fe = udf_node->fe;
4467: struct extfile_entry *efe = udf_node->efe;
4468: uid_t nobody_uid;
4469: gid_t nobody_gid;
4470:
4471: UDF_LOCK_NODE(udf_node, 0);
4472:
4473: /* do the uid/gid translation game */
4474: nobody_uid = ump->mount_args.nobody_uid;
4475: nobody_gid = ump->mount_args.nobody_gid;
1.76 reinoud 4476: if (uid == nobody_uid)
1.45 reinoud 4477: uid = (uid_t) -1;
1.76 reinoud 4478: if (gid == nobody_gid)
1.45 reinoud 4479: gid = (gid_t) -1;
1.26 reinoud 4480:
1.45 reinoud 4481: if (fe) {
4482: fe->uid = udf_rw32((uint32_t) uid);
4483: fe->gid = udf_rw32((uint32_t) gid);
1.26 reinoud 4484: } else {
1.45 reinoud 4485: efe->uid = udf_rw32((uint32_t) uid);
4486: efe->gid = udf_rw32((uint32_t) gid);
1.26 reinoud 4487: }
1.45 reinoud 4488:
4489: UDF_UNLOCK_NODE(udf_node, 0);
1.26 reinoud 4490: }
1.45 reinoud 4491:
1.26 reinoud 4492:
4493: /* --------------------------------------------------------------------- */
4494:
1.59 reinoud 4495:
1.120 reinoud 4496: int
4497: udf_dirhash_fill(struct udf_node *dir_node)
1.1 reinoud 4498: {
1.59 reinoud 4499: struct vnode *dvp = dir_node->vnode;
1.73 reinoud 4500: struct dirhash *dirh;
1.45 reinoud 4501: struct file_entry *fe = dir_node->fe;
4502: struct extfile_entry *efe = dir_node->efe;
4503: struct fileid_desc *fid;
4504: struct dirent *dirent;
1.59 reinoud 4505: uint64_t file_size, pre_diroffset, diroffset;
1.45 reinoud 4506: uint32_t lb_size;
1.59 reinoud 4507: int error;
4508:
1.66 reinoud 4509: /* make sure we have a dirhash to work on */
4510: dirh = dir_node->dir_hash;
4511: KASSERT(dirh);
4512: KASSERT(dirh->refcnt > 0);
4513:
1.73 reinoud 4514: if (dirh->flags & DIRH_BROKEN)
1.59 reinoud 4515: return EIO;
1.73 reinoud 4516: if (dirh->flags & DIRH_COMPLETE)
1.59 reinoud 4517: return 0;
4518:
1.66 reinoud 4519: /* make sure we have a clean dirhash to add to */
1.73 reinoud 4520: dirhash_purge_entries(dirh);
1.45 reinoud 4521:
4522: /* get directory filesize */
4523: if (fe) {
4524: file_size = udf_rw64(fe->inf_len);
4525: } else {
4526: assert(efe);
4527: file_size = udf_rw64(efe->inf_len);
4528: }
4529:
4530: /* allocate temporary space for fid */
4531: lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
4532: fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
1.1 reinoud 4533:
1.59 reinoud 4534: /* allocate temporary space for dirent */
4535: dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
4536:
4537: error = 0;
4538: diroffset = 0;
4539: while (diroffset < file_size) {
4540: /* transfer a new fid/dirent */
4541: pre_diroffset = diroffset;
4542: error = udf_read_fid_stream(dvp, &diroffset, fid, dirent);
4543: if (error) {
4544: /* TODO what to do? continue but not add? */
1.73 reinoud 4545: dirh->flags |= DIRH_BROKEN;
4546: dirhash_purge_entries(dirh);
1.59 reinoud 4547: break;
4548: }
1.1 reinoud 4549:
1.59 reinoud 4550: if ((fid->file_char & UDF_FILE_CHAR_DEL)) {
4551: /* register deleted extent for reuse */
1.73 reinoud 4552: dirhash_enter_freed(dirh, pre_diroffset,
1.59 reinoud 4553: udf_fidsize(fid));
4554: } else {
4555: /* append to the dirhash */
1.73 reinoud 4556: dirhash_enter(dirh, dirent, pre_diroffset,
1.59 reinoud 4557: udf_fidsize(fid), 0);
4558: }
1.9 christos 4559: }
1.73 reinoud 4560: dirh->flags |= DIRH_COMPLETE;
1.59 reinoud 4561:
4562: free(fid, M_UDFTEMP);
4563: free(dirent, M_UDFTEMP);
4564:
4565: return error;
4566: }
4567:
4568:
4569: /* --------------------------------------------------------------------- */
4570:
4571: /*
4572: * Directory read and manipulation functions.
4573: *
4574: */
4575:
1.152 skrll 4576: int
1.59 reinoud 4577: udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen,
4578: struct long_ad *icb_loc, int *found)
4579: {
4580: struct udf_node *dir_node = VTOI(vp);
1.73 reinoud 4581: struct dirhash *dirh;
4582: struct dirhash_entry *dirh_ep;
1.59 reinoud 4583: struct fileid_desc *fid;
1.136 reinoud 4584: struct dirent *dirent, *s_dirent;
4585: struct charspec osta_charspec;
1.59 reinoud 4586: uint64_t diroffset;
4587: uint32_t lb_size;
4588: int hit, error;
4589:
4590: /* set default return */
4591: *found = 0;
4592:
1.66 reinoud 4593: /* get our dirhash and make sure its read in */
1.73 reinoud 4594: dirhash_get(&dir_node->dir_hash);
1.120 reinoud 4595: error = udf_dirhash_fill(dir_node);
1.66 reinoud 4596: if (error) {
1.73 reinoud 4597: dirhash_put(dir_node->dir_hash);
1.59 reinoud 4598: return error;
1.66 reinoud 4599: }
1.73 reinoud 4600: dirh = dir_node->dir_hash;
1.1 reinoud 4601:
1.59 reinoud 4602: /* allocate temporary space for fid */
1.136 reinoud 4603: lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
4604: fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
4605: dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
4606: s_dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
1.59 reinoud 4607:
4608: DPRINTF(DIRHASH, ("dirhash_lookup looking for `%*.*s`\n",
4609: namelen, namelen, name));
1.1 reinoud 4610:
1.136 reinoud 4611: /* convert given unix name to canonical unix name */
4612: udf_osta_charset(&osta_charspec);
4613: unix_to_udf_name((char *) fid->data, &fid->l_fi,
4614: name, namelen, &osta_charspec);
4615: udf_to_unix_name(s_dirent->d_name, NAME_MAX,
4616: (char *) fid->data, fid->l_fi,
4617: &osta_charspec);
4618: s_dirent->d_namlen = strlen(s_dirent->d_name);
4619:
1.59 reinoud 4620: /* search our dirhash hits */
4621: memset(icb_loc, 0, sizeof(*icb_loc));
4622: dirh_ep = NULL;
4623: for (;;) {
1.136 reinoud 4624: hit = dirhash_lookup(dirh, s_dirent->d_name, s_dirent->d_namlen, &dirh_ep);
1.59 reinoud 4625: /* if no hit, abort the search */
4626: if (!hit)
4627: break;
1.1 reinoud 4628:
1.59 reinoud 4629: /* check this hit */
4630: diroffset = dirh_ep->offset;
1.1 reinoud 4631:
1.45 reinoud 4632: /* transfer a new fid/dirent */
4633: error = udf_read_fid_stream(vp, &diroffset, fid, dirent);
1.1 reinoud 4634: if (error)
4635: break;
4636:
1.59 reinoud 4637: DPRINTF(DIRHASH, ("dirhash_lookup\tchecking `%*.*s`\n",
4638: dirent->d_namlen, dirent->d_namlen, dirent->d_name));
1.1 reinoud 4639:
1.59 reinoud 4640: /* see if its our entry */
1.136 reinoud 4641: if (strncmp(dirent->d_name, s_dirent->d_name, s_dirent->d_namlen) == 0) {
1.59 reinoud 4642: *found = 1;
4643: *icb_loc = fid->icb;
1.45 reinoud 4644: break;
1.9 christos 4645: }
1.45 reinoud 4646: }
4647: free(fid, M_UDFTEMP);
4648: free(dirent, M_UDFTEMP);
1.136 reinoud 4649: free(s_dirent, M_UDFTEMP);
1.1 reinoud 4650:
1.73 reinoud 4651: dirhash_put(dir_node->dir_hash);
1.66 reinoud 4652:
1.59 reinoud 4653: return error;
1.45 reinoud 4654: }
1.1 reinoud 4655:
1.45 reinoud 4656: /* --------------------------------------------------------------------- */
1.1 reinoud 4657:
1.45 reinoud 4658: static int
4659: udf_create_new_fe(struct udf_mount *ump, struct file_entry *fe, int file_type,
4660: struct long_ad *node_icb, struct long_ad *parent_icb,
4661: uint64_t parent_unique_id)
4662: {
4663: struct timespec now;
4664: struct icb_tag *icb;
1.51 reinoud 4665: struct filetimes_extattr_entry *ft_extattr;
1.45 reinoud 4666: uint64_t unique_id;
4667: uint32_t fidsize, lb_num;
1.51 reinoud 4668: uint8_t *bpos;
4669: int crclen, attrlen;
1.45 reinoud 4670:
4671: lb_num = udf_rw32(node_icb->loc.lb_num);
4672: udf_inittag(ump, &fe->tag, TAGID_FENTRY, lb_num);
4673: icb = &fe->icbtag;
1.1 reinoud 4674:
4675: /*
1.45 reinoud 4676: * Always use strategy type 4 unless on WORM wich we don't support
4677: * (yet). Fill in defaults and set for internal allocation of data.
1.1 reinoud 4678: */
1.45 reinoud 4679: icb->strat_type = udf_rw16(4);
4680: icb->max_num_entries = udf_rw16(1);
4681: icb->file_type = file_type; /* 8 bit */
4682: icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
4683:
4684: fe->perm = udf_rw32(0x7fff); /* all is allowed */
4685: fe->link_cnt = udf_rw16(0); /* explicit setting */
1.1 reinoud 4686:
1.45 reinoud 4687: fe->ckpoint = udf_rw32(1); /* user supplied file version */
4688:
4689: vfs_timestamp(&now);
4690: udf_timespec_to_timestamp(&now, &fe->atime);
4691: udf_timespec_to_timestamp(&now, &fe->attrtime);
4692: udf_timespec_to_timestamp(&now, &fe->mtime);
1.1 reinoud 4693:
1.45 reinoud 4694: udf_set_regid(&fe->imp_id, IMPL_NAME);
4695: udf_add_impl_regid(ump, &fe->imp_id);
1.1 reinoud 4696:
1.45 reinoud 4697: unique_id = udf_advance_uniqueid(ump);
4698: fe->unique_id = udf_rw64(unique_id);
1.51 reinoud 4699: fe->l_ea = udf_rw32(0);
4700:
4701: /* create extended attribute to record our creation time */
4702: attrlen = UDF_FILETIMES_ATTR_SIZE(1);
4703: ft_extattr = malloc(attrlen, M_UDFTEMP, M_WAITOK);
4704: memset(ft_extattr, 0, attrlen);
4705: ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO);
4706: ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */
4707: ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1));
4708: ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */
4709: ft_extattr->existence = UDF_FILETIMES_FILE_CREATION;
4710: udf_timespec_to_timestamp(&now, &ft_extattr->times[0]);
4711:
4712: udf_extattr_insert_internal(ump, (union dscrptr *) fe,
4713: (struct extattr_entry *) ft_extattr);
4714: free(ft_extattr, M_UDFTEMP);
1.1 reinoud 4715:
1.51 reinoud 4716: /* if its a directory, create '..' */
4717: bpos = (uint8_t *) fe->data + udf_rw32(fe->l_ea);
1.45 reinoud 4718: fidsize = 0;
4719: if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
4720: fidsize = udf_create_parentfid(ump,
1.51 reinoud 4721: (struct fileid_desc *) bpos, parent_icb,
1.45 reinoud 4722: parent_unique_id);
1.9 christos 4723: }
1.1 reinoud 4724:
1.45 reinoud 4725: /* record fidlength information */
4726: fe->inf_len = udf_rw64(fidsize);
4727: fe->l_ad = udf_rw32(fidsize);
4728: fe->logblks_rec = udf_rw64(0); /* intern */
4729:
4730: crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
1.51 reinoud 4731: crclen += udf_rw32(fe->l_ea) + fidsize;
1.45 reinoud 4732: fe->tag.desc_crc_len = udf_rw16(crclen);
1.1 reinoud 4733:
1.45 reinoud 4734: (void) udf_validate_tag_and_crc_sums((union dscrptr *) fe);
1.1 reinoud 4735:
1.45 reinoud 4736: return fidsize;
1.1 reinoud 4737: }
4738:
4739: /* --------------------------------------------------------------------- */
4740:
1.45 reinoud 4741: static int
4742: udf_create_new_efe(struct udf_mount *ump, struct extfile_entry *efe,
4743: int file_type, struct long_ad *node_icb, struct long_ad *parent_icb,
4744: uint64_t parent_unique_id)
4745: {
4746: struct timespec now;
4747: struct icb_tag *icb;
4748: uint64_t unique_id;
4749: uint32_t fidsize, lb_num;
1.51 reinoud 4750: uint8_t *bpos;
1.45 reinoud 4751: int crclen;
4752:
4753: lb_num = udf_rw32(node_icb->loc.lb_num);
4754: udf_inittag(ump, &efe->tag, TAGID_EXTFENTRY, lb_num);
4755: icb = &efe->icbtag;
4756:
4757: /*
4758: * Always use strategy type 4 unless on WORM wich we don't support
4759: * (yet). Fill in defaults and set for internal allocation of data.
4760: */
4761: icb->strat_type = udf_rw16(4);
4762: icb->max_num_entries = udf_rw16(1);
4763: icb->file_type = file_type; /* 8 bit */
4764: icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC);
1.1 reinoud 4765:
1.45 reinoud 4766: efe->perm = udf_rw32(0x7fff); /* all is allowed */
4767: efe->link_cnt = udf_rw16(0); /* explicit setting */
1.1 reinoud 4768:
1.45 reinoud 4769: efe->ckpoint = udf_rw32(1); /* user supplied file version */
1.1 reinoud 4770:
1.45 reinoud 4771: vfs_timestamp(&now);
4772: udf_timespec_to_timestamp(&now, &efe->ctime);
4773: udf_timespec_to_timestamp(&now, &efe->atime);
4774: udf_timespec_to_timestamp(&now, &efe->attrtime);
4775: udf_timespec_to_timestamp(&now, &efe->mtime);
1.26 reinoud 4776:
1.45 reinoud 4777: udf_set_regid(&efe->imp_id, IMPL_NAME);
4778: udf_add_impl_regid(ump, &efe->imp_id);
1.1 reinoud 4779:
1.45 reinoud 4780: unique_id = udf_advance_uniqueid(ump);
4781: efe->unique_id = udf_rw64(unique_id);
1.51 reinoud 4782: efe->l_ea = udf_rw32(0);
1.1 reinoud 4783:
1.51 reinoud 4784: /* if its a directory, create '..' */
4785: bpos = (uint8_t *) efe->data + udf_rw32(efe->l_ea);
1.45 reinoud 4786: fidsize = 0;
4787: if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
4788: fidsize = udf_create_parentfid(ump,
1.51 reinoud 4789: (struct fileid_desc *) bpos, parent_icb,
1.45 reinoud 4790: parent_unique_id);
4791: }
1.1 reinoud 4792:
1.45 reinoud 4793: /* record fidlength information */
4794: efe->obj_size = udf_rw64(fidsize);
4795: efe->inf_len = udf_rw64(fidsize);
4796: efe->l_ad = udf_rw32(fidsize);
4797: efe->logblks_rec = udf_rw64(0); /* intern */
1.1 reinoud 4798:
1.45 reinoud 4799: crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
1.51 reinoud 4800: crclen += udf_rw32(efe->l_ea) + fidsize;
1.45 reinoud 4801: efe->tag.desc_crc_len = udf_rw16(crclen);
1.1 reinoud 4802:
1.45 reinoud 4803: (void) udf_validate_tag_and_crc_sums((union dscrptr *) efe);
1.1 reinoud 4804:
1.45 reinoud 4805: return fidsize;
1.1 reinoud 4806: }
4807:
4808: /* --------------------------------------------------------------------- */
4809:
1.45 reinoud 4810: int
4811: udf_dir_detach(struct udf_mount *ump, struct udf_node *dir_node,
4812: struct udf_node *udf_node, struct componentname *cnp)
1.1 reinoud 4813: {
1.59 reinoud 4814: struct vnode *dvp = dir_node->vnode;
1.73 reinoud 4815: struct dirhash *dirh;
4816: struct dirhash_entry *dirh_ep;
1.45 reinoud 4817: struct file_entry *fe = dir_node->fe;
4818: struct fileid_desc *fid;
1.136 reinoud 4819: struct dirent *dirent, *s_dirent;
4820: struct charspec osta_charspec;
1.121 christos 4821: uint64_t diroffset;
1.45 reinoud 4822: uint32_t lb_size, fidsize;
4823: int found, error;
1.59 reinoud 4824: int hit, refcnt;
1.1 reinoud 4825:
1.66 reinoud 4826: /* get our dirhash and make sure its read in */
1.73 reinoud 4827: dirhash_get(&dir_node->dir_hash);
1.120 reinoud 4828: error = udf_dirhash_fill(dir_node);
1.66 reinoud 4829: if (error) {
1.73 reinoud 4830: dirhash_put(dir_node->dir_hash);
1.66 reinoud 4831: return error;
4832: }
1.73 reinoud 4833: dirh = dir_node->dir_hash;
1.66 reinoud 4834:
1.45 reinoud 4835: /* get directory filesize */
1.121 christos 4836: if (!fe) {
1.122 riz 4837: assert(dir_node->efe);
1.45 reinoud 4838: }
1.1 reinoud 4839:
1.136 reinoud 4840: /* allocate temporary space for fid and dirents */
4841: lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
4842: fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
4843: dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
4844: s_dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
4845:
4846: /* convert given unix name to canonical unix name */
4847: udf_osta_charset(&osta_charspec);
4848: unix_to_udf_name((char *) fid->data, &fid->l_fi,
4849: cnp->cn_nameptr, cnp->cn_namelen, &osta_charspec);
4850: udf_to_unix_name(s_dirent->d_name, NAME_MAX,
4851: (char *) fid->data, fid->l_fi,
4852: &osta_charspec);
4853: s_dirent->d_namlen = strlen(s_dirent->d_name);
1.1 reinoud 4854:
1.59 reinoud 4855: /* search our dirhash hits */
1.45 reinoud 4856: found = 0;
1.59 reinoud 4857: dirh_ep = NULL;
4858: for (;;) {
1.136 reinoud 4859: hit = dirhash_lookup(dirh, s_dirent->d_name, s_dirent->d_namlen, &dirh_ep);
1.59 reinoud 4860: /* if no hit, abort the search */
4861: if (!hit)
4862: break;
1.1 reinoud 4863:
1.59 reinoud 4864: /* check this hit */
4865: diroffset = dirh_ep->offset;
1.1 reinoud 4866:
1.45 reinoud 4867: /* transfer a new fid/dirent */
1.59 reinoud 4868: error = udf_read_fid_stream(dvp, &diroffset, fid, dirent);
1.45 reinoud 4869: if (error)
4870: break;
1.1 reinoud 4871:
1.59 reinoud 4872: /* see if its our entry */
1.136 reinoud 4873: KASSERT(dirent->d_namlen == s_dirent->d_namlen);
4874: if (strncmp(dirent->d_name, s_dirent->d_name, s_dirent->d_namlen) == 0) {
1.59 reinoud 4875: found = 1;
1.45 reinoud 4876: break;
4877: }
4878: }
1.59 reinoud 4879:
4880: if (!found)
4881: error = ENOENT;
4882: if (error)
4883: goto error_out;
1.1 reinoud 4884:
1.45 reinoud 4885: /* mark deleted */
4886: fid->file_char |= UDF_FILE_CHAR_DEL;
4887: #ifdef UDF_COMPLETE_DELETE
4888: memset(&fid->icb, 0, sizeof(fid->icb));
4889: #endif
4890: (void) udf_validate_tag_and_crc_sums((union dscrptr *) fid);
1.1 reinoud 4891:
1.59 reinoud 4892: /* get size of fid and compensate for the read_fid_stream advance */
1.45 reinoud 4893: fidsize = udf_fidsize(fid);
4894: diroffset -= fidsize;
4895:
4896: /* write out */
4897: error = vn_rdwr(UIO_WRITE, dir_node->vnode,
1.152 skrll 4898: fid, fidsize, diroffset,
1.45 reinoud 4899: UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED,
4900: FSCRED, NULL, NULL);
1.59 reinoud 4901: if (error)
4902: goto error_out;
4903:
4904: /* get reference count of attached node */
4905: if (udf_node->fe) {
4906: refcnt = udf_rw16(udf_node->fe->link_cnt);
4907: } else {
4908: KASSERT(udf_node->efe);
4909: refcnt = udf_rw16(udf_node->efe->link_cnt);
4910: }
1.45 reinoud 4911: #ifdef UDF_COMPLETE_DELETE
1.59 reinoud 4912: /* substract reference counter in attached node */
4913: refcnt -= 1;
4914: if (udf_node->fe) {
4915: udf_node->fe->link_cnt = udf_rw16(refcnt);
4916: } else {
4917: udf_node->efe->link_cnt = udf_rw16(refcnt);
4918: }
4919:
4920: /* prevent writeout when refcnt == 0 */
4921: if (refcnt == 0)
4922: udf_node->i_flags |= IN_DELETED;
4923:
4924: if (fid->file_char & UDF_FILE_CHAR_DIR) {
4925: int drefcnt;
4926:
4927: /* substract reference counter in directory node */
4928: /* note subtract 2 (?) for its was also backreferenced */
4929: if (dir_node->fe) {
4930: drefcnt = udf_rw16(dir_node->fe->link_cnt);
4931: drefcnt -= 1;
4932: dir_node->fe->link_cnt = udf_rw16(drefcnt);
1.45 reinoud 4933: } else {
1.59 reinoud 4934: KASSERT(dir_node->efe);
4935: drefcnt = udf_rw16(dir_node->efe->link_cnt);
4936: drefcnt -= 1;
4937: dir_node->efe->link_cnt = udf_rw16(drefcnt);
1.45 reinoud 4938: }
1.59 reinoud 4939: }
1.1 reinoud 4940:
1.59 reinoud 4941: udf_node->i_flags |= IN_MODIFIED;
4942: dir_node->i_flags |= IN_MODIFIED;
1.45 reinoud 4943: #endif
1.59 reinoud 4944: /* if it is/was a hardlink adjust the file count */
4945: if (refcnt > 0)
4946: udf_adjust_filecount(udf_node, -1);
4947:
4948: /* remove from the dirhash */
1.73 reinoud 4949: dirhash_remove(dirh, dirent, diroffset,
1.59 reinoud 4950: udf_fidsize(fid));
1.1 reinoud 4951:
1.59 reinoud 4952: error_out:
1.45 reinoud 4953: free(fid, M_UDFTEMP);
4954: free(dirent, M_UDFTEMP);
1.136 reinoud 4955: free(s_dirent, M_UDFTEMP);
1.1 reinoud 4956:
1.73 reinoud 4957: dirhash_put(dir_node->dir_hash);
1.66 reinoud 4958:
1.45 reinoud 4959: return error;
1.1 reinoud 4960: }
4961:
4962: /* --------------------------------------------------------------------- */
4963:
1.94 reinoud 4964: int
4965: udf_dir_update_rootentry(struct udf_mount *ump, struct udf_node *dir_node,
4966: struct udf_node *new_parent_node)
4967: {
4968: struct vnode *dvp = dir_node->vnode;
4969: struct dirhash *dirh;
4970: struct dirhash_entry *dirh_ep;
4971: struct file_entry *fe;
4972: struct extfile_entry *efe;
4973: struct fileid_desc *fid;
4974: struct dirent *dirent;
1.121 christos 4975: uint64_t diroffset;
1.94 reinoud 4976: uint64_t new_parent_unique_id;
4977: uint32_t lb_size, fidsize;
4978: int found, error;
4979: char const *name = "..";
4980: int namelen = 2;
4981: int hit;
4982:
4983: /* get our dirhash and make sure its read in */
4984: dirhash_get(&dir_node->dir_hash);
1.120 reinoud 4985: error = udf_dirhash_fill(dir_node);
1.94 reinoud 4986: if (error) {
4987: dirhash_put(dir_node->dir_hash);
4988: return error;
4989: }
4990: dirh = dir_node->dir_hash;
4991:
4992: /* get new parent's unique ID */
4993: fe = new_parent_node->fe;
4994: efe = new_parent_node->efe;
4995: if (fe) {
4996: new_parent_unique_id = udf_rw64(fe->unique_id);
4997: } else {
4998: assert(efe);
4999: new_parent_unique_id = udf_rw64(efe->unique_id);
5000: }
5001:
5002: /* get directory filesize */
5003: fe = dir_node->fe;
5004: efe = dir_node->efe;
1.121 christos 5005: if (!fe) {
1.94 reinoud 5006: assert(efe);
5007: }
5008:
5009: /* allocate temporary space for fid */
5010: lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
5011: fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
5012: dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
5013:
5014: /*
5015: * NOTE the standard does not dictate the FID entry '..' should be
5016: * first, though in practice it will most likely be.
5017: */
5018:
5019: /* search our dirhash hits */
5020: found = 0;
5021: dirh_ep = NULL;
5022: for (;;) {
5023: hit = dirhash_lookup(dirh, name, namelen, &dirh_ep);
5024: /* if no hit, abort the search */
5025: if (!hit)
5026: break;
5027:
5028: /* check this hit */
5029: diroffset = dirh_ep->offset;
5030:
5031: /* transfer a new fid/dirent */
5032: error = udf_read_fid_stream(dvp, &diroffset, fid, dirent);
5033: if (error)
5034: break;
5035:
5036: /* see if its our entry */
5037: KASSERT(dirent->d_namlen == namelen);
5038: if (strncmp(dirent->d_name, name, namelen) == 0) {
5039: found = 1;
5040: break;
5041: }
5042: }
5043:
5044: if (!found)
5045: error = ENOENT;
5046: if (error)
5047: goto error_out;
5048:
5049: /* update our ICB to the new parent, hit of lower 32 bits of uniqueid */
5050: fid->icb = new_parent_node->write_loc;
5051: fid->icb.longad_uniqueid = udf_rw32(new_parent_unique_id);
5052:
5053: (void) udf_validate_tag_and_crc_sums((union dscrptr *) fid);
5054:
5055: /* get size of fid and compensate for the read_fid_stream advance */
5056: fidsize = udf_fidsize(fid);
5057: diroffset -= fidsize;
5058:
5059: /* write out */
5060: error = vn_rdwr(UIO_WRITE, dir_node->vnode,
1.152 skrll 5061: fid, fidsize, diroffset,
1.94 reinoud 5062: UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED,
5063: FSCRED, NULL, NULL);
5064:
5065: /* nothing to be done in the dirhash */
5066:
5067: error_out:
5068: free(fid, M_UDFTEMP);
5069: free(dirent, M_UDFTEMP);
5070:
5071: dirhash_put(dir_node->dir_hash);
5072:
5073: return error;
5074: }
5075:
5076: /* --------------------------------------------------------------------- */
5077:
1.45 reinoud 5078: /*
5079: * We are not allowed to split the fid tag itself over an logical block so
5080: * check the space remaining in the logical block.
5081: *
5082: * We try to select the smallest candidate for recycling or when none is
5083: * found, append a new one at the end of the directory.
5084: */
5085:
1.1 reinoud 5086: int
1.45 reinoud 5087: udf_dir_attach(struct udf_mount *ump, struct udf_node *dir_node,
5088: struct udf_node *udf_node, struct vattr *vap, struct componentname *cnp)
1.1 reinoud 5089: {
1.45 reinoud 5090: struct vnode *dvp = dir_node->vnode;
1.73 reinoud 5091: struct dirhash *dirh;
5092: struct dirhash_entry *dirh_ep;
1.45 reinoud 5093: struct fileid_desc *fid;
5094: struct icb_tag *icbtag;
5095: struct charspec osta_charspec;
5096: struct dirent dirent;
1.74 reinoud 5097: uint64_t unique_id, dir_size;
1.45 reinoud 5098: uint64_t fid_pos, end_fid_pos, chosen_fid_pos;
5099: uint32_t chosen_size, chosen_size_diff;
5100: int lb_size, lb_rest, fidsize, this_fidsize, size_diff;
1.59 reinoud 5101: int file_char, refcnt, icbflags, addr_type, hit, error;
1.45 reinoud 5102:
1.66 reinoud 5103: /* get our dirhash and make sure its read in */
1.73 reinoud 5104: dirhash_get(&dir_node->dir_hash);
1.120 reinoud 5105: error = udf_dirhash_fill(dir_node);
1.66 reinoud 5106: if (error) {
1.73 reinoud 5107: dirhash_put(dir_node->dir_hash);
1.66 reinoud 5108: return error;
5109: }
1.73 reinoud 5110: dirh = dir_node->dir_hash;
1.66 reinoud 5111:
5112: /* get info */
1.45 reinoud 5113: lb_size = udf_rw32(ump->logical_vol->lb_size);
5114: udf_osta_charset(&osta_charspec);
5115:
5116: if (dir_node->fe) {
5117: dir_size = udf_rw64(dir_node->fe->inf_len);
1.59 reinoud 5118: icbtag = &dir_node->fe->icbtag;
1.45 reinoud 5119: } else {
5120: dir_size = udf_rw64(dir_node->efe->inf_len);
1.59 reinoud 5121: icbtag = &dir_node->efe->icbtag;
1.45 reinoud 5122: }
1.1 reinoud 5123:
1.45 reinoud 5124: icbflags = udf_rw16(icbtag->flags);
5125: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
1.1 reinoud 5126:
1.45 reinoud 5127: if (udf_node->fe) {
5128: unique_id = udf_rw64(udf_node->fe->unique_id);
1.59 reinoud 5129: refcnt = udf_rw16(udf_node->fe->link_cnt);
1.45 reinoud 5130: } else {
5131: unique_id = udf_rw64(udf_node->efe->unique_id);
1.59 reinoud 5132: refcnt = udf_rw16(udf_node->efe->link_cnt);
1.45 reinoud 5133: }
1.1 reinoud 5134:
1.45 reinoud 5135: if (refcnt > 0) {
5136: unique_id = udf_advance_uniqueid(ump);
5137: udf_adjust_filecount(udf_node, 1);
1.9 christos 5138: }
1.1 reinoud 5139:
1.45 reinoud 5140: /* determine file characteristics */
5141: file_char = 0; /* visible non deleted file and not stream metadata */
5142: if (vap->va_type == VDIR)
5143: file_char = UDF_FILE_CHAR_DIR;
5144:
5145: /* malloc scrap buffer */
1.83 cegger 5146: fid = malloc(lb_size, M_TEMP, M_WAITOK|M_ZERO);
1.45 reinoud 5147:
5148: /* calculate _minimum_ fid size */
5149: unix_to_udf_name((char *) fid->data, &fid->l_fi,
5150: cnp->cn_nameptr, cnp->cn_namelen, &osta_charspec);
5151: fidsize = UDF_FID_SIZE + fid->l_fi;
5152: fidsize = (fidsize + 3) & ~3; /* multiple of 4 */
1.1 reinoud 5153:
1.45 reinoud 5154: /* find position that will fit the FID */
1.59 reinoud 5155: chosen_fid_pos = dir_size;
1.45 reinoud 5156: chosen_size = 0;
5157: chosen_size_diff = UINT_MAX;
1.1 reinoud 5158:
1.59 reinoud 5159: /* shut up gcc */
5160: dirent.d_namlen = 0;
5161:
5162: /* search our dirhash hits */
5163: error = 0;
5164: dirh_ep = NULL;
1.45 reinoud 5165: for (;;) {
1.73 reinoud 5166: hit = dirhash_lookup_freed(dirh, fidsize, &dirh_ep);
1.59 reinoud 5167: /* if no hit, abort the search */
5168: if (!hit)
1.45 reinoud 5169: break;
1.1 reinoud 5170:
1.59 reinoud 5171: /* check this hit for size */
1.73 reinoud 5172: this_fidsize = dirh_ep->entry_size;
1.1 reinoud 5173:
1.59 reinoud 5174: /* check this hit */
5175: fid_pos = dirh_ep->offset;
5176: end_fid_pos = fid_pos + this_fidsize;
5177: size_diff = this_fidsize - fidsize;
5178: lb_rest = lb_size - (end_fid_pos % lb_size);
1.45 reinoud 5179:
5180: #ifndef UDF_COMPLETE_DELETE
1.59 reinoud 5181: /* transfer a new fid/dirent */
5182: error = udf_read_fid_stream(vp, &fid_pos, fid, dirent);
5183: if (error)
5184: goto error_out;
5185:
5186: /* only reuse entries that are wiped */
5187: /* check if the len + loc are marked zero */
1.88 reinoud 5188: if (udf_rw32(fid->icb.len) != 0)
1.59 reinoud 5189: continue;
5190: if (udf_rw32(fid->icb.loc.lb_num) != 0)
5191: continue;
1.88 reinoud 5192: if (udf_rw16(fid->icb.loc.part_num) != 0)
1.59 reinoud 5193: continue;
5194: #endif /* UDF_COMPLETE_DELETE */
5195:
5196: /* select if not splitting the tag and its smaller */
5197: if ((size_diff >= 0) &&
5198: (size_diff < chosen_size_diff) &&
5199: (lb_rest >= sizeof(struct desc_tag)))
5200: {
5201: /* UDF 2.3.4.2+3 specifies rules for iu size */
5202: if ((size_diff == 0) || (size_diff >= 32)) {
5203: chosen_fid_pos = fid_pos;
5204: chosen_size = this_fidsize;
5205: chosen_size_diff = size_diff;
1.45 reinoud 5206: }
5207: }
1.59 reinoud 5208: }
1.1 reinoud 5209:
5210:
1.45 reinoud 5211: /* extend directory if no other candidate found */
5212: if (chosen_size == 0) {
5213: chosen_fid_pos = dir_size;
5214: chosen_size = fidsize;
5215: chosen_size_diff = 0;
1.1 reinoud 5216:
1.45 reinoud 5217: /* special case UDF 2.00+ 2.3.4.4, no splitting up fid tag */
5218: if (addr_type == UDF_ICB_INTERN_ALLOC) {
5219: /* pre-grow directory to see if we're to switch */
5220: udf_grow_node(dir_node, dir_size + chosen_size);
1.1 reinoud 5221:
1.45 reinoud 5222: icbflags = udf_rw16(icbtag->flags);
5223: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
5224: }
1.1 reinoud 5225:
1.156 andvar 5226: /* make sure the next fid desc_tag won't be split */
1.45 reinoud 5227: if (addr_type != UDF_ICB_INTERN_ALLOC) {
5228: end_fid_pos = chosen_fid_pos + chosen_size;
5229: lb_rest = lb_size - (end_fid_pos % lb_size);
1.1 reinoud 5230:
1.45 reinoud 5231: /* pad with implementation use regid if needed */
5232: if (lb_rest < sizeof(struct desc_tag))
5233: chosen_size += 32;
5234: }
1.1 reinoud 5235: }
1.45 reinoud 5236: chosen_size_diff = chosen_size - fidsize;
5237:
5238: /* populate the FID */
5239: memset(fid, 0, lb_size);
5240: udf_inittag(ump, &fid->tag, TAGID_FID, 0);
5241: fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */
5242: fid->file_char = file_char;
5243: fid->icb = udf_node->loc;
5244: fid->icb.longad_uniqueid = udf_rw32((uint32_t) unique_id);
5245: fid->l_iu = udf_rw16(0);
5246:
5247: if (chosen_size > fidsize) {
5248: /* insert implementation-use regid to space it correctly */
5249: fid->l_iu = udf_rw16(chosen_size_diff);
5250:
5251: /* set implementation use */
5252: udf_set_regid((struct regid *) fid->data, IMPL_NAME);
5253: udf_add_impl_regid(ump, (struct regid *) fid->data);
5254: }
5255:
5256: /* fill in name */
5257: unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu),
5258: &fid->l_fi, cnp->cn_nameptr, cnp->cn_namelen, &osta_charspec);
5259:
1.88 reinoud 5260: fid->tag.desc_crc_len = udf_rw16(chosen_size - UDF_DESC_TAG_LENGTH);
1.45 reinoud 5261: (void) udf_validate_tag_and_crc_sums((union dscrptr *) fid);
5262:
5263: /* writeout FID/update parent directory */
5264: error = vn_rdwr(UIO_WRITE, dvp,
1.152 skrll 5265: fid, chosen_size, chosen_fid_pos,
1.45 reinoud 5266: UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED,
5267: FSCRED, NULL, NULL);
5268:
1.59 reinoud 5269: if (error)
5270: goto error_out;
1.45 reinoud 5271:
5272: /* add reference counter in attached node */
5273: if (udf_node->fe) {
5274: refcnt = udf_rw16(udf_node->fe->link_cnt);
5275: udf_node->fe->link_cnt = udf_rw16(refcnt+1);
5276: } else {
5277: KASSERT(udf_node->efe);
5278: refcnt = udf_rw16(udf_node->efe->link_cnt);
5279: udf_node->efe->link_cnt = udf_rw16(refcnt+1);
5280: }
5281:
5282: /* mark not deleted if it was... just in case, but do warn */
5283: if (udf_node->i_flags & IN_DELETED) {
5284: printf("udf: warning, marking a file undeleted\n");
5285: udf_node->i_flags &= ~IN_DELETED;
5286: }
5287:
5288: if (file_char & UDF_FILE_CHAR_DIR) {
5289: /* add reference counter in directory node for '..' */
5290: if (dir_node->fe) {
5291: refcnt = udf_rw16(dir_node->fe->link_cnt);
5292: refcnt++;
5293: dir_node->fe->link_cnt = udf_rw16(refcnt);
5294: } else {
5295: KASSERT(dir_node->efe);
5296: refcnt = udf_rw16(dir_node->efe->link_cnt);
5297: refcnt++;
5298: dir_node->efe->link_cnt = udf_rw16(refcnt);
5299: }
1.1 reinoud 5300: }
5301:
1.59 reinoud 5302: /* append to the dirhash */
1.110 reinoud 5303: /* NOTE do not use dirent anymore or it won't match later! */
1.117 christos 5304: udf_to_unix_name(dirent.d_name, NAME_MAX,
1.110 reinoud 5305: (char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi, &osta_charspec);
5306: dirent.d_namlen = strlen(dirent.d_name);
1.73 reinoud 5307: dirhash_enter(dirh, &dirent, chosen_fid_pos,
1.59 reinoud 5308: udf_fidsize(fid), 1);
1.45 reinoud 5309:
1.59 reinoud 5310: /* note updates */
1.45 reinoud 5311: udf_node->i_flags |= IN_CHANGE | IN_MODIFY; /* | IN_CREATE? */
5312: /* VN_KNOTE(udf_node, ...) */
1.50 reinoud 5313: udf_update(udf_node->vnode, NULL, NULL, NULL, 0);
1.45 reinoud 5314:
1.59 reinoud 5315: error_out:
1.45 reinoud 5316: free(fid, M_TEMP);
1.1 reinoud 5317:
1.73 reinoud 5318: dirhash_put(dir_node->dir_hash);
1.66 reinoud 5319:
1.59 reinoud 5320: return error;
1.45 reinoud 5321: }
1.1 reinoud 5322:
5323: /* --------------------------------------------------------------------- */
5324:
5325: /*
1.45 reinoud 5326: * Each node can have an attached streamdir node though not recursively. These
5327: * are otherwise known as named substreams/named extended attributes that have
5328: * no size limitations.
1.1 reinoud 5329: *
5330: * `Normal' extended attributes are indicated with a number and are recorded
5331: * in either the fe/efe descriptor itself for small descriptors or recorded in
1.45 reinoud 5332: * the attached extended attribute file. Since these spaces can get
5333: * fragmented, care ought to be taken.
5334: *
5335: * Since the size of the space reserved for allocation descriptors is limited,
5336: * there is a mechanim provided for extending this space; this is done by a
5337: * special extent to allow schrinking of the allocations without breaking the
5338: * linkage to the allocation extent descriptor.
1.1 reinoud 5339: */
5340:
5341: int
1.129 hannken 5342: udf_loadvnode(struct mount *mp, struct vnode *vp,
5343: const void *key, size_t key_len, const void **new_key)
1.1 reinoud 5344: {
1.45 reinoud 5345: union dscrptr *dscr;
1.129 hannken 5346: struct udf_mount *ump;
1.45 reinoud 5347: struct udf_node *udf_node;
1.129 hannken 5348: struct long_ad node_icb_loc, icb_loc, next_icb_loc, last_fe_icb_loc;
1.1 reinoud 5349: uint64_t file_size;
5350: uint32_t lb_size, sector, dummy;
5351: int udf_file_type, dscr_type, strat, strat4096, needs_indirect;
1.45 reinoud 5352: int slot, eof, error;
1.126 reinoud 5353: int num_indir_followed = 0;
1.1 reinoud 5354:
1.129 hannken 5355: DPRINTF(NODE, ("udf_loadvnode called\n"));
5356: udf_node = NULL;
5357: ump = VFSTOUDF(mp);
5358:
5359: KASSERT(key_len == sizeof(node_icb_loc.loc));
5360: memset(&node_icb_loc, 0, sizeof(node_icb_loc));
5361: node_icb_loc.len = ump->logical_vol->lb_size;
5362: memcpy(&node_icb_loc.loc, key, key_len);
1.1 reinoud 5363:
1.45 reinoud 5364: /* garbage check: translate udf_node_icb_loc to sectornr */
1.129 hannken 5365: error = udf_translate_vtop(ump, &node_icb_loc, §or, &dummy);
1.1 reinoud 5366: if (error) {
1.111 reinoud 5367: DPRINTF(NODE, ("\tcan't translate icb address!\n"));
1.1 reinoud 5368: /* no use, this will fail anyway */
5369: return EINVAL;
1.9 christos 5370: }
1.1 reinoud 5371:
1.45 reinoud 5372: /* build udf_node (do initialise!) */
5373: udf_node = pool_get(&udf_node_pool, PR_WAITOK);
5374: memset(udf_node, 0, sizeof(struct udf_node));
1.1 reinoud 5375:
1.129 hannken 5376: vp->v_tag = VT_UDF;
5377: vp->v_op = udf_vnodeop_p;
5378: vp->v_data = udf_node;
1.1 reinoud 5379:
5380: /* initialise crosslinks, note location of fe/efe for hashing */
1.45 reinoud 5381: udf_node->ump = ump;
1.129 hannken 5382: udf_node->vnode = vp;
5383: udf_node->loc = node_icb_loc;
1.45 reinoud 5384: udf_node->lockf = 0;
5385: mutex_init(&udf_node->node_mutex, MUTEX_DEFAULT, IPL_NONE);
5386: cv_init(&udf_node->node_lock, "udf_nlk");
1.129 hannken 5387: genfs_node_init(vp, &udf_genfsops); /* inititise genfs */
1.45 reinoud 5388: udf_node->outstanding_bufs = 0;
5389: udf_node->outstanding_nodedscr = 0;
1.95 reinoud 5390: udf_node->uncommitted_lbs = 0;
1.1 reinoud 5391:
1.81 reinoud 5392: /* check if we're fetching the root */
5393: if (ump->fileset_desc)
5394: if (memcmp(&udf_node->loc, &ump->fileset_desc->rootdir_icb,
5395: sizeof(struct long_ad)) == 0)
1.129 hannken 5396: vp->v_vflag |= VV_ROOT;
1.79 reinoud 5397:
1.129 hannken 5398: icb_loc = node_icb_loc;
1.1 reinoud 5399: needs_indirect = 0;
5400: strat4096 = 0;
5401: udf_file_type = UDF_ICB_FILETYPE_UNKNOWN;
5402: file_size = 0;
5403: lb_size = udf_rw32(ump->logical_vol->lb_size);
5404:
1.45 reinoud 5405: DPRINTF(NODE, ("\tstart reading descriptors\n"));
1.1 reinoud 5406: do {
5407: /* try to read in fe/efe */
1.45 reinoud 5408: error = udf_read_logvol_dscr(ump, &icb_loc, &dscr);
1.1 reinoud 5409:
5410: /* blank sector marks end of sequence, check this */
1.45 reinoud 5411: if ((dscr == NULL) && (!strat4096))
1.1 reinoud 5412: error = ENOENT;
5413:
5414: /* break if read error or blank sector */
1.45 reinoud 5415: if (error || (dscr == NULL))
1.1 reinoud 5416: break;
5417:
5418: /* process descriptor based on the descriptor type */
1.45 reinoud 5419: dscr_type = udf_rw16(dscr->tag.id);
5420: DPRINTF(NODE, ("\tread descriptor %d\n", dscr_type));
1.1 reinoud 5421:
5422: /* if dealing with an indirect entry, follow the link */
1.45 reinoud 5423: if (dscr_type == TAGID_INDIRECTENTRY) {
1.1 reinoud 5424: needs_indirect = 0;
1.127 reinoud 5425: next_icb_loc = dscr->inde.indirect_icb;
1.45 reinoud 5426: udf_free_logvol_dscr(ump, &icb_loc, dscr);
1.127 reinoud 5427: icb_loc = next_icb_loc;
1.126 reinoud 5428: if (++num_indir_followed > UDF_MAX_INDIRS_FOLLOW) {
5429: error = EMLINK;
5430: break;
5431: }
1.1 reinoud 5432: continue;
1.9 christos 5433: }
1.1 reinoud 5434:
5435: /* only file entries and extended file entries allowed here */
5436: if ((dscr_type != TAGID_FENTRY) &&
5437: (dscr_type != TAGID_EXTFENTRY)) {
1.45 reinoud 5438: udf_free_logvol_dscr(ump, &icb_loc, dscr);
1.1 reinoud 5439: error = ENOENT;
5440: break;
1.9 christos 5441: }
1.1 reinoud 5442:
1.45 reinoud 5443: KASSERT(udf_tagsize(dscr, lb_size) == lb_size);
1.1 reinoud 5444:
1.45 reinoud 5445: /* choose this one */
5446: last_fe_icb_loc = icb_loc;
1.152 skrll 5447:
1.1 reinoud 5448: /* record and process/update (ext)fentry */
5449: if (dscr_type == TAGID_FENTRY) {
1.45 reinoud 5450: if (udf_node->fe)
5451: udf_free_logvol_dscr(ump, &last_fe_icb_loc,
5452: udf_node->fe);
5453: udf_node->fe = &dscr->fe;
5454: strat = udf_rw16(udf_node->fe->icbtag.strat_type);
5455: udf_file_type = udf_node->fe->icbtag.file_type;
5456: file_size = udf_rw64(udf_node->fe->inf_len);
1.1 reinoud 5457: } else {
1.45 reinoud 5458: if (udf_node->efe)
5459: udf_free_logvol_dscr(ump, &last_fe_icb_loc,
5460: udf_node->efe);
5461: udf_node->efe = &dscr->efe;
5462: strat = udf_rw16(udf_node->efe->icbtag.strat_type);
5463: udf_file_type = udf_node->efe->icbtag.file_type;
5464: file_size = udf_rw64(udf_node->efe->inf_len);
1.9 christos 5465: }
1.1 reinoud 5466:
5467: /* check recording strategy (structure) */
5468:
5469: /*
5470: * Strategy 4096 is a daisy linked chain terminating with an
5471: * unrecorded sector or a TERM descriptor. The next
5472: * descriptor is to be found in the sector that follows the
5473: * current sector.
5474: */
5475: if (strat == 4096) {
5476: strat4096 = 1;
5477: needs_indirect = 1;
5478:
5479: icb_loc.loc.lb_num = udf_rw32(icb_loc.loc.lb_num) + 1;
1.9 christos 5480: }
1.1 reinoud 5481:
5482: /*
5483: * Strategy 4 is the normal strategy and terminates, but if
5484: * we're in strategy 4096, we can't have strategy 4 mixed in
5485: */
5486:
5487: if (strat == 4) {
5488: if (strat4096) {
5489: error = EINVAL;
5490: break;
1.9 christos 5491: }
1.1 reinoud 5492: break; /* done */
1.9 christos 5493: }
1.1 reinoud 5494: } while (!error);
5495:
1.45 reinoud 5496: /* first round of cleanup code */
1.1 reinoud 5497: if (error) {
1.45 reinoud 5498: DPRINTF(NODE, ("\tnode fe/efe failed!\n"));
1.1 reinoud 5499: /* recycle udf_node */
1.45 reinoud 5500: udf_dispose_node(udf_node);
1.1 reinoud 5501:
5502: return EINVAL; /* error code ok? */
1.9 christos 5503: }
1.45 reinoud 5504: DPRINTF(NODE, ("\tnode fe/efe read in fine\n"));
1.1 reinoud 5505:
5506: /* assert no references to dscr anymore beyong this point */
1.45 reinoud 5507: assert((udf_node->fe) || (udf_node->efe));
1.1 reinoud 5508: dscr = NULL;
5509:
5510: /*
1.45 reinoud 5511: * Remember where to record an updated version of the descriptor. If
1.1 reinoud 5512: * there is a sequence of indirect entries, icb_loc will have been
5513: * updated. Its the write disipline to allocate new space and to make
5514: * sure the chain is maintained.
5515: *
5516: * `needs_indirect' flags if the next location is to be filled with
1.164 andvar 5517: * an indirect entry.
1.1 reinoud 5518: */
1.45 reinoud 5519: udf_node->write_loc = icb_loc;
5520: udf_node->needs_indirect = needs_indirect;
5521:
5522: /*
5523: * Go trough all allocations extents of this descriptor and when
5524: * encountering a redirect read in the allocation extension. These are
5525: * daisy-chained.
5526: */
5527: UDF_LOCK_NODE(udf_node, 0);
5528: udf_node->num_extensions = 0;
5529:
5530: error = 0;
5531: slot = 0;
5532: for (;;) {
5533: udf_get_adslot(udf_node, slot, &icb_loc, &eof);
1.52 reinoud 5534: DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, "
5535: "lb_num = %d, part = %d\n", slot, eof,
5536: UDF_EXT_FLAGS(udf_rw32(icb_loc.len)),
5537: UDF_EXT_LEN(udf_rw32(icb_loc.len)),
5538: udf_rw32(icb_loc.loc.lb_num),
5539: udf_rw16(icb_loc.loc.part_num)));
1.45 reinoud 5540: if (eof)
5541: break;
1.52 reinoud 5542: slot++;
1.45 reinoud 5543:
1.52 reinoud 5544: if (UDF_EXT_FLAGS(udf_rw32(icb_loc.len)) != UDF_EXT_REDIRECT)
1.45 reinoud 5545: continue;
5546:
5547: DPRINTF(NODE, ("\tgot redirect extent\n"));
5548: if (udf_node->num_extensions >= UDF_MAX_ALLOC_EXTENTS) {
5549: DPRINTF(ALLOC, ("udf_get_node: implementation limit, "
5550: "too many allocation extensions on "
5551: "udf_node\n"));
5552: error = EINVAL;
5553: break;
5554: }
5555:
5556: /* length can only be *one* lb : UDF 2.50/2.3.7.1 */
1.52 reinoud 5557: if (UDF_EXT_LEN(udf_rw32(icb_loc.len)) != lb_size) {
1.45 reinoud 5558: DPRINTF(ALLOC, ("udf_get_node: bad allocation "
5559: "extension size in udf_node\n"));
5560: error = EINVAL;
5561: break;
5562: }
5563:
1.52 reinoud 5564: DPRINTF(NODE, ("read allocation extent at lb_num %d\n",
5565: UDF_EXT_LEN(udf_rw32(icb_loc.loc.lb_num))));
1.45 reinoud 5566: /* load in allocation extent */
5567: error = udf_read_logvol_dscr(ump, &icb_loc, &dscr);
5568: if (error || (dscr == NULL))
5569: break;
5570:
5571: /* process read-in descriptor */
5572: dscr_type = udf_rw16(dscr->tag.id);
5573:
5574: if (dscr_type != TAGID_ALLOCEXTENT) {
5575: udf_free_logvol_dscr(ump, &icb_loc, dscr);
5576: error = ENOENT;
5577: break;
5578: }
5579:
5580: DPRINTF(NODE, ("\trecording redirect extent\n"));
5581: udf_node->ext[udf_node->num_extensions] = &dscr->aee;
5582: udf_node->ext_loc[udf_node->num_extensions] = icb_loc;
5583:
5584: udf_node->num_extensions++;
5585:
5586: } /* while */
5587: UDF_UNLOCK_NODE(udf_node, 0);
5588:
5589: /* second round of cleanup code */
5590: if (error) {
5591: /* recycle udf_node */
5592: udf_dispose_node(udf_node);
5593:
5594: return EINVAL; /* error code ok? */
5595: }
5596:
5597: DPRINTF(NODE, ("\tnode read in fine\n"));
1.1 reinoud 5598:
5599: /*
5600: * Translate UDF filetypes into vnode types.
5601: *
5602: * Systemfiles like the meta main and mirror files are not treated as
5603: * normal files, so we type them as having no type. UDF dictates that
5604: * they are not allowed to be visible.
5605: */
5606:
1.45 reinoud 5607: switch (udf_file_type) {
5608: case UDF_ICB_FILETYPE_DIRECTORY :
5609: case UDF_ICB_FILETYPE_STREAMDIR :
1.129 hannken 5610: vp->v_type = VDIR;
1.45 reinoud 5611: break;
5612: case UDF_ICB_FILETYPE_BLOCKDEVICE :
1.129 hannken 5613: vp->v_type = VBLK;
1.45 reinoud 5614: break;
5615: case UDF_ICB_FILETYPE_CHARDEVICE :
1.129 hannken 5616: vp->v_type = VCHR;
1.45 reinoud 5617: break;
5618: case UDF_ICB_FILETYPE_SOCKET :
1.129 hannken 5619: vp->v_type = VSOCK;
1.45 reinoud 5620: break;
5621: case UDF_ICB_FILETYPE_FIFO :
1.129 hannken 5622: vp->v_type = VFIFO;
1.45 reinoud 5623: break;
5624: case UDF_ICB_FILETYPE_SYMLINK :
1.129 hannken 5625: vp->v_type = VLNK;
1.45 reinoud 5626: break;
5627: case UDF_ICB_FILETYPE_VAT :
5628: case UDF_ICB_FILETYPE_META_MAIN :
5629: case UDF_ICB_FILETYPE_META_MIRROR :
1.129 hannken 5630: vp->v_type = VNON;
1.45 reinoud 5631: break;
5632: case UDF_ICB_FILETYPE_RANDOMACCESS :
5633: case UDF_ICB_FILETYPE_REALTIME :
1.129 hannken 5634: vp->v_type = VREG;
1.45 reinoud 5635: break;
5636: default:
5637: /* YIKES, something else */
1.129 hannken 5638: vp->v_type = VNON;
1.45 reinoud 5639: }
5640:
1.1 reinoud 5641: /* TODO specfs, fifofs etc etc. vnops setting */
1.45 reinoud 5642:
5643: /* don't forget to set vnode's v_size */
1.129 hannken 5644: uvm_vnp_setsize(vp, file_size);
1.45 reinoud 5645:
5646: /* TODO ext attr and streamdir udf_nodes */
5647:
1.129 hannken 5648: *new_key = &udf_node->loc.loc;
1.45 reinoud 5649:
5650: return 0;
5651: }
5652:
1.129 hannken 5653: int
5654: udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc,
1.148 ad 5655: struct udf_node **udf_noderes, int lktype)
1.129 hannken 5656: {
5657: int error;
5658: struct vnode *vp;
5659:
1.137 reinoud 5660: *udf_noderes = NULL;
5661:
1.129 hannken 5662: error = vcache_get(ump->vfs_mountp, &node_icb_loc->loc,
5663: sizeof(node_icb_loc->loc), &vp);
5664: if (error)
5665: return error;
1.150 hannken 5666: error = vn_lock(vp, lktype);
1.129 hannken 5667: if (error) {
5668: vrele(vp);
5669: return error;
5670: }
5671: *udf_noderes = VTOI(vp);
5672: return 0;
5673: }
5674:
1.45 reinoud 5675: /* --------------------------------------------------------------------- */
5676:
5677: int
5678: udf_writeout_node(struct udf_node *udf_node, int waitfor)
5679: {
5680: union dscrptr *dscr;
5681: struct long_ad *loc;
1.91 reinoud 5682: int extnr, error;
1.45 reinoud 5683:
5684: DPRINTF(NODE, ("udf_writeout_node called\n"));
5685:
5686: KASSERT(udf_node->outstanding_bufs == 0);
5687: KASSERT(udf_node->outstanding_nodedscr == 0);
5688:
5689: KASSERT(LIST_EMPTY(&udf_node->vnode->v_dirtyblkhd));
5690:
5691: if (udf_node->i_flags & IN_DELETED) {
5692: DPRINTF(NODE, ("\tnode deleted; not writing out\n"));
1.95 reinoud 5693: udf_cleanup_reservation(udf_node);
1.45 reinoud 5694: return 0;
5695: }
5696:
1.93 reinoud 5697: /* lock node; unlocked in callback */
1.91 reinoud 5698: UDF_LOCK_NODE(udf_node, 0);
1.55 reinoud 5699:
1.95 reinoud 5700: /* remove pending reservations, we're written out */
5701: udf_cleanup_reservation(udf_node);
5702:
1.55 reinoud 5703: /* at least one descriptor writeout */
5704: udf_node->outstanding_nodedscr = 1;
5705:
1.45 reinoud 5706: /* we're going to write out the descriptor so clear the flags */
5707: udf_node->i_flags &= ~(IN_MODIFIED | IN_ACCESSED);
5708:
1.55 reinoud 5709: /* if we were rebuild, write out the allocation extents */
5710: if (udf_node->i_flags & IN_NODE_REBUILD) {
1.71 reinoud 5711: /* mark outstanding node descriptors and issue them */
1.55 reinoud 5712: udf_node->outstanding_nodedscr += udf_node->num_extensions;
5713: for (extnr = 0; extnr < udf_node->num_extensions; extnr++) {
5714: loc = &udf_node->ext_loc[extnr];
5715: dscr = (union dscrptr *) udf_node->ext[extnr];
5716: error = udf_write_logvol_dscr(udf_node, dscr, loc, 0);
5717: if (error)
5718: return error;
5719: }
5720: /* mark allocation extents written out */
5721: udf_node->i_flags &= ~(IN_NODE_REBUILD);
5722: }
5723:
1.45 reinoud 5724: if (udf_node->fe) {
1.71 reinoud 5725: KASSERT(udf_node->efe == NULL);
1.45 reinoud 5726: dscr = (union dscrptr *) udf_node->fe;
5727: } else {
5728: KASSERT(udf_node->efe);
1.71 reinoud 5729: KASSERT(udf_node->fe == NULL);
1.45 reinoud 5730: dscr = (union dscrptr *) udf_node->efe;
5731: }
5732: KASSERT(dscr);
5733:
5734: loc = &udf_node->write_loc;
5735: error = udf_write_logvol_dscr(udf_node, dscr, loc, waitfor);
1.95 reinoud 5736:
1.45 reinoud 5737: return error;
5738: }
5739:
5740: /* --------------------------------------------------------------------- */
5741:
5742: int
5743: udf_dispose_node(struct udf_node *udf_node)
5744: {
5745: struct vnode *vp;
1.52 reinoud 5746: int extnr;
1.45 reinoud 5747:
5748: DPRINTF(NODE, ("udf_dispose_node called on node %p\n", udf_node));
5749: if (!udf_node) {
5750: DPRINTF(NODE, ("UDF: Dispose node on node NULL, ignoring\n"));
5751: return 0;
5752: }
5753:
5754: vp = udf_node->vnode;
5755: #ifdef DIAGNOSTIC
5756: if (vp->v_numoutput)
5757: panic("disposing UDF node with pending I/O's, udf_node = %p, "
5758: "v_numoutput = %d", udf_node, vp->v_numoutput);
5759: #endif
5760:
1.95 reinoud 5761: udf_cleanup_reservation(udf_node);
1.45 reinoud 5762:
5763: /* TODO extended attributes and streamdir */
5764:
1.59 reinoud 5765: /* remove dirhash if present */
1.73 reinoud 5766: dirhash_purge(&udf_node->dir_hash);
1.59 reinoud 5767:
1.45 reinoud 5768: /* destroy our lock */
5769: mutex_destroy(&udf_node->node_mutex);
5770: cv_destroy(&udf_node->node_lock);
5771:
5772: /* dissociate our udf_node from the vnode */
5773: genfs_node_destroy(udf_node->vnode);
1.132 hannken 5774: mutex_enter(vp->v_interlock);
1.45 reinoud 5775: vp->v_data = NULL;
1.132 hannken 5776: mutex_exit(vp->v_interlock);
1.45 reinoud 5777:
5778: /* free associated memory and the node itself */
1.52 reinoud 5779: for (extnr = 0; extnr < udf_node->num_extensions; extnr++) {
5780: udf_free_logvol_dscr(udf_node->ump, &udf_node->ext_loc[extnr],
5781: udf_node->ext[extnr]);
5782: udf_node->ext[extnr] = (void *) 0xdeadcccc;
5783: }
5784:
1.45 reinoud 5785: if (udf_node->fe)
1.52 reinoud 5786: udf_free_logvol_dscr(udf_node->ump, &udf_node->loc,
5787: udf_node->fe);
1.45 reinoud 5788: if (udf_node->efe)
1.52 reinoud 5789: udf_free_logvol_dscr(udf_node->ump, &udf_node->loc,
5790: udf_node->efe);
1.45 reinoud 5791:
5792: udf_node->fe = (void *) 0xdeadaaaa;
5793: udf_node->efe = (void *) 0xdeadbbbb;
5794: udf_node->ump = (void *) 0xdeadbeef;
5795: pool_put(&udf_node_pool, udf_node);
5796:
5797: return 0;
5798: }
5799:
5800:
5801:
5802: /*
1.129 hannken 5803: * create a new node using the specified dvp, vap and cnp.
5804: * This allows special files to be created. Use with care.
1.45 reinoud 5805: */
5806:
1.129 hannken 5807: int
5808: udf_newvnode(struct mount *mp, struct vnode *dvp, struct vnode *vp,
1.145 hannken 5809: struct vattr *vap, kauth_cred_t cred, void *extra,
1.129 hannken 5810: size_t *key_len, const void **new_key)
1.45 reinoud 5811: {
5812: union dscrptr *dscr;
1.101 mbalmer 5813: struct udf_node *dir_node = VTOI(dvp);
1.45 reinoud 5814: struct udf_node *udf_node;
5815: struct udf_mount *ump = dir_node->ump;
5816: struct long_ad node_icb_loc;
5817: uint64_t parent_unique_id;
1.70 reinoud 5818: uint64_t lmapping;
1.45 reinoud 5819: uint32_t lb_size, lb_num;
5820: uint16_t vpart_num;
1.56 reinoud 5821: uid_t uid;
5822: gid_t gid, parent_gid;
1.129 hannken 5823: int (**vnodeops)(void *);
5824: int udf_file_type, fid_size, error;
5825:
5826: vnodeops = udf_vnodeop_p;
5827: udf_file_type = UDF_ICB_FILETYPE_RANDOMACCESS;
5828:
5829: switch (vap->va_type) {
5830: case VREG :
5831: udf_file_type = UDF_ICB_FILETYPE_RANDOMACCESS;
5832: break;
5833: case VDIR :
5834: udf_file_type = UDF_ICB_FILETYPE_DIRECTORY;
5835: break;
5836: case VLNK :
5837: udf_file_type = UDF_ICB_FILETYPE_SYMLINK;
5838: break;
5839: case VBLK :
5840: udf_file_type = UDF_ICB_FILETYPE_BLOCKDEVICE;
5841: /* specfs */
5842: return ENOTSUP;
5843: break;
5844: case VCHR :
5845: udf_file_type = UDF_ICB_FILETYPE_CHARDEVICE;
5846: /* specfs */
5847: return ENOTSUP;
5848: break;
5849: case VFIFO :
5850: udf_file_type = UDF_ICB_FILETYPE_FIFO;
5851: /* fifofs */
5852: return ENOTSUP;
5853: break;
5854: case VSOCK :
5855: udf_file_type = UDF_ICB_FILETYPE_SOCKET;
5856: return ENOTSUP;
5857: break;
5858: case VNON :
5859: case VBAD :
5860: default :
5861: /* nothing; can we even create these? */
5862: return EINVAL;
5863: }
1.45 reinoud 5864:
5865: lb_size = udf_rw32(ump->logical_vol->lb_size);
5866:
1.95 reinoud 5867: /* reserve space for one logical block */
1.71 reinoud 5868: vpart_num = ump->node_part;
1.95 reinoud 5869: error = udf_reserve_space(ump, NULL, UDF_C_NODE,
5870: vpart_num, 1, /* can_fail */ true);
5871: if (error)
1.129 hannken 5872: return error;
1.95 reinoud 5873:
5874: /* allocate node */
5875: error = udf_allocate_space(ump, NULL, UDF_C_NODE,
5876: vpart_num, 1, &lmapping);
1.129 hannken 5877: if (error) {
5878: udf_do_unreserve_space(ump, NULL, vpart_num, 1);
5879: return error;
5880: }
5881:
1.45 reinoud 5882: lb_num = lmapping;
1.1 reinoud 5883:
1.45 reinoud 5884: /* initialise pointer to location */
5885: memset(&node_icb_loc, 0, sizeof(struct long_ad));
1.89 reinoud 5886: node_icb_loc.len = udf_rw32(lb_size);
1.45 reinoud 5887: node_icb_loc.loc.lb_num = udf_rw32(lb_num);
5888: node_icb_loc.loc.part_num = udf_rw16(vpart_num);
5889:
5890: /* build udf_node (do initialise!) */
5891: udf_node = pool_get(&udf_node_pool, PR_WAITOK);
5892: memset(udf_node, 0, sizeof(struct udf_node));
5893:
5894: /* initialise crosslinks, note location of fe/efe for hashing */
5895: /* bugalert: synchronise with udf_get_node() */
5896: udf_node->ump = ump;
1.129 hannken 5897: udf_node->vnode = vp;
5898: vp->v_data = udf_node;
1.45 reinoud 5899: udf_node->loc = node_icb_loc;
5900: udf_node->write_loc = node_icb_loc;
5901: udf_node->lockf = 0;
5902: mutex_init(&udf_node->node_mutex, MUTEX_DEFAULT, IPL_NONE);
5903: cv_init(&udf_node->node_lock, "udf_nlk");
5904: udf_node->outstanding_bufs = 0;
5905: udf_node->outstanding_nodedscr = 0;
1.95 reinoud 5906: udf_node->uncommitted_lbs = 0;
1.45 reinoud 5907:
1.129 hannken 5908: vp->v_tag = VT_UDF;
5909: vp->v_op = vnodeops;
5910:
1.1 reinoud 5911: /* initialise genfs */
1.129 hannken 5912: genfs_node_init(vp, &udf_genfsops);
1.1 reinoud 5913:
1.45 reinoud 5914: /* get parent's unique ID for refering '..' if its a directory */
5915: if (dir_node->fe) {
5916: parent_unique_id = udf_rw64(dir_node->fe->unique_id);
1.56 reinoud 5917: parent_gid = (gid_t) udf_rw32(dir_node->fe->gid);
1.45 reinoud 5918: } else {
5919: parent_unique_id = udf_rw64(dir_node->efe->unique_id);
1.56 reinoud 5920: parent_gid = (gid_t) udf_rw32(dir_node->efe->gid);
1.45 reinoud 5921: }
1.1 reinoud 5922:
1.45 reinoud 5923: /* get descriptor */
5924: udf_create_logvol_dscr(ump, udf_node, &node_icb_loc, &dscr);
1.1 reinoud 5925:
1.45 reinoud 5926: /* choose a fe or an efe for it */
1.90 reinoud 5927: if (udf_rw16(ump->logical_vol->tag.descriptor_ver) == 2) {
1.45 reinoud 5928: udf_node->fe = &dscr->fe;
5929: fid_size = udf_create_new_fe(ump, udf_node->fe,
5930: udf_file_type, &udf_node->loc,
5931: &dir_node->loc, parent_unique_id);
5932: /* TODO add extended attribute for creation time */
5933: } else {
5934: udf_node->efe = &dscr->efe;
5935: fid_size = udf_create_new_efe(ump, udf_node->efe,
5936: udf_file_type, &udf_node->loc,
5937: &dir_node->loc, parent_unique_id);
5938: }
5939: KASSERT(dscr->tag.tag_loc == udf_node->loc.loc.lb_num);
1.1 reinoud 5940:
1.45 reinoud 5941: /* update vnode's size and type */
1.129 hannken 5942: vp->v_type = vap->va_type;
5943: uvm_vnp_setsize(vp, fid_size);
1.1 reinoud 5944:
1.45 reinoud 5945: /* set access mode */
5946: udf_setaccessmode(udf_node, vap->va_mode);
1.1 reinoud 5947:
1.45 reinoud 5948: /* set ownership */
1.129 hannken 5949: uid = kauth_cred_geteuid(cred);
1.56 reinoud 5950: gid = parent_gid;
5951: udf_setownership(udf_node, uid, gid);
1.1 reinoud 5952:
1.141 maya 5953: *key_len = sizeof(udf_node->loc.loc);
1.129 hannken 5954: *new_key = &udf_node->loc.loc;
5955:
5956: return 0;
5957: }
5958:
5959:
5960: int
5961: udf_create_node(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
5962: struct componentname *cnp)
5963: {
5964: struct udf_node *udf_node, *dir_node = VTOI(dvp);
5965: struct udf_mount *ump = dir_node->ump;
5966: int error;
5967:
1.145 hannken 5968: error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, NULL, vpp);
1.129 hannken 5969: if (error)
5970: return error;
5971:
5972: udf_node = VTOI(*vpp);
1.45 reinoud 5973: error = udf_dir_attach(ump, dir_node, udf_node, vap, cnp);
5974: if (error) {
1.129 hannken 5975: struct long_ad *node_icb_loc = &udf_node->loc;
5976: uint32_t lb_num = udf_rw32(node_icb_loc->loc.lb_num);
5977: uint16_t vpart_num = udf_rw16(node_icb_loc->loc.part_num);
5978:
1.45 reinoud 5979: /* free disc allocation for node */
5980: udf_free_allocated_space(ump, lb_num, vpart_num, 1);
1.1 reinoud 5981:
1.45 reinoud 5982: /* recycle udf_node */
5983: udf_dispose_node(udf_node);
1.129 hannken 5984: vrele(*vpp);
1.1 reinoud 5985:
1.45 reinoud 5986: *vpp = NULL;
5987: return error;
5988: }
1.1 reinoud 5989:
1.45 reinoud 5990: /* adjust file count */
5991: udf_adjust_filecount(udf_node, 1);
1.1 reinoud 5992:
1.147 christos 5993: cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);
1.45 reinoud 5994: return 0;
1.1 reinoud 5995: }
5996:
5997: /* --------------------------------------------------------------------- */
5998:
1.45 reinoud 5999: static void
6000: udf_free_descriptor_space(struct udf_node *udf_node, struct long_ad *loc, void *mem)
6001: {
6002: struct udf_mount *ump = udf_node->ump;
6003: uint32_t lb_size, lb_num, len, num_lb;
6004: uint16_t vpart_num;
6005:
6006: /* is there really one? */
6007: if (mem == NULL)
6008: return;
1.1 reinoud 6009:
1.45 reinoud 6010: /* got a descriptor here */
1.55 reinoud 6011: len = UDF_EXT_LEN(udf_rw32(loc->len));
1.45 reinoud 6012: lb_num = udf_rw32(loc->loc.lb_num);
6013: vpart_num = udf_rw16(loc->loc.part_num);
1.1 reinoud 6014:
1.45 reinoud 6015: lb_size = udf_rw32(ump->logical_vol->lb_size);
6016: num_lb = (len + lb_size -1) / lb_size;
1.1 reinoud 6017:
1.45 reinoud 6018: udf_free_allocated_space(ump, lb_num, vpart_num, num_lb);
1.1 reinoud 6019: }
6020:
6021: void
1.45 reinoud 6022: udf_delete_node(struct udf_node *udf_node)
1.1 reinoud 6023: {
1.45 reinoud 6024: void *dscr;
6025: struct long_ad *loc;
6026: int extnr, lvint, dummy;
6027:
1.137 reinoud 6028: if (udf_node->i_flags & IN_NO_DELETE)
6029: return;
6030:
1.45 reinoud 6031: /* paranoia check on integrity; should be open!; we could panic */
6032: lvint = udf_rw32(udf_node->ump->logvol_integrity->integrity_type);
6033: if (lvint == UDF_INTEGRITY_CLOSED)
6034: printf("\tIntegrity was CLOSED!\n");
6035:
6036: /* whatever the node type, change its size to zero */
6037: (void) udf_resize_node(udf_node, 0, &dummy);
1.1 reinoud 6038:
1.45 reinoud 6039: /* force it to be `clean'; no use writing it out */
6040: udf_node->i_flags &= ~(IN_MODIFIED | IN_ACCESSED | IN_ACCESS |
6041: IN_CHANGE | IN_UPDATE | IN_MODIFY);
1.1 reinoud 6042:
1.45 reinoud 6043: /* adjust file count */
6044: udf_adjust_filecount(udf_node, -1);
1.1 reinoud 6045:
6046: /*
1.45 reinoud 6047: * Free its allocated descriptors; memory will be released when
6048: * vop_reclaim() is called.
1.1 reinoud 6049: */
1.45 reinoud 6050: loc = &udf_node->loc;
6051:
6052: dscr = udf_node->fe;
6053: udf_free_descriptor_space(udf_node, loc, dscr);
6054: dscr = udf_node->efe;
6055: udf_free_descriptor_space(udf_node, loc, dscr);
1.1 reinoud 6056:
1.45 reinoud 6057: for (extnr = 0; extnr < UDF_MAX_ALLOC_EXTENTS; extnr++) {
6058: dscr = udf_node->ext[extnr];
6059: loc = &udf_node->ext_loc[extnr];
6060: udf_free_descriptor_space(udf_node, loc, dscr);
1.9 christos 6061: }
1.1 reinoud 6062: }
6063:
6064: /* --------------------------------------------------------------------- */
6065:
1.45 reinoud 6066: /* set new filesize; node but be LOCKED on entry and is locked on exit */
6067: int
6068: udf_resize_node(struct udf_node *udf_node, uint64_t new_size, int *extended)
1.1 reinoud 6069: {
1.45 reinoud 6070: struct file_entry *fe = udf_node->fe;
6071: struct extfile_entry *efe = udf_node->efe;
6072: uint64_t file_size;
6073: int error;
1.1 reinoud 6074:
1.45 reinoud 6075: if (fe) {
6076: file_size = udf_rw64(fe->inf_len);
1.1 reinoud 6077: } else {
6078: assert(udf_node->efe);
1.45 reinoud 6079: file_size = udf_rw64(efe->inf_len);
1.9 christos 6080: }
1.1 reinoud 6081:
1.45 reinoud 6082: DPRINTF(ATTR, ("\tchanging file length from %"PRIu64" to %"PRIu64"\n",
6083: file_size, new_size));
6084:
6085: /* if not changing, we're done */
6086: if (file_size == new_size)
6087: return 0;
1.1 reinoud 6088:
1.45 reinoud 6089: *extended = (new_size > file_size);
6090: if (*extended) {
6091: error = udf_grow_node(udf_node, new_size);
6092: } else {
6093: error = udf_shrink_node(udf_node, new_size);
6094: }
1.1 reinoud 6095:
1.45 reinoud 6096: return error;
1.1 reinoud 6097: }
6098:
1.45 reinoud 6099:
1.1 reinoud 6100: /* --------------------------------------------------------------------- */
6101:
1.45 reinoud 6102: void
6103: udf_itimes(struct udf_node *udf_node, struct timespec *acc,
1.50 reinoud 6104: struct timespec *mod, struct timespec *birth)
1.1 reinoud 6105: {
1.45 reinoud 6106: struct timespec now;
1.1 reinoud 6107: struct file_entry *fe;
6108: struct extfile_entry *efe;
1.51 reinoud 6109: struct filetimes_extattr_entry *ft_extattr;
1.50 reinoud 6110: struct timestamp *atime, *mtime, *attrtime, *ctime;
6111: struct timestamp fe_ctime;
6112: struct timespec cur_birth;
1.51 reinoud 6113: uint32_t offset, a_l;
6114: uint8_t *filedata;
6115: int error;
1.45 reinoud 6116:
6117: /* protect against rogue values */
6118: if (!udf_node)
6119: return;
6120:
6121: fe = udf_node->fe;
6122: efe = udf_node->efe;
6123:
6124: if (!(udf_node->i_flags & (IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_MODIFY)))
6125: return;
1.1 reinoud 6126:
1.45 reinoud 6127: /* get descriptor information */
6128: if (fe) {
6129: atime = &fe->atime;
6130: mtime = &fe->mtime;
6131: attrtime = &fe->attrtime;
1.51 reinoud 6132: filedata = fe->data;
6133:
6134: /* initial save dummy setting */
1.50 reinoud 6135: ctime = &fe_ctime;
1.51 reinoud 6136:
6137: /* check our extended attribute if present */
6138: error = udf_extattr_search_intern(udf_node,
6139: UDF_FILETIMES_ATTR_NO, "", &offset, &a_l);
6140: if (!error) {
6141: ft_extattr = (struct filetimes_extattr_entry *)
6142: (filedata + offset);
6143: if (ft_extattr->existence & UDF_FILETIMES_FILE_CREATION)
6144: ctime = &ft_extattr->times[0];
6145: }
6146: /* TODO create the extended attribute if not found ? */
1.1 reinoud 6147: } else {
1.45 reinoud 6148: assert(udf_node->efe);
6149: atime = &efe->atime;
6150: mtime = &efe->mtime;
6151: attrtime = &efe->attrtime;
1.50 reinoud 6152: ctime = &efe->ctime;
1.45 reinoud 6153: }
6154:
6155: vfs_timestamp(&now);
6156:
6157: /* set access time */
6158: if (udf_node->i_flags & IN_ACCESS) {
6159: if (acc == NULL)
6160: acc = &now;
6161: udf_timespec_to_timestamp(acc, atime);
6162: }
6163:
6164: /* set modification time */
6165: if (udf_node->i_flags & (IN_UPDATE | IN_MODIFY)) {
6166: if (mod == NULL)
6167: mod = &now;
6168: udf_timespec_to_timestamp(mod, mtime);
1.50 reinoud 6169:
6170: /* ensure birthtime is older than set modification! */
6171: udf_timestamp_to_timespec(udf_node->ump, ctime, &cur_birth);
6172: if ((cur_birth.tv_sec > mod->tv_sec) ||
6173: ((cur_birth.tv_sec == mod->tv_sec) &&
6174: (cur_birth.tv_nsec > mod->tv_nsec))) {
6175: udf_timespec_to_timestamp(mod, ctime);
6176: }
1.45 reinoud 6177: }
6178:
1.50 reinoud 6179: /* update birthtime if specified */
1.116 mbalmer 6180: /* XXX we assume here that given birthtime is older than mod */
1.51 reinoud 6181: if (birth && (birth->tv_sec != VNOVAL)) {
1.50 reinoud 6182: udf_timespec_to_timestamp(birth, ctime);
1.51 reinoud 6183: }
1.50 reinoud 6184:
1.45 reinoud 6185: /* set change time */
1.50 reinoud 6186: if (udf_node->i_flags & (IN_CHANGE | IN_MODIFY))
6187: udf_timespec_to_timestamp(&now, attrtime);
1.1 reinoud 6188:
1.45 reinoud 6189: /* notify updates to the node itself */
6190: if (udf_node->i_flags & (IN_ACCESS | IN_MODIFY))
6191: udf_node->i_flags |= IN_ACCESSED;
6192: if (udf_node->i_flags & (IN_UPDATE | IN_CHANGE))
6193: udf_node->i_flags |= IN_MODIFIED;
6194:
6195: /* clear modification flags */
6196: udf_node->i_flags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY);
6197: }
6198:
6199: /* --------------------------------------------------------------------- */
1.1 reinoud 6200:
1.45 reinoud 6201: int
6202: udf_update(struct vnode *vp, struct timespec *acc,
1.50 reinoud 6203: struct timespec *mod, struct timespec *birth, int updflags)
1.45 reinoud 6204: {
1.71 reinoud 6205: union dscrptr *dscrptr;
1.45 reinoud 6206: struct udf_node *udf_node = VTOI(vp);
6207: struct udf_mount *ump = udf_node->ump;
6208: struct regid *impl_id;
6209: int mnt_async = (vp->v_mount->mnt_flag & MNT_ASYNC);
6210: int waitfor, flags;
1.31 reinoud 6211:
1.45 reinoud 6212: #ifdef DEBUG
6213: char bits[128];
1.50 reinoud 6214: DPRINTF(CALL, ("udf_update(node, %p, %p, %p, %d)\n", acc, mod, birth,
6215: updflags));
1.80 christos 6216: snprintb(bits, sizeof(bits), IN_FLAGBITS, udf_node->i_flags);
1.45 reinoud 6217: DPRINTF(CALL, ("\tnode flags %s\n", bits));
6218: DPRINTF(CALL, ("\t\tmnt_async = %d\n", mnt_async));
6219: #endif
1.31 reinoud 6220:
1.45 reinoud 6221: /* set our times */
1.51 reinoud 6222: udf_itimes(udf_node, acc, mod, birth);
1.37 rumble 6223:
1.45 reinoud 6224: /* set our implementation id */
6225: if (udf_node->fe) {
1.71 reinoud 6226: dscrptr = (union dscrptr *) udf_node->fe;
1.45 reinoud 6227: impl_id = &udf_node->fe->imp_id;
6228: } else {
1.71 reinoud 6229: dscrptr = (union dscrptr *) udf_node->efe;
1.45 reinoud 6230: impl_id = &udf_node->efe->imp_id;
6231: }
1.71 reinoud 6232:
6233: /* set our ID */
1.45 reinoud 6234: udf_set_regid(impl_id, IMPL_NAME);
6235: udf_add_impl_regid(ump, impl_id);
1.18 reinoud 6236:
1.71 reinoud 6237: /* update our crc! on RMW we are not allowed to change a thing */
6238: udf_validate_tag_and_crc_sums(dscrptr);
6239:
1.45 reinoud 6240: /* if called when mounted readonly, never write back */
6241: if (vp->v_mount->mnt_flag & MNT_RDONLY)
6242: return 0;
1.1 reinoud 6243:
1.45 reinoud 6244: /* check if the node is dirty 'enough'*/
6245: if (updflags & UPDATE_CLOSE) {
6246: flags = udf_node->i_flags & (IN_MODIFIED | IN_ACCESSED);
6247: } else {
6248: flags = udf_node->i_flags & IN_MODIFIED;
6249: }
6250: if (flags == 0)
6251: return 0;
1.19 reinoud 6252:
1.45 reinoud 6253: /* determine if we need to write sync or async */
6254: waitfor = 0;
6255: if ((flags & IN_MODIFIED) && (mnt_async == 0)) {
6256: /* sync mounted */
6257: waitfor = updflags & UPDATE_WAIT;
6258: if (updflags & UPDATE_DIROP)
6259: waitfor |= UPDATE_WAIT;
1.9 christos 6260: }
1.45 reinoud 6261: if (waitfor)
6262: return VOP_FSYNC(vp, FSCRED, FSYNC_WAIT, 0,0);
1.1 reinoud 6263:
1.45 reinoud 6264: return 0;
1.1 reinoud 6265: }
6266:
1.45 reinoud 6267:
1.1 reinoud 6268: /* --------------------------------------------------------------------- */
6269:
1.59 reinoud 6270:
1.1 reinoud 6271: /*
6272: * Read one fid and process it into a dirent and advance to the next (*fid)
6273: * has to be allocated a logical block in size, (*dirent) struct dirent length
6274: */
6275:
6276: int
6277: udf_read_fid_stream(struct vnode *vp, uint64_t *offset,
1.97 reinoud 6278: struct fileid_desc *fid, struct dirent *dirent)
1.1 reinoud 6279: {
6280: struct udf_node *dir_node = VTOI(vp);
6281: struct udf_mount *ump = dir_node->ump;
1.45 reinoud 6282: struct file_entry *fe = dir_node->fe;
6283: struct extfile_entry *efe = dir_node->efe;
6284: uint32_t fid_size, lb_size;
1.1 reinoud 6285: uint64_t file_size;
6286: char *fid_name;
6287: int enough, error;
6288:
6289: assert(fid);
6290: assert(dirent);
6291: assert(dir_node);
6292: assert(offset);
6293: assert(*offset != 1);
6294:
1.45 reinoud 6295: DPRINTF(FIDS, ("read_fid_stream called at offset %"PRIu64"\n", *offset));
1.1 reinoud 6296: /* check if we're past the end of the directory */
1.45 reinoud 6297: if (fe) {
1.1 reinoud 6298: file_size = udf_rw64(fe->inf_len);
6299: } else {
6300: assert(dir_node->efe);
6301: file_size = udf_rw64(efe->inf_len);
1.9 christos 6302: }
1.1 reinoud 6303: if (*offset >= file_size)
6304: return EINVAL;
6305:
6306: /* get maximum length of FID descriptor */
6307: lb_size = udf_rw32(ump->logical_vol->lb_size);
6308:
6309: /* initialise return values */
1.45 reinoud 6310: fid_size = 0;
1.1 reinoud 6311: memset(dirent, 0, sizeof(struct dirent));
6312: memset(fid, 0, lb_size);
6313:
1.45 reinoud 6314: enough = (file_size - (*offset) >= UDF_FID_SIZE);
6315: if (!enough) {
6316: /* short dir ... */
6317: return EIO;
6318: }
1.1 reinoud 6319:
1.45 reinoud 6320: error = vn_rdwr(UIO_READ, vp,
6321: fid, MIN(file_size - (*offset), lb_size), *offset,
6322: UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, FSCRED,
6323: NULL, NULL);
1.1 reinoud 6324: if (error)
6325: return error;
6326:
1.45 reinoud 6327: DPRINTF(FIDS, ("\tfid piece read in fine\n"));
1.1 reinoud 6328: /*
6329: * Check if we got a whole descriptor.
1.45 reinoud 6330: * TODO Try to `resync' directory stream when something is very wrong.
1.1 reinoud 6331: */
6332:
6333: /* check if our FID header is OK */
6334: error = udf_check_tag(fid);
1.45 reinoud 6335: if (error) {
6336: goto brokendir;
1.9 christos 6337: }
1.45 reinoud 6338: DPRINTF(FIDS, ("\ttag check ok\n"));
1.1 reinoud 6339:
1.45 reinoud 6340: if (udf_rw16(fid->tag.id) != TAGID_FID) {
6341: error = EIO;
6342: goto brokendir;
1.9 christos 6343: }
1.45 reinoud 6344: DPRINTF(FIDS, ("\ttag checked ok: got TAGID_FID\n"));
1.1 reinoud 6345:
1.45 reinoud 6346: /* check for length */
6347: fid_size = udf_fidsize(fid);
6348: enough = (file_size - (*offset) >= fid_size);
1.1 reinoud 6349: if (!enough) {
1.45 reinoud 6350: error = EIO;
6351: goto brokendir;
1.9 christos 6352: }
1.45 reinoud 6353: DPRINTF(FIDS, ("\tthe complete fid is read in\n"));
1.1 reinoud 6354:
6355: /* check FID contents */
1.45 reinoud 6356: error = udf_check_tag_payload((union dscrptr *) fid, lb_size);
6357: brokendir:
1.1 reinoud 6358: if (error) {
6359: /* note that is sometimes a bit quick to report */
1.84 pooka 6360: printf("UDF: BROKEN DIRECTORY ENTRY\n");
1.1 reinoud 6361: /* RESYNC? */
6362: /* TODO: use udf_resync_fid_stream */
6363: return EIO;
1.9 christos 6364: }
1.45 reinoud 6365: DPRINTF(FIDS, ("\tpayload checked ok\n"));
1.1 reinoud 6366:
6367: /* we got a whole and valid descriptor! */
1.45 reinoud 6368: DPRINTF(FIDS, ("\tinterpret FID\n"));
1.1 reinoud 6369:
6370: /* create resulting dirent structure */
6371: fid_name = (char *) fid->data + udf_rw16(fid->l_iu);
1.117 christos 6372: udf_to_unix_name(dirent->d_name, NAME_MAX,
1.1 reinoud 6373: fid_name, fid->l_fi, &ump->logical_vol->desc_charset);
6374:
6375: /* '..' has no name, so provide one */
6376: if (fid->file_char & UDF_FILE_CHAR_PAR)
6377: strcpy(dirent->d_name, "..");
6378:
1.98 reinoud 6379: dirent->d_fileno = udf_get_node_id(&fid->icb); /* inode hash XXX */
1.1 reinoud 6380: dirent->d_namlen = strlen(dirent->d_name);
6381: dirent->d_reclen = _DIRENT_SIZE(dirent);
6382:
6383: /*
6384: * Note that its not worth trying to go for the filetypes now... its
6385: * too expensive too
6386: */
6387: dirent->d_type = DT_UNKNOWN;
6388:
6389: /* initial guess for filetype we can make */
6390: if (fid->file_char & UDF_FILE_CHAR_DIR)
6391: dirent->d_type = DT_DIR;
6392:
6393: /* advance */
1.45 reinoud 6394: *offset += fid_size;
1.1 reinoud 6395:
6396: return error;
6397: }
6398:
1.45 reinoud 6399:
6400: /* --------------------------------------------------------------------- */
6401:
6402: static void
1.132 hannken 6403: udf_sync_pass(struct udf_mount *ump, kauth_cred_t cred, int pass, int *ndirty)
1.45 reinoud 6404: {
6405: struct udf_node *udf_node, *n_udf_node;
6406: struct vnode *vp;
6407: int vdirty, error;
6408:
1.132 hannken 6409: KASSERT(mutex_owned(&ump->sync_lock));
1.45 reinoud 6410:
6411: DPRINTF(SYNC, ("sync_pass %d\n", pass));
1.108 rmind 6412: udf_node = RB_TREE_MIN(&ump->udf_node_tree);
1.45 reinoud 6413: for (;udf_node; udf_node = n_udf_node) {
6414: DPRINTF(SYNC, ("."));
6415:
6416: vp = udf_node->vnode;
6417:
1.108 rmind 6418: n_udf_node = rb_tree_iterate(&ump->udf_node_tree,
6419: udf_node, RB_DIR_RIGHT);
1.98 reinoud 6420:
1.130 riastrad 6421: error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT);
6422: if (error) {
6423: KASSERT(error == EBUSY);
6424: *ndirty += 1;
6425: continue;
6426: }
1.45 reinoud 6427:
6428: switch (pass) {
6429: case 1:
6430: VOP_FSYNC(vp, cred, 0 | FSYNC_DATAONLY,0,0);
6431: break;
6432: case 2:
6433: vdirty = vp->v_numoutput;
6434: if (vp->v_tag == VT_UDF)
6435: vdirty += udf_node->outstanding_bufs +
6436: udf_node->outstanding_nodedscr;
6437: if (vdirty == 0)
6438: VOP_FSYNC(vp, cred, 0,0,0);
6439: *ndirty += vdirty;
6440: break;
6441: case 3:
6442: vdirty = vp->v_numoutput;
6443: if (vp->v_tag == VT_UDF)
6444: vdirty += udf_node->outstanding_bufs +
6445: udf_node->outstanding_nodedscr;
6446: *ndirty += vdirty;
6447: break;
6448: }
6449:
1.132 hannken 6450: VOP_UNLOCK(vp);
1.45 reinoud 6451: }
6452: DPRINTF(SYNC, ("END sync_pass %d\n", pass));
6453: }
6454:
6455:
1.132 hannken 6456: static bool
6457: udf_sync_selector(void *cl, struct vnode *vp)
6458: {
1.139 riastrad 6459: struct udf_node *udf_node;
6460:
6461: KASSERT(mutex_owned(vp->v_interlock));
6462:
6463: udf_node = VTOI(vp);
1.132 hannken 6464:
6465: if (vp->v_vflag & VV_SYSTEM)
6466: return false;
6467: if (vp->v_type == VNON)
6468: return false;
6469: if (udf_node == NULL)
6470: return false;
6471: if ((udf_node->i_flags & (IN_ACCESSED | IN_UPDATE | IN_MODIFIED)) == 0)
6472: return false;
1.149 ad 6473: if (LIST_EMPTY(&vp->v_dirtyblkhd) && (vp->v_iflag & VI_ONWORKLST) == 0)
1.132 hannken 6474: return false;
6475:
6476: return true;
6477: }
6478:
1.45 reinoud 6479: void
6480: udf_do_sync(struct udf_mount *ump, kauth_cred_t cred, int waitfor)
6481: {
1.132 hannken 6482: struct vnode_iterator *marker;
6483: struct vnode *vp;
6484: struct udf_node *udf_node, *udf_next_node;
1.45 reinoud 6485: int dummy, ndirty;
6486:
1.132 hannken 6487: if (waitfor == MNT_LAZY)
6488: return;
6489:
6490: mutex_enter(&ump->sync_lock);
6491:
6492: /* Fill the rbtree with nodes to sync. */
6493: vfs_vnode_iterator_init(ump->vfs_mountp, &marker);
6494: while ((vp = vfs_vnode_iterator_next(marker,
6495: udf_sync_selector, NULL)) != NULL) {
6496: udf_node = VTOI(vp);
6497: udf_node->i_flags |= IN_SYNCED;
6498: rb_tree_insert_node(&ump->udf_node_tree, udf_node);
6499: }
6500: vfs_vnode_iterator_destroy(marker);
6501:
1.45 reinoud 6502: dummy = 0;
6503: DPRINTF(CALL, ("issue VOP_FSYNC(DATA only) on all nodes\n"));
6504: DPRINTF(SYNC, ("issue VOP_FSYNC(DATA only) on all nodes\n"));
1.132 hannken 6505: udf_sync_pass(ump, cred, 1, &dummy);
1.45 reinoud 6506:
6507: DPRINTF(CALL, ("issue VOP_FSYNC(COMPLETE) on all finished nodes\n"));
6508: DPRINTF(SYNC, ("issue VOP_FSYNC(COMPLETE) on all finished nodes\n"));
1.132 hannken 6509: udf_sync_pass(ump, cred, 2, &dummy);
1.45 reinoud 6510:
6511: if (waitfor == MNT_WAIT) {
1.132 hannken 6512: recount:
1.45 reinoud 6513: ndirty = ump->devvp->v_numoutput;
1.77 reinoud 6514: DPRINTF(SYNC, ("counting pending blocks: on devvp %d\n",
1.45 reinoud 6515: ndirty));
1.132 hannken 6516: udf_sync_pass(ump, cred, 3, &ndirty);
1.77 reinoud 6517: DPRINTF(SYNC, ("counted num dirty pending blocks %d\n",
1.45 reinoud 6518: ndirty));
1.152 skrll 6519:
1.45 reinoud 6520: if (ndirty) {
6521: /* 1/4 second wait */
1.131 hannken 6522: kpause("udfsync2", false, hz/4, NULL);
1.45 reinoud 6523: goto recount;
6524: }
6525: }
6526:
1.132 hannken 6527: /* Clean the rbtree. */
6528: for (udf_node = RB_TREE_MIN(&ump->udf_node_tree);
6529: udf_node; udf_node = udf_next_node) {
6530: udf_next_node = rb_tree_iterate(&ump->udf_node_tree,
6531: udf_node, RB_DIR_RIGHT);
6532: rb_tree_remove_node(&ump->udf_node_tree, udf_node);
6533: udf_node->i_flags &= ~IN_SYNCED;
6534: vrele(udf_node->vnode);
6535: }
6536:
6537: mutex_exit(&ump->sync_lock);
1.45 reinoud 6538: }
6539:
1.1 reinoud 6540: /* --------------------------------------------------------------------- */
6541:
6542: /*
1.45 reinoud 6543: * Read and write file extent in/from the buffer.
6544: *
1.146 msaitoh 6545: * The splitup of the extent into separate request-buffers is to minimise
1.45 reinoud 6546: * copying around as much as possible.
6547: *
1.1 reinoud 6548: * block based file reading and writing
6549: */
6550:
6551: static int
6552: udf_read_internal(struct udf_node *node, uint8_t *blob)
6553: {
6554: struct udf_mount *ump;
1.45 reinoud 6555: struct file_entry *fe = node->fe;
6556: struct extfile_entry *efe = node->efe;
1.1 reinoud 6557: uint64_t inflen;
6558: uint32_t sector_size;
1.135 dholland 6559: uint8_t *srcpos;
1.1 reinoud 6560: int icbflags, addr_type;
6561:
6562: /* get extent and do some paranoia checks */
6563: ump = node->ump;
6564: sector_size = ump->discinfo.sector_size;
6565:
1.135 dholland 6566: /*
6567: * XXX there should be real bounds-checking logic here,
6568: * in case ->l_ea or ->inf_len contains nonsense.
6569: */
6570:
1.1 reinoud 6571: if (fe) {
6572: inflen = udf_rw64(fe->inf_len);
1.135 dholland 6573: srcpos = &fe->data[0] + udf_rw32(fe->l_ea);
1.1 reinoud 6574: icbflags = udf_rw16(fe->icbtag.flags);
1.45 reinoud 6575: } else {
6576: assert(node->efe);
1.1 reinoud 6577: inflen = udf_rw64(efe->inf_len);
1.135 dholland 6578: srcpos = &efe->data[0] + udf_rw32(efe->l_ea);
1.1 reinoud 6579: icbflags = udf_rw16(efe->icbtag.flags);
1.9 christos 6580: }
1.1 reinoud 6581: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
6582:
6583: assert(addr_type == UDF_ICB_INTERN_ALLOC);
1.124 christos 6584: __USE(addr_type);
1.1 reinoud 6585: assert(inflen < sector_size);
6586:
6587: /* copy out info */
1.135 dholland 6588: memcpy(blob, srcpos, inflen);
1.134 christos 6589: memset(&blob[inflen], 0, sector_size - inflen);
1.1 reinoud 6590:
6591: return 0;
6592: }
6593:
6594:
1.45 reinoud 6595: static int
6596: udf_write_internal(struct udf_node *node, uint8_t *blob)
1.1 reinoud 6597: {
1.45 reinoud 6598: struct udf_mount *ump;
6599: struct file_entry *fe = node->fe;
6600: struct extfile_entry *efe = node->efe;
6601: uint64_t inflen;
1.1 reinoud 6602: uint32_t sector_size;
1.45 reinoud 6603: uint8_t *pos;
6604: int icbflags, addr_type;
6605:
6606: /* get extent and do some paranoia checks */
6607: ump = node->ump;
6608: sector_size = ump->discinfo.sector_size;
1.1 reinoud 6609:
1.45 reinoud 6610: if (fe) {
6611: inflen = udf_rw64(fe->inf_len);
6612: pos = &fe->data[0] + udf_rw32(fe->l_ea);
6613: icbflags = udf_rw16(fe->icbtag.flags);
6614: } else {
6615: assert(node->efe);
6616: inflen = udf_rw64(efe->inf_len);
6617: pos = &efe->data[0] + udf_rw32(efe->l_ea);
6618: icbflags = udf_rw16(efe->icbtag.flags);
6619: }
6620: addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
1.1 reinoud 6621:
1.45 reinoud 6622: assert(addr_type == UDF_ICB_INTERN_ALLOC);
1.124 christos 6623: __USE(addr_type);
1.45 reinoud 6624: assert(inflen < sector_size);
1.124 christos 6625: __USE(sector_size);
1.1 reinoud 6626:
1.45 reinoud 6627: /* copy in blob */
6628: /* memset(pos, 0, inflen); */
6629: memcpy(pos, blob, inflen);
1.1 reinoud 6630:
1.45 reinoud 6631: return 0;
1.1 reinoud 6632: }
6633:
6634:
6635: void
1.45 reinoud 6636: udf_read_filebuf(struct udf_node *udf_node, struct buf *buf)
1.1 reinoud 6637: {
6638: struct buf *nestbuf;
1.45 reinoud 6639: struct udf_mount *ump = udf_node->ump;
1.10 christos 6640: uint64_t *mapping;
1.1 reinoud 6641: uint64_t run_start;
6642: uint32_t sector_size;
6643: uint32_t buf_offset, sector, rbuflen, rblk;
1.45 reinoud 6644: uint32_t from, lblkno;
6645: uint32_t sectors;
1.1 reinoud 6646: uint8_t *buf_pos;
1.95 reinoud 6647: int error, run_length, what;
1.1 reinoud 6648:
1.45 reinoud 6649: sector_size = udf_node->ump->discinfo.sector_size;
1.1 reinoud 6650:
6651: from = buf->b_blkno;
6652: sectors = buf->b_bcount / sector_size;
6653:
1.95 reinoud 6654: what = udf_get_c_type(udf_node);
1.45 reinoud 6655:
1.1 reinoud 6656: /* assure we have enough translation slots */
1.45 reinoud 6657: KASSERT(buf->b_bcount / sector_size <= UDF_MAX_MAPPINGS);
6658: KASSERT(MAXPHYS / sector_size <= UDF_MAX_MAPPINGS);
1.1 reinoud 6659:
1.45 reinoud 6660: if (sectors > UDF_MAX_MAPPINGS) {
1.1 reinoud 6661: printf("udf_read_filebuf: implementation limit on bufsize\n");
6662: buf->b_error = EIO;
6663: biodone(buf);
6664: return;
1.9 christos 6665: }
1.1 reinoud 6666:
1.45 reinoud 6667: mapping = malloc(sizeof(*mapping) * UDF_MAX_MAPPINGS, M_TEMP, M_WAITOK);
1.10 christos 6668:
1.1 reinoud 6669: error = 0;
6670: DPRINTF(READ, ("\ttranslate %d-%d\n", from, sectors));
1.45 reinoud 6671: error = udf_translate_file_extent(udf_node, from, sectors, mapping);
1.1 reinoud 6672: if (error) {
6673: buf->b_error = error;
6674: biodone(buf);
1.10 christos 6675: goto out;
1.9 christos 6676: }
1.1 reinoud 6677: DPRINTF(READ, ("\ttranslate extent went OK\n"));
6678:
1.45 reinoud 6679: /* pre-check if its an internal */
1.1 reinoud 6680: if (*mapping == UDF_TRANS_INTERN) {
1.45 reinoud 6681: error = udf_read_internal(udf_node, (uint8_t *) buf->b_data);
6682: if (error)
1.1 reinoud 6683: buf->b_error = error;
6684: biodone(buf);
1.10 christos 6685: goto out;
1.9 christos 6686: }
1.1 reinoud 6687: DPRINTF(READ, ("\tnot intern\n"));
6688:
1.45 reinoud 6689: #ifdef DEBUG
6690: if (udf_verbose & UDF_DEBUG_TRANSLATE) {
6691: printf("Returned translation table:\n");
6692: for (sector = 0; sector < sectors; sector++) {
6693: printf("%d : %"PRIu64"\n", sector, mapping[sector]);
6694: }
6695: }
6696: #endif
6697:
6698: /* request read-in of data from disc sheduler */
1.1 reinoud 6699: buf->b_resid = buf->b_bcount;
6700: for (sector = 0; sector < sectors; sector++) {
6701: buf_offset = sector * sector_size;
6702: buf_pos = (uint8_t *) buf->b_data + buf_offset;
6703: DPRINTF(READ, ("\tprocessing rel sector %d\n", sector));
6704:
1.45 reinoud 6705: /* check if its zero or unmapped to stop reading */
1.1 reinoud 6706: switch (mapping[sector]) {
6707: case UDF_TRANS_UNMAPPED:
6708: case UDF_TRANS_ZERO:
1.45 reinoud 6709: /* copy zero sector TODO runlength like below */
1.1 reinoud 6710: memset(buf_pos, 0, sector_size);
6711: DPRINTF(READ, ("\treturning zero sector\n"));
6712: nestiobuf_done(buf, sector_size, 0);
6713: break;
6714: default :
6715: DPRINTF(READ, ("\tread sector "
6716: "%"PRIu64"\n", mapping[sector]));
6717:
1.45 reinoud 6718: lblkno = from + sector;
1.1 reinoud 6719: run_start = mapping[sector];
6720: run_length = 1;
6721: while (sector < sectors-1) {
6722: if (mapping[sector+1] != mapping[sector]+1)
6723: break;
6724: run_length++;
6725: sector++;
1.9 christos 6726: }
1.1 reinoud 6727:
6728: /*
6729: * nest an iobuf and mark it for async reading. Since
6730: * we're using nested buffers, they can't be cached by
6731: * design.
6732: */
6733: rbuflen = run_length * sector_size;
6734: rblk = run_start * (sector_size/DEV_BSIZE);
6735:
1.44 ad 6736: nestbuf = getiobuf(NULL, true);
1.1 reinoud 6737: nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
6738: /* nestbuf is B_ASYNC */
6739:
1.45 reinoud 6740: /* identify this nestbuf */
6741: nestbuf->b_lblkno = lblkno;
6742: assert(nestbuf->b_vp == udf_node->vnode);
6743:
6744: /* CD shedules on raw blkno */
6745: nestbuf->b_blkno = rblk;
6746: nestbuf->b_proc = NULL;
6747: nestbuf->b_rawblkno = rblk;
6748: nestbuf->b_udf_c_type = what;
6749:
6750: udf_discstrat_queuebuf(ump, nestbuf);
1.9 christos 6751: }
6752: }
1.10 christos 6753: out:
1.45 reinoud 6754: /* if we're synchronously reading, wait for the completion */
6755: if ((buf->b_flags & B_ASYNC) == 0)
6756: biowait(buf);
6757:
1.1 reinoud 6758: DPRINTF(READ, ("\tend of read_filebuf\n"));
1.45 reinoud 6759: free(mapping, M_TEMP);
1.10 christos 6760: return;
1.1 reinoud 6761: }
6762:
6763:
1.45 reinoud 6764: void
6765: udf_write_filebuf(struct udf_node *udf_node, struct buf *buf)
6766: {
6767: struct buf *nestbuf;
6768: struct udf_mount *ump = udf_node->ump;
6769: uint64_t *mapping;
6770: uint64_t run_start;
6771: uint32_t lb_size;
6772: uint32_t buf_offset, lb_num, rbuflen, rblk;
6773: uint32_t from, lblkno;
6774: uint32_t num_lb;
1.95 reinoud 6775: int error, run_length, what, s;
1.45 reinoud 6776:
6777: lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
6778:
6779: from = buf->b_blkno;
6780: num_lb = buf->b_bcount / lb_size;
1.1 reinoud 6781:
1.95 reinoud 6782: what = udf_get_c_type(udf_node);
1.70 reinoud 6783:
1.45 reinoud 6784: /* assure we have enough translation slots */
6785: KASSERT(buf->b_bcount / lb_size <= UDF_MAX_MAPPINGS);
6786: KASSERT(MAXPHYS / lb_size <= UDF_MAX_MAPPINGS);
1.1 reinoud 6787:
1.45 reinoud 6788: if (num_lb > UDF_MAX_MAPPINGS) {
6789: printf("udf_write_filebuf: implementation limit on bufsize\n");
6790: buf->b_error = EIO;
6791: biodone(buf);
6792: return;
6793: }
1.1 reinoud 6794:
1.45 reinoud 6795: mapping = malloc(sizeof(*mapping) * UDF_MAX_MAPPINGS, M_TEMP, M_WAITOK);
1.1 reinoud 6796:
1.45 reinoud 6797: error = 0;
6798: DPRINTF(WRITE, ("\ttranslate %d-%d\n", from, num_lb));
6799: error = udf_translate_file_extent(udf_node, from, num_lb, mapping);
6800: if (error) {
6801: buf->b_error = error;
6802: biodone(buf);
6803: goto out;
1.9 christos 6804: }
1.45 reinoud 6805: DPRINTF(WRITE, ("\ttranslate extent went OK\n"));
6806:
6807: /* if its internally mapped, we can write it in the descriptor itself */
6808: if (*mapping == UDF_TRANS_INTERN) {
6809: /* TODO paranoia check if we ARE going to have enough space */
6810: error = udf_write_internal(udf_node, (uint8_t *) buf->b_data);
6811: if (error)
6812: buf->b_error = error;
6813: biodone(buf);
6814: goto out;
1.9 christos 6815: }
1.45 reinoud 6816: DPRINTF(WRITE, ("\tnot intern\n"));
6817:
6818: /* request write out of data to disc sheduler */
6819: buf->b_resid = buf->b_bcount;
6820: for (lb_num = 0; lb_num < num_lb; lb_num++) {
6821: buf_offset = lb_num * lb_size;
6822: DPRINTF(WRITE, ("\tprocessing rel lb_num %d\n", lb_num));
6823:
6824: /*
6825: * Mappings are not that important here. Just before we write
6826: * the lb_num we late-allocate them when needed and update the
6827: * mapping in the udf_node.
6828: */
6829:
6830: /* XXX why not ignore the mapping altogether ? */
6831: DPRINTF(WRITE, ("\twrite lb_num "
6832: "%"PRIu64, mapping[lb_num]));
6833:
6834: lblkno = from + lb_num;
6835: run_start = mapping[lb_num];
6836: run_length = 1;
6837: while (lb_num < num_lb-1) {
6838: if (mapping[lb_num+1] != mapping[lb_num]+1)
6839: if (mapping[lb_num+1] != mapping[lb_num])
6840: break;
6841: run_length++;
6842: lb_num++;
6843: }
6844: DPRINTF(WRITE, ("+ %d\n", run_length));
1.1 reinoud 6845:
1.45 reinoud 6846: /* nest an iobuf on the master buffer for the extent */
6847: rbuflen = run_length * lb_size;
6848: rblk = run_start * (lb_size/DEV_BSIZE);
1.1 reinoud 6849:
1.45 reinoud 6850: nestbuf = getiobuf(NULL, true);
6851: nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
6852: /* nestbuf is B_ASYNC */
6853:
6854: /* identify this nestbuf */
6855: nestbuf->b_lblkno = lblkno;
6856: KASSERT(nestbuf->b_vp == udf_node->vnode);
6857:
6858: /* CD shedules on raw blkno */
6859: nestbuf->b_blkno = rblk;
6860: nestbuf->b_proc = NULL;
6861: nestbuf->b_rawblkno = rblk;
6862: nestbuf->b_udf_c_type = what;
6863:
6864: /* increment our outstanding bufs counter */
6865: s = splbio();
6866: udf_node->outstanding_bufs++;
6867: splx(s);
1.1 reinoud 6868:
1.45 reinoud 6869: udf_discstrat_queuebuf(ump, nestbuf);
1.9 christos 6870: }
1.45 reinoud 6871: out:
6872: /* if we're synchronously writing, wait for the completion */
6873: if ((buf->b_flags & B_ASYNC) == 0)
6874: biowait(buf);
6875:
6876: DPRINTF(WRITE, ("\tend of write_filebuf\n"));
6877: free(mapping, M_TEMP);
6878: return;
1.1 reinoud 6879: }
6880:
6881: /* --------------------------------------------------------------------- */
CVSweb <webmaster@jp.NetBSD.org>