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