This is an automated email from the ASF dual-hosted git repository.

abukor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new de02a34  [encryption] Add encryption support to Env
de02a34 is described below

commit de02a34390f9bdb722be39f96ef9ad9573c0eeeb
Author: Attila Bukor <[email protected]>
AuthorDate: Wed Mar 31 18:57:28 2021 +0200

    [encryption] Add encryption support to Env
    
    This commit introduces reading and writing encrypted files through Env.
    At this stage, encryption is not usable, as it uses a static dummy key.
    
    Originally, I wanted to use a simple Caesar's cipher like ROT13 until
    the rest of the key infra is in place, but then I decided this proof of
    concept implementation should also prove that CTR, which is our chosen
    mode of operation[1] works for our access patterns, so I ended up using
    OpenSSL even in this proof of concept, albeit with a static key and
    key size.
    
    [1] https://s.apache.org/kudu-atrest-enc-design
    
    Change-Id: Id5a81b5736a0c1970818dbbc4a234480476b8d41
    Reviewed-on: http://gerrit.cloudera.org:8080/17251
    Tested-by: Kudu Jenkins
    Reviewed-by: Alexey Serbin <[email protected]>
---
 src/kudu/util/coding-inl.h   |  14 +++
 src/kudu/util/env-test.cc    | 111 ++++++++++++++++++++++++
 src/kudu/util/env.h          |  28 ++++--
 src/kudu/util/env_posix.cc   | 200 +++++++++++++++++++++++++++++++++++++------
 src/kudu/util/openssl_util.h |   4 +-
 5 files changed, 321 insertions(+), 36 deletions(-)

diff --git a/src/kudu/util/coding-inl.h b/src/kudu/util/coding-inl.h
index a47e9ce..20e639f 100644
--- a/src/kudu/util/coding-inl.h
+++ b/src/kudu/util/coding-inl.h
@@ -86,6 +86,20 @@ inline void InlineEncodeFixed64(uint8_t *buf, uint64_t 
value) {
 #endif
 }
 
+inline void InlineBigEndianEncodeFixed64(uint8_t* buf, uint64_t value) {
+#if __BYTE_ORDER == __BIG_ENDIAN
+  memcpy(buf, &value, sizeof(value));
+#else
+  buf[0] = (value >> 56) & 0xff;
+  buf[1] = (value >> 48) & 0xff;
+  buf[2] = (value >> 40) & 0xff;
+  buf[3] = (value >> 32) & 0xff;
+  buf[4] = (value >> 24) & 0xff;
+  buf[5] = (value >> 16) & 0xff;
+  buf[6] = (value >> 8) & 0xff;
+  buf[7] = value & 0xff;
+#endif
+}
 
 // Standard Put... routines append to a string
 template <class StrType>
diff --git a/src/kudu/util/env-test.cc b/src/kudu/util/env-test.cc
index 287ec6b..5dbe4cf 100644
--- a/src/kudu/util/env-test.cc
+++ b/src/kudu/util/env-test.cc
@@ -1249,4 +1249,115 @@ TEST_F(TestEnv, TestCreateFifo) {
   ASSERT_OK(env_->NewFifo(kFifo, &fifo));
 }
 
