1 /*
2 * Copyright (C) 2017, Google Inc. and others
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 */
10
11 package org.eclipse.jgit.internal.storage.io;
12
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.nio.ByteBuffer;
16 import java.nio.channels.FileChannel;
17
18 /**
19 * Provides content blocks of file.
20 * <p>
21 * {@code BlockSource} implementations must decide if they will be thread-safe,
22 * or not.
23 */
24 public abstract class BlockSource implements AutoCloseable {
25 /**
26 * Wrap a byte array as a {@code BlockSource}.
27 *
28 * @param content
29 * input file.
30 * @return block source to read from {@code content}.
31 */
32 public static BlockSource from(byte[] content) {
33 return new BlockSource() {
34 @Override
35 public ByteBuffer read(long pos, int cnt) {
36 ByteBuffer buf = ByteBuffer.allocate(cnt);
37 if (pos < content.length) {
38 int p = (int) pos;
39 int n = Math.min(cnt, content.length - p);
40 buf.put(content, p, n);
41 }
42 return buf;
43 }
44
45 @Override
46 public long size() {
47 return content.length;
48 }
49
50 @Override
51 public void close() {
52 // Do nothing.
53 }
54 };
55 }
56
57 /**
58 * Read from a {@code FileInputStream}.
59 * <p>
60 * The returned {@code BlockSource} is not thread-safe, as it must seek the
61 * file channel to read a block.
62 *
63 * @param in
64 * the file. The {@code BlockSource} will close {@code in}.
65 * @return wrapper for {@code in}.
66 */
67 public static BlockSource from(FileInputStream in) {
68 return from(in.getChannel());
69 }
70
71 /**
72 * Read from a {@code FileChannel}.
73 * <p>
74 * The returned {@code BlockSource} is not thread-safe, as it must seek the
75 * file channel to read a block.
76 *
77 * @param ch
78 * the file. The {@code BlockSource} will close {@code ch}.
79 * @return wrapper for {@code ch}.
80 */
81 public static BlockSource from(FileChannel ch) {
82 return new BlockSource() {
83 @Override
84 public ByteBuffer read(long pos, int blockSize) throws IOException {
85 ByteBuffer b = ByteBuffer.allocate(blockSize);
86 ch.position(pos);
87 int n;
88 do {
89 n = ch.read(b);
90 } while (n > 0 && b.position() < blockSize);
91 return b;
92 }
93
94 @Override
95 public long size() throws IOException {
96 return ch.size();
97 }
98
99 @Override
100 public void close() {
101 try {
102 ch.close();
103 } catch (IOException e) {
104 // Ignore close failures of read-only files.
105 }
106 }
107 };
108 }
109
110 /**
111 * Read a block from the file.
112 * <p>
113 * To reduce copying, the returned ByteBuffer should have an accessible
114 * array and {@code arrayOffset() == 0}. The caller will discard the
115 * ByteBuffer and directly use the backing array.
116 *
117 * @param position
118 * position of the block in the file, specified in bytes from the
119 * beginning of the file.
120 * @param blockSize
121 * size to read.
122 * @return buffer containing the block content.
123 * @throws java.io.IOException
124 * if block cannot be read.
125 */
126 public abstract ByteBuffer read(long position, int blockSize)
127 throws IOException;
128
129 /**
130 * Determine the size of the file.
131 *
132 * @return total number of bytes in the file.
133 * @throws java.io.IOException
134 * if size cannot be obtained.
135 */
136 public abstract long size() throws IOException;
137
138 /**
139 * Advise the {@code BlockSource} a sequential scan is starting.
140 *
141 * @param startPos
142 * starting position.
143 * @param endPos
144 * ending position.
145 */
146 public void adviseSequentialRead(long startPos, long endPos) {
147 // Do nothing by default.
148 }
149
150 /** {@inheritDoc} */
151 @Override
152 public abstract void close();
153 }