Completed
Pull Request — master (#6992)
by Joas
12:20
created
lib/private/Files/Storage/Local.php 1 patch
Indentation   +409 added lines, -409 removed lines patch added patch discarded remove patch
@@ -43,413 +43,413 @@
 block discarded – undo
43 43
  * for local filestore, we only have to map the paths
44 44
  */
45 45
 class Local extends \OC\Files\Storage\Common {
46
-	protected $datadir;
47
-
48
-	protected $dataDirLength;
49
-
50
-	protected $allowSymlinks = false;
51
-
52
-	protected $realDataDir;
53
-
54
-	public function __construct($arguments) {
55
-		if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
56
-			throw new \InvalidArgumentException('No data directory set for local storage');
57
-		}
58
-		$this->datadir = $arguments['datadir'];
59
-		// some crazy code uses a local storage on root...
60
-		if ($this->datadir === '/') {
61
-			$this->realDataDir = $this->datadir;
62
-		} else {
63
-			$this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
64
-		}
65
-		if (substr($this->datadir, -1) !== '/') {
66
-			$this->datadir .= '/';
67
-		}
68
-		$this->dataDirLength = strlen($this->realDataDir);
69
-	}
70
-
71
-	public function __destruct() {
72
-	}
73
-
74
-	public function getId() {
75
-		return 'local::' . $this->datadir;
76
-	}
77
-
78
-	public function mkdir($path) {
79
-		return @mkdir($this->getSourcePath($path), 0777, true);
80
-	}
81
-
82
-	public function rmdir($path) {
83
-		if (!$this->isDeletable($path)) {
84
-			return false;
85
-		}
86
-		try {
87
-			$it = new \RecursiveIteratorIterator(
88
-				new \RecursiveDirectoryIterator($this->getSourcePath($path)),
89
-				\RecursiveIteratorIterator::CHILD_FIRST
90
-			);
91
-			/**
92
-			 * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
93
-			 * This bug is fixed in PHP 5.5.9 or before
94
-			 * See #8376
95
-			 */
96
-			$it->rewind();
97
-			while ($it->valid()) {
98
-				/**
99
-				 * @var \SplFileInfo $file
100
-				 */
101
-				$file = $it->current();
102
-				if (in_array($file->getBasename(), array('.', '..'))) {
103
-					$it->next();
104
-					continue;
105
-				} elseif ($file->isDir()) {
106
-					rmdir($file->getPathname());
107
-				} elseif ($file->isFile() || $file->isLink()) {
108
-					unlink($file->getPathname());
109
-				}
110
-				$it->next();
111
-			}
112
-			return rmdir($this->getSourcePath($path));
113
-		} catch (\UnexpectedValueException $e) {
114
-			return false;
115
-		}
116
-	}
117
-
118
-	public function opendir($path) {
119
-		return opendir($this->getSourcePath($path));
120
-	}
121
-
122
-	public function is_dir($path) {
123
-		if (substr($path, -1) == '/') {
124
-			$path = substr($path, 0, -1);
125
-		}
126
-		return is_dir($this->getSourcePath($path));
127
-	}
128
-
129
-	public function is_file($path) {
130
-		return is_file($this->getSourcePath($path));
131
-	}
132
-
133
-	public function stat($path) {
134
-		clearstatcache();
135
-		$fullPath = $this->getSourcePath($path);
136
-		$statResult = stat($fullPath);
137
-		if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
138
-			$filesize = $this->filesize($path);
139
-			$statResult['size'] = $filesize;
140
-			$statResult[7] = $filesize;
141
-		}
142
-		return $statResult;
143
-	}
144
-
145
-	public function filetype($path) {
146
-		$filetype = filetype($this->getSourcePath($path));
147
-		if ($filetype == 'link') {
148
-			$filetype = filetype(realpath($this->getSourcePath($path)));
149
-		}
150
-		return $filetype;
151
-	}
152
-
153
-	public function filesize($path) {
154
-		if ($this->is_dir($path)) {
155
-			return 0;
156
-		}
157
-		$fullPath = $this->getSourcePath($path);
158
-		if (PHP_INT_SIZE === 4) {
159
-			$helper = new \OC\LargeFileHelper;
160
-			return $helper->getFileSize($fullPath);
161
-		}
162
-		return filesize($fullPath);
163
-	}
164
-
165
-	public function isReadable($path) {
166
-		return is_readable($this->getSourcePath($path));
167
-	}
168
-
169
-	public function isUpdatable($path) {
170
-		return is_writable($this->getSourcePath($path));
171
-	}
172
-
173
-	public function file_exists($path) {
174
-		return file_exists($this->getSourcePath($path));
175
-	}
176
-
177
-	public function filemtime($path) {
178
-		$fullPath = $this->getSourcePath($path);
179
-		clearstatcache($fullPath);
180
-		if (!$this->file_exists($path)) {
181
-			return false;
182
-		}
183
-		if (PHP_INT_SIZE === 4) {
184
-			$helper = new \OC\LargeFileHelper();
185
-			return $helper->getFileMtime($fullPath);
186
-		}
187
-		return filemtime($fullPath);
188
-	}
189
-
190
-	public function touch($path, $mtime = null) {
191
-		// sets the modification time of the file to the given value.
192
-		// If mtime is nil the current time is set.
193
-		// note that the access time of the file always changes to the current time.
194
-		if ($this->file_exists($path) and !$this->isUpdatable($path)) {
195
-			return false;
196
-		}
197
-		if (!is_null($mtime)) {
198
-			$result = touch($this->getSourcePath($path), $mtime);
199
-		} else {
200
-			$result = touch($this->getSourcePath($path));
201
-		}
202
-		if ($result) {
203
-			clearstatcache(true, $this->getSourcePath($path));
204
-		}
205
-
206
-		return $result;
207
-	}
208
-
209
-	public function file_get_contents($path) {
210
-		return file_get_contents($this->getSourcePath($path));
211
-	}
212
-
213
-	public function file_put_contents($path, $data) {
214
-		return file_put_contents($this->getSourcePath($path), $data);
215
-	}
216
-
217
-	public function unlink($path) {
218
-		if ($this->is_dir($path)) {
219
-			return $this->rmdir($path);
220
-		} else if ($this->is_file($path)) {
221
-			return unlink($this->getSourcePath($path));
222
-		} else {
223
-			return false;
224
-		}
225
-
226
-	}
227
-
228
-	public function rename($path1, $path2) {
229
-		$srcParent = dirname($path1);
230
-		$dstParent = dirname($path2);
231
-
232
-		if (!$this->isUpdatable($srcParent)) {
233
-			\OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR);
234
-			return false;
235
-		}
236
-
237
-		if (!$this->isUpdatable($dstParent)) {
238
-			\OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR);
239
-			return false;
240
-		}
241
-
242
-		if (!$this->file_exists($path1)) {
243
-			\OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR);
244
-			return false;
245
-		}
246
-
247
-		if ($this->is_dir($path2)) {
248
-			$this->rmdir($path2);
249
-		} else if ($this->is_file($path2)) {
250
-			$this->unlink($path2);
251
-		}
252
-
253
-		if ($this->is_dir($path1)) {
254
-			// we can't move folders across devices, use copy instead
255
-			$stat1 = stat(dirname($this->getSourcePath($path1)));
256
-			$stat2 = stat(dirname($this->getSourcePath($path2)));
257
-			if ($stat1['dev'] !== $stat2['dev']) {
258
-				$result = $this->copy($path1, $path2);
259
-				if ($result) {
260
-					$result &= $this->rmdir($path1);
261
-				}
262
-				return $result;
263
-			}
264
-		}
265
-
266
-		return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
267
-	}
268
-
269
-	public function copy($path1, $path2) {
270
-		if ($this->is_dir($path1)) {
271
-			return parent::copy($path1, $path2);
272
-		} else {
273
-			return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
274
-		}
275
-	}
276
-
277
-	public function fopen($path, $mode) {
278
-		return fopen($this->getSourcePath($path), $mode);
279
-	}
280
-
281
-	public function hash($type, $path, $raw = false) {
282
-		return hash_file($type, $this->getSourcePath($path), $raw);
283
-	}
284
-
285
-	public function free_space($path) {
286
-		$sourcePath = $this->getSourcePath($path);
287
-		// using !is_dir because $sourcePath might be a part file or
288
-		// non-existing file, so we'd still want to use the parent dir
289
-		// in such cases
290
-		if (!is_dir($sourcePath)) {
291
-			// disk_free_space doesn't work on files
292
-			$sourcePath = dirname($sourcePath);
293
-		}
294
-		$space = @disk_free_space($sourcePath);
295
-		if ($space === false || is_null($space)) {
296
-			return \OCP\Files\FileInfo::SPACE_UNKNOWN;
297
-		}
298
-		return $space;
299
-	}
300
-
301
-	public function search($query) {
302
-		return $this->searchInDir($query);
303
-	}
304
-
305
-	public function getLocalFile($path) {
306
-		return $this->getSourcePath($path);
307
-	}
308
-
309
-	public function getLocalFolder($path) {
310
-		return $this->getSourcePath($path);
311
-	}
312
-
313
-	/**
314
-	 * @param string $query
315
-	 * @param string $dir
316
-	 * @return array
317
-	 */
318
-	protected function searchInDir($query, $dir = '') {
319
-		$files = array();
320
-		$physicalDir = $this->getSourcePath($dir);
321
-		foreach (scandir($physicalDir) as $item) {
322
-			if (\OC\Files\Filesystem::isIgnoredDir($item))
323
-				continue;
324
-			$physicalItem = $physicalDir . '/' . $item;
325
-
326
-			if (strstr(strtolower($item), strtolower($query)) !== false) {
327
-				$files[] = $dir . '/' . $item;
328
-			}
329
-			if (is_dir($physicalItem)) {
330
-				$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
331
-			}
332
-		}
333
-		return $files;
334
-	}
335
-
336
-	/**
337
-	 * check if a file or folder has been updated since $time
338
-	 *
339
-	 * @param string $path
340
-	 * @param int $time
341
-	 * @return bool
342
-	 */
343
-	public function hasUpdated($path, $time) {
344
-		if ($this->file_exists($path)) {
345
-			return $this->filemtime($path) > $time;
346
-		} else {
347
-			return true;
348
-		}
349
-	}
350
-
351
-	/**
352
-	 * Get the source path (on disk) of a given path
353
-	 *
354
-	 * @param string $path
355
-	 * @return string
356
-	 * @throws ForbiddenException
357
-	 */
358
-	public function getSourcePath($path) {
359
-		$fullPath = $this->datadir . $path;
360
-		if ($this->allowSymlinks || $path === '') {
361
-			return $fullPath;
362
-		}
363
-		$pathToResolve = $fullPath;
364
-		$realPath = realpath($pathToResolve);
365
-		while ($realPath === false) { // for non existing files check the parent directory
366
-			$pathToResolve = dirname($pathToResolve);
367
-			$realPath = realpath($pathToResolve);
368
-		}
369
-		if ($realPath) {
370
-			$realPath = $realPath . '/';
371
-		}
372
-		if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
373
-			return $fullPath;
374
-		}
375
-
376
-		\OCP\Util::writeLog('core', "Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", \OCP\Util::ERROR);
377
-		throw new ForbiddenException('Following symlinks is not allowed', false);
378
-	}
379
-
380
-	/**
381
-	 * {@inheritdoc}
382
-	 */
383
-	public function isLocal() {
384
-		return true;
385
-	}
386
-
387
-	/**
388
-	 * get the ETag for a file or folder
389
-	 *
390
-	 * @param string $path
391
-	 * @return string
392
-	 */
393
-	public function getETag($path) {
394
-		if ($this->is_file($path)) {
395
-			$stat = $this->stat($path);
396
-			return md5(
397
-				$stat['mtime'] .
398
-				$stat['ino'] .
399
-				$stat['dev'] .
400
-				$stat['size']
401
-			);
402
-		} else {
403
-			return parent::getETag($path);
404
-		}
405
-	}
406
-
407
-	/**
408
-	 * @param IStorage $sourceStorage
409
-	 * @param string $sourceInternalPath
410
-	 * @param string $targetInternalPath
411
-	 * @param bool $preserveMtime
412
-	 * @return bool
413
-	 */
414
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
415
-		if ($sourceStorage->instanceOfStorage(Local::class)) {
416
-			if ($sourceStorage->instanceOfStorage(Jail::class)) {
417
-				/**
418
-				 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
419
-				 */
420
-				$sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
421
-			}
422
-			/**
423
-			 * @var \OC\Files\Storage\Local $sourceStorage
424
-			 */
425
-			$rootStorage = new Local(['datadir' => '/']);
426
-			return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
427
-		} else {
428
-			return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
429
-		}
430
-	}
431
-
432
-	/**
433
-	 * @param IStorage $sourceStorage
434
-	 * @param string $sourceInternalPath
435
-	 * @param string $targetInternalPath
436
-	 * @return bool
437
-	 */
438
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
439
-		if ($sourceStorage->instanceOfStorage(Local::class)) {
440
-			if ($sourceStorage->instanceOfStorage(Jail::class)) {
441
-				/**
442
-				 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
443
-				 */
444
-				$sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
445
-			}
446
-			/**
447
-			 * @var \OC\Files\Storage\Local $sourceStorage
448
-			 */
449
-			$rootStorage = new Local(['datadir' => '/']);
450
-			return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
451
-		} else {
452
-			return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
453
-		}
454
-	}
46
+    protected $datadir;
47
+
48
+    protected $dataDirLength;
49
+
50
+    protected $allowSymlinks = false;
51
+
52
+    protected $realDataDir;
53
+
54
+    public function __construct($arguments) {
55
+        if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
56
+            throw new \InvalidArgumentException('No data directory set for local storage');
57
+        }
58
+        $this->datadir = $arguments['datadir'];
59
+        // some crazy code uses a local storage on root...
60
+        if ($this->datadir === '/') {
61
+            $this->realDataDir = $this->datadir;
62
+        } else {
63
+            $this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
64
+        }
65
+        if (substr($this->datadir, -1) !== '/') {
66
+            $this->datadir .= '/';
67
+        }
68
+        $this->dataDirLength = strlen($this->realDataDir);
69
+    }
70
+
71
+    public function __destruct() {
72
+    }
73
+
74
+    public function getId() {
75
+        return 'local::' . $this->datadir;
76
+    }
77
+
78
+    public function mkdir($path) {
79
+        return @mkdir($this->getSourcePath($path), 0777, true);
80
+    }
81
+
82
+    public function rmdir($path) {
83
+        if (!$this->isDeletable($path)) {
84
+            return false;
85
+        }
86
+        try {
87
+            $it = new \RecursiveIteratorIterator(
88
+                new \RecursiveDirectoryIterator($this->getSourcePath($path)),
89
+                \RecursiveIteratorIterator::CHILD_FIRST
90
+            );
91
+            /**
92
+             * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
93
+             * This bug is fixed in PHP 5.5.9 or before
94
+             * See #8376
95
+             */
96
+            $it->rewind();
97
+            while ($it->valid()) {
98
+                /**
99
+                 * @var \SplFileInfo $file
100
+                 */
101
+                $file = $it->current();
102
+                if (in_array($file->getBasename(), array('.', '..'))) {
103
+                    $it->next();
104
+                    continue;
105
+                } elseif ($file->isDir()) {
106
+                    rmdir($file->getPathname());
107
+                } elseif ($file->isFile() || $file->isLink()) {
108
+                    unlink($file->getPathname());
109
+                }
110
+                $it->next();
111
+            }
112
+            return rmdir($this->getSourcePath($path));
113
+        } catch (\UnexpectedValueException $e) {
114
+            return false;
115
+        }
116
+    }
117
+
118
+    public function opendir($path) {
119
+        return opendir($this->getSourcePath($path));
120
+    }
121
+
122
+    public function is_dir($path) {
123
+        if (substr($path, -1) == '/') {
124
+            $path = substr($path, 0, -1);
125
+        }
126
+        return is_dir($this->getSourcePath($path));
127
+    }
128
+
129
+    public function is_file($path) {
130
+        return is_file($this->getSourcePath($path));
131
+    }
132
+
133
+    public function stat($path) {
134
+        clearstatcache();
135
+        $fullPath = $this->getSourcePath($path);
136
+        $statResult = stat($fullPath);
137
+        if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
138
+            $filesize = $this->filesize($path);
139
+            $statResult['size'] = $filesize;
140
+            $statResult[7] = $filesize;
141
+        }
142
+        return $statResult;
143
+    }
144
+
145
+    public function filetype($path) {
146
+        $filetype = filetype($this->getSourcePath($path));
147
+        if ($filetype == 'link') {
148
+            $filetype = filetype(realpath($this->getSourcePath($path)));
149
+        }
150
+        return $filetype;
151
+    }
152
+
153
+    public function filesize($path) {
154
+        if ($this->is_dir($path)) {
155
+            return 0;
156
+        }
157
+        $fullPath = $this->getSourcePath($path);
158
+        if (PHP_INT_SIZE === 4) {
159
+            $helper = new \OC\LargeFileHelper;
160
+            return $helper->getFileSize($fullPath);
161
+        }
162
+        return filesize($fullPath);
163
+    }
164
+
165
+    public function isReadable($path) {
166
+        return is_readable($this->getSourcePath($path));
167
+    }
168
+
169
+    public function isUpdatable($path) {
170
+        return is_writable($this->getSourcePath($path));
171
+    }
172
+
173
+    public function file_exists($path) {
174
+        return file_exists($this->getSourcePath($path));
175
+    }
176
+
177
+    public function filemtime($path) {
178
+        $fullPath = $this->getSourcePath($path);
179
+        clearstatcache($fullPath);
180
+        if (!$this->file_exists($path)) {
181
+            return false;
182
+        }
183
+        if (PHP_INT_SIZE === 4) {
184
+            $helper = new \OC\LargeFileHelper();
185
+            return $helper->getFileMtime($fullPath);
186
+        }
187
+        return filemtime($fullPath);
188
+    }
189
+
190
+    public function touch($path, $mtime = null) {
191
+        // sets the modification time of the file to the given value.
192
+        // If mtime is nil the current time is set.
193
+        // note that the access time of the file always changes to the current time.
194
+        if ($this->file_exists($path) and !$this->isUpdatable($path)) {
195
+            return false;
196
+        }
197
+        if (!is_null($mtime)) {
198
+            $result = touch($this->getSourcePath($path), $mtime);
199
+        } else {
200
+            $result = touch($this->getSourcePath($path));
201
+        }
202
+        if ($result) {
203
+            clearstatcache(true, $this->getSourcePath($path));
204
+        }
205
+
206
+        return $result;
207
+    }
208
+
209
+    public function file_get_contents($path) {
210
+        return file_get_contents($this->getSourcePath($path));
211
+    }
212
+
213
+    public function file_put_contents($path, $data) {
214
+        return file_put_contents($this->getSourcePath($path), $data);
215
+    }
216
+
217
+    public function unlink($path) {
218
+        if ($this->is_dir($path)) {
219
+            return $this->rmdir($path);
220
+        } else if ($this->is_file($path)) {
221
+            return unlink($this->getSourcePath($path));
222
+        } else {
223
+            return false;
224
+        }
225
+
226
+    }
227
+
228
+    public function rename($path1, $path2) {
229
+        $srcParent = dirname($path1);
230
+        $dstParent = dirname($path2);
231
+
232
+        if (!$this->isUpdatable($srcParent)) {
233
+            \OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR);
234
+            return false;
235
+        }
236
+
237
+        if (!$this->isUpdatable($dstParent)) {
238
+            \OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR);
239
+            return false;
240
+        }
241
+
242
+        if (!$this->file_exists($path1)) {
243
+            \OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR);
244
+            return false;
245
+        }
246
+
247
+        if ($this->is_dir($path2)) {
248
+            $this->rmdir($path2);
249
+        } else if ($this->is_file($path2)) {
250
+            $this->unlink($path2);
251
+        }
252
+
253
+        if ($this->is_dir($path1)) {
254
+            // we can't move folders across devices, use copy instead
255
+            $stat1 = stat(dirname($this->getSourcePath($path1)));
256
+            $stat2 = stat(dirname($this->getSourcePath($path2)));
257
+            if ($stat1['dev'] !== $stat2['dev']) {
258
+                $result = $this->copy($path1, $path2);
259
+                if ($result) {
260
+                    $result &= $this->rmdir($path1);
261
+                }
262
+                return $result;
263
+            }
264
+        }
265
+
266
+        return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
267
+    }
268
+
269
+    public function copy($path1, $path2) {
270
+        if ($this->is_dir($path1)) {
271
+            return parent::copy($path1, $path2);
272
+        } else {
273
+            return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
274
+        }
275
+    }
276
+
277
+    public function fopen($path, $mode) {
278
+        return fopen($this->getSourcePath($path), $mode);
279
+    }
280
+
281
+    public function hash($type, $path, $raw = false) {
282
+        return hash_file($type, $this->getSourcePath($path), $raw);
283
+    }
284
+
285
+    public function free_space($path) {
286
+        $sourcePath = $this->getSourcePath($path);
287
+        // using !is_dir because $sourcePath might be a part file or
288
+        // non-existing file, so we'd still want to use the parent dir
289
+        // in such cases
290
+        if (!is_dir($sourcePath)) {
291
+            // disk_free_space doesn't work on files
292
+            $sourcePath = dirname($sourcePath);
293
+        }
294
+        $space = @disk_free_space($sourcePath);
295
+        if ($space === false || is_null($space)) {
296
+            return \OCP\Files\FileInfo::SPACE_UNKNOWN;
297
+        }
298
+        return $space;
299
+    }
300
+
301
+    public function search($query) {
302
+        return $this->searchInDir($query);
303
+    }
304
+
305
+    public function getLocalFile($path) {
306
+        return $this->getSourcePath($path);
307
+    }
308
+
309
+    public function getLocalFolder($path) {
310
+        return $this->getSourcePath($path);
311
+    }
312
+
313
+    /**
314
+     * @param string $query
315
+     * @param string $dir
316
+     * @return array
317
+     */
318
+    protected function searchInDir($query, $dir = '') {
319
+        $files = array();
320
+        $physicalDir = $this->getSourcePath($dir);
321
+        foreach (scandir($physicalDir) as $item) {
322
+            if (\OC\Files\Filesystem::isIgnoredDir($item))
323
+                continue;
324
+            $physicalItem = $physicalDir . '/' . $item;
325
+
326
+            if (strstr(strtolower($item), strtolower($query)) !== false) {
327
+                $files[] = $dir . '/' . $item;
328
+            }
329
+            if (is_dir($physicalItem)) {
330
+                $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
331
+            }
332
+        }
333
+        return $files;
334
+    }
335
+
336
+    /**
337
+     * check if a file or folder has been updated since $time
338
+     *
339
+     * @param string $path
340
+     * @param int $time
341
+     * @return bool
342
+     */
343
+    public function hasUpdated($path, $time) {
344
+        if ($this->file_exists($path)) {
345
+            return $this->filemtime($path) > $time;
346
+        } else {
347
+            return true;
348
+        }
349
+    }
350
+
351
+    /**
352
+     * Get the source path (on disk) of a given path
353
+     *
354
+     * @param string $path
355
+     * @return string
356
+     * @throws ForbiddenException
357
+     */
358
+    public function getSourcePath($path) {
359
+        $fullPath = $this->datadir . $path;
360
+        if ($this->allowSymlinks || $path === '') {
361
+            return $fullPath;
362
+        }
363
+        $pathToResolve = $fullPath;
364
+        $realPath = realpath($pathToResolve);
365
+        while ($realPath === false) { // for non existing files check the parent directory
366
+            $pathToResolve = dirname($pathToResolve);
367
+            $realPath = realpath($pathToResolve);
368
+        }
369
+        if ($realPath) {
370
+            $realPath = $realPath . '/';
371
+        }
372
+        if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
373
+            return $fullPath;
374
+        }
375
+
376
+        \OCP\Util::writeLog('core', "Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", \OCP\Util::ERROR);
377
+        throw new ForbiddenException('Following symlinks is not allowed', false);
378
+    }
379
+
380
+    /**
381
+     * {@inheritdoc}
382
+     */
383
+    public function isLocal() {
384
+        return true;
385
+    }
386
+
387
+    /**
388
+     * get the ETag for a file or folder
389
+     *
390
+     * @param string $path
391
+     * @return string
392
+     */
393
+    public function getETag($path) {
394
+        if ($this->is_file($path)) {
395
+            $stat = $this->stat($path);
396
+            return md5(
397
+                $stat['mtime'] .
398
+                $stat['ino'] .
399
+                $stat['dev'] .
400
+                $stat['size']
401
+            );
402
+        } else {
403
+            return parent::getETag($path);
404
+        }
405
+    }
406
+
407
+    /**
408
+     * @param IStorage $sourceStorage
409
+     * @param string $sourceInternalPath
410
+     * @param string $targetInternalPath
411
+     * @param bool $preserveMtime
412
+     * @return bool
413
+     */
414
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
415
+        if ($sourceStorage->instanceOfStorage(Local::class)) {
416
+            if ($sourceStorage->instanceOfStorage(Jail::class)) {
417
+                /**
418
+                 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
419
+                 */
420
+                $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
421
+            }
422
+            /**
423
+             * @var \OC\Files\Storage\Local $sourceStorage
424
+             */
425
+            $rootStorage = new Local(['datadir' => '/']);
426
+            return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
427
+        } else {
428
+            return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
429
+        }
430
+    }
431
+
432
+    /**
433
+     * @param IStorage $sourceStorage
434
+     * @param string $sourceInternalPath
435
+     * @param string $targetInternalPath
436
+     * @return bool
437
+     */
438
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
439
+        if ($sourceStorage->instanceOfStorage(Local::class)) {
440
+            if ($sourceStorage->instanceOfStorage(Jail::class)) {
441
+                /**
442
+                 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
443
+                 */
444
+                $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
445
+            }
446
+            /**
447
+             * @var \OC\Files\Storage\Local $sourceStorage
448
+             */
449
+            $rootStorage = new Local(['datadir' => '/']);
450
+            return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
451
+        } else {
452
+            return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
453
+        }
454
+    }
455 455
 }
Please login to merge, or discard this patch.