1<?php 2 3namespace SabreForRainLoop\DAV\Locks\Backend; 4 5use SabreForRainLoop\DAV\Locks\LockInfo; 6 7/** 8 * This Lock Backend stores all its data in the filesystem in separate file per 9 * node. 10 * 11 * This Lock Manager is now deprecated. It has a bug that allows parent 12 * collections to be deletes when children deeper in the tree are locked. 13 * 14 * This also means that using this backend means you will not pass the Neon 15 * Litmus test. 16 * 17 * You are recommended to use either the PDO or the File backend instead. 18 * 19 * @deprecated 20 * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/). 21 * @author Evert Pot (http://evertpot.com/) 22 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License 23 */ 24class FS extends AbstractBackend { 25 26 /** 27 * The default data directory 28 * 29 * @var string 30 */ 31 private $dataDir; 32 33 public function __construct($dataDir) { 34 35 $this->dataDir = $dataDir; 36 37 } 38 39 protected function getFileNameForUri($uri) { 40 41 return $this->dataDir . '/sabredav_' . md5($uri) . '.locks'; 42 43 } 44 45 46 /** 47 * Returns a list of SabreForRainLoop\DAV\Locks\LockInfo objects 48 * 49 * This method should return all the locks for a particular uri, including 50 * locks that might be set on a parent uri. 51 * 52 * If returnChildLocks is set to true, this method should also look for 53 * any locks in the subtree of the uri for locks. 54 * 55 * @param string $uri 56 * @param bool $returnChildLocks 57 * @return array 58 */ 59 public function getLocks($uri, $returnChildLocks) { 60 61 $lockList = array(); 62 $currentPath = ''; 63 64 foreach(explode('/',$uri) as $uriPart) { 65 66 // weird algorithm that can probably be improved, but we're traversing the path top down 67 if ($currentPath) $currentPath.='/'; 68 $currentPath.=$uriPart; 69 70 $uriLocks = $this->getData($currentPath); 71 72 foreach($uriLocks as $uriLock) { 73 74 // Unless we're on the leaf of the uri-tree we should ignore locks with depth 0 75 if($uri==$currentPath || $uriLock->depth!=0) { 76 $uriLock->uri = $currentPath; 77 $lockList[] = $uriLock; 78 } 79 80 } 81 82 } 83 84 // Checking if we can remove any of these locks 85 foreach($lockList as $k=>$lock) { 86 if (time() > $lock->timeout + $lock->created) unset($lockList[$k]); 87 } 88 return $lockList; 89 90 } 91 92 /** 93 * Locks a uri 94 * 95 * @param string $uri 96 * @param LockInfo $lockInfo 97 * @return bool 98 */ 99 public function lock($uri, LockInfo $lockInfo) { 100 101 // We're making the lock timeout 30 minutes 102 $lockInfo->timeout = 1800; 103 $lockInfo->created = time(); 104 105 $locks = $this->getLocks($uri,false); 106 foreach($locks as $k=>$lock) { 107 if ($lock->token == $lockInfo->token) unset($locks[$k]); 108 } 109 $locks[] = $lockInfo; 110 $this->putData($uri,$locks); 111 return true; 112 113 } 114 115 /** 116 * Removes a lock from a uri 117 * 118 * @param string $uri 119 * @param LockInfo $lockInfo 120 * @return bool 121 */ 122 public function unlock($uri, LockInfo $lockInfo) { 123 124 $locks = $this->getLocks($uri,false); 125 foreach($locks as $k=>$lock) { 126 127 if ($lock->token == $lockInfo->token) { 128 129 unset($locks[$k]); 130 $this->putData($uri,$locks); 131 return true; 132 133 } 134 } 135 return false; 136 137 } 138 139 /** 140 * Returns the stored data for a uri 141 * 142 * @param string $uri 143 * @return array 144 */ 145 protected function getData($uri) { 146 147 $path = $this->getFilenameForUri($uri); 148 if (!file_exists($path)) return array(); 149 150 // opening up the file, and creating a shared lock 151 $handle = fopen($path,'r'); 152 flock($handle,LOCK_SH); 153 $data = ''; 154 155 // Reading data until the eof 156 while(!feof($handle)) { 157 $data.=fread($handle,8192); 158 } 159 160 // We're all good 161 fclose($handle); 162 163 // Unserializing and checking if the resource file contains data for this file 164 $data = unserialize($data); 165 if (!$data) return array(); 166 return $data; 167 168 } 169 170 /** 171 * Updates the lock information 172 * 173 * @param string $uri 174 * @param array $newData 175 * @return void 176 */ 177 protected function putData($uri,array $newData) { 178 179 $path = $this->getFileNameForUri($uri); 180 181 // opening up the file, and creating a shared lock 182 $handle = fopen($path,'a+'); 183 flock($handle,LOCK_EX); 184 ftruncate($handle,0); 185 rewind($handle); 186 187 fwrite($handle,serialize($newData)); 188 fclose($handle); 189 190 } 191 192} 193 194