diff --git a/Example.lhs b/Example.lhs
new file mode 100644
--- /dev/null
+++ b/Example.lhs
@@ -0,0 +1,86 @@
+Comprehensive walkthough of the functionality provided by this library.
+
+> {-# LANGUAGE OverloadedStrings #-}
+> module Main where
+>
+> import Control.Monad
+> import Data.ByteString.Char8 hiding (take)
+> import Prelude hiding (putStrLn)
+> import System.FilePath
+>
+> import Database.LevelDB
+>
+> import Debug.Trace
+>
+>
+> main :: IO ()
+> main =
+
+Almost all operations on a leveldb database occur within the @withLevelDB@
+bracket, to ensure proper resource de-/allocation.
+
+>     withLevelDB dbdir [ CreateIfMissing, CacheSize 2048 ] $ \db -> do
+
+The basic operations are @put@, @get@ and @delete@, straightforwardly:
+
+>         put db [] "foo" "bar"
+>         get db [ FillCache ] "foo" >>= print
+>         delete db [] "foo"
+>         get db [ FillCache ] "foo" >>= print
+
+Additionally, we can write several key/value pairs in a batch, which is
+guaranteed to be atomic. Note the use of the @Sync@ option here: it tells
+leveldb to flush the data to disk before returning. While syncing may have a
+considerable performance impact, it is most useful with batch operations.
+
+Also note that we're taking a snapshot of the database before issueing the
+write.
+
+>         withSnapshot db $ \snap -> do
+>             write db [ Sync ] [ Put "a" "one"
+>                               , Put "b" "two"
+>                               , Put "c" "three" ]
+
+Now, we can perform a snapshot read. As expected, this will output nothing,
+since we took the snapshot before writing.
+
+>             dumpEntries db [ UseSnapshot snap, FillCache ]
+
+Conversely, we should see the values just written in a "dirty" read:
+
+>             dumpEntries db [ FillCache ]
+
+
+Let's inspect the state of our database, just for the fun of it.
+
+>         approximateSize db ("a", "z") >>= print
+>         getProperty db SSTables >>= printProperty "sstables"
+>         getProperty db Stats    >>= printProperty "stats"
+>         getProperty db (NumFilesAtLevel 1) >>= printProperty "num files at level"
+
+Similar to the batch write above, we can also use @write@ to delete key/value
+pairs:
+
+>         write db [ Sync ] [ Del "a", Del "b", Del "c" ]
+>         dumpEntries db [ FillCache ]
+>
+>     where
+>         dbdir = "/" </> "tmp" </> "leveltest"
+>
+>         dumpEntries db opts =
+>             withIterator db opts $ \iter -> do
+>                 iterFirst iter
+>                 iterEntries iter print
+>
+>         iterEntries iter f = do
+>             valid <- iterValid iter
+>             when valid $ do
+>                 key <- iterKey iter
+>                 val <- iterValue iter
+>                 _   <- f (key, val)
+>                 _   <- iterNext iter
+>                 iterEntries iter f
+>
+>         printProperty l p = do
+>             putStrLn l
+>             maybe (putStrLn "n/a") putStrLn $ p
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2011, Kim Altintop
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Kim Altintop nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Readme.md b/Readme.md
new file mode 100644
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,28 @@
+This library provides Haskell bindings to
+[LevelDB](http://leveldb.googlecode.com)
+
+## Installation
+
+Prerequisites:
+
+* GHC 7.* (http://www.haskell.org/ghc)
+* Cabal (http://www.haskell.org/cabal)
+* `make` and a working C++ compiler
+
+`cabal install` will build and install the package, including the bundled
+LevelDB sources.
+
+## Notes
+
+This library is in very early stage and has seen very limited testing. Comments
+and contributions are welcome.
+
+## Bugs and Contributing
+
+Please report issues via http://github.com/kim/leveldb-haskell/issues.<br />
+Patches are best submitted as pull requests, or via email
+(kim.altintop@gmail.com).
+
+## License
+
+BSD 3, see LICENSE file.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cbits/leveldb/include/leveldb/c.h b/cbits/leveldb/include/leveldb/c.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/c.h
@@ -0,0 +1,246 @@
+/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+  C bindings for leveldb.  May be useful as a stable ABI that can be
+  used by programs that keep leveldb in a shared library, or for
+  a JNI api.
+
+  Does not support:
+  . getters for the option types
+  . custom comparators that implement key shortening
+  . capturing post-write-snapshot
+  . custom iter, db, env, cache implementations using just the C bindings
+
+  Some conventions:
+
+  (1) We expose just opaque struct pointers and functions to clients.
+  This allows us to change internal representations without having to
+  recompile clients.
+
+  (2) For simplicity, there is no equivalent to the Slice type.  Instead,
+  the caller has to pass the pointer and length as separate
+  arguments.
+
+  (3) Errors are represented by a null-terminated c string.  NULL
+  means no error.  All operations that can raise an error are passed
+  a "char** errptr" as the last argument.  One of the following must
+  be true on entry:
+     *errptr == NULL
+     *errptr points to a malloc()ed null-terminated error message
+  On success, a leveldb routine leaves *errptr unchanged.
+  On failure, leveldb frees the old value of *errptr and
+  set *errptr to a malloc()ed error message.
+
+  (4) Bools have the type unsigned char (0 == false; rest == true)
+
+  (5) All of the pointer arguments must be non-NULL.
+*/
+
+#ifndef STORAGE_LEVELDB_INCLUDE_C_H_
+#define STORAGE_LEVELDB_INCLUDE_C_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Exported types */
+
+typedef struct leveldb_t               leveldb_t;
+typedef struct leveldb_cache_t         leveldb_cache_t;
+typedef struct leveldb_comparator_t    leveldb_comparator_t;
+typedef struct leveldb_env_t           leveldb_env_t;
+typedef struct leveldb_filelock_t      leveldb_filelock_t;
+typedef struct leveldb_iterator_t      leveldb_iterator_t;
+typedef struct leveldb_logger_t        leveldb_logger_t;
+typedef struct leveldb_options_t       leveldb_options_t;
+typedef struct leveldb_randomfile_t    leveldb_randomfile_t;
+typedef struct leveldb_readoptions_t   leveldb_readoptions_t;
+typedef struct leveldb_seqfile_t       leveldb_seqfile_t;
+typedef struct leveldb_snapshot_t      leveldb_snapshot_t;
+typedef struct leveldb_writablefile_t  leveldb_writablefile_t;
+typedef struct leveldb_writebatch_t    leveldb_writebatch_t;
+typedef struct leveldb_writeoptions_t  leveldb_writeoptions_t;
+
+/* DB operations */
+
+extern leveldb_t* leveldb_open(
+    const leveldb_options_t* options,
+    const char* name,
+    char** errptr);
+
+extern void leveldb_close(leveldb_t* db);
+
+extern void leveldb_put(
+    leveldb_t* db,
+    const leveldb_writeoptions_t* options,
+    const char* key, size_t keylen,
+    const char* val, size_t vallen,
+    char** errptr);
+
+extern void leveldb_delete(
+    leveldb_t* db,
+    const leveldb_writeoptions_t* options,
+    const char* key, size_t keylen,
+    char** errptr);
+
+extern void leveldb_write(
+    leveldb_t* db,
+    const leveldb_writeoptions_t* options,
+    leveldb_writebatch_t* batch,
+    char** errptr);
+
+/* Returns NULL if not found.  A malloc()ed array otherwise.
+   Stores the length of the array in *vallen. */
+extern char* leveldb_get(
+    leveldb_t* db,
+    const leveldb_readoptions_t* options,
+    const char* key, size_t keylen,
+    size_t* vallen,
+    char** errptr);
+
+extern leveldb_iterator_t* leveldb_create_iterator(
+    leveldb_t* db,
+    const leveldb_readoptions_t* options);
+
+extern const leveldb_snapshot_t* leveldb_create_snapshot(
+    leveldb_t* db);
+
+extern void leveldb_release_snapshot(
+    leveldb_t* db,
+    const leveldb_snapshot_t* snapshot);
+
+/* Returns NULL if property name is unknown.
+   Else returns a pointer to a malloc()-ed null-terminated value. */
+extern char* leveldb_property_value(
+    leveldb_t* db,
+    const char* propname);
+
+extern void leveldb_approximate_sizes(
+    leveldb_t* db,
+    int num_ranges,
+    const char* const* range_start_key, const size_t* range_start_key_len,
+    const char* const* range_limit_key, const size_t* range_limit_key_len,
+    uint64_t* sizes);
+
+/* Management operations */
+
+extern void leveldb_destroy_db(
+    const leveldb_options_t* options,
+    const char* name,
+    char** errptr);
+
+extern void leveldb_repair_db(
+    const leveldb_options_t* options,
+    const char* name,
+    char** errptr);
+
+/* Iterator */
+
+extern void leveldb_iter_destroy(leveldb_iterator_t*);
+extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*);
+extern void leveldb_iter_seek_to_first(leveldb_iterator_t*);
+extern void leveldb_iter_seek_to_last(leveldb_iterator_t*);
+extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen);
+extern void leveldb_iter_next(leveldb_iterator_t*);
+extern void leveldb_iter_prev(leveldb_iterator_t*);
+extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen);
+extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen);
+extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr);
+
+/* Write batch */
+
+extern leveldb_writebatch_t* leveldb_writebatch_create();
+extern void leveldb_writebatch_destroy(leveldb_writebatch_t*);
+extern void leveldb_writebatch_clear(leveldb_writebatch_t*);
+extern void leveldb_writebatch_put(
+    leveldb_writebatch_t*,
+    const char* key, size_t klen,
+    const char* val, size_t vlen);
+extern void leveldb_writebatch_delete(
+    leveldb_writebatch_t*,
+    const char* key, size_t klen);
+extern void leveldb_writebatch_iterate(
+    leveldb_writebatch_t*,
+    void* state,
+    void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen),
+    void (*deleted)(void*, const char* k, size_t klen));
+
+/* Options */
+
+extern leveldb_options_t* leveldb_options_create();
+extern void leveldb_options_destroy(leveldb_options_t*);
+extern void leveldb_options_set_comparator(
+    leveldb_options_t*,
+    leveldb_comparator_t*);
+extern void leveldb_options_set_create_if_missing(
+    leveldb_options_t*, unsigned char);
+extern void leveldb_options_set_error_if_exists(
+    leveldb_options_t*, unsigned char);
+extern void leveldb_options_set_paranoid_checks(
+    leveldb_options_t*, unsigned char);
+extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*);
+extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*);
+extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t);
+extern void leveldb_options_set_max_open_files(leveldb_options_t*, int);
+extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*);
+extern void leveldb_options_set_block_size(leveldb_options_t*, size_t);
+extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int);
+
+enum {
+  leveldb_no_compression = 0,
+  leveldb_snappy_compression = 1
+};
+extern void leveldb_options_set_compression(leveldb_options_t*, int);
+
+/* Comparator */
+
+extern leveldb_comparator_t* leveldb_comparator_create(
+    void* state,
+    void (*destructor)(void*),
+    int (*compare)(
+        void*,
+        const char* a, size_t alen,
+        const char* b, size_t blen),
+    const char* (*name)(void*));
+extern void leveldb_comparator_destroy(leveldb_comparator_t*);
+
+/* Read options */
+
+extern leveldb_readoptions_t* leveldb_readoptions_create();
+extern void leveldb_readoptions_destroy(leveldb_readoptions_t*);
+extern void leveldb_readoptions_set_verify_checksums(
+    leveldb_readoptions_t*,
+    unsigned char);
+extern void leveldb_readoptions_set_fill_cache(
+    leveldb_readoptions_t*, unsigned char);
+extern void leveldb_readoptions_set_snapshot(
+    leveldb_readoptions_t*,
+    const leveldb_snapshot_t*);
+
+/* Write options */
+
+extern leveldb_writeoptions_t* leveldb_writeoptions_create();
+extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*);
+extern void leveldb_writeoptions_set_sync(
+    leveldb_writeoptions_t*, unsigned char);
+
+/* Cache */
+
+extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity);
+extern void leveldb_cache_destroy(leveldb_cache_t* cache);
+
+/* Env */
+
+extern leveldb_env_t* leveldb_create_default_env();
+extern void leveldb_env_destroy(leveldb_env_t*);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif  /* STORAGE_LEVELDB_INCLUDE_C_H_ */
diff --git a/cbits/leveldb/include/leveldb/cache.h b/cbits/leveldb/include/leveldb/cache.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/cache.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// A Cache is an interface that maps keys to values.  It has internal
+// synchronization and may be safely accessed concurrently from
+// multiple threads.  It may automatically evict entries to make room
+// for new entries.  Values have a specified charge against the cache
+// capacity.  For example, a cache where the values are variable
+// length strings, may use the length of the string as the charge for
+// the string.
+//
+// A builtin cache implementation with a least-recently-used eviction
+// policy is provided.  Clients may use their own implementations if
+// they want something more sophisticated (like scan-resistance, a
+// custom eviction policy, variable cache sizing, etc.)
+
+#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_
+#define STORAGE_LEVELDB_INCLUDE_CACHE_H_
+
+#include <stdint.h>
+#include "leveldb/slice.h"
+
+namespace leveldb {
+
+class Cache;
+
+// Create a new cache with a fixed size capacity.  This implementation
+// of Cache uses a least-recently-used eviction policy.
+extern Cache* NewLRUCache(size_t capacity);
+
+class Cache {
+ public:
+  Cache() { }
+
+  // Destroys all existing entries by calling the "deleter"
+  // function that was passed to the constructor.
+  virtual ~Cache();
+
+  // Opaque handle to an entry stored in the cache.
+  struct Handle { };
+
+  // Insert a mapping from key->value into the cache and assign it
+  // the specified charge against the total cache capacity.
+  //
+  // Returns a handle that corresponds to the mapping.  The caller
+  // must call this->Release(handle) when the returned mapping is no
+  // longer needed.
+  //
+  // When the inserted entry is no longer needed, the key and
+  // value will be passed to "deleter".
+  virtual Handle* Insert(const Slice& key, void* value, size_t charge,
+                         void (*deleter)(const Slice& key, void* value)) = 0;
+
+  // If the cache has no mapping for "key", returns NULL.
+  //
+  // Else return a handle that corresponds to the mapping.  The caller
+  // must call this->Release(handle) when the returned mapping is no
+  // longer needed.
+  virtual Handle* Lookup(const Slice& key) = 0;
+
+  // Release a mapping returned by a previous Lookup().
+  // REQUIRES: handle must not have been released yet.
+  // REQUIRES: handle must have been returned by a method on *this.
+  virtual void Release(Handle* handle) = 0;
+
+  // Return the value encapsulated in a handle returned by a
+  // successful Lookup().
+  // REQUIRES: handle must not have been released yet.
+  // REQUIRES: handle must have been returned by a method on *this.
+  virtual void* Value(Handle* handle) = 0;
+
+  // If the cache contains entry for key, erase it.  Note that the
+  // underlying entry will be kept around until all existing handles
+  // to it have been released.
+  virtual void Erase(const Slice& key) = 0;
+
+  // Return a new numeric id.  May be used by multiple clients who are
+  // sharing the same cache to partition the key space.  Typically the
+  // client will allocate a new id at startup and prepend the id to
+  // its cache keys.
+  virtual uint64_t NewId() = 0;
+
+ private:
+  void LRU_Remove(Handle* e);
+  void LRU_Append(Handle* e);
+  void Unref(Handle* e);
+
+  struct Rep;
+  Rep* rep_;
+
+  // No copying allowed
+  Cache(const Cache&);
+  void operator=(const Cache&);
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_UTIL_CACHE_H_
diff --git a/cbits/leveldb/include/leveldb/comparator.h b/cbits/leveldb/include/leveldb/comparator.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/comparator.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
+#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
+
+#include <string>
+
+namespace leveldb {
+
+class Slice;
+
+// A Comparator object provides a total order across slices that are
+// used as keys in an sstable or a database.  A Comparator implementation
+// must be thread-safe since leveldb may invoke its methods concurrently
+// from multiple threads.
+class Comparator {
+ public:
+  virtual ~Comparator();
+
+  // Three-way comparison.  Returns value:
+  //   < 0 iff "a" < "b",
+  //   == 0 iff "a" == "b",
+  //   > 0 iff "a" > "b"
+  virtual int Compare(const Slice& a, const Slice& b) const = 0;
+
+  // The name of the comparator.  Used to check for comparator
+  // mismatches (i.e., a DB created with one comparator is
+  // accessed using a different comparator.
+  //
+  // The client of this package should switch to a new name whenever
+  // the comparator implementation changes in a way that will cause
+  // the relative ordering of any two keys to change.
+  //
+  // Names starting with "leveldb." are reserved and should not be used
+  // by any clients of this package.
+  virtual const char* Name() const = 0;
+
+  // Advanced functions: these are used to reduce the space requirements
+  // for internal data structures like index blocks.
+
+  // If *start < limit, changes *start to a short string in [start,limit).
+  // Simple comparator implementations may return with *start unchanged,
+  // i.e., an implementation of this method that does nothing is correct.
+  virtual void FindShortestSeparator(
+      std::string* start,
+      const Slice& limit) const = 0;
+
+  // Changes *key to a short string >= *key.
+  // Simple comparator implementations may return with *key unchanged,
+  // i.e., an implementation of this method that does nothing is correct.
+  virtual void FindShortSuccessor(std::string* key) const = 0;
+};
+
+// Return a builtin comparator that uses lexicographic byte-wise
+// ordering.  The result remains the property of this module and
+// must not be deleted.
+extern const Comparator* BytewiseComparator();
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
diff --git a/cbits/leveldb/include/leveldb/db.h b/cbits/leveldb/include/leveldb/db.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/db.h
@@ -0,0 +1,160 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_
+#define STORAGE_LEVELDB_INCLUDE_DB_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include "leveldb/iterator.h"
+#include "leveldb/options.h"
+
+namespace leveldb {
+
+static const int kMajorVersion = 1;
+static const int kMinorVersion = 2;
+
+struct Options;
+struct ReadOptions;
+struct WriteOptions;
+class WriteBatch;
+
+// Abstract handle to particular state of a DB.
+// A Snapshot is an immutable object and can therefore be safely
+// accessed from multiple threads without any external synchronization.
+class Snapshot {
+ protected:
+  virtual ~Snapshot();
+};
+
+// A range of keys
+struct Range {
+  Slice start;          // Included in the range
+  Slice limit;          // Not included in the range
+
+  Range() { }
+  Range(const Slice& s, const Slice& l) : start(s), limit(l) { }
+};
+
+// A DB is a persistent ordered map from keys to values.
+// A DB is safe for concurrent access from multiple threads without
+// any external synchronization.
+class DB {
+ public:
+  // Open the database with the specified "name".
+  // Stores a pointer to a heap-allocated database in *dbptr and returns
+  // OK on success.
+  // Stores NULL in *dbptr and returns a non-OK status on error.
+  // Caller should delete *dbptr when it is no longer needed.
+  static Status Open(const Options& options,
+                     const std::string& name,
+                     DB** dbptr);
+
+  DB() { }
+  virtual ~DB();
+
+  // Set the database entry for "key" to "value".  Returns OK on success,
+  // and a non-OK status on error.
+  // Note: consider setting options.sync = true.
+  virtual Status Put(const WriteOptions& options,
+                     const Slice& key,
+                     const Slice& value) = 0;
+
+  // Remove the database entry (if any) for "key".  Returns OK on
+  // success, and a non-OK status on error.  It is not an error if "key"
+  // did not exist in the database.
+  // Note: consider setting options.sync = true.
+  virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;
+
+  // Apply the specified updates to the database.
+  // Returns OK on success, non-OK on failure.
+  // Note: consider setting options.sync = true.
+  virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;
+
+  // If the database contains an entry for "key" store the
+  // corresponding value in *value and return OK.
+  //
+  // If there is no entry for "key" leave *value unchanged and return
+  // a status for which Status::IsNotFound() returns true.
+  //
+  // May return some other Status on an error.
+  virtual Status Get(const ReadOptions& options,
+                     const Slice& key, std::string* value) = 0;
+
+  // Return a heap-allocated iterator over the contents of the database.
+  // The result of NewIterator() is initially invalid (caller must
+  // call one of the Seek methods on the iterator before using it).
+  //
+  // Caller should delete the iterator when it is no longer needed.
+  // The returned iterator should be deleted before this db is deleted.
+  virtual Iterator* NewIterator(const ReadOptions& options) = 0;
+
+  // Return a handle to the current DB state.  Iterators created with
+  // this handle will all observe a stable snapshot of the current DB
+  // state.  The caller must call ReleaseSnapshot(result) when the
+  // snapshot is no longer needed.
+  virtual const Snapshot* GetSnapshot() = 0;
+
+  // Release a previously acquired snapshot.  The caller must not
+  // use "snapshot" after this call.
+  virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;
+
+  // DB implementations can export properties about their state
+  // via this method.  If "property" is a valid property understood by this
+  // DB implementation, fills "*value" with its current value and returns
+  // true.  Otherwise returns false.
+  //
+  //
+  // Valid property names include:
+  //
+  //  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
+  //     where <N> is an ASCII representation of a level number (e.g. "0").
+  //  "leveldb.stats" - returns a multi-line string that describes statistics
+  //     about the internal operation of the DB.
+  //  "leveldb.sstables" - returns a multi-line string that describes all
+  //     of the sstables that make up the db contents.
+  virtual bool GetProperty(const Slice& property, std::string* value) = 0;
+
+  // For each i in [0,n-1], store in "sizes[i]", the approximate
+  // file system space used by keys in "[range[i].start .. range[i].limit)".
+  //
+  // Note that the returned sizes measure file system space usage, so
+  // if the user data compresses by a factor of ten, the returned
+  // sizes will be one-tenth the size of the corresponding user data size.
+  //
+  // The results may not include the sizes of recently written data.
+  virtual void GetApproximateSizes(const Range* range, int n,
+                                   uint64_t* sizes) = 0;
+
+  // Compact the underlying storage for the key range [*begin,*end].
+  // In particular, deleted and overwritten versions are discarded,
+  // and the data is rearranged to reduce the cost of operations
+  // needed to access the data.  This operation should typically only
+  // be invoked by users who understand the underlying implementation.
+  //
+  // begin==NULL is treated as a key before all keys in the database.
+  // end==NULL is treated as a key after all keys in the database.
+  // Therefore the following call will compact the entire database:
+  //    db->CompactRange(NULL, NULL);
+  virtual void CompactRange(const Slice* begin, const Slice* end) = 0;
+
+ private:
+  // No copying allowed
+  DB(const DB&);
+  void operator=(const DB&);
+};
+
+// Destroy the contents of the specified database.
+// Be very careful using this method.
+Status DestroyDB(const std::string& name, const Options& options);
+
+// If a DB cannot be opened, you may attempt to call this method to
+// resurrect as much of the contents of the database as possible.
+// Some data may be lost, so be careful when calling this function
+// on a database that contains important information.
+Status RepairDB(const std::string& dbname, const Options& options);
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_DB_H_
diff --git a/cbits/leveldb/include/leveldb/env.h b/cbits/leveldb/include/leveldb/env.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/env.h
@@ -0,0 +1,323 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// An Env is an interface used by the leveldb implementation to access
+// operating system functionality like the filesystem etc.  Callers
+// may wish to provide a custom Env object when opening a database to
+// get fine gain control; e.g., to rate limit file system operations.
+//
+// All Env implementations are safe for concurrent access from
+// multiple threads without any external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_
+#define STORAGE_LEVELDB_INCLUDE_ENV_H_
+
+#include <cstdarg>
+#include <string>
+#include <vector>
+#include <stdint.h>
+#include "leveldb/status.h"
+
+namespace leveldb {
+
+class FileLock;
+class Logger;
+class RandomAccessFile;
+class SequentialFile;
+class Slice;
+class WritableFile;
+
+class Env {
+ public:
+  Env() { }
+  virtual ~Env();
+
+  // Return a default environment suitable for the current operating
+  // system.  Sophisticated users may wish to provide their own Env
+  // implementation instead of relying on this default environment.
+  //
+  // The result of Default() belongs to leveldb and must never be deleted.
+  static Env* Default();
+
+  // Create a brand new sequentially-readable file with the specified name.
+  // On success, stores a pointer to the new file in *result and returns OK.
+  // On failure stores NULL in *result and returns non-OK.  If the file does
+  // not exist, returns a non-OK status.
+  //
+  // The returned file will only be accessed by one thread at a time.
+  virtual Status NewSequentialFile(const std::string& fname,
+                                   SequentialFile** result) = 0;
+
+  // Create a brand new random access read-only file with the
+  // specified name.  On success, stores a pointer to the new file in
+  // *result and returns OK.  On failure stores NULL in *result and
+  // returns non-OK.  If the file does not exist, returns a non-OK
+  // status.
+  //
+  // The returned file may be concurrently accessed by multiple threads.
+  virtual Status NewRandomAccessFile(const std::string& fname,
+                                     RandomAccessFile** result) = 0;
+
+  // Create an object that writes to a new file with the specified
+  // name.  Deletes any existing file with the same name and creates a
+  // new file.  On success, stores a pointer to the new file in
+  // *result and returns OK.  On failure stores NULL in *result and
+  // returns non-OK.
+  //
+  // The returned file will only be accessed by one thread at a time.
+  virtual Status NewWritableFile(const std::string& fname,
+                                 WritableFile** result) = 0;
+
+  // Returns true iff the named file exists.
+  virtual bool FileExists(const std::string& fname) = 0;
+
+  // Store in *result the names of the children of the specified directory.
+  // The names are relative to "dir".
+  // Original contents of *results are dropped.
+  virtual Status GetChildren(const std::string& dir,
+                             std::vector<std::string>* result) = 0;
+
+  // Delete the named file.
+  virtual Status DeleteFile(const std::string& fname) = 0;
+
+  // Create the specified directory.
+  virtual Status CreateDir(const std::string& dirname) = 0;
+
+  // Delete the specified directory.
+  virtual Status DeleteDir(const std::string& dirname) = 0;
+
+  // Store the size of fname in *file_size.
+  virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0;
+
+  // Rename file src to target.
+  virtual Status RenameFile(const std::string& src,
+                            const std::string& target) = 0;
+
+  // Lock the specified file.  Used to prevent concurrent access to
+  // the same db by multiple processes.  On failure, stores NULL in
+  // *lock and returns non-OK.
+  //
+  // On success, stores a pointer to the object that represents the
+  // acquired lock in *lock and returns OK.  The caller should call
+  // UnlockFile(*lock) to release the lock.  If the process exits,
+  // the lock will be automatically released.
+  //
+  // If somebody else already holds the lock, finishes immediately
+  // with a failure.  I.e., this call does not wait for existing locks
+  // to go away.
+  //
+  // May create the named file if it does not already exist.
+  virtual Status LockFile(const std::string& fname, FileLock** lock) = 0;
+
+  // Release the lock acquired by a previous successful call to LockFile.
+  // REQUIRES: lock was returned by a successful LockFile() call
+  // REQUIRES: lock has not already been unlocked.
+  virtual Status UnlockFile(FileLock* lock) = 0;
+
+  // Arrange to run "(*function)(arg)" once in a background thread.
+  //
+  // "function" may run in an unspecified thread.  Multiple functions
+  // added to the same Env may run concurrently in different threads.
+  // I.e., the caller may not assume that background work items are
+  // serialized.
+  virtual void Schedule(
+      void (*function)(void* arg),
+      void* arg) = 0;
+
+  // Start a new thread, invoking "function(arg)" within the new thread.
+  // When "function(arg)" returns, the thread will be destroyed.
+  virtual void StartThread(void (*function)(void* arg), void* arg) = 0;
+
+  // *path is set to a temporary directory that can be used for testing. It may
+  // or many not have just been created. The directory may or may not differ
+  // between runs of the same process, but subsequent calls will return the
+  // same directory.
+  virtual Status GetTestDirectory(std::string* path) = 0;
+
+  // Create and return a log file for storing informational messages.
+  virtual Status NewLogger(const std::string& fname, Logger** result) = 0;
+
+  // Returns the number of micro-seconds since some fixed point in time. Only
+  // useful for computing deltas of time.
+  virtual uint64_t NowMicros() = 0;
+
+  // Sleep/delay the thread for the perscribed number of micro-seconds.
+  virtual void SleepForMicroseconds(int micros) = 0;
+
+ private:
+  // No copying allowed
+  Env(const Env&);
+  void operator=(const Env&);
+};
+
+// A file abstraction for reading sequentially through a file
+class SequentialFile {
+ public:
+  SequentialFile() { }
+  virtual ~SequentialFile();
+
+  // Read up to "n" bytes from the file.  "scratch[0..n-1]" may be
+  // written by this routine.  Sets "*result" to the data that was
+  // read (including if fewer than "n" bytes were successfully read).
+  // May set "*result" to point at data in "scratch[0..n-1]", so
+  // "scratch[0..n-1]" must be live when "*result" is used.
+  // If an error was encountered, returns a non-OK status.
+  //
+  // REQUIRES: External synchronization
+  virtual Status Read(size_t n, Slice* result, char* scratch) = 0;
+
+  // Skip "n" bytes from the file. This is guaranteed to be no
+  // slower that reading the same data, but may be faster.
+  //
+  // If end of file is reached, skipping will stop at the end of the
+  // file, and Skip will return OK.
+  //
+  // REQUIRES: External synchronization
+  virtual Status Skip(uint64_t n) = 0;
+};
+
+// A file abstraction for randomly reading the contents of a file.
+class RandomAccessFile {
+ public:
+  RandomAccessFile() { }
+  virtual ~RandomAccessFile();
+
+  // Read up to "n" bytes from the file starting at "offset".
+  // "scratch[0..n-1]" may be written by this routine.  Sets "*result"
+  // to the data that was read (including if fewer than "n" bytes were
+  // successfully read).  May set "*result" to point at data in
+  // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
+  // "*result" is used.  If an error was encountered, returns a non-OK
+  // status.
+  //
+  // Safe for concurrent use by multiple threads.
+  virtual Status Read(uint64_t offset, size_t n, Slice* result,
+                      char* scratch) const = 0;
+};
+
+// A file abstraction for sequential writing.  The implementation
+// must provide buffering since callers may append small fragments
+// at a time to the file.
+class WritableFile {
+ public:
+  WritableFile() { }
+  virtual ~WritableFile();
+
+  virtual Status Append(const Slice& data) = 0;
+  virtual Status Close() = 0;
+  virtual Status Flush() = 0;
+  virtual Status Sync() = 0;
+
+ private:
+  // No copying allowed
+  WritableFile(const WritableFile&);
+  void operator=(const WritableFile&);
+};
+
+// An interface for writing log messages.
+class Logger {
+ public:
+  Logger() { }
+  virtual ~Logger();
+
+  // Write an entry to the log file with the specified format.
+  virtual void Logv(const char* format, va_list ap) = 0;
+
+ private:
+  // No copying allowed
+  Logger(const Logger&);
+  void operator=(const Logger&);
+};
+
+
+// Identifies a locked file.
+class FileLock {
+ public:
+  FileLock() { }
+  virtual ~FileLock();
+ private:
+  // No copying allowed
+  FileLock(const FileLock&);
+  void operator=(const FileLock&);
+};
+
+// Log the specified data to *info_log if info_log is non-NULL.
+extern void Log(Logger* info_log, const char* format, ...)
+#   if defined(__GNUC__) || defined(__clang__)
+    __attribute__((__format__ (__printf__, 2, 3)))
+#   endif
+    ;
+
+// A utility routine: write "data" to the named file.
+extern Status WriteStringToFile(Env* env, const Slice& data,
+                                const std::string& fname);
+
+// A utility routine: read contents of named file into *data
+extern Status ReadFileToString(Env* env, const std::string& fname,
+                               std::string* data);
+
+// An implementation of Env that forwards all calls to another Env.
+// May be useful to clients who wish to override just part of the
+// functionality of another Env.
+class EnvWrapper : public Env {
+ public:
+  // Initialize an EnvWrapper that delegates all calls to *t
+  explicit EnvWrapper(Env* t) : target_(t) { }
+  virtual ~EnvWrapper();
+
+  // Return the target to which this Env forwards all calls
+  Env* target() const { return target_; }
+
+  // The following text is boilerplate that forwards all methods to target()
+  Status NewSequentialFile(const std::string& f, SequentialFile** r) {
+    return target_->NewSequentialFile(f, r);
+  }
+  Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) {
+    return target_->NewRandomAccessFile(f, r);
+  }
+  Status NewWritableFile(const std::string& f, WritableFile** r) {
+    return target_->NewWritableFile(f, r);
+  }
+  bool FileExists(const std::string& f) { return target_->FileExists(f); }
+  Status GetChildren(const std::string& dir, std::vector<std::string>* r) {
+    return target_->GetChildren(dir, r);
+  }
+  Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); }
+  Status CreateDir(const std::string& d) { return target_->CreateDir(d); }
+  Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); }
+  Status GetFileSize(const std::string& f, uint64_t* s) {
+    return target_->GetFileSize(f, s);
+  }
+  Status RenameFile(const std::string& s, const std::string& t) {
+    return target_->RenameFile(s, t);
+  }
+  Status LockFile(const std::string& f, FileLock** l) {
+    return target_->LockFile(f, l);
+  }
+  Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); }
+  void Schedule(void (*f)(void*), void* a) {
+    return target_->Schedule(f, a);
+  }
+  void StartThread(void (*f)(void*), void* a) {
+    return target_->StartThread(f, a);
+  }
+  virtual Status GetTestDirectory(std::string* path) {
+    return target_->GetTestDirectory(path);
+  }
+  virtual Status NewLogger(const std::string& fname, Logger** result) {
+    return target_->NewLogger(fname, result);
+  }
+  uint64_t NowMicros() {
+    return target_->NowMicros();
+  }
+  void SleepForMicroseconds(int micros) {
+    target_->SleepForMicroseconds(micros);
+  }
+ private:
+  Env* target_;
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_ENV_H_
diff --git a/cbits/leveldb/include/leveldb/iterator.h b/cbits/leveldb/include/leveldb/iterator.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/iterator.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// An iterator yields a sequence of key/value pairs from a source.
+// The following class defines the interface.  Multiple implementations
+// are provided by this library.  In particular, iterators are provided
+// to access the contents of a Table or a DB.
+//
+// Multiple threads can invoke const methods on an Iterator without
+// external synchronization, but if any of the threads may call a
+// non-const method, all threads accessing the same Iterator must use
+// external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
+#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
+
+#include "leveldb/slice.h"
+#include "leveldb/status.h"
+
+namespace leveldb {
+
+class Iterator {
+ public:
+  Iterator();
+  virtual ~Iterator();
+
+  // An iterator is either positioned at a key/value pair, or
+  // not valid.  This method returns true iff the iterator is valid.
+  virtual bool Valid() const = 0;
+
+  // Position at the first key in the source.  The iterator is Valid()
+  // after this call iff the source is not empty.
+  virtual void SeekToFirst() = 0;
+
+  // Position at the last key in the source.  The iterator is
+  // Valid() after this call iff the source is not empty.
+  virtual void SeekToLast() = 0;
+
+  // Position at the first key in the source that at or past target
+  // The iterator is Valid() after this call iff the source contains
+  // an entry that comes at or past target.
+  virtual void Seek(const Slice& target) = 0;
+
+  // Moves to the next entry in the source.  After this call, Valid() is
+  // true iff the iterator was not positioned at the last entry in the source.
+  // REQUIRES: Valid()
+  virtual void Next() = 0;
+
+  // Moves to the previous entry in the source.  After this call, Valid() is
+  // true iff the iterator was not positioned at the first entry in source.
+  // REQUIRES: Valid()
+  virtual void Prev() = 0;
+
+  // Return the key for the current entry.  The underlying storage for
+  // the returned slice is valid only until the next modification of
+  // the iterator.
+  // REQUIRES: Valid()
+  virtual Slice key() const = 0;
+
+  // Return the value for the current entry.  The underlying storage for
+  // the returned slice is valid only until the next modification of
+  // the iterator.
+  // REQUIRES: !AtEnd() && !AtStart()
+  virtual Slice value() const = 0;
+
+  // If an error has occurred, return it.  Else return an ok status.
+  virtual Status status() const = 0;
+
+  // Clients are allowed to register function/arg1/arg2 triples that
+  // will be invoked when this iterator is destroyed.
+  //
+  // Note that unlike all of the preceding methods, this method is
+  // not abstract and therefore clients should not override it.
+  typedef void (*CleanupFunction)(void* arg1, void* arg2);
+  void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2);
+
+ private:
+  struct Cleanup {
+    CleanupFunction function;
+    void* arg1;
+    void* arg2;
+    Cleanup* next;
+  };
+  Cleanup cleanup_;
+
+  // No copying allowed
+  Iterator(const Iterator&);
+  void operator=(const Iterator&);
+};
+
+// Return an empty iterator (yields nothing).
+extern Iterator* NewEmptyIterator();
+
+// Return an empty iterator with the specified status.
+extern Iterator* NewErrorIterator(const Status& status);
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
diff --git a/cbits/leveldb/include/leveldb/options.h b/cbits/leveldb/include/leveldb/options.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/options.h
@@ -0,0 +1,187 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
+#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
+
+#include <stddef.h>
+
+namespace leveldb {
+
+class Cache;
+class Comparator;
+class Env;
+class Logger;
+class Snapshot;
+
+// DB contents are stored in a set of blocks, each of which holds a
+// sequence of key,value pairs.  Each block may be compressed before
+// being stored in a file.  The following enum describes which
+// compression method (if any) is used to compress a block.
+enum CompressionType {
+  // NOTE: do not change the values of existing entries, as these are
+  // part of the persistent format on disk.
+  kNoCompression     = 0x0,
+  kSnappyCompression = 0x1
+};
+
+// Options to control the behavior of a database (passed to DB::Open)
+struct Options {
+  // -------------------
+  // Parameters that affect behavior
+
+  // Comparator used to define the order of keys in the table.
+  // Default: a comparator that uses lexicographic byte-wise ordering
+  //
+  // REQUIRES: The client must ensure that the comparator supplied
+  // here has the same name and orders keys *exactly* the same as the
+  // comparator provided to previous open calls on the same DB.
+  const Comparator* comparator;
+
+  // If true, the database will be created if it is missing.
+  // Default: false
+  bool create_if_missing;
+
+  // If true, an error is raised if the database already exists.
+  // Default: false
+  bool error_if_exists;
+
+  // If true, the implementation will do aggressive checking of the
+  // data it is processing and will stop early if it detects any
+  // errors.  This may have unforeseen ramifications: for example, a
+  // corruption of one DB entry may cause a large number of entries to
+  // become unreadable or for the entire DB to become unopenable.
+  // Default: false
+  bool paranoid_checks;
+
+  // Use the specified object to interact with the environment,
+  // e.g. to read/write files, schedule background work, etc.
+  // Default: Env::Default()
+  Env* env;
+
+  // Any internal progress/error information generated by the db will
+  // be written to info_log if it is non-NULL, or to a file stored
+  // in the same directory as the DB contents if info_log is NULL.
+  // Default: NULL
+  Logger* info_log;
+
+  // -------------------
+  // Parameters that affect performance
+
+  // Amount of data to build up in memory (backed by an unsorted log
+  // on disk) before converting to a sorted on-disk file.
+  //
+  // Larger values increase performance, especially during bulk loads.
+  // Up to two write buffers may be held in memory at the same time,
+  // so you may wish to adjust this parameter to control memory usage.
+  // Also, a larger write buffer will result in a longer recovery time
+  // the next time the database is opened.
+  //
+  // Default: 4MB
+  size_t write_buffer_size;
+
+  // Number of open files that can be used by the DB.  You may need to
+  // increase this if your database has a large working set (budget
+  // one open file per 2MB of working set).
+  //
+  // Default: 1000
+  int max_open_files;
+
+  // Control over blocks (user data is stored in a set of blocks, and
+  // a block is the unit of reading from disk).
+
+  // If non-NULL, use the specified cache for blocks.
+  // If NULL, leveldb will automatically create and use an 8MB internal cache.
+  // Default: NULL
+  Cache* block_cache;
+
+  // Approximate size of user data packed per block.  Note that the
+  // block size specified here corresponds to uncompressed data.  The
+  // actual size of the unit read from disk may be smaller if
+  // compression is enabled.  This parameter can be changed dynamically.
+  //
+  // Default: 4K
+  size_t block_size;
+
+  // Number of keys between restart points for delta encoding of keys.
+  // This parameter can be changed dynamically.  Most clients should
+  // leave this parameter alone.
+  //
+  // Default: 16
+  int block_restart_interval;
+
+  // Compress blocks using the specified compression algorithm.  This
+  // parameter can be changed dynamically.
+  //
+  // Default: kSnappyCompression, which gives lightweight but fast
+  // compression.
+  //
+  // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:
+  //    ~200-500MB/s compression
+  //    ~400-800MB/s decompression
+  // Note that these speeds are significantly faster than most
+  // persistent storage speeds, and therefore it is typically never
+  // worth switching to kNoCompression.  Even if the input data is
+  // incompressible, the kSnappyCompression implementation will
+  // efficiently detect that and will switch to uncompressed mode.
+  CompressionType compression;
+
+  // Create an Options object with default values for all fields.
+  Options();
+};
+
+// Options that control read operations
+struct ReadOptions {
+  // If true, all data read from underlying storage will be
+  // verified against corresponding checksums.
+  // Default: false
+  bool verify_checksums;
+
+  // Should the data read for this iteration be cached in memory?
+  // Callers may wish to set this field to false for bulk scans.
+  // Default: true
+  bool fill_cache;
+
+  // If "snapshot" is non-NULL, read as of the supplied snapshot
+  // (which must belong to the DB that is being read and which must
+  // not have been released).  If "snapshot" is NULL, use an impliicit
+  // snapshot of the state at the beginning of this read operation.
+  // Default: NULL
+  const Snapshot* snapshot;
+
+  ReadOptions()
+      : verify_checksums(false),
+        fill_cache(true),
+        snapshot(NULL) {
+  }
+};
+
+// Options that control write operations
+struct WriteOptions {
+  // If true, the write will be flushed from the operating system
+  // buffer cache (by calling WritableFile::Sync()) before the write
+  // is considered complete.  If this flag is true, writes will be
+  // slower.
+  //
+  // If this flag is false, and the machine crashes, some recent
+  // writes may be lost.  Note that if it is just the process that
+  // crashes (i.e., the machine does not reboot), no writes will be
+  // lost even if sync==false.
+  //
+  // In other words, a DB write with sync==false has similar
+  // crash semantics as the "write()" system call.  A DB write
+  // with sync==true has similar crash semantics to a "write()"
+  // system call followed by "fsync()".
+  //
+  // Default: false
+  bool sync;
+
+  WriteOptions()
+      : sync(false) {
+  }
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
diff --git a/cbits/leveldb/include/leveldb/slice.h b/cbits/leveldb/include/leveldb/slice.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/slice.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// Slice is a simple structure containing a pointer into some external
+// storage and a size.  The user of a Slice must ensure that the slice
+// is not used after the corresponding external storage has been
+// deallocated.
+//
+// Multiple threads can invoke const methods on a Slice without
+// external synchronization, but if any of the threads may call a
+// non-const method, all threads accessing the same Slice must use
+// external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_
+#define STORAGE_LEVELDB_INCLUDE_SLICE_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+
+namespace leveldb {
+
+class Slice {
+ public:
+  // Create an empty slice.
+  Slice() : data_(""), size_(0) { }
+
+  // Create a slice that refers to d[0,n-1].
+  Slice(const char* d, size_t n) : data_(d), size_(n) { }
+
+  // Create a slice that refers to the contents of "s"
+  Slice(const std::string& s) : data_(s.data()), size_(s.size()) { }
+
+  // Create a slice that refers to s[0,strlen(s)-1]
+  Slice(const char* s) : data_(s), size_(strlen(s)) { }
+
+  // Return a pointer to the beginning of the referenced data
+  const char* data() const { return data_; }
+
+  // Return the length (in bytes) of the referenced data
+  size_t size() const { return size_; }
+
+  // Return true iff the length of the referenced data is zero
+  bool empty() const { return size_ == 0; }
+
+  // Return the ith byte in the referenced data.
+  // REQUIRES: n < size()
+  char operator[](size_t n) const {
+    assert(n < size());
+    return data_[n];
+  }
+
+  // Change this slice to refer to an empty array
+  void clear() { data_ = ""; size_ = 0; }
+
+  // Drop the first "n" bytes from this slice.
+  void remove_prefix(size_t n) {
+    assert(n <= size());
+    data_ += n;
+    size_ -= n;
+  }
+
+  // Return a string that contains the copy of the referenced data.
+  std::string ToString() const { return std::string(data_, size_); }
+
+  // Three-way comparison.  Returns value:
+  //   <  0 iff "*this" <  "b",
+  //   == 0 iff "*this" == "b",
+  //   >  0 iff "*this" >  "b"
+  int compare(const Slice& b) const;
+
+  // Return true iff "x" is a prefix of "*this"
+  bool starts_with(const Slice& x) const {
+    return ((size_ >= x.size_) &&
+            (memcmp(data_, x.data_, x.size_) == 0));
+  }
+
+ private:
+  const char* data_;
+  size_t size_;
+
+  // Intentionally copyable
+};
+
+inline bool operator==(const Slice& x, const Slice& y) {
+  return ((x.size() == y.size()) &&
+          (memcmp(x.data(), y.data(), x.size()) == 0));
+}
+
+inline bool operator!=(const Slice& x, const Slice& y) {
+  return !(x == y);
+}
+
+inline int Slice::compare(const Slice& b) const {
+  const int min_len = (size_ < b.size_) ? size_ : b.size_;
+  int r = memcmp(data_, b.data_, min_len);
+  if (r == 0) {
+    if (size_ < b.size_) r = -1;
+    else if (size_ > b.size_) r = +1;
+  }
+  return r;
+}
+
+}  // namespace leveldb
+
+
+#endif  // STORAGE_LEVELDB_INCLUDE_SLICE_H_
diff --git a/cbits/leveldb/include/leveldb/status.h b/cbits/leveldb/include/leveldb/status.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/status.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// A Status encapsulates the result of an operation.  It may indicate success,
+// or it may indicate an error with an associated error message.
+//
+// Multiple threads can invoke const methods on a Status without
+// external synchronization, but if any of the threads may call a
+// non-const method, all threads accessing the same Status must use
+// external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_
+#define STORAGE_LEVELDB_INCLUDE_STATUS_H_
+
+#include <string>
+#include "leveldb/slice.h"
+
+namespace leveldb {
+
+class Status {
+ public:
+  // Create a success status.
+  Status() : state_(NULL) { }
+  ~Status() { delete[] state_; }
+
+  // Copy the specified status.
+  Status(const Status& s);
+  void operator=(const Status& s);
+
+  // Return a success status.
+  static Status OK() { return Status(); }
+
+  // Return error status of an appropriate type.
+  static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {
+    return Status(kNotFound, msg, msg2);
+  }
+  static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {
+    return Status(kCorruption, msg, msg2);
+  }
+  static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {
+    return Status(kNotSupported, msg, msg2);
+  }
+  static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {
+    return Status(kInvalidArgument, msg, msg2);
+  }
+  static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {
+    return Status(kIOError, msg, msg2);
+  }
+
+  // Returns true iff the status indicates success.
+  bool ok() const { return (state_ == NULL); }
+
+  // Returns true iff the status indicates a NotFound error.
+  bool IsNotFound() const { return code() == kNotFound; }
+
+  // Return a string representation of this status suitable for printing.
+  // Returns the string "OK" for success.
+  std::string ToString() const;
+
+ private:
+  // OK status has a NULL state_.  Otherwise, state_ is a new[] array
+  // of the following form:
+  //    state_[0..3] == length of message
+  //    state_[4]    == code
+  //    state_[5..]  == message
+  const char* state_;
+
+  enum Code {
+    kOk = 0,
+    kNotFound = 1,
+    kCorruption = 2,
+    kNotSupported = 3,
+    kInvalidArgument = 4,
+    kIOError = 5
+  };
+
+  Code code() const {
+    return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);
+  }
+
+  Status(Code code, const Slice& msg, const Slice& msg2);
+  static const char* CopyState(const char* s);
+};
+
+inline Status::Status(const Status& s) {
+  state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
+}
+inline void Status::operator=(const Status& s) {
+  // The following condition catches both aliasing (when this == &s),
+  // and the common case where both s and *this are ok.
+  if (state_ != s.state_) {
+    delete[] state_;
+    state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
+  }
+}
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_STATUS_H_
diff --git a/cbits/leveldb/include/leveldb/table.h b/cbits/leveldb/include/leveldb/table.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/table.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_
+#define STORAGE_LEVELDB_INCLUDE_TABLE_H_
+
+#include <stdint.h>
+#include "leveldb/iterator.h"
+
+namespace leveldb {
+
+class Block;
+class BlockHandle;
+struct Options;
+class RandomAccessFile;
+struct ReadOptions;
+
+// A Table is a sorted map from strings to strings.  Tables are
+// immutable and persistent.  A Table may be safely accessed from
+// multiple threads without external synchronization.
+class Table {
+ public:
+  // Attempt to open the table that is stored in bytes [0..file_size)
+  // of "file", and read the metadata entries necessary to allow
+  // retrieving data from the table.
+  //
+  // If successful, returns ok and sets "*table" to the newly opened
+  // table.  The client should delete "*table" when no longer needed.
+  // If there was an error while initializing the table, sets "*table"
+  // to NULL and returns a non-ok status.  Does not take ownership of
+  // "*source", but the client must ensure that "source" remains live
+  // for the duration of the returned table's lifetime.
+  //
+  // *file must remain live while this Table is in use.
+  static Status Open(const Options& options,
+                     RandomAccessFile* file,
+                     uint64_t file_size,
+                     Table** table);
+
+  ~Table();
+
+  // Returns a new iterator over the table contents.
+  // The result of NewIterator() is initially invalid (caller must
+  // call one of the Seek methods on the iterator before using it).
+  Iterator* NewIterator(const ReadOptions&) const;
+
+  // Given a key, return an approximate byte offset in the file where
+  // the data for that key begins (or would begin if the key were
+  // present in the file).  The returned value is in terms of file
+  // bytes, and so includes effects like compression of the underlying data.
+  // E.g., the approximate offset of the last key in the table will
+  // be close to the file length.
+  uint64_t ApproximateOffsetOf(const Slice& key) const;
+
+ private:
+  struct Rep;
+  Rep* rep_;
+
+  explicit Table(Rep* rep) { rep_ = rep; }
+  static Iterator* BlockReader(void*, const ReadOptions&, const Slice&);
+
+  // No copying allowed
+  Table(const Table&);
+  void operator=(const Table&);
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_H_
diff --git a/cbits/leveldb/include/leveldb/table_builder.h b/cbits/leveldb/include/leveldb/table_builder.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/table_builder.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// TableBuilder provides the interface used to build a Table
+// (an immutable and sorted map from keys to values).
+//
+// Multiple threads can invoke const methods on a TableBuilder without
+// external synchronization, but if any of the threads may call a
+// non-const method, all threads accessing the same TableBuilder must use
+// external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_
+#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_
+
+#include <stdint.h>
+#include "leveldb/options.h"
+#include "leveldb/status.h"
+
+namespace leveldb {
+
+class BlockBuilder;
+class BlockHandle;
+class WritableFile;
+
+class TableBuilder {
+ public:
+  // Create a builder that will store the contents of the table it is
+  // building in *file.  Does not close the file.  It is up to the
+  // caller to close the file after calling Finish().
+  TableBuilder(const Options& options, WritableFile* file);
+
+  // REQUIRES: Either Finish() or Abandon() has been called.
+  ~TableBuilder();
+
+  // Change the options used by this builder.  Note: only some of the
+  // option fields can be changed after construction.  If a field is
+  // not allowed to change dynamically and its value in the structure
+  // passed to the constructor is different from its value in the
+  // structure passed to this method, this method will return an error
+  // without changing any fields.
+  Status ChangeOptions(const Options& options);
+
+  // Add key,value to the table being constructed.
+  // REQUIRES: key is after any previously added key according to comparator.
+  // REQUIRES: Finish(), Abandon() have not been called
+  void Add(const Slice& key, const Slice& value);
+
+  // Advanced operation: flush any buffered key/value pairs to file.
+  // Can be used to ensure that two adjacent entries never live in
+  // the same data block.  Most clients should not need to use this method.
+  // REQUIRES: Finish(), Abandon() have not been called
+  void Flush();
+
+  // Return non-ok iff some error has been detected.
+  Status status() const;
+
+  // Finish building the table.  Stops using the file passed to the
+  // constructor after this function returns.
+  // REQUIRES: Finish(), Abandon() have not been called
+  Status Finish();
+
+  // Indicate that the contents of this builder should be abandoned.  Stops
+  // using the file passed to the constructor after this function returns.
+  // If the caller is not going to call Finish(), it must call Abandon()
+  // before destroying this builder.
+  // REQUIRES: Finish(), Abandon() have not been called
+  void Abandon();
+
+  // Number of calls to Add() so far.
+  uint64_t NumEntries() const;
+
+  // Size of the file generated so far.  If invoked after a successful
+  // Finish() call, returns the size of the final generated file.
+  uint64_t FileSize() const;
+
+ private:
+  bool ok() const { return status().ok(); }
+  void WriteBlock(BlockBuilder* block, BlockHandle* handle);
+
+  struct Rep;
+  Rep* rep_;
+
+  // No copying allowed
+  TableBuilder(const TableBuilder&);
+  void operator=(const TableBuilder&);
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_
diff --git a/cbits/leveldb/include/leveldb/write_batch.h b/cbits/leveldb/include/leveldb/write_batch.h
new file mode 100644
--- /dev/null
+++ b/cbits/leveldb/include/leveldb/write_batch.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// WriteBatch holds a collection of updates to apply atomically to a DB.
+//
+// The updates are applied in the order in which they are added
+// to the WriteBatch.  For example, the value of "key" will be "v3"
+// after the following batch is written:
+//
+//    batch.Put("key", "v1");
+//    batch.Delete("key");
+//    batch.Put("key", "v2");
+//    batch.Put("key", "v3");
+//
+// Multiple threads can invoke const methods on a WriteBatch without
+// external synchronization, but if any of the threads may call a
+// non-const method, all threads accessing the same WriteBatch must use
+// external synchronization.
+
+#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_
+#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_
+
+#include <string>
+#include "leveldb/status.h"
+
+namespace leveldb {
+
+class Slice;
+
+class WriteBatch {
+ public:
+  WriteBatch();
+  ~WriteBatch();
+
+  // Store the mapping "key->value" in the database.
+  void Put(const Slice& key, const Slice& value);
+
+  // If the database contains a mapping for "key", erase it.  Else do nothing.
+  void Delete(const Slice& key);
+
+  // Clear all updates buffered in this batch.
+  void Clear();
+
+  // Support for iterating over the contents of a batch.
+  class Handler {
+   public:
+    virtual ~Handler();
+    virtual void Put(const Slice& key, const Slice& value) = 0;
+    virtual void Delete(const Slice& key) = 0;
+  };
+  Status Iterate(Handler* handler) const;
+
+ private:
+  friend class WriteBatchInternal;
+
+  std::string rep_;  // See comment in write_batch.cc for the format of rep_
+
+  // Intentionally copyable
+};
+
+}  // namespace leveldb
+
+#endif  // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_
diff --git a/configure b/configure
new file mode 100644
--- /dev/null
+++ b/configure
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+make --directory=cbits/leveldb libleveldb.a
+echo extra-lib-dirs: `pwd`/cbits/leveldb > leveldb-haskell.buildinfo
diff --git a/leveldb-haskell.cabal b/leveldb-haskell.cabal
new file mode 100644
--- /dev/null
+++ b/leveldb-haskell.cabal
@@ -0,0 +1,57 @@
+name:                leveldb-haskell
+version:             0.0.1
+synopsis:            Haskell bindings to LevelDB
+homepage:            http://github.com/kim/leveldb-haskell
+license:             BSD3
+license-file:        LICENSE
+author:              Kim Altintop
+maintainer:          kim.altintop@gmail.com
+category:            Database
+stability:           Experimental
+build-type:          Configure
+cabal-version:       >=1.8
+tested-with:         GHC == 7.2.2, GHC == 7.4.1
+description:
+    From <http://leveldb.googlecode.com>:
+    .
+    LevelDB is a fast key-value storage library written at Google that provides
+    an ordered mapping from string keys to string values.
+    .
+    .
+    This library provides a Haskell language binding to LeveldDB. It is in very
+    early stage and has seen very limited testing.
+    .
+    Note: the LevelDB source code is bundled with this package and built as
+    part of the installation, assuming that a working C++ compiler is installed
+    on the target system and the @make@ command can invoke it.
+
+extra-source-files:  Example.lhs
+                   , Readme.md
+                   , configure
+                   , cbits/leveldb/include/leveldb/*.h
+
+source-repository head
+  type:     git
+  location: git://github.com/kim/leveldb-haskell.git
+
+library
+  exposed-modules:  Database.LevelDB
+  other-modules:    Database.LevelDB.Base
+  extensions:       CPP
+                  , ForeignFunctionInterface
+  build-depends:    base >= 3 && < 5
+                  , bytestring
+  ghc-options:      -Wall -O2 -static -optl-static -rtsopts
+  ghc-prof-options: -prof -auto-all
+  hs-source-dirs:   src
+  includes:         leveldb/c.h
+  extra-libraries:  leveldb, snappy, stdc++
+  include-dirs:     cbits/leveldb/include
+
+executable hsleveldb-example
+  main-is:          Example.lhs
+  build-depends:    base
+                  , leveldb-haskell
+                  , bytestring
+                  , filepath
+  ghc-options:      -rtsopts -threaded
diff --git a/src/Database/LevelDB.hs b/src/Database/LevelDB.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/LevelDB.hs
@@ -0,0 +1,446 @@
+-- |
+-- LevelDB Haskell binding.
+--
+-- The API closely follows the C-API of LevelDB.
+-- For more information, see: <http://leveldb.googlecode.com>
+--
+--
+-- Basic example:
+--
+-- > withLevelDB "/tmp/leveldbtest" [CreateIfMissing, CacheSize 1024] $ \db -> do
+-- >     put db [] "foo" "bar"
+-- >     get db [] "foo" >>= print
+-- >     delete db [] "foo"
+-- >     get db [] "foo" >>= print
+--
+-- Batch write and iterating:
+--
+-- > withLevelDB "/tmp/leveldbtest" [CreateIfMissing, CacheSize 1024] $ \db -> do
+-- >     write db [Sync] [ Put "a" "one"
+-- >                     , Put "b" "two"
+-- >                     , Put "c" "three" ]
+-- >     dumpEntries db []
+-- >
+-- >     where
+-- >         dumpEntries db opts =
+-- >             withIterator db opts $ \iter -> do
+-- >                 iterFirst iter
+-- >                 iterEntries iter print
+-- >
+-- >         iterEntries iter f = do
+-- >             valid <- iterValid iter
+-- >             when valid $ do
+-- >                 key <- iterKey iter
+-- >                 val <- iterValue iter
+-- >                 _   <- f (key, val)
+-- >                 _   <- iterNext iter
+-- >                 iterEntries iter f
+
+module Database.LevelDB (
+  -- * Exported Types
+    DB
+  , BatchOp(..)
+  , Compression(..)
+  , Option(..)
+  , Options
+  , ReadOption(..)
+  , ReadOptions
+  , Snapshot
+  , WriteBatch
+  , WriteOption(..)
+  , WriteOptions
+  , Range
+
+  -- * Basic Database Manipulation
+  , withLevelDB
+  , withSnapshot
+  , put
+  , delete
+  , write
+  , get
+
+  -- * Administrative Functions
+  , Property(..), getProperty
+  , destroy
+  , repair
+  , approximateSize
+
+  -- * Iteration
+  , Iterator
+  , withIterator
+  , iterOpen
+  , iterClose
+  , iterValid
+  , iterSeek
+  , iterFirst
+  , iterLast
+  , iterNext
+  , iterPrev
+  , iterKey
+  , iterValue
+) where
+
+import Control.Exception  (bracket)
+import Control.Monad      (liftM, when)
+import Data.ByteString    (ByteString)
+import Data.List          (find)
+import Data.Maybe
+import Foreign
+import Foreign.C.Error    (throwErrnoIfNull)
+import Foreign.C.String   (withCString, peekCString)
+import Foreign.C.Types    (CSize, CInt)
+
+import Database.LevelDB.Base
+
+import qualified Data.ByteString as SB
+import qualified Data.ByteString.Unsafe as UB
+
+-- import Debug.Trace
+
+-- | Database handle
+newtype DB = DB LevelDBPtr
+
+-- | Iterator handle
+newtype Iterator = Iterator IteratorPtr
+
+-- | Snapshot handle
+newtype Snapshot = Snapshot SnapshotPtr
+
+-- | Compression setting
+data Compression = NoCompression | Snappy deriving (Eq, Show)
+
+type Options = [Option]
+-- | Options when opening a database
+data Option = CreateIfMissing
+            | ErrorIfExists
+            | ParanoidChecks
+            | WriteBufferSize Int
+            | MaxOpenFiles Int
+            | BlockSize Int
+            | BlockRestartInterval Int
+            | UseCompression Compression
+            | CacheSize Int
+            deriving (Eq, Show)
+
+type WriteOptions = [WriteOption]
+-- | Options for write operations
+data WriteOption  = Sync -- ^ fsync the rows written immediately
+                  deriving (Show)
+
+type ReadOptions = [ReadOption]
+-- | Options for read operations
+data ReadOption  = VerifyCheckSums
+                 | FillCache
+                 | UseSnapshot Snapshot
+
+type WriteBatch = [BatchOp]
+-- | Batch operation
+data BatchOp = Put ByteString ByteString | Del ByteString deriving (Show)
+
+-- | Properties exposed by LevelDB
+data Property = NumFilesAtLevel Int | Stats | SSTables deriving (Eq, Show)
+
+
+-- | Run an action on a database
+withLevelDB :: FilePath -> Options -> (DB -> IO a) -> IO a
+withLevelDB path opts act =
+    withCString path    $ \path_ptr ->
+    withCOptions opts   $ \opts_ptr ->
+    alloca              $ \err_ptr  ->
+        bracket (open path_ptr opts_ptr err_ptr) close act
+    where
+        open path_ptr opts_ptr err_ptr = do
+            p <- throwIfErr "open" err_ptr $ c_leveldb_open opts_ptr path_ptr
+            return . DB $ p
+
+        close (DB db) = c_leveldb_close db
+
+-- | Run an action with a snapshot of the database.
+withSnapshot :: DB -> (Snapshot -> IO a) -> IO a
+withSnapshot (DB db) = bracket (create db) (release db)
+    where
+        create  db_ptr = liftM Snapshot $ c_leveldb_create_snapshot db_ptr
+        release db_ptr (Snapshot snap) = c_leveldb_release_snapshot db_ptr snap
+
+-- | Get a DB property
+getProperty :: DB -> Property -> IO (Maybe ByteString)
+getProperty (DB db) p =
+    withCString (prop p) $ \prop_ptr -> do
+        val_ptr <- c_leveldb_property_value db prop_ptr
+        if val_ptr == nullPtr
+            then return Nothing
+            else do res <- liftM Just $ SB.packCString val_ptr
+                    free val_ptr
+                    return res
+
+    where
+        prop (NumFilesAtLevel i) = "leveldb.num-files-at-level" ++ show i
+        prop Stats    = "leveldb.stats"
+        prop SSTables = "leveldb.sstables"
+
+-- | Destroy the given leveldb database.
+destroy :: FilePath -> Options -> IO ()
+destroy path opts =
+    withCString path    $ \path_ptr ->
+    withCOptions opts   $ \opts_ptr ->
+    alloca              $ \err_ptr  ->
+        throwIfErr "destroy" err_ptr $ c_leveldb_destroy_db opts_ptr path_ptr
+
+-- | Repair the given leveldb database.
+repair :: FilePath -> Options -> IO ()
+repair path opts =
+    withCString path    $ \path_ptr ->
+    withCOptions opts   $ \opts_ptr ->
+    alloca              $ \err_ptr  ->
+        throwIfErr "repair" err_ptr $ c_leveldb_repair_db opts_ptr path_ptr
+
+-- TODO: support [Range], like C API does
+type Range  = (ByteString, ByteString)
+
+-- | Inspect the approximate sizes of the different levels
+approximateSize :: DB -> Range -> IO Int64
+approximateSize (DB db) (from, to) =
+    UB.unsafeUseAsCStringLen from $ \(from_ptr, flen) ->
+    UB.unsafeUseAsCStringLen to   $ \(to_ptr, tlen)   ->
+    withArray [from_ptr]          $ \from_ptrs        ->
+    withArray [i2s flen]          $ \flen_ptrs        ->
+    withArray [to_ptr]            $ \to_ptrs          ->
+    withArray [i2s tlen]          $ \tlen_ptrs        ->
+    allocaArray 1                 $ \size_ptrs        -> do
+        c_leveldb_approximate_sizes db 1 from_ptrs flen_ptrs to_ptrs tlen_ptrs size_ptrs
+        liftM head $ peekArray 1 size_ptrs >>= mapM toInt64
+
+    where
+        toInt64 = return . fromIntegral
+
+-- | Write a key/value pair
+put :: DB -> WriteOptions -> ByteString -> ByteString -> IO ()
+put (DB db) opts key value =
+    UB.unsafeUseAsCStringLen key   $ \(key_ptr, klen) ->
+    UB.unsafeUseAsCStringLen value $ \(val_ptr, vlen) ->
+    withCWriteOptions opts         $ \opts_ptr        ->
+    alloca                         $ \err_ptr         ->
+        throwIfErr "put" err_ptr
+        $ c_leveldb_put db opts_ptr
+                        key_ptr (i2s klen)
+                        val_ptr (i2s vlen)
+
+-- | Read a value by key
+get :: DB -> ReadOptions -> ByteString -> IO (Maybe ByteString)
+get (DB db) opts key =
+    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->
+    withCReadOptions opts        $ \opts_ptr        ->
+    alloca                       $ \err_ptr         ->
+    alloca                       $ \vlen_ptr        -> do
+        val_ptr <- throwIfErr "get" err_ptr
+                   $ c_leveldb_get db opts_ptr key_ptr (i2s klen) vlen_ptr
+        vlen <- peek vlen_ptr
+        if val_ptr /= nullPtr
+            then do
+                res <- liftM Just $ SB.packCStringLen (val_ptr, s2i vlen)
+                free val_ptr
+                return res
+            else return Nothing
+
+-- | Delete a key/value pair
+delete :: DB -> WriteOptions -> ByteString -> IO ()
+delete (DB db) opts key =
+    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->
+    withCWriteOptions opts       $ \opts_ptr        ->
+    alloca                       $ \err_ptr         ->
+        throwIfErr "delete" err_ptr
+        $ c_leveldb_delete db opts_ptr key_ptr (i2s klen)
+
+-- | Perform a batch mutation
+write :: DB -> WriteOptions -> WriteBatch -> IO ()
+write (DB db) opts batch =
+    withCWriteOptions opts $ \opts_ptr  ->
+    withCWriteBatch batch  $ \batch_ptr ->
+    alloca                 $ \err_ptr   ->
+        throwIfErr "write" err_ptr
+        $ c_leveldb_write db opts_ptr batch_ptr
+
+    where
+        withCWriteBatch b f = do
+            batch_ptr <- c_leveldb_writebatch_create
+            mapM_ (batchAdd batch_ptr) b
+            res <- f batch_ptr
+            c_leveldb_writebatch_destroy batch_ptr
+            return res
+
+        batchAdd batch_ptr (Put key val) =
+            UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->
+            UB.unsafeUseAsCStringLen val $ \(val_ptr, vlen) ->
+                c_leveldb_writebatch_put batch_ptr
+                                         key_ptr (i2s klen)
+                                         val_ptr (i2s vlen)
+
+        batchAdd batch_ptr (Del key) =
+            UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->
+                c_leveldb_writebatch_delete batch_ptr key_ptr (i2s klen)
+
+-- | Run an action with an Iterator. The iterator will be closed after the
+-- action returns or an error is thrown. Thus, the iterator will /not/ be valid
+-- after this function terminates.
+withIterator :: DB -> ReadOptions -> (Iterator -> IO a) -> IO a
+withIterator db opts = bracket (iterOpen db opts) iterClose
+
+-- | Create an Iterator. Consider using withIterator.
+iterOpen :: DB -> ReadOptions -> IO Iterator
+iterOpen (DB db) opts =
+    withCReadOptions opts $ \opts_ptr ->
+        liftM Iterator
+        $ throwErrnoIfNull "create_iterator"
+        $ c_leveldb_create_iterator db opts_ptr
+
+-- | Release an Iterator. Consider using withIterator.
+iterClose :: Iterator -> IO ()
+iterClose (Iterator iter) = c_leveldb_iter_destroy iter
+
+-- | An iterator is either positioned at a key/value pair, or not valid. This
+-- function returns /true/ iff the iterator is valid.
+iterValid :: Iterator -> IO Bool
+iterValid (Iterator iter) = do
+    x <- c_leveldb_iter_valid iter
+    return (x /= 0)
+
+-- | Position at the first key in the source that is at or past target. The
+-- iterator is /valid/ after this call iff the source contains an entry that
+-- comes at or past target.
+iterSeek :: Iterator -> ByteString -> IO ()
+iterSeek (Iterator iter) key =
+    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->
+        c_leveldb_iter_seek iter key_ptr (i2s klen)
+
+-- | Position at the first key in the source. The iterator is /valid/ after this
+-- call iff the source is not empty.
+iterFirst :: Iterator -> IO ()
+iterFirst (Iterator iter) = c_leveldb_iter_seek_to_first iter
+
+-- | Position at the last key in the source. The iterator is /valid/ after this
+-- call iff the source is not empty.
+iterLast :: Iterator -> IO ()
+iterLast (Iterator iter) = c_leveldb_iter_seek_to_last iter
+
+-- | Moves to the next entry in the source. After this call, 'iterValid' is
+-- /true/ iff the iterator was not positioned the last entry in the source.
+iterNext :: Iterator -> IO ()
+iterNext (Iterator iter) = c_leveldb_iter_next iter
+
+-- | Moves to the previous entry in the source. After this call, 'iterValid' is
+-- /true/ iff the iterator was not positioned at the first entry in the source.
+iterPrev :: Iterator -> IO ()
+iterPrev (Iterator iter) = c_leveldb_iter_prev iter
+
+-- | Return the key for the current entry. The underlying storage for the
+-- returned slice is valid only until the next modification of the iterator.
+iterKey :: Iterator -> IO ByteString
+iterKey (Iterator iter) =
+    alloca $ \len_ptr -> do
+        key_ptr <- c_leveldb_iter_key iter len_ptr
+        klen <- peek len_ptr
+        if key_ptr /= nullPtr
+            then SB.packCStringLen (key_ptr, s2i klen)
+            else ioError $ userError "null key"
+
+-- | Return the value for the current entry. The underlying storage for the
+-- returned slice is valid only until the next modification of the iterator.
+iterValue :: Iterator -> IO ByteString
+iterValue (Iterator iter) =
+    alloca $ \len_ptr -> do
+        val_ptr <- c_leveldb_iter_value iter len_ptr
+        vlen <- peek len_ptr
+        if val_ptr /= nullPtr
+            then SB.packCStringLen (val_ptr, s2i vlen)
+            else ioError $ userError "null value"
+
+-- | Internal
+
+withCOptions :: Options -> (OptionsPtr -> IO a) -> IO a
+withCOptions opts f = do
+    opts_ptr <- c_leveldb_options_create
+    mapM_ (setopt opts_ptr) opts
+    if isJust $ maybeCacheSize opts
+        then withCache (fromJust $ maybeCacheSize opts) $ \cache_ptr -> do
+                 c_leveldb_options_set_cache opts_ptr cache_ptr
+                 run opts_ptr
+        else run opts_ptr
+
+    where
+        run opts_ptr = do
+            res <- f opts_ptr
+            c_leveldb_options_destroy opts_ptr
+            return res
+
+        maybeCacheSize os = find isCs os >>= \(CacheSize s) -> return s
+
+        isCs (CacheSize _) = True
+        isCs _             = False
+
+        withCache s = bracket (c_leveldb_cache_create_lru $ i2s s)
+                              c_leveldb_cache_destroy
+
+        setopt opts_ptr CreateIfMissing =
+            c_leveldb_options_set_create_if_missing opts_ptr 1
+        setopt opts_ptr ErrorIfExists =
+            c_leveldb_options_set_error_if_exists opts_ptr 1
+        setopt opts_ptr ParanoidChecks =
+            c_leveldb_options_set_paranoid_checks opts_ptr 1
+        setopt opts_ptr (WriteBufferSize s) =
+            c_leveldb_options_set_write_buffer_size opts_ptr $ i2s s
+        setopt opts_ptr (MaxOpenFiles n) =
+            c_leveldb_options_set_max_open_files opts_ptr $ i2ci n
+        setopt opts_ptr (BlockSize s) =
+            c_leveldb_options_set_block_size opts_ptr $ i2s s
+        setopt opts_ptr (BlockRestartInterval i) =
+            c_leveldb_options_set_block_restart_interval opts_ptr $ i2ci i
+        setopt opts_ptr (UseCompression NoCompression) =
+            c_leveldb_options_set_compression opts_ptr noCompression
+        setopt opts_ptr (UseCompression Snappy) =
+            c_leveldb_options_set_compression opts_ptr snappyCompression
+        setopt _ (CacheSize _) = return ()
+
+withCWriteOptions :: WriteOptions -> (WriteOptionsPtr -> IO a) -> IO a
+withCWriteOptions opts f = do
+    opts_ptr <- c_leveldb_writeoptions_create
+    mapM_ (setopt opts_ptr) opts
+    res <- f opts_ptr
+    c_leveldb_writeoptions_destroy opts_ptr
+    return res
+
+    where
+        setopt opts_ptr Sync = c_leveldb_writeoptions_set_sync opts_ptr 1
+
+withCReadOptions :: ReadOptions -> (ReadOptionsPtr -> IO a) -> IO a
+withCReadOptions opts f = do
+    opts_ptr <- c_leveldb_readoptions_create
+    mapM_ (setopt opts_ptr) opts
+    res <- f opts_ptr
+    c_leveldb_readoptions_destroy opts_ptr
+    return res
+
+    where
+        setopt opts_ptr VerifyCheckSums =
+            c_leveldb_readoptions_set_verify_checksums opts_ptr 1
+        setopt opts_ptr FillCache =
+            c_leveldb_readoptions_set_fill_cache opts_ptr 1
+        setopt opts_ptr (UseSnapshot (Snapshot snap)) =
+            c_leveldb_readoptions_set_snapshot opts_ptr snap
+
+throwIfErr :: String -> ErrPtr -> (ErrPtr -> IO a) -> IO a
+throwIfErr s err_ptr f = do
+    res  <- f err_ptr
+    erra <- peek err_ptr
+    when (erra /= nullPtr) $ do
+        err <- peekCString erra
+        ioError $ userError $ s ++ ": " ++ err
+    return res
+
+s2i :: CSize -> Int
+s2i = fromIntegral
+
+i2s :: Int -> CSize
+i2s = fromIntegral
+
+i2ci :: Int -> CInt
+i2ci = fromIntegral
diff --git a/src/Database/LevelDB/Base.hsc b/src/Database/LevelDB/Base.hsc
new file mode 100644
--- /dev/null
+++ b/src/Database/LevelDB/Base.hsc
@@ -0,0 +1,298 @@
+{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}
+
+module Database.LevelDB.Base where
+
+import Foreign
+import Foreign.C.Types
+import Foreign.C.String
+
+#include <leveldb/c.h>
+
+data LevelDB
+data LCache
+data LComparator
+data LIterator
+data LLogger
+data LOptions
+data LReadOptions
+data LSnapshot
+data LWriteBatch
+data LWriteOptions
+
+type LevelDBPtr      = Ptr LevelDB
+type CachePtr        = Ptr LCache
+type ComparatorPtr   = Ptr LComparator
+type IteratorPtr     = Ptr LIterator
+type LoggerPtr       = Ptr LLogger
+type OptionsPtr      = Ptr LOptions
+type ReadOptionsPtr  = Ptr LReadOptions
+type SnapshotPtr     = Ptr LSnapshot
+type WriteBatchPtr   = Ptr LWriteBatch
+type WriteOptionsPtr = Ptr LWriteOptions
+
+-- custom env from haskell doesn't make too much sense
+data LEnv
+data LFileLock
+data LRandomFile
+data LSeqfile
+data LWritableFile
+type EnvPtr          = Ptr LEnv
+type FileLockPtr     = Ptr LFileLock
+type RandomFilePtr   = Ptr LRandomFile
+type WritableFilePtr = Ptr LWritableFile
+type SeqfilePtr      = Ptr LSeqfile
+
+type DBName = CString
+type ErrPtr = Ptr CString
+type Key    = CString
+type Val    = CString
+
+newtype CompressionOpt = CompressionOpt { compressionOpt :: CInt }
+  deriving (Eq, Show)
+#{enum CompressionOpt, CompressionOpt
+ , noCompression     = 0
+ , snappyCompression = 1
+ }
+
+
+foreign import ccall unsafe "leveldb/c.h leveldb_open"
+  c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_close"
+  c_leveldb_close :: LevelDBPtr -> IO ()
+
+
+foreign import ccall unsafe "leveldb/c.h leveldb_put"
+  c_leveldb_put :: LevelDBPtr
+                -> WriteOptionsPtr
+                -> Key -> CSize
+                -> Val -> CSize
+                -> ErrPtr
+                -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_delete"
+  c_leveldb_delete :: LevelDBPtr
+                   -> WriteOptionsPtr
+                   -> Key -> CSize
+                   -> ErrPtr
+                   -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_write"
+  c_leveldb_write :: LevelDBPtr
+                  -> WriteOptionsPtr
+                  -> WriteBatchPtr
+                  -> ErrPtr
+                  -> IO ()
+
+-- | Returns NULL if not found. A malloc()ed array otherwise. Stores the length
+-- of the array in *vallen.
+foreign import ccall unsafe "leveldb/c.h leveldb_get"
+  c_leveldb_get :: LevelDBPtr
+                -> ReadOptionsPtr
+                -> Key -> CSize
+                -> Ptr CSize        -- ^ value length
+                -> ErrPtr
+                -> IO CString
+
+foreign import ccall unsafe "leveldb/c.h leveldb_create_snapshot"
+  c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_release_snapshot"
+  c_leveldb_release_snapshot :: LevelDBPtr -> SnapshotPtr -> IO ()
+
+-- | Returns NULL if property name is unknown. Else returns a pointer to a
+-- malloc()-ed null-terminated value.
+foreign import ccall unsafe "leveldb/c.h leveldb_property_value"
+  c_leveldb_property_value :: LevelDBPtr -> CString -> IO CString
+
+-- not sure why this needs to be imported unsafe
+foreign import ccall unsafe "leveldb/c.h leveldb_approximate_sizes"
+  c_leveldb_approximate_sizes :: LevelDBPtr
+                              -> CInt                     -- ^ num ranges
+                              -> Ptr CString -> Ptr CSize -- ^ range start keys (array)
+                              -> Ptr CString -> Ptr CSize -- ^ range limit keys (array)
+                              -> Ptr Word64               -- ^ array of approx. sizes of ranges
+                              -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_destroy_db"
+  c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_repair_db"
+  c_leveldb_repair_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()
+
+-- ^ Iterator
+
+foreign import ccall unsafe "leveldb/c.h leveldb_create_iterator"
+  c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_destroy"
+  c_leveldb_iter_destroy :: IteratorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_valid"
+  c_leveldb_iter_valid :: IteratorPtr -> IO CUChar
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek_to_first"
+  c_leveldb_iter_seek_to_first :: IteratorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek_to_last"
+  c_leveldb_iter_seek_to_last :: IteratorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek"
+  c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_next"
+  c_leveldb_iter_next :: IteratorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_prev"
+  c_leveldb_iter_prev :: IteratorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_key"
+  c_leveldb_iter_key :: IteratorPtr -> Ptr CSize -> IO Key
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_value"
+  c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val
+
+foreign import ccall unsafe "leveldb/c.h leveldb_iter_get_error"
+  c_leveldb_iter_get_error :: IteratorPtr -> ErrPtr -> IO ()
+
+-- ^ Write batch
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_create"
+  c_leveldb_writebatch_create :: IO WriteBatchPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_destroy"
+  c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_clear"
+  c_leveldb_writebatch_clear :: WriteBatchPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_put"
+  c_leveldb_writebatch_put :: WriteBatchPtr
+                           -> Key -> CSize
+                           -> Val -> CSize
+                           -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_delete"
+  c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_iterate"
+  c_leveldb_writebatch_iterate :: WriteBatchPtr
+                               -> Ptr ()                            -- ^ state
+                               -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -- ^ put
+                               -> FunPtr (Ptr () -> Key -> CSize)     -- ^ delete
+                               -> IO ()
+
+-- ^ Options
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_create"
+  c_leveldb_options_create :: IO OptionsPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_destroy"
+  c_leveldb_options_destroy :: OptionsPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_comparator"
+  c_leveldb_options_set_comparator :: OptionsPtr -> ComparatorPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_create_if_missing"
+  c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_error_if_exists"
+  c_leveldb_options_set_error_if_exists :: OptionsPtr -> CUChar -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_paranoid_checks"
+  c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_env"
+  c_leveldb_options_set_env :: OptionsPtr -> EnvPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_info_log"
+  c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_write_buffer_size"
+  c_leveldb_options_set_write_buffer_size :: OptionsPtr -> CSize -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_max_open_files"
+  c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_block_size"
+  c_leveldb_options_set_block_size :: OptionsPtr -> CSize -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_block_restart_interval"
+  c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_compression"
+  c_leveldb_options_set_compression :: OptionsPtr -> CompressionOpt -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_options_set_cache"
+  c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()
+
+--
+-- Comparator
+--
+type StatePtr   = Ptr ()
+type Destructor = StatePtr -> ()
+type CompareFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CInt
+type NameFun    = StatePtr -> CString
+
+-- | Make a FunPtr to a user-defined comparator function
+foreign import ccall "wrapper" mkCmp :: CompareFun -> IO (FunPtr CompareFun)
+
+-- | Make a destructor FunPtr
+foreign import ccall "wrapper" mkDest :: Destructor -> IO (FunPtr Destructor)
+
+-- | Make a name FunPtr
+foreign import ccall "wrapper" mkName :: NameFun -> IO (FunPtr NameFun)
+
+foreign import ccall unsafe "leveldb/c.h leveldb_comparator_create"
+  c_leveldb_comparator_create :: StatePtr
+                              -> FunPtr Destructor
+                              -> FunPtr CompareFun
+                              -> FunPtr NameFun
+                              -> IO ComparatorPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_comparator_destroy"
+  c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()
+
+-- ^ Read options
+
+foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_create"
+  c_leveldb_readoptions_create :: IO ReadOptionsPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_destroy"
+  c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_verify_checksums"
+  c_leveldb_readoptions_set_verify_checksums :: ReadOptionsPtr -> CUChar -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_fill_cache"
+  c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_snapshot"
+  c_leveldb_readoptions_set_snapshot :: ReadOptionsPtr -> SnapshotPtr -> IO ()
+
+-- ^ Write options
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_create"
+  c_leveldb_writeoptions_create :: IO WriteOptionsPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_destroy"
+  c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO ()
+
+foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_set_sync"
+  c_leveldb_writeoptions_set_sync :: WriteOptionsPtr -> CUChar -> IO ()
+
+-- ^ Cache
+
+foreign import ccall unsafe "leveldb/c.h leveldb_cache_create_lru"
+  c_leveldb_cache_create_lru :: CSize -> IO CachePtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_cache_destroy"
+  c_leveldb_cache_destroy :: CachePtr -> IO ()
+
+-- ^ Env
+
+foreign import ccall unsafe "leveldb/c.h leveldb_create_default_env"
+  c_leveldb_create_default_env :: IO EnvPtr
+
+foreign import ccall unsafe "leveldb/c.h leveldb_env_destroy"
+  c_leveldb_env_destroy :: EnvPtr -> IO ()
