PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/datadir/util_rt.php

https://gitlab.com/billyprice1/ruTorrent
PHP | 439 lines | 333 code | 38 blank | 68 comment | 102 complexity | 14d341a3b8814fabf3dd678ff79fcfdc MD5 | raw file
  1. <?php
  2. require_once( "../../php/xmlrpc.php" );
  3. require_once( "../../php/Torrent.php" );
  4. //------------------------------------------------------------------------------
  5. // Debug stub
  6. //------------------------------------------------------------------------------
  7. function rtDbg( $prefix, $str )
  8. {
  9. if( !$str )
  10. toLog( "" );
  11. elseif( $prefix && strlen( $prefix ) > 0 )
  12. toLog( $prefix.": ".$str );
  13. else
  14. toLog( $str );
  15. }
  16. //------------------------------------------------------------------------------
  17. // Check if script was launched in background (with --daemon switch)
  18. //------------------------------------------------------------------------------
  19. function rtIsDaemon( $args )
  20. {
  21. foreach( $args as $arg )
  22. if( $arg == '--daemon' )
  23. return true;
  24. return false;
  25. }
  26. //------------------------------------------------------------------------------
  27. // Making current process a daemon (run in background)
  28. //------------------------------------------------------------------------------
  29. function rtDaemon( $php, $script, $args )
  30. {
  31. if( !$php || $php == '' ) $php = 'php';
  32. $params = escapeshellarg( $script ).' --daemon';
  33. foreach( $args as $arg )
  34. $params .= ' '.escapeshellarg( $arg );
  35. exec( $php.' '.$params.' > /dev/null 2>/dev/null &', $out, $ret );
  36. exit( (int)$ret );
  37. }
  38. //------------------------------------------------------------------------------
  39. // Operations with semaphores
  40. //------------------------------------------------------------------------------
  41. function rtSemGet( $id )
  42. {
  43. //$available = in_array( "sysvsem", get_loaded_extensions() );
  44. $available = function_exists( "sem_get" );
  45. return $available ? sem_get( $id, 1 ) : false;
  46. }
  47. //------------------------------------------------------------------------------
  48. function rtSemLock( $sem_key )
  49. {
  50. if( $sem_key ) sem_acquire( $sem_key );
  51. }
  52. //------------------------------------------------------------------------------
  53. function rtSemUnlock( $sem_key )
  54. {
  55. if( $sem_key ) sem_release( $sem_key );
  56. }
  57. //------------------------------------------------------------------------------
  58. // Operations with slashes in paths
  59. //------------------------------------------------------------------------------
  60. function rtAddTailSlash( $str )
  61. {
  62. $len = strlen( $str );
  63. if( $len > 0 && $str[$len-1] == '/' )
  64. return $str;
  65. return $str.'/';
  66. }
  67. //------------------------------------------------------------------------------
  68. function rtRemoveTailSlash( $str )
  69. {
  70. $len = strlen( $str );
  71. if( $len == 0 || $str[$len-1] != '/' )
  72. return $str;
  73. return substr( $str, 0, -1 );
  74. }
  75. //------------------------------------------------------------------------------
  76. function rtRemoveHeadSlash( $str )
  77. {
  78. $len = strlen( $str );
  79. if( $len == 0 || $str[0] != '/' )
  80. return $str;
  81. return substr( $str, 1 );
  82. }
  83. //------------------------------------------------------------------------------
  84. // Remove last token from $str string, using $sep as separator
  85. //------------------------------------------------------------------------------
  86. function rtRemoveLastToken( $str, $sep )
  87. {
  88. $pos = strrpos( $str, $sep );
  89. if( $pos === false )
  90. return $str;
  91. return substr( $str, 0, $pos );
  92. }
  93. //------------------------------------------------------------------------------
  94. // Return a part of $real_dir path, relative to $base_dir
  95. //------------------------------------------------------------------------------
  96. function rtGetRelativePath( $base_dir, $real_dir )
  97. {
  98. $base_dir = rtAddTailSlash( $base_dir );
  99. $len = strlen( $base_dir );
  100. $str = substr( $real_dir, 0, $len );
  101. if( $str != $base_dir )
  102. return ''; // $real_dir is NOT SUBDIR of $base_dir
  103. $str = substr( $real_dir, $len );
  104. if( $str != '' )
  105. return $str; // $read_dir is SUBDIR of $base_dir
  106. return './'; // $real_dir is EQUAL to $base_dir
  107. }
  108. //------------------------------------------------------------------------------
  109. // Check if path is a file (without 2 Gb limit)
  110. //------------------------------------------------------------------------------
  111. function rtIsFile( $path )
  112. {
  113. // use Novik's implementation
  114. return LFS::is_file( $path );
  115. //if( is_file( $path ) )
  116. // return true;
  117. //$out = array();
  118. //$ret = "1";
  119. //exec( 'test -f '.escapeshellarg( $path ), $out, $ret );
  120. //return (int)$ret == 0;
  121. }
  122. //------------------------------------------------------------------------------
  123. // Check if $dir exists and try to create it if not
  124. //------------------------------------------------------------------------------
  125. function rtMkDir( $dir, $mode = 0777 )
  126. {
  127. if( !is_dir( $dir ) )
  128. {
  129. // recursive mkdir() only after PHP_5.0
  130. mkdir( $dir, $mode, true );
  131. //system( 'mkdir -p "'.$dst_dir.'"' );
  132. if( !is_dir( $dir ) )
  133. return false;
  134. }
  135. return true;
  136. }
  137. //------------------------------------------------------------------------------
  138. // Move $src file to $dst
  139. //------------------------------------------------------------------------------
  140. function rtMoveFile( $src, $dst, $dbg = false )
  141. {
  142. $ss = LFS::stat($src);
  143. if( !rename( $src, $dst ) )
  144. {
  145. if( $dbg ) rtDbg( __FUNCTION__, "from ".$src );
  146. if( $dbg ) rtDbg( __FUNCTION__, "to ".$dst );
  147. if( $dbg ) rtDbg( __FUNCTION__, "move fail, try to copy" );
  148. if( !copy( $src, $dst ) )
  149. {
  150. if( $dbg ) rtDbg( __FUNCTION__, "copy fail" );
  151. return false;
  152. }
  153. if( !unlink( $src ) )
  154. if( $dbg ) rtDbg( __FUNCTION__, "delete fail (".$src.")" );
  155. }
  156. // there are problems here, if run-user is not file owner
  157. if($ss!==false)
  158. touch( $dst, $ss['mtime'], $ss['atime'] );
  159. return true;
  160. }
  161. //------------------------------------------------------------------------------
  162. // Make operation an array of files from $src directory to $dst directory
  163. // ( files in array are relative to $src directory )
  164. //------------------------------------------------------------------------------
  165. function rtOpFiles( $files, $src, $dst, $op, $dbg = false )
  166. {
  167. // Check if source and destination directories are valid
  168. if( !is_array( $files ) || $src == '' || $dst == '' )
  169. {
  170. if( $dbg ) rtDbg( __FUNCTION__, "invalid params" );
  171. return false;
  172. }
  173. // Check if source directory exists
  174. if( !is_dir( $src ) )
  175. {
  176. if( $dbg ) rtDbg( __FUNCTION__, "src is not a directory" );
  177. if( $dbg ) rtDbg( __FUNCTION__, "( ".$src." )" );
  178. return false;
  179. }
  180. else $src = rtAddTailSlash( $src );
  181. // Check if destination directory exists or can be created
  182. if( !rtMkDir( dirname( $dst ), 0777 ) )
  183. {
  184. if( $dbg ) rtDbg( __FUNCTION__, "can't create ".dirname( $dst ) );
  185. return false;
  186. }
  187. else $dst = rtAddTailSlash( $dst );
  188. // Check if source and destination directories are the same
  189. if( realpath( $src ) == realpath( $dst ) )
  190. {
  191. if( $dbg ) rtDbg( __FUNCTION__, "source is equal to destination" );
  192. if( $dbg ) rtDbg( __FUNCTION__, "( ".realpath( $src )." )" );
  193. return false;
  194. }
  195. foreach( $files as $file )
  196. {
  197. $source = $src.$file;
  198. $dest = $dst.$file;
  199. if( !rtMkDir( dirname( $dest ), 0777 ) )
  200. {
  201. if( $dbg ) rtDbg( __FUNCTION__, "can't create ".dirname( $dest ) );
  202. return false;
  203. }
  204. if( rtIsFile( $dest ) )
  205. unlink( $dest );
  206. switch( $op )
  207. {
  208. case "HardLink":
  209. {
  210. if( link( $source, $dest ) )
  211. break;
  212. }
  213. case "Copy":
  214. {
  215. if( !copy( $source, $dest ) )
  216. return false;
  217. break;
  218. }
  219. case "SoftLink":
  220. {
  221. if( !symlink( $source, $dest ) )
  222. return false;
  223. break;
  224. }
  225. default:
  226. {
  227. if( !rtMoveFile( $source, $dest, $dbg ) )
  228. return false;
  229. break;
  230. }
  231. }
  232. }
  233. if( $dbg ) rtDbg( __FUNCTION__, "finished" );
  234. return true;
  235. }
  236. //------------------------------------------------------------------------------
  237. // Recursively scan files at $path directory
  238. //------------------------------------------------------------------------------
  239. function rtScanFiles( $path, $mask, $subdir = '' )
  240. {
  241. $path = rtAddTailSlash( $path );
  242. if( $subdir != '' )
  243. $subdir = rtAddTailSlash( $subdir );
  244. $ret = array();
  245. if( is_dir( $path.$subdir ) )
  246. {
  247. $handle = opendir( $path.$subdir );
  248. while( false !== ( $item = readdir( $handle ) ) )
  249. {
  250. if( $item == '.' || $item == '..' )
  251. continue;
  252. $path_to_item = $path.$subdir.$item;
  253. if( is_dir( $path_to_item ) )
  254. {
  255. $ret = array_merge( $ret,
  256. rtScanFiles( $path, $mask, $subdir.$item ) );
  257. }
  258. elseif( rtIsFile( $path_to_item ) &&
  259. preg_match( $mask, $item ) )
  260. {
  261. $ret[] = $subdir.$item;
  262. }
  263. }
  264. closedir( $handle );
  265. }
  266. return ( $ret );
  267. }
  268. //------------------------------------------------------------------------------
  269. // Recursively remove $path directory (optionally with or without files)
  270. //------------------------------------------------------------------------------
  271. function rtRemoveDirectory( $path, $with_files = false )
  272. {
  273. $path = rtRemoveTailSlash( $path );
  274. if( !file_exists( $path ) || !is_dir( $path ) )
  275. return false;
  276. $handle = opendir( $path );
  277. $empty = true;
  278. while( false !== ( $item = readdir( $handle ) ) )
  279. {
  280. if( $item == '.' || $item == '..' )
  281. continue;
  282. $path_to_item = $path.'/'.$item;
  283. if( is_dir( $path_to_item ) )
  284. {
  285. if( !rtRemoveDirectory( $path_to_item, $with_files ) )
  286. $empty = false;
  287. }
  288. else
  289. {
  290. if( !$with_files || !unlink( $path_to_item ) )
  291. $empty = false;
  292. }
  293. }
  294. closedir( $handle );
  295. return ( $empty && rmdir( $path ) );
  296. }
  297. //------------------------------------------------------------------------------
  298. // Exec $cmds set of commands for the $hash torrent
  299. //------------------------------------------------------------------------------
  300. function rtExec( $cmds, $hash, $dbg )
  301. {
  302. $req = new rXMLRPCRequest();
  303. if( !is_array( $cmds ) )
  304. {
  305. $req->addCommand( new rXMLRPCCommand( $cmds, $hash ) );
  306. if( $dbg ) rtDbg( __FUNCTION__, $cmds );
  307. }
  308. else {
  309. $s = '';
  310. foreach( $cmds as $cmd )
  311. {
  312. $s.= $cmd.", ";
  313. $req->addCommand( new rXMLRPCCommand( $cmd, $hash ) );
  314. }
  315. if( $dbg ) rtDbg( __FUNCTION__, substr( $s, 0, -2 ) );
  316. }
  317. if( !$req->run() )
  318. {
  319. if( $dbg ) rtDbg( __FUNCTION__, "rXMLRPCRequest() run fail" );
  320. return null;
  321. }
  322. elseif( $req->fault )
  323. {
  324. if( $dbg ) rtDbg( __FUNCTION__, "rXMLRPCRequest() fault" );
  325. return null;
  326. }
  327. else return $req;
  328. }
  329. //------------------------------------------------------------------------------
  330. // Make string param for XMLRPC call
  331. //------------------------------------------------------------------------------
  332. function rtMakeStrParam( $param )
  333. {
  334. return "<param><value><string>".$param."</string></value></param>";
  335. }
  336. //------------------------------------------------------------------------------
  337. // Add ".torrent" file to rTorrent
  338. //------------------------------------------------------------------------------
  339. function rtAddTorrent( $fname, $isStart, $directory, $label, $dbg = false )
  340. {
  341. if( $isStart )
  342. $method = 'load_start_verbose';
  343. else
  344. $method = 'load_verbose';
  345. if( $dbg ) rtDbg( __FUNCTION__, "1".$fname );
  346. $torrent = new Torrent($fname);
  347. if( $dbg ) rtDbg( __FUNCTION__, "2" );
  348. if( $torrent->errors() )
  349. {
  350. if( $dbg ) rtDbg( __FUNCTION__, "fail to create Torrent() object" );
  351. return false;
  352. }
  353. if( $directory && strlen( $directory ) > 0 )
  354. {
  355. $directory = rtMakeStrParam( "d.set_directory=\"".$directory."\"" );
  356. }
  357. else $directory = "";
  358. $comment = $torrent->comment();
  359. if( $comment && strlen( $comment ) > 0 )
  360. {
  361. if( isInvalidUTF8( $comment ) )
  362. $comment = win2utf($comment);
  363. if( strlen( $comment ) > 0 )
  364. {
  365. $comment = rtMakeStrParam( "d.set_custom2=VRS24mrker".rawurlencode( $comment ) );
  366. if(strlen($comment)>4096)
  367. $comment = '';
  368. }
  369. }
  370. else $comment = "";
  371. if( $label && strlen( $label ) > 0 )
  372. {
  373. $label = rtMakeStrParam( "d.set_custom1=\"".rawurlencode( $label )."\"" );
  374. }
  375. else $label = "";
  376. $addition = "";
  377. global $saveUploadedTorrents;
  378. $delete_tied = ($saveUploadedTorrents ? "" : rtMakeStrParam( "d.delete_tied=" ));
  379. $content =
  380. '<?xml version="1.0" encoding="UTF-8"?>'.
  381. '<methodCall>'.
  382. '<methodName>'.$method.'</methodName>'.
  383. '<params>'.
  384. '<param><value><string>'.$fname.'</string></value></param>'.
  385. $directory.
  386. $comment.
  387. $label.
  388. $addition.
  389. $delete_tied.
  390. '</params></methodCall>';
  391. //if( $dbg ) rtDbg( __FUNCTION__, $content );
  392. $res = rXMLRPCRequest::send( $content );
  393. if( $dbg && !empty($res) ) rtDbg( __FUNCTION__, $res );
  394. if( !$res || $res = '' )
  395. return false;
  396. else
  397. return $torrent->hash_info();
  398. }