예제 #1
0
  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");
      }
    }
  }
예제 #2
0
  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);
    }
  }
예제 #3
0
  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();
        }
      }
    }
  }