+TEST_F(TestEnv, TestEncryption) {
+  const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+  unique_ptr<RWFile> rw;
+  RWFileOptions opts;
+  opts.encrypted = true;
+  ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+  string kTestData =
+      "Hello world! This text is slightly longer than usual to make sure 
multiple blocks are "
+      "encrypted and we can read at unaligned offsets correctly. Lorem ipsum 
dolor sit amet, "
+      "consectetur adipiscing elit.";
+
+  string kTestData2 =
+      "We also need to append to this file to make sure initialization vectors 
are calculated "
+      "correctly.";
+
+  ASSERT_OK(rw->Write(0, kTestData));
+  ASSERT_OK(rw->Write(kTestData.length(), kTestData2));
+
+  // Setup read parameters
+  constexpr size_t size1 = 9;
+  uint8_t scratch1[size1];
+  Slice result1(scratch1, size1);
+  constexpr size_t size2 = 19;
+  uint8_t scratch2[size2];
+  Slice result2(scratch2, size2);
+  vector<Slice> results = { result1, result2 };
+
+  // Reading back from the RWFile should succeed
+  ASSERT_OK(rw->ReadV(13, results));
+  ASSERT_EQ(result1, "This text");
+  ASSERT_EQ(result2, " is slightly longer");
+
+  ASSERT_OK(rw->Close());
+
+  unique_ptr<RandomAccessFile> unencrpyted;
+  RandomAccessFileOptions unencrpyted_opts;
+  unencrpyted_opts.encrypted = false;
+  ASSERT_OK(env_->NewRandomAccessFile(unencrpyted_opts, kFile, &unencrpyted));
+
+  // Treating it as an unencrypted file should yield garbage and not contain 
the
+  // cleartext written to the file.
+  string unencrypted_string;
+  ASSERT_OK(unencrpyted->Read(0, unencrypted_string));
+  ASSERT_EQ(string::npos, unencrypted_string.find("This text is slightly 
longer"));
+
+  // Check if the file can be read into a SequentialFile.
+  unique_ptr<SequentialFile> seq_file;
+  SequentialFileOptions seq_opts;
+  seq_opts.encrypted = true;
+  ASSERT_OK(env_->NewSequentialFile(seq_opts, kFile, &seq_file));
+
+  ASSERT_OK(seq_file->Read(&result1));
+  ASSERT_OK(seq_file->Read(&result2));
+  ASSERT_EQ(result1, "Hello wor");
+  ASSERT_EQ(result2, "ld! This text is sl");
+
+  // Check if the file can be read into a RandomAccessFile if treated properly
+  // as an encrypted file.
+  unique_ptr<RandomAccessFile> random;
+  RandomAccessFileOptions random_opts;
+  random_opts.encrypted = true;
+  ASSERT_OK(env_->NewRandomAccessFile(random_opts, kFile, &random));
+  size_t size = kTestData.length() + kTestData2.length();
+  uint8_t scratch[size];
+  Slice result(scratch, size);
+  ASSERT_OK(random->Read(0, result));
+  ASSERT_EQ(kTestData + kTestData2, result);
+
+  // Read a SequentialFile until EOF.
+  ASSERT_OK(env_->NewSequentialFile(seq_opts, kFile, &seq_file));
+  uint8_t scratch3[size + 10];
+  Slice result3(scratch3, size + 10);
+  ASSERT_OK(seq_file->Read(&result3));
+  ASSERT_EQ(kTestData + kTestData2, result3);
+}
+
+TEST_F(TestEnv, TestPreallocatedReadEncryptedFile) {
+  const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+  unique_ptr<RWFile> rw;
+  RWFileOptions opts;
+  opts.encrypted = true;
+  ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+  ASSERT_OK(rw->PreAllocate(0, 1024, RWFile::CHANGE_FILE_SIZE));
+
+  size_t size = 10;
+  uint8_t scratch[size];
+  Slice result(scratch, size);
+  vector<Slice> results = {result};
+  ASSERT_OK(rw->ReadV(0, results));
+  ASSERT_TRUE(IsAllZeros(result));
+}
+
+TEST_F(TestEnv, TestEncryptionMultipleSlices) {
+  const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+  unique_ptr<RWFile> rw;
+  RWFileOptions opts;
+  opts.encrypted = true;
+  ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+  vector<Slice> data = {"foo", "bar", "hello", "world"};
+
+  ASSERT_OK(rw->WriteV(0, data));
+
+  uint8_t scratch[16];
+  Slice result(scratch, 16);
+  ASSERT_OK(rw->Read(0, result));
+  ASSERT_EQ("foobarhelloworld", result);
+}
+
 }  // namespace kudu
diff --git a/src/kudu/util/env.h b/src/kudu/util/env.h
index ce436a8..2ed394b 100644
--- a/src/kudu/util/env.h
+++ b/src/kudu/util/env.h
@@ -37,6 +37,7 @@ class WritableFile;
 struct RandomAccessFileOptions;
 struct RWFileOptions;
 struct WritableFileOptions;
+struct SequentialFileOptions;
 
 template <typename T>
 class ArrayView;
@@ -84,6 +85,11 @@ class Env {
   virtual Status NewSequentialFile(const std::string& fname,
                                    std::unique_ptr<SequentialFile>* result) = 
0;
 
+  // Like the previous NewSequentialFile, but allows options to be specified.
+  virtual Status NewSequentialFile(const SequentialFileOptions& opts,
+                                   const std::string& fname,
+                                   std::unique_ptr<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
@@ -407,10 +413,16 @@ class Fifo : public File {
   virtual int write_fd() const = 0;
 };
 
+struct SequentialFileOptions {
+  bool encrypted;
+
+  SequentialFileOptions() : encrypted(false) {}
+};
+
 // A file abstraction for reading sequentially through a file
 class SequentialFile : public File {
  public:
-  SequentialFile() { }
+  SequentialFile() {}
 
   // Read up to "result.size" bytes from the file.
   // Sets "result.data" to the data that was read.
@@ -482,14 +494,17 @@ struct WritableFileOptions {
   // See CreateMode for details.
   Env::OpenMode mode;
 
+  bool encrypted;
+
   WritableFileOptions()
-    : sync_on_close(false),
-      mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE) { }
+      : sync_on_close(false), mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE), 
encrypted(false) {}
 };
 
 // Options specified when a file is opened for random access.
 struct RandomAccessFileOptions {
-  RandomAccessFileOptions() {}
+  bool encrypted;
+
+  RandomAccessFileOptions() : encrypted(false) {}
 };
 
 // A file abstraction for sequential writing.  The implementation
@@ -549,9 +564,10 @@ struct RWFileOptions {
   // See CreateMode for details.
   Env::OpenMode mode;
 
+  bool encrypted;
+
   RWFileOptions()
-    : sync_on_close(false),
-      mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE) { }
+      : sync_on_close(false), mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE), 
encrypted(false) {}
 };
 
 // A file abstraction for both reading and writing. No notion of a built-in
