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