Blame view

sources/lib/private/files/storage/mappedlocal.php 9.3 KB
03e52840d   Kload   Init
1
2
3
4
5
6
7
8
9
10
11
12
  <?php
  /**
   * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
   * This file is licensed under the Affero General Public License version 3 or
   * later.
   * See the COPYING-README file.
   */
  namespace OC\Files\Storage;
  
  /**
   * for local filestore, we only have to map the paths
   */
6d9380f96   Cédric Dupont   Update sources OC...
13
  class MappedLocal extends \OC\Files\Storage\Common {
03e52840d   Kload   Init
14
15
16
17
  	protected $datadir;
  	private $mapper;
  
  	public function __construct($arguments) {
6d9380f96   Cédric Dupont   Update sources OC...
18
19
20
  		$this->datadir = $arguments['datadir'];
  		if (substr($this->datadir, -1) !== '/') {
  			$this->datadir .= '/';
03e52840d   Kload   Init
21
  		}
6d9380f96   Cédric Dupont   Update sources OC...
22
  		$this->mapper = new \OC\Files\Mapper($this->datadir);
03e52840d   Kload   Init
23
  	}
6d9380f96   Cédric Dupont   Update sources OC...
24

03e52840d   Kload   Init
25
26
27
28
29
  	public function __destruct() {
  		if (defined('PHPUNIT_RUN')) {
  			$this->mapper->removePath($this->datadir, true, true);
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
30
31
32
  
  	public function getId() {
  		return 'local::' . $this->datadir;
03e52840d   Kload   Init
33
  	}
6d9380f96   Cédric Dupont   Update sources OC...
34

03e52840d   Kload   Init
35
  	public function mkdir($path) {
6d9380f96   Cédric Dupont   Update sources OC...
36
  		return @mkdir($this->buildPath($path), 0777, true);
03e52840d   Kload   Init
37
  	}
6d9380f96   Cédric Dupont   Update sources OC...
38

03e52840d   Kload   Init
39
  	public function rmdir($path) {
31b7f2792   Kload   Upgrade to ownclo...
40
41
42
43
44
  		try {
  			$it = new \RecursiveIteratorIterator(
  				new \RecursiveDirectoryIterator($this->buildPath($path)),
  				\RecursiveIteratorIterator::CHILD_FIRST
  			);
6d9380f96   Cédric Dupont   Update sources OC...
45
46
47
48
49
50
51
  			/**
  			 * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
  			 * This bug is fixed in PHP 5.5.9 or before
  			 * See #8376
  			 */
  			$it->rewind();
  			while ($it->valid()) {
31b7f2792   Kload   Upgrade to ownclo...
52
53
54
  				/**
  				 * @var \SplFileInfo $file
  				 */
6d9380f96   Cédric Dupont   Update sources OC...
55
  				$file = $it->current();
31b7f2792   Kload   Upgrade to ownclo...
56
  				if (in_array($file->getBasename(), array('.', '..'))) {
6d9380f96   Cédric Dupont   Update sources OC...
57
  					$it->next();
31b7f2792   Kload   Upgrade to ownclo...
58
59
60
61
62
63
  					continue;
  				} elseif ($file->isDir()) {
  					rmdir($file->getPathname());
  				} elseif ($file->isFile() || $file->isLink()) {
  					unlink($file->getPathname());
  				}
6d9380f96   Cédric Dupont   Update sources OC...
64
  				$it->next();
31b7f2792   Kload   Upgrade to ownclo...
65
66
67
68
69
70
71
  			}
  			if ($result = @rmdir($this->buildPath($path))) {
  				$this->cleanMapper($path);
  			}
  			return $result;
  		} catch (\UnexpectedValueException $e) {
  			return false;
03e52840d   Kload   Init
72
  		}
03e52840d   Kload   Init
73
  	}
6d9380f96   Cédric Dupont   Update sources OC...
74

03e52840d   Kload   Init
75
76
  	public function opendir($path) {
  		$files = array('.', '..');
6d9380f96   Cédric Dupont   Update sources OC...
77
  		$physicalPath = $this->buildPath($path);
03e52840d   Kload   Init
78
79
80
81
82
83
84
85
  
  		$logicalPath = $this->mapper->physicalToLogic($physicalPath);
  		$dh = opendir($physicalPath);
  		if(is_resource($dh)) {
  			while (($file = readdir($dh)) !== false) {
  				if ($file === '.' or $file === '..') {
  					continue;
  				}
6d9380f96   Cédric Dupont   Update sources OC...
86
  				$logicalFilePath = $this->mapper->physicalToLogic($physicalPath . '/' . $file);
03e52840d   Kload   Init
87
88
89
90
91
92
  
  				$file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath);
  				$file = $this->stripLeading($file);
  				$files[]= $file;
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
93
94
  		\OC\Files\Stream\Dir::register('local-win32' . $path, $files);
  		return opendir('fakedir://local-win32' . $path);
03e52840d   Kload   Init
95
  	}
6d9380f96   Cédric Dupont   Update sources OC...
96

03e52840d   Kload   Init
97
  	public function is_dir($path) {
6d9380f96   Cédric Dupont   Update sources OC...
98
99
  		if (substr($path, -1) == '/') {
  			$path = substr($path, 0, -1);
03e52840d   Kload   Init
100
101
102
  		}
  		return is_dir($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
103

03e52840d   Kload   Init
104
105
106
  	public function is_file($path) {
  		return is_file($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
107

03e52840d   Kload   Init
108
109
110
  	public function stat($path) {
  		$fullPath = $this->buildPath($path);
  		$statResult = stat($fullPath);
6d9380f96   Cédric Dupont   Update sources OC...
111
112
113
114
  		if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
  			$filesize = $this->filesize($path);
  			$statResult['size'] = $filesize;
  			$statResult[7] = $filesize;
03e52840d   Kload   Init
115
116
117
  		}
  		return $statResult;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
118

03e52840d   Kload   Init
119
  	public function filetype($path) {
6d9380f96   Cédric Dupont   Update sources OC...
120
121
122
  		$filetype = filetype($this->buildPath($path));
  		if ($filetype == 'link') {
  			$filetype = filetype(realpath($this->buildPath($path)));
03e52840d   Kload   Init
123
124
125
  		}
  		return $filetype;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
126

03e52840d   Kload   Init
127
  	public function filesize($path) {
6d9380f96   Cédric Dupont   Update sources OC...
128
  		if ($this->is_dir($path)) {
03e52840d   Kload   Init
129
  			return 0;
03e52840d   Kload   Init
130
  		}
6d9380f96   Cédric Dupont   Update sources OC...
131
132
133
134
135
136
  		$fullPath = $this->buildPath($path);
  		if (PHP_INT_SIZE === 4) {
  			$helper = new \OC\LargeFileHelper;
  			return $helper->getFilesize($fullPath);
  		}
  		return filesize($fullPath);
03e52840d   Kload   Init
137
  	}
6d9380f96   Cédric Dupont   Update sources OC...
138

03e52840d   Kload   Init
139
140
141
  	public function isReadable($path) {
  		return is_readable($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
142

03e52840d   Kload   Init
143
144
145
  	public function isUpdatable($path) {
  		return is_writable($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
146

03e52840d   Kload   Init
147
148
149
  	public function file_exists($path) {
  		return file_exists($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
150

03e52840d   Kload   Init
151
152
153
  	public function filemtime($path) {
  		return filemtime($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
154
155
  
  	public function touch($path, $mtime = null) {
03e52840d   Kload   Init
156
157
158
  		// sets the modification time of the file to the given value.
  		// If mtime is nil the current time is set.
  		// note that the access time of the file always changes to the current time.
6d9380f96   Cédric Dupont   Update sources OC...
159
160
161
162
  		if (!is_null($mtime)) {
  			$result = touch($this->buildPath($path), $mtime);
  		} else {
  			$result = touch($this->buildPath($path));
03e52840d   Kload   Init
163
  		}
6d9380f96   Cédric Dupont   Update sources OC...
164
165
  		if ($result) {
  			clearstatcache(true, $this->buildPath($path));
03e52840d   Kload   Init
166
167
168
169
  		}
  
  		return $result;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
170

03e52840d   Kload   Init
171
172
173
  	public function file_get_contents($path) {
  		return file_get_contents($this->buildPath($path));
  	}
6d9380f96   Cédric Dupont   Update sources OC...
174

03e52840d   Kload   Init
175
176
177
  	public function file_put_contents($path, $data) {
  		return file_put_contents($this->buildPath($path), $data);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
178

03e52840d   Kload   Init
179
180
181
  	public function unlink($path) {
  		return $this->delTree($path);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
182

03e52840d   Kload   Init
183
184
  	public function rename($path1, $path2) {
  		if (!$this->isUpdatable($path1)) {
6d9380f96   Cédric Dupont   Update sources OC...
185
  			\OC_Log::write('core', 'unable to rename, file is not writable : ' . $path1, \OC_Log::ERROR);
03e52840d   Kload   Init
186
187
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
188
189
  		if (!$this->file_exists($path1)) {
  			\OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR);
03e52840d   Kload   Init
190
191
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
192
193
194
195
196
  		if ($this->is_dir($path2)) {
  			$this->rmdir($path2);
  		} else if ($this->is_file($path2)) {
  			$this->unlink($path2);
  		}
03e52840d   Kload   Init
197
198
  		$physicPath1 = $this->buildPath($path1);
  		$physicPath2 = $this->buildPath($path2);
6d9380f96   Cédric Dupont   Update sources OC...
199
  		if ($return = rename($physicPath1, $physicPath2)) {
03e52840d   Kload   Init
200
201
202
203
204
205
  			// mapper needs to create copies or all children
  			$this->copyMapping($path1, $path2);
  			$this->cleanMapper($physicPath1, false, true);
  		}
  		return $return;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
206

03e52840d   Kload   Init
207
  	public function copy($path1, $path2) {
6d9380f96   Cédric Dupont   Update sources OC...
208
209
210
211
212
  		if ($this->is_dir($path1)) {
  			if ($this->is_dir($path2)) {
  				$this->rmdir($path2);
  			} else if ($this->is_file($path2)) {
  				$this->unlink($path2);
03e52840d   Kload   Init
213
  			}
6d9380f96   Cédric Dupont   Update sources OC...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  			$dir = $this->opendir($path1);
  			$this->mkdir($path2);
  			while ($file = readdir($dir)) {
  				if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
  					if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
  						return false;
  					}
  				}
  			}
  			closedir($dir);
  			return true;
  		} else {
  			if ($return = copy($this->buildPath($path1), $this->buildPath($path2))) {
  				$this->copyMapping($path1, $path2);
  			}
  			return $return;
03e52840d   Kload   Init
230
  		}
03e52840d   Kload   Init
231
  	}
6d9380f96   Cédric Dupont   Update sources OC...
232

03e52840d   Kload   Init
233
  	public function fopen($path, $mode) {
6d9380f96   Cédric Dupont   Update sources OC...
234
235
  		if ($return = fopen($this->buildPath($path), $mode)) {
  			switch ($mode) {
03e52840d   Kload   Init
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  				case 'r':
  					break;
  				case 'r+':
  				case 'w+':
  				case 'x+':
  				case 'a+':
  					break;
  				case 'w':
  				case 'x':
  				case 'a':
  					break;
  			}
  		}
  		return $return;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
251
252
253
  	/**
  	 * @param string $dir
  	 */
03e52840d   Kload   Init
254
  	private function delTree($dir, $isLogicPath=true) {
6d9380f96   Cédric Dupont   Update sources OC...
255
  		$dirRelative = $dir;
03e52840d   Kload   Init
256
  		if ($isLogicPath) {
6d9380f96   Cédric Dupont   Update sources OC...
257
  			$dir = $this->buildPath($dir);
03e52840d   Kload   Init
258
259
260
261
262
  		}
  		if (!file_exists($dir)) {
  			return true;
  		}
  		if (!is_dir($dir) || is_link($dir)) {
6d9380f96   Cédric Dupont   Update sources OC...
263
  			if ($return = unlink($dir)) {
03e52840d   Kload   Init
264
265
266
267
268
269
270
271
  				$this->cleanMapper($dir, false);
  				return $return;
  			}
  		}
  		foreach (scandir($dir) as $item) {
  			if ($item == '.' || $item == '..') {
  				continue;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
272
273
274
  			if (is_file($dir . '/' . $item)) {
  				if (unlink($dir . '/' . $item)) {
  					$this->cleanMapper($dir . '/' . $item, false);
03e52840d   Kload   Init
275
  				}
6d9380f96   Cédric Dupont   Update sources OC...
276
277
  			} elseif (is_dir($dir . '/' . $item)) {
  				if (!$this->delTree($dir . "/" . $item, false)) {
03e52840d   Kload   Init
278
279
280
281
  					return false;
  				};
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
282
  		if ($return = rmdir($dir)) {
03e52840d   Kload   Init
283
284
285
286
  			$this->cleanMapper($dir, false);
  		}
  		return $return;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
287
  	public function hash($type, $path, $raw = false) {
03e52840d   Kload   Init
288
289
290
291
292
293
294
295
296
297
  		return hash_file($type, $this->buildPath($path), $raw);
  	}
  
  	public function free_space($path) {
  		return @disk_free_space($this->buildPath($path));
  	}
  
  	public function search($query) {
  		return $this->searchInDir($query);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
298

03e52840d   Kload   Init
299
300
301
  	public function getLocalFile($path) {
  		return $this->buildPath($path);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
302

03e52840d   Kload   Init
303
304
305
  	public function getLocalFolder($path) {
  		return $this->buildPath($path);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
306
307
308
309
310
  	/**
  	 * @param string $query
  	 */
  	protected function searchInDir($query, $dir = '') {
  		$files = array();
03e52840d   Kload   Init
311
312
313
314
  		$physicalDir = $this->buildPath($dir);
  		foreach (scandir($physicalDir) as $item) {
  			if ($item == '.' || $item == '..')
  				continue;
6d9380f96   Cédric Dupont   Update sources OC...
315
316
  			$physicalItem = $this->mapper->physicalToLogic($physicalDir . '/' . $item);
  			$item = substr($physicalItem, strlen($physicalDir) + 1);
03e52840d   Kload   Init
317

6d9380f96   Cédric Dupont   Update sources OC...
318
319
  			if (strstr(strtolower($item), strtolower($query)) !== false) {
  				$files[] = $dir . '/' . $item;
03e52840d   Kload   Init
320
  			}
6d9380f96   Cédric Dupont   Update sources OC...
321
322
  			if (is_dir($physicalItem)) {
  				$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
03e52840d   Kload   Init
323
324
325
326
327
328
329
  			}
  		}
  		return $files;
  	}
  
  	/**
  	 * check if a file or folder has been updated since $time
6d9380f96   Cédric Dupont   Update sources OC...
330
  	 *
03e52840d   Kload   Init
331
332
333
334
335
  	 * @param string $path
  	 * @param int $time
  	 * @return bool
  	 */
  	public function hasUpdated($path, $time) {
6d9380f96   Cédric Dupont   Update sources OC...
336
  		return $this->filemtime($path) > $time;
03e52840d   Kload   Init
337
  	}
6d9380f96   Cédric Dupont   Update sources OC...
338
339
340
341
  	/**
  	 * @param string $path
  	 */
  	private function buildPath($path, $create = true) {
03e52840d   Kload   Init
342
  		$path = $this->stripLeading($path);
6d9380f96   Cédric Dupont   Update sources OC...
343
  		$fullPath = $this->datadir . $path;
03e52840d   Kload   Init
344
345
  		return $this->mapper->logicToPhysical($fullPath, $create);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
346
347
348
349
  	/**
  	 * @param string $path
  	 */
  	private function cleanMapper($path, $isLogicPath = true, $recursive=true) {
03e52840d   Kload   Init
350
351
  		$fullPath = $path;
  		if ($isLogicPath) {
6d9380f96   Cédric Dupont   Update sources OC...
352
  			$fullPath = $this->datadir . $path;
03e52840d   Kload   Init
353
354
355
  		}
  		$this->mapper->removePath($fullPath, $isLogicPath, $recursive);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
356
357
358
359
  	/**
  	 * @param string $path1
  	 * @param string $path2
  	 */
03e52840d   Kload   Init
360
361
362
  	private function copyMapping($path1, $path2) {
  		$path1 = $this->stripLeading($path1);
  		$path2 = $this->stripLeading($path2);
6d9380f96   Cédric Dupont   Update sources OC...
363
364
  		$fullPath1 = $this->datadir . $path1;
  		$fullPath2 = $this->datadir . $path2;
03e52840d   Kload   Init
365
366
367
  
  		$this->mapper->copy($fullPath1, $fullPath2);
  	}
6d9380f96   Cédric Dupont   Update sources OC...
368
369
370
  	/**
  	 * @param string $path
  	 */
03e52840d   Kload   Init
371
  	private function stripLeading($path) {
6d9380f96   Cédric Dupont   Update sources OC...
372
  		if (strpos($path, '/') === 0) {
03e52840d   Kload   Init
373
374
  			$path = substr($path, 1);
  		}
6d9380f96   Cédric Dupont   Update sources OC...
375
  		if (strpos($path, '\\') === 0) {
03e52840d   Kload   Init
376
377
378
379
380
381
382
383
384
  			$path = substr($path, 1);
  		}
  		if ($path === false) {
  			return '';
  		}
  
  		return $path;
  	}
  }