diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-30 17:41:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-30 17:41:31 +0000 |
commit | 1e10afcdfb2b3725458d7a245aa0fe2d39f6d812 (patch) | |
tree | ed4736d6448b409c0f18b6ea9f94ea4bc4b59da7 | |
parent | a34b8a4d305544aaeb6fa3b3576f4fd8a582b082 (diff) | |
download | busybox-w32-1e10afcdfb2b3725458d7a245aa0fe2d39f6d812.tar.gz busybox-w32-1e10afcdfb2b3725458d7a245aa0fe2d39f6d812.tar.bz2 busybox-w32-1e10afcdfb2b3725458d7a245aa0fe2d39f6d812.zip |
volume_id/fat: careful with sector#, it may not fit in 32 bits. +91 bytes
volume_id/*: a bit of code shrink
-rw-r--r-- | util-linux/volume_id/fat.c | 14 | ||||
-rw-r--r-- | util-linux/volume_id/util.c | 96 | ||||
-rw-r--r-- | util-linux/volume_id/volume_id_internal.h | 24 |
3 files changed, 68 insertions, 66 deletions
diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c index 816d69d4c..0e0a57d62 100644 --- a/util-linux/volume_id/fat.c +++ b/util-linux/volume_id/fat.c | |||
@@ -245,7 +245,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) | |||
245 | buf_size = dir_entries * sizeof(struct vfat_dir_entry); | 245 | buf_size = dir_entries * sizeof(struct vfat_dir_entry); |
246 | buf = volume_id_get_buffer(id, fat_partition_off + root_start_off, buf_size); | 246 | buf = volume_id_get_buffer(id, fat_partition_off + root_start_off, buf_size); |
247 | if (buf == NULL) | 247 | if (buf == NULL) |
248 | goto found; | 248 | goto ret; |
249 | 249 | ||
250 | label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries); | 250 | label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries); |
251 | 251 | ||
@@ -261,7 +261,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) | |||
261 | volume_id_set_label_string(id, vs->type.fat.label, 11); | 261 | volume_id_set_label_string(id, vs->type.fat.label, 11); |
262 | } | 262 | } |
263 | volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS); | 263 | volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS); |
264 | goto found; | 264 | goto ret; |
265 | 265 | ||
266 | fat32: | 266 | fat32: |
267 | /* FAT32 root dir is a cluster chain like any other directory */ | 267 | /* FAT32 root dir is a cluster chain like any other directory */ |
@@ -272,20 +272,20 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) | |||
272 | next_cluster = root_cluster; | 272 | next_cluster = root_cluster; |
273 | maxloop = 100; | 273 | maxloop = 100; |
274 | while (--maxloop) { | 274 | while (--maxloop) { |
275 | uint32_t next_off_sct; | 275 | uint64_t next_off_sct; |
276 | uint64_t next_off; | 276 | uint64_t next_off; |
277 | uint64_t fat_entry_off; | 277 | uint64_t fat_entry_off; |
278 | int count; | 278 | int count; |
279 | 279 | ||
280 | dbg("next_cluster 0x%x", (unsigned)next_cluster); | 280 | dbg("next_cluster 0x%x", (unsigned)next_cluster); |
281 | next_off_sct = (next_cluster - 2) * vs->sectors_per_cluster; | 281 | next_off_sct = (uint64_t)(next_cluster - 2) * vs->sectors_per_cluster; |
282 | next_off = (start_data_sct + next_off_sct) * sector_size_bytes; | 282 | next_off = (start_data_sct + next_off_sct) * sector_size_bytes; |
283 | dbg("cluster offset 0x%llx", (unsigned long long) next_off); | 283 | dbg("cluster offset 0x%llx", (unsigned long long) next_off); |
284 | 284 | ||
285 | /* get cluster */ | 285 | /* get cluster */ |
286 | buf = volume_id_get_buffer(id, fat_partition_off + next_off, buf_size); | 286 | buf = volume_id_get_buffer(id, fat_partition_off + next_off, buf_size); |
287 | if (buf == NULL) | 287 | if (buf == NULL) |
288 | goto found; | 288 | goto ret; |
289 | 289 | ||
290 | dir = (struct vfat_dir_entry*) buf; | 290 | dir = (struct vfat_dir_entry*) buf; |
291 | count = buf_size / sizeof(struct vfat_dir_entry); | 291 | count = buf_size / sizeof(struct vfat_dir_entry); |
@@ -300,7 +300,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) | |||
300 | dbg("fat_entry_off 0x%llx", (unsigned long long)fat_entry_off); | 300 | dbg("fat_entry_off 0x%llx", (unsigned long long)fat_entry_off); |
301 | buf = volume_id_get_buffer(id, fat_partition_off + fat_entry_off, buf_size); | 301 | buf = volume_id_get_buffer(id, fat_partition_off + fat_entry_off, buf_size); |
302 | if (buf == NULL) | 302 | if (buf == NULL) |
303 | goto found; | 303 | goto ret; |
304 | 304 | ||
305 | /* set next cluster */ | 305 | /* set next cluster */ |
306 | next_cluster = le32_to_cpu(*(uint32_t*)buf) & 0x0fffffff; | 306 | next_cluster = le32_to_cpu(*(uint32_t*)buf) & 0x0fffffff; |
@@ -323,7 +323,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t fat_partition_off) | |||
323 | } | 323 | } |
324 | volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS); | 324 | volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS); |
325 | 325 | ||
326 | found: | 326 | ret: |
327 | // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); | 327 | // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); |
328 | // id->type = "vfat"; | 328 | // id->type = "vfat"; |
329 | 329 | ||
diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c index c4d20ba47..1a1b3f92e 100644 --- a/util-linux/volume_id/util.c +++ b/util-linux/volume_id/util.c | |||
@@ -195,70 +195,73 @@ set: | |||
195 | * It's better to ignore such fs and continue. */ | 195 | * It's better to ignore such fs and continue. */ |
196 | void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) | 196 | void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) |
197 | { | 197 | { |
198 | ssize_t buf_len; | 198 | uint8_t *dst; |
199 | unsigned small_off; | ||
200 | ssize_t read_len; | ||
201 | |||
202 | dbg("get buffer off 0x%llx(%llu), len 0x%zx", | ||
203 | (unsigned long long) off, (unsigned long long) off, len); | ||
199 | 204 | ||
200 | dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len); | ||
201 | /* check if requested area fits in superblock buffer */ | 205 | /* check if requested area fits in superblock buffer */ |
202 | if (off + len <= SB_BUFFER_SIZE) { | 206 | if (off + len <= SB_BUFFER_SIZE |
207 | /* && off <= SB_BUFFER_SIZE - want this paranoid overflow check? */ | ||
208 | ) { | ||
203 | if (id->sbbuf == NULL) { | 209 | if (id->sbbuf == NULL) { |
204 | id->sbbuf = xmalloc(SB_BUFFER_SIZE); | 210 | id->sbbuf = xmalloc(SB_BUFFER_SIZE); |
205 | } | 211 | } |
212 | small_off = off; | ||
213 | dst = id->sbbuf; | ||
206 | 214 | ||
207 | /* check if we need to read */ | 215 | /* check if we need to read */ |
208 | if ((off + len) > id->sbbuf_len) { | 216 | len += off; |
209 | dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len)); | 217 | if (len <= id->sbbuf_len) |
210 | if (lseek(id->fd, 0, SEEK_SET) != 0) { | 218 | goto ret; /* we already have it */ |
211 | dbg("seek(0) failed"); | ||
212 | return NULL; | ||
213 | } | ||
214 | buf_len = full_read(id->fd, id->sbbuf, off + len); | ||
215 | if (buf_len < 0) { | ||
216 | dbg("read failed (%s)", strerror(errno)); | ||
217 | return NULL; | ||
218 | } | ||
219 | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); | ||
220 | id->sbbuf_len = buf_len; | ||
221 | if ((uint64_t)buf_len < off + len) { | ||
222 | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); | ||
223 | return NULL; | ||
224 | } | ||
225 | } | ||
226 | 219 | ||
227 | return &(id->sbbuf[off]); | 220 | dbg("read sbbuf len:0x%x", (unsigned) len); |
221 | id->sbbuf_len = len; | ||
222 | off = 0; | ||
223 | goto do_read; | ||
228 | } | 224 | } |
229 | 225 | ||
230 | if (len > SEEK_BUFFER_SIZE) { | 226 | if (len > SEEK_BUFFER_SIZE) { |
231 | dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); | 227 | dbg("seek buffer too small %d", SEEK_BUFFER_SIZE); |
232 | return NULL; | 228 | return NULL; |
233 | } | 229 | } |
234 | 230 | dst = id->seekbuf; | |
235 | /* get seek buffer */ | ||
236 | if (id->seekbuf == NULL) { | ||
237 | id->seekbuf = xmalloc(SEEK_BUFFER_SIZE); | ||
238 | } | ||
239 | 231 | ||
240 | /* check if we need to read */ | 232 | /* check if we need to read */ |
241 | if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) { | 233 | if ((off >= id->seekbuf_off) |
242 | dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len); | 234 | && ((off + len) <= (id->seekbuf_off + id->seekbuf_len)) |
243 | if (lseek(id->fd, off, SEEK_SET) != off) { | 235 | ) { |
244 | dbg("seek(0x%llx) failed", (unsigned long long) off); | 236 | small_off = off - id->seekbuf_off; /* can't overflow */ |
245 | return NULL; | 237 | goto ret; /* we already have it */ |
246 | } | ||
247 | buf_len = full_read(id->fd, id->seekbuf, len); | ||
248 | if (buf_len < 0) { | ||
249 | dbg("read failed (%s)", strerror(errno)); | ||
250 | return NULL; | ||
251 | } | ||
252 | dbg("got 0x%zx (%zi) bytes", buf_len, buf_len); | ||
253 | id->seekbuf_off = off; | ||
254 | id->seekbuf_len = buf_len; | ||
255 | if ((size_t)buf_len < len) { | ||
256 | dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len); | ||
257 | return NULL; | ||
258 | } | ||
259 | } | 238 | } |
260 | 239 | ||
261 | return &(id->seekbuf[off - id->seekbuf_off]); | 240 | id->seekbuf_off = off; |
241 | id->seekbuf_len = len; | ||
242 | id->seekbuf = xrealloc(id->seekbuf, len); | ||
243 | small_off = 0; | ||
244 | dst = id->seekbuf; | ||
245 | dbg("read seekbuf off:0x%llx len:0x%zx", | ||
246 | (unsigned long long) off, len); | ||
247 | do_read: | ||
248 | if (lseek(id->fd, off, SEEK_SET) != off) { | ||
249 | dbg("seek(0x%llx) failed", (unsigned long long) off); | ||
250 | goto err; | ||
251 | } | ||
252 | read_len = full_read(id->fd, dst, len); | ||
253 | if (read_len != len) { | ||
254 | dbg("requested 0x%x bytes, got 0x%x bytes", | ||
255 | (unsigned) len, (unsigned) read_len); | ||
256 | err: | ||
257 | /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. | ||
258 | * Most likely user will not do any additional | ||
259 | * calls anyway, it's a corrupted fs or something. */ | ||
260 | volume_id_free_buffer(id); | ||
261 | return NULL; | ||
262 | } | ||
263 | ret: | ||
264 | return dst + small_off; | ||
262 | } | 265 | } |
263 | 266 | ||
264 | void volume_id_free_buffer(struct volume_id *id) | 267 | void volume_id_free_buffer(struct volume_id *id) |
@@ -269,4 +272,5 @@ void volume_id_free_buffer(struct volume_id *id) | |||
269 | free(id->seekbuf); | 272 | free(id->seekbuf); |
270 | id->seekbuf = NULL; | 273 | id->seekbuf = NULL; |
271 | id->seekbuf_len = 0; | 274 | id->seekbuf_len = 0; |
275 | id->seekbuf_off = 0; /* paranoia */ | ||
272 | } | 276 | } |
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h index 075ddb344..fe3547d13 100644 --- a/util-linux/volume_id/volume_id_internal.h +++ b/util-linux/volume_id/volume_id_internal.h | |||
@@ -61,6 +61,17 @@ struct volume_id_partition { | |||
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | struct volume_id { | 63 | struct volume_id { |
64 | int fd; | ||
65 | // int fd_close:1; | ||
66 | size_t sbbuf_len; | ||
67 | size_t seekbuf_len; | ||
68 | uint8_t *sbbuf; | ||
69 | uint8_t *seekbuf; | ||
70 | uint64_t seekbuf_off; | ||
71 | #ifdef UNUSED_PARTITION_CODE | ||
72 | struct volume_id_partition *partitions; | ||
73 | size_t partition_count; | ||
74 | #endif | ||
64 | // uint8_t label_raw[VOLUME_ID_LABEL_SIZE]; | 75 | // uint8_t label_raw[VOLUME_ID_LABEL_SIZE]; |
65 | // size_t label_raw_len; | 76 | // size_t label_raw_len; |
66 | char label[VOLUME_ID_LABEL_SIZE+1]; | 77 | char label[VOLUME_ID_LABEL_SIZE+1]; |
@@ -72,19 +83,6 @@ struct volume_id { | |||
72 | // smallint usage_id; | 83 | // smallint usage_id; |
73 | // const char *usage; | 84 | // const char *usage; |
74 | // const char *type; | 85 | // const char *type; |
75 | |||
76 | #ifdef UNUSED_PARTITION_CODE | ||
77 | struct volume_id_partition *partitions; | ||
78 | size_t partition_count; | ||
79 | #endif | ||
80 | |||
81 | int fd; | ||
82 | uint8_t *sbbuf; | ||
83 | uint8_t *seekbuf; | ||
84 | size_t sbbuf_len; | ||
85 | uint64_t seekbuf_off; | ||
86 | size_t seekbuf_len; | ||
87 | // int fd_close:1; | ||
88 | }; | 86 | }; |
89 | 87 | ||
90 | struct volume_id *volume_id_open_node(int fd); | 88 | struct volume_id *volume_id_open_node(int fd); |