libblkid-tiny: add exfat superblock support
[project/fstools.git] / libblkid-tiny / libblkid-tiny.c
1 #include <stdio.h>
2 #include <sys/utsname.h>
3
4 #include "libblkid-tiny.h"
5 #include "superblocks.h"
6 #include "linux_version.h"
7
8 #if 0
9 #define DEBUG(fmt, ...) printf(fmt, __VA_ARGS__)
10 #else
11 #define DEBUG(fmt, ...)
12 #endif
13
14 int blkid_debug_mask = 0;
15
16 int get_linux_version (void)
17 {
18 static int kver = -1;
19 struct utsname uts;
20 int major = 0;
21 int minor = 0;
22 int teeny = 0;
23 int n;
24
25 if (kver != -1)
26 return kver;
27 if (uname (&uts))
28 return kver = 0;
29
30 n = sscanf(uts.release, "%d.%d.%d", &major, &minor, &teeny);
31 if (n < 1 || n > 3)
32 return kver = 0;
33
34 return kver = KERNEL_VERSION(major, minor, teeny);
35 }
36
37 int blkid_probe_is_tiny(blkid_probe pr)
38 {
39 /* never true ? */
40 return 0;
41 }
42
43 int blkid_probe_set_value(blkid_probe pr, const char *name,
44 unsigned char *data, size_t len)
45 {
46 /* empty stub */
47 return 0;
48 }
49
50 int blkid_probe_set_version(blkid_probe pr, const char *version)
51 {
52 int len = strlen(version);
53 if (len > (sizeof(pr->version) - 1)) {
54 fprintf(stderr, "version buffer too small %d\n", len);
55 return -1;
56 }
57
58 strncpy(pr->version, version, sizeof(pr->version));
59
60 return 0;
61 }
62
63 int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
64 {
65 va_list ap;
66 int n;
67
68 va_start(ap, fmt);
69 n = vsnprintf(pr->version, sizeof(pr->version), fmt, ap);
70 va_end(ap);
71
72 if (n >= sizeof(pr->version))
73 fprintf(stderr, "version buffer too small %d\n", n);
74
75 return 0;
76 }
77
78 unsigned char *blkid_probe_get_buffer(blkid_probe pr,
79 blkid_loff_t off, blkid_loff_t len)
80 {
81 struct blkid_bufinfo *bf;
82 int ret;
83
84 bf = malloc(sizeof(*bf) + len);
85 if (!bf)
86 return NULL;
87 memset(bf, 0, sizeof(*bf));
88 bf->data = ((unsigned char *)bf) + sizeof(*bf);
89
90 if (lseek(pr->fd, off, SEEK_SET) < 0) {
91 fprintf(stderr, "failed to seek\n");
92 free(bf);
93 return NULL;
94 }
95 ret = read(pr->fd, bf->data, len);
96
97 if (ret != len) {
98 fprintf(stderr, "failed to read blkid\n");
99 free(bf);
100 return NULL;
101 }
102
103 list_add_tail(&bf->bufs, &pr->buffers);
104
105 return bf->data;
106 }
107
108 int blkid_probe_set_id_label(blkid_probe pr, const char *name,
109 const unsigned char *data, size_t len)
110 {
111 return -ENOTSUP;
112 }
113
114 int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
115 {
116 if (len > (sizeof(pr->label) - 1)) {
117 fprintf(stderr, "label buffer too small %d > %d\n",
118 (int) len, (int) sizeof(pr->label) - 1);
119 return -1;
120 }
121 memcpy(pr->label, label, len + 1);
122
123 return 0;
124 }
125
126 int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
127 size_t len, int enc)
128 {
129 if (len > (sizeof(pr->label) - 1)) {
130 fprintf(stderr, "label buffer too small %d > %d\n",
131 (int) len, (int) sizeof(pr->label) - 1);
132 return -1;
133 }
134
135 blkid_encode_to_utf8(enc,(unsigned char*) pr->label, len,
136 label, len+1);
137
138 return 0;
139 }
140
141 int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
142 {
143 short unsigned int*u = (short unsigned int*) uuid;
144
145 if (u[0] && (!name || !strcmp(name, "UUID"))) {
146 sprintf(pr->uuid,
147 "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
148 be16_to_cpu(u[0]), be16_to_cpu(u[1]), be16_to_cpu(u[2]), be16_to_cpu(u[3]),
149 be16_to_cpu(u[4]), be16_to_cpu(u[5]), be16_to_cpu(u[6]), be16_to_cpu(u[7]));
150 }
151
152 return 0;
153 }
154
155 int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
156 {
157 return blkid_probe_set_uuid_as(pr, uuid, NULL);
158 }
159
160 int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
161 size_t len, const char *fmt, ...)
162 {
163 va_list ap;
164
165 va_start(ap, fmt);
166 vsnprintf(pr->uuid, sizeof(pr->uuid), fmt, ap);
167 va_end(ap);
168
169 return 0;
170 }
171
172 static const struct blkid_idinfo *idinfos[] =
173 {
174 &vfat_idinfo,
175 &swsuspend_idinfo,
176 &swap_idinfo,
177 &exfat_idinfo,
178 &ext4dev_idinfo,
179 &ext4_idinfo,
180 &ext3_idinfo,
181 &ext2_idinfo,
182 &jbd_idinfo,
183 &ntfs_idinfo,
184 &squashfs_idinfo,
185 &ubi_idinfo,
186 &ubifs_idinfo,
187 &jffs2_idinfo,
188 &hfsplus_idinfo,
189 &hfs_idinfo,
190 &btrfs_idinfo,
191 &f2fs_idinfo,
192 };
193
194 int probe_block(char *block, struct blkid_struct_probe *pr)
195 {
196 struct stat s;
197 int i;
198
199 if (stat(block, &s) || (!S_ISBLK(s.st_mode) && !S_ISREG(s.st_mode) && !strncmp(block, "ubi", 3)))
200 return -1;
201
202 pr->err = -1;
203 pr->fd = open(block, O_RDONLY);
204 if (pr->fd == -1)
205 return -1;
206
207 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
208 /* loop over all magic handlers */
209 const struct blkid_idmag *mag;
210
211 /* loop over all probe handlers */
212 DEBUG("scanning %s\n", idinfos[i]->name);
213
214 mag = &idinfos[i]->magics[0];
215
216 while (mag->magic) {
217 int off = (mag->kboff * 1024) + mag->sboff;
218 char magic[32] = { 0 };
219
220 if (lseek(pr->fd, off, SEEK_SET) < 0) {
221 close(pr->fd);
222 return -1;
223 }
224 if (read(pr->fd, magic, mag->len) < 0) {
225 close(pr->fd);
226 return -1;
227 }
228 DEBUG("magic: %s %s %d\n", mag->magic, magic, mag->len);
229 if (!memcmp(mag->magic, magic, mag->len))
230 break;
231 mag++;
232 }
233
234 if (mag && mag->magic) {
235 DEBUG("probing %s\n", idinfos[i]->name);
236 pr->err = idinfos[i]->probefunc(pr, mag);
237 pr->id = idinfos[i];
238 if (!pr->err)
239 break;
240 }
241 }
242
243 close(pr->fd);
244
245 return 0;
246 }