AU: Extent writer utility classes

These are similar to the FileWriter classes, but focus on writing to
extents within a file (or device) rather than writing a file in order.

Again there is a ExtentWriter interface from which all types of extent
writers interit.

There are also two basic extent writers: a direct extent writer that
writes data directly to the file descriptor, and a zero padding extent
writer that piggy-backs on another extent writer. When the
zero-padding extent writer is End()ed, it fills out the rest of the
extent with zeros.

Also, BzipExtentWriter: an ExtentWriter concrete subclass that writes
to another ExtentWriter.  BzipExtentWriter bzip2 decompresses all data
passed through.

Review URL: http://codereview.chromium.org/551132
diff --git a/extent_writer.h b/extent_writer.h
new file mode 100644
index 0000000..cbb62fe
--- /dev/null
+++ b/extent_writer.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_EXTENT_WRITER_H__
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_EXTENT_WRITER_H__
+
+#include <vector>
+#include "chromeos/obsolete_logging.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/utils.h"
+
+// ExtentWriter is an abstract class which synchronously writes to a given
+// file descriptor at the extents given.
+
+namespace chromeos_update_engine {
+
+// When an extent's start block is kSparseHole, that data written for that
+// extent will be dropped rather than written to the unerlying fd.
+const uint64 kSparseHole = kuint64max;
+
+class ExtentWriter {
+ public:
+  ExtentWriter() : end_called_(false) {}
+  virtual ~ExtentWriter() {
+    LOG_IF(ERROR, !end_called_) << "End() not called on ExtentWriter.";
+  }
+
+  // Returns true on success.
+  virtual bool Init(int fd,
+                    const std::vector<Extent>& extents,
+                    size_t block_size) = 0;
+
+  // Returns true on success.
+  virtual bool Write(const void* bytes, size_t count) = 0;
+
+  // Should be called when all writing is complete. Returns true on success.
+  // The fd is not closed. Caller is responsible for closing it.
+  bool End() {
+    end_called_ = true;
+    return EndImpl();
+  }
+  virtual bool EndImpl() = 0;
+ private:
+  bool end_called_;
+};
+
+// DirectExtentWriter is probably the simplest ExtentWriter implementation.
+// It writes the data directly into the extents.
+
+class DirectExtentWriter : public ExtentWriter {
+ public:
+  DirectExtentWriter()
+      : fd_(-1),
+        block_size_(0),
+        extent_bytes_written_(0),
+        next_extent_index_(0) {}
+  ~DirectExtentWriter() {}
+
+  bool Init(int fd, const std::vector<Extent>& extents, size_t block_size) {
+    fd_ = fd;
+    block_size_ = block_size;
+    extents_ = extents;
+    return true;
+  }
+  bool Write(const void* bytes, size_t count);
+  bool EndImpl() {
+    return true;
+  }
+
+ private:
+  int fd_;
+  
+  size_t block_size_;
+  // Bytes written into next_extent_index_ thus far
+  uint64 extent_bytes_written_;
+  std::vector<Extent> extents_;
+  // The next call to write should correspond to extents_[next_extent_index_]
+  std::vector<Extent>::size_type next_extent_index_;
+};
+
+// Takes an underlying ExtentWriter to which all operations are delegated.
+// When End() is called, ZeroPadExtentWriter ensures that the total number
+// of bytes written is a multiple of block_size_. If not, it writes zeros
+// to pad as needed.
+
+class ZeroPadExtentWriter : public ExtentWriter {
+ public:
+  ZeroPadExtentWriter(ExtentWriter* underlying_extent_writer)
+      : underlying_extent_writer_(underlying_extent_writer),
+        block_size_(0),
+        bytes_written_mod_block_size_(0) {}
+  ~ZeroPadExtentWriter() {}
+
+  bool Init(int fd, const std::vector<Extent>& extents, size_t block_size) {
+    block_size_ = block_size;
+    return underlying_extent_writer_->Init(fd, extents, block_size);
+  }
+  bool Write(const void* bytes, size_t count) {
+    if (underlying_extent_writer_->Write(bytes, count)) {
+      bytes_written_mod_block_size_ += count;
+      bytes_written_mod_block_size_ %= block_size_;
+      return true;
+    }
+    return false;
+  }
+  bool EndImpl() {
+    if (bytes_written_mod_block_size_) {
+      const size_t write_size = block_size_ - bytes_written_mod_block_size_;
+      std::vector<char> zeros(write_size, 0);
+      TEST_AND_RETURN_FALSE(underlying_extent_writer_->Write(&zeros[0],
+                                                             write_size));
+    }
+    return underlying_extent_writer_->End();
+  }
+
+ private:
+  ExtentWriter* underlying_extent_writer_;  // The underlying ExtentWriter.
+  size_t block_size_;
+  size_t bytes_written_mod_block_size_;
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_EXTENT_WRITER_H__