@Override public boolean putSubpiece(int piece, byte[] bs) throws IOException { // First check if the piece is correct. // If we were paranoid we could copy the array first. synchronized (bitfield) { if (bitfield.get(piece)) { return true; // No need to store twice. } else { bitfield.set(piece, false); needed--; } } assert (this.length != 0); int start = piece * metainfo.getSubpieceSize(0); FileChannel fc = getFileChannel(); long raflen = this.length; while (start > raflen) { start -= raflen; } ByteBuffer bb = ByteBuffer.wrap(bs); fc.position(start); while (bb.hasRemaining()) { fc.write(bb); } return true; }
@Override public String percent() { StringBuilder sb = new StringBuilder(); float p = ((float) (nbSubpieces - needed) / nbSubpieces) * 100; sb.append(p).append("% ").append(bitfield.getChunkHumanReadable()); return sb.toString(); }
@Override public void removeSubpiece(int subpiece) throws IOException { synchronized (bitfield) { bitfield.remove(subpiece); needed++; } }
@Override public List<Integer> missingSubpieces(int piece) { List<Integer> result = new ArrayList<Integer>(); int subpiece; if (bitfield.getPiece(piece)) { System.out.println("bug"); } for (int i = 0; i < BitField.NUM_SUBPIECES_PER_PIECE; i++) { subpiece = piece * BitField.NUM_SUBPIECES_PER_PIECE + i; if (!bitfield.get(subpiece)) { result.add(subpiece); } if (subpiece == metainfo.getnbSubpieces() - 1) { return result; } } return result; }
@Override public byte[] getPiece(int piece) throws IOException { if (!bitfield.getPiece(piece)) { return null; } byte[] bs = new byte[metainfo.getPieceSize(piece)]; getUncheckedPiece(piece, bs); return bs; }
/* create storage from infos about the path */ public StorageFcByteBuf(MetaInfoExec metainfo, String baseDir, boolean seeding) throws IOException { this.metainfo = metainfo; this.baseDir = baseDir; nbSubpieces = metainfo.getnbSubpieces(); bitfield = new BitField(metainfo.getnbSubpieces()); if (!seeding) { needed = metainfo.getnbSubpieces(); } else { needed = 0; for (int i = 0; i < (nbSubpieces / BitField.NUM_SUBPIECES_PER_PIECE) + 1; i++) { for (int j = 0; j < metainfo.getPieceNbSubPieces(i); j++) { bitfield.set(i * BitField.NUM_SUBPIECES_PER_PIECE + j, true); } } } this.length = metainfo.getLength(); }
/** * Returns a byte array containing the requested piece or null if the storage doesn't contain the * piece yet. */ @Override public Map<Integer, byte[]> getSubpieces(int piece) throws IOException { if (!bitfield.getPiece(piece)) { return null; } Map<Integer, byte[]> result = new HashMap<Integer, byte[]>(); int subpiece; for (int i = 0; i < BitField.NUM_SUBPIECES_PER_PIECE; i++) { subpiece = piece * BitField.NUM_SUBPIECES_PER_PIECE + i; byte[] bs = new byte[metainfo.getSubpieceSize(subpiece)]; getUncheckedSubPiece(subpiece, bs, 0); result.put(subpiece, bs); if (subpiece == metainfo.getnbSubpieces() - 1) { return result; } } return result; }
void checkCreateFiles() throws IOException { // boolean resume = false; // Make sure all files are available and of correct length FileChannel fc = getFileChannel(); // Check which pieces match and which don't nbSubpieces = metainfo.getnbSubpieces(); byte[] piece = new byte[metainfo.getSubpieceSize(0) * BitField.NUM_SUBPIECES_PER_PIECE]; for (int i = 0; i < metainfo.getNbChunks(); i++) { if (metainfo.haveHashes(i)) { for (int j = 0; j < metainfo.getChunkNbPieces(i); j++) { if (metainfo.checkPiece( i * BitField.NUM_PIECES_PER_CHUNK + j, getUncheckedPiece(i * BitField.NUM_PIECES_PER_CHUNK + j), 0, metainfo.getPieceSize(i * BitField.NUM_PIECES_PER_CHUNK + j))) { for (int k = 0; k < metainfo.getPieceNbSubPieces(i * BitField.NUM_PIECES_PER_CHUNK + j); k++) { bitfield.set( i * BitField.NUM_PIECES_PER_CHUNK * BitField.NUM_SUBPIECES_PER_PIECE + j * BitField.NUM_SUBPIECES_PER_PIECE + k, true); needed--; } } } } else { byte[] chunkHashes = new byte[BitField.NUM_PIECES_PER_CHUNK * VodConfig.NUM_HASHES_IN_TORRENT_FILE]; for (int j = 0; j < metainfo.getChunkNbPieces(i); j++) { int pieceLength = getUncheckedPiece(i * BitField.NUM_PIECES_PER_CHUNK + j, piece); if (pieceLength == 0) { break; } MessageDigest sha1; try { sha1 = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException nsae) { throw new InternalError("No SHA digest available: " + nsae); } sha1.update(piece, 0, pieceLength); byte[] hash = sha1.digest(); System.arraycopy( hash, 0, chunkHashes, j * VodConfig.NUM_HASHES_IN_TORRENT_FILE, VodConfig.NUM_HASHES_IN_TORRENT_FILE); } boolean correctHash = metainfo.checkChunk( i, chunkHashes, 0, VodConfig.NUM_HASHES_IN_TORRENT_FILE * BitField.NUM_PIECES_PER_CHUNK); if (correctHash) { for (int j = 0; j < metainfo.getChunkNbPieces(i); j++) { for (int k = 0; k < metainfo.getPieceNbSubPieces(i * BitField.NUM_PIECES_PER_CHUNK + j); k++) { bitfield.set( i * BitField.NUM_PIECES_PER_CHUNK * BitField.NUM_SUBPIECES_PER_PIECE + j * BitField.NUM_SUBPIECES_PER_PIECE + k, true); needed--; } } metainfo.setPieceHashes(chunkHashes, i); } } } }
@Override public void create(JProgressBar progressBar) throws IOException { // Calculate piece_hashes MessageDigest digest = null; try { digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException nsa) { throw new InternalError(nsa.toString()); } byte[] pieceHashes = metainfo.getPieceHashes(); byte[] piece = new byte[subpieceSize * BitField.NUM_SUBPIECES_PER_PIECE]; for (int i = 0; i < (nbSubpieces / BitField.NUM_SUBPIECES_PER_PIECE) + 1; i++) { if (progressBar != null && (i % 100 == 0)) { int percentComplete = i / ((nbSubpieces / BitField.NUM_SUBPIECES_PER_PIECE) + 1); progressBar.setValue(percentComplete); } int pieceLength = getUncheckedPiece(i, piece); if (pieceLength > 0) { digest.update(piece, 0, pieceLength); byte[] hash = digest.digest(); System.arraycopy( hash, 0, pieceHashes, VodConfig.NUM_HASHES_IN_TORRENT_FILE * i, VodConfig.NUM_HASHES_IN_TORRENT_FILE); for (int j = 0; j < metainfo.getPieceNbSubPieces(i); j++) { bitfield.set(i * BitField.NUM_SUBPIECES_PER_PIECE + j, true); } } } boolean[] initializedPieceHash = metainfo.getInitializedPieceHashes(); byte[] chunkHash = metainfo.getChunksHashes(); byte[] chunk = new byte[BitField.NUM_PIECES_PER_CHUNK * VodConfig.NUM_HASHES_IN_TORRENT_FILE]; for (int i = 0; i < pieceHashes.length / BitField.NUM_PIECES_PER_CHUNK / VodConfig.NUM_HASHES_IN_TORRENT_FILE; i++) { for (int j = 0; j < BitField.NUM_PIECES_PER_CHUNK * VodConfig.NUM_HASHES_IN_TORRENT_FILE; j++) { chunk[j] = pieceHashes[ i * BitField.NUM_PIECES_PER_CHUNK * VodConfig.NUM_HASHES_IN_TORRENT_FILE + j]; } digest.update(chunk, 0, chunk.length); byte[] hash = digest.digest(); System.arraycopy( hash, 0, chunkHash, VodConfig.NUM_HASHES_IN_TORRENT_FILE * i, VodConfig.NUM_HASHES_IN_TORRENT_FILE); initializedPieceHash[i] = true; } // Reannounce to force recalculating the info_hash. metainfo = metainfo.reannounce(); }