summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-11-07 19:06:58 +0200
committerTimo Teras <timo.teras@iki.fi>2008-11-07 19:06:58 +0200
commit0bf7a1a2cc45086d594e4af64e1e1a8c96274f47 (patch)
treecc1e5afeee95826135c0f437466d52e5066676eb
parentaef0f036f08f8949e4e2a5b84c9199ef8ec40595 (diff)
downloadapk-tools-0bf7a1a2cc45086d594e4af64e1e1a8c96274f47.tar.bz2
apk-tools-0bf7a1a2cc45086d594e4af64e1e1a8c96274f47.tar.xz
io: implement mmap(2) for reading pkgs
-rw-r--r--TODO3
-rw-r--r--src/io.c107
2 files changed, 99 insertions, 11 deletions
diff --git a/TODO b/TODO
index 9fdccef..a504e38 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
-- mmapped block stream from file
-
+- Empty .APK is not remembered as installed
- Index/pkginfo reader: same field multiple times -> memleak
- Compress index and db files
diff --git a/src/io.c b/src/io.c
index 38a1b07..81e3de3 100644
--- a/src/io.c
+++ b/src/io.c
@@ -13,6 +13,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <malloc.h>
+#include <sys/mman.h>
#include "apk_defines.h"
#include "apk_io.h"
@@ -122,23 +123,36 @@ size_t apk_istream_skip(struct apk_istream *is, size_t size)
size_t apk_istream_splice(void *stream, int fd, size_t size)
{
struct apk_istream *is = (struct apk_istream *) stream;
- unsigned char buf[2048];
- size_t done = 0, r, togo;
+ unsigned char *buf;
+ size_t bufsz, done = 0, r, togo;
+
+ bufsz = size;
+ if (bufsz > 256*1024)
+ bufsz = 256*1024;
+
+ buf = malloc(bufsz);
+ if (buf == NULL)
+ return -1;
while (done < size) {
togo = size - done;
- if (togo > sizeof(buf))
- togo = sizeof(buf);
+ if (togo > bufsz)
+ togo = bufsz;
r = is->read(is, buf, togo);
if (r < 0)
- return r;
- if (write(fd, buf, r) != r)
- return -1;
+ goto err;
+ if (write(fd, buf, r) != r) {
+ r = -1;
+ goto err;
+ }
done += r;
if (r != togo)
break;
}
- return done;
+ r = done;
+err:
+ free(buf);
+ return r;
}
struct apk_istream_bstream {
@@ -193,9 +207,84 @@ struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream)
return &isbs->bs;
}
+struct apk_mmap_bstream {
+ struct apk_bstream bs;
+ csum_ctx_t csum_ctx;
+ int fd;
+ size_t size;
+ unsigned char *ptr;
+ size_t pos;
+};
+
+static size_t mmap_read(void *stream, void **ptr)
+{
+ struct apk_mmap_bstream *mbs =
+ container_of(stream, struct apk_mmap_bstream, bs);
+ size_t size;
+
+ size = mbs->size - mbs->pos;
+ if (size > 1024*1024)
+ size = 1024*1024;
+
+ *ptr = (void *) &mbs->ptr[mbs->pos];
+ csum_process(&mbs->csum_ctx, &mbs->ptr[mbs->pos], size);
+ mbs->pos += size;
+
+ return size;
+}
+
+static void mmap_close(void *stream, csum_t csum)
+{
+ struct apk_mmap_bstream *mbs =
+ container_of(stream, struct apk_mmap_bstream, bs);
+
+ if (csum != NULL)
+ csum_finish(&mbs->csum_ctx, csum);
+
+ munmap(mbs->ptr, mbs->size);
+ free(mbs);
+}
+
+static struct apk_bstream *apk_mmap_bstream_from_fd(int fd)
+{
+ struct apk_mmap_bstream *mbs;
+ struct stat st;
+ void *ptr;
+
+ if (fstat(fd, &st) < 0)
+ return NULL;
+
+ ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (ptr == MAP_FAILED)
+ return NULL;
+
+ mbs = malloc(sizeof(struct apk_mmap_bstream));
+ if (mbs == NULL) {
+ munmap(ptr, st.st_size);
+ return NULL;
+ }
+
+ mbs->bs = (struct apk_bstream) {
+ .read = mmap_read,
+ .close = mmap_close,
+ };
+ mbs->fd = fd;
+ mbs->size = st.st_size;
+ mbs->ptr = ptr;
+ mbs->pos = 0;
+ csum_init(&mbs->csum_ctx);
+
+ return &mbs->bs;
+}
+
struct apk_bstream *apk_bstream_from_fd(int fd)
{
- /* FIXME: Write mmap based bstream for files */
+ struct apk_bstream *bs;
+
+ bs = apk_mmap_bstream_from_fd(fd);
+ if (bs != NULL)
+ return bs;
+
return apk_bstream_from_istream(apk_istream_from_fd(fd));
}