diff options
Diffstat (limited to 'shlibs/blkid/src/probe.c')
-rw-r--r-- | shlibs/blkid/src/probe.c | 161 |
1 files changed, 89 insertions, 72 deletions
diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 7ed80072..91366851 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -115,6 +115,7 @@ static const struct blkid_chaindrv *chains_drvs[] = { }; static void blkid_probe_reset_vals(blkid_probe pr); +static void blkid_probe_reset_buffer(blkid_probe pr); /** * blkid_new_probe: @@ -137,6 +138,7 @@ blkid_probe blkid_new_probe(void) pr->chains[i].flags = chains_drvs[i]->dflt_flags; pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; } + INIT_LIST_HEAD(&pr->buffers); return pr; } @@ -202,26 +204,13 @@ void blkid_free_probe(blkid_probe pr) ch->driver->free_data(pr, ch->data); free(ch->fltr); } - free(pr->buf); - free(pr->sbbuf); if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0) close(pr->fd); + blkid_probe_reset_buffer(pr); free(pr); } -static void blkid_probe_reset_buffer(blkid_probe pr) -{ - DBG(DEBUG_LOWPROBE, printf("reseting blkid probe buffer\n")); - if (pr->buf) - memset(pr->buf, 0, pr->buf_max); - pr->buf_off = 0; - pr->buf_len = 0; - if (pr->sbbuf) - memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); - pr->sbbuf_len = 0; -} - /* * Removes chain values from probing result. @@ -470,73 +459,87 @@ int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[ return 0; } -/* - * Note that we have two offsets: - * - * 1/ general device offset (pr->off), that's useful for example when we - * probe a partition from whole disk image: - * blkid-low --offset <partition_position> disk.img - * - * 2/ buffer offset (the 'off' argument), that useful for offsets in - * superbloks, ... - * - * That means never use lseek(fd, 0, SEEK_SET), the zero position is always - * pr->off, so lseek(fd, pr->off, SEEK_SET). - * - */ unsigned char *blkid_probe_get_buffer(blkid_probe pr, blkid_loff_t off, blkid_loff_t len) { - ssize_t ret_read = 0; + struct list_head *p; + struct blkid_bufinfo *bf = NULL; + + list_for_each(p, &pr->buffers) { + struct blkid_bufinfo *x = + list_entry(p, struct blkid_bufinfo, bufs); + + if (x->off <= off && off + len <= x->off + x->len) { + DBG(DEBUG_LOWPROBE, + printf("\treuse buffer: off=%jd len=%jd\n", + x->off, x->len)); + bf = x; + break; + } + } + if (!bf) { + ssize_t ret; + + if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) + return NULL; + + /* allocate info and space for data by why call */ + bf = calloc(1, sizeof(struct blkid_bufinfo) + len); + if (!bf) + return NULL; + + bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); + bf->len = len; + bf->off = off; + INIT_LIST_HEAD(&bf->bufs); - if (off < 0 || len < 0) { DBG(DEBUG_LOWPROBE, - printf("unexpected offset or length of buffer requested\n")); - return NULL; - } - if (off + len <= BLKID_SB_BUFSIZ) { - if (!pr->sbbuf) { - pr->sbbuf = malloc(BLKID_SB_BUFSIZ); - if (!pr->sbbuf) - return NULL; - } - if (!pr->sbbuf_len) { - if (lseek(pr->fd, pr->off, SEEK_SET) < 0) - return NULL; - ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); - if (ret_read < 0) - ret_read = 0; - pr->sbbuf_len = ret_read; - } - if (off + len > pr->sbbuf_len) + printf("\tbuffer read: off=%jd len=%jd\n", off, len)); + + ret = read(pr->fd, bf->data, len); + if (ret != (ssize_t) len) { + free(bf); return NULL; - return pr->sbbuf + off; - } else { - unsigned char *newbuf = NULL; - - if (len > pr->buf_max) { - newbuf = realloc(pr->buf, len); - if (!newbuf) - return NULL; - pr->buf = newbuf; - pr->buf_max = len; - pr->buf_off = 0; - pr->buf_len = 0; } - if (newbuf || off < pr->buf_off || - off + len > pr->buf_off + pr->buf_len) { + list_add_tail(&bf->bufs, &pr->buffers); + } - if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) - return NULL; + return off ? bf->data + (off - bf->off) : bf->data; +} - ret_read = read(pr->fd, pr->buf, len); - if (ret_read != (ssize_t) len) - return NULL; - pr->buf_off = off; - pr->buf_len = len; - } - return off ? pr->buf + (off - pr->buf_off) : pr->buf; + +static void blkid_probe_reset_buffer(blkid_probe pr) +{ + ssize_t read_ct = 0, len_ct = 0; + + if (!pr || list_empty(&pr->buffers)) + return; + + DBG(DEBUG_LOWPROBE, printf("reseting probing buffers\n")); + + while (!list_empty(&pr->buffers)) { + struct blkid_bufinfo *bf = list_entry(pr->buffers.next, + struct blkid_bufinfo, bufs); + + read_ct++; + len_ct += bf->len; + list_del(&bf->bufs); + free(bf); } + + DBG(DEBUG_LOWPROBE, + printf("buffers summary: %jd bytes by %jd read() call(s)\n", + len_ct, read_ct)); + + INIT_LIST_HEAD(&pr->buffers); +} + +/* + * Small devices need a special care. + */ +int blkid_probe_is_tiny(blkid_probe pr) +{ + return pr && (pr->flags & BLKID_TINY_DEV); } /** @@ -570,6 +573,10 @@ int blkid_probe_set_device(blkid_probe pr, int fd, pr->mode = 0; pr->blkssz = 0; +#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE) + /* Disable read-ahead */ + posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); +#endif if (size) pr->size = size; else { @@ -589,13 +596,23 @@ int blkid_probe_set_device(blkid_probe pr, int fd, if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) pr->devno = sb.st_rdev; + + if (pr->off > pr->size) + goto err; + + /* The probing area cannot be larger than whole device, pr->off + * is offset within the device */ + pr->size -= pr->off; } if (!pr->size) goto err; - DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", pr->off, pr->size)); + + if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode)) + pr->flags |= BLKID_TINY_DEV; + return 0; err: DBG(DEBUG_LOWPROBE, |