diff --git a/Makefile b/Makefile
index 621cb86..6a34be6 100644
--- a/Makefile
+++ b/Makefile
@@ -152,7 +152,6 @@ vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) qemu-timer-comm
 	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
 
 ######################################################################
-
 qemu-img.o: qemu-img-cmds.h
 
 tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
@@ -160,6 +159,9 @@ tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 	iohandler.o cutils.o iov.o async.o
 tools-obj-$(CONFIG_POSIX) += compatfd.o
 
+libqblock-test$(EXESUF): libqblock.o libqblock-test.o $(tools-obj-y) $(block-obj-y)
+	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(LIBS),"  LINK  $@")
+
 qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
 qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
 qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
diff --git a/libqblock-test.c b/libqblock-test.c
new file mode 100644
index 0000000..663111e
--- /dev/null
+++ b/libqblock-test.c
@@ -0,0 +1,56 @@
+#include "libqblock.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+unsigned char buf0[1024];
+unsigned char buf1[1024] = {4, 0, 0, 2};
+int main(int argc, char **argv)
+{
+    struct QBlockState i_qbs;
+    struct QBlockOpenOption i_qboo;
+    struct QBlockCreateOption i_qbco;
+    struct QBlockInfo i_qbi;
+    char *filename;
+
+    int i;
+    unsigned long op_size = 512;
+    unsigned long op_start = 1024;
+
+    filename = argv[1];
+    printf("qemu test, file name is %s.\n", filename);
+
+    libqblock_init();
+
+    qbs_init(&i_qbs);
+    memset(&i_qbco, 0, sizeof(struct QBlockCreateOption));
+
+    i_qbco.filename = filename;
+    i_qbco.fmt = (char *)"qcow2";
+    i_qbco.flag = BDRV_O_NOCACHE;
+    i_qbco.size = 512 * 1024 * 1024;
+    qb_create(&i_qbs, &i_qbco);
+
+    i_qboo.filename = filename;
+    i_qboo.flag = BDRV_O_RDWR;
+    qb_open(&i_qbs, &i_qboo);
+
+    qb_write(&i_qbs, op_start, op_size, buf1);
+    qb_read(&i_qbs, op_start, op_size, buf0);
+    for (i = 0; i < op_size; i++) {
+        if (buf0[i] != buf1[i]) {
+            printf("unmatch found at %d.\n", i);
+            break;
+        }
+    }
+    qbi_init(&i_qbi);
+    qb_getinfo(&i_qbs, &i_qbi);
+    qbi_print_test(&i_qbi);
+    qbi_uninit(&i_qbi);
+
+    qb_close(&i_qbs);
+    qb_delete(&i_qbs, filename);
+    qbs_uninit(&i_qbs);
+    return 0;
+}
diff --git a/libqblock.c b/libqblock.c
new file mode 100644
index 0000000..00b6649
--- /dev/null
+++ b/libqblock.c
@@ -0,0 +1,199 @@
+#include "libqblock.h"
+
+#include <unistd.h>
+
+#define QB_ERR_MEM_ERR (-1)
+#define QB_ERR_INTERNAL_ERR (-2)
+#define QB_ERR_INVALID_PARAM (-3)
+
+#define FUNC_FREE g_free
+
+#define CLEAN_FREE(p) { \
+        FUNC_FREE(p); \
+        (p) = NULL; \
+}
+
+/* try string dup and check if it succeed, dest would be freed before dup */
+#define SAFE_STRDUP(dest, src, ret, err_v) { \
+    if ((ret) != (err_v)) { \
+        if ((dest) != NULL) { \
+            FUNC_FREE(dest); \
+        } \
+        (dest) = strdup(src); \
+        if ((dest) == NULL) { \
+            (ret) = (err_v); \
+        } \
+    } \
+}
+
+int libqblock_init(void)
+{
+    bdrv_init();
+    return 0;
+}
+
+int qbs_init(struct QBlockState *qbs)
+{
+    memset(qbs, 0, sizeof(struct QBlockState));
+    qbs->bdrvs = bdrv_new("hda");
+    if (qbs->bdrvs == NULL) {
+        return QB_ERR_INTERNAL_ERR;
+    }
+    return 0;
+}
+
+int qbs_uninit(struct QBlockState *qbs)
+{
+    CLEAN_FREE(qbs->filename);
+    if (qbs->bdrvs == NULL) {
+        return QB_ERR_INVALID_PARAM;
+    }
+    bdrv_delete(qbs->bdrvs);
+    return 0;
+}
+
+int qb_create(struct QBlockState *qbs, struct QBlockCreateOption *op)
+{
+    int ret;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+
+    ret = bdrv_img_create(op->filename, op->fmt, op->base_filename,
+                          op->base_fmt, op->options, op->size, op->flag);
+    return 0;
+}
+
+int qb_open(struct QBlockState *qbs, struct QBlockOpenOption *op)
+{
+    int ret;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+    ret = bdrv_open(bs, op->filename, op->flag, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    SAFE_STRDUP(qbs->filename, op->filename, ret, QB_ERR_MEM_ERR);
+    return ret;
+}
+
+int qb_close(struct QBlockState *qbs)
+{
+    int ret = 0;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+    bdrv_close(bs);
+    return ret;
+}
+
+int qb_delete(struct QBlockState *qbs, const char *filename)
+{
+    return unlink(filename);
+}
+
+/* ignore case that len is not alligned to 512 now. */
+int qb_read(struct QBlockState *qbs, unsigned long start, unsigned long len,
+                                                          unsigned char *buf)
+{
+    int ret;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+
+    ret = bdrv_read(bs, start / 512,
+                        buf, len / 512);
+    return ret;
+}
+
+/* ignore case that len is not alligned to 512 now. */
+int qb_write(struct QBlockState *qbs, unsigned long start, unsigned long len,
+                                                           unsigned char *buf)
+{
+    int ret;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+    ret = bdrv_write(bs, start / 512,
+                        buf, len / 512);
+    return ret;
+}
+
+int qb_flush(struct QBlockState *qbs)
+{
+    int ret = 0;
+    BlockDriverState *bs;
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+    ret = bdrv_flush(bs);
+    return ret;
+}
+
+int qbi_init(struct QBlockInfo *info)
+{
+    memset(info, 0, sizeof(struct QBlockInfo));
+    return 0;
+}
+
+int qbi_uninit(struct QBlockInfo *info)
+{
+    CLEAN_FREE(info->filename);
+    CLEAN_FREE(info->fmt);
+    CLEAN_FREE(info->backing_filename);
+    CLEAN_FREE(info->sn_tab);
+    return 0;
+}
+
+int qbi_print_test(struct QBlockInfo *info)
+{
+    printf("name:%s, fmt %s, virt_size %ld, allocated_size %ld, encryt %d, "
+           "back_file %s, sn_tab %p, sn_num %d, cluster size %d, "
+           "vm_state_offset %ld, dirty %d.\n",
+           info->filename, info->fmt, info->virt_size, info->allocated_size,
+           info->encrypt_flag,
+           info->backing_filename, info->sn_tab, info->sn_tab_num,
+           info->cluster_size,
+           info->vm_state_offset, info->is_dirty);
+    return 0;
+}
+
+int qb_getinfo(struct QBlockState *qbs, struct QBlockInfo *info)
+{
+    int ret = 0;
+    BlockDriverState *bs;
+    const char *tmp;
+    BlockDriverInfo bdi;
+    uint64_t total_sectors;
+    char backing_filename[1024];
+
+    bs = (BlockDriverState *)qbs->bdrvs;
+    SAFE_STRDUP(info->filename, qbs->filename, ret, QB_ERR_MEM_ERR);
+    tmp = bdrv_get_format_name(bs);
+    SAFE_STRDUP(info->fmt, tmp, ret, QB_ERR_MEM_ERR);
+    bdrv_get_geometry(bs, &total_sectors);
+    info->virt_size = total_sectors * 512;
+    info->allocated_size = bdrv_get_allocated_file_size(bs);
+    info->encrypt_flag = bdrv_is_encrypted(bs);
+    bdrv_get_full_backing_filename(bs, backing_filename,
+                                   sizeof(backing_filename));
+    if (backing_filename[0] != '\0') {
+        SAFE_STRDUP(info->backing_filename, backing_filename, ret,
+                                                   QB_ERR_MEM_ERR);
+    }
+    info->sn_tab_num = bdrv_snapshot_list(bs, &(info->sn_tab));
+    if (info->sn_tab_num < 0) {
+        info->sn_tab_num = 0;
+    }
+    if (bdrv_get_info(bs, &bdi) >= 0) {
+        info->cluster_size = bdi.cluster_size;
+        info->vm_state_offset = bdi.vm_state_offset;
+        info->is_dirty = bdi.is_dirty;
+    } else {
+        info->cluster_size = -1;
+        info->vm_state_offset = -1;
+        info->is_dirty = -1;
+    }
+    return ret;
+}
diff --git a/libqblock.h b/libqblock.h
new file mode 100644
index 0000000..64a8b96
--- /dev/null
+++ b/libqblock.h
@@ -0,0 +1,72 @@
+#ifndef LIBQBLOCK_H
+#define LIBQBLOCK_H
+
+#include "block.h"
+
+/* details should be hidden to user */
+struct QBlockState {
+    void *bdrvs;
+    char *filename;
+};
+
+/* libarary init or uninit */
+int libqblock_init(void);
+
+/* qbs init and uninit */
+int qbs_init(struct QBlockState *qbs);
+int qbs_uninit(struct QBlockState *qbs);
+
+/* file open and close */
+struct QBlockOpenOption {
+    char *filename;
+    int flag;
+};
+
+struct QBlockCreateOption {
+    char *filename;
+    char *fmt;
+    char *base_filename;
+    char *base_fmt;
+    char *options;
+    unsigned long size;
+    int flag;
+};
+
+int qb_open(struct QBlockState *qbs, struct QBlockOpenOption *op);
+int qb_close(struct QBlockState *qbs);
+
+int qb_create(struct QBlockState *qbs, struct QBlockCreateOption *op);
+int qb_delete(struct QBlockState *qbs, const char *filename);
+
+/* information */
+struct QBlockInfo {
+    /* basic info */
+    char *filename;
+    char *fmt;
+    /* advance info */
+    unsigned long virt_size;
+    unsigned long allocated_size;
+    int encrypt_flag;
+    char *backing_filename;
+    QEMUSnapshotInfo *sn_tab;
+    int sn_tab_num;
+
+    /* in bytes, 0 if irrelevant */
+    int cluster_size;
+    int64_t vm_state_offset;
+    int is_dirty;
+};
+
+/* sync access */
+int qb_read(struct QBlockState *qbs, unsigned long start, unsigned long len,
+                                                          unsigned char *buf);
+int qb_write(struct QBlockState *qbs, unsigned long start, unsigned long len,
+                                                          unsigned char *buf);
+int qb_flush(struct QBlockState *qbs);
+
+/* get info */
+int qbi_init(struct QBlockInfo *info);
+int qbi_uninit(struct QBlockInfo *info);
+int qbi_print_test(struct QBlockInfo *info);
+int qb_getinfo(struct QBlockState *qbs, struct QBlockInfo *info);
+#endif
