summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/ext')
-rw-r--r--src/third_party/wiredtiger/ext/compressors/bzip2/bzip2_compress.c9
-rw-r--r--src/third_party/wiredtiger/ext/compressors/lz4/lz4_compress.c288
-rw-r--r--src/third_party/wiredtiger/ext/compressors/nop/nop_compress.c7
-rw-r--r--src/third_party/wiredtiger/ext/encryptors/nop/Makefile.am9
-rw-r--r--src/third_party/wiredtiger/ext/encryptors/nop/nop_encrypt.c178
-rw-r--r--src/third_party/wiredtiger/ext/encryptors/rotn/Makefile.am9
-rw-r--r--src/third_party/wiredtiger/ext/encryptors/rotn/rotn_encrypt.c433
7 files changed, 846 insertions, 87 deletions
diff --git a/src/third_party/wiredtiger/ext/compressors/bzip2/bzip2_compress.c b/src/third_party/wiredtiger/ext/compressors/bzip2/bzip2_compress.c
index 3f2e09de2f6..6cd53aba5d2 100644
--- a/src/third_party/wiredtiger/ext/compressors/bzip2/bzip2_compress.c
+++ b/src/third_party/wiredtiger/ext/compressors/bzip2/bzip2_compress.c
@@ -314,8 +314,15 @@ bzip2_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
if ((ret = BZ2_bzDecompress(&bz)) == BZ_STREAM_END) {
*result_lenp = dst_len - bz.avail_out;
ret = 0;
- } else
+ } else {
+ /*
+ * If BZ2_bzDecompress returns 0, it expects there to be more
+ * data available. There isn't, so treat this as an error.
+ */
+ if (ret == 0)
+ ret = BZ_DATA_ERROR;
(void)bzip2_error(compressor, session, "BZ2_bzDecompress", ret);
+ }
if ((tret = BZ2_bzDecompressEnd(&bz)) != BZ_OK)
return (bzip2_error(
diff --git a/src/third_party/wiredtiger/ext/compressors/lz4/lz4_compress.c b/src/third_party/wiredtiger/ext/compressors/lz4/lz4_compress.c
index 9939a4f8a04..0906e1d131d 100644
--- a/src/third_party/wiredtiger/ext/compressors/lz4/lz4_compress.c
+++ b/src/third_party/wiredtiger/ext/compressors/lz4/lz4_compress.c
@@ -48,19 +48,41 @@ typedef struct {
} LZ4_COMPRESSOR;
/*
+ * LZ4 decompression requires the exact compressed byte count returned by the
+ * LZ4_compress and LZ4_compress_destSize functions. WiredTiger doesn't track
+ * that value, store it in the destination buffer.
+ *
+ * Additionally, LZ4_compress_destSize may compress into the middle of a record,
+ * and after decompression we return the length to the last record successfully
+ * decompressed, not the number of bytes decompressed; store that value in the
+ * destination buffer as well.
+ *
+ * Use fixed-size, 4B values (WiredTiger never writes buffers larger than 4GB).
+ *
+ * The unused field is available for a mode flag if one is needed in the future,
+ * we guarantee it's 0.
+ */
+typedef struct {
+ uint32_t compressed_len; /* True compressed length */
+ uint32_t uncompressed_len; /* True uncompressed source length */
+ uint32_t useful_len; /* Decompression return value */
+ uint32_t unused; /* Guaranteed to be 0 */
+} LZ4_PREFIX;
+
+/*
* lz4_error --
* Output an error message, and return a standard error code.
*/
static int
lz4_error(
- WT_COMPRESSOR *compressor, WT_SESSION *session, const char *call, int zret)
+ WT_COMPRESSOR *compressor, WT_SESSION *session, const char *call, int error)
{
WT_EXTENSION_API *wt_api;
wt_api = ((LZ4_COMPRESSOR *)compressor)->wt_api;
(void)wt_api->err_printf(wt_api,
- session, "lz4 error: %s: %d", call, zret);
+ session, "lz4 error: %s: %d", call, error);
return (WT_ERROR);
}
@@ -74,39 +96,34 @@ lz4_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *dst, size_t dst_len,
size_t *result_lenp, int *compression_failed)
{
- char *lz4buf;
- size_t lz4_len;
+ LZ4_PREFIX prefix;
+ int lz4_len;
- /*
- * The buffer should always be large enough due to the lz4_pre_size
- * call, but be paranoid and error if it isn't.
- */
- if (dst_len < src_len + sizeof(size_t))
- return (lz4_error(compressor, session,
- "LZ4 compress buffer too small", 0));
+ (void)compressor; /* Unused parameters */
+ (void)session;
+ (void)dst_len;
- /* Store the length of the compressed block in the first 8 bytes. */
- lz4buf = (char *)dst + sizeof(size_t);
- lz4_len = (size_t)LZ4_compress((const char *)src, lz4buf, (int)src_len);
+ /* Compress, starting after the prefix bytes. */
+ lz4_len = LZ4_compress(
+ (const char *)src, (char *)dst + sizeof(LZ4_PREFIX), (int)src_len);
/*
- * Flag no-compression if the result was larger than the original
- * size or compression failed.
+ * If compression succeeded and the compressed length is smaller than
+ * the original size, return success.
*/
- if (lz4_len == 0 || lz4_len + sizeof(size_t) >= src_len)
- *compression_failed = 1;
- else {
- /*
- * On decompression, lz4 requires the exact compressed byte
- * count (the current value of lz4_len). WiredTiger does not
- * preserve that value, so save lz4_len at the beginning of the
- * destination buffer.
- */
- *(size_t *)dst = lz4_len;
- *result_lenp = lz4_len + sizeof(size_t);
+ if (lz4_len != 0 && (size_t)lz4_len + sizeof(LZ4_PREFIX) < src_len) {
+ prefix.compressed_len = (uint32_t)lz4_len;
+ prefix.uncompressed_len = (uint32_t)src_len;
+ prefix.useful_len = (uint32_t)src_len;
+ prefix.unused = 0;
+ memcpy(dst, &prefix, sizeof(LZ4_PREFIX));
+
+ *result_lenp = (size_t)lz4_len + sizeof(LZ4_PREFIX);
*compression_failed = 0;
+ return (0);
}
+ *compression_failed = 1;
return (0);
}
@@ -121,40 +138,143 @@ lz4_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
size_t *result_lenp)
{
WT_EXTENSION_API *wt_api;
- char *compressed_data;
+ LZ4_PREFIX prefix;
int decoded;
- size_t src_data_len;
+ uint8_t *dst_tmp;
+
+ (void)src_len; /* Unused parameters */
wt_api = ((LZ4_COMPRESSOR *)compressor)->wt_api;
- /* Retrieve compressed length from start of the data buffer. */
- src_data_len = *(size_t *)src;
- if (src_data_len + sizeof(size_t) > src_len) {
- (void)wt_api->err_printf(wt_api,
- session,
- "lz4_decompress: stored size exceeds buffer size");
- return (WT_ERROR);
+ /*
+ * Retrieve the true length of the compressed block and source and the
+ * decompressed bytes to return from the start of the source buffer.
+ */
+ memcpy(&prefix, src, sizeof(LZ4_PREFIX));
+
+ /*
+ * Decompress, starting after the prefix bytes. Use safe decompression:
+ * we rely on decompression to detect corruption.
+ *
+ * Two code paths, one with and one without a bounce buffer. When doing
+ * raw compression, we compress to a target size irrespective of row
+ * boundaries, and return to our caller a "useful" compression length
+ * based on the last complete row that was compressed. Our caller stores
+ * that length, not the length of bytes actually compressed by LZ4. In
+ * other words, our caller doesn't know how many bytes will result from
+ * decompression, likely hasn't provided us a large enough buffer, and
+ * we have to allocate a scratch buffer.
+ */
+ if (dst_len < prefix.uncompressed_len) {
+ if ((dst_tmp = wt_api->scr_alloc(
+ wt_api, session, (size_t)prefix.uncompressed_len)) == NULL)
+ return (ENOMEM);
+
+ decoded = LZ4_decompress_safe(
+ (const char *)src + sizeof(LZ4_PREFIX), (char *)dst_tmp,
+ (int)prefix.compressed_len, (int)prefix.uncompressed_len);
+
+ if (decoded >= 0)
+ memcpy(dst, dst_tmp, dst_len);
+ wt_api->scr_free(wt_api, session, dst_tmp);
+ } else
+ decoded = LZ4_decompress_safe(
+ (const char *)src + sizeof(LZ4_PREFIX),
+ (char *)dst, (int)prefix.compressed_len, (int)dst_len);
+
+ if (decoded >= 0) {
+ *result_lenp = prefix.useful_len;
+ return (0);
}
- /* Skip over the data size to the start of compressed data. */
- compressed_data = (char *)src + sizeof(size_t);
+ return (
+ lz4_error(compressor, session, "LZ4 decompress error", decoded));
+}
+
+/*
+ * lz4_find_slot --
+ * Find the slot containing the target offset (binary search).
+ */
+static inline uint32_t
+lz4_find_slot(int target_arg, uint32_t *offsets, uint32_t slots)
+{
+ uint32_t base, indx, limit, target;
+
+ indx = 1; /* -Wuninitialized */
+
+ target = (uint32_t)target_arg; /* Type conversion */
+
+ /* Fast check if we consumed it all, it's a likely result. */
+ if (target >= offsets[slots])
+ return (slots);
/*
- * The destination buffer length should always be sufficient because
- * wiredtiger keeps track of the byte count before compression. Use
- * safe decompression: we may be relying on decompression to detect
- * corruption.
+ * Figure out which slot we got to: binary search. Note the test of
+ * offset (slot + 1), that's (end-byte + 1) for slot.
*/
- decoded = LZ4_decompress_safe(
- compressed_data, (char *)dst, (int)src_data_len, (int)dst_len);
+ for (base = 0, limit = slots; limit != 0; limit >>= 1) {
+ indx = base + (limit >> 1);
+ if (target > offsets[indx + 1]) {
+ base = indx + 1;
+ --limit;
+ }
+ }
+
+ return (indx);
+}
+
+/*
+ * lz4_compress_raw --
+ * Pack records into a specified on-disk page size.
+ */
+static int
+lz4_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
+ size_t page_max, int split_pct, size_t extra,
+ uint8_t *src, uint32_t *offsets, uint32_t slots,
+ uint8_t *dst, size_t dst_len, int final,
+ size_t *result_lenp, uint32_t *result_slotsp)
+{
+ LZ4_PREFIX prefix;
+ int lz4_len;
+ uint32_t slot;
+ int sourceSize, targetDestSize;
+
+ (void)compressor; /* Unused parameters */
+ (void)session;
+ (void)split_pct;
+ (void)final;
+
+ sourceSize = (int)offsets[slots]; /* Type conversion */
+ targetDestSize =
+ (int)((dst_len < page_max ? dst_len : page_max) - extra);
- if (decoded < 0)
- return (lz4_error(compressor, session,
- "LZ4 decompress error", decoded));
+ /* Compress, starting after the prefix bytes. */
+ lz4_len = LZ4_compress_destSize((const char *)src,
+ (char *)dst + sizeof(LZ4_PREFIX), &sourceSize, targetDestSize);
- /* return the uncompressed data length */
- *result_lenp = dst_len;
+ /*
+ * If compression succeeded and the compressed length is smaller than
+ * the original size, return success.
+ */
+ if (lz4_len != 0) {
+ /* Find the first slot we didn't compress. */
+ slot = lz4_find_slot(sourceSize, offsets, slots);
+
+ if ((size_t)lz4_len + sizeof(LZ4_PREFIX) < offsets[slot]) {
+ prefix.compressed_len = (uint32_t)lz4_len;
+ prefix.uncompressed_len = (uint32_t)sourceSize;
+ prefix.useful_len = offsets[slot];
+ prefix.unused = 0;
+ memcpy(dst, &prefix, sizeof(LZ4_PREFIX));
+
+ *result_slotsp = slot;
+ *result_lenp = (size_t)lz4_len + sizeof(LZ4_PREFIX);
+ return (0);
+ }
+ }
+ *result_slotsp = 0;
+ *result_lenp = 1;
return (0);
}
@@ -164,18 +284,18 @@ lz4_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
*/
static int
lz4_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
- uint8_t *src, size_t src_len,
- size_t *result_lenp)
+ uint8_t *src, size_t src_len, size_t *result_lenp)
{
- (void)compressor;
+ (void)compressor; /* Unused parameters */
(void)session;
(void)src;
/*
- * LZ4 can use more space than the input data size, use the library
- * calculation of that overhead (plus our overhead) to be safe.
+ * In block mode, LZ4 can use more space than the input data size, use
+ * the library calculation of that overhead (plus our overhead) to be
+ * safe.
*/
- *result_lenp = LZ4_COMPRESSBOUND(src_len) + sizeof(size_t);
+ *result_lenp = LZ4_COMPRESSBOUND(src_len) + sizeof(LZ4_PREFIX);
return (0);
}
@@ -186,44 +306,30 @@ lz4_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
static int
lz4_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
{
- (void)session;
+ (void)session; /* Unused parameters */
- /* Free the allocated memory. */
free(compressor);
-
return (0);
}
-int lz4_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
-
/*
- * lz4_extension_init --
- * A simple shared library compression example.
+ * lz4_add_compressor --
+ * Add a LZ4 compressor.
*/
-int
-lz4_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+static int
+lz_add_compressor(WT_CONNECTION *connection, int raw, const char *name)
{
LZ4_COMPRESSOR *lz4_compressor;
- (void)config; /* Unused parameters */
-
+ /*
+ * There are two almost identical LZ4 compressors: one using raw
+ * compression to target a specific block size, and one without.
+ */
if ((lz4_compressor = calloc(1, sizeof(LZ4_COMPRESSOR))) == NULL)
return (errno);
- /*
- * Allocate a local compressor structure, with a WT_COMPRESSOR structure
- * as the first field, allowing us to treat references to either type of
- * structure as a reference to the other type.
- *
- * This could be simplified if only a single database is opened in the
- * application, we could use a static WT_COMPRESSOR structure, and a
- * static reference to the WT_EXTENSION_API methods, then we don't need
- * to allocate memory when the compressor is initialized or free it when
- * the compressor is terminated. However, this approach is more general
- * purpose and supports multiple databases per application.
- */
lz4_compressor->compressor.compress = lz4_compress;
- lz4_compressor->compressor.compress_raw = NULL;
+ lz4_compressor->compressor.compress_raw = raw ? lz4_compress_raw : NULL;
lz4_compressor->compressor.decompress = lz4_decompress;
lz4_compressor->compressor.pre_size = lz4_pre_size;
lz4_compressor->compressor.terminate = lz4_terminate;
@@ -232,7 +338,29 @@ lz4_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
/* Load the compressor */
return (connection->add_compressor(
- connection, "lz4", (WT_COMPRESSOR *)lz4_compressor, NULL));
+ connection, name, (WT_COMPRESSOR *)lz4_compressor, NULL));
+}
+
+int lz4_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
+
+/*
+ * lz4_extension_init --
+ * WiredTiger LZ4 compression extension - called directly when LZ4 support
+ * is built in, or via wiredtiger_extension_init when LZ4 support is included
+ * via extension loading.
+ */
+int
+lz4_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+{
+ int ret;
+
+ (void)config; /* Unused parameters */
+
+ if ((ret = lz_add_compressor(connection, 1, "lz4")) != 0)
+ return (ret);
+ if ((ret = lz_add_compressor(connection, 0, "lz4-noraw")) != 0)
+ return (ret);
+ return (0);
}
/*
diff --git a/src/third_party/wiredtiger/ext/compressors/nop/nop_compress.c b/src/third_party/wiredtiger/ext/compressors/nop/nop_compress.c
index 6b640adf777..ce6964be85d 100644
--- a/src/third_party/wiredtiger/ext/compressors/nop/nop_compress.c
+++ b/src/third_party/wiredtiger/ext/compressors/nop/nop_compress.c
@@ -166,12 +166,7 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
* as the first field, allowing us to treat references to either type of
* structure as a reference to the other type.
*
- * This could be simplified if only a single database is opened in the
- * application, we could use a static WT_COMPRESSOR structure, and a
- * static reference to the WT_EXTENSION_API methods, then we don't need
- * to allocate memory when the compressor is initialized or free it when
- * the compressor is terminated. However, this approach is more general
- * purpose and supports multiple databases per application.
+ * Heap memory (not static), because it can support multiple databases.
*/
nop_compressor->compressor.compress = nop_compress;
nop_compressor->compressor.compress_raw = NULL;
diff --git a/src/third_party/wiredtiger/ext/encryptors/nop/Makefile.am b/src/third_party/wiredtiger/ext/encryptors/nop/Makefile.am
new file mode 100644
index 00000000000..189f764b04c
--- /dev/null
+++ b/src/third_party/wiredtiger/ext/encryptors/nop/Makefile.am
@@ -0,0 +1,9 @@
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)/src/include
+
+noinst_LTLIBRARIES = libwiredtiger_nop.la
+libwiredtiger_nop_la_SOURCES = nop_encrypt.c
+
+# libtool hack: noinst_LTLIBRARIES turns off building shared libraries as well
+# as installation, it will only build static libraries. As far as I can tell,
+# the "approved" libtool way to turn them back on is by adding -rpath.
+libwiredtiger_nop_la_LDFLAGS = -avoid-version -module -rpath /nowhere
diff --git a/src/third_party/wiredtiger/ext/encryptors/nop/nop_encrypt.c b/src/third_party/wiredtiger/ext/encryptors/nop/nop_encrypt.c
new file mode 100644
index 00000000000..e3f693ad37d
--- /dev/null
+++ b/src/third_party/wiredtiger/ext/encryptors/nop/nop_encrypt.c
@@ -0,0 +1,178 @@
+/*-
+ * Public Domain 2014-2015 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <wiredtiger.h>
+#include <wiredtiger_ext.h>
+
+/*! [WT_ENCRYPTOR initialization structure] */
+/* Local encryptor structure. */
+typedef struct {
+ WT_ENCRYPTOR encryptor; /* Must come first */
+
+ WT_EXTENSION_API *wt_api; /* Extension API */
+
+ unsigned long nop_calls; /* Count of calls */
+
+} NOP_ENCRYPTOR;
+/*! [WT_ENCRYPTOR initialization structure] */
+
+/*! [WT_ENCRYPTOR encrypt] */
+/*
+ * nop_encrypt --
+ * A simple encryption example that passes data through unchanged.
+ */
+static int
+nop_encrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp)
+{
+ NOP_ENCRYPTOR *nop_encryptor = (NOP_ENCRYPTOR *)encryptor;
+
+ (void)session; /* Unused parameters */
+
+ ++nop_encryptor->nop_calls; /* Call count */
+
+ if (dst_len < src_len)
+ return (ENOMEM);
+
+ memcpy(dst, src, src_len);
+ *result_lenp = src_len;
+
+ return (0);
+}
+/*! [WT_ENCRYPTOR encrypt] */
+
+/*! [WT_ENCRYPTOR decrypt] */
+/*
+ * nop_decrypt --
+ * A simple decryption example that passes data through unchanged.
+ */
+static int
+nop_decrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp)
+{
+ NOP_ENCRYPTOR *nop_encryptor = (NOP_ENCRYPTOR *)encryptor;
+
+ (void)session; /* Unused parameters */
+ (void)src_len;
+
+ ++nop_encryptor->nop_calls; /* Call count */
+
+ /*
+ * The destination length is the number of unencrypted bytes we're
+ * expected to return.
+ */
+ memcpy(dst, src, dst_len);
+ *result_lenp = dst_len;
+ return (0);
+}
+/*! [WT_ENCRYPTOR decrypt] */
+
+/*! [WT_ENCRYPTOR sizing] */
+/*
+ * nop_sizing --
+ * A simple sizing example that tells wiredtiger that the
+ * encrypted buffer is always the same as the source buffer.
+ */
+static int
+nop_sizing(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ size_t *expansion_constantp)
+{
+ NOP_ENCRYPTOR *nop_encryptor = (NOP_ENCRYPTOR *)encryptor;
+
+ (void)session; /* Unused parameters */
+
+ ++nop_encryptor->nop_calls; /* Call count */
+
+ *expansion_constantp = 0;
+ return (0);
+}
+/*! [WT_ENCRYPTOR sizing] */
+
+/*! [WT_ENCRYPTOR terminate] */
+/*
+ * nop_terminate --
+ * WiredTiger no-op encryption termination.
+ */
+static int
+nop_terminate(WT_ENCRYPTOR *encryptor, WT_SESSION *session)
+{
+ NOP_ENCRYPTOR *nop_encryptor = (NOP_ENCRYPTOR *)encryptor;
+
+ (void)session; /* Unused parameters */
+
+ ++nop_encryptor->nop_calls; /* Call count */
+
+ /* Free the allocated memory. */
+ free(encryptor);
+
+ return (0);
+}
+/*! [WT_ENCRYPTOR terminate] */
+
+/*! [WT_ENCRYPTOR initialization function] */
+/*
+ * wiredtiger_extension_init --
+ * A simple shared library encryption example.
+ */
+int
+wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+{
+ NOP_ENCRYPTOR *nop_encryptor;
+
+ (void)config; /* Unused parameters */
+
+ if ((nop_encryptor = calloc(1, sizeof(NOP_ENCRYPTOR))) == NULL)
+ return (errno);
+
+ /*
+ * Allocate a local encryptor structure, with a WT_ENCRYPTOR structure
+ * as the first field, allowing us to treat references to either type of
+ * structure as a reference to the other type.
+ *
+ * Heap memory (not static), because it can support multiple databases.
+ */
+ nop_encryptor->encryptor.encrypt = nop_encrypt;
+ nop_encryptor->encryptor.decrypt = nop_decrypt;
+ nop_encryptor->encryptor.sizing = nop_sizing;
+ nop_encryptor->encryptor.terminate = nop_terminate;
+
+ nop_encryptor->wt_api = connection->get_extension_api(connection);
+
+ /* Load the encryptor */
+ return (connection->add_encryptor(
+ connection, "nop", (WT_ENCRYPTOR *)nop_encryptor, NULL));
+}
+/*! [WT_ENCRYPTOR initialization function] */
diff --git a/src/third_party/wiredtiger/ext/encryptors/rotn/Makefile.am b/src/third_party/wiredtiger/ext/encryptors/rotn/Makefile.am
new file mode 100644
index 00000000000..fec4ed0f861
--- /dev/null
+++ b/src/third_party/wiredtiger/ext/encryptors/rotn/Makefile.am
@@ -0,0 +1,9 @@
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)/src/include
+
+noinst_LTLIBRARIES = libwiredtiger_rotn.la
+libwiredtiger_rotn_la_SOURCES = rotn_encrypt.c
+
+# libtool hack: noinst_LTLIBRARIES turns off building shared libraries as well
+# as installation, it will only build static libraries. As far as I can tell,
+# the "approved" libtool way to turn them back on is by adding -rpath.
+libwiredtiger_rotn_la_LDFLAGS = -avoid-version -module -rpath /nowhere
diff --git a/src/third_party/wiredtiger/ext/encryptors/rotn/rotn_encrypt.c b/src/third_party/wiredtiger/ext/encryptors/rotn/rotn_encrypt.c
new file mode 100644
index 00000000000..503dcae83a7
--- /dev/null
+++ b/src/third_party/wiredtiger/ext/encryptors/rotn/rotn_encrypt.c
@@ -0,0 +1,433 @@
+/*-
+ * Public Domain 2014-2015 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <wiredtiger.h>
+#include <wiredtiger_ext.h>
+
+/*! [WT_ENCRYPTOR initialization structure] */
+
+/*
+ * This encryptor is used for testing and demonstration only.
+ *
+ * IT IS TRIVIAL TO BREAK AND DOES NOT OFFER ANY SECURITY!
+ *
+ * There are two configuration parameters that control it: the keyid and the
+ * secretkey (which may be thought of as a password). The keyid is expected
+ * to be a digits giving a number between 0 and 25. The secretkey, when
+ * present, must be composed of alphabetic characters.
+ *
+ * When there is no secretkey, the encryptor acts as a ROT(N) encryptor (a
+ * "Caesar cipher"), where N is the value of keyid. Thus, with keyid=13,
+ * text "Hello" maps to "Uryyb", as we preserve case. Only the alphabetic
+ * characters in the input text are changed.
+ *
+ * When there is a secretkey we are implementing a Vigenere cipher.
+ * Each byte is rotated the distance from 'A' for each letter in the
+ * (repeating) secretkey. The distance is increased by the value of
+ * the keyid. Thus, with secretkey "ABC" and keyid "2", we show how
+ * we map the input "MySecret".
+ * secretkey = ABC
+ * distances from 'A' = 012
+ * add keyid (2) = 234
+ * repeated = 23423423
+ * input = MySecret
+ * output = ObWgfvgw
+ * In this case, we transform all bytes in the input.
+ */
+
+/* Local encryptor structure. */
+typedef struct {
+ WT_ENCRYPTOR encryptor; /* Must come first */
+
+ WT_EXTENSION_API *wt_api; /* Extension API */
+
+ int rot_N; /* rotN value */
+ char *keyid; /* Saved keyid */
+ char *secretkey; /* Saved secretkey */
+ u_char *shift_forw; /* Encrypt shift data from secretkey */
+ u_char *shift_back; /* Decrypt shift data from secretkey */
+ size_t shift_len; /* Length of shift* byte arrays */
+
+} ROTN_ENCRYPTOR;
+/*! [WT_ENCRYPTOR initialization structure] */
+
+#define CHKSUM_LEN 4
+#define IV_LEN 16
+
+/*
+ * make_cksum --
+ * This is where one would call a checksum function on the encrypted
+ * buffer. Here we just put a constant value in it.
+ */
+static void
+make_cksum(uint8_t *dst)
+{
+ int i;
+ /*
+ * Assume array is big enough for the checksum.
+ */
+ for (i = 0; i < CHKSUM_LEN; i++)
+ dst[i] = 'C';
+}
+
+/*
+ * make_iv --
+ * This is where one would generate the initialization vector.
+ * Here we just put a constant value in it.
+ */
+static void
+make_iv(uint8_t *dst)
+{
+ int i;
+ /*
+ * Assume array is big enough for the initialization vector.
+ */
+ for (i = 0; i < IV_LEN; i++)
+ dst[i] = 'I';
+}
+
+/*
+ * Rotate encryption functions.
+ */
+/*
+ * do_rotate --
+ * Perform rot-N on the buffer given.
+ */
+static void
+do_rotate(char *buf, size_t len, int rotn)
+{
+ uint32_t i;
+ /*
+ * Now rotate.
+ *
+ * Avoid ctype functions because they behave in unexpected ways,
+ * particularly when the locale is not "C".
+ */
+ for (i = 0; i < len; i++) {
+ if ('a' <= buf[i] && buf[i] <= 'z')
+ buf[i] = ((buf[i] - 'a') + rotn) % 26 + 'a';
+ else if ('A' <= buf[i] && buf[i] <= 'Z')
+ buf[i] = ((buf[i] - 'A') + rotn) % 26 + 'A';
+ }
+}
+
+/*
+ * do_shift --
+ * Perform a Vigenere cipher
+ */
+static void
+do_shift(uint8_t *buf, size_t len, u_char *shift, size_t shiftlen)
+{
+ uint32_t i;
+ /*
+ * Now shift.
+ */
+ for (i = 0; i < len; i++)
+ buf[i] += shift[i % shiftlen];
+}
+
+/*! [WT_ENCRYPTOR encrypt] */
+/*
+ * rotn_encrypt --
+ * A simple encryption example that passes data through unchanged.
+ */
+static int
+rotn_encrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp)
+{
+ ROTN_ENCRYPTOR *rotn_encryptor = (ROTN_ENCRYPTOR *)encryptor;
+ uint32_t i;
+
+ (void)session; /* Unused */
+
+ if (dst_len < src_len + CHKSUM_LEN + IV_LEN)
+ return (ENOMEM);
+
+ /*
+ * !!! Most implementations would verify any needed
+ * checksum and initialize the IV here.
+ */
+ i = CHKSUM_LEN + IV_LEN;
+ memcpy(&dst[i], &src[0], src_len);
+ /*
+ * Depending on whether we have a secret key or not,
+ * call the common rotate or shift function on the text portion
+ * of the destination buffer. Send in src_len as the length of
+ * the text.
+ */
+ if (rotn_encryptor->shift_len == 0)
+ do_rotate((char *)dst + i, src_len, rotn_encryptor->rot_N);
+ else
+ do_shift(&dst[i], src_len,
+ rotn_encryptor->shift_forw, rotn_encryptor->shift_len);
+ /*
+ * Checksum the encrypted buffer and add the IV.
+ */
+ i = 0;
+ make_cksum(&dst[i]);
+ i += CHKSUM_LEN;
+ make_iv(&dst[i]);
+ *result_lenp = dst_len;
+ return (0);
+}
+/*! [WT_ENCRYPTOR encrypt] */
+
+/*! [WT_ENCRYPTOR decrypt] */
+/*
+ * rotn_decrypt --
+ * A simple decryption example that passes data through unchanged.
+ */
+static int
+rotn_decrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp)
+{
+ ROTN_ENCRYPTOR *rotn_encryptor = (ROTN_ENCRYPTOR *)encryptor;
+ size_t mylen;
+ uint32_t i;
+
+ (void)session; /* Unused */
+
+ /*
+ * Make sure it is big enough.
+ */
+ mylen = src_len - (CHKSUM_LEN + IV_LEN);
+ if (dst_len < mylen) {
+ fprintf(stderr, "Rotate: ENOMEM ERROR\n");
+ return (ENOMEM);
+ }
+
+ /*
+ * !!! Most implementations would verify the checksum here.
+ */
+ /*
+ * Copy the encrypted data to the destination buffer and then
+ * decrypt the destination buffer.
+ */
+ i = CHKSUM_LEN + IV_LEN;
+ memcpy(&dst[0], &src[i], mylen);
+ /*
+ * Depending on whether we have a secret key or not,
+ * call the common rotate or shift function on the text portion
+ * of the destination buffer. Send in dst_len as the length of
+ * the text.
+ */
+ /*
+ * !!! Most implementations would need the IV too.
+ */
+ if (rotn_encryptor->shift_len == 0)
+ do_rotate((char *)dst, mylen, 26 - rotn_encryptor->rot_N);
+ else
+ do_shift(&dst[0], mylen,
+ rotn_encryptor->shift_back, rotn_encryptor->shift_len);
+ *result_lenp = mylen;
+ return (0);
+}
+/*! [WT_ENCRYPTOR decrypt] */
+
+/*! [WT_ENCRYPTOR postsize] */
+/*
+ * rotn_sizing --
+ * A sizing example that returns the header size needed.
+ */
+static int
+rotn_sizing(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ size_t *expansion_constantp)
+{
+ (void)encryptor; /* Unused parameters */
+ (void)session; /* Unused parameters */
+
+ *expansion_constantp = CHKSUM_LEN + IV_LEN;
+ return (0);
+}
+/*! [WT_ENCRYPTOR postsize] */
+
+/*! [WT_ENCRYPTOR customize] */
+/*
+ * rotn_customize --
+ * The customize function creates a customized encryptor
+ */
+static int
+rotn_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
+ WT_CONFIG_ARG *encrypt_config, WT_ENCRYPTOR **customp)
+{
+ const ROTN_ENCRYPTOR *orig;
+ ROTN_ENCRYPTOR *rotn_encryptor;
+ WT_CONFIG_ITEM keyid, secret;
+ WT_EXTENSION_API *wt_api;
+ size_t i, len;
+ int ret, keyid_val;
+ u_char base;
+
+ ret = 0;
+ keyid_val = 0;
+
+ orig = (const ROTN_ENCRYPTOR *)encryptor;
+ wt_api = orig->wt_api;
+
+ if ((rotn_encryptor = calloc(1, sizeof(ROTN_ENCRYPTOR))) == NULL)
+ return (errno);
+ *rotn_encryptor = *orig;
+ rotn_encryptor->keyid = rotn_encryptor->secretkey = NULL;
+
+ /*
+ * Stash the keyid from the configuration string.
+ */
+ if ((ret = wt_api->config_get(wt_api, session, encrypt_config,
+ "keyid", &keyid)) == 0 && keyid.len != 0) {
+ /*
+ * In this demonstration, we expect keyid to be a number.
+ */
+ if ((keyid_val = atoi(keyid.str)) < 0) {
+ ret = EINVAL;
+ goto err;
+ }
+ if ((rotn_encryptor->keyid = malloc(keyid.len + 1)) == NULL) {
+ ret = errno;
+ goto err;
+ }
+ strncpy(rotn_encryptor->keyid, keyid.str, keyid.len + 1);
+ rotn_encryptor->keyid[keyid.len] = '\0';
+ }
+
+ /*
+ * In this demonstration, the secret key must be alphabetic characters.
+ * We stash the secret key from the configuration string
+ * and build some shift bytes to make encryption/decryption easy.
+ */
+ if ((ret = wt_api->config_get(wt_api, session, encrypt_config,
+ "secretkey", &secret)) == 0 && secret.len != 0) {
+ len = secret.len;
+ if ((rotn_encryptor->secretkey = malloc(len + 1)) == NULL ||
+ (rotn_encryptor->shift_forw = malloc(len)) == NULL ||
+ (rotn_encryptor->shift_back = malloc(len)) == NULL) {
+ ret = errno;
+ goto err;
+ }
+ for (i = 0; i < len; i++) {
+ if ('a' <= secret.str[i] && secret.str[i] <= 'z')
+ base = 'a';
+ else if ('A' <= secret.str[i] && secret.str[i] <= 'Z')
+ base = 'A';
+ else {
+ ret = EINVAL;
+ goto err;
+ }
+ base -= (u_char)keyid_val;
+ rotn_encryptor->shift_forw[i] =
+ (u_char)secret.str[i] - base;
+ rotn_encryptor->shift_back[i] =
+ base - (u_char)secret.str[i];
+ }
+ rotn_encryptor->shift_len = len;
+ strncpy(rotn_encryptor->secretkey, secret.str, secret.len + 1);
+ rotn_encryptor->secretkey[secret.len] = '\0';
+ }
+
+ /*
+ * In a real encryptor, we could use some sophisticated key management
+ * here to map the keyid onto a secret key.
+ */
+ rotn_encryptor->rot_N = keyid_val;
+
+ *customp = (WT_ENCRYPTOR *)rotn_encryptor;
+ return (0);
+
+err: free(rotn_encryptor->keyid);
+ free(rotn_encryptor->secretkey);
+ free(rotn_encryptor->shift_forw);
+ free(rotn_encryptor->shift_back);
+ free(rotn_encryptor);
+ return (ret);
+}
+/*! [WT_ENCRYPTOR presize] */
+
+/*! [WT_ENCRYPTOR terminate] */
+/*
+ * rotn_terminate --
+ * WiredTiger no-op encryption termination.
+ */
+static int
+rotn_terminate(WT_ENCRYPTOR *encryptor, WT_SESSION *session)
+{
+ ROTN_ENCRYPTOR *rotn_encryptor = (ROTN_ENCRYPTOR *)encryptor;
+
+ (void)session; /* Unused parameters */
+
+ /* Free the allocated memory. */
+ free(rotn_encryptor->secretkey);
+ free(rotn_encryptor->keyid);
+ free(rotn_encryptor->shift_forw);
+ free(rotn_encryptor->shift_back);
+ free(encryptor);
+ return (0);
+}
+/*! [WT_ENCRYPTOR terminate] */
+
+/*! [WT_ENCRYPTOR initialization function] */
+/*
+ * wiredtiger_extension_init --
+ * A simple shared library encryption example.
+ */
+int
+wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+{
+ ROTN_ENCRYPTOR *rotn_encryptor;
+
+ (void)config; /* Unused parameters */
+
+ if ((rotn_encryptor = calloc(1, sizeof(ROTN_ENCRYPTOR))) == NULL)
+ return (errno);
+
+ /*
+ * Allocate a local encryptor structure, with a WT_ENCRYPTOR structure
+ * as the first field, allowing us to treat references to either type of
+ * structure as a reference to the other type.
+ *
+ * Heap memory (not static), because it can support multiple databases.
+ */
+ rotn_encryptor->encryptor.encrypt = rotn_encrypt;
+ rotn_encryptor->encryptor.decrypt = rotn_decrypt;
+ rotn_encryptor->encryptor.sizing = rotn_sizing;
+ rotn_encryptor->encryptor.customize = rotn_customize;
+ rotn_encryptor->encryptor.terminate = rotn_terminate;
+
+ rotn_encryptor->wt_api = connection->get_extension_api(connection);
+
+ /* Load the encryptor */
+ return (connection->add_encryptor(
+ connection, "rotn", (WT_ENCRYPTOR *)rotn_encryptor, NULL));
+}
+/*! [WT_ENCRYPTOR initialization function] */