From e3d8289ce007afa1904652b4f3ba91fc1bad0753 Mon Sep 17 00:00:00 2001 From: parg Date: Sun, 24 Sep 2023 19:35:36 +0100 Subject: [PATCH] Added strict file-op timeout for image repository is-dir --- .../core/torrent/impl/TOTorrentImpl.java | 21 +- core/src/com/biglybt/core/util/FileUtil.java | 286 +++++++++++------- .../com/biglybt/ui/swt/ImageRepository.java | 2 +- 3 files changed, 196 insertions(+), 113 deletions(-) diff --git a/core/src/com/biglybt/core/torrent/impl/TOTorrentImpl.java b/core/src/com/biglybt/core/torrent/impl/TOTorrentImpl.java index 25a54d07536..cafe6afee45 100644 --- a/core/src/com/biglybt/core/torrent/impl/TOTorrentImpl.java +++ b/core/src/com/biglybt/core/torrent/impl/TOTorrentImpl.java @@ -75,6 +75,11 @@ protected static final String TK_V2_PIECE_LAYERS = "piece layers"; protected static final String TK_V2_PIECES_ROOT = "pieces root"; + //public static final String TK_INFO_BIGLY_FLAGS = "bigly_flags"; + //public static final long TK_INFO_BIGLY_FLAGS_BIGLY_PRIVATE = 0x0001L; + + //private static final String TK_INFO_BIGLY_PRIVATE = "bigly_private"; + private static CopyOnWriteList global_listeners = new CopyOnWriteList<>(); public static void @@ -925,7 +930,7 @@ protected void setCreatedBy(String _created_by) { protected void setHashFromInfo( - Map info ) + Map info ) throws TOTorrentException { @@ -937,9 +942,19 @@ protected void setCreatedBy(String _created_by) { Debug.out( "Torrent type unknown" ); } - byte[] encoded = BEncoder.encode(info); - + /* + Long flags = (Long)additional_info_properties.get( TK_INFO_BIGLY_FLAGS ); + if ( flags != null && (( flags & TK_INFO_BIGLY_FLAGS_BIGLY_PRIVATE ) != 0 )){ + + info = new HashMap<>( info ); + + info.put( TK_INFO_BIGLY_PRIVATE, 1L ); + } + */ + + byte[] encoded = BEncoder.encode(info); + if ( torrent_type == TT_V1_V2 ){ Map private_props = getAdditionalMapProperty( AZUREUS_PRIVATE_PROPERTIES ); diff --git a/core/src/com/biglybt/core/util/FileUtil.java b/core/src/com/biglybt/core/util/FileUtil.java index 8d9b932310a..8ac5d8a2c4b 100644 --- a/core/src/com/biglybt/core/util/FileUtil.java +++ b/core/src/com/biglybt/core/util/FileUtil.java @@ -3619,10 +3619,11 @@ public static long getUsableSpace(File f) runFileOpWithTimeout( File file, FileOpWithTimeout fo, - T def ) + T def, + long strict_timeout ) { try{ - return( runFileOpWithTimeoutEx( file, fo, def, null )); + return( runFileOpWithTimeoutEx( file, fo, def, null, strict_timeout )); }catch( Throwable e ){ @@ -3639,7 +3640,7 @@ public static long getUsableSpace(File f) throws IOException { try{ - return( runFileOpWithTimeoutEx( file, fo, null, def_error )); + return( runFileOpWithTimeoutEx( file, fo, null, def_error, -1 )); }catch( IOException e ){ @@ -3651,12 +3652,15 @@ public static long getUsableSpace(File f) } } + private static AsyncDispatcher fot_dispatcher = new AsyncDispatcher( "FOT" ); + private static T runFileOpWithTimeoutEx( File file, FileOpWithTimeout fo, T def_result, - IOException def_error ) + IOException def_error, + long strict_timeout ) throws IOException { @@ -3680,141 +3684,197 @@ public static long getUsableSpace(File f) } } - long start = SystemTime.getMonotonousTime(); - - try{ - return( fo.run()); - - }finally{ - - long elapsed = SystemTime.getMonotonousTime() - start; - - if ( elapsed > 2500 ){ + FileOpWithTimeout delegate = ()->{ + + long start = SystemTime.getMonotonousTime(); + + try{ + return( fo.run()); - Path root_path = file.toPath().getRoot(); + }finally{ - synchronized( bad_roots ){ - - if ( !bad_roots.containsKey(root_path)){ + long elapsed = SystemTime.getMonotonousTime() - start; - if ( bad_roots.size() > 1024 ){ - - Debug.out( "Bad roots size limit exceeded for " + root_path ); - - }else{ - - bad_roots.put(root_path, new int[]{0}); - - if ( bad_roots.size() == 1 ){ + if ( elapsed > 2500 ){ + + Path root_path = file.toPath().getRoot(); + + synchronized( bad_roots ){ + + if ( !bad_roots.containsKey(root_path)){ + + if ( bad_roots.size() > 1024 ){ + + Debug.out( "Bad roots size limit exceeded for " + root_path ); + + }else{ - AEThread2.createAndStartDaemon( "BadRootChecker", ()->{ + bad_roots.put(root_path, new int[]{0}); + + if ( bad_roots.size() == 1 ){ - while( true ){ - try{ - Thread.sleep( 30*1000 ); - - }catch( Throwable e ){ - - } + AEThread2.createAndStartDaemon( "BadRootChecker", ()->{ - Map to_check; - - synchronized( bad_roots ){ + while( true ){ + try{ + Thread.sleep( 30*1000 ); + + }catch( Throwable e ){ + + } - to_check = new HashMap<>( bad_roots ); - } - - for ( Map.Entry entry: to_check.entrySet()){ + Map to_check; - try{ - long check_start = SystemTime.getMonotonousTime(); + synchronized( bad_roots ){ - int limit = 250; + to_check = new HashMap<>( bad_roots ); + } + + for ( Map.Entry entry: to_check.entrySet()){ - Path path = entry.getKey(); - int[] oks = entry.getValue(); - - File check_file = path.toFile(); -outer: - for ( int i=0;; i++){ + try{ + long check_start = SystemTime.getMonotonousTime(); - switch(i){ - case 0:{ - check_file.getCanonicalPath(); - break; - } - case 1:{ - check_file.exists(); - break; - } - case 2:{ - check_file.length(); - break; - } - case 3:{ - check_file.isDirectory(); - break; - } - case 4:{ - File random_file = new File( check_file, "Test" + RandomUtils.nextAbsoluteLong() + ".dat" ); - - if ( random_file.isFile()){ + int limit = 250; + + Path path = entry.getKey(); + int[] oks = entry.getValue(); - Thread.sleep(limit); + File check_file = path.toFile(); + outer: + for ( int i=0;; i++){ + + switch(i){ + case 0:{ + check_file.getCanonicalPath(); + break; + } + case 1:{ + check_file.exists(); + break; + } + case 2:{ + check_file.length(); + break; + } + case 3:{ + check_file.isDirectory(); + break; + } + case 4:{ + File random_file = new File( check_file, "Test" + RandomUtils.nextAbsoluteLong() + ".dat" ); + + if ( random_file.isFile()){ + + Thread.sleep(limit); + } + + break; + } + case 5:{ + check_file.listFiles(); + break; + } + default:{ + break outer; } - - break; } - case 5:{ - check_file.listFiles(); + + if ( SystemTime.getMonotonousTime() - check_start >= limit ){ + break; } - default:{ - break outer; - } - } + } - if ( SystemTime.getMonotonousTime() - check_start >= limit ){ + if ( SystemTime.getMonotonousTime() - check_start < limit ){ - break; - } - } - - if ( SystemTime.getMonotonousTime() - check_start < limit ){ - - oks[0]++; - - if ( oks[0] > 2 ){ - - Debug.out( "Root path " + path + " appears to be responding in a timely manner, enabling" ); + oks[0]++; - synchronized( bad_roots ){ + if ( oks[0] > 2 ){ - bad_roots.remove( path ); + Debug.out( "Root path " + path + " appears to be responding in a timely manner, enabling" ); - if ( bad_roots.isEmpty()){ + synchronized( bad_roots ){ - return; + bad_roots.remove( path ); + + if ( bad_roots.isEmpty()){ + + return; + } } } + }else{ + + oks[0] = 0; } - }else{ + }catch( Throwable e ){ - oks[0] = 0; } - }catch( Throwable e ){ - } } - } - }); + }); + } + + Debug.out( "Root path " + root_path + " isn't responding in a timely manner, disabling" ); } - - Debug.out( "Root path " + root_path + " isn't responding in a timely manner, disabling" ); } } } } + }; + + if ( strict_timeout == -1 ){ + + return( delegate.run()); + + }else{ + + AESemaphore sem = new AESemaphore( "FOT" ); + + Object[] result = { null }; + + fot_dispatcher.dispatch(()->{ + + try{ + + T r = delegate.run(); + + synchronized( result ){ + + result[0] = r; + } + }catch( IOException e ){ + + synchronized( result ){ + + result[0] = e; + } + + }finally{ + + sem.release(); + } + }); + + if ( sem.reserve( strict_timeout )){ + + synchronized( result ){ + + Object r = result[0]; + + if ( r instanceof IOException ){ + + throw((IOException)r); + }else{ + + return((T)r); + } + } + }else{ + + return( def_result ); + } } } @@ -3824,7 +3884,7 @@ public static long getUsableSpace(File f) { return(runFileOpWithTimeout(file,()->{ return( file.length()); - },0L)); + },0L, -1 )); } public static boolean @@ -3833,16 +3893,24 @@ public static long getUsableSpace(File f) { return(runFileOpWithTimeout(file,()->{ return( file.canRead()); - },false)); + },false, -1 )); } public static boolean isDirectoryWithTimeout( File file ) + { + return( isDirectoryWithTimeout( file, -1 )); + } + + public static boolean + isDirectoryWithTimeout( + File file, + long strict_timeout ) { return(runFileOpWithTimeout(file,()->{ return( file.isDirectory()); - },false)); + },false, strict_timeout )); } public static boolean @@ -3851,7 +3919,7 @@ public static long getUsableSpace(File f) { return(runFileOpWithTimeout(file,()->{ return( file.exists()); - },false)); + },false, -1 )); } public static String diff --git a/uis/src/com/biglybt/ui/swt/ImageRepository.java b/uis/src/com/biglybt/ui/swt/ImageRepository.java index bed03b1eff9..41f262378f4 100644 --- a/uis/src/com/biglybt/ui/swt/ImageRepository.java +++ b/uis/src/com/biglybt/ui/swt/ImageRepository.java @@ -290,7 +290,7 @@ public static Image getPathIcon(final String path, boolean bBig, // Mac OS X - Do not mix AWT with SWT (possible workaround: use IPC/Cocoa) String key; - if (FileUtil.isDirectoryWithTimeout( file )) { + if (FileUtil.isDirectoryWithTimeout( file, 250 )) { if (noAWT) { if (Constants.isWindows || Constants.isOSX) { return getIconFromExtension(file, "-folder", bBig, false);