summaryrefslogtreecommitdiff
path: root/shlibs/blkid/src/probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'shlibs/blkid/src/probe.c')
-rw-r--r--shlibs/blkid/src/probe.c161
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,