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 }