1/* 2 * volume_id - reads filesystem label and uuid 3 * 4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation version 2 of the License. 9 */ 10 11#ifndef _GNU_SOURCE 12#define _GNU_SOURCE 1 13#endif 14 15#ifdef HAVE_CONFIG_H 16# include <config.h> 17#endif 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <unistd.h> 22#include <string.h> 23#include <errno.h> 24#include <ctype.h> 25 26#include "libvolume_id.h" 27#include "util.h" 28 29struct volume_descriptor { 30 struct descriptor_tag { 31 uint16_t id; 32 uint16_t version; 33 uint8_t checksum; 34 uint8_t reserved; 35 uint16_t serial; 36 uint16_t crc; 37 uint16_t crc_len; 38 uint32_t location; 39 } PACKED tag; 40 union { 41 struct anchor_descriptor { 42 uint32_t length; 43 uint32_t location; 44 } PACKED anchor; 45 struct primary_descriptor { 46 uint32_t seq_num; 47 uint32_t desc_num; 48 struct dstring { 49 uint8_t clen; 50 uint8_t c[31]; 51 } PACKED ident; 52 } PACKED primary; 53 } PACKED type; 54} PACKED; 55 56struct volume_structure_descriptor { 57 uint8_t type; 58 uint8_t id[5]; 59 uint8_t version; 60} PACKED; 61 62#define UDF_VSD_OFFSET 0x8000 63 64int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size) 65{ 66 struct volume_descriptor *vd; 67 struct volume_structure_descriptor *vsd; 68 unsigned int bs; 69 unsigned int b; 70 unsigned int type; 71 unsigned int count; 72 unsigned int loc; 73 unsigned int clen; 74 75 info("probing at offset 0x%llx", (unsigned long long) off); 76 77 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200); 78 if (vsd == NULL) 79 return -1; 80 81 if (memcmp(vsd->id, "NSR02", 5) == 0) 82 goto blocksize; 83 if (memcmp(vsd->id, "NSR03", 5) == 0) 84 goto blocksize; 85 if (memcmp(vsd->id, "BEA01", 5) == 0) 86 goto blocksize; 87 if (memcmp(vsd->id, "BOOT2", 5) == 0) 88 goto blocksize; 89 if (memcmp(vsd->id, "CD001", 5) == 0) 90 goto blocksize; 91 if (memcmp(vsd->id, "CDW02", 5) == 0) 92 goto blocksize; 93 if (memcmp(vsd->id, "TEA03", 5) == 0) 94 goto blocksize; 95 return -1; 96 97blocksize: 98 /* search the next VSD to get the logical block size of the volume */ 99 for (bs = 0x800; bs < 0x8000; bs += 0x800) { 100 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800); 101 if (vsd == NULL) 102 return -1; 103 dbg("test for blocksize: 0x%x", bs); 104 if (vsd->id[0] != '\0') 105 goto nsr; 106 } 107 return -1; 108 109nsr: 110 /* search the list of VSDs for a NSR descriptor */ 111 for (b = 0; b < 64; b++) { 112 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800); 113 if (vsd == NULL) 114 return -1; 115 116 dbg("vsd: %c%c%c%c%c", 117 vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]); 118 119 if (vsd->id[0] == '\0') 120 return -1; 121 if (memcmp(vsd->id, "NSR02", 5) == 0) 122 goto anchor; 123 if (memcmp(vsd->id, "NSR03", 5) == 0) 124 goto anchor; 125 } 126 return -1; 127 128anchor: 129 /* read anchor volume descriptor */ 130 vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200); 131 if (vd == NULL) 132 return -1; 133 134 type = le16_to_cpu(vd->tag.id); 135 if (type != 2) /* TAG_ID_AVDP */ 136 goto found; 137 138 /* get desriptor list address and block count */ 139 count = le32_to_cpu(vd->type.anchor.length) / bs; 140 loc = le32_to_cpu(vd->type.anchor.location); 141 dbg("0x%x descriptors starting at logical secor 0x%x", count, loc); 142 143 /* pick the primary descriptor from the list */ 144 for (b = 0; b < count; b++) { 145 vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200); 146 if (vd == NULL) 147 return -1; 148 149 type = le16_to_cpu(vd->tag.id); 150 dbg("descriptor type %i", type); 151 152 /* check validity */ 153 if (type == 0) 154 goto found; 155 if (le32_to_cpu(vd->tag.location) != loc + b) 156 goto found; 157 158 if (type == 1) /* TAG_ID_PVD */ 159 goto pvd; 160 } 161 goto found; 162 163pvd: 164 volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32); 165 166 clen = vd->type.primary.ident.clen; 167 dbg("label string charsize=%i bit", clen); 168 if (clen == 8) 169 volume_id_set_label_string(id, vd->type.primary.ident.c, 31); 170 else if (clen == 16) 171 volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31); 172 173found: 174 volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 175 id->type = "udf"; 176 177 return 0; 178} 179