You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

filecache.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. <?php
  2. /**
  3. * @author Robin Appelman
  4. * @copyright 2011 Robin Appelman icewind1991@gmail.com
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public
  17. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. /**
  21. * provide caching for filesystem info in the database
  22. *
  23. * not used by OC_Filesystem for reading filesystem info,
  24. * instread apps should use OC_FileCache::get where possible
  25. *
  26. * It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache
  27. */
  28. class OC_FileCache{
  29. private static $savedData=array();
  30. /**
  31. * get the filesystem info from the cache
  32. * @param string path
  33. * @param string root (optional)
  34. * @return array
  35. *
  36. * returns an assiciative array with the following keys:
  37. * - size
  38. * - mtime
  39. * - ctime
  40. * - mimetype
  41. * - encrypted
  42. * - versioned
  43. */
  44. public static function get($path,$root=''){
  45. if(self::isUpdated($path,$root)){
  46. if(!$root){//filesystem hooks are only valid for the default root
  47. OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path));
  48. }else{
  49. self::fileSystemWatcherWrite(array('path'=>$path),$root);
  50. }
  51. }
  52. if(!$root){
  53. $root=OC_Filesystem::getRoot();
  54. }
  55. if($root=='/'){
  56. $root='';
  57. }
  58. $path=$root.$path;
  59. $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?');
  60. $result=$query->execute(array(md5($path)))->fetchRow();
  61. if(is_array($result)){
  62. return $result;
  63. }else{
  64. OC_Log::write('files','get(): file not found in cache ('.$path.')',OC_Log::DEBUG);
  65. return false;
  66. }
  67. }
  68. /**
  69. * put filesystem info in the cache
  70. * @param string $path
  71. * @param array data
  72. * @param string root (optional)
  73. *
  74. * $data is an assiciative array in the same format as returned by get
  75. */
  76. public static function put($path,$data,$root=''){
  77. if(!$root){
  78. $root=OC_Filesystem::getRoot();
  79. }
  80. if($root=='/'){
  81. $root='';
  82. }
  83. $path=$root.$path;
  84. if($path=='/'){
  85. $parent=-1;
  86. }else{
  87. $parent=self::getFileId(dirname($path));
  88. }
  89. $id=self::getFileId($path);
  90. if($id!=-1){
  91. self::update($id,$data);
  92. return;
  93. }
  94. if(isset(self::$savedData[$path])){
  95. $data=array_merge($data,self::$savedData[$path]);
  96. unset(self::$savedData[$path]);
  97. }
  98. if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it
  99. self::$savedData[$path]=$data;
  100. return;
  101. }
  102. if(!isset($data['encrypted'])){
  103. $data['encrypted']=false;
  104. }
  105. if(!isset($data['versioned'])){
  106. $data['versioned']=false;
  107. }
  108. $mimePart=dirname($data['mimetype']);
  109. $data['size']=(int)$data['size'];
  110. $data['ctime']=(int)$data['mtime'];
  111. $data['writable']=(int)$data['writable'];
  112. $data['encrypted']=(int)$data['encrypted'];
  113. $data['versioned']=(int)$data['versioned'];
  114. $user=OC_User::getUser();
  115. $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, path_hash, size, mtime, ctime, mimetype, mimepart,`user`,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)');
  116. $result=$query->execute(array($parent,basename($path),$path,md5($path),$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned']));
  117. if(OC_DB::isError($result)){
  118. OC_Log::write('files','error while writing file('.$path.') to cache',OC_Log::ERROR);
  119. }
  120. }
  121. /**
  122. * update filesystem info of a file
  123. * @param int $id
  124. * @param array $data
  125. */
  126. private static function update($id,$data){
  127. $arguments=array();
  128. $queryParts=array();
  129. foreach(array('size','mtime','ctime','mimetype','encrypted','versioned','writable') as $attribute){
  130. if(isset($data[$attribute])){
  131. $arguments[]=$data[$attribute];
  132. $queryParts[]=$attribute.'=?';
  133. }
  134. }
  135. if(isset($data['mimetype'])){
  136. $arguments[]=dirname($data['mimetype']);
  137. $queryParts[]='mimepart=?';
  138. }
  139. $arguments[]=$id;
  140. $sql = 'UPDATE *PREFIX*fscache SET '.implode(' , ',$queryParts).' WHERE id=?';
  141. $query=OC_DB::prepare($sql);
  142. $result=$query->execute($arguments);
  143. if(OC_DB::isError($result)){
  144. OC_Log::write('files','error while updating file('.$path.') in cache',OC_Log::ERROR);
  145. }
  146. }
  147. /**
  148. * register a file move in the cache
  149. * @param string oldPath
  150. * @param string newPath
  151. * @param string root (optional)
  152. */
  153. public static function move($oldPath,$newPath,$root=''){
  154. if(!$root){
  155. $root=OC_Filesystem::getRoot();
  156. }
  157. if($root=='/'){
  158. $root='';
  159. }
  160. $oldPath=$root.$oldPath;
  161. $newPath=$root.$newPath;
  162. $newParent=self::getParentId($newPath);
  163. $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=?, path_hash=? WHERE path_hash=?');
  164. $query->execute(array($newParent,basename($newPath),$newPath,md5($newPath),md5($oldPath)));
  165. }
  166. /**
  167. * delete info from the cache
  168. * @param string/int $file
  169. * @param string root (optional)
  170. */
  171. public static function delete($file,$root=''){
  172. if(!is_numeric($file)){
  173. if(!$root){
  174. $root=OC_Filesystem::getRoot();
  175. }
  176. if($root=='/'){
  177. $root='';
  178. }
  179. $path=$root.$file;
  180. self::delete(self::getFileId($path));
  181. }elseif($file!=-1){
  182. $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE parent=?');
  183. $result=$query->execute(array($file));
  184. while($child=$result->fetchRow()){
  185. self::delete(intval($child['id']));
  186. }
  187. $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE id=?');
  188. $query->execute(array($file));
  189. }
  190. }
  191. /**
  192. * return array of filenames matching the querty
  193. * @param string $query
  194. * @param boolean $returnData
  195. * @param string root (optional)
  196. * @return array of filepaths
  197. */
  198. public static function search($search,$returnData=false,$root=''){
  199. if(!$root){
  200. $root=OC_Filesystem::getRoot();
  201. }
  202. if($root=='/'){
  203. $root='';
  204. }
  205. $rootLen=strlen($root);
  206. if(!$returnData){
  207. $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?');
  208. }else{
  209. $query=OC_DB::prepare('SELECT * FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?');
  210. }
  211. $result=$query->execute(array("%$search%",OC_User::getUser()));
  212. $names=array();
  213. while($row=$result->fetchRow()){
  214. if(!$returnData){
  215. $names[]=substr($row['path'],$rootLen);
  216. }else{
  217. $row['path']=substr($row['path'],$rootLen);
  218. $names[]=$row;
  219. }
  220. }
  221. return $names;
  222. }
  223. /**
  224. * get all files and folders in a folder
  225. * @param string path
  226. * @param string root (optional)
  227. * @return array
  228. *
  229. * returns an array of assiciative arrays with the following keys:
  230. * - name
  231. * - size
  232. * - mtime
  233. * - ctime
  234. * - mimetype
  235. * - encrypted
  236. * - versioned
  237. */
  238. public static function getFolderContent($path,$root='',$mimetype_filter=''){
  239. if(self::isUpdated($path,$root)){
  240. self::updateFolder($path,$root);
  241. }
  242. if(!$root){
  243. $root=OC_Filesystem::getRoot();
  244. }
  245. if($root=='/'){
  246. $root='';
  247. }
  248. $path=$root.$path;
  249. $parent=self::getFileId($path);
  250. $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)');
  251. $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll();
  252. if(is_array($result)){
  253. return $result;
  254. }else{
  255. OC_Log::write('files','getFolderContent(): file not found in cache ('.$path.')',OC_Log::DEBUG);
  256. return false;
  257. }
  258. }
  259. /**
  260. * check if a file or folder is in the cache
  261. * @param string $path
  262. * @param string root (optional)
  263. * @return bool
  264. */
  265. public static function inCache($path,$root=''){
  266. if(!$root){
  267. $root=OC_Filesystem::getRoot();
  268. }
  269. if($root=='/'){
  270. $root='';
  271. }
  272. $path=$root.$path;
  273. return self::getFileId($path)!=-1;
  274. }
  275. /**
  276. * get the file id as used in the cache
  277. * unlike the public getId, full paths are used here (/usename/files/foo instead of /foo)
  278. * @param string $path
  279. * @return int
  280. */
  281. private static function getFileId($path){
  282. $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?');
  283. if(OC_DB::isError($query)){
  284. OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
  285. return -1;
  286. }
  287. $result=$query->execute(array(md5($path)));
  288. if(OC_DB::isError($result)){
  289. OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
  290. return -1;
  291. }
  292. $result=$result->fetchRow();
  293. if(is_array($result)){
  294. return $result['id'];
  295. }else{
  296. OC_Log::write('files','getFileId(): file not found in cache ('.$path.')',OC_Log::DEBUG);
  297. return -1;
  298. }
  299. }
  300. /**
  301. * get the file id as used in the cache
  302. * @param string path
  303. * @param string root (optional)
  304. * @return int
  305. */
  306. public static function getId($path,$root=''){
  307. if(!$root){
  308. $root=OC_Filesystem::getRoot();
  309. }
  310. if($root=='/'){
  311. $root='';
  312. }
  313. $path=$root.$path;
  314. return self::getFileId($path);
  315. }
  316. /**
  317. * get the file path from the id, relative to the home folder of the user
  318. * @param int id
  319. * @param string user (optional)
  320. * @return string
  321. */
  322. public static function getPath($id,$user=''){
  323. if(!$user){
  324. $user=OC_User::getUser();
  325. }
  326. $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE id=? AND `user`=?');
  327. $result=$query->execute(array($id,$user));
  328. $row=$result->fetchRow();
  329. $path=$row['path'];
  330. $root='/'.$user.'/files';
  331. if(substr($path,0,strlen($root))!=$root){
  332. return false;
  333. }
  334. return substr($path,strlen($root));
  335. }
  336. /**
  337. * get the file id of the parent folder, taking into account '/' has no parent
  338. * @param string $path
  339. * @return int
  340. */
  341. private static function getParentId($path){
  342. if($path=='/'){
  343. return -1;
  344. }else{
  345. return self::getFileId(dirname($path));
  346. }
  347. }
  348. /**
  349. * called when changes are made to files
  350. * @param array $params
  351. * @param string root (optional)
  352. */
  353. public static function fileSystemWatcherWrite($params,$root=''){
  354. if(!$root){
  355. $view=OC_Filesystem::getView();
  356. }else{
  357. $view=new OC_FilesystemView(($root=='/')?'':$root);
  358. }
  359. $path=$params['path'];
  360. $fullPath=$view->getRoot().$path;
  361. $mimetype=$view->getMimeType($path);
  362. $dir=$view->is_dir($path.'/');
  363. //dont use self::get here, we don't want inifinte loops when a file has changed
  364. $cachedSize=self::getCachedSize($path,$root);
  365. $size=0;
  366. if($dir){
  367. if(self::inCache($path,$root)){
  368. $parent=self::getFileId($fullPath);
  369. $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?');
  370. $result=$query->execute(array($parent));
  371. while($row=$result->fetchRow()){
  372. $size+=$row['size'];
  373. }
  374. $mtime=$view->filemtime($path);
  375. $ctime=$view->filectime($path);
  376. $writable=$view->is_writable($path);
  377. self::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable));
  378. }else{
  379. $count=0;
  380. self::scan($path,null,$count,$root);
  381. }
  382. }else{
  383. $size=self::scanFile($path,$root);
  384. }
  385. self::increaseSize(dirname($fullPath),$size-$cachedSize);
  386. }
  387. public static function getCached($path,$root=''){
  388. if(!$root){
  389. $root=OC_Filesystem::getRoot();
  390. }else{
  391. if($root=='/'){
  392. $root='';
  393. }
  394. }
  395. $path=$root.$path;
  396. $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?');
  397. $result=$query->execute(array(md5($path)))->fetchRow();
  398. if(is_array($result)){
  399. if(isset(self::$savedData[$path])){
  400. $result=array_merge($result,self::$savedData[$path]);
  401. }
  402. return $result;
  403. }else{
  404. OC_Log::write('files','getChached(): file not found in cache ('.$path.')',OC_Log::DEBUG);
  405. if(isset(self::$savedData[$path])){
  406. return self::$savedData[$path];
  407. }else{
  408. return array();
  409. }
  410. }
  411. }
  412. private static function getCachedSize($path,$root){
  413. if(!$root){
  414. $root=OC_Filesystem::getRoot();
  415. }else{
  416. if($root=='/'){
  417. $root='';
  418. }
  419. }
  420. $path=$root.$path;
  421. $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path_hash=?');
  422. $result=$query->execute(array(md5($path)));
  423. if($row=$result->fetchRow()){
  424. return $row['size'];
  425. }else{//file not in cache
  426. return 0;
  427. }
  428. }
  429. /**
  430. * called when files are deleted
  431. * @param array $params
  432. * @param string root (optional)
  433. */
  434. public static function fileSystemWatcherDelete($params,$root=''){
  435. if(!$root){
  436. $root=OC_Filesystem::getRoot();
  437. }
  438. if($root=='/'){
  439. $root='';
  440. }
  441. $path=$params['path'];
  442. $fullPath=$root.$path;
  443. if(self::getFileId($fullPath)==-1){
  444. return;
  445. }
  446. $size=self::getCachedSize($path,$root);
  447. self::increaseSize(dirname($fullPath),-$size);
  448. self::delete($path);
  449. }
  450. /**
  451. * called when files are deleted
  452. * @param array $params
  453. * @param string root (optional)
  454. */
  455. public static function fileSystemWatcherRename($params,$root=''){
  456. if(!$root){
  457. $root=OC_Filesystem::getRoot();
  458. }
  459. if($root=='/'){
  460. $root='';
  461. }
  462. $oldPath=$params['oldpath'];
  463. $newPath=$params['newpath'];
  464. $fullOldPath=$root.$oldPath;
  465. $fullNewPath=$root.$newPath;
  466. if(($id=self::getFileId($fullOldPath))!=-1){
  467. $oldSize=self::getCachedSize($oldPath,$root);
  468. }else{
  469. return;
  470. }
  471. $size=OC_Filesystem::filesize($newPath);
  472. self::increaseSize(dirname($fullOldPath),-$oldSize);
  473. self::increaseSize(dirname($fullNewPath),$oldSize);
  474. self::move($oldPath,$newPath);
  475. }
  476. /**
  477. * adjust the size of the parent folders
  478. * @param string $path
  479. * @param int $sizeDiff
  480. */
  481. private static function increaseSize($path,$sizeDiff){
  482. if($sizeDiff==0) return;
  483. while(($id=self::getFileId($path))!=-1){//walk up the filetree increasing the size of all parent folders
  484. $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET size=size+? WHERE id=?');
  485. $query->execute(array($sizeDiff,$id));
  486. $path=dirname($path);
  487. }
  488. }
  489. /**
  490. * recursively scan the filesystem and fill the cache
  491. * @param string $path
  492. * @param OC_EventSource $enventSource (optional)
  493. * @param int count (optional)
  494. * @param string root (optionak)
  495. */
  496. public static function scan($path,$eventSource=false,&$count=0,$root=''){
  497. if($eventSource){
  498. $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
  499. }
  500. $lastSend=$count;
  501. if(!$root){
  502. $view=OC_Filesystem::getView();
  503. }else{
  504. $view=new OC_FilesystemView(($root=='/')?'':$root);
  505. }
  506. self::scanFile($path,$root);
  507. $dh=$view->opendir($path.'/');
  508. $totalSize=0;
  509. if($dh){
  510. while (($filename = readdir($dh)) !== false) {
  511. if($filename != '.' and $filename != '..'){
  512. $file=$path.'/'.$filename;
  513. if($view->is_dir($file.'/')){
  514. self::scan($file,$eventSource,$count,$root);
  515. }else{
  516. $totalSize+=self::scanFile($file,$root);
  517. $count++;
  518. if($count>$lastSend+25 and $eventSource){
  519. $lastSend=$count;
  520. $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
  521. }
  522. }
  523. }
  524. }
  525. }
  526. self::cleanFolder($path,$root);
  527. self::increaseSize($view->getRoot().$path,$totalSize);
  528. }
  529. /**
  530. * scan a single file
  531. * @param string path
  532. * @param string root (optional)
  533. * @return int size of the scanned file
  534. */
  535. public static function scanFile($path,$root=''){
  536. if(!$root){
  537. $view=OC_Filesystem::getView();
  538. }else{
  539. $view=new OC_FilesystemView(($root=='/')?'':$root);
  540. }
  541. if(!$view->is_readable($path)) return; //cant read, nothing we can do
  542. clearstatcache();
  543. $mimetype=$view->getMimeType($path);
  544. $stat=$view->stat($path);
  545. if($mimetype=='httpd/unix-directory'){
  546. $writable=$view->is_writable($path.'/');
  547. }else{
  548. $writable=$view->is_writable($path);
  549. }
  550. $stat['mimetype']=$mimetype;
  551. $stat['writable']=$writable;
  552. if($path=='/'){
  553. $path='';
  554. }
  555. self::put($path,$stat,$root);
  556. return $stat['size'];
  557. }
  558. /**
  559. * find files by mimetype
  560. * @param string $part1
  561. * @param string $part2 (optional)
  562. * @param string root (optional)
  563. * @return array of file paths
  564. *
  565. * $part1 and $part2 together form the complete mimetype.
  566. * e.g. searchByMime('text','plain')
  567. *
  568. * seccond mimetype part can be ommited
  569. * e.g. searchByMime('audio')
  570. */
  571. public static function searchByMime($part1,$part2=null,$root=null){
  572. if(!$root){
  573. $root=OC_Filesystem::getRoot();
  574. }elseif($root=='/'){
  575. $root='';
  576. }
  577. $rootLen=strlen($root);
  578. $root .= '%';
  579. $user=OC_User::getUser();
  580. if(!$part2){
  581. $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimepart=? AND `user`=? AND path LIKE ?');
  582. $result=$query->execute(array($part1,$user, $root));
  583. }else{
  584. $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimetype=? AND `user`=? AND path LIKE ? ');
  585. $result=$query->execute(array($part1.'/'.$part2,$user, $root));
  586. }
  587. $names=array();
  588. while($row=$result->fetchRow()){
  589. $names[]=substr($row['path'],$rootLen);
  590. }
  591. return $names;
  592. }
  593. /**
  594. * check if a file or folder is updated outside owncloud
  595. * @param string path
  596. * @param string root (optional)
  597. * @return bool
  598. */
  599. public static function isUpdated($path,$root=''){
  600. if(!$root){
  601. $root=OC_Filesystem::getRoot();
  602. $view=OC_Filesystem::getView();
  603. }else{
  604. if($root=='/'){
  605. $root='';
  606. }
  607. $view=new OC_FilesystemView($root);
  608. }
  609. if(!$view->file_exists($path)){
  610. return false;
  611. }
  612. $mtime=$view->filemtime($path);
  613. $isDir=$view->is_dir($path);
  614. $fullPath=$root.$path;
  615. $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?');
  616. $result=$query->execute(array(md5($fullPath)));
  617. if($row=$result->fetchRow()){
  618. $cachedMTime=$row['mtime'];
  619. return ($mtime>$cachedMTime);
  620. }else{//file not in cache, so it has to be updated
  621. if($path=='/' or $path==''){//dont auto update the root folder, it will be scanned
  622. return false;
  623. }
  624. return true;
  625. }
  626. }
  627. /**
  628. * update the cache according to changes in the folder
  629. * @param string path
  630. * @param string root (optional)
  631. */
  632. private static function updateFolder($path,$root=''){
  633. if(!$root){
  634. $view=OC_Filesystem::getView();
  635. }else{
  636. $view=new OC_FilesystemView(($root=='/')?'':$root);
  637. }
  638. $dh=$view->opendir($path.'/');
  639. if($dh){//check for changed/new files
  640. while (($filename = readdir($dh)) !== false) {
  641. if($filename != '.' and $filename != '..'){
  642. $file=$path.'/'.$filename;
  643. if(self::isUpdated($file,$root)){
  644. if(!$root){//filesystem hooks are only valid for the default root
  645. OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file));
  646. }else{
  647. self::fileSystemWatcherWrite(array('path'=>$file),$root);
  648. }
  649. }
  650. }
  651. }
  652. }
  653. self::cleanFolder($path,$root);
  654. //update the folder last, so we can calculate the size correctly
  655. if(!$root){//filesystem hooks are only valid for the default root
  656. OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path));
  657. }else{
  658. self::fileSystemWatcherWrite(array('path'=>$path),$root);
  659. }
  660. }
  661. /**
  662. * delete non existing files from the cache
  663. */
  664. private static function cleanFolder($path,$root=''){
  665. if(!$root){
  666. $view=OC_Filesystem::getView();
  667. }else{
  668. $view=new OC_FilesystemView(($root=='/')?'':$root);
  669. }
  670. //check for removed files, not using getFolderContent to prevent loops
  671. $parent=self::getFileId($view->getRoot().$path);
  672. $query=OC_DB::prepare('SELECT name FROM *PREFIX*fscache WHERE parent=?');
  673. $result=$query->execute(array($parent));
  674. while($row=$result->fetchRow()){
  675. $file=$path.'/'.$row['name'];
  676. if(!$view->file_exists($file)){
  677. if(!$root){//filesystem hooks are only valid for the default root
  678. OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file));
  679. }else{
  680. self::fileSystemWatcherDelete(array('path'=>$file),$root);
  681. }
  682. }
  683. }
  684. }
  685. /**
  686. * clean old pre-path_hash entries
  687. */
  688. public static function clean(){
  689. $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE LENGTH(path_hash)<30');
  690. $query->execute();
  691. }
  692. }
  693. //watch for changes and try to keep the cache up to date
  694. OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache','fileSystemWatcherWrite');
  695. OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache','fileSystemWatcherDelete');
  696. OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache','fileSystemWatcherRename');