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();