1// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef _BSDIFF_EXTENTS_FILE_H_
6#define _BSDIFF_EXTENTS_FILE_H_
7
8#include <stddef.h>
9#include <stdint.h>
10
11#include <memory>
12#include <vector>
13
14#include "bsdiff/file_interface.h"
15
16/*
17 * Extent files.
18 *
19 * This modules provides a familiar interface for handling files through an
20 * indirection layer of extents, which are contiguous chunks of variable length
21 * at arbitrary offsets within a file.  Once an extent file handle is obtained,
22 * users may read, write and seek as they do with ordinary files, having the I/O
23 * with the underlying file done for them by the extent file implementation. The
24 * implementation supports "sparse extents", which are assumed to contain zeros
25 * but otherwise have no actual representation in the underlying file; these are
26 * denoted by negative offset values.
27 *
28 * Unlike ordinary files, the size of an extent file is fixed; it is not
29 * truncated on open, nor is writing past the extent span allowed. Also, writing
30 * to a sparse extent has no effect and will not raise an error.
31 */
32
33namespace bsdiff {
34
35/* An extent, defined by an offset and a length. */
36struct BSDIFF_EXPORT ex_t {
37  off_t off;     // the extent offset; negative indicates a sparse extent.
38  uint64_t len;  // the extent length.
39};
40
41class BSDIFF_EXPORT ExtentsFile : public FileInterface {
42 public:
43  // Creates an ExtentsFile based on the underlying |file| passed. The positions
44  // in the ExtentsFile will be linearly mapped to the extents provided in
45  // |extents|. The created ExtentsFile takes ownership of the |file| will close
46  // it on destruction.
47  ExtentsFile(std::unique_ptr<FileInterface> file,
48              const std::vector<ex_t>& extents);
49
50  ~ExtentsFile() override;
51
52  // FileInterface overrides.
53  bool Read(void* buf, size_t count, size_t* bytes_read) override;
54  bool Write(const void* buf, size_t count, size_t* bytes_written) override;
55  bool Seek(off_t pos) override;
56  bool Close() override;
57  bool GetSize(uint64_t* size) override;
58
59 private:
60  void AdvancePos(uint64_t size);
61
62  // Performs an I/O operation (either read or write). This template shares the
63  // code for both Read() and Write() implementations.
64  template <typename T>
65  bool IOOperation(bool (FileInterface::*io_op)(T*, size_t, size_t*),
66                   T* buf,
67                   size_t count,
68                   size_t* bytes_processed);
69
70  // The underlying FileInterace instance.
71  std::unique_ptr<FileInterface> file_;
72
73  // The list of extents mapping this instance to |file_|.
74  const std::vector<ex_t> extents_;
75
76  // The accumulated length of the extents. The i-th element contains the sum of
77  // the length of all the extents from 0 up to but not including the i-th
78  // extent. This reduces the complexity for random-access Seek() calls.
79  std::vector<uint64_t> acc_len_;
80
81  // Current extent index.
82  size_t curr_ex_idx_{0};
83
84  // Current logical file position.
85  uint64_t curr_pos_{0};
86
87  // Total length of all extents (constant).
88  uint64_t total_ex_len_{0};
89};
90
91}  // namespace bsdiff
92
93#endif  // _BSDIFF_EXTENTS_FILE_H_
94