/*
* Created on 1 Nov 2006
* Created by Paul Gardner
* Copyright (C) 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 63.529,40 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.disk.impl;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.disk.*;
import org.gudy.azureus2.core3.disk.impl.resume.RDResumeHandler;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerException;
import org.gudy.azureus2.core3.download.DownloadManagerState;
import org.gudy.azureus2.core3.internat.LocaleTorrentUtil;
import org.gudy.azureus2.core3.internat.LocaleUtilDecoder;
import org.gudy.azureus2.core3.logging.LogAlert;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.diskmanager.cache.CacheFile;
import com.aelitis.azureus.core.diskmanager.cache.CacheFileManagerFactory;
import com.aelitis.azureus.core.diskmanager.cache.CacheFileOwner;
import com.aelitis.azureus.core.diskmanager.file.FMFileManagerFactory;
public class
DiskManagerUtil
{
private static final LogIDs LOGID = LogIDs.DISK;
protected static int max_read_block_size;
static{
ParameterListener param_listener = new ParameterListener() {
public void
parameterChanged(
String str )
{
max_read_block_size = COConfigurationManager.getIntParameter( "BT Request Max Block Size" );
}
};
COConfigurationManager.addAndFireParameterListener( "BT Request Max Block Size", param_listener);
}
public static boolean
checkBlockConsistencyForHint(
DiskManager dm,
String originator,
int pieceNumber,
int offset,
int length)
{
if (length <= 0 ) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " length=" + length + " <= 0"));
return false;
}
if (pieceNumber < 0) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " pieceNumber=" + pieceNumber + " < 0"));
return false;
}
if (pieceNumber >= dm.getNbPieces()) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " pieceNumber=" + pieceNumber + " >= this.nbPieces="
+ dm.getNbPieces()));
return false;
}
int pLength = dm.getPieceLength(pieceNumber);
if (offset < 0) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " offset=" + offset + " < 0"));
return false;
}
if (offset > pLength) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " offset=" + offset + " > pLength=" + pLength));
return false;
}
if (offset + length > pLength) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Hint invalid: " + originator + " offset=" + offset + " + length=" + length
+ " > pLength=" + pLength));
return false;
}
return true;
}
public static boolean
checkBlockConsistencyForRead(
DiskManager dm,
String originator,
boolean peer_request,
int pieceNumber,
int offset,
int length)
{
if ( !checkBlockConsistencyForHint( dm, originator, pieceNumber, offset, length )){
return( false );
}
if (length > max_read_block_size && peer_request) {
if (Logger.isEnabled())
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Read invalid: " + originator + " length=" + length + " > " + max_read_block_size));
return false;
}
if(!dm.getPiece(pieceNumber).isDone()) {
Logger.log(new LogEvent(dm, LOGID, LogEvent.LT_ERROR,
"Read invalid: " + originator + " piece #" + pieceNumber + " not done"));
return false;
}
return true;
}
public static void doFileExistenceChecks(DiskManagerFileInfoSet fileSet, boolean[] toCheck, DownloadManager dm, boolean allowAlloction)
{
DiskManagerFileInfo[] files = fileSet.getFiles();
int lastPieceScanned = -1;
int windowStart = -1;
int windowEnd = -1;
String[] types = DiskManagerImpl.getStorageTypes(dm);
// sweep over all files to see if adjacent files of changed files can be deleted or need allocation
for(int i = 0; i< files.length;i++)
{
int firstPiece = files[i].getFirstPieceNumber();
int lastPiece = files[i].getLastPieceNumber();
if(toCheck[i])
{ // found a file that changed, scan adjacent files
if(lastPieceScanned < firstPiece)
{ // haven't checked the preceding files, slide backwards
windowStart = firstPiece;
while(i > 0 && files[i-1].getLastPieceNumber() >= windowStart)
i--;
}
if(windowEnd < lastPiece)
windowEnd = lastPiece;
}
if((windowStart <= firstPiece && firstPiece <= windowEnd) || (windowStart <= lastPiece && lastPiece <= windowEnd))
{ // file falls in current scanning window, check it
File currentFile = files[i].getFile(true);
if(!RDResumeHandler.fileMustExist(dm, files[i]))
{
int st = convertDMStorageTypeFromString( types[i] );
if( st == DiskManagerFileInfo.ST_COMPACT || st == DiskManagerFileInfo.ST_REORDER_COMPACT ){
currentFile.delete();
}
} else if(allowAlloction && !currentFile.exists()) {
/*
* file must exist, does not exist and we probably just changed to linear
* mode, assume that (re)allocation of adjacent files is necessary
*/
dm.setDataAlreadyAllocated(false);
}
lastPieceScanned = lastPiece;
}
}
}
private static AEMonitor cache_read_mon = new AEMonitor( "DiskManager:cacheRead" );
private static boolean
setFileLink(
DownloadManager download_manager,
DiskManagerFileInfo[] info,
DiskManagerFileInfo file_info,
File from_file,
File to_link )
{
// existing link is that for the TO_LINK and will come back as TO_LINK if no link is defined
File existing_link = FMFileManagerFactory.getSingleton().getFileLink( download_manager.getTorrent(), to_link );
if ( !existing_link.equals( to_link )){
// where we're mapping to is already linked somewhere else. Only case we support
// is where this is a remapping of the same file back to where it came from
if ( !from_file.equals( to_link )){
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR,
"Attempt to link to existing link '" + existing_link.toString()
+ "'"));
return( false );
}
}
File existing_file = file_info.getFile( true );
if ( to_link.equals( existing_file )){
// already pointing to the right place
return( true );
}
for (int i=0;i<info.length;i++){
if ( to_link.equals( info[i].getFile( true ))){
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR,
"Attempt to link to existing file '" + info[i].getFile(true)
+ "'"));
return( false );
}
}
if ( to_link.exists()){
if ( !existing_file.exists()){
// using a new file, make sure we recheck
download_manager.recheckFile( file_info );
}else{
if ( FileUtil.deleteWithRecycle(
existing_file,
download_manager.getDownloadState().getFlag( DownloadManagerState.FLAG_LOW_NOISE ))){
// new file, recheck
download_manager.recheckFile( file_info );
}else{
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR,
"Failed to delete '" + existing_file.toString() + "'"));
return( false );
}
}
}else{
if ( existing_file.exists()){
if ( !FileUtil.renameFile( existing_file, to_link )){
Logger.log(new LogAlert(download_manager, LogAlert.REPEATABLE, LogAlert.AT_ERROR,
"Failed to rename '" + existing_file.toString() + "'" ));
return( false );
}
}
}
DownloadManagerState state = download_manager.getDownloadState();
state.setFileLink( from_file, to_link );
state.save();
return( true );
}
static abstract class FileSkeleton implements DiskManagerFileInfoHelper {
protected int priority;
protected boolean skipped;
protected long downloaded;
}
public static DiskManagerFileInfoSet
getFileInfoSkeleton(
final DownloadManager download_manager,
final DiskManagerListener listener )
{
TOTorrent torrent = download_manager.getTorrent();
if ( torrent == null ){
return( new DiskManagerFileInfoSetImpl(new DiskManagerFileInfoImpl[0],null) );
}
String tempRootDir = download_manager.getAbsoluteSaveLocation().getParent();
if(tempRootDir == null) // in case we alraedy are at the root
tempRootDir = download_manager.getAbsoluteSaveLocation().getPath();
if ( !torrent.isSimpleTorrent()){
tempRootDir += File.separator + download_manager.getAbsoluteSaveLocation().getName();
}
tempRootDir += File.separator;
final String root_dir = StringInterner.intern(tempRootDir) ;
try{
final LocaleUtilDecoder locale_decoder = LocaleTorrentUtil.getTorrentEncoding( torrent );
TOTorrentFile[] torrent_files = torrent.getFiles();
final FileSkeleton[] res = new FileSkeleton[ torrent_files.length ];
final String incomplete_suffix = download_manager.getDownloadState().getAttribute( DownloadManagerState.AT_INCOMP_FILE_SUFFIX );
final DiskManagerFileInfoSet fileSetSkeleton = new DiskManagerFileInfoSet() {
public DiskManagerFileInfo[] getFiles() {
return res;
}
public int nbFiles() {
return res.length;
}
public void setPriority(int[] toChange) {
if(toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
for(int i=0;i<res.length;i++)
res[i].priority = toChange[i];
DiskManagerImpl.storeFilePriorities( download_manager, res);
for(int i=0;i<res.length;i++)
if(toChange[i] > 0 )
listener.filePriorityChanged(res[i]);
}
public void setSkipped(boolean[] toChange, boolean setSkipped) {
if(toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
if (!setSkipped ){
String[] types = DiskManagerImpl.getStorageTypes(download_manager);
boolean[] toLinear = new boolean[toChange.length];
boolean[] toReorder = new boolean[toChange.length];
int num_linear = 0;
int num_reorder = 0;
for ( int i=0;i<toChange.length;i++){
if ( toChange[i] ){
int old_type = DiskManagerUtil.convertDMStorageTypeFromString( types[i] );
if ( old_type == DiskManagerFileInfo.ST_COMPACT ){
toLinear[i] = true;
num_linear++;
}else if ( old_type == DiskManagerFileInfo.ST_REORDER_COMPACT ){
toReorder[i] = true;
num_reorder++;
}
}
}
if ( num_linear > 0 ){
if (!Arrays.equals(toLinear, setStorageTypes(toLinear, DiskManagerFileInfo.ST_LINEAR))){
return;
}
}
if ( num_reorder > 0 ){
if (!Arrays.equals(toReorder, setStorageTypes(toReorder, DiskManagerFileInfo.ST_REORDER ))){
return;
}
}
}
for(int i=0;i<res.length;i++)
if(toChange[i])
res[i].skipped = setSkipped;
if(!setSkipped)
doFileExistenceChecks(this, toChange, download_manager, true);
DiskManagerImpl.storeFilePriorities( download_manager, res);
for(int i=0;i<res.length;i++)
if(toChange[i])
listener.filePriorityChanged(res[i]);
}
public boolean[] setStorageTypes(boolean[] toChange, int newStorageType) {
if(toChange.length != res.length)
throw new IllegalArgumentException("array length mismatches the number of files");
String[] types = DiskManagerImpl.getStorageTypes(download_manager);
boolean[] modified = new boolean[res.length];
boolean[] toSkip = new boolean[res.length];
int toSkipCount = 0;
DownloadManagerState dmState = download_manager.getDownloadState();
try {
dmState.suppressStateSave(true);
for(int i=0;i<res.length;i++)
{
if(!toChange[i])
continue;
final int idx = i;
int old_type = DiskManagerUtil.convertDMStorageTypeFromString( types[i] );
//System.out.println(old_type + " <> " + newStroageType);
if ( newStorageType == old_type )
{
modified[i] = true;
continue;
}
try{
File target_file = res[i].getFile( true );
// if the file doesn't exist then this is the start-of-day, most likely
// being called from the torrent-opener, so we don't need to do any
// file fiddling (in fact, if we do, we end up leaving zero length
// files for dnd files which then force a recheck when the download
// starts for the first time)
if ( target_file.exists()){
CacheFile cache_file =
CacheFileManagerFactory.getSingleton().createFile(
new CacheFileOwner()
{
public String
getCacheFileOwnerName()
{
return( download_manager.getInternalName());
}
public TOTorrentFile
getCacheFileTorrentFile()
{
return( res[idx].getTorrentFile() );
}
public File
getCacheFileControlFileDir()
{
return( download_manager.getDownloadState().getStateFile( ));
}
public int
getCacheMode()
{
return( CacheFileOwner.CACHE_MODE_NORMAL );
}
},
target_file,
DiskManagerUtil.convertDMStorageTypeToCache( newStorageType ));
cache_file.close();
toSkip[i] = ( newStorageType == FileSkeleton.ST_COMPACT || newStorageType == FileSkeleton.ST_REORDER_COMPACT )&& !res[i].isSkipped();
if(toSkip[i])
toSkipCount++;
}
modified[i] = true;
}catch( Throwable e ){
Debug.printStackTrace(e);
Logger.log(
new LogAlert(download_manager,
LogAlert.REPEATABLE,
LogAlert.AT_ERROR,
"Failed to change storage type for '" + res[i].getFile(true) +"': " + Debug.getNestedExceptionMessage(e)));
// download's not running - tag for recheck
RDResumeHandler.recheckFile( download_manager, res[i] );
}
types[i] = DiskManagerUtil.convertDMStorageTypeToString( newStorageType );
}
/*
* set storage type and skipped before we do piece clearing and file
* clearing checks as those checks work better when skipped/stype is set
* properly
*/
dmState.setListAttribute( DownloadManagerState.AT_FILE_STORE_TYPES, types);
if(toSkipCount > 0)
setSkipped(toSkip, true);
for(int i=0;i<res.length;i++)
{
if(!toChange[i])
continue;
// download's not running, update resume data as necessary
int cleared = RDResumeHandler.storageTypeChanged( download_manager, res[i] );
// try and maintain reasonable figures for downloaded. Note that because
// we don't screw with the first and last pieces of the file during
// storage type changes we don't have the problem of dealing with
// the last piece being smaller than torrent piece size
if (cleared > 0)
{
res[i].downloaded = res[i].downloaded - cleared * res[i].getTorrentFile().getTorrent().getPieceLength();
if (res[i].downloaded < 0) res[i].downloaded = 0;
}
}
DiskManagerImpl.storeFileDownloaded( download_manager, res, true );
doFileExistenceChecks(this, toChange, download_manager, newStorageType == FileSkeleton.ST_LINEAR || newStorageType == FileSkeleton.ST_REORDER );
} finally {
dmState.suppressStateSave(false);
dmState.save();
}
return modified;
}
};
for (int i=0;i<res.length;i++){
final TOTorrentFile torrent_file = torrent_files[i];
final int file_index = i;
FileSkeleton info = new FileSkeleton() {
private CacheFile read_cache_file;
// do not access this field directly, use lazyGetFile() instead
private WeakReference dataFile = new WeakReference(null);
public void
setPriority(int b)
{
priority = b;
DiskManagerImpl.storeFilePriorities( download_manager, res );
listener.filePriorityChanged( this );
}
public void
setSkipped(boolean _skipped)
{
if ( !_skipped && getStorageType() == ST_COMPACT ){
if ( !setStorageType( ST_LINEAR )){
return;
}
}
if ( !_skipped && getStorageType() == ST_REORDER_COMPACT ){
if ( !setStorageType( ST_REORDER )){
return;
}
}
skipped = _skipped;
DiskManagerImpl.storeFilePriorities( download_manager, res );
if(!_skipped)
{
boolean[] toCheck = new boolean[fileSetSkeleton.nbFiles()];
toCheck[file_index] = true;
doFileExistenceChecks(fileSetSkeleton, toCheck, download_manager, true);
}
listener.filePriorityChanged( this );
}
public int
getAccessMode()
{
return( READ );
}
public long
getDownloaded()
{
return( downloaded );
}
public void
setDownloaded(
long l )
{
downloaded = l;
}
public String
getExtension()
{
String ext = lazyGetFile().getName();
if ( incomplete_suffix != null && ext.endsWith( incomplete_suffix )){
ext = ext.substring( 0, ext.length() - incomplete_suffix.length());
}
int separator = ext.lastIndexOf(".");
if (separator == -1)
separator = 0;
return ext.substring(separator);
}
public int
getFirstPieceNumber()
{
return( torrent_file.getFirstPieceNumber());
}
public int
getLastPieceNumber()
{
return( torrent_file.getLastPieceNumber());
}
public long
getLength()
{
return( torrent_file.getLength());
}
public int
getIndex()
{
return( file_index );
}
public int
getNbPieces()
{
return( torrent_file.getNumberOfPieces());
}
public int
getPriority()
{
return( priority );
}
public boolean
isSkipped()
{
return( skipped );
}
public DiskManager
getDiskManager()
{
return( null );
}
public DownloadManager
getDownloadManager()
{
return( download_manager );
}
public File
getFile(
boolean follow_link )
{
if ( follow_link ){
File link = getLink();
if ( link != null ){
return( link );
}
}
return lazyGetFile();
}
private File lazyGetFile()
{
File toReturn = (File)dataFile.get();
if(toReturn != null)
return toReturn;
TOTorrent tor = download_manager.getTorrent();
String path_str = root_dir;
File simpleFile = null;
// for a simple torrent the target file can be changed
if ( tor.isSimpleTorrent()){
simpleFile = download_manager.getAbsoluteSaveLocation();
}else{
byte[][]path_comps = torrent_file.getPathComponents();
for (int j=0;j<path_comps.length;j++){
String comp;
try
{
comp = locale_decoder.decodeString( path_comps[j] );
} catch (UnsupportedEncodingException e)
{
Debug.printStackTrace(e);
comp = "undecodableFileName"+file_index;
}
comp = FileUtil.convertOSSpecificChars( comp, j != path_comps.length-1 );
path_str += (j==0?"":File.separator) + comp;
}
}
dataFile = new WeakReference(toReturn = simpleFile != null ? simpleFile : new File( path_str ));
//System.out.println("new file:"+toReturn);
return toReturn;
}
public TOTorrentFile
getTorrentFile()
{
return( torrent_file );
}
public boolean
setLink(
File link_destination )
{
/**
* If we a simple torrent, then we'll redirect the call to the download and move the
* data files that way - that'll keep everything in sync.
*/
if (download_manager.getTorrent().isSimpleTorrent()) {
try {
download_manager.moveDataFiles(link_destination.getParentFile(), link_destination.getName());
return true;
}
catch (DownloadManagerException e) {
// What should we do with the error?
return false;
}
}
return setLinkAtomic(link_destination);
}
public boolean
setLinkAtomic(
File link_destination )
{
return( setFileLink( download_manager, res, this, lazyGetFile(), link_destination ));
}
public File
getLink()
{
return( download_manager.getDownloadState().getFileLink( lazyGetFile() ));
}
public boolean setStorageType(int type) {
boolean[] change = new boolean[res.length];
change[file_index] = true;
return fileSetSkeleton.setStorageTypes(change, type)[file_index];
}
public int
getStorageType()
{
return( DiskManagerUtil.convertDMStorageTypeFromString( DiskManagerImpl.getStorageType(download_manager, file_index)));
}
public void
flushCache()
{
}
public DirectByteBuffer
read(
long offset,
int length )
throws IOException
{
CacheFile temp;;
try{
cache_read_mon.enter();
if ( read_cache_file == null ){
try{
int type = convertDMStorageTypeFromString( DiskManagerImpl.getStorageType(download_manager, file_index));
read_cache_file =
CacheFileManagerFactory.getSingleton().createFile(
new CacheFileOwner()
{
public String
getCacheFileOwnerName()
{
return( download_manager.getInternalName());
}
public TOTorrentFile
getCacheFileTorrentFile()
{
return( torrent_file );
}
public File
getCacheFileControlFileDir()
{
return( download_manager.getDownloadState().getStateFile( ));
}
public int
getCacheMode()
{
return( CacheFileOwner.CACHE_MODE_NORMAL );
}
},
getFile( true ),
convertDMStorageTypeToCache( type ));
}catch( Throwable e ){
Debug.printStackTrace(e);
throw( new IOException( e.getMessage()));
}
}
temp = read_cache_file;
}finally{
cache_read_mon.exit();
}
DirectByteBuffer buffer =
DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_DM_READ, length );
try{
temp.read( buffer, offset, CacheFile.CP_READ_CACHE );
}catch( Throwable e ){
buffer.returnToPool();
Debug.printStackTrace(e);
throw( new IOException( e.getMessage()));
}
return( buffer );
}
public void
close()
{
CacheFile temp;
try{
cache_read_mon.enter();
temp = read_cache_file;
read_cache_file = null;
}finally{
cache_read_mon.exit();
}
if ( temp != null ){
try{
temp.close();
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
public void
addListener(
DiskManagerFileInfoListener listener )
{
if ( getDownloaded() == getLength()){
try{
listener.dataWritten( 0, getLength());
listener.dataChecked( 0, getLength());
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
public void
removeListener(
DiskManagerFileInfoListener listener )
{
}
};
res[i] = info;
}
loadFilePriorities( download_manager, fileSetSkeleton);
loadFileDownloaded( download_manager, res );
return( fileSetSkeleton );
}catch( Throwable e ){
Debug.printStackTrace(e);
return( new DiskManagerFileInfoSetImpl(new DiskManagerFileInfoImpl[0],null) );
}
}
public static int
convertDMStorageTypeFromString(
String str )
{
char c = str.charAt(0);
switch( c ){
case 'L':{
return( DiskManagerFileInfo.ST_LINEAR );
}
case 'C':{
return( DiskManagerFileInfo.ST_COMPACT );
}
case 'R':{
return( DiskManagerFileInfo.ST_REORDER );
}
case 'X':{
return( DiskManagerFileInfo.ST_REORDER_COMPACT );
}
}
Debug.out( "eh?" );
return( DiskManagerFileInfo.ST_LINEAR );
}
public static String
convertDMStorageTypeToString(
int dm_type )
{
switch( dm_type ){
case DiskManagerFileInfo.ST_LINEAR:{
return( "L" );
}
case DiskManagerFileInfo.ST_COMPACT:{
return( "C" );
}
case DiskManagerFileInfo.ST_REORDER:{
return( "R" );
}
case DiskManagerFileInfo.ST_REORDER_COMPACT:{
return( "X" );
}
}
Debug.out( "eh?" );
return( "?" );
}
public static String
convertCacheStorageTypeToString(
int cache_type )
{
switch( cache_type ){
case CacheFile.CT_LINEAR:{
return( "L" );
}
case CacheFile.CT_COMPACT:{
return( "C" );
}
case CacheFile.CT_PIECE_REORDER:{
return( "R" );
}
case CacheFile.CT_PIECE_REORDER_COMPACT:{
return( "X" );
}
}
Debug.out( "eh?" );
return( "?" );
}
public static int
convertDMStorageTypeToCache(
int dm_type )
{
switch( dm_type ){
case DiskManagerFileInfo.ST_LINEAR:{
return( CacheFile.CT_LINEAR );
}
case DiskManagerFileInfo.ST_COMPACT:{
return( CacheFile.CT_COMPACT );
}
case DiskManagerFileInfo.ST_REORDER:{
return( CacheFile.CT_PIECE_REORDER );
}
case DiskManagerFileInfo.ST_REORDER_COMPACT:{
return( CacheFile.CT_PIECE_REORDER_COMPACT );
}
}
Debug.out( "eh?" );
return( CacheFile.CT_LINEAR );
}
static void
loadFilePriorities(
DownloadManager download_manager,
DiskManagerFileInfoSet fileSet )
{
// TODO: remove this try/catch. should only be needed for those upgrading from previous snapshot
try {
DiskManagerFileInfo[] files = fileSet.getFiles();
if ( files == null ) return;
List file_priorities = (List)download_manager.getData( "file_priorities" );
if ( file_priorities == null ) return;
boolean[] toSkip = new boolean[files.length];
int[] prio = new int[files.length];
for (int i=0; i < files.length; i++) {
DiskManagerFileInfo file = files[i];
if (file == null) return;
int priority = ((Long)file_priorities.get( i )).intValue();
if ( priority == 0 ) toSkip[i] = true;
else if (priority >= 1) prio[i] = priority;
}
fileSet.setPriority(prio);
fileSet.setSkipped(toSkip, true);
}
catch (Throwable t) {Debug.printStackTrace( t );}
}
protected static void
loadFileDownloaded(
DownloadManager download_manager,
DiskManagerFileInfoHelper[] files )
{
DownloadManagerState state = download_manager.getDownloadState();
Map details = state.getMapAttribute( DownloadManagerState.AT_FILE_DOWNLOADED );
if ( details == null ){
return;
}
List downloaded = (List)details.get( "downloaded" );
if ( downloaded == null ){
return;
}
try{
for (int i=0;i<files.length;i++){
files[i].setDownloaded(((Long)downloaded.get(i)).longValue());
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}