protected void setControlFile() { TOTorrentFile tf = owner.getOwner().getTorrentFile(); if (tf == null) { controlFileName = null; control_dir = null; } else { TOTorrent torrent = tf.getTorrent(); TOTorrentFile[] files = torrent.getFiles(); int file_index = -1; for (int i = 0; i < files.length; i++) { if (files[i] == tf) { file_index = i; break; } } if (file_index == -1) { Debug.out("File '" + owner.getName() + "' not found in torrent!"); controlFileName = null; control_dir = null; } else { control_dir = owner.getOwner().getControlFileDir(); controlFileName = StringInterner.intern("fmfile" + file_index + ".dat"); } } }
protected FMFileAccessController(FMFileImpl _file, int _target_type) throws FMFileManagerException { if (TEST_PIECE_REORDER) { _target_type = FMFile.FT_PIECE_REORDER; } owner = _file; // actual file shouldn't exist for change to occur - it is the responsibility // of the caller to delete the file first and take consequent actions (in // particular force recheck the file to ensure that the loss in save state // is represented in the resume view of the world ) // in the future, if we support format conversion, this obviously changes setControlFile(); if (control_dir == null) { // Debug.out( "No control file" ); in optimised environments we don't support compact and // return null here if (_target_type == FMFile.FT_LINEAR) { file_access = new FMFileAccessLinear(owner); } else { throw (new FMFileManagerException( "Compact storage not supported: no control file available")); } } else { if (new File(control_dir, controlFileName).exists()) { type = FMFile.FT_COMPACT; } else if (new File(control_dir, controlFileName + REORDER_SUFFIX).exists()) { type = _target_type == FMFile.FT_PIECE_REORDER ? FMFile.FT_PIECE_REORDER : FMFile.FT_PIECE_REORDER_COMPACT; } else { if ((_target_type == FMFile.FT_PIECE_REORDER || _target_type == FMFile.FT_PIECE_REORDER_COMPACT)) { File target_file = owner.getLinkedFile(); if (target_file.exists()) { FMFileAccessPieceReorderer.recoverConfig( owner.getOwner().getTorrentFile(), target_file, new File(control_dir, controlFileName + REORDER_SUFFIX), _target_type); } type = _target_type; } else { type = FMFile.FT_LINEAR; } } if (type == FMFile.FT_LINEAR) { file_access = new FMFileAccessLinear(owner); } else if (type == FMFile.FT_COMPACT) { file_access = new FMFileAccessCompact( owner.getOwner().getTorrentFile(), control_dir, controlFileName, new FMFileAccessLinear(owner)); } else { file_access = new FMFileAccessPieceReorderer( owner.getOwner().getTorrentFile(), control_dir, controlFileName + REORDER_SUFFIX, type, new FMFileAccessLinear(owner)); } convert(_target_type); } }
protected void convert(int target_type) throws FMFileManagerException { if (type == target_type) { return; } if (type == FMFile.FT_PIECE_REORDER || target_type == FMFile.FT_PIECE_REORDER) { if (target_type == FMFile.FT_PIECE_REORDER_COMPACT || type == FMFile.FT_PIECE_REORDER_COMPACT) { // these two access modes are in fact identical at the moment type = target_type; return; } throw (new FMFileManagerException("Conversion to/from piece-reorder not supported")); } File file = owner.getLinkedFile(); RandomAccessFile raf = null; boolean ok = false; try { FMFileAccess target_access; if (target_type == FMFile.FT_LINEAR) { target_access = new FMFileAccessLinear(owner); } else { target_access = new FMFileAccessCompact( owner.getOwner().getTorrentFile(), control_dir, controlFileName, new FMFileAccessLinear(owner)); } if (file.exists()) { raf = new RandomAccessFile(file, FMFileImpl.WRITE_ACCESS_MODE); // due to the simplistic implementation of compact we only actually need to deal with // the last piece of the file (first piece is in the right place already) FMFileAccessCompact compact_access; if (target_type == FMFile.FT_LINEAR) { compact_access = (FMFileAccessCompact) file_access; } else { compact_access = (FMFileAccessCompact) target_access; } long length = file_access.getLength(raf); long last_piece_start = compact_access.getLastPieceStart(); long last_piece_length = compact_access.getLastPieceLength(); // see if we have any potential data for the last piece if (last_piece_length > 0 && length > last_piece_start) { long data_length = length - last_piece_start; if (data_length > last_piece_length) { Debug.out( "data length inconsistent: len=" + data_length + ",limit=" + last_piece_length); data_length = last_piece_length; } DirectByteBuffer buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_FILE, (int) data_length); try { file_access.read(raf, new DirectByteBuffer[] {buffer}, last_piece_start); // see if we need to truncate if (target_type == FMFile.FT_COMPACT) { long first_piece_length = compact_access.getFirstPieceLength(); long physical_length = raf.length(); if (physical_length > first_piece_length) { raf.setLength(first_piece_length); } } buffer.flip(DirectByteBuffer.AL_FILE); target_access.write(raf, new DirectByteBuffer[] {buffer}, last_piece_start); } finally { buffer.returnToPool(); } } else { // no last piece, truncate after the first piece if (target_type == FMFile.FT_COMPACT) { long first_piece_length = compact_access.getFirstPieceLength(); long physical_length = raf.length(); if (physical_length > first_piece_length) { raf.setLength(first_piece_length); } } } target_access.setLength(raf, length); target_access.flush(); } type = target_type; file_access = target_access; ok = true; } catch (Throwable e) { Debug.printStackTrace(e); throw (new FMFileManagerException("convert fails", e)); } finally { try { if (raf != null) { try { raf.close(); } catch (Throwable e) { // override original exception if there isn't one if (ok) { ok = false; throw (new FMFileManagerException("convert fails", e)); } } } } finally { if (!ok) { // conversion failed - replace with linear access, caller is responsible for // handling this (marking file requiring recheck) type = FMFile.FT_LINEAR; file_access = new FMFileAccessLinear(owner); } if (type == FMFile.FT_LINEAR) { new File(control_dir, controlFileName).delete(); } } } }