diff --git a/src/kudu/util/env_posix.cc b/src/kudu/util/env_posix.cc
index b25e9c5..eec7e5e 100644
--- a/src/kudu/util/env_posix.cc
+++ b/src/kudu/util/env_posix.cc
@@ -7,6 +7,7 @@
 #include <fnmatch.h>
 #include <fts.h>
 #include <glob.h>
+#include <openssl/ssl.h>
 #include <pthread.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
@@ -49,6 +50,7 @@
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/gutil/strings/util.h"
 #include "kudu/util/array_view.h"
+#include "kudu/util/coding-inl.h"
 #include "kudu/util/debug/trace_event.h"
 #include "kudu/util/env.h"
 #include "kudu/util/errno.h"
@@ -58,6 +60,7 @@
 #include "kudu/util/logging.h"
 #include "kudu/util/malloc.h"
 #include "kudu/util/monotime.h"
+#include "kudu/util/openssl_util.h"
 #include "kudu/util/path_util.h"
 #include "kudu/util/scoped_cleanup.h"
 #include "kudu/util/slice.h"
@@ -204,6 +207,10 @@ namespace kudu {
 
 const char* const Env::kInjectedFailureStatusMsg = "INJECTED FAILURE";
 
+const uint8_t kEncryptionBlockSize = 16;
+
+using evp_ctx_unique_ptr = std::unique_ptr<EVP_CIPHER_CTX, 
decltype(&EVP_CIPHER_CTX_free)>;
+
 namespace {
 
 struct FreeDeleter {
@@ -212,6 +219,12 @@ struct FreeDeleter {
   }
 };
 
+// KUDU-3316: This is the key temporarily used for all encrypion. Obviously,
+// this is not secure and MUST be removed and replaced with real keys once the
+// key infra is in place.
+// TODO(abukor): delete this.
+const uint8_t kDummyEncryptionKey[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14, 42};
+
 #if defined(__APPLE__)
 // Simulates Linux's fallocate file preallocation API on OS X.
 int fallocate(int fd, int mode, off_t offset, off_t len) {
@@ -364,6 +377,90 @@ Status DoOpen(const string& filename, int flags, const 
string& reason, int* fd)
   return Status::OK();
 }
 
+// Encrypts the data in 'cleartext' and writes it to 'ciphertext'. It requires
+// 'offset' to be set in the file as it's used to set the initialization 
vector.
+Status DoEncryptV(const uint8_t* key,
+                  uint64_t offset,
+                  ArrayView<const Slice> cleartext,
+                  ArrayView<Slice> ciphertext) {
+  DCHECK_EQ(cleartext.size(), ciphertext.size());
+  // Set the initialization vector based on the offset.
+  uint8_t iv[16];
+  InlineBigEndianEncodeFixed64(&iv[0], 0);
+  InlineBigEndianEncodeFixed64(&iv[8], offset / kEncryptionBlockSize);
+
+  evp_ctx_unique_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+  OPENSSL_RET_NOT_OK(EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, 
key, iv),
+                     "Failed to initialize encryption");
+  size_t offset_mod = offset % kEncryptionBlockSize;
+  if (offset_mod) {
+    unsigned char scratch_clear[kEncryptionBlockSize];
+    unsigned char scratch_cipher[kEncryptionBlockSize];
+    int out_length;
+    OPENSSL_RET_NOT_OK(EVP_EncryptUpdate(ctx.get(), scratch_cipher, 
&out_length,
+                                         scratch_clear, offset_mod),
+                       "Failed to encrypt scratch data");
+    DCHECK_LE(out_length, kEncryptionBlockSize);
+  }
+  for (auto i = 0; i < cleartext.size(); ++i) {
+    int out_length;
+    // Normally, EVP_EncryptFinal_ex() would be needed after the last chunk of
+    // data encrypted with EVP_EncryptUpdate(). In Kudu, we only use AES-CTR
+    // which requires no padding or authentication tags, so
+    // EVP_EncryptFinal_ex() doesn't actually add anything.
+    OPENSSL_RET_NOT_OK(EVP_EncryptUpdate(ctx.get(),
+                                         ciphertext[i].mutable_data(),
+                                         &out_length,
+                                         cleartext[i].data(),
+                                         cleartext[i].size()),
+                       "Failed to encrypt data");
+    DCHECK_EQ(out_length, cleartext[i].size());
+    DCHECK_LE(out_length, ciphertext[i].size());
+  }
+  return Status::OK();
+}
+
+// Decrypts 'data'. Uses 'offset' in the file to set the initialization vector.
+Status DoDecryptV(const uint8_t* key, uint64_t offset, ArrayView<Slice> data) {
+  // Set the initialization vector based on the offset.
+  uint8_t iv[16];
+  InlineBigEndianEncodeFixed64(&iv[0], 0);
+  InlineBigEndianEncodeFixed64(&iv[8], offset / kEncryptionBlockSize);
+
+  evp_ctx_unique_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+  OPENSSL_RET_NOT_OK(EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, 
key, iv),
+                     "Failed to initialize decryption");
+  size_t offset_mod = offset % kEncryptionBlockSize;
+  if (offset_mod) {
+    unsigned char scratch_clear[kEncryptionBlockSize];
+    unsigned char scratch_cipher[kEncryptionBlockSize];
+    int out_length;
+    OPENSSL_RET_NOT_OK(EVP_DecryptUpdate(ctx.get(),
+                                         scratch_clear,
+                                         &out_length,
+                                         scratch_cipher,
+                                         offset_mod),
+                       "Failed to decrypt scratch data");
+  }
+
+  for (auto i = 0; i < data.size(); ++i) {
+    const Slice& ciphertext_slice = data[i];
+    int in_length = ciphertext_slice.size();
+    if (!in_length || IsAllZeros(ciphertext_slice)) continue;
+    int out_length;
+    // We don't call EVP_DecryptFinal_ex() after EVP_DecryptUpdate() for the
+    // same reason we don't call EVP_EncryptFinal_ex().
+    OPENSSL_RET_NOT_OK(EVP_DecryptUpdate(ctx.get(),
+                                         data[i].mutable_data(),
+                                         &out_length,
+                                         ciphertext_slice.data(),
+                                         in_length),
+                       "Failed to decrypt data");
+    DCHECK_EQ(out_length, in_length);
+  }
+  return Status::OK();
+}
+
 Status DoOpen(const string& filename, Env::OpenMode mode, int* fd) {
   MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
   ThreadRestrictions::AssertIOAllowed();
@@ -392,8 +489,8 @@ Status DoOpen(const string& filename, Env::OpenMode mode, 
int* fd) {
   return Status::OK();
 }
 
-Status DoReadV(int fd, const string& filename, uint64_t offset,
-               ArrayView<Slice> results) {
+Status DoReadV(
+    int fd, const string& filename, uint64_t offset, ArrayView<Slice> results, 
bool decrypt) {
   MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
   ThreadRestrictions::AssertIOAllowed();
 
@@ -405,7 +502,7 @@ Status DoReadV(int fd, const string& filename, uint64_t 
offset,
   for (size_t i = 0; i < iov_size; i++) {
     Slice& result = results[i];
     bytes_req += result.size();
-    iov[i] = { result.mutable_data(), result.size() };
+    iov[i] = {result.mutable_data(), result.size()};
   }
 
   uint64_t cur_offset = offset;
@@ -432,11 +529,15 @@ Status DoReadV(int fd, const string& filename, uint64_t 
offset,
     }
     if (PREDICT_FALSE(r == 0)) {
       // EOF.
+      RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
       return Status::EndOfFile(
           Substitute("EOF trying to read $0 bytes at offset $1", bytes_req, 
offset));
     }
     if (PREDICT_TRUE(r == rem)) {
       // All requested bytes were read. This is almost always the case.
+      if (decrypt) {
+        RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
+      }
       return Status::OK();
     }
     DCHECK_LE(r, rem);
@@ -458,11 +559,15 @@ Status DoReadV(int fd, const string& filename, uint64_t 
offset,
     cur_offset += r;
     rem -= r;
   }
+  if (decrypt) {
+    RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
+  }
   DCHECK_EQ(0, rem);
   return Status::OK();
 }
 
-Status DoWriteV(int fd, const string& filename, uint64_t offset, 
ArrayView<const Slice> data) {
+Status DoWriteV(
+    int fd, const string& filename, uint64_t offset, ArrayView<const Slice> 
data, bool encrypt) {
   MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
   ThreadRestrictions::AssertIOAllowed();
 
@@ -471,10 +576,32 @@ Status DoWriteV(int fd, const string& filename, uint64_t 
offset, ArrayView<const
   size_t bytes_req = 0;
   size_t iov_size = data.size();
   struct iovec iov[iov_size];
-  for (size_t i = 0; i < iov_size; i++) {
-    const Slice& result = data[i];
-    bytes_req += result.size();
-    iov[i] = { const_cast<uint8_t*>(result.data()), result.size() };
+  std::vector<Slice> encrypted_data(iov_size);
+  SCOPED_CLEANUP({
+    if (encrypt) {
+      delete[] encrypted_data[0].mutable_data();
+    }
+  });
+  if (encrypt) {
+    for (size_t i = 0; i < iov_size; i++) {
+      bytes_req += data[i].size();
+    }
+    unique_ptr<unsigned char[]> encrypted_buf(new unsigned char[bytes_req]);
+    size_t buffer_offset = 0;
+    for (size_t i = 0; i < iov_size; i++) {
+      size_t size = data[i].size();
+      encrypted_data[i] = Slice(&encrypted_buf[buffer_offset], size);
+      buffer_offset += size;
+      iov[i] = {const_cast<uint8_t*>(encrypted_data[i].data()), size};
+    }
+    RETURN_NOT_OK(DoEncryptV(kDummyEncryptionKey, offset, data, 
encrypted_data));
+    encrypted_buf.release();
+  } else {
+    for (size_t i = 0; i < iov_size; i++) {
+      const Slice& result = data[i];
+      bytes_req += result.size();
+      iov[i] = {const_cast<uint8_t*>(result.data()), result.size()};
+    }
   }
 
   uint64_t cur_offset = offset;
@@ -625,10 +752,12 @@ class PosixSequentialFile: public SequentialFile {
  private:
   const string filename_;
   FILE* const file_;
+  const bool encrypted_;
+  size_t offset_;
 
  public:
-  PosixSequentialFile(string fname, FILE* f)
-      : filename_(std::move(fname)), file_(f) {}
+  PosixSequentialFile(string fname, bool encrypted, FILE* f)
+      : filename_(std::move(fname)), file_(f), encrypted_(encrypted), 
offset_(0) {}
   ~PosixSequentialFile() {
     int err;
     RETRY_ON_EINTR(err, fclose(file_));
@@ -653,6 +782,10 @@ class PosixSequentialFile: public SequentialFile {
         return IOError(filename_, errno);
       }
     }
+    if (encrypted_) {
+      RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset_, 
ArrayView<Slice>(result, 1)));
+    }
+    offset_ += r;
     return Status::OK();
   }
 
@@ -663,6 +796,7 @@ class PosixSequentialFile: public SequentialFile {
     if (fseek(file_, n, SEEK_CUR)) {
       return IOError(filename_, errno);
     }
+    offset_ += n;
     return Status::OK();
   }
 
@@ -674,20 +808,21 @@ class PosixRandomAccessFile: public RandomAccessFile {
  private:
   const string filename_;
   const int fd_;
+  const bool encrypted_;
 
  public:
-  PosixRandomAccessFile(string fname, int fd)
-      : filename_(std::move(fname)), fd_(fd) {}
+  PosixRandomAccessFile(string fname, int fd, bool encrypted)
+      : filename_(std::move(fname)), fd_(fd), encrypted_(encrypted) {}
   ~PosixRandomAccessFile() {
     DoClose(fd_);
   }
 
   virtual Status Read(uint64_t offset, Slice result) const OVERRIDE {
-    return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1));
+    return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1), 
encrypted_);
   }
 
   virtual Status ReadV(uint64_t offset, ArrayView<Slice> results) const 
OVERRIDE {
-    return DoReadV(fd_, filename_, offset, results);
+    return DoReadV(fd_, filename_, offset, results, encrypted_);
   }
 
   virtual Status Size(uint64_t *size) const OVERRIDE {
@@ -715,15 +850,15 @@ class PosixRandomAccessFile: public RandomAccessFile {
 // order to further improve Sync() performance.
 class PosixWritableFile : public WritableFile {
  public:
-  PosixWritableFile(string fname, int fd, uint64_t file_size,
-                    bool sync_on_close)
+  PosixWritableFile(string fname, int fd, uint64_t file_size, bool 
sync_on_close, bool encrypted)
       : filename_(std::move(fname)),
         fd_(fd),
         sync_on_close_(sync_on_close),
         filesize_(file_size),
         pre_allocated_size_(0),
         pending_sync_(false),
-        closed_(false) {}
+        closed_(false),
+        encrypted_(encrypted) {}
 
   ~PosixWritableFile() {
     WARN_NOT_OK(Close(), "Failed to close " + filename_);
@@ -735,7 +870,7 @@ class PosixWritableFile : public WritableFile {
 
   virtual Status AppendV(ArrayView<const Slice> data) OVERRIDE {
     ThreadRestrictions::AssertIOAllowed();
-    RETURN_NOT_OK(DoWriteV(fd_, filename_, filesize_, data));
+    RETURN_NOT_OK(DoWriteV(fd_, filename_, filesize_, data, encrypted_));
     // Calculate the amount of data written
     size_t bytes_written = accumulate(data.begin(), data.end(), 
static_cast<size_t>(0),
                                       [&](int sum, const Slice& curr) {
@@ -857,27 +992,29 @@ class PosixWritableFile : public WritableFile {
   uint64_t pre_allocated_size_;
   bool pending_sync_;
   bool closed_;
+  const bool encrypted_;
 };
 
 class PosixRWFile : public RWFile {
  public:
-  PosixRWFile(string fname, int fd, bool sync_on_close)
+  PosixRWFile(string fname, int fd, bool sync_on_close, bool encrypted)
       : filename_(std::move(fname)),
         fd_(fd),
         sync_on_close_(sync_on_close),
         is_on_xfs_(false),
-        closed_(false) {}
+        closed_(false),
+        encrypted_(encrypted) {}
 
   ~PosixRWFile() {
     WARN_NOT_OK(Close(), "Failed to close " + filename_);
   }
 
   virtual Status Read(uint64_t offset, Slice result) const OVERRIDE {
-    return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1));
+    return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1), 
encrypted_);
   }
 
   virtual Status ReadV(uint64_t offset, ArrayView<Slice> results) const 
OVERRIDE {
-    return DoReadV(fd_, filename_, offset, results);
+    return DoReadV(fd_, filename_, offset, results, encrypted_);
   }
 
   virtual Status Write(uint64_t offset, const Slice& data) OVERRIDE {
@@ -885,7 +1022,7 @@ class PosixRWFile : public RWFile {
   }
 
   virtual Status WriteV(uint64_t offset, ArrayView<const Slice> data) OVERRIDE 
{
-    return DoWriteV(fd_, filename_, offset, data);
+    return DoWriteV(fd_, filename_, offset, data, encrypted_);
   }
 
   virtual Status PreAllocate(uint64_t offset,
@@ -1118,6 +1255,7 @@ class PosixRWFile : public RWFile {
   GoogleOnceDynamic once_;
   bool is_on_xfs_;
   bool closed_;
+  const bool encrypted_;
 };
 
 int LockOrUnlock(int fd, bool lock) {
@@ -1147,6 +1285,12 @@ class PosixEnv : public Env {
   }
 
   virtual Status NewSequentialFile(const string& fname,
+                                   unique_ptr<SequentialFile>* result) 
override {
+    return NewSequentialFile(SequentialFileOptions(), fname, result);
+  }
+
+  virtual Status NewSequentialFile(const SequentialFileOptions& opts,
+                                   const string& fname,
                                    unique_ptr<SequentialFile>* result) 
OVERRIDE {
     TRACE_EVENT1("io", "PosixEnv::NewSequentialFile", "path", fname);
     MAYBE_RETURN_EIO(fname, IOError(Env::kInjectedFailureStatusMsg, EIO));
@@ -1156,7 +1300,7 @@ class PosixEnv : public Env {
     if (f == nullptr) {
       return IOError(fname, errno);
     }
-    result->reset(new PosixSequentialFile(fname, f));
+    result->reset(new PosixSequentialFile(fname, opts.encrypted, f));
     return Status::OK();
   }
 
@@ -1177,7 +1321,7 @@ class PosixEnv : public Env {
       return IOError(fname, errno);
     }
 
-    result->reset(new PosixRandomAccessFile(fname, fd));
+    result->reset(new PosixRandomAccessFile(fname, fd, opts.encrypted));
     return Status::OK();
   }
 
@@ -1219,7 +1363,7 @@ class PosixEnv : public Env {
     TRACE_EVENT1("io", "PosixEnv::NewRWFile", "path", fname);
     int fd;
     RETURN_NOT_OK(DoOpen(fname, opts.mode, &fd));
-    result->reset(new PosixRWFile(fname, fd, opts.sync_on_close));
+    result->reset(new PosixRWFile(fname, fd, opts.sync_on_close, 
opts.encrypted));
     return Status::OK();
   }
 
@@ -1228,7 +1372,7 @@ class PosixEnv : public Env {
     TRACE_EVENT1("io", "PosixEnv::NewTempRWFile", "template", name_template);
     int fd = 0;
     RETURN_NOT_OK(MkTmpFile(name_template, &fd, created_filename));
-    res->reset(new PosixRWFile(*created_filename, fd, opts.sync_on_close));
+    res->reset(new PosixRWFile(*created_filename, fd, opts.sync_on_close, 
opts.encrypted));
     return Status::OK();
   }
 
@@ -1888,7 +2032,7 @@ class PosixEnv : public Env {
     if (opts.mode == MUST_EXIST) {
       RETURN_NOT_OK(GetFileSize(fname, &file_size));
     }
-    result->reset(new PosixWritableFile(fname, fd, file_size, 
opts.sync_on_close));
+    result->reset(new PosixWritableFile(fname, fd, file_size, 
opts.sync_on_close, opts.encrypted));
     return Status::OK();
   }
 
diff --git a/src/kudu/util/openssl_util.h b/src/kudu/util/openssl_util.h
index 03769bd..d1e4b16 100644
--- a/src/kudu/util/openssl_util.h
+++ b/src/kudu/util/openssl_util.h
@@ -53,12 +53,12 @@ typedef struct x509_st X509;
 
 #define OPENSSL_RET_NOT_OK(call, msg) \
   if ((call) <= 0) { \
-    return Status::RuntimeError((msg), GetOpenSSLErrors()); \
+    return Status::RuntimeError((msg), security::GetOpenSSLErrors()); \
   }
 
 #define OPENSSL_RET_IF_NULL(call, msg) \
   if ((call) == nullptr) { \
-    return Status::RuntimeError((msg), GetOpenSSLErrors()); \
+    return Status::RuntimeError((msg), security::GetOpenSSLErrors()); \
   }
 
 // Scoped helper which DCHECKs that on both scope entry and exit, there are no

Reply via email to