diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-18 21:08:49 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-18 21:08:49 +0000 |
commit | de7684a309ad20c1b889d048d741cb1dd52245f7 (patch) | |
tree | efae3387e1978cdd128ff2a922b734d0e9d0180f /util-linux/volume_id/util.c | |
parent | 27dd495b98a6135554b1d839fefe436ba3c6ca71 (diff) | |
download | busybox-w32-de7684a309ad20c1b889d048d741cb1dd52245f7.tar.gz busybox-w32-de7684a309ad20c1b889d048d741cb1dd52245f7.tar.bz2 busybox-w32-de7684a309ad20c1b889d048d741cb1dd52245f7.zip |
support for mount by label (not yet tested)
Also adds findfs applet. Closes bug 1143.
Diffstat (limited to 'util-linux/volume_id/util.c')
-rw-r--r-- | util-linux/volume_id/util.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c new file mode 100644 index 000000000..d2265c249 --- /dev/null +++ b/util-linux/volume_id/util.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * volume_id - reads filesystem label and uuid | ||
3 | * | ||
4 | * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; either | ||
9 | * version 2.1 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This library is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with this library; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "volume_id_internal.h" | ||
22 | |||
23 | void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count) | ||
24 | { | ||
25 | unsigned i, j; | ||
26 | uint16_t c; | ||
27 | |||
28 | j = 0; | ||
29 | for (i = 0; i + 2 <= count; i += 2) { | ||
30 | if (endianess == LE) | ||
31 | c = (buf[i+1] << 8) | buf[i]; | ||
32 | else | ||
33 | c = (buf[i] << 8) | buf[i+1]; | ||
34 | if (c == 0) { | ||
35 | str[j] = '\0'; | ||
36 | break; | ||
37 | } else if (c < 0x80) { | ||
38 | if (j+1 >= len) | ||
39 | break; | ||
40 | str[j++] = (uint8_t) c; | ||
41 | } else if (c < 0x800) { | ||
42 | if (j+2 >= len) | ||
43 | break; | ||
44 | str[j++] = (uint8_t) (0xc0 | (c >> 6)); | ||
45 | str[j++] = (uint8_t) (0x80 | (c & 0x3f)); | ||
46 | } else { | ||
47 | if (j+3 >= len) | ||
48 | break; | ||
49 | str[j++] = (uint8_t) (0xe0 | (c >> 12)); | ||
50 | str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); | ||
51 | str[j++] = (uint8_t) (0x80 | (c & 0x3f)); | ||
52 | } | ||
53 | } | ||
54 | str[j] = '\0'; | ||
55 | } | ||
56 | |||
57 | static const char *usage_to_string(enum volume_id_usage usage_id) | ||
58 | { | ||
59 | switch (usage_id) { | ||
60 | case VOLUME_ID_FILESYSTEM: | ||
61 | return "filesystem"; | ||
62 | case VOLUME_ID_PARTITIONTABLE: | ||
63 | return "partitiontable"; | ||
64 | case VOLUME_ID_OTHER: | ||
65 | return "other"; | ||
66 | case VOLUME_ID_RAID: | ||
67 | return "raid"; | ||
68 | case VOLUME_ID_DISKLABEL: | ||
69 | return "disklabel"; | ||
70 | case VOLUME_ID_CRYPTO: | ||
71 | return "crypto"; | ||
72 | case VOLUME_ID_UNPROBED: | ||
73 | return "unprobed"; | ||
74 | case VOLUME_ID_UNUSED: | ||
75 | return "unused"; | ||
76 | } | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id) | ||
81 | { | ||
82 | part->usage_id = usage_id; | ||
83 | part->usage = usage_to_string(usage_id); | ||
84 | } | ||
85 | |||
86 | void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id) | ||
87 | { | ||
88 | id->usage_id = usage_id; | ||
89 | id->usage = usage_to_string(usage_id); | ||
90 | } | ||
91 | |||
92 | void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count) | ||
93 | { | ||
94 | memcpy(id->label_raw, buf, count); | ||
95 | id->label_raw_len = count; | ||
96 | } | ||
97 | |||
98 | #ifdef NOT_NEEDED | ||
99 | static size_t strnlen(const char *s, size_t maxlen) | ||
100 | { | ||
101 | size_t i; | ||
102 | if (!maxlen) return 0; | ||
103 | if (!s) return 0; | ||
104 | for (i = 0; *s && i < maxlen; ++s) ++i; | ||
105 | return i; | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count) | ||
110 | { | ||
111 | unsigned i; | ||
112 | |||
113 | memcpy(id->label, buf, count); | ||
114 | |||
115 | /* remove trailing whitespace */ | ||
116 | i = strnlen(id->label, count); | ||
117 | while (i--) { | ||
118 | if (!isspace(id->label[i])) | ||
119 | break; | ||
120 | } | ||
121 | id->label[i+1] = '\0'; | ||
122 | } | ||
123 | |||
124 | void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count) | ||
125 | { | ||
126 | volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count); | ||
127 | } | ||
128 | |||
129 | void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format) | ||
130 | { | ||
131 | unsigned i; | ||
132 | unsigned count = 0; | ||
133 | |||
134 | switch(format) { | ||
135 | case UUID_DOS: | ||
136 | count = 4; | ||
137 | break; | ||
138 | case UUID_NTFS: | ||
139 | case UUID_HFS: | ||
140 | count = 8; | ||
141 | break; | ||
142 | case UUID_DCE: | ||
143 | count = 16; | ||
144 | break; | ||
145 | case UUID_DCE_STRING: | ||
146 | count = 36; | ||
147 | break; | ||
148 | } | ||
149 | memcpy(id->uuid_raw, buf, count); | ||
150 | id->uuid_raw_len = count; | ||
151 | |||
152 | /* if set, create string in the same format, the native platform uses */ | ||
153 | for (i = 0; i < count; i++) | ||
154 | if (buf[i] != 0) | ||
155 | goto set; | ||
156 | return; | ||
157 | |||
158 | set: | ||
159 | switch(format) { | ||
160 | case UUID_DOS: | ||
161 | sprintf(id->uuid, "%02X%02X-%02X%02X", | ||
162 | buf[3], buf[2], buf[1], buf[0]); | ||
163 | break; | ||
164 | case UUID_NTFS: | ||
165 | sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", | ||
166 | buf[7], buf[6], buf[5], buf[4], | ||
167 | buf[3], buf[2], buf[1], buf[0]); | ||
168 | break; | ||
169 | case UUID_HFS: | ||
170 | sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X", | ||
171 | buf[0], buf[1], buf[2], buf[3], | ||
172 | buf[4], buf[5], buf[6], buf[7]); | ||
173 | break; | ||
174 | case UUID_DCE: | ||
175 | sprintf(id->uuid, | ||
176 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||
177 | buf[0], buf[1], buf[2], buf[3], | ||
178 | buf[4], buf[5], | ||
179 | buf[6], buf[7], | ||
180 | buf[8], buf[9], | ||
181 | buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]); | ||
182 | break; | ||
183 | case UUID_DCE_STRING: | ||
184 | memcpy(id->uuid, buf, count); | ||
185 | id->uuid[count] = '\0'; | ||
186 | break; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) | ||
191 | { | ||
192 | ssize_t buf_len; | ||
193 | |||
194 | dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len); | ||
195 | /* check if requested area fits in superblock buffer */ | ||
196 | if (off + len <= SB_BUFFER_SIZE) { | ||
197 | if (id->sbbuf == NULL) { | ||
198 | id->sbbuf = xmalloc(SB_BUFFER_SIZE); | ||
199 | } | ||
200 | |||
201 | /* check if we need to read */ | ||
202 | if ((off + len) > id->sbbuf_len) { | ||
203 | dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len)); | ||
204 | xlseek(id->fd, 0, SEEK_SET); | ||
205 | buf_len = full_read(id->fd, id->sbbuf, off + len); | ||
206 | if (buf_len < 0) { | ||
207 | dbg("read failed (%s)", strerror(errno)); | ||
208 | return NULL; | ||
209 | } | ||
210 | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); | ||
211 | id->sbbuf_len = buf_len; | ||
212 | if (buf_len < off + len) { | ||
213 | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); | ||
214 | return NULL; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | return &(id->sbbuf[off]); | ||
219 | } | ||
220 | |||
221 | if (len > SEEK_BUFFER_SIZE) { | ||
222 | dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); | ||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | /* get seek buffer */ | ||
227 | if (id->seekbuf == NULL) { | ||
228 | id->seekbuf = xmalloc(SEEK_BUFFER_SIZE); | ||
229 | } | ||
230 | |||
231 | /* check if we need to read */ | ||
232 | if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { | ||
233 | dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len); | ||
234 | xlseek(id->fd, off, SEEK_SET); | ||
235 | buf_len = full_read(id->fd, id->seekbuf, len); | ||
236 | if (buf_len < 0) { | ||
237 | dbg("read failed (%s)", strerror(errno)); | ||
238 | return NULL; | ||
239 | } | ||
240 | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); | ||
241 | id->seekbuf_off = off; | ||
242 | id->seekbuf_len = buf_len; | ||
243 | if (buf_len < len) { | ||
244 | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); | ||
245 | return NULL; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return &(id->seekbuf[off - id->seekbuf_off]); | ||
250 | } | ||
251 | |||
252 | void volume_id_free_buffer(struct volume_id *id) | ||
253 | { | ||
254 | free(id->sbbuf); | ||
255 | id->sbbuf = NULL; | ||
256 | id->sbbuf_len = 0; | ||
257 | free(id->seekbuf); | ||
258 | id->seekbuf = NULL; | ||
259 | id->seekbuf_len = 0; | ||
260 | } | ||