Passed
Push — master ( 62403d...0c3e2f )
by Joas
14:50 queued 14s
created
lib/private/Files/Node/LazyRoot.php 1 patch
Indentation   +461 added lines, -461 removed lines patch added patch discarded remove patch
@@ -34,465 +34,465 @@
 block discarded – undo
34 34
  * @package OC\Files\Node
35 35
  */
36 36
 class LazyRoot implements IRootFolder {
37
-	/** @var \Closure */
38
-	private $rootFolderClosure;
39
-
40
-	/** @var IRootFolder */
41
-	private $rootFolder;
42
-
43
-	/**
44
-	 * LazyRoot constructor.
45
-	 *
46
-	 * @param \Closure $rootFolderClosure
47
-	 */
48
-	public function __construct(\Closure $rootFolderClosure) {
49
-		$this->rootFolderClosure = $rootFolderClosure;
50
-	}
51
-
52
-	/**
53
-	 * Magic method to first get the real rootFolder and then
54
-	 * call $method with $args on it
55
-	 *
56
-	 * @param $method
57
-	 * @param $args
58
-	 * @return mixed
59
-	 */
60
-	public function __call($method, $args) {
61
-		if ($this->rootFolder === null) {
62
-			$this->rootFolder = call_user_func($this->rootFolderClosure);
63
-		}
64
-
65
-		return call_user_func_array([$this->rootFolder, $method], $args);
66
-	}
67
-
68
-	/**
69
-	 * @inheritDoc
70
-	 */
71
-	public function getUser() {
72
-		return $this->__call(__FUNCTION__, func_get_args());
73
-	}
74
-
75
-	/**
76
-	 * @inheritDoc
77
-	 */
78
-	public function listen($scope, $method, callable $callback) {
79
-		$this->__call(__FUNCTION__, func_get_args());
80
-	}
81
-
82
-	/**
83
-	 * @inheritDoc
84
-	 */
85
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
86
-		$this->__call(__FUNCTION__, func_get_args());
87
-	}
88
-
89
-	/**
90
-	 * @inheritDoc
91
-	 */
92
-	public function emit($scope, $method, $arguments = []) {
93
-		$this->__call(__FUNCTION__, func_get_args());
94
-	}
95
-
96
-	/**
97
-	 * @inheritDoc
98
-	 */
99
-	public function mount($storage, $mountPoint, $arguments = []) {
100
-		$this->__call(__FUNCTION__, func_get_args());
101
-	}
102
-
103
-	/**
104
-	 * @inheritDoc
105
-	 */
106
-	public function getMount($mountPoint) {
107
-		return $this->__call(__FUNCTION__, func_get_args());
108
-	}
109
-
110
-	/**
111
-	 * @inheritDoc
112
-	 */
113
-	public function getMountsIn($mountPoint) {
114
-		return $this->__call(__FUNCTION__, func_get_args());
115
-	}
116
-
117
-	/**
118
-	 * @inheritDoc
119
-	 */
120
-	public function getMountByStorageId($storageId) {
121
-		return $this->__call(__FUNCTION__, func_get_args());
122
-	}
123
-
124
-	/**
125
-	 * @inheritDoc
126
-	 */
127
-	public function getMountByNumericStorageId($numericId) {
128
-		return $this->__call(__FUNCTION__, func_get_args());
129
-	}
130
-
131
-	/**
132
-	 * @inheritDoc
133
-	 */
134
-	public function unMount($mount) {
135
-		$this->__call(__FUNCTION__, func_get_args());
136
-	}
137
-
138
-	/**
139
-	 * @inheritDoc
140
-	 */
141
-	public function get($path) {
142
-		return $this->__call(__FUNCTION__, func_get_args());
143
-	}
144
-
145
-	/**
146
-	 * @inheritDoc
147
-	 */
148
-	public function rename($targetPath) {
149
-		return $this->__call(__FUNCTION__, func_get_args());
150
-	}
151
-
152
-	/**
153
-	 * @inheritDoc
154
-	 */
155
-	public function delete() {
156
-		return $this->__call(__FUNCTION__, func_get_args());
157
-	}
158
-
159
-	/**
160
-	 * @inheritDoc
161
-	 */
162
-	public function copy($targetPath) {
163
-		return $this->__call(__FUNCTION__, func_get_args());
164
-	}
165
-
166
-	/**
167
-	 * @inheritDoc
168
-	 */
169
-	public function touch($mtime = null) {
170
-		$this->__call(__FUNCTION__, func_get_args());
171
-	}
172
-
173
-	/**
174
-	 * @inheritDoc
175
-	 */
176
-	public function getStorage() {
177
-		return $this->__call(__FUNCTION__, func_get_args());
178
-	}
179
-
180
-	/**
181
-	 * @inheritDoc
182
-	 */
183
-	public function getPath() {
184
-		return $this->__call(__FUNCTION__, func_get_args());
185
-	}
186
-
187
-	/**
188
-	 * @inheritDoc
189
-	 */
190
-	public function getInternalPath() {
191
-		return $this->__call(__FUNCTION__, func_get_args());
192
-	}
193
-
194
-	/**
195
-	 * @inheritDoc
196
-	 */
197
-	public function getId() {
198
-		return $this->__call(__FUNCTION__, func_get_args());
199
-	}
200
-
201
-	/**
202
-	 * @inheritDoc
203
-	 */
204
-	public function stat() {
205
-		return $this->__call(__FUNCTION__, func_get_args());
206
-	}
207
-
208
-	/**
209
-	 * @inheritDoc
210
-	 */
211
-	public function getMTime() {
212
-		return $this->__call(__FUNCTION__, func_get_args());
213
-	}
214
-
215
-	/**
216
-	 * @inheritDoc
217
-	 */
218
-	public function getSize($includeMounts = true) {
219
-		return $this->__call(__FUNCTION__, func_get_args());
220
-	}
221
-
222
-	/**
223
-	 * @inheritDoc
224
-	 */
225
-	public function getEtag() {
226
-		return $this->__call(__FUNCTION__, func_get_args());
227
-	}
228
-
229
-	/**
230
-	 * @inheritDoc
231
-	 */
232
-	public function getPermissions() {
233
-		return $this->__call(__FUNCTION__, func_get_args());
234
-	}
235
-
236
-	/**
237
-	 * @inheritDoc
238
-	 */
239
-	public function isReadable() {
240
-		return $this->__call(__FUNCTION__, func_get_args());
241
-	}
242
-
243
-	/**
244
-	 * @inheritDoc
245
-	 */
246
-	public function isUpdateable() {
247
-		return $this->__call(__FUNCTION__, func_get_args());
248
-	}
249
-
250
-	/**
251
-	 * @inheritDoc
252
-	 */
253
-	public function isDeletable() {
254
-		return $this->__call(__FUNCTION__, func_get_args());
255
-	}
256
-
257
-	/**
258
-	 * @inheritDoc
259
-	 */
260
-	public function isShareable() {
261
-		return $this->__call(__FUNCTION__, func_get_args());
262
-	}
263
-
264
-	/**
265
-	 * @inheritDoc
266
-	 */
267
-	public function getParent() {
268
-		return $this->__call(__FUNCTION__, func_get_args());
269
-	}
270
-
271
-	/**
272
-	 * @inheritDoc
273
-	 */
274
-	public function getName() {
275
-		return $this->__call(__FUNCTION__, func_get_args());
276
-	}
277
-
278
-	/**
279
-	 * @inheritDoc
280
-	 */
281
-	public function getUserFolder($userId) {
282
-		return $this->__call(__FUNCTION__, func_get_args());
283
-	}
284
-
285
-	/**
286
-	 * @inheritDoc
287
-	 */
288
-	public function getMimetype() {
289
-		return $this->__call(__FUNCTION__, func_get_args());
290
-	}
291
-
292
-	/**
293
-	 * @inheritDoc
294
-	 */
295
-	public function getMimePart() {
296
-		return $this->__call(__FUNCTION__, func_get_args());
297
-	}
298
-
299
-	/**
300
-	 * @inheritDoc
301
-	 */
302
-	public function isEncrypted() {
303
-		return $this->__call(__FUNCTION__, func_get_args());
304
-	}
305
-
306
-	/**
307
-	 * @inheritDoc
308
-	 */
309
-	public function getType() {
310
-		return $this->__call(__FUNCTION__, func_get_args());
311
-	}
312
-
313
-	/**
314
-	 * @inheritDoc
315
-	 */
316
-	public function isShared() {
317
-		return $this->__call(__FUNCTION__, func_get_args());
318
-	}
319
-
320
-	/**
321
-	 * @inheritDoc
322
-	 */
323
-	public function isMounted() {
324
-		return $this->__call(__FUNCTION__, func_get_args());
325
-	}
326
-
327
-	/**
328
-	 * @inheritDoc
329
-	 */
330
-	public function getMountPoint() {
331
-		return $this->__call(__FUNCTION__, func_get_args());
332
-	}
333
-
334
-	/**
335
-	 * @inheritDoc
336
-	 */
337
-	public function getOwner() {
338
-		return $this->__call(__FUNCTION__, func_get_args());
339
-	}
340
-
341
-	/**
342
-	 * @inheritDoc
343
-	 */
344
-	public function getChecksum() {
345
-		return $this->__call(__FUNCTION__, func_get_args());
346
-	}
347
-
348
-	public function getExtension(): string {
349
-		return $this->__call(__FUNCTION__, func_get_args());
350
-	}
351
-
352
-	/**
353
-	 * @inheritDoc
354
-	 */
355
-	public function getFullPath($path) {
356
-		return $this->__call(__FUNCTION__, func_get_args());
357
-	}
358
-
359
-	/**
360
-	 * @inheritDoc
361
-	 */
362
-	public function getRelativePath($path) {
363
-		return $this->__call(__FUNCTION__, func_get_args());
364
-	}
365
-
366
-	/**
367
-	 * @inheritDoc
368
-	 */
369
-	public function isSubNode($node) {
370
-		return $this->__call(__FUNCTION__, func_get_args());
371
-	}
372
-
373
-	/**
374
-	 * @inheritDoc
375
-	 */
376
-	public function getDirectoryListing() {
377
-		return $this->__call(__FUNCTION__, func_get_args());
378
-	}
379
-
380
-	/**
381
-	 * @inheritDoc
382
-	 */
383
-	public function nodeExists($path) {
384
-		return $this->__call(__FUNCTION__, func_get_args());
385
-	}
386
-
387
-	/**
388
-	 * @inheritDoc
389
-	 */
390
-	public function newFolder($path) {
391
-		return $this->__call(__FUNCTION__, func_get_args());
392
-	}
393
-
394
-	/**
395
-	 * @inheritDoc
396
-	 */
397
-	public function newFile($path, $content = null) {
398
-		return $this->__call(__FUNCTION__, func_get_args());
399
-	}
400
-
401
-	/**
402
-	 * @inheritDoc
403
-	 */
404
-	public function search($query) {
405
-		return $this->__call(__FUNCTION__, func_get_args());
406
-	}
407
-
408
-	/**
409
-	 * @inheritDoc
410
-	 */
411
-	public function searchByMime($mimetype) {
412
-		return $this->__call(__FUNCTION__, func_get_args());
413
-	}
414
-
415
-	/**
416
-	 * @inheritDoc
417
-	 */
418
-	public function searchByTag($tag, $userId) {
419
-		return $this->__call(__FUNCTION__, func_get_args());
420
-	}
421
-
422
-	/**
423
-	 * @inheritDoc
424
-	 */
425
-	public function getById($id) {
426
-		return $this->__call(__FUNCTION__, func_get_args());
427
-	}
428
-
429
-	/**
430
-	 * @inheritDoc
431
-	 */
432
-	public function getFreeSpace() {
433
-		return $this->__call(__FUNCTION__, func_get_args());
434
-	}
435
-
436
-	/**
437
-	 * @inheritDoc
438
-	 */
439
-	public function isCreatable() {
440
-		return $this->__call(__FUNCTION__, func_get_args());
441
-	}
442
-
443
-	/**
444
-	 * @inheritDoc
445
-	 */
446
-	public function getNonExistingName($name) {
447
-		return $this->__call(__FUNCTION__, func_get_args());
448
-	}
449
-
450
-	/**
451
-	 * @inheritDoc
452
-	 */
453
-	public function move($targetPath) {
454
-		return $this->__call(__FUNCTION__, func_get_args());
455
-	}
456
-
457
-	/**
458
-	 * @inheritDoc
459
-	 */
460
-	public function lock($type) {
461
-		return $this->__call(__FUNCTION__, func_get_args());
462
-	}
463
-
464
-	/**
465
-	 * @inheritDoc
466
-	 */
467
-	public function changeLock($targetType) {
468
-		return $this->__call(__FUNCTION__, func_get_args());
469
-	}
470
-
471
-	/**
472
-	 * @inheritDoc
473
-	 */
474
-	public function unlock($type) {
475
-		return $this->__call(__FUNCTION__, func_get_args());
476
-	}
477
-
478
-	/**
479
-	 * @inheritDoc
480
-	 */
481
-	public function getRecent($limit, $offset = 0) {
482
-		return $this->__call(__FUNCTION__, func_get_args());
483
-	}
484
-
485
-	/**
486
-	 * @inheritDoc
487
-	 */
488
-	public function getCreationTime(): int {
489
-		return $this->__call(__FUNCTION__, func_get_args());
490
-	}
491
-
492
-	/**
493
-	 * @inheritDoc
494
-	 */
495
-	public function getUploadTime(): int {
496
-		return $this->__call(__FUNCTION__, func_get_args());
497
-	}
37
+    /** @var \Closure */
38
+    private $rootFolderClosure;
39
+
40
+    /** @var IRootFolder */
41
+    private $rootFolder;
42
+
43
+    /**
44
+     * LazyRoot constructor.
45
+     *
46
+     * @param \Closure $rootFolderClosure
47
+     */
48
+    public function __construct(\Closure $rootFolderClosure) {
49
+        $this->rootFolderClosure = $rootFolderClosure;
50
+    }
51
+
52
+    /**
53
+     * Magic method to first get the real rootFolder and then
54
+     * call $method with $args on it
55
+     *
56
+     * @param $method
57
+     * @param $args
58
+     * @return mixed
59
+     */
60
+    public function __call($method, $args) {
61
+        if ($this->rootFolder === null) {
62
+            $this->rootFolder = call_user_func($this->rootFolderClosure);
63
+        }
64
+
65
+        return call_user_func_array([$this->rootFolder, $method], $args);
66
+    }
67
+
68
+    /**
69
+     * @inheritDoc
70
+     */
71
+    public function getUser() {
72
+        return $this->__call(__FUNCTION__, func_get_args());
73
+    }
74
+
75
+    /**
76
+     * @inheritDoc
77
+     */
78
+    public function listen($scope, $method, callable $callback) {
79
+        $this->__call(__FUNCTION__, func_get_args());
80
+    }
81
+
82
+    /**
83
+     * @inheritDoc
84
+     */
85
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
86
+        $this->__call(__FUNCTION__, func_get_args());
87
+    }
88
+
89
+    /**
90
+     * @inheritDoc
91
+     */
92
+    public function emit($scope, $method, $arguments = []) {
93
+        $this->__call(__FUNCTION__, func_get_args());
94
+    }
95
+
96
+    /**
97
+     * @inheritDoc
98
+     */
99
+    public function mount($storage, $mountPoint, $arguments = []) {
100
+        $this->__call(__FUNCTION__, func_get_args());
101
+    }
102
+
103
+    /**
104
+     * @inheritDoc
105
+     */
106
+    public function getMount($mountPoint) {
107
+        return $this->__call(__FUNCTION__, func_get_args());
108
+    }
109
+
110
+    /**
111
+     * @inheritDoc
112
+     */
113
+    public function getMountsIn($mountPoint) {
114
+        return $this->__call(__FUNCTION__, func_get_args());
115
+    }
116
+
117
+    /**
118
+     * @inheritDoc
119
+     */
120
+    public function getMountByStorageId($storageId) {
121
+        return $this->__call(__FUNCTION__, func_get_args());
122
+    }
123
+
124
+    /**
125
+     * @inheritDoc
126
+     */
127
+    public function getMountByNumericStorageId($numericId) {
128
+        return $this->__call(__FUNCTION__, func_get_args());
129
+    }
130
+
131
+    /**
132
+     * @inheritDoc
133
+     */
134
+    public function unMount($mount) {
135
+        $this->__call(__FUNCTION__, func_get_args());
136
+    }
137
+
138
+    /**
139
+     * @inheritDoc
140
+     */
141
+    public function get($path) {
142
+        return $this->__call(__FUNCTION__, func_get_args());
143
+    }
144
+
145
+    /**
146
+     * @inheritDoc
147
+     */
148
+    public function rename($targetPath) {
149
+        return $this->__call(__FUNCTION__, func_get_args());
150
+    }
151
+
152
+    /**
153
+     * @inheritDoc
154
+     */
155
+    public function delete() {
156
+        return $this->__call(__FUNCTION__, func_get_args());
157
+    }
158
+
159
+    /**
160
+     * @inheritDoc
161
+     */
162
+    public function copy($targetPath) {
163
+        return $this->__call(__FUNCTION__, func_get_args());
164
+    }
165
+
166
+    /**
167
+     * @inheritDoc
168
+     */
169
+    public function touch($mtime = null) {
170
+        $this->__call(__FUNCTION__, func_get_args());
171
+    }
172
+
173
+    /**
174
+     * @inheritDoc
175
+     */
176
+    public function getStorage() {
177
+        return $this->__call(__FUNCTION__, func_get_args());
178
+    }
179
+
180
+    /**
181
+     * @inheritDoc
182
+     */
183
+    public function getPath() {
184
+        return $this->__call(__FUNCTION__, func_get_args());
185
+    }
186
+
187
+    /**
188
+     * @inheritDoc
189
+     */
190
+    public function getInternalPath() {
191
+        return $this->__call(__FUNCTION__, func_get_args());
192
+    }
193
+
194
+    /**
195
+     * @inheritDoc
196
+     */
197
+    public function getId() {
198
+        return $this->__call(__FUNCTION__, func_get_args());
199
+    }
200
+
201
+    /**
202
+     * @inheritDoc
203
+     */
204
+    public function stat() {
205
+        return $this->__call(__FUNCTION__, func_get_args());
206
+    }
207
+
208
+    /**
209
+     * @inheritDoc
210
+     */
211
+    public function getMTime() {
212
+        return $this->__call(__FUNCTION__, func_get_args());
213
+    }
214
+
215
+    /**
216
+     * @inheritDoc
217
+     */
218
+    public function getSize($includeMounts = true) {
219
+        return $this->__call(__FUNCTION__, func_get_args());
220
+    }
221
+
222
+    /**
223
+     * @inheritDoc
224
+     */
225
+    public function getEtag() {
226
+        return $this->__call(__FUNCTION__, func_get_args());
227
+    }
228
+
229
+    /**
230
+     * @inheritDoc
231
+     */
232
+    public function getPermissions() {
233
+        return $this->__call(__FUNCTION__, func_get_args());
234
+    }
235
+
236
+    /**
237
+     * @inheritDoc
238
+     */
239
+    public function isReadable() {
240
+        return $this->__call(__FUNCTION__, func_get_args());
241
+    }
242
+
243
+    /**
244
+     * @inheritDoc
245
+     */
246
+    public function isUpdateable() {
247
+        return $this->__call(__FUNCTION__, func_get_args());
248
+    }
249
+
250
+    /**
251
+     * @inheritDoc
252
+     */
253
+    public function isDeletable() {
254
+        return $this->__call(__FUNCTION__, func_get_args());
255
+    }
256
+
257
+    /**
258
+     * @inheritDoc
259
+     */
260
+    public function isShareable() {
261
+        return $this->__call(__FUNCTION__, func_get_args());
262
+    }
263
+
264
+    /**
265
+     * @inheritDoc
266
+     */
267
+    public function getParent() {
268
+        return $this->__call(__FUNCTION__, func_get_args());
269
+    }
270
+
271
+    /**
272
+     * @inheritDoc
273
+     */
274
+    public function getName() {
275
+        return $this->__call(__FUNCTION__, func_get_args());
276
+    }
277
+
278
+    /**
279
+     * @inheritDoc
280
+     */
281
+    public function getUserFolder($userId) {
282
+        return $this->__call(__FUNCTION__, func_get_args());
283
+    }
284
+
285
+    /**
286
+     * @inheritDoc
287
+     */
288
+    public function getMimetype() {
289
+        return $this->__call(__FUNCTION__, func_get_args());
290
+    }
291
+
292
+    /**
293
+     * @inheritDoc
294
+     */
295
+    public function getMimePart() {
296
+        return $this->__call(__FUNCTION__, func_get_args());
297
+    }
298
+
299
+    /**
300
+     * @inheritDoc
301
+     */
302
+    public function isEncrypted() {
303
+        return $this->__call(__FUNCTION__, func_get_args());
304
+    }
305
+
306
+    /**
307
+     * @inheritDoc
308
+     */
309
+    public function getType() {
310
+        return $this->__call(__FUNCTION__, func_get_args());
311
+    }
312
+
313
+    /**
314
+     * @inheritDoc
315
+     */
316
+    public function isShared() {
317
+        return $this->__call(__FUNCTION__, func_get_args());
318
+    }
319
+
320
+    /**
321
+     * @inheritDoc
322
+     */
323
+    public function isMounted() {
324
+        return $this->__call(__FUNCTION__, func_get_args());
325
+    }
326
+
327
+    /**
328
+     * @inheritDoc
329
+     */
330
+    public function getMountPoint() {
331
+        return $this->__call(__FUNCTION__, func_get_args());
332
+    }
333
+
334
+    /**
335
+     * @inheritDoc
336
+     */
337
+    public function getOwner() {
338
+        return $this->__call(__FUNCTION__, func_get_args());
339
+    }
340
+
341
+    /**
342
+     * @inheritDoc
343
+     */
344
+    public function getChecksum() {
345
+        return $this->__call(__FUNCTION__, func_get_args());
346
+    }
347
+
348
+    public function getExtension(): string {
349
+        return $this->__call(__FUNCTION__, func_get_args());
350
+    }
351
+
352
+    /**
353
+     * @inheritDoc
354
+     */
355
+    public function getFullPath($path) {
356
+        return $this->__call(__FUNCTION__, func_get_args());
357
+    }
358
+
359
+    /**
360
+     * @inheritDoc
361
+     */
362
+    public function getRelativePath($path) {
363
+        return $this->__call(__FUNCTION__, func_get_args());
364
+    }
365
+
366
+    /**
367
+     * @inheritDoc
368
+     */
369
+    public function isSubNode($node) {
370
+        return $this->__call(__FUNCTION__, func_get_args());
371
+    }
372
+
373
+    /**
374
+     * @inheritDoc
375
+     */
376
+    public function getDirectoryListing() {
377
+        return $this->__call(__FUNCTION__, func_get_args());
378
+    }
379
+
380
+    /**
381
+     * @inheritDoc
382
+     */
383
+    public function nodeExists($path) {
384
+        return $this->__call(__FUNCTION__, func_get_args());
385
+    }
386
+
387
+    /**
388
+     * @inheritDoc
389
+     */
390
+    public function newFolder($path) {
391
+        return $this->__call(__FUNCTION__, func_get_args());
392
+    }
393
+
394
+    /**
395
+     * @inheritDoc
396
+     */
397
+    public function newFile($path, $content = null) {
398
+        return $this->__call(__FUNCTION__, func_get_args());
399
+    }
400
+
401
+    /**
402
+     * @inheritDoc
403
+     */
404
+    public function search($query) {
405
+        return $this->__call(__FUNCTION__, func_get_args());
406
+    }
407
+
408
+    /**
409
+     * @inheritDoc
410
+     */
411
+    public function searchByMime($mimetype) {
412
+        return $this->__call(__FUNCTION__, func_get_args());
413
+    }
414
+
415
+    /**
416
+     * @inheritDoc
417
+     */
418
+    public function searchByTag($tag, $userId) {
419
+        return $this->__call(__FUNCTION__, func_get_args());
420
+    }
421
+
422
+    /**
423
+     * @inheritDoc
424
+     */
425
+    public function getById($id) {
426
+        return $this->__call(__FUNCTION__, func_get_args());
427
+    }
428
+
429
+    /**
430
+     * @inheritDoc
431
+     */
432
+    public function getFreeSpace() {
433
+        return $this->__call(__FUNCTION__, func_get_args());
434
+    }
435
+
436
+    /**
437
+     * @inheritDoc
438
+     */
439
+    public function isCreatable() {
440
+        return $this->__call(__FUNCTION__, func_get_args());
441
+    }
442
+
443
+    /**
444
+     * @inheritDoc
445
+     */
446
+    public function getNonExistingName($name) {
447
+        return $this->__call(__FUNCTION__, func_get_args());
448
+    }
449
+
450
+    /**
451
+     * @inheritDoc
452
+     */
453
+    public function move($targetPath) {
454
+        return $this->__call(__FUNCTION__, func_get_args());
455
+    }
456
+
457
+    /**
458
+     * @inheritDoc
459
+     */
460
+    public function lock($type) {
461
+        return $this->__call(__FUNCTION__, func_get_args());
462
+    }
463
+
464
+    /**
465
+     * @inheritDoc
466
+     */
467
+    public function changeLock($targetType) {
468
+        return $this->__call(__FUNCTION__, func_get_args());
469
+    }
470
+
471
+    /**
472
+     * @inheritDoc
473
+     */
474
+    public function unlock($type) {
475
+        return $this->__call(__FUNCTION__, func_get_args());
476
+    }
477
+
478
+    /**
479
+     * @inheritDoc
480
+     */
481
+    public function getRecent($limit, $offset = 0) {
482
+        return $this->__call(__FUNCTION__, func_get_args());
483
+    }
484
+
485
+    /**
486
+     * @inheritDoc
487
+     */
488
+    public function getCreationTime(): int {
489
+        return $this->__call(__FUNCTION__, func_get_args());
490
+    }
491
+
492
+    /**
493
+     * @inheritDoc
494
+     */
495
+    public function getUploadTime(): int {
496
+        return $this->__call(__FUNCTION__, func_get_args());
497
+    }
498 498
 }
Please login to merge, or discard this patch.
lib/private/Files/Node/File.php 1 patch
Indentation   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -33,128 +33,128 @@
 block discarded – undo
33 33
 use OCP\Lock\LockedException;
34 34
 
35 35
 class File extends Node implements \OCP\Files\File {
36
-	/**
37
-	 * Creates a Folder that represents a non-existing path
38
-	 *
39
-	 * @param string $path path
40
-	 * @return string non-existing node class
41
-	 */
42
-	protected function createNonExistingNode($path) {
43
-		return new NonExistingFile($this->root, $this->view, $path);
44
-	}
36
+    /**
37
+     * Creates a Folder that represents a non-existing path
38
+     *
39
+     * @param string $path path
40
+     * @return string non-existing node class
41
+     */
42
+    protected function createNonExistingNode($path) {
43
+        return new NonExistingFile($this->root, $this->view, $path);
44
+    }
45 45
 
46
-	/**
47
-	 * @return string
48
-	 * @throws NotPermittedException
49
-	 * @throws LockedException
50
-	 */
51
-	public function getContent() {
52
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
53
-			/**
54
-			 * @var \OC\Files\Storage\Storage $storage;
55
-			 */
56
-			return $this->view->file_get_contents($this->path);
57
-		} else {
58
-			throw new NotPermittedException();
59
-		}
60
-	}
46
+    /**
47
+     * @return string
48
+     * @throws NotPermittedException
49
+     * @throws LockedException
50
+     */
51
+    public function getContent() {
52
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
53
+            /**
54
+             * @var \OC\Files\Storage\Storage $storage;
55
+             */
56
+            return $this->view->file_get_contents($this->path);
57
+        } else {
58
+            throw new NotPermittedException();
59
+        }
60
+    }
61 61
 
62
-	/**
63
-	 * @param string|resource $data
64
-	 * @throws NotPermittedException
65
-	 * @throws \OCP\Files\GenericFileException
66
-	 * @throws LockedException
67
-	 */
68
-	public function putContent($data) {
69
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
70
-			$this->sendHooks(['preWrite']);
71
-			if ($this->view->file_put_contents($this->path, $data) === false) {
72
-				throw new GenericFileException('file_put_contents failed');
73
-			}
74
-			$this->fileInfo = null;
75
-			$this->sendHooks(['postWrite']);
76
-		} else {
77
-			throw new NotPermittedException();
78
-		}
79
-	}
62
+    /**
63
+     * @param string|resource $data
64
+     * @throws NotPermittedException
65
+     * @throws \OCP\Files\GenericFileException
66
+     * @throws LockedException
67
+     */
68
+    public function putContent($data) {
69
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
70
+            $this->sendHooks(['preWrite']);
71
+            if ($this->view->file_put_contents($this->path, $data) === false) {
72
+                throw new GenericFileException('file_put_contents failed');
73
+            }
74
+            $this->fileInfo = null;
75
+            $this->sendHooks(['postWrite']);
76
+        } else {
77
+            throw new NotPermittedException();
78
+        }
79
+    }
80 80
 
81
-	/**
82
-	 * @param string $mode
83
-	 * @return resource
84
-	 * @throws NotPermittedException
85
-	 * @throws LockedException
86
-	 */
87
-	public function fopen($mode) {
88
-		$preHooks = [];
89
-		$postHooks = [];
90
-		$requiredPermissions = \OCP\Constants::PERMISSION_READ;
91
-		switch ($mode) {
92
-			case 'r+':
93
-			case 'rb+':
94
-			case 'w+':
95
-			case 'wb+':
96
-			case 'x+':
97
-			case 'xb+':
98
-			case 'a+':
99
-			case 'ab+':
100
-			case 'w':
101
-			case 'wb':
102
-			case 'x':
103
-			case 'xb':
104
-			case 'a':
105
-			case 'ab':
106
-				$preHooks[] = 'preWrite';
107
-				$postHooks[] = 'postWrite';
108
-				$requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
109
-				break;
110
-		}
81
+    /**
82
+     * @param string $mode
83
+     * @return resource
84
+     * @throws NotPermittedException
85
+     * @throws LockedException
86
+     */
87
+    public function fopen($mode) {
88
+        $preHooks = [];
89
+        $postHooks = [];
90
+        $requiredPermissions = \OCP\Constants::PERMISSION_READ;
91
+        switch ($mode) {
92
+            case 'r+':
93
+            case 'rb+':
94
+            case 'w+':
95
+            case 'wb+':
96
+            case 'x+':
97
+            case 'xb+':
98
+            case 'a+':
99
+            case 'ab+':
100
+            case 'w':
101
+            case 'wb':
102
+            case 'x':
103
+            case 'xb':
104
+            case 'a':
105
+            case 'ab':
106
+                $preHooks[] = 'preWrite';
107
+                $postHooks[] = 'postWrite';
108
+                $requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
109
+                break;
110
+        }
111 111
 
112
-		if ($this->checkPermissions($requiredPermissions)) {
113
-			$this->sendHooks($preHooks);
114
-			$result = $this->view->fopen($this->path, $mode);
115
-			$this->sendHooks($postHooks);
116
-			return $result;
117
-		} else {
118
-			throw new NotPermittedException();
119
-		}
120
-	}
112
+        if ($this->checkPermissions($requiredPermissions)) {
113
+            $this->sendHooks($preHooks);
114
+            $result = $this->view->fopen($this->path, $mode);
115
+            $this->sendHooks($postHooks);
116
+            return $result;
117
+        } else {
118
+            throw new NotPermittedException();
119
+        }
120
+    }
121 121
 
122
-	/**
123
-	 * @throws NotPermittedException
124
-	 * @throws \OCP\Files\InvalidPathException
125
-	 * @throws \OCP\Files\NotFoundException
126
-	 */
127
-	public function delete() {
128
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
129
-			$this->sendHooks(['preDelete']);
130
-			$fileInfo = $this->getFileInfo();
131
-			$this->view->unlink($this->path);
132
-			$nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
133
-			$this->sendHooks(['postDelete'], [$nonExisting]);
134
-			$this->exists = false;
135
-			$this->fileInfo = null;
136
-		} else {
137
-			throw new NotPermittedException();
138
-		}
139
-	}
122
+    /**
123
+     * @throws NotPermittedException
124
+     * @throws \OCP\Files\InvalidPathException
125
+     * @throws \OCP\Files\NotFoundException
126
+     */
127
+    public function delete() {
128
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
129
+            $this->sendHooks(['preDelete']);
130
+            $fileInfo = $this->getFileInfo();
131
+            $this->view->unlink($this->path);
132
+            $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
133
+            $this->sendHooks(['postDelete'], [$nonExisting]);
134
+            $this->exists = false;
135
+            $this->fileInfo = null;
136
+        } else {
137
+            throw new NotPermittedException();
138
+        }
139
+    }
140 140
 
141
-	/**
142
-	 * @param string $type
143
-	 * @param bool $raw
144
-	 * @return string
145
-	 */
146
-	public function hash($type, $raw = false) {
147
-		return $this->view->hash($type, $this->path, $raw);
148
-	}
141
+    /**
142
+     * @param string $type
143
+     * @param bool $raw
144
+     * @return string
145
+     */
146
+    public function hash($type, $raw = false) {
147
+        return $this->view->hash($type, $this->path, $raw);
148
+    }
149 149
 
150
-	/**
151
-	 * @inheritdoc
152
-	 */
153
-	public function getChecksum() {
154
-		return $this->getFileInfo()->getChecksum();
155
-	}
150
+    /**
151
+     * @inheritdoc
152
+     */
153
+    public function getChecksum() {
154
+        return $this->getFileInfo()->getChecksum();
155
+    }
156 156
 
157
-	public function getExtension(): string {
158
-		return $this->getFileInfo()->getExtension();
159
-	}
157
+    public function getExtension(): string {
158
+        return $this->getFileInfo()->getExtension();
159
+    }
160 160
 }
Please login to merge, or discard this patch.
lib/private/Files/Filesystem.php 1 patch
Indentation   +844 added lines, -844 removed lines patch added patch discarded remove patch
@@ -72,848 +72,848 @@
 block discarded – undo
72 72
 
73 73
 class Filesystem {
74 74
 
75
-	/**
76
-	 * @var Mount\Manager $mounts
77
-	 */
78
-	private static $mounts;
79
-
80
-	public static $loaded = false;
81
-	/**
82
-	 * @var \OC\Files\View $defaultInstance
83
-	 */
84
-	static private $defaultInstance;
85
-
86
-	static private $usersSetup = [];
87
-
88
-	static private $normalizedPathCache = null;
89
-
90
-	static private $listeningForProviders = false;
91
-
92
-	/**
93
-	 * classname which used for hooks handling
94
-	 * used as signalclass in OC_Hooks::emit()
95
-	 */
96
-	const CLASSNAME = 'OC_Filesystem';
97
-
98
-	/**
99
-	 * signalname emitted before file renaming
100
-	 *
101
-	 * @param string $oldpath
102
-	 * @param string $newpath
103
-	 */
104
-	const signal_rename = 'rename';
105
-
106
-	/**
107
-	 * signal emitted after file renaming
108
-	 *
109
-	 * @param string $oldpath
110
-	 * @param string $newpath
111
-	 */
112
-	const signal_post_rename = 'post_rename';
113
-
114
-	/**
115
-	 * signal emitted before file/dir creation
116
-	 *
117
-	 * @param string $path
118
-	 * @param bool $run changing this flag to false in hook handler will cancel event
119
-	 */
120
-	const signal_create = 'create';
121
-
122
-	/**
123
-	 * signal emitted after file/dir creation
124
-	 *
125
-	 * @param string $path
126
-	 * @param bool $run changing this flag to false in hook handler will cancel event
127
-	 */
128
-	const signal_post_create = 'post_create';
129
-
130
-	/**
131
-	 * signal emits before file/dir copy
132
-	 *
133
-	 * @param string $oldpath
134
-	 * @param string $newpath
135
-	 * @param bool $run changing this flag to false in hook handler will cancel event
136
-	 */
137
-	const signal_copy = 'copy';
138
-
139
-	/**
140
-	 * signal emits after file/dir copy
141
-	 *
142
-	 * @param string $oldpath
143
-	 * @param string $newpath
144
-	 */
145
-	const signal_post_copy = 'post_copy';
146
-
147
-	/**
148
-	 * signal emits before file/dir save
149
-	 *
150
-	 * @param string $path
151
-	 * @param bool $run changing this flag to false in hook handler will cancel event
152
-	 */
153
-	const signal_write = 'write';
154
-
155
-	/**
156
-	 * signal emits after file/dir save
157
-	 *
158
-	 * @param string $path
159
-	 */
160
-	const signal_post_write = 'post_write';
161
-
162
-	/**
163
-	 * signal emitted before file/dir update
164
-	 *
165
-	 * @param string $path
166
-	 * @param bool $run changing this flag to false in hook handler will cancel event
167
-	 */
168
-	const signal_update = 'update';
169
-
170
-	/**
171
-	 * signal emitted after file/dir update
172
-	 *
173
-	 * @param string $path
174
-	 * @param bool $run changing this flag to false in hook handler will cancel event
175
-	 */
176
-	const signal_post_update = 'post_update';
177
-
178
-	/**
179
-	 * signal emits when reading file/dir
180
-	 *
181
-	 * @param string $path
182
-	 */
183
-	const signal_read = 'read';
184
-
185
-	/**
186
-	 * signal emits when removing file/dir
187
-	 *
188
-	 * @param string $path
189
-	 */
190
-	const signal_delete = 'delete';
191
-
192
-	/**
193
-	 * parameters definitions for signals
194
-	 */
195
-	const signal_param_path = 'path';
196
-	const signal_param_oldpath = 'oldpath';
197
-	const signal_param_newpath = 'newpath';
198
-
199
-	/**
200
-	 * run - changing this flag to false in hook handler will cancel event
201
-	 */
202
-	const signal_param_run = 'run';
203
-
204
-	const signal_create_mount = 'create_mount';
205
-	const signal_delete_mount = 'delete_mount';
206
-	const signal_param_mount_type = 'mounttype';
207
-	const signal_param_users = 'users';
208
-
209
-	/**
210
-	 * @var \OC\Files\Storage\StorageFactory $loader
211
-	 */
212
-	private static $loader;
213
-
214
-	/** @var bool */
215
-	private static $logWarningWhenAddingStorageWrapper = true;
216
-
217
-	/**
218
-	 * @param bool $shouldLog
219
-	 * @return bool previous value
220
-	 * @internal
221
-	 */
222
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
223
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
224
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
225
-		return $previousValue;
226
-	}
227
-
228
-	/**
229
-	 * @param string $wrapperName
230
-	 * @param callable $wrapper
231
-	 * @param int $priority
232
-	 */
233
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
234
-		if (self::$logWarningWhenAddingStorageWrapper) {
235
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
236
-				'wrapper' => $wrapperName,
237
-				'app' => 'filesystem',
238
-			]);
239
-		}
240
-
241
-		$mounts = self::getMountManager()->getAll();
242
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
243
-			// do not re-wrap if storage with this name already existed
244
-			return;
245
-		}
246
-	}
247
-
248
-	/**
249
-	 * Returns the storage factory
250
-	 *
251
-	 * @return IStorageFactory
252
-	 */
253
-	public static function getLoader() {
254
-		if (!self::$loader) {
255
-			self::$loader = \OC::$server->query(IStorageFactory::class);
256
-		}
257
-		return self::$loader;
258
-	}
259
-
260
-	/**
261
-	 * Returns the mount manager
262
-	 *
263
-	 * @return \OC\Files\Mount\Manager
264
-	 */
265
-	public static function getMountManager($user = '') {
266
-		if (!self::$mounts) {
267
-			\OC_Util::setupFS($user);
268
-		}
269
-		return self::$mounts;
270
-	}
271
-
272
-	/**
273
-	 * get the mountpoint of the storage object for a path
274
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
275
-	 * returned mountpoint is relative to the absolute root of the filesystem
276
-	 * and doesn't take the chroot into account )
277
-	 *
278
-	 * @param string $path
279
-	 * @return string
280
-	 */
281
-	static public function getMountPoint($path) {
282
-		if (!self::$mounts) {
283
-			\OC_Util::setupFS();
284
-		}
285
-		$mount = self::$mounts->find($path);
286
-		if ($mount) {
287
-			return $mount->getMountPoint();
288
-		} else {
289
-			return '';
290
-		}
291
-	}
292
-
293
-	/**
294
-	 * get a list of all mount points in a directory
295
-	 *
296
-	 * @param string $path
297
-	 * @return string[]
298
-	 */
299
-	static public function getMountPoints($path) {
300
-		if (!self::$mounts) {
301
-			\OC_Util::setupFS();
302
-		}
303
-		$result = [];
304
-		$mounts = self::$mounts->findIn($path);
305
-		foreach ($mounts as $mount) {
306
-			$result[] = $mount->getMountPoint();
307
-		}
308
-		return $result;
309
-	}
310
-
311
-	/**
312
-	 * get the storage mounted at $mountPoint
313
-	 *
314
-	 * @param string $mountPoint
315
-	 * @return \OC\Files\Storage\Storage
316
-	 */
317
-	public static function getStorage($mountPoint) {
318
-		if (!self::$mounts) {
319
-			\OC_Util::setupFS();
320
-		}
321
-		$mount = self::$mounts->find($mountPoint);
322
-		return $mount->getStorage();
323
-	}
324
-
325
-	/**
326
-	 * @param string $id
327
-	 * @return Mount\MountPoint[]
328
-	 */
329
-	public static function getMountByStorageId($id) {
330
-		if (!self::$mounts) {
331
-			\OC_Util::setupFS();
332
-		}
333
-		return self::$mounts->findByStorageId($id);
334
-	}
335
-
336
-	/**
337
-	 * @param int $id
338
-	 * @return Mount\MountPoint[]
339
-	 */
340
-	public static function getMountByNumericId($id) {
341
-		if (!self::$mounts) {
342
-			\OC_Util::setupFS();
343
-		}
344
-		return self::$mounts->findByNumericId($id);
345
-	}
346
-
347
-	/**
348
-	 * resolve a path to a storage and internal path
349
-	 *
350
-	 * @param string $path
351
-	 * @return array an array consisting of the storage and the internal path
352
-	 */
353
-	static public function resolvePath($path) {
354
-		if (!self::$mounts) {
355
-			\OC_Util::setupFS();
356
-		}
357
-		$mount = self::$mounts->find($path);
358
-		if ($mount) {
359
-			return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
360
-		} else {
361
-			return [null, null];
362
-		}
363
-	}
364
-
365
-	static public function init($user, $root) {
366
-		if (self::$defaultInstance) {
367
-			return false;
368
-		}
369
-		self::getLoader();
370
-		self::$defaultInstance = new View($root);
371
-
372
-		if (!self::$mounts) {
373
-			self::$mounts = \OC::$server->getMountManager();
374
-		}
375
-
376
-		//load custom mount config
377
-		self::initMountPoints($user);
378
-
379
-		self::$loaded = true;
380
-
381
-		return true;
382
-	}
383
-
384
-	static public function initMountManager() {
385
-		if (!self::$mounts) {
386
-			self::$mounts = \OC::$server->getMountManager();
387
-		}
388
-	}
389
-
390
-	/**
391
-	 * Initialize system and personal mount points for a user
392
-	 *
393
-	 * @param string $user
394
-	 * @throws \OC\User\NoUserException if the user is not available
395
-	 */
396
-	public static function initMountPoints($user = '') {
397
-		if ($user == '') {
398
-			$user = \OC_User::getUser();
399
-		}
400
-		if ($user === null || $user === false || $user === '') {
401
-			throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
402
-		}
403
-
404
-		if (isset(self::$usersSetup[$user])) {
405
-			return;
406
-		}
407
-
408
-		self::$usersSetup[$user] = true;
409
-
410
-		$userManager = \OC::$server->getUserManager();
411
-		$userObject = $userManager->get($user);
412
-
413
-		if (is_null($userObject)) {
414
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
415
-			// reset flag, this will make it possible to rethrow the exception if called again
416
-			unset(self::$usersSetup[$user]);
417
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
418
-		}
419
-
420
-		$realUid = $userObject->getUID();
421
-		// workaround in case of different casings
422
-		if ($user !== $realUid) {
423
-			$stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
424
-			\OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
425
-			$user = $realUid;
426
-
427
-			// again with the correct casing
428
-			if (isset(self::$usersSetup[$user])) {
429
-				return;
430
-			}
431
-
432
-			self::$usersSetup[$user] = true;
433
-		}
434
-
435
-		if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
436
-			/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
437
-			$mountConfigManager = \OC::$server->getMountProviderCollection();
438
-
439
-			// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
440
-			$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
441
-
442
-			self::getMountManager()->addMount($homeMount);
443
-
444
-			\OC\Files\Filesystem::getStorage($user);
445
-
446
-			// Chance to mount for other storages
447
-			if ($userObject) {
448
-				$mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
449
-				$mounts[] = $homeMount;
450
-				$mountConfigManager->registerMounts($userObject, $mounts);
451
-			}
452
-
453
-			self::listenForNewMountProviders($mountConfigManager, $userManager);
454
-		} else {
455
-			self::getMountManager()->addMount(new MountPoint(
456
-				new NullStorage([]),
457
-				'/' . $user
458
-			));
459
-			self::getMountManager()->addMount(new MountPoint(
460
-				new NullStorage([]),
461
-				'/' . $user . '/files'
462
-			));
463
-		}
464
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
465
-	}
466
-
467
-	/**
468
-	 * Get mounts from mount providers that are registered after setup
469
-	 *
470
-	 * @param MountProviderCollection $mountConfigManager
471
-	 * @param IUserManager $userManager
472
-	 */
473
-	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
474
-		if (!self::$listeningForProviders) {
475
-			self::$listeningForProviders = true;
476
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
477
-				foreach (Filesystem::$usersSetup as $user => $setup) {
478
-					$userObject = $userManager->get($user);
479
-					if ($userObject) {
480
-						$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
481
-						array_walk($mounts, [self::$mounts, 'addMount']);
482
-					}
483
-				}
484
-			});
485
-		}
486
-	}
487
-
488
-	/**
489
-	 * get the default filesystem view
490
-	 *
491
-	 * @return View
492
-	 */
493
-	static public function getView() {
494
-		return self::$defaultInstance;
495
-	}
496
-
497
-	/**
498
-	 * tear down the filesystem, removing all storage providers
499
-	 */
500
-	static public function tearDown() {
501
-		self::clearMounts();
502
-		self::$defaultInstance = null;
503
-	}
504
-
505
-	/**
506
-	 * get the relative path of the root data directory for the current user
507
-	 *
508
-	 * @return string
509
-	 *
510
-	 * Returns path like /admin/files
511
-	 */
512
-	static public function getRoot() {
513
-		if (!self::$defaultInstance) {
514
-			return null;
515
-		}
516
-		return self::$defaultInstance->getRoot();
517
-	}
518
-
519
-	/**
520
-	 * clear all mounts and storage backends
521
-	 */
522
-	public static function clearMounts() {
523
-		if (self::$mounts) {
524
-			self::$usersSetup = [];
525
-			self::$mounts->clear();
526
-		}
527
-	}
528
-
529
-	/**
530
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
531
-	 *
532
-	 * @param \OC\Files\Storage\Storage|string $class
533
-	 * @param array $arguments
534
-	 * @param string $mountpoint
535
-	 */
536
-	static public function mount($class, $arguments, $mountpoint) {
537
-		if (!self::$mounts) {
538
-			\OC_Util::setupFS();
539
-		}
540
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
541
-		self::$mounts->addMount($mount);
542
-	}
543
-
544
-	/**
545
-	 * return the path to a local version of the file
546
-	 * we need this because we can't know if a file is stored local or not from
547
-	 * outside the filestorage and for some purposes a local file is needed
548
-	 *
549
-	 * @param string $path
550
-	 * @return string
551
-	 */
552
-	static public function getLocalFile($path) {
553
-		return self::$defaultInstance->getLocalFile($path);
554
-	}
555
-
556
-	/**
557
-	 * @param string $path
558
-	 * @return string
559
-	 */
560
-	static public function getLocalFolder($path) {
561
-		return self::$defaultInstance->getLocalFolder($path);
562
-	}
563
-
564
-	/**
565
-	 * return path to file which reflects one visible in browser
566
-	 *
567
-	 * @param string $path
568
-	 * @return string
569
-	 */
570
-	static public function getLocalPath($path) {
571
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
572
-		$newpath = $path;
573
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
574
-			$newpath = substr($path, strlen($datadir));
575
-		}
576
-		return $newpath;
577
-	}
578
-
579
-	/**
580
-	 * check if the requested path is valid
581
-	 *
582
-	 * @param string $path
583
-	 * @return bool
584
-	 */
585
-	static public function isValidPath($path) {
586
-		$path = self::normalizePath($path);
587
-		if (!$path || $path[0] !== '/') {
588
-			$path = '/' . $path;
589
-		}
590
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
591
-			return false;
592
-		}
593
-		return true;
594
-	}
595
-
596
-	/**
597
-	 * checks if a file is blacklisted for storage in the filesystem
598
-	 * Listens to write and rename hooks
599
-	 *
600
-	 * @param array $data from hook
601
-	 */
602
-	static public function isBlacklisted($data) {
603
-		if (isset($data['path'])) {
604
-			$path = $data['path'];
605
-		} else if (isset($data['newpath'])) {
606
-			$path = $data['newpath'];
607
-		}
608
-		if (isset($path)) {
609
-			if (self::isFileBlacklisted($path)) {
610
-				$data['run'] = false;
611
-			}
612
-		}
613
-	}
614
-
615
-	/**
616
-	 * @param string $filename
617
-	 * @return bool
618
-	 */
619
-	static public function isFileBlacklisted($filename) {
620
-		$filename = self::normalizePath($filename);
621
-
622
-		$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
623
-		$filename = strtolower(basename($filename));
624
-		return in_array($filename, $blacklist);
625
-	}
626
-
627
-	/**
628
-	 * check if the directory should be ignored when scanning
629
-	 * NOTE: the special directories . and .. would cause never ending recursion
630
-	 *
631
-	 * @param string $dir
632
-	 * @return boolean
633
-	 */
634
-	static public function isIgnoredDir($dir) {
635
-		if ($dir === '.' || $dir === '..') {
636
-			return true;
637
-		}
638
-		return false;
639
-	}
640
-
641
-	/**
642
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
643
-	 */
644
-	static public function mkdir($path) {
645
-		return self::$defaultInstance->mkdir($path);
646
-	}
647
-
648
-	static public function rmdir($path) {
649
-		return self::$defaultInstance->rmdir($path);
650
-	}
651
-
652
-	static public function is_dir($path) {
653
-		return self::$defaultInstance->is_dir($path);
654
-	}
655
-
656
-	static public function is_file($path) {
657
-		return self::$defaultInstance->is_file($path);
658
-	}
659
-
660
-	static public function stat($path) {
661
-		return self::$defaultInstance->stat($path);
662
-	}
663
-
664
-	static public function filetype($path) {
665
-		return self::$defaultInstance->filetype($path);
666
-	}
667
-
668
-	static public function filesize($path) {
669
-		return self::$defaultInstance->filesize($path);
670
-	}
671
-
672
-	static public function readfile($path) {
673
-		return self::$defaultInstance->readfile($path);
674
-	}
675
-
676
-	static public function isCreatable($path) {
677
-		return self::$defaultInstance->isCreatable($path);
678
-	}
679
-
680
-	static public function isReadable($path) {
681
-		return self::$defaultInstance->isReadable($path);
682
-	}
683
-
684
-	static public function isUpdatable($path) {
685
-		return self::$defaultInstance->isUpdatable($path);
686
-	}
687
-
688
-	static public function isDeletable($path) {
689
-		return self::$defaultInstance->isDeletable($path);
690
-	}
691
-
692
-	static public function isSharable($path) {
693
-		return self::$defaultInstance->isSharable($path);
694
-	}
695
-
696
-	static public function file_exists($path) {
697
-		return self::$defaultInstance->file_exists($path);
698
-	}
699
-
700
-	static public function filemtime($path) {
701
-		return self::$defaultInstance->filemtime($path);
702
-	}
703
-
704
-	static public function touch($path, $mtime = null) {
705
-		return self::$defaultInstance->touch($path, $mtime);
706
-	}
707
-
708
-	/**
709
-	 * @return string
710
-	 */
711
-	static public function file_get_contents($path) {
712
-		return self::$defaultInstance->file_get_contents($path);
713
-	}
714
-
715
-	static public function file_put_contents($path, $data) {
716
-		return self::$defaultInstance->file_put_contents($path, $data);
717
-	}
718
-
719
-	static public function unlink($path) {
720
-		return self::$defaultInstance->unlink($path);
721
-	}
722
-
723
-	static public function rename($path1, $path2) {
724
-		return self::$defaultInstance->rename($path1, $path2);
725
-	}
726
-
727
-	static public function copy($path1, $path2) {
728
-		return self::$defaultInstance->copy($path1, $path2);
729
-	}
730
-
731
-	static public function fopen($path, $mode) {
732
-		return self::$defaultInstance->fopen($path, $mode);
733
-	}
734
-
735
-	/**
736
-	 * @return string
737
-	 */
738
-	static public function toTmpFile($path) {
739
-		return self::$defaultInstance->toTmpFile($path);
740
-	}
741
-
742
-	static public function fromTmpFile($tmpFile, $path) {
743
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
744
-	}
745
-
746
-	static public function getMimeType($path) {
747
-		return self::$defaultInstance->getMimeType($path);
748
-	}
749
-
750
-	static public function hash($type, $path, $raw = false) {
751
-		return self::$defaultInstance->hash($type, $path, $raw);
752
-	}
753
-
754
-	static public function free_space($path = '/') {
755
-		return self::$defaultInstance->free_space($path);
756
-	}
757
-
758
-	static public function search($query) {
759
-		return self::$defaultInstance->search($query);
760
-	}
761
-
762
-	/**
763
-	 * @param string $query
764
-	 */
765
-	static public function searchByMime($query) {
766
-		return self::$defaultInstance->searchByMime($query);
767
-	}
768
-
769
-	/**
770
-	 * @param string|int $tag name or tag id
771
-	 * @param string $userId owner of the tags
772
-	 * @return FileInfo[] array or file info
773
-	 */
774
-	static public function searchByTag($tag, $userId) {
775
-		return self::$defaultInstance->searchByTag($tag, $userId);
776
-	}
777
-
778
-	/**
779
-	 * check if a file or folder has been updated since $time
780
-	 *
781
-	 * @param string $path
782
-	 * @param int $time
783
-	 * @return bool
784
-	 */
785
-	static public function hasUpdated($path, $time) {
786
-		return self::$defaultInstance->hasUpdated($path, $time);
787
-	}
788
-
789
-	/**
790
-	 * Fix common problems with a file path
791
-	 *
792
-	 * @param string $path
793
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
794
-	 * @param bool $isAbsolutePath whether the given path is absolute
795
-	 * @param bool $keepUnicode true to disable unicode normalization
796
-	 * @return string
797
-	 */
798
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
799
-		if (is_null(self::$normalizedPathCache)) {
800
-			self::$normalizedPathCache = new CappedMemoryCache(2048);
801
-		}
802
-
803
-		/**
804
-		 * FIXME: This is a workaround for existing classes and files which call
805
-		 *        this function with another type than a valid string. This
806
-		 *        conversion should get removed as soon as all existing
807
-		 *        function calls have been fixed.
808
-		 */
809
-		$path = (string)$path;
810
-
811
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
812
-
813
-		if (isset(self::$normalizedPathCache[$cacheKey])) {
814
-			return self::$normalizedPathCache[$cacheKey];
815
-		}
816
-
817
-		if ($path === '') {
818
-			return '/';
819
-		}
820
-
821
-		//normalize unicode if possible
822
-		if (!$keepUnicode) {
823
-			$path = \OC_Util::normalizeUnicode($path);
824
-		}
825
-
826
-		//add leading slash, if it is already there we strip it anyway
827
-		$path = '/' . $path;
828
-
829
-		$patterns = [
830
-			'/\\\\/s',          // no windows style slashes
831
-			'/\/\.(\/\.)?\//s', // remove '/./'
832
-			'/\/{2,}/s',        // remove squence of slashes
833
-			'/\/\.$/s',         // remove trailing /.
834
-		];
835
-
836
-		do {
837
-			$count = 0;
838
-			$path = preg_replace($patterns, '/', $path, -1, $count);
839
-		} while ($count > 0);
840
-
841
-		//remove trailing slash
842
-		if ($stripTrailingSlash && strlen($path) > 1) {
843
-			$path = rtrim($path, '/');
844
-		}
845
-
846
-		self::$normalizedPathCache[$cacheKey] = $path;
847
-
848
-		return $path;
849
-	}
850
-
851
-	/**
852
-	 * get the filesystem info
853
-	 *
854
-	 * @param string $path
855
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
856
-	 * defaults to true
857
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
858
-	 */
859
-	public static function getFileInfo($path, $includeMountPoints = true) {
860
-		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
861
-	}
862
-
863
-	/**
864
-	 * change file metadata
865
-	 *
866
-	 * @param string $path
867
-	 * @param array $data
868
-	 * @return int
869
-	 *
870
-	 * returns the fileid of the updated file
871
-	 */
872
-	public static function putFileInfo($path, $data) {
873
-		return self::$defaultInstance->putFileInfo($path, $data);
874
-	}
875
-
876
-	/**
877
-	 * get the content of a directory
878
-	 *
879
-	 * @param string $directory path under datadirectory
880
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
881
-	 * @return \OC\Files\FileInfo[]
882
-	 */
883
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
884
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
885
-	}
886
-
887
-	/**
888
-	 * Get the path of a file by id
889
-	 *
890
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
891
-	 *
892
-	 * @param int $id
893
-	 * @throws NotFoundException
894
-	 * @return string
895
-	 */
896
-	public static function getPath($id) {
897
-		return self::$defaultInstance->getPath($id);
898
-	}
899
-
900
-	/**
901
-	 * Get the owner for a file or folder
902
-	 *
903
-	 * @param string $path
904
-	 * @return string
905
-	 */
906
-	public static function getOwner($path) {
907
-		return self::$defaultInstance->getOwner($path);
908
-	}
909
-
910
-	/**
911
-	 * get the ETag for a file or folder
912
-	 *
913
-	 * @param string $path
914
-	 * @return string
915
-	 */
916
-	static public function getETag($path) {
917
-		return self::$defaultInstance->getETag($path);
918
-	}
75
+    /**
76
+     * @var Mount\Manager $mounts
77
+     */
78
+    private static $mounts;
79
+
80
+    public static $loaded = false;
81
+    /**
82
+     * @var \OC\Files\View $defaultInstance
83
+     */
84
+    static private $defaultInstance;
85
+
86
+    static private $usersSetup = [];
87
+
88
+    static private $normalizedPathCache = null;
89
+
90
+    static private $listeningForProviders = false;
91
+
92
+    /**
93
+     * classname which used for hooks handling
94
+     * used as signalclass in OC_Hooks::emit()
95
+     */
96
+    const CLASSNAME = 'OC_Filesystem';
97
+
98
+    /**
99
+     * signalname emitted before file renaming
100
+     *
101
+     * @param string $oldpath
102
+     * @param string $newpath
103
+     */
104
+    const signal_rename = 'rename';
105
+
106
+    /**
107
+     * signal emitted after file renaming
108
+     *
109
+     * @param string $oldpath
110
+     * @param string $newpath
111
+     */
112
+    const signal_post_rename = 'post_rename';
113
+
114
+    /**
115
+     * signal emitted before file/dir creation
116
+     *
117
+     * @param string $path
118
+     * @param bool $run changing this flag to false in hook handler will cancel event
119
+     */
120
+    const signal_create = 'create';
121
+
122
+    /**
123
+     * signal emitted after file/dir creation
124
+     *
125
+     * @param string $path
126
+     * @param bool $run changing this flag to false in hook handler will cancel event
127
+     */
128
+    const signal_post_create = 'post_create';
129
+
130
+    /**
131
+     * signal emits before file/dir copy
132
+     *
133
+     * @param string $oldpath
134
+     * @param string $newpath
135
+     * @param bool $run changing this flag to false in hook handler will cancel event
136
+     */
137
+    const signal_copy = 'copy';
138
+
139
+    /**
140
+     * signal emits after file/dir copy
141
+     *
142
+     * @param string $oldpath
143
+     * @param string $newpath
144
+     */
145
+    const signal_post_copy = 'post_copy';
146
+
147
+    /**
148
+     * signal emits before file/dir save
149
+     *
150
+     * @param string $path
151
+     * @param bool $run changing this flag to false in hook handler will cancel event
152
+     */
153
+    const signal_write = 'write';
154
+
155
+    /**
156
+     * signal emits after file/dir save
157
+     *
158
+     * @param string $path
159
+     */
160
+    const signal_post_write = 'post_write';
161
+
162
+    /**
163
+     * signal emitted before file/dir update
164
+     *
165
+     * @param string $path
166
+     * @param bool $run changing this flag to false in hook handler will cancel event
167
+     */
168
+    const signal_update = 'update';
169
+
170
+    /**
171
+     * signal emitted after file/dir update
172
+     *
173
+     * @param string $path
174
+     * @param bool $run changing this flag to false in hook handler will cancel event
175
+     */
176
+    const signal_post_update = 'post_update';
177
+
178
+    /**
179
+     * signal emits when reading file/dir
180
+     *
181
+     * @param string $path
182
+     */
183
+    const signal_read = 'read';
184
+
185
+    /**
186
+     * signal emits when removing file/dir
187
+     *
188
+     * @param string $path
189
+     */
190
+    const signal_delete = 'delete';
191
+
192
+    /**
193
+     * parameters definitions for signals
194
+     */
195
+    const signal_param_path = 'path';
196
+    const signal_param_oldpath = 'oldpath';
197
+    const signal_param_newpath = 'newpath';
198
+
199
+    /**
200
+     * run - changing this flag to false in hook handler will cancel event
201
+     */
202
+    const signal_param_run = 'run';
203
+
204
+    const signal_create_mount = 'create_mount';
205
+    const signal_delete_mount = 'delete_mount';
206
+    const signal_param_mount_type = 'mounttype';
207
+    const signal_param_users = 'users';
208
+
209
+    /**
210
+     * @var \OC\Files\Storage\StorageFactory $loader
211
+     */
212
+    private static $loader;
213
+
214
+    /** @var bool */
215
+    private static $logWarningWhenAddingStorageWrapper = true;
216
+
217
+    /**
218
+     * @param bool $shouldLog
219
+     * @return bool previous value
220
+     * @internal
221
+     */
222
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
223
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
224
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
225
+        return $previousValue;
226
+    }
227
+
228
+    /**
229
+     * @param string $wrapperName
230
+     * @param callable $wrapper
231
+     * @param int $priority
232
+     */
233
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
234
+        if (self::$logWarningWhenAddingStorageWrapper) {
235
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
236
+                'wrapper' => $wrapperName,
237
+                'app' => 'filesystem',
238
+            ]);
239
+        }
240
+
241
+        $mounts = self::getMountManager()->getAll();
242
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
243
+            // do not re-wrap if storage with this name already existed
244
+            return;
245
+        }
246
+    }
247
+
248
+    /**
249
+     * Returns the storage factory
250
+     *
251
+     * @return IStorageFactory
252
+     */
253
+    public static function getLoader() {
254
+        if (!self::$loader) {
255
+            self::$loader = \OC::$server->query(IStorageFactory::class);
256
+        }
257
+        return self::$loader;
258
+    }
259
+
260
+    /**
261
+     * Returns the mount manager
262
+     *
263
+     * @return \OC\Files\Mount\Manager
264
+     */
265
+    public static function getMountManager($user = '') {
266
+        if (!self::$mounts) {
267
+            \OC_Util::setupFS($user);
268
+        }
269
+        return self::$mounts;
270
+    }
271
+
272
+    /**
273
+     * get the mountpoint of the storage object for a path
274
+     * ( note: because a storage is not always mounted inside the fakeroot, the
275
+     * returned mountpoint is relative to the absolute root of the filesystem
276
+     * and doesn't take the chroot into account )
277
+     *
278
+     * @param string $path
279
+     * @return string
280
+     */
281
+    static public function getMountPoint($path) {
282
+        if (!self::$mounts) {
283
+            \OC_Util::setupFS();
284
+        }
285
+        $mount = self::$mounts->find($path);
286
+        if ($mount) {
287
+            return $mount->getMountPoint();
288
+        } else {
289
+            return '';
290
+        }
291
+    }
292
+
293
+    /**
294
+     * get a list of all mount points in a directory
295
+     *
296
+     * @param string $path
297
+     * @return string[]
298
+     */
299
+    static public function getMountPoints($path) {
300
+        if (!self::$mounts) {
301
+            \OC_Util::setupFS();
302
+        }
303
+        $result = [];
304
+        $mounts = self::$mounts->findIn($path);
305
+        foreach ($mounts as $mount) {
306
+            $result[] = $mount->getMountPoint();
307
+        }
308
+        return $result;
309
+    }
310
+
311
+    /**
312
+     * get the storage mounted at $mountPoint
313
+     *
314
+     * @param string $mountPoint
315
+     * @return \OC\Files\Storage\Storage
316
+     */
317
+    public static function getStorage($mountPoint) {
318
+        if (!self::$mounts) {
319
+            \OC_Util::setupFS();
320
+        }
321
+        $mount = self::$mounts->find($mountPoint);
322
+        return $mount->getStorage();
323
+    }
324
+
325
+    /**
326
+     * @param string $id
327
+     * @return Mount\MountPoint[]
328
+     */
329
+    public static function getMountByStorageId($id) {
330
+        if (!self::$mounts) {
331
+            \OC_Util::setupFS();
332
+        }
333
+        return self::$mounts->findByStorageId($id);
334
+    }
335
+
336
+    /**
337
+     * @param int $id
338
+     * @return Mount\MountPoint[]
339
+     */
340
+    public static function getMountByNumericId($id) {
341
+        if (!self::$mounts) {
342
+            \OC_Util::setupFS();
343
+        }
344
+        return self::$mounts->findByNumericId($id);
345
+    }
346
+
347
+    /**
348
+     * resolve a path to a storage and internal path
349
+     *
350
+     * @param string $path
351
+     * @return array an array consisting of the storage and the internal path
352
+     */
353
+    static public function resolvePath($path) {
354
+        if (!self::$mounts) {
355
+            \OC_Util::setupFS();
356
+        }
357
+        $mount = self::$mounts->find($path);
358
+        if ($mount) {
359
+            return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
360
+        } else {
361
+            return [null, null];
362
+        }
363
+    }
364
+
365
+    static public function init($user, $root) {
366
+        if (self::$defaultInstance) {
367
+            return false;
368
+        }
369
+        self::getLoader();
370
+        self::$defaultInstance = new View($root);
371
+
372
+        if (!self::$mounts) {
373
+            self::$mounts = \OC::$server->getMountManager();
374
+        }
375
+
376
+        //load custom mount config
377
+        self::initMountPoints($user);
378
+
379
+        self::$loaded = true;
380
+
381
+        return true;
382
+    }
383
+
384
+    static public function initMountManager() {
385
+        if (!self::$mounts) {
386
+            self::$mounts = \OC::$server->getMountManager();
387
+        }
388
+    }
389
+
390
+    /**
391
+     * Initialize system and personal mount points for a user
392
+     *
393
+     * @param string $user
394
+     * @throws \OC\User\NoUserException if the user is not available
395
+     */
396
+    public static function initMountPoints($user = '') {
397
+        if ($user == '') {
398
+            $user = \OC_User::getUser();
399
+        }
400
+        if ($user === null || $user === false || $user === '') {
401
+            throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
402
+        }
403
+
404
+        if (isset(self::$usersSetup[$user])) {
405
+            return;
406
+        }
407
+
408
+        self::$usersSetup[$user] = true;
409
+
410
+        $userManager = \OC::$server->getUserManager();
411
+        $userObject = $userManager->get($user);
412
+
413
+        if (is_null($userObject)) {
414
+            \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
415
+            // reset flag, this will make it possible to rethrow the exception if called again
416
+            unset(self::$usersSetup[$user]);
417
+            throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
418
+        }
419
+
420
+        $realUid = $userObject->getUID();
421
+        // workaround in case of different casings
422
+        if ($user !== $realUid) {
423
+            $stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
424
+            \OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
425
+            $user = $realUid;
426
+
427
+            // again with the correct casing
428
+            if (isset(self::$usersSetup[$user])) {
429
+                return;
430
+            }
431
+
432
+            self::$usersSetup[$user] = true;
433
+        }
434
+
435
+        if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
436
+            /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
437
+            $mountConfigManager = \OC::$server->getMountProviderCollection();
438
+
439
+            // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
440
+            $homeMount = $mountConfigManager->getHomeMountForUser($userObject);
441
+
442
+            self::getMountManager()->addMount($homeMount);
443
+
444
+            \OC\Files\Filesystem::getStorage($user);
445
+
446
+            // Chance to mount for other storages
447
+            if ($userObject) {
448
+                $mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
449
+                $mounts[] = $homeMount;
450
+                $mountConfigManager->registerMounts($userObject, $mounts);
451
+            }
452
+
453
+            self::listenForNewMountProviders($mountConfigManager, $userManager);
454
+        } else {
455
+            self::getMountManager()->addMount(new MountPoint(
456
+                new NullStorage([]),
457
+                '/' . $user
458
+            ));
459
+            self::getMountManager()->addMount(new MountPoint(
460
+                new NullStorage([]),
461
+                '/' . $user . '/files'
462
+            ));
463
+        }
464
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
465
+    }
466
+
467
+    /**
468
+     * Get mounts from mount providers that are registered after setup
469
+     *
470
+     * @param MountProviderCollection $mountConfigManager
471
+     * @param IUserManager $userManager
472
+     */
473
+    private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
474
+        if (!self::$listeningForProviders) {
475
+            self::$listeningForProviders = true;
476
+            $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
477
+                foreach (Filesystem::$usersSetup as $user => $setup) {
478
+                    $userObject = $userManager->get($user);
479
+                    if ($userObject) {
480
+                        $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
481
+                        array_walk($mounts, [self::$mounts, 'addMount']);
482
+                    }
483
+                }
484
+            });
485
+        }
486
+    }
487
+
488
+    /**
489
+     * get the default filesystem view
490
+     *
491
+     * @return View
492
+     */
493
+    static public function getView() {
494
+        return self::$defaultInstance;
495
+    }
496
+
497
+    /**
498
+     * tear down the filesystem, removing all storage providers
499
+     */
500
+    static public function tearDown() {
501
+        self::clearMounts();
502
+        self::$defaultInstance = null;
503
+    }
504
+
505
+    /**
506
+     * get the relative path of the root data directory for the current user
507
+     *
508
+     * @return string
509
+     *
510
+     * Returns path like /admin/files
511
+     */
512
+    static public function getRoot() {
513
+        if (!self::$defaultInstance) {
514
+            return null;
515
+        }
516
+        return self::$defaultInstance->getRoot();
517
+    }
518
+
519
+    /**
520
+     * clear all mounts and storage backends
521
+     */
522
+    public static function clearMounts() {
523
+        if (self::$mounts) {
524
+            self::$usersSetup = [];
525
+            self::$mounts->clear();
526
+        }
527
+    }
528
+
529
+    /**
530
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
531
+     *
532
+     * @param \OC\Files\Storage\Storage|string $class
533
+     * @param array $arguments
534
+     * @param string $mountpoint
535
+     */
536
+    static public function mount($class, $arguments, $mountpoint) {
537
+        if (!self::$mounts) {
538
+            \OC_Util::setupFS();
539
+        }
540
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
541
+        self::$mounts->addMount($mount);
542
+    }
543
+
544
+    /**
545
+     * return the path to a local version of the file
546
+     * we need this because we can't know if a file is stored local or not from
547
+     * outside the filestorage and for some purposes a local file is needed
548
+     *
549
+     * @param string $path
550
+     * @return string
551
+     */
552
+    static public function getLocalFile($path) {
553
+        return self::$defaultInstance->getLocalFile($path);
554
+    }
555
+
556
+    /**
557
+     * @param string $path
558
+     * @return string
559
+     */
560
+    static public function getLocalFolder($path) {
561
+        return self::$defaultInstance->getLocalFolder($path);
562
+    }
563
+
564
+    /**
565
+     * return path to file which reflects one visible in browser
566
+     *
567
+     * @param string $path
568
+     * @return string
569
+     */
570
+    static public function getLocalPath($path) {
571
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
572
+        $newpath = $path;
573
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
574
+            $newpath = substr($path, strlen($datadir));
575
+        }
576
+        return $newpath;
577
+    }
578
+
579
+    /**
580
+     * check if the requested path is valid
581
+     *
582
+     * @param string $path
583
+     * @return bool
584
+     */
585
+    static public function isValidPath($path) {
586
+        $path = self::normalizePath($path);
587
+        if (!$path || $path[0] !== '/') {
588
+            $path = '/' . $path;
589
+        }
590
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
591
+            return false;
592
+        }
593
+        return true;
594
+    }
595
+
596
+    /**
597
+     * checks if a file is blacklisted for storage in the filesystem
598
+     * Listens to write and rename hooks
599
+     *
600
+     * @param array $data from hook
601
+     */
602
+    static public function isBlacklisted($data) {
603
+        if (isset($data['path'])) {
604
+            $path = $data['path'];
605
+        } else if (isset($data['newpath'])) {
606
+            $path = $data['newpath'];
607
+        }
608
+        if (isset($path)) {
609
+            if (self::isFileBlacklisted($path)) {
610
+                $data['run'] = false;
611
+            }
612
+        }
613
+    }
614
+
615
+    /**
616
+     * @param string $filename
617
+     * @return bool
618
+     */
619
+    static public function isFileBlacklisted($filename) {
620
+        $filename = self::normalizePath($filename);
621
+
622
+        $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
623
+        $filename = strtolower(basename($filename));
624
+        return in_array($filename, $blacklist);
625
+    }
626
+
627
+    /**
628
+     * check if the directory should be ignored when scanning
629
+     * NOTE: the special directories . and .. would cause never ending recursion
630
+     *
631
+     * @param string $dir
632
+     * @return boolean
633
+     */
634
+    static public function isIgnoredDir($dir) {
635
+        if ($dir === '.' || $dir === '..') {
636
+            return true;
637
+        }
638
+        return false;
639
+    }
640
+
641
+    /**
642
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
643
+     */
644
+    static public function mkdir($path) {
645
+        return self::$defaultInstance->mkdir($path);
646
+    }
647
+
648
+    static public function rmdir($path) {
649
+        return self::$defaultInstance->rmdir($path);
650
+    }
651
+
652
+    static public function is_dir($path) {
653
+        return self::$defaultInstance->is_dir($path);
654
+    }
655
+
656
+    static public function is_file($path) {
657
+        return self::$defaultInstance->is_file($path);
658
+    }
659
+
660
+    static public function stat($path) {
661
+        return self::$defaultInstance->stat($path);
662
+    }
663
+
664
+    static public function filetype($path) {
665
+        return self::$defaultInstance->filetype($path);
666
+    }
667
+
668
+    static public function filesize($path) {
669
+        return self::$defaultInstance->filesize($path);
670
+    }
671
+
672
+    static public function readfile($path) {
673
+        return self::$defaultInstance->readfile($path);
674
+    }
675
+
676
+    static public function isCreatable($path) {
677
+        return self::$defaultInstance->isCreatable($path);
678
+    }
679
+
680
+    static public function isReadable($path) {
681
+        return self::$defaultInstance->isReadable($path);
682
+    }
683
+
684
+    static public function isUpdatable($path) {
685
+        return self::$defaultInstance->isUpdatable($path);
686
+    }
687
+
688
+    static public function isDeletable($path) {
689
+        return self::$defaultInstance->isDeletable($path);
690
+    }
691
+
692
+    static public function isSharable($path) {
693
+        return self::$defaultInstance->isSharable($path);
694
+    }
695
+
696
+    static public function file_exists($path) {
697
+        return self::$defaultInstance->file_exists($path);
698
+    }
699
+
700
+    static public function filemtime($path) {
701
+        return self::$defaultInstance->filemtime($path);
702
+    }
703
+
704
+    static public function touch($path, $mtime = null) {
705
+        return self::$defaultInstance->touch($path, $mtime);
706
+    }
707
+
708
+    /**
709
+     * @return string
710
+     */
711
+    static public function file_get_contents($path) {
712
+        return self::$defaultInstance->file_get_contents($path);
713
+    }
714
+
715
+    static public function file_put_contents($path, $data) {
716
+        return self::$defaultInstance->file_put_contents($path, $data);
717
+    }
718
+
719
+    static public function unlink($path) {
720
+        return self::$defaultInstance->unlink($path);
721
+    }
722
+
723
+    static public function rename($path1, $path2) {
724
+        return self::$defaultInstance->rename($path1, $path2);
725
+    }
726
+
727
+    static public function copy($path1, $path2) {
728
+        return self::$defaultInstance->copy($path1, $path2);
729
+    }
730
+
731
+    static public function fopen($path, $mode) {
732
+        return self::$defaultInstance->fopen($path, $mode);
733
+    }
734
+
735
+    /**
736
+     * @return string
737
+     */
738
+    static public function toTmpFile($path) {
739
+        return self::$defaultInstance->toTmpFile($path);
740
+    }
741
+
742
+    static public function fromTmpFile($tmpFile, $path) {
743
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
744
+    }
745
+
746
+    static public function getMimeType($path) {
747
+        return self::$defaultInstance->getMimeType($path);
748
+    }
749
+
750
+    static public function hash($type, $path, $raw = false) {
751
+        return self::$defaultInstance->hash($type, $path, $raw);
752
+    }
753
+
754
+    static public function free_space($path = '/') {
755
+        return self::$defaultInstance->free_space($path);
756
+    }
757
+
758
+    static public function search($query) {
759
+        return self::$defaultInstance->search($query);
760
+    }
761
+
762
+    /**
763
+     * @param string $query
764
+     */
765
+    static public function searchByMime($query) {
766
+        return self::$defaultInstance->searchByMime($query);
767
+    }
768
+
769
+    /**
770
+     * @param string|int $tag name or tag id
771
+     * @param string $userId owner of the tags
772
+     * @return FileInfo[] array or file info
773
+     */
774
+    static public function searchByTag($tag, $userId) {
775
+        return self::$defaultInstance->searchByTag($tag, $userId);
776
+    }
777
+
778
+    /**
779
+     * check if a file or folder has been updated since $time
780
+     *
781
+     * @param string $path
782
+     * @param int $time
783
+     * @return bool
784
+     */
785
+    static public function hasUpdated($path, $time) {
786
+        return self::$defaultInstance->hasUpdated($path, $time);
787
+    }
788
+
789
+    /**
790
+     * Fix common problems with a file path
791
+     *
792
+     * @param string $path
793
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
794
+     * @param bool $isAbsolutePath whether the given path is absolute
795
+     * @param bool $keepUnicode true to disable unicode normalization
796
+     * @return string
797
+     */
798
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
799
+        if (is_null(self::$normalizedPathCache)) {
800
+            self::$normalizedPathCache = new CappedMemoryCache(2048);
801
+        }
802
+
803
+        /**
804
+         * FIXME: This is a workaround for existing classes and files which call
805
+         *        this function with another type than a valid string. This
806
+         *        conversion should get removed as soon as all existing
807
+         *        function calls have been fixed.
808
+         */
809
+        $path = (string)$path;
810
+
811
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
812
+
813
+        if (isset(self::$normalizedPathCache[$cacheKey])) {
814
+            return self::$normalizedPathCache[$cacheKey];
815
+        }
816
+
817
+        if ($path === '') {
818
+            return '/';
819
+        }
820
+
821
+        //normalize unicode if possible
822
+        if (!$keepUnicode) {
823
+            $path = \OC_Util::normalizeUnicode($path);
824
+        }
825
+
826
+        //add leading slash, if it is already there we strip it anyway
827
+        $path = '/' . $path;
828
+
829
+        $patterns = [
830
+            '/\\\\/s',          // no windows style slashes
831
+            '/\/\.(\/\.)?\//s', // remove '/./'
832
+            '/\/{2,}/s',        // remove squence of slashes
833
+            '/\/\.$/s',         // remove trailing /.
834
+        ];
835
+
836
+        do {
837
+            $count = 0;
838
+            $path = preg_replace($patterns, '/', $path, -1, $count);
839
+        } while ($count > 0);
840
+
841
+        //remove trailing slash
842
+        if ($stripTrailingSlash && strlen($path) > 1) {
843
+            $path = rtrim($path, '/');
844
+        }
845
+
846
+        self::$normalizedPathCache[$cacheKey] = $path;
847
+
848
+        return $path;
849
+    }
850
+
851
+    /**
852
+     * get the filesystem info
853
+     *
854
+     * @param string $path
855
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
856
+     * defaults to true
857
+     * @return \OC\Files\FileInfo|bool False if file does not exist
858
+     */
859
+    public static function getFileInfo($path, $includeMountPoints = true) {
860
+        return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
861
+    }
862
+
863
+    /**
864
+     * change file metadata
865
+     *
866
+     * @param string $path
867
+     * @param array $data
868
+     * @return int
869
+     *
870
+     * returns the fileid of the updated file
871
+     */
872
+    public static function putFileInfo($path, $data) {
873
+        return self::$defaultInstance->putFileInfo($path, $data);
874
+    }
875
+
876
+    /**
877
+     * get the content of a directory
878
+     *
879
+     * @param string $directory path under datadirectory
880
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
881
+     * @return \OC\Files\FileInfo[]
882
+     */
883
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
884
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
885
+    }
886
+
887
+    /**
888
+     * Get the path of a file by id
889
+     *
890
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
891
+     *
892
+     * @param int $id
893
+     * @throws NotFoundException
894
+     * @return string
895
+     */
896
+    public static function getPath($id) {
897
+        return self::$defaultInstance->getPath($id);
898
+    }
899
+
900
+    /**
901
+     * Get the owner for a file or folder
902
+     *
903
+     * @param string $path
904
+     * @return string
905
+     */
906
+    public static function getOwner($path) {
907
+        return self::$defaultInstance->getOwner($path);
908
+    }
909
+
910
+    /**
911
+     * get the ETag for a file or folder
912
+     *
913
+     * @param string $path
914
+     * @return string
915
+     */
916
+    static public function getETag($path) {
917
+        return self::$defaultInstance->getETag($path);
918
+    }
919 919
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Updater.php 1 patch
Indentation   +215 added lines, -215 removed lines patch added patch discarded remove patch
@@ -36,219 +36,219 @@
 block discarded – undo
36 36
  *
37 37
  */
38 38
 class Updater implements IUpdater {
39
-	/**
40
-	 * @var bool
41
-	 */
42
-	protected $enabled = true;
43
-
44
-	/**
45
-	 * @var \OC\Files\Storage\Storage
46
-	 */
47
-	protected $storage;
48
-
49
-	/**
50
-	 * @var \OC\Files\Cache\Propagator
51
-	 */
52
-	protected $propagator;
53
-
54
-	/**
55
-	 * @var Scanner
56
-	 */
57
-	protected $scanner;
58
-
59
-	/**
60
-	 * @var Cache
61
-	 */
62
-	protected $cache;
63
-
64
-	/**
65
-	 * @param \OC\Files\Storage\Storage $storage
66
-	 */
67
-	public function __construct(\OC\Files\Storage\Storage $storage) {
68
-		$this->storage = $storage;
69
-		$this->propagator = $storage->getPropagator();
70
-		$this->scanner = $storage->getScanner();
71
-		$this->cache = $storage->getCache();
72
-	}
73
-
74
-	/**
75
-	 * Disable updating the cache trough this updater
76
-	 */
77
-	public function disable() {
78
-		$this->enabled = false;
79
-	}
80
-
81
-	/**
82
-	 * Re-enable the updating of the cache trough this updater
83
-	 */
84
-	public function enable() {
85
-		$this->enabled = true;
86
-	}
87
-
88
-	/**
89
-	 * Get the propagator for etags and mtime for the view the updater works on
90
-	 *
91
-	 * @return Propagator
92
-	 */
93
-	public function getPropagator() {
94
-		return $this->propagator;
95
-	}
96
-
97
-	/**
98
-	 * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem
99
-	 *
100
-	 * @param string $path the path of the file to propagate the changes for
101
-	 * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used
102
-	 */
103
-	public function propagate($path, $time = null) {
104
-		if (Scanner::isPartialFile($path)) {
105
-			return;
106
-		}
107
-		$this->propagator->propagateChange($path, $time);
108
-	}
109
-
110
-	/**
111
-	 * Update the cache for $path and update the size, etag and mtime of the parent folders
112
-	 *
113
-	 * @param string $path
114
-	 * @param int $time
115
-	 */
116
-	public function update($path, $time = null) {
117
-		if (!$this->enabled or Scanner::isPartialFile($path)) {
118
-			return;
119
-		}
120
-		if (is_null($time)) {
121
-			$time = time();
122
-		}
123
-
124
-		$data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false);
125
-		if (
126
-			isset($data['oldSize']) && isset($data['size']) &&
127
-			!$data['encrypted'] // encryption is a pita and touches the cache itself
128
-		) {
129
-			$sizeDifference = $data['size'] - $data['oldSize'];
130
-		} else {
131
-			// scanner didn't provide size info, fallback to full size calculation
132
-			$sizeDifference = 0;
133
-			if ($this->cache instanceof Cache) {
134
-				$this->cache->correctFolderSize($path, $data);
135
-			}
136
-		}
137
-		$this->correctParentStorageMtime($path);
138
-		$this->propagator->propagateChange($path, $time, $sizeDifference);
139
-	}
140
-
141
-	/**
142
-	 * Remove $path from the cache and update the size, etag and mtime of the parent folders
143
-	 *
144
-	 * @param string $path
145
-	 */
146
-	public function remove($path) {
147
-		if (!$this->enabled or Scanner::isPartialFile($path)) {
148
-			return;
149
-		}
150
-
151
-		$parent = dirname($path);
152
-		if ($parent === '.') {
153
-			$parent = '';
154
-		}
155
-
156
-		$entry = $this->cache->get($path);
157
-
158
-		$this->cache->remove($path);
159
-
160
-		$this->correctParentStorageMtime($path);
161
-		if ($entry instanceof ICacheEntry) {
162
-			$this->propagator->propagateChange($path, time(), -$entry->getSize());
163
-		} else {
164
-			$this->propagator->propagateChange($path, time());
165
-			if ($this->cache instanceof Cache) {
166
-				$this->cache->correctFolderSize($parent);
167
-			}
168
-		}
169
-
170
-	}
171
-
172
-	/**
173
-	 * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
174
-	 *
175
-	 * @param IStorage $sourceStorage
176
-	 * @param string $source
177
-	 * @param string $target
178
-	 */
179
-	public function renameFromStorage(IStorage $sourceStorage, $source, $target) {
180
-		if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
181
-			return;
182
-		}
183
-
184
-		$time = time();
185
-
186
-		$sourceCache = $sourceStorage->getCache();
187
-		$sourceUpdater = $sourceStorage->getUpdater();
188
-		$sourcePropagator = $sourceStorage->getPropagator();
189
-
190
-		if ($sourceCache->inCache($source)) {
191
-			if ($this->cache->inCache($target)) {
192
-				$this->cache->remove($target);
193
-			}
194
-
195
-			if ($sourceStorage === $this->storage) {
196
-				$this->cache->move($source, $target);
197
-			} else {
198
-				$this->cache->moveFromCache($sourceCache, $source, $target);
199
-			}
200
-		}
201
-
202
-		if (pathinfo($source, PATHINFO_EXTENSION) !== pathinfo($target, PATHINFO_EXTENSION)) {
203
-			// handle mime type change
204
-			$mimeType = $this->storage->getMimeType($target);
205
-			$fileId = $this->cache->getId($target);
206
-			$this->cache->update($fileId, ['mimetype' => $mimeType]);
207
-		}
208
-
209
-		if ($sourceCache instanceof Cache) {
210
-			$sourceCache->correctFolderSize($source);
211
-		}
212
-		if ($this->cache instanceof Cache) {
213
-			$this->cache->correctFolderSize($target);
214
-		}
215
-		if ($sourceUpdater instanceof Updater) {
216
-			$sourceUpdater->correctParentStorageMtime($source);
217
-		}
218
-		$this->correctParentStorageMtime($target);
219
-		$this->updateStorageMTimeOnly($target);
220
-		$sourcePropagator->propagateChange($source, $time);
221
-		$this->propagator->propagateChange($target, $time);
222
-	}
223
-
224
-	private function updateStorageMTimeOnly($internalPath) {
225
-		$fileId = $this->cache->getId($internalPath);
226
-		if ($fileId !== -1) {
227
-			$mtime = $this->storage->filemtime($internalPath);
228
-			if ($mtime !== false) {
229
-				$this->cache->update(
230
-					$fileId, [
231
-						'mtime' => null, // this magic tells it to not overwrite mtime
232
-						'storage_mtime' => $mtime
233
-					]
234
-				);
235
-			}
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * update the storage_mtime of the direct parent in the cache to the mtime from the storage
241
-	 *
242
-	 * @param string $internalPath
243
-	 */
244
-	private function correctParentStorageMtime($internalPath) {
245
-		$parentId = $this->cache->getParentId($internalPath);
246
-		$parent = dirname($internalPath);
247
-		if ($parentId != -1) {
248
-			$mtime = $this->storage->filemtime($parent);
249
-			if ($mtime !== false) {
250
-				$this->cache->update($parentId, ['storage_mtime' => $mtime]);
251
-			}
252
-		}
253
-	}
39
+    /**
40
+     * @var bool
41
+     */
42
+    protected $enabled = true;
43
+
44
+    /**
45
+     * @var \OC\Files\Storage\Storage
46
+     */
47
+    protected $storage;
48
+
49
+    /**
50
+     * @var \OC\Files\Cache\Propagator
51
+     */
52
+    protected $propagator;
53
+
54
+    /**
55
+     * @var Scanner
56
+     */
57
+    protected $scanner;
58
+
59
+    /**
60
+     * @var Cache
61
+     */
62
+    protected $cache;
63
+
64
+    /**
65
+     * @param \OC\Files\Storage\Storage $storage
66
+     */
67
+    public function __construct(\OC\Files\Storage\Storage $storage) {
68
+        $this->storage = $storage;
69
+        $this->propagator = $storage->getPropagator();
70
+        $this->scanner = $storage->getScanner();
71
+        $this->cache = $storage->getCache();
72
+    }
73
+
74
+    /**
75
+     * Disable updating the cache trough this updater
76
+     */
77
+    public function disable() {
78
+        $this->enabled = false;
79
+    }
80
+
81
+    /**
82
+     * Re-enable the updating of the cache trough this updater
83
+     */
84
+    public function enable() {
85
+        $this->enabled = true;
86
+    }
87
+
88
+    /**
89
+     * Get the propagator for etags and mtime for the view the updater works on
90
+     *
91
+     * @return Propagator
92
+     */
93
+    public function getPropagator() {
94
+        return $this->propagator;
95
+    }
96
+
97
+    /**
98
+     * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem
99
+     *
100
+     * @param string $path the path of the file to propagate the changes for
101
+     * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used
102
+     */
103
+    public function propagate($path, $time = null) {
104
+        if (Scanner::isPartialFile($path)) {
105
+            return;
106
+        }
107
+        $this->propagator->propagateChange($path, $time);
108
+    }
109
+
110
+    /**
111
+     * Update the cache for $path and update the size, etag and mtime of the parent folders
112
+     *
113
+     * @param string $path
114
+     * @param int $time
115
+     */
116
+    public function update($path, $time = null) {
117
+        if (!$this->enabled or Scanner::isPartialFile($path)) {
118
+            return;
119
+        }
120
+        if (is_null($time)) {
121
+            $time = time();
122
+        }
123
+
124
+        $data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false);
125
+        if (
126
+            isset($data['oldSize']) && isset($data['size']) &&
127
+            !$data['encrypted'] // encryption is a pita and touches the cache itself
128
+        ) {
129
+            $sizeDifference = $data['size'] - $data['oldSize'];
130
+        } else {
131
+            // scanner didn't provide size info, fallback to full size calculation
132
+            $sizeDifference = 0;
133
+            if ($this->cache instanceof Cache) {
134
+                $this->cache->correctFolderSize($path, $data);
135
+            }
136
+        }
137
+        $this->correctParentStorageMtime($path);
138
+        $this->propagator->propagateChange($path, $time, $sizeDifference);
139
+    }
140
+
141
+    /**
142
+     * Remove $path from the cache and update the size, etag and mtime of the parent folders
143
+     *
144
+     * @param string $path
145
+     */
146
+    public function remove($path) {
147
+        if (!$this->enabled or Scanner::isPartialFile($path)) {
148
+            return;
149
+        }
150
+
151
+        $parent = dirname($path);
152
+        if ($parent === '.') {
153
+            $parent = '';
154
+        }
155
+
156
+        $entry = $this->cache->get($path);
157
+
158
+        $this->cache->remove($path);
159
+
160
+        $this->correctParentStorageMtime($path);
161
+        if ($entry instanceof ICacheEntry) {
162
+            $this->propagator->propagateChange($path, time(), -$entry->getSize());
163
+        } else {
164
+            $this->propagator->propagateChange($path, time());
165
+            if ($this->cache instanceof Cache) {
166
+                $this->cache->correctFolderSize($parent);
167
+            }
168
+        }
169
+
170
+    }
171
+
172
+    /**
173
+     * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
174
+     *
175
+     * @param IStorage $sourceStorage
176
+     * @param string $source
177
+     * @param string $target
178
+     */
179
+    public function renameFromStorage(IStorage $sourceStorage, $source, $target) {
180
+        if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
181
+            return;
182
+        }
183
+
184
+        $time = time();
185
+
186
+        $sourceCache = $sourceStorage->getCache();
187
+        $sourceUpdater = $sourceStorage->getUpdater();
188
+        $sourcePropagator = $sourceStorage->getPropagator();
189
+
190
+        if ($sourceCache->inCache($source)) {
191
+            if ($this->cache->inCache($target)) {
192
+                $this->cache->remove($target);
193
+            }
194
+
195
+            if ($sourceStorage === $this->storage) {
196
+                $this->cache->move($source, $target);
197
+            } else {
198
+                $this->cache->moveFromCache($sourceCache, $source, $target);
199
+            }
200
+        }
201
+
202
+        if (pathinfo($source, PATHINFO_EXTENSION) !== pathinfo($target, PATHINFO_EXTENSION)) {
203
+            // handle mime type change
204
+            $mimeType = $this->storage->getMimeType($target);
205
+            $fileId = $this->cache->getId($target);
206
+            $this->cache->update($fileId, ['mimetype' => $mimeType]);
207
+        }
208
+
209
+        if ($sourceCache instanceof Cache) {
210
+            $sourceCache->correctFolderSize($source);
211
+        }
212
+        if ($this->cache instanceof Cache) {
213
+            $this->cache->correctFolderSize($target);
214
+        }
215
+        if ($sourceUpdater instanceof Updater) {
216
+            $sourceUpdater->correctParentStorageMtime($source);
217
+        }
218
+        $this->correctParentStorageMtime($target);
219
+        $this->updateStorageMTimeOnly($target);
220
+        $sourcePropagator->propagateChange($source, $time);
221
+        $this->propagator->propagateChange($target, $time);
222
+    }
223
+
224
+    private function updateStorageMTimeOnly($internalPath) {
225
+        $fileId = $this->cache->getId($internalPath);
226
+        if ($fileId !== -1) {
227
+            $mtime = $this->storage->filemtime($internalPath);
228
+            if ($mtime !== false) {
229
+                $this->cache->update(
230
+                    $fileId, [
231
+                        'mtime' => null, // this magic tells it to not overwrite mtime
232
+                        'storage_mtime' => $mtime
233
+                    ]
234
+                );
235
+            }
236
+        }
237
+    }
238
+
239
+    /**
240
+     * update the storage_mtime of the direct parent in the cache to the mtime from the storage
241
+     *
242
+     * @param string $internalPath
243
+     */
244
+    private function correctParentStorageMtime($internalPath) {
245
+        $parentId = $this->cache->getParentId($internalPath);
246
+        $parent = dirname($internalPath);
247
+        if ($parentId != -1) {
248
+            $mtime = $this->storage->filemtime($parent);
249
+            if ($mtime !== false) {
250
+                $this->cache->update($parentId, ['storage_mtime' => $mtime]);
251
+            }
252
+        }
253
+    }
254 254
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Watcher.php 1 patch
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -33,113 +33,113 @@
 block discarded – undo
33 33
  */
34 34
 class Watcher implements IWatcher {
35 35
 
36
-	protected $watchPolicy = self::CHECK_ONCE;
36
+    protected $watchPolicy = self::CHECK_ONCE;
37 37
 
38
-	protected $checkedPaths = [];
38
+    protected $checkedPaths = [];
39 39
 
40
-	/**
41
-	 * @var \OC\Files\Storage\Storage $storage
42
-	 */
43
-	protected $storage;
40
+    /**
41
+     * @var \OC\Files\Storage\Storage $storage
42
+     */
43
+    protected $storage;
44 44
 
45
-	/**
46
-	 * @var Cache $cache
47
-	 */
48
-	protected $cache;
45
+    /**
46
+     * @var Cache $cache
47
+     */
48
+    protected $cache;
49 49
 
50
-	/**
51
-	 * @var Scanner $scanner ;
52
-	 */
53
-	protected $scanner;
50
+    /**
51
+     * @var Scanner $scanner ;
52
+     */
53
+    protected $scanner;
54 54
 
55
-	/**
56
-	 * @param \OC\Files\Storage\Storage $storage
57
-	 */
58
-	public function __construct(\OC\Files\Storage\Storage $storage) {
59
-		$this->storage = $storage;
60
-		$this->cache = $storage->getCache();
61
-		$this->scanner = $storage->getScanner();
62
-	}
55
+    /**
56
+     * @param \OC\Files\Storage\Storage $storage
57
+     */
58
+    public function __construct(\OC\Files\Storage\Storage $storage) {
59
+        $this->storage = $storage;
60
+        $this->cache = $storage->getCache();
61
+        $this->scanner = $storage->getScanner();
62
+    }
63 63
 
64
-	/**
65
-	 * @param int $policy either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS
66
-	 */
67
-	public function setPolicy($policy) {
68
-		$this->watchPolicy = $policy;
69
-	}
64
+    /**
65
+     * @param int $policy either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS
66
+     */
67
+    public function setPolicy($policy) {
68
+        $this->watchPolicy = $policy;
69
+    }
70 70
 
71
-	/**
72
-	 * @return int either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS
73
-	 */
74
-	public function getPolicy() {
75
-		return $this->watchPolicy;
76
-	}
71
+    /**
72
+     * @return int either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS
73
+     */
74
+    public function getPolicy() {
75
+        return $this->watchPolicy;
76
+    }
77 77
 
78
-	/**
79
-	 * check $path for updates and update if needed
80
-	 *
81
-	 * @param string $path
82
-	 * @param ICacheEntry|null $cachedEntry
83
-	 * @return boolean true if path was updated
84
-	 */
85
-	public function checkUpdate($path, $cachedEntry = null) {
86
-		if (is_null($cachedEntry)) {
87
-			$cachedEntry = $this->cache->get($path);
88
-		}
89
-		if ($cachedEntry === false || $this->needsUpdate($path, $cachedEntry)) {
90
-			$this->update($path, $cachedEntry);
91
-			return true;
92
-		} else {
93
-			return false;
94
-		}
95
-	}
78
+    /**
79
+     * check $path for updates and update if needed
80
+     *
81
+     * @param string $path
82
+     * @param ICacheEntry|null $cachedEntry
83
+     * @return boolean true if path was updated
84
+     */
85
+    public function checkUpdate($path, $cachedEntry = null) {
86
+        if (is_null($cachedEntry)) {
87
+            $cachedEntry = $this->cache->get($path);
88
+        }
89
+        if ($cachedEntry === false || $this->needsUpdate($path, $cachedEntry)) {
90
+            $this->update($path, $cachedEntry);
91
+            return true;
92
+        } else {
93
+            return false;
94
+        }
95
+    }
96 96
 
97
-	/**
98
-	 * Update the cache for changes to $path
99
-	 *
100
-	 * @param string $path
101
-	 * @param ICacheEntry $cachedData
102
-	 */
103
-	public function update($path, $cachedData) {
104
-		if ($this->storage->is_dir($path)) {
105
-			$this->scanner->scan($path, Scanner::SCAN_SHALLOW);
106
-		} else {
107
-			$this->scanner->scanFile($path);
108
-		}
109
-		if (is_array($cachedData) && $cachedData['mimetype'] === 'httpd/unix-directory') {
110
-			$this->cleanFolder($path);
111
-		}
112
-		if ($this->cache instanceof Cache) {
113
-			$this->cache->correctFolderSize($path);
114
-		}
115
-	}
97
+    /**
98
+     * Update the cache for changes to $path
99
+     *
100
+     * @param string $path
101
+     * @param ICacheEntry $cachedData
102
+     */
103
+    public function update($path, $cachedData) {
104
+        if ($this->storage->is_dir($path)) {
105
+            $this->scanner->scan($path, Scanner::SCAN_SHALLOW);
106
+        } else {
107
+            $this->scanner->scanFile($path);
108
+        }
109
+        if (is_array($cachedData) && $cachedData['mimetype'] === 'httpd/unix-directory') {
110
+            $this->cleanFolder($path);
111
+        }
112
+        if ($this->cache instanceof Cache) {
113
+            $this->cache->correctFolderSize($path);
114
+        }
115
+    }
116 116
 
117
-	/**
118
-	 * Check if the cache for $path needs to be updated
119
-	 *
120
-	 * @param string $path
121
-	 * @param ICacheEntry $cachedData
122
-	 * @return bool
123
-	 */
124
-	public function needsUpdate($path, $cachedData) {
125
-		if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and array_search($path, $this->checkedPaths) === false)) {
126
-			$this->checkedPaths[] = $path;
127
-			return $this->storage->hasUpdated($path, $cachedData['storage_mtime']);
128
-		}
129
-		return false;
130
-	}
117
+    /**
118
+     * Check if the cache for $path needs to be updated
119
+     *
120
+     * @param string $path
121
+     * @param ICacheEntry $cachedData
122
+     * @return bool
123
+     */
124
+    public function needsUpdate($path, $cachedData) {
125
+        if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and array_search($path, $this->checkedPaths) === false)) {
126
+            $this->checkedPaths[] = $path;
127
+            return $this->storage->hasUpdated($path, $cachedData['storage_mtime']);
128
+        }
129
+        return false;
130
+    }
131 131
 
132
-	/**
133
-	 * remove deleted files in $path from the cache
134
-	 *
135
-	 * @param string $path
136
-	 */
137
-	public function cleanFolder($path) {
138
-		$cachedContent = $this->cache->getFolderContents($path);
139
-		foreach ($cachedContent as $entry) {
140
-			if (!$this->storage->file_exists($entry['path'])) {
141
-				$this->cache->remove($entry['path']);
142
-			}
143
-		}
144
-	}
132
+    /**
133
+     * remove deleted files in $path from the cache
134
+     *
135
+     * @param string $path
136
+     */
137
+    public function cleanFolder($path) {
138
+        $cachedContent = $this->cache->getFolderContents($path);
139
+        foreach ($cachedContent as $entry) {
140
+            if (!$this->storage->file_exists($entry['path'])) {
141
+                $this->cache->remove($entry['path']);
142
+            }
143
+        }
144
+    }
145 145
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Scanner.php 1 patch
Indentation   +500 added lines, -500 removed lines patch added patch discarded remove patch
@@ -54,504 +54,504 @@
 block discarded – undo
54 54
  * @package OC\Files\Cache
55 55
  */
56 56
 class Scanner extends BasicEmitter implements IScanner {
57
-	/**
58
-	 * @var \OC\Files\Storage\Storage $storage
59
-	 */
60
-	protected $storage;
61
-
62
-	/**
63
-	 * @var string $storageId
64
-	 */
65
-	protected $storageId;
66
-
67
-	/**
68
-	 * @var \OC\Files\Cache\Cache $cache
69
-	 */
70
-	protected $cache;
71
-
72
-	/**
73
-	 * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache
74
-	 */
75
-	protected $cacheActive;
76
-
77
-	/**
78
-	 * @var bool $useTransactions whether to use transactions
79
-	 */
80
-	protected $useTransactions = true;
81
-
82
-	/**
83
-	 * @var \OCP\Lock\ILockingProvider
84
-	 */
85
-	protected $lockingProvider;
86
-
87
-	public function __construct(\OC\Files\Storage\Storage $storage) {
88
-		$this->storage = $storage;
89
-		$this->storageId = $this->storage->getId();
90
-		$this->cache = $storage->getCache();
91
-		$this->cacheActive = !\OC::$server->getConfig()->getSystemValue('filesystem_cache_readonly', false);
92
-		$this->lockingProvider = \OC::$server->getLockingProvider();
93
-	}
94
-
95
-	/**
96
-	 * Whether to wrap the scanning of a folder in a database transaction
97
-	 * On default transactions are used
98
-	 *
99
-	 * @param bool $useTransactions
100
-	 */
101
-	public function setUseTransactions($useTransactions) {
102
-		$this->useTransactions = $useTransactions;
103
-	}
104
-
105
-	/**
106
-	 * get all the metadata of a file or folder
107
-	 * *
108
-	 *
109
-	 * @param string $path
110
-	 * @return array an array of metadata of the file
111
-	 */
112
-	protected function getData($path) {
113
-		$data = $this->storage->getMetaData($path);
114
-		if (is_null($data)) {
115
-			\OCP\Util::writeLog(Scanner::class, "!!! Path '$path' is not accessible or present !!!", ILogger::DEBUG);
116
-		}
117
-		return $data;
118
-	}
119
-
120
-	/**
121
-	 * scan a single file and store it in the cache
122
-	 *
123
-	 * @param string $file
124
-	 * @param int $reuseExisting
125
-	 * @param int $parentId
126
-	 * @param array | null $cacheData existing data in the cache for the file to be scanned
127
-	 * @param bool $lock set to false to disable getting an additional read lock during scanning
128
-	 * @return array an array of metadata of the scanned file
129
-	 * @throws \OC\ServerNotAvailableException
130
-	 * @throws \OCP\Lock\LockedException
131
-	 */
132
-	public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
133
-		if ($file !== '') {
134
-			try {
135
-				$this->storage->verifyPath(dirname($file), basename($file));
136
-			} catch (\Exception $e) {
137
-				return null;
138
-			}
139
-		}
140
-		// only proceed if $file is not a partial file nor a blacklisted file
141
-		if (!self::isPartialFile($file) and !Filesystem::isFileBlacklisted($file)) {
142
-
143
-			//acquire a lock
144
-			if ($lock) {
145
-				if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
146
-					$this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
147
-				}
148
-			}
149
-
150
-			try {
151
-				$data = $this->getData($file);
152
-			} catch (ForbiddenException $e) {
153
-				if ($lock) {
154
-					if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
155
-						$this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
156
-					}
157
-				}
158
-
159
-				return null;
160
-			}
161
-
162
-			try {
163
-				if ($data) {
164
-
165
-					// pre-emit only if it was a file. By that we avoid counting/treating folders as files
166
-					if ($data['mimetype'] !== 'httpd/unix-directory') {
167
-						$this->emit('\OC\Files\Cache\Scanner', 'scanFile', [$file, $this->storageId]);
168
-						\OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', ['path' => $file, 'storage' => $this->storageId]);
169
-					}
170
-
171
-					$parent = dirname($file);
172
-					if ($parent === '.' or $parent === '/') {
173
-						$parent = '';
174
-					}
175
-					if ($parentId === -1) {
176
-						$parentId = $this->cache->getParentId($file);
177
-					}
178
-
179
-					// scan the parent if it's not in the cache (id -1) and the current file is not the root folder
180
-					if ($file and $parentId === -1) {
181
-						$parentData = $this->scanFile($parent);
182
-						if (!$parentData) {
183
-							return null;
184
-						}
185
-						$parentId = $parentData['fileid'];
186
-					}
187
-					if ($parent) {
188
-						$data['parent'] = $parentId;
189
-					}
190
-					if (is_null($cacheData)) {
191
-						/** @var CacheEntry $cacheData */
192
-						$cacheData = $this->cache->get($file);
193
-					}
194
-					if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) {
195
-						// prevent empty etag
196
-						if (empty($cacheData['etag'])) {
197
-							$etag = $data['etag'];
198
-						} else {
199
-							$etag = $cacheData['etag'];
200
-						}
201
-						$fileId = $cacheData['fileid'];
202
-						$data['fileid'] = $fileId;
203
-						// only reuse data if the file hasn't explicitly changed
204
-						if (isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']) {
205
-							$data['mtime'] = $cacheData['mtime'];
206
-							if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) {
207
-								$data['size'] = $cacheData['size'];
208
-							}
209
-							if ($reuseExisting & self::REUSE_ETAG) {
210
-								$data['etag'] = $etag;
211
-							}
212
-						}
213
-						// Only update metadata that has changed
214
-						$newData = array_diff_assoc($data, $cacheData->getData());
215
-					} else {
216
-						$newData = $data;
217
-						$fileId = -1;
218
-					}
219
-					if (!empty($newData)) {
220
-						// Reset the checksum if the data has changed
221
-						$newData['checksum'] = '';
222
-						$data['fileid'] = $this->addToCache($file, $newData, $fileId);
223
-					}
224
-					if (isset($cacheData['size'])) {
225
-						$data['oldSize'] = $cacheData['size'];
226
-					} else {
227
-						$data['oldSize'] = 0;
228
-					}
229
-
230
-					if (isset($cacheData['encrypted'])) {
231
-						$data['encrypted'] = $cacheData['encrypted'];
232
-					}
233
-
234
-					// post-emit only if it was a file. By that we avoid counting/treating folders as files
235
-					if ($data['mimetype'] !== 'httpd/unix-directory') {
236
-						$this->emit('\OC\Files\Cache\Scanner', 'postScanFile', [$file, $this->storageId]);
237
-						\OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', ['path' => $file, 'storage' => $this->storageId]);
238
-					}
239
-
240
-				} else {
241
-					$this->removeFromCache($file);
242
-				}
243
-			} catch (\Exception $e) {
244
-				if ($lock) {
245
-					if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
246
-						$this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
247
-					}
248
-				}
249
-				throw $e;
250
-			}
251
-
252
-			//release the acquired lock
253
-			if ($lock) {
254
-				if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
255
-					$this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
256
-				}
257
-			}
258
-
259
-			if ($data && !isset($data['encrypted'])) {
260
-				$data['encrypted'] = false;
261
-			}
262
-			return $data;
263
-		}
264
-
265
-		return null;
266
-	}
267
-
268
-	protected function removeFromCache($path) {
269
-		\OC_Hook::emit('Scanner', 'removeFromCache', ['file' => $path]);
270
-		$this->emit('\OC\Files\Cache\Scanner', 'removeFromCache', [$path]);
271
-		if ($this->cacheActive) {
272
-			$this->cache->remove($path);
273
-		}
274
-	}
275
-
276
-	/**
277
-	 * @param string $path
278
-	 * @param array $data
279
-	 * @param int $fileId
280
-	 * @return int the id of the added file
281
-	 */
282
-	protected function addToCache($path, $data, $fileId = -1) {
283
-		if (isset($data['scan_permissions'])) {
284
-			$data['permissions'] = $data['scan_permissions'];
285
-		}
286
-		\OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]);
287
-		$this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data]);
288
-		if ($this->cacheActive) {
289
-			if ($fileId !== -1) {
290
-				$this->cache->update($fileId, $data);
291
-				return $fileId;
292
-			} else {
293
-				return $this->cache->put($path, $data);
294
-			}
295
-		} else {
296
-			return -1;
297
-		}
298
-	}
299
-
300
-	/**
301
-	 * @param string $path
302
-	 * @param array $data
303
-	 * @param int $fileId
304
-	 */
305
-	protected function updateCache($path, $data, $fileId = -1) {
306
-		\OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]);
307
-		$this->emit('\OC\Files\Cache\Scanner', 'updateCache', [$path, $this->storageId, $data]);
308
-		if ($this->cacheActive) {
309
-			if ($fileId !== -1) {
310
-				$this->cache->update($fileId, $data);
311
-			} else {
312
-				$this->cache->put($path, $data);
313
-			}
314
-		}
315
-	}
316
-
317
-	/**
318
-	 * scan a folder and all it's children
319
-	 *
320
-	 * @param string $path
321
-	 * @param bool $recursive
322
-	 * @param int $reuse
323
-	 * @param bool $lock set to false to disable getting an additional read lock during scanning
324
-	 * @return array an array of the meta data of the scanned file or folder
325
-	 */
326
-	public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) {
327
-		if ($reuse === -1) {
328
-			$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
329
-		}
330
-		if ($lock) {
331
-			if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
332
-				$this->storage->acquireLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider);
333
-				$this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
334
-			}
335
-		}
336
-		try {
337
-			$data = $this->scanFile($path, $reuse, -1, null, $lock);
338
-			if ($data and $data['mimetype'] === 'httpd/unix-directory') {
339
-				$size = $this->scanChildren($path, $recursive, $reuse, $data['fileid'], $lock);
340
-				$data['size'] = $size;
341
-			}
342
-		} finally {
343
-			if ($lock) {
344
-				if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
345
-					$this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
346
-					$this->storage->releaseLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider);
347
-				}
348
-			}
349
-		}
350
-		return $data;
351
-	}
352
-
353
-	/**
354
-	 * Get the children currently in the cache
355
-	 *
356
-	 * @param int $folderId
357
-	 * @return array[]
358
-	 */
359
-	protected function getExistingChildren($folderId) {
360
-		$existingChildren = [];
361
-		$children = $this->cache->getFolderContentsById($folderId);
362
-		foreach ($children as $child) {
363
-			$existingChildren[$child['name']] = $child;
364
-		}
365
-		return $existingChildren;
366
-	}
367
-
368
-	/**
369
-	 * Get the children from the storage
370
-	 *
371
-	 * @param string $folder
372
-	 * @return string[]
373
-	 */
374
-	protected function getNewChildren($folder) {
375
-		$children = [];
376
-		if ($dh = $this->storage->opendir($folder)) {
377
-			if (is_resource($dh)) {
378
-				while (($file = readdir($dh)) !== false) {
379
-					if (!Filesystem::isIgnoredDir($file)) {
380
-						$children[] = trim(\OC\Files\Filesystem::normalizePath($file), '/');
381
-					}
382
-				}
383
-			}
384
-		}
385
-		return $children;
386
-	}
387
-
388
-	/**
389
-	 * scan all the files and folders in a folder
390
-	 *
391
-	 * @param string $path
392
-	 * @param bool $recursive
393
-	 * @param int $reuse
394
-	 * @param int $folderId id for the folder to be scanned
395
-	 * @param bool $lock set to false to disable getting an additional read lock during scanning
396
-	 * @return int the size of the scanned folder or -1 if the size is unknown at this stage
397
-	 */
398
-	protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true) {
399
-		if ($reuse === -1) {
400
-			$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
401
-		}
402
-		$this->emit('\OC\Files\Cache\Scanner', 'scanFolder', [$path, $this->storageId]);
403
-		$size = 0;
404
-		if (!is_null($folderId)) {
405
-			$folderId = $this->cache->getId($path);
406
-		}
407
-		$childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size);
408
-
409
-		foreach ($childQueue as $child => $childId) {
410
-			$childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock);
411
-			if ($childSize === -1) {
412
-				$size = -1;
413
-			} else if ($size !== -1) {
414
-				$size += $childSize;
415
-			}
416
-		}
417
-		if ($this->cacheActive) {
418
-			$this->cache->update($folderId, ['size' => $size]);
419
-		}
420
-		$this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]);
421
-		return $size;
422
-	}
423
-
424
-	private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) {
425
-		// we put this in it's own function so it cleans up the memory before we start recursing
426
-		$existingChildren = $this->getExistingChildren($folderId);
427
-		$newChildren = $this->getNewChildren($path);
428
-
429
-		if ($this->useTransactions) {
430
-			\OC::$server->getDatabaseConnection()->beginTransaction();
431
-		}
432
-
433
-		$exceptionOccurred = false;
434
-		$childQueue = [];
435
-		foreach ($newChildren as $file) {
436
-			$child = $path ? $path . '/' . $file : $file;
437
-			try {
438
-				$existingData = isset($existingChildren[$file]) ? $existingChildren[$file] : null;
439
-				$data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock);
440
-				if ($data) {
441
-					if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE) {
442
-						$childQueue[$child] = $data['fileid'];
443
-					} else if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE_INCOMPLETE and $data['size'] === -1) {
444
-						// only recurse into folders which aren't fully scanned
445
-						$childQueue[$child] = $data['fileid'];
446
-					} else if ($data['size'] === -1) {
447
-						$size = -1;
448
-					} else if ($size !== -1) {
449
-						$size += $data['size'];
450
-					}
451
-				}
452
-			} catch (\Doctrine\DBAL\DBALException $ex) {
453
-				// might happen if inserting duplicate while a scanning
454
-				// process is running in parallel
455
-				// log and ignore
456
-				if ($this->useTransactions) {
457
-					\OC::$server->getDatabaseConnection()->rollback();
458
-					\OC::$server->getDatabaseConnection()->beginTransaction();
459
-				}
460
-				\OC::$server->getLogger()->logException($ex, [
461
-					'message' => 'Exception while scanning file "' . $child . '"',
462
-					'level' => ILogger::DEBUG,
463
-					'app' => 'core',
464
-				]);
465
-				$exceptionOccurred = true;
466
-			} catch (\OCP\Lock\LockedException $e) {
467
-				if ($this->useTransactions) {
468
-					\OC::$server->getDatabaseConnection()->rollback();
469
-				}
470
-				throw $e;
471
-			}
472
-		}
473
-		$removedChildren = \array_diff(array_keys($existingChildren), $newChildren);
474
-		foreach ($removedChildren as $childName) {
475
-			$child = $path ? $path . '/' . $childName : $childName;
476
-			$this->removeFromCache($child);
477
-		}
478
-		if ($this->useTransactions) {
479
-			\OC::$server->getDatabaseConnection()->commit();
480
-		}
481
-		if ($exceptionOccurred) {
482
-			// It might happen that the parallel scan process has already
483
-			// inserted mimetypes but those weren't available yet inside the transaction
484
-			// To make sure to have the updated mime types in such cases,
485
-			// we reload them here
486
-			\OC::$server->getMimeTypeLoader()->reset();
487
-		}
488
-		return $childQueue;
489
-	}
490
-
491
-	/**
492
-	 * check if the file should be ignored when scanning
493
-	 * NOTE: files with a '.part' extension are ignored as well!
494
-	 *       prevents unfinished put requests to be scanned
495
-	 *
496
-	 * @param string $file
497
-	 * @return boolean
498
-	 */
499
-	public static function isPartialFile($file) {
500
-		if (pathinfo($file, PATHINFO_EXTENSION) === 'part') {
501
-			return true;
502
-		}
503
-		if (strpos($file, '.part/') !== false) {
504
-			return true;
505
-		}
506
-
507
-		return false;
508
-	}
509
-
510
-	/**
511
-	 * walk over any folders that are not fully scanned yet and scan them
512
-	 */
513
-	public function backgroundScan() {
514
-		if (!$this->cache->inCache('')) {
515
-			$this->runBackgroundScanJob(function () {
516
-				$this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG);
517
-			}, '');
518
-		} else {
519
-			$lastPath = null;
520
-			while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
521
-				$this->runBackgroundScanJob(function () use ($path) {
522
-					$this->scan($path, self::SCAN_RECURSIVE_INCOMPLETE, self::REUSE_ETAG | self::REUSE_SIZE);
523
-				}, $path);
524
-				// FIXME: this won't proceed with the next item, needs revamping of getIncomplete()
525
-				// to make this possible
526
-				$lastPath = $path;
527
-			}
528
-		}
529
-	}
530
-
531
-	private function runBackgroundScanJob(callable $callback, $path) {
532
-		try {
533
-			$callback();
534
-			\OC_Hook::emit('Scanner', 'correctFolderSize', ['path' => $path]);
535
-			if ($this->cacheActive && $this->cache instanceof Cache) {
536
-				$this->cache->correctFolderSize($path, null, true);
537
-			}
538
-		} catch (\OCP\Files\StorageInvalidException $e) {
539
-			// skip unavailable storages
540
-		} catch (\OCP\Files\StorageNotAvailableException $e) {
541
-			// skip unavailable storages
542
-		} catch (\OCP\Files\ForbiddenException $e) {
543
-			// skip forbidden storages
544
-		} catch (\OCP\Lock\LockedException $e) {
545
-			// skip unavailable storages
546
-		}
547
-	}
548
-
549
-	/**
550
-	 * Set whether the cache is affected by scan operations
551
-	 *
552
-	 * @param boolean $active The active state of the cache
553
-	 */
554
-	public function setCacheActive($active) {
555
-		$this->cacheActive = $active;
556
-	}
57
+    /**
58
+     * @var \OC\Files\Storage\Storage $storage
59
+     */
60
+    protected $storage;
61
+
62
+    /**
63
+     * @var string $storageId
64
+     */
65
+    protected $storageId;
66
+
67
+    /**
68
+     * @var \OC\Files\Cache\Cache $cache
69
+     */
70
+    protected $cache;
71
+
72
+    /**
73
+     * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache
74
+     */
75
+    protected $cacheActive;
76
+
77
+    /**
78
+     * @var bool $useTransactions whether to use transactions
79
+     */
80
+    protected $useTransactions = true;
81
+
82
+    /**
83
+     * @var \OCP\Lock\ILockingProvider
84
+     */
85
+    protected $lockingProvider;
86
+
87
+    public function __construct(\OC\Files\Storage\Storage $storage) {
88
+        $this->storage = $storage;
89
+        $this->storageId = $this->storage->getId();
90
+        $this->cache = $storage->getCache();
91
+        $this->cacheActive = !\OC::$server->getConfig()->getSystemValue('filesystem_cache_readonly', false);
92
+        $this->lockingProvider = \OC::$server->getLockingProvider();
93
+    }
94
+
95
+    /**
96
+     * Whether to wrap the scanning of a folder in a database transaction
97
+     * On default transactions are used
98
+     *
99
+     * @param bool $useTransactions
100
+     */
101
+    public function setUseTransactions($useTransactions) {
102
+        $this->useTransactions = $useTransactions;
103
+    }
104
+
105
+    /**
106
+     * get all the metadata of a file or folder
107
+     * *
108
+     *
109
+     * @param string $path
110
+     * @return array an array of metadata of the file
111
+     */
112
+    protected function getData($path) {
113
+        $data = $this->storage->getMetaData($path);
114
+        if (is_null($data)) {
115
+            \OCP\Util::writeLog(Scanner::class, "!!! Path '$path' is not accessible or present !!!", ILogger::DEBUG);
116
+        }
117
+        return $data;
118
+    }
119
+
120
+    /**
121
+     * scan a single file and store it in the cache
122
+     *
123
+     * @param string $file
124
+     * @param int $reuseExisting
125
+     * @param int $parentId
126
+     * @param array | null $cacheData existing data in the cache for the file to be scanned
127
+     * @param bool $lock set to false to disable getting an additional read lock during scanning
128
+     * @return array an array of metadata of the scanned file
129
+     * @throws \OC\ServerNotAvailableException
130
+     * @throws \OCP\Lock\LockedException
131
+     */
132
+    public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
133
+        if ($file !== '') {
134
+            try {
135
+                $this->storage->verifyPath(dirname($file), basename($file));
136
+            } catch (\Exception $e) {
137
+                return null;
138
+            }
139
+        }
140
+        // only proceed if $file is not a partial file nor a blacklisted file
141
+        if (!self::isPartialFile($file) and !Filesystem::isFileBlacklisted($file)) {
142
+
143
+            //acquire a lock
144
+            if ($lock) {
145
+                if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
146
+                    $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
147
+                }
148
+            }
149
+
150
+            try {
151
+                $data = $this->getData($file);
152
+            } catch (ForbiddenException $e) {
153
+                if ($lock) {
154
+                    if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
155
+                        $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
156
+                    }
157
+                }
158
+
159
+                return null;
160
+            }
161
+
162
+            try {
163
+                if ($data) {
164
+
165
+                    // pre-emit only if it was a file. By that we avoid counting/treating folders as files
166
+                    if ($data['mimetype'] !== 'httpd/unix-directory') {
167
+                        $this->emit('\OC\Files\Cache\Scanner', 'scanFile', [$file, $this->storageId]);
168
+                        \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', ['path' => $file, 'storage' => $this->storageId]);
169
+                    }
170
+
171
+                    $parent = dirname($file);
172
+                    if ($parent === '.' or $parent === '/') {
173
+                        $parent = '';
174
+                    }
175
+                    if ($parentId === -1) {
176
+                        $parentId = $this->cache->getParentId($file);
177
+                    }
178
+
179
+                    // scan the parent if it's not in the cache (id -1) and the current file is not the root folder
180
+                    if ($file and $parentId === -1) {
181
+                        $parentData = $this->scanFile($parent);
182
+                        if (!$parentData) {
183
+                            return null;
184
+                        }
185
+                        $parentId = $parentData['fileid'];
186
+                    }
187
+                    if ($parent) {
188
+                        $data['parent'] = $parentId;
189
+                    }
190
+                    if (is_null($cacheData)) {
191
+                        /** @var CacheEntry $cacheData */
192
+                        $cacheData = $this->cache->get($file);
193
+                    }
194
+                    if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) {
195
+                        // prevent empty etag
196
+                        if (empty($cacheData['etag'])) {
197
+                            $etag = $data['etag'];
198
+                        } else {
199
+                            $etag = $cacheData['etag'];
200
+                        }
201
+                        $fileId = $cacheData['fileid'];
202
+                        $data['fileid'] = $fileId;
203
+                        // only reuse data if the file hasn't explicitly changed
204
+                        if (isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']) {
205
+                            $data['mtime'] = $cacheData['mtime'];
206
+                            if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) {
207
+                                $data['size'] = $cacheData['size'];
208
+                            }
209
+                            if ($reuseExisting & self::REUSE_ETAG) {
210
+                                $data['etag'] = $etag;
211
+                            }
212
+                        }
213
+                        // Only update metadata that has changed
214
+                        $newData = array_diff_assoc($data, $cacheData->getData());
215
+                    } else {
216
+                        $newData = $data;
217
+                        $fileId = -1;
218
+                    }
219
+                    if (!empty($newData)) {
220
+                        // Reset the checksum if the data has changed
221
+                        $newData['checksum'] = '';
222
+                        $data['fileid'] = $this->addToCache($file, $newData, $fileId);
223
+                    }
224
+                    if (isset($cacheData['size'])) {
225
+                        $data['oldSize'] = $cacheData['size'];
226
+                    } else {
227
+                        $data['oldSize'] = 0;
228
+                    }
229
+
230
+                    if (isset($cacheData['encrypted'])) {
231
+                        $data['encrypted'] = $cacheData['encrypted'];
232
+                    }
233
+
234
+                    // post-emit only if it was a file. By that we avoid counting/treating folders as files
235
+                    if ($data['mimetype'] !== 'httpd/unix-directory') {
236
+                        $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', [$file, $this->storageId]);
237
+                        \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', ['path' => $file, 'storage' => $this->storageId]);
238
+                    }
239
+
240
+                } else {
241
+                    $this->removeFromCache($file);
242
+                }
243
+            } catch (\Exception $e) {
244
+                if ($lock) {
245
+                    if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
246
+                        $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
247
+                    }
248
+                }
249
+                throw $e;
250
+            }
251
+
252
+            //release the acquired lock
253
+            if ($lock) {
254
+                if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
255
+                    $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
256
+                }
257
+            }
258
+
259
+            if ($data && !isset($data['encrypted'])) {
260
+                $data['encrypted'] = false;
261
+            }
262
+            return $data;
263
+        }
264
+
265
+        return null;
266
+    }
267
+
268
+    protected function removeFromCache($path) {
269
+        \OC_Hook::emit('Scanner', 'removeFromCache', ['file' => $path]);
270
+        $this->emit('\OC\Files\Cache\Scanner', 'removeFromCache', [$path]);
271
+        if ($this->cacheActive) {
272
+            $this->cache->remove($path);
273
+        }
274
+    }
275
+
276
+    /**
277
+     * @param string $path
278
+     * @param array $data
279
+     * @param int $fileId
280
+     * @return int the id of the added file
281
+     */
282
+    protected function addToCache($path, $data, $fileId = -1) {
283
+        if (isset($data['scan_permissions'])) {
284
+            $data['permissions'] = $data['scan_permissions'];
285
+        }
286
+        \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]);
287
+        $this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data]);
288
+        if ($this->cacheActive) {
289
+            if ($fileId !== -1) {
290
+                $this->cache->update($fileId, $data);
291
+                return $fileId;
292
+            } else {
293
+                return $this->cache->put($path, $data);
294
+            }
295
+        } else {
296
+            return -1;
297
+        }
298
+    }
299
+
300
+    /**
301
+     * @param string $path
302
+     * @param array $data
303
+     * @param int $fileId
304
+     */
305
+    protected function updateCache($path, $data, $fileId = -1) {
306
+        \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]);
307
+        $this->emit('\OC\Files\Cache\Scanner', 'updateCache', [$path, $this->storageId, $data]);
308
+        if ($this->cacheActive) {
309
+            if ($fileId !== -1) {
310
+                $this->cache->update($fileId, $data);
311
+            } else {
312
+                $this->cache->put($path, $data);
313
+            }
314
+        }
315
+    }
316
+
317
+    /**
318
+     * scan a folder and all it's children
319
+     *
320
+     * @param string $path
321
+     * @param bool $recursive
322
+     * @param int $reuse
323
+     * @param bool $lock set to false to disable getting an additional read lock during scanning
324
+     * @return array an array of the meta data of the scanned file or folder
325
+     */
326
+    public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) {
327
+        if ($reuse === -1) {
328
+            $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
329
+        }
330
+        if ($lock) {
331
+            if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
332
+                $this->storage->acquireLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider);
333
+                $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
334
+            }
335
+        }
336
+        try {
337
+            $data = $this->scanFile($path, $reuse, -1, null, $lock);
338
+            if ($data and $data['mimetype'] === 'httpd/unix-directory') {
339
+                $size = $this->scanChildren($path, $recursive, $reuse, $data['fileid'], $lock);
340
+                $data['size'] = $size;
341
+            }
342
+        } finally {
343
+            if ($lock) {
344
+                if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
345
+                    $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider);
346
+                    $this->storage->releaseLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider);
347
+                }
348
+            }
349
+        }
350
+        return $data;
351
+    }
352
+
353
+    /**
354
+     * Get the children currently in the cache
355
+     *
356
+     * @param int $folderId
357
+     * @return array[]
358
+     */
359
+    protected function getExistingChildren($folderId) {
360
+        $existingChildren = [];
361
+        $children = $this->cache->getFolderContentsById($folderId);
362
+        foreach ($children as $child) {
363
+            $existingChildren[$child['name']] = $child;
364
+        }
365
+        return $existingChildren;
366
+    }
367
+
368
+    /**
369
+     * Get the children from the storage
370
+     *
371
+     * @param string $folder
372
+     * @return string[]
373
+     */
374
+    protected function getNewChildren($folder) {
375
+        $children = [];
376
+        if ($dh = $this->storage->opendir($folder)) {
377
+            if (is_resource($dh)) {
378
+                while (($file = readdir($dh)) !== false) {
379
+                    if (!Filesystem::isIgnoredDir($file)) {
380
+                        $children[] = trim(\OC\Files\Filesystem::normalizePath($file), '/');
381
+                    }
382
+                }
383
+            }
384
+        }
385
+        return $children;
386
+    }
387
+
388
+    /**
389
+     * scan all the files and folders in a folder
390
+     *
391
+     * @param string $path
392
+     * @param bool $recursive
393
+     * @param int $reuse
394
+     * @param int $folderId id for the folder to be scanned
395
+     * @param bool $lock set to false to disable getting an additional read lock during scanning
396
+     * @return int the size of the scanned folder or -1 if the size is unknown at this stage
397
+     */
398
+    protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true) {
399
+        if ($reuse === -1) {
400
+            $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
401
+        }
402
+        $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', [$path, $this->storageId]);
403
+        $size = 0;
404
+        if (!is_null($folderId)) {
405
+            $folderId = $this->cache->getId($path);
406
+        }
407
+        $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size);
408
+
409
+        foreach ($childQueue as $child => $childId) {
410
+            $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock);
411
+            if ($childSize === -1) {
412
+                $size = -1;
413
+            } else if ($size !== -1) {
414
+                $size += $childSize;
415
+            }
416
+        }
417
+        if ($this->cacheActive) {
418
+            $this->cache->update($folderId, ['size' => $size]);
419
+        }
420
+        $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]);
421
+        return $size;
422
+    }
423
+
424
+    private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) {
425
+        // we put this in it's own function so it cleans up the memory before we start recursing
426
+        $existingChildren = $this->getExistingChildren($folderId);
427
+        $newChildren = $this->getNewChildren($path);
428
+
429
+        if ($this->useTransactions) {
430
+            \OC::$server->getDatabaseConnection()->beginTransaction();
431
+        }
432
+
433
+        $exceptionOccurred = false;
434
+        $childQueue = [];
435
+        foreach ($newChildren as $file) {
436
+            $child = $path ? $path . '/' . $file : $file;
437
+            try {
438
+                $existingData = isset($existingChildren[$file]) ? $existingChildren[$file] : null;
439
+                $data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock);
440
+                if ($data) {
441
+                    if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE) {
442
+                        $childQueue[$child] = $data['fileid'];
443
+                    } else if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE_INCOMPLETE and $data['size'] === -1) {
444
+                        // only recurse into folders which aren't fully scanned
445
+                        $childQueue[$child] = $data['fileid'];
446
+                    } else if ($data['size'] === -1) {
447
+                        $size = -1;
448
+                    } else if ($size !== -1) {
449
+                        $size += $data['size'];
450
+                    }
451
+                }
452
+            } catch (\Doctrine\DBAL\DBALException $ex) {
453
+                // might happen if inserting duplicate while a scanning
454
+                // process is running in parallel
455
+                // log and ignore
456
+                if ($this->useTransactions) {
457
+                    \OC::$server->getDatabaseConnection()->rollback();
458
+                    \OC::$server->getDatabaseConnection()->beginTransaction();
459
+                }
460
+                \OC::$server->getLogger()->logException($ex, [
461
+                    'message' => 'Exception while scanning file "' . $child . '"',
462
+                    'level' => ILogger::DEBUG,
463
+                    'app' => 'core',
464
+                ]);
465
+                $exceptionOccurred = true;
466
+            } catch (\OCP\Lock\LockedException $e) {
467
+                if ($this->useTransactions) {
468
+                    \OC::$server->getDatabaseConnection()->rollback();
469
+                }
470
+                throw $e;
471
+            }
472
+        }
473
+        $removedChildren = \array_diff(array_keys($existingChildren), $newChildren);
474
+        foreach ($removedChildren as $childName) {
475
+            $child = $path ? $path . '/' . $childName : $childName;
476
+            $this->removeFromCache($child);
477
+        }
478
+        if ($this->useTransactions) {
479
+            \OC::$server->getDatabaseConnection()->commit();
480
+        }
481
+        if ($exceptionOccurred) {
482
+            // It might happen that the parallel scan process has already
483
+            // inserted mimetypes but those weren't available yet inside the transaction
484
+            // To make sure to have the updated mime types in such cases,
485
+            // we reload them here
486
+            \OC::$server->getMimeTypeLoader()->reset();
487
+        }
488
+        return $childQueue;
489
+    }
490
+
491
+    /**
492
+     * check if the file should be ignored when scanning
493
+     * NOTE: files with a '.part' extension are ignored as well!
494
+     *       prevents unfinished put requests to be scanned
495
+     *
496
+     * @param string $file
497
+     * @return boolean
498
+     */
499
+    public static function isPartialFile($file) {
500
+        if (pathinfo($file, PATHINFO_EXTENSION) === 'part') {
501
+            return true;
502
+        }
503
+        if (strpos($file, '.part/') !== false) {
504
+            return true;
505
+        }
506
+
507
+        return false;
508
+    }
509
+
510
+    /**
511
+     * walk over any folders that are not fully scanned yet and scan them
512
+     */
513
+    public function backgroundScan() {
514
+        if (!$this->cache->inCache('')) {
515
+            $this->runBackgroundScanJob(function () {
516
+                $this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG);
517
+            }, '');
518
+        } else {
519
+            $lastPath = null;
520
+            while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
521
+                $this->runBackgroundScanJob(function () use ($path) {
522
+                    $this->scan($path, self::SCAN_RECURSIVE_INCOMPLETE, self::REUSE_ETAG | self::REUSE_SIZE);
523
+                }, $path);
524
+                // FIXME: this won't proceed with the next item, needs revamping of getIncomplete()
525
+                // to make this possible
526
+                $lastPath = $path;
527
+            }
528
+        }
529
+    }
530
+
531
+    private function runBackgroundScanJob(callable $callback, $path) {
532
+        try {
533
+            $callback();
534
+            \OC_Hook::emit('Scanner', 'correctFolderSize', ['path' => $path]);
535
+            if ($this->cacheActive && $this->cache instanceof Cache) {
536
+                $this->cache->correctFolderSize($path, null, true);
537
+            }
538
+        } catch (\OCP\Files\StorageInvalidException $e) {
539
+            // skip unavailable storages
540
+        } catch (\OCP\Files\StorageNotAvailableException $e) {
541
+            // skip unavailable storages
542
+        } catch (\OCP\Files\ForbiddenException $e) {
543
+            // skip forbidden storages
544
+        } catch (\OCP\Lock\LockedException $e) {
545
+            // skip unavailable storages
546
+        }
547
+    }
548
+
549
+    /**
550
+     * Set whether the cache is affected by scan operations
551
+     *
552
+     * @param boolean $active The active state of the cache
553
+     */
554
+    public function setCacheActive($active) {
555
+        $this->cacheActive = $active;
556
+    }
557 557
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Wrapper/CacheJail.php 1 patch
Indentation   +292 added lines, -292 removed lines patch added patch discarded remove patch
@@ -37,296 +37,296 @@
 block discarded – undo
37 37
  * Jail to a subdirectory of the wrapped cache
38 38
  */
39 39
 class CacheJail extends CacheWrapper {
40
-	/**
41
-	 * @var string
42
-	 */
43
-	protected $root;
44
-
45
-	/**
46
-	 * @param \OCP\Files\Cache\ICache $cache
47
-	 * @param string $root
48
-	 */
49
-	public function __construct($cache, $root) {
50
-		parent::__construct($cache);
51
-		$this->root = $root;
52
-	}
53
-
54
-	protected function getRoot() {
55
-		return $this->root;
56
-	}
57
-
58
-	protected function getSourcePath($path) {
59
-		if ($path === '') {
60
-			return $this->getRoot();
61
-		} else {
62
-			return $this->getRoot() . '/' . ltrim($path, '/');
63
-		}
64
-	}
65
-
66
-	/**
67
-	 * @param string $path
68
-	 * @return null|string the jailed path or null if the path is outside the jail
69
-	 */
70
-	protected function getJailedPath($path) {
71
-		if ($this->getRoot() === '') {
72
-			return $path;
73
-		}
74
-		$rootLength = strlen($this->getRoot()) + 1;
75
-		if ($path === $this->getRoot()) {
76
-			return '';
77
-		} else if (substr($path, 0, $rootLength) === $this->getRoot() . '/') {
78
-			return substr($path, $rootLength);
79
-		} else {
80
-			return null;
81
-		}
82
-	}
83
-
84
-	/**
85
-	 * @param ICacheEntry|array $entry
86
-	 * @return array
87
-	 */
88
-	protected function formatCacheEntry($entry) {
89
-		if (isset($entry['path'])) {
90
-			$entry['path'] = $this->getJailedPath($entry['path']);
91
-		}
92
-		return $entry;
93
-	}
94
-
95
-	protected function filterCacheEntry($entry) {
96
-		$rootLength = strlen($this->getRoot()) + 1;
97
-		return $rootLength === 1 || ($entry['path'] === $this->getRoot()) || (substr($entry['path'], 0, $rootLength) === $this->getRoot() . '/');
98
-	}
99
-
100
-	/**
101
-	 * get the stored metadata of a file or folder
102
-	 *
103
-	 * @param string /int $file
104
-	 * @return ICacheEntry|false
105
-	 */
106
-	public function get($file) {
107
-		if (is_string($file) or $file == '') {
108
-			$file = $this->getSourcePath($file);
109
-		}
110
-		return parent::get($file);
111
-	}
112
-
113
-	/**
114
-	 * insert meta data for a new file or folder
115
-	 *
116
-	 * @param string $file
117
-	 * @param array $data
118
-	 *
119
-	 * @return int file id
120
-	 * @throws \RuntimeException
121
-	 */
122
-	public function insert($file, array $data) {
123
-		return $this->getCache()->insert($this->getSourcePath($file), $data);
124
-	}
125
-
126
-	/**
127
-	 * update the metadata in the cache
128
-	 *
129
-	 * @param int $id
130
-	 * @param array $data
131
-	 */
132
-	public function update($id, array $data) {
133
-		$this->getCache()->update($id, $data);
134
-	}
135
-
136
-	/**
137
-	 * get the file id for a file
138
-	 *
139
-	 * @param string $file
140
-	 * @return int
141
-	 */
142
-	public function getId($file) {
143
-		return $this->getCache()->getId($this->getSourcePath($file));
144
-	}
145
-
146
-	/**
147
-	 * get the id of the parent folder of a file
148
-	 *
149
-	 * @param string $file
150
-	 * @return int
151
-	 */
152
-	public function getParentId($file) {
153
-		return $this->getCache()->getParentId($this->getSourcePath($file));
154
-	}
155
-
156
-	/**
157
-	 * check if a file is available in the cache
158
-	 *
159
-	 * @param string $file
160
-	 * @return bool
161
-	 */
162
-	public function inCache($file) {
163
-		return $this->getCache()->inCache($this->getSourcePath($file));
164
-	}
165
-
166
-	/**
167
-	 * remove a file or folder from the cache
168
-	 *
169
-	 * @param string $file
170
-	 */
171
-	public function remove($file) {
172
-		$this->getCache()->remove($this->getSourcePath($file));
173
-	}
174
-
175
-	/**
176
-	 * Move a file or folder in the cache
177
-	 *
178
-	 * @param string $source
179
-	 * @param string $target
180
-	 */
181
-	public function move($source, $target) {
182
-		$this->getCache()->move($this->getSourcePath($source), $this->getSourcePath($target));
183
-	}
184
-
185
-	/**
186
-	 * Get the storage id and path needed for a move
187
-	 *
188
-	 * @param string $path
189
-	 * @return array [$storageId, $internalPath]
190
-	 */
191
-	protected function getMoveInfo($path) {
192
-		return [$this->getNumericStorageId(), $this->getSourcePath($path)];
193
-	}
194
-
195
-	/**
196
-	 * remove all entries for files that are stored on the storage from the cache
197
-	 */
198
-	public function clear() {
199
-		$this->getCache()->remove($this->getRoot());
200
-	}
201
-
202
-	/**
203
-	 * @param string $file
204
-	 *
205
-	 * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
206
-	 */
207
-	public function getStatus($file) {
208
-		return $this->getCache()->getStatus($this->getSourcePath($file));
209
-	}
210
-
211
-	private function formatSearchResults($results) {
212
-		$results = array_filter($results, [$this, 'filterCacheEntry']);
213
-		$results = array_values($results);
214
-		return array_map([$this, 'formatCacheEntry'], $results);
215
-	}
216
-
217
-	/**
218
-	 * search for files matching $pattern
219
-	 *
220
-	 * @param string $pattern
221
-	 * @return array an array of file data
222
-	 */
223
-	public function search($pattern) {
224
-		$results = $this->getCache()->search($pattern);
225
-		return $this->formatSearchResults($results);
226
-	}
227
-
228
-	/**
229
-	 * search for files by mimetype
230
-	 *
231
-	 * @param string $mimetype
232
-	 * @return array
233
-	 */
234
-	public function searchByMime($mimetype) {
235
-		$results = $this->getCache()->searchByMime($mimetype);
236
-		return $this->formatSearchResults($results);
237
-	}
238
-
239
-	public function searchQuery(ISearchQuery $query) {
240
-		$simpleQuery = new SearchQuery($query->getSearchOperation(), 0, 0, $query->getOrder(), $query->getUser());
241
-		$results = $this->getCache()->searchQuery($simpleQuery);
242
-		$results = $this->formatSearchResults($results);
243
-
244
-		$limit = $query->getLimit() === 0 ? null : $query->getLimit();
245
-		$results = array_slice($results, $query->getOffset(), $limit);
246
-
247
-		return $results;
248
-	}
249
-
250
-	/**
251
-	 * update the folder size and the size of all parent folders
252
-	 *
253
-	 * @param string|boolean $path
254
-	 * @param array $data (optional) meta data of the folder
255
-	 */
256
-	public function correctFolderSize($path, $data = null, $isBackgroundSize = false) {
257
-		if ($this->getCache() instanceof Cache) {
258
-			$this->getCache()->correctFolderSize($this->getSourcePath($path), $data, $isBackgroundSize);
259
-		}
260
-	}
261
-
262
-	/**
263
-	 * get the size of a folder and set it in the cache
264
-	 *
265
-	 * @param string $path
266
-	 * @param array $entry (optional) meta data of the folder
267
-	 * @return int
268
-	 */
269
-	public function calculateFolderSize($path, $entry = null) {
270
-		if ($this->getCache() instanceof Cache) {
271
-			return $this->getCache()->calculateFolderSize($this->getSourcePath($path), $entry);
272
-		} else {
273
-			return 0;
274
-		}
275
-
276
-	}
277
-
278
-	/**
279
-	 * get all file ids on the files on the storage
280
-	 *
281
-	 * @return int[]
282
-	 */
283
-	public function getAll() {
284
-		// not supported
285
-		return [];
286
-	}
287
-
288
-	/**
289
-	 * find a folder in the cache which has not been fully scanned
290
-	 *
291
-	 * If multiply incomplete folders are in the cache, the one with the highest id will be returned,
292
-	 * use the one with the highest id gives the best result with the background scanner, since that is most
293
-	 * likely the folder where we stopped scanning previously
294
-	 *
295
-	 * @return string|bool the path of the folder or false when no folder matched
296
-	 */
297
-	public function getIncomplete() {
298
-		// not supported
299
-		return false;
300
-	}
301
-
302
-	/**
303
-	 * get the path of a file on this storage by it's id
304
-	 *
305
-	 * @param int $id
306
-	 * @return string|null
307
-	 */
308
-	public function getPathById($id) {
309
-		$path = $this->getCache()->getPathById($id);
310
-		if ($path === null) {
311
-			return null;
312
-		}
313
-
314
-		return $this->getJailedPath($path);
315
-	}
316
-
317
-	/**
318
-	 * Move a file or folder in the cache
319
-	 *
320
-	 * Note that this should make sure the entries are removed from the source cache
321
-	 *
322
-	 * @param \OCP\Files\Cache\ICache $sourceCache
323
-	 * @param string $sourcePath
324
-	 * @param string $targetPath
325
-	 */
326
-	public function moveFromCache(\OCP\Files\Cache\ICache $sourceCache, $sourcePath, $targetPath) {
327
-		if ($sourceCache === $this) {
328
-			return $this->move($sourcePath, $targetPath);
329
-		}
330
-		return $this->getCache()->moveFromCache($sourceCache, $sourcePath, $this->getSourcePath($targetPath));
331
-	}
40
+    /**
41
+     * @var string
42
+     */
43
+    protected $root;
44
+
45
+    /**
46
+     * @param \OCP\Files\Cache\ICache $cache
47
+     * @param string $root
48
+     */
49
+    public function __construct($cache, $root) {
50
+        parent::__construct($cache);
51
+        $this->root = $root;
52
+    }
53
+
54
+    protected function getRoot() {
55
+        return $this->root;
56
+    }
57
+
58
+    protected function getSourcePath($path) {
59
+        if ($path === '') {
60
+            return $this->getRoot();
61
+        } else {
62
+            return $this->getRoot() . '/' . ltrim($path, '/');
63
+        }
64
+    }
65
+
66
+    /**
67
+     * @param string $path
68
+     * @return null|string the jailed path or null if the path is outside the jail
69
+     */
70
+    protected function getJailedPath($path) {
71
+        if ($this->getRoot() === '') {
72
+            return $path;
73
+        }
74
+        $rootLength = strlen($this->getRoot()) + 1;
75
+        if ($path === $this->getRoot()) {
76
+            return '';
77
+        } else if (substr($path, 0, $rootLength) === $this->getRoot() . '/') {
78
+            return substr($path, $rootLength);
79
+        } else {
80
+            return null;
81
+        }
82
+    }
83
+
84
+    /**
85
+     * @param ICacheEntry|array $entry
86
+     * @return array
87
+     */
88
+    protected function formatCacheEntry($entry) {
89
+        if (isset($entry['path'])) {
90
+            $entry['path'] = $this->getJailedPath($entry['path']);
91
+        }
92
+        return $entry;
93
+    }
94
+
95
+    protected function filterCacheEntry($entry) {
96
+        $rootLength = strlen($this->getRoot()) + 1;
97
+        return $rootLength === 1 || ($entry['path'] === $this->getRoot()) || (substr($entry['path'], 0, $rootLength) === $this->getRoot() . '/');
98
+    }
99
+
100
+    /**
101
+     * get the stored metadata of a file or folder
102
+     *
103
+     * @param string /int $file
104
+     * @return ICacheEntry|false
105
+     */
106
+    public function get($file) {
107
+        if (is_string($file) or $file == '') {
108
+            $file = $this->getSourcePath($file);
109
+        }
110
+        return parent::get($file);
111
+    }
112
+
113
+    /**
114
+     * insert meta data for a new file or folder
115
+     *
116
+     * @param string $file
117
+     * @param array $data
118
+     *
119
+     * @return int file id
120
+     * @throws \RuntimeException
121
+     */
122
+    public function insert($file, array $data) {
123
+        return $this->getCache()->insert($this->getSourcePath($file), $data);
124
+    }
125
+
126
+    /**
127
+     * update the metadata in the cache
128
+     *
129
+     * @param int $id
130
+     * @param array $data
131
+     */
132
+    public function update($id, array $data) {
133
+        $this->getCache()->update($id, $data);
134
+    }
135
+
136
+    /**
137
+     * get the file id for a file
138
+     *
139
+     * @param string $file
140
+     * @return int
141
+     */
142
+    public function getId($file) {
143
+        return $this->getCache()->getId($this->getSourcePath($file));
144
+    }
145
+
146
+    /**
147
+     * get the id of the parent folder of a file
148
+     *
149
+     * @param string $file
150
+     * @return int
151
+     */
152
+    public function getParentId($file) {
153
+        return $this->getCache()->getParentId($this->getSourcePath($file));
154
+    }
155
+
156
+    /**
157
+     * check if a file is available in the cache
158
+     *
159
+     * @param string $file
160
+     * @return bool
161
+     */
162
+    public function inCache($file) {
163
+        return $this->getCache()->inCache($this->getSourcePath($file));
164
+    }
165
+
166
+    /**
167
+     * remove a file or folder from the cache
168
+     *
169
+     * @param string $file
170
+     */
171
+    public function remove($file) {
172
+        $this->getCache()->remove($this->getSourcePath($file));
173
+    }
174
+
175
+    /**
176
+     * Move a file or folder in the cache
177
+     *
178
+     * @param string $source
179
+     * @param string $target
180
+     */
181
+    public function move($source, $target) {
182
+        $this->getCache()->move($this->getSourcePath($source), $this->getSourcePath($target));
183
+    }
184
+
185
+    /**
186
+     * Get the storage id and path needed for a move
187
+     *
188
+     * @param string $path
189
+     * @return array [$storageId, $internalPath]
190
+     */
191
+    protected function getMoveInfo($path) {
192
+        return [$this->getNumericStorageId(), $this->getSourcePath($path)];
193
+    }
194
+
195
+    /**
196
+     * remove all entries for files that are stored on the storage from the cache
197
+     */
198
+    public function clear() {
199
+        $this->getCache()->remove($this->getRoot());
200
+    }
201
+
202
+    /**
203
+     * @param string $file
204
+     *
205
+     * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
206
+     */
207
+    public function getStatus($file) {
208
+        return $this->getCache()->getStatus($this->getSourcePath($file));
209
+    }
210
+
211
+    private function formatSearchResults($results) {
212
+        $results = array_filter($results, [$this, 'filterCacheEntry']);
213
+        $results = array_values($results);
214
+        return array_map([$this, 'formatCacheEntry'], $results);
215
+    }
216
+
217
+    /**
218
+     * search for files matching $pattern
219
+     *
220
+     * @param string $pattern
221
+     * @return array an array of file data
222
+     */
223
+    public function search($pattern) {
224
+        $results = $this->getCache()->search($pattern);
225
+        return $this->formatSearchResults($results);
226
+    }
227
+
228
+    /**
229
+     * search for files by mimetype
230
+     *
231
+     * @param string $mimetype
232
+     * @return array
233
+     */
234
+    public function searchByMime($mimetype) {
235
+        $results = $this->getCache()->searchByMime($mimetype);
236
+        return $this->formatSearchResults($results);
237
+    }
238
+
239
+    public function searchQuery(ISearchQuery $query) {
240
+        $simpleQuery = new SearchQuery($query->getSearchOperation(), 0, 0, $query->getOrder(), $query->getUser());
241
+        $results = $this->getCache()->searchQuery($simpleQuery);
242
+        $results = $this->formatSearchResults($results);
243
+
244
+        $limit = $query->getLimit() === 0 ? null : $query->getLimit();
245
+        $results = array_slice($results, $query->getOffset(), $limit);
246
+
247
+        return $results;
248
+    }
249
+
250
+    /**
251
+     * update the folder size and the size of all parent folders
252
+     *
253
+     * @param string|boolean $path
254
+     * @param array $data (optional) meta data of the folder
255
+     */
256
+    public function correctFolderSize($path, $data = null, $isBackgroundSize = false) {
257
+        if ($this->getCache() instanceof Cache) {
258
+            $this->getCache()->correctFolderSize($this->getSourcePath($path), $data, $isBackgroundSize);
259
+        }
260
+    }
261
+
262
+    /**
263
+     * get the size of a folder and set it in the cache
264
+     *
265
+     * @param string $path
266
+     * @param array $entry (optional) meta data of the folder
267
+     * @return int
268
+     */
269
+    public function calculateFolderSize($path, $entry = null) {
270
+        if ($this->getCache() instanceof Cache) {
271
+            return $this->getCache()->calculateFolderSize($this->getSourcePath($path), $entry);
272
+        } else {
273
+            return 0;
274
+        }
275
+
276
+    }
277
+
278
+    /**
279
+     * get all file ids on the files on the storage
280
+     *
281
+     * @return int[]
282
+     */
283
+    public function getAll() {
284
+        // not supported
285
+        return [];
286
+    }
287
+
288
+    /**
289
+     * find a folder in the cache which has not been fully scanned
290
+     *
291
+     * If multiply incomplete folders are in the cache, the one with the highest id will be returned,
292
+     * use the one with the highest id gives the best result with the background scanner, since that is most
293
+     * likely the folder where we stopped scanning previously
294
+     *
295
+     * @return string|bool the path of the folder or false when no folder matched
296
+     */
297
+    public function getIncomplete() {
298
+        // not supported
299
+        return false;
300
+    }
301
+
302
+    /**
303
+     * get the path of a file on this storage by it's id
304
+     *
305
+     * @param int $id
306
+     * @return string|null
307
+     */
308
+    public function getPathById($id) {
309
+        $path = $this->getCache()->getPathById($id);
310
+        if ($path === null) {
311
+            return null;
312
+        }
313
+
314
+        return $this->getJailedPath($path);
315
+    }
316
+
317
+    /**
318
+     * Move a file or folder in the cache
319
+     *
320
+     * Note that this should make sure the entries are removed from the source cache
321
+     *
322
+     * @param \OCP\Files\Cache\ICache $sourceCache
323
+     * @param string $sourcePath
324
+     * @param string $targetPath
325
+     */
326
+    public function moveFromCache(\OCP\Files\Cache\ICache $sourceCache, $sourcePath, $targetPath) {
327
+        if ($sourceCache === $this) {
328
+            return $this->move($sourcePath, $targetPath);
329
+        }
330
+        return $this->getCache()->moveFromCache($sourceCache, $sourcePath, $this->getSourcePath($targetPath));
331
+    }
332 332
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Wrapper/CacheWrapper.php 1 patch
Indentation   +258 added lines, -258 removed lines patch added patch discarded remove patch
@@ -35,290 +35,290 @@
 block discarded – undo
35 35
 use OCP\Files\Search\ISearchQuery;
36 36
 
37 37
 class CacheWrapper extends Cache {
38
-	/**
39
-	 * @var \OCP\Files\Cache\ICache
40
-	 */
41
-	protected $cache;
38
+    /**
39
+     * @var \OCP\Files\Cache\ICache
40
+     */
41
+    protected $cache;
42 42
 
43
-	/**
44
-	 * @param \OCP\Files\Cache\ICache $cache
45
-	 */
46
-	public function __construct($cache) {
47
-		$this->cache = $cache;
48
-	}
43
+    /**
44
+     * @param \OCP\Files\Cache\ICache $cache
45
+     */
46
+    public function __construct($cache) {
47
+        $this->cache = $cache;
48
+    }
49 49
 
50
-	protected function getCache() {
51
-		return $this->cache;
52
-	}
50
+    protected function getCache() {
51
+        return $this->cache;
52
+    }
53 53
 
54
-	/**
55
-	 * Make it easy for wrappers to modify every returned cache entry
56
-	 *
57
-	 * @param ICacheEntry $entry
58
-	 * @return ICacheEntry
59
-	 */
60
-	protected function formatCacheEntry($entry) {
61
-		return $entry;
62
-	}
54
+    /**
55
+     * Make it easy for wrappers to modify every returned cache entry
56
+     *
57
+     * @param ICacheEntry $entry
58
+     * @return ICacheEntry
59
+     */
60
+    protected function formatCacheEntry($entry) {
61
+        return $entry;
62
+    }
63 63
 
64
-	/**
65
-	 * get the stored metadata of a file or folder
66
-	 *
67
-	 * @param string|int $file
68
-	 * @return ICacheEntry|false
69
-	 */
70
-	public function get($file) {
71
-		$result = $this->getCache()->get($file);
72
-		if ($result) {
73
-			$result = $this->formatCacheEntry($result);
74
-		}
75
-		return $result;
76
-	}
64
+    /**
65
+     * get the stored metadata of a file or folder
66
+     *
67
+     * @param string|int $file
68
+     * @return ICacheEntry|false
69
+     */
70
+    public function get($file) {
71
+        $result = $this->getCache()->get($file);
72
+        if ($result) {
73
+            $result = $this->formatCacheEntry($result);
74
+        }
75
+        return $result;
76
+    }
77 77
 
78
-	/**
79
-	 * get the metadata of all files stored in $folder
80
-	 *
81
-	 * @param string $folder
82
-	 * @return ICacheEntry[]
83
-	 */
84
-	public function getFolderContents($folder) {
85
-		// can't do a simple $this->getCache()->.... call here since getFolderContentsById needs to be called on this
86
-		// and not the wrapped cache
87
-		$fileId = $this->getId($folder);
88
-		return $this->getFolderContentsById($fileId);
89
-	}
78
+    /**
79
+     * get the metadata of all files stored in $folder
80
+     *
81
+     * @param string $folder
82
+     * @return ICacheEntry[]
83
+     */
84
+    public function getFolderContents($folder) {
85
+        // can't do a simple $this->getCache()->.... call here since getFolderContentsById needs to be called on this
86
+        // and not the wrapped cache
87
+        $fileId = $this->getId($folder);
88
+        return $this->getFolderContentsById($fileId);
89
+    }
90 90
 
91
-	/**
92
-	 * get the metadata of all files stored in $folder
93
-	 *
94
-	 * @param int $fileId the file id of the folder
95
-	 * @return array
96
-	 */
97
-	public function getFolderContentsById($fileId) {
98
-		$results = $this->getCache()->getFolderContentsById($fileId);
99
-		return array_map([$this, 'formatCacheEntry'], $results);
100
-	}
91
+    /**
92
+     * get the metadata of all files stored in $folder
93
+     *
94
+     * @param int $fileId the file id of the folder
95
+     * @return array
96
+     */
97
+    public function getFolderContentsById($fileId) {
98
+        $results = $this->getCache()->getFolderContentsById($fileId);
99
+        return array_map([$this, 'formatCacheEntry'], $results);
100
+    }
101 101
 
102
-	/**
103
-	 * insert or update meta data for a file or folder
104
-	 *
105
-	 * @param string $file
106
-	 * @param array $data
107
-	 *
108
-	 * @return int file id
109
-	 * @throws \RuntimeException
110
-	 */
111
-	public function put($file, array $data) {
112
-		if (($id = $this->getId($file)) > -1) {
113
-			$this->update($id, $data);
114
-			return $id;
115
-		} else {
116
-			return $this->insert($file, $data);
117
-		}
118
-	}
102
+    /**
103
+     * insert or update meta data for a file or folder
104
+     *
105
+     * @param string $file
106
+     * @param array $data
107
+     *
108
+     * @return int file id
109
+     * @throws \RuntimeException
110
+     */
111
+    public function put($file, array $data) {
112
+        if (($id = $this->getId($file)) > -1) {
113
+            $this->update($id, $data);
114
+            return $id;
115
+        } else {
116
+            return $this->insert($file, $data);
117
+        }
118
+    }
119 119
 
120
-	/**
121
-	 * insert meta data for a new file or folder
122
-	 *
123
-	 * @param string $file
124
-	 * @param array $data
125
-	 *
126
-	 * @return int file id
127
-	 * @throws \RuntimeException
128
-	 */
129
-	public function insert($file, array $data) {
130
-		return $this->getCache()->insert($file, $data);
131
-	}
120
+    /**
121
+     * insert meta data for a new file or folder
122
+     *
123
+     * @param string $file
124
+     * @param array $data
125
+     *
126
+     * @return int file id
127
+     * @throws \RuntimeException
128
+     */
129
+    public function insert($file, array $data) {
130
+        return $this->getCache()->insert($file, $data);
131
+    }
132 132
 
133
-	/**
134
-	 * update the metadata in the cache
135
-	 *
136
-	 * @param int $id
137
-	 * @param array $data
138
-	 */
139
-	public function update($id, array $data) {
140
-		$this->getCache()->update($id, $data);
141
-	}
133
+    /**
134
+     * update the metadata in the cache
135
+     *
136
+     * @param int $id
137
+     * @param array $data
138
+     */
139
+    public function update($id, array $data) {
140
+        $this->getCache()->update($id, $data);
141
+    }
142 142
 
143
-	/**
144
-	 * get the file id for a file
145
-	 *
146
-	 * @param string $file
147
-	 * @return int
148
-	 */
149
-	public function getId($file) {
150
-		return $this->getCache()->getId($file);
151
-	}
143
+    /**
144
+     * get the file id for a file
145
+     *
146
+     * @param string $file
147
+     * @return int
148
+     */
149
+    public function getId($file) {
150
+        return $this->getCache()->getId($file);
151
+    }
152 152
 
153
-	/**
154
-	 * get the id of the parent folder of a file
155
-	 *
156
-	 * @param string $file
157
-	 * @return int
158
-	 */
159
-	public function getParentId($file) {
160
-		return $this->getCache()->getParentId($file);
161
-	}
153
+    /**
154
+     * get the id of the parent folder of a file
155
+     *
156
+     * @param string $file
157
+     * @return int
158
+     */
159
+    public function getParentId($file) {
160
+        return $this->getCache()->getParentId($file);
161
+    }
162 162
 
163
-	/**
164
-	 * check if a file is available in the cache
165
-	 *
166
-	 * @param string $file
167
-	 * @return bool
168
-	 */
169
-	public function inCache($file) {
170
-		return $this->getCache()->inCache($file);
171
-	}
163
+    /**
164
+     * check if a file is available in the cache
165
+     *
166
+     * @param string $file
167
+     * @return bool
168
+     */
169
+    public function inCache($file) {
170
+        return $this->getCache()->inCache($file);
171
+    }
172 172
 
173
-	/**
174
-	 * remove a file or folder from the cache
175
-	 *
176
-	 * @param string $file
177
-	 */
178
-	public function remove($file) {
179
-		$this->getCache()->remove($file);
180
-	}
173
+    /**
174
+     * remove a file or folder from the cache
175
+     *
176
+     * @param string $file
177
+     */
178
+    public function remove($file) {
179
+        $this->getCache()->remove($file);
180
+    }
181 181
 
182
-	/**
183
-	 * Move a file or folder in the cache
184
-	 *
185
-	 * @param string $source
186
-	 * @param string $target
187
-	 */
188
-	public function move($source, $target) {
189
-		$this->getCache()->move($source, $target);
190
-	}
182
+    /**
183
+     * Move a file or folder in the cache
184
+     *
185
+     * @param string $source
186
+     * @param string $target
187
+     */
188
+    public function move($source, $target) {
189
+        $this->getCache()->move($source, $target);
190
+    }
191 191
 
192
-	protected function getMoveInfo($path) {
193
-		/** @var Cache $cache */
194
-		$cache = $this->getCache();
195
-		return $cache->getMoveInfo($path);
196
-	}
192
+    protected function getMoveInfo($path) {
193
+        /** @var Cache $cache */
194
+        $cache = $this->getCache();
195
+        return $cache->getMoveInfo($path);
196
+    }
197 197
 
198
-	public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
199
-		$this->getCache()->moveFromCache($sourceCache, $sourcePath, $targetPath);
200
-	}
198
+    public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
199
+        $this->getCache()->moveFromCache($sourceCache, $sourcePath, $targetPath);
200
+    }
201 201
 
202
-	/**
203
-	 * remove all entries for files that are stored on the storage from the cache
204
-	 */
205
-	public function clear() {
206
-		$this->getCache()->clear();
207
-	}
202
+    /**
203
+     * remove all entries for files that are stored on the storage from the cache
204
+     */
205
+    public function clear() {
206
+        $this->getCache()->clear();
207
+    }
208 208
 
209
-	/**
210
-	 * @param string $file
211
-	 *
212
-	 * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
213
-	 */
214
-	public function getStatus($file) {
215
-		return $this->getCache()->getStatus($file);
216
-	}
209
+    /**
210
+     * @param string $file
211
+     *
212
+     * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
213
+     */
214
+    public function getStatus($file) {
215
+        return $this->getCache()->getStatus($file);
216
+    }
217 217
 
218
-	/**
219
-	 * search for files matching $pattern
220
-	 *
221
-	 * @param string $pattern
222
-	 * @return ICacheEntry[] an array of file data
223
-	 */
224
-	public function search($pattern) {
225
-		$results = $this->getCache()->search($pattern);
226
-		return array_map([$this, 'formatCacheEntry'], $results);
227
-	}
218
+    /**
219
+     * search for files matching $pattern
220
+     *
221
+     * @param string $pattern
222
+     * @return ICacheEntry[] an array of file data
223
+     */
224
+    public function search($pattern) {
225
+        $results = $this->getCache()->search($pattern);
226
+        return array_map([$this, 'formatCacheEntry'], $results);
227
+    }
228 228
 
229
-	/**
230
-	 * search for files by mimetype
231
-	 *
232
-	 * @param string $mimetype
233
-	 * @return ICacheEntry[]
234
-	 */
235
-	public function searchByMime($mimetype) {
236
-		$results = $this->getCache()->searchByMime($mimetype);
237
-		return array_map([$this, 'formatCacheEntry'], $results);
238
-	}
229
+    /**
230
+     * search for files by mimetype
231
+     *
232
+     * @param string $mimetype
233
+     * @return ICacheEntry[]
234
+     */
235
+    public function searchByMime($mimetype) {
236
+        $results = $this->getCache()->searchByMime($mimetype);
237
+        return array_map([$this, 'formatCacheEntry'], $results);
238
+    }
239 239
 
240
-	public function searchQuery(ISearchQuery $query) {
241
-		$results = $this->getCache()->searchQuery($query);
242
-		return array_map([$this, 'formatCacheEntry'], $results);
243
-	}
240
+    public function searchQuery(ISearchQuery $query) {
241
+        $results = $this->getCache()->searchQuery($query);
242
+        return array_map([$this, 'formatCacheEntry'], $results);
243
+    }
244 244
 
245
-	/**
246
-	 * update the folder size and the size of all parent folders
247
-	 *
248
-	 * @param string|boolean $path
249
-	 * @param array $data (optional) meta data of the folder
250
-	 */
251
-	public function correctFolderSize($path, $data = null, $isBackgroundScan = false) {
252
-		if ($this->getCache() instanceof Cache) {
253
-			$this->getCache()->correctFolderSize($path, $data, $isBackgroundScan);
254
-		}
255
-	}
245
+    /**
246
+     * update the folder size and the size of all parent folders
247
+     *
248
+     * @param string|boolean $path
249
+     * @param array $data (optional) meta data of the folder
250
+     */
251
+    public function correctFolderSize($path, $data = null, $isBackgroundScan = false) {
252
+        if ($this->getCache() instanceof Cache) {
253
+            $this->getCache()->correctFolderSize($path, $data, $isBackgroundScan);
254
+        }
255
+    }
256 256
 
257
-	/**
258
-	 * get the size of a folder and set it in the cache
259
-	 *
260
-	 * @param string $path
261
-	 * @param array $entry (optional) meta data of the folder
262
-	 * @return int
263
-	 */
264
-	public function calculateFolderSize($path, $entry = null) {
265
-		if ($this->getCache() instanceof Cache) {
266
-			return $this->getCache()->calculateFolderSize($path, $entry);
267
-		} else {
268
-			return 0;
269
-		}
270
-	}
257
+    /**
258
+     * get the size of a folder and set it in the cache
259
+     *
260
+     * @param string $path
261
+     * @param array $entry (optional) meta data of the folder
262
+     * @return int
263
+     */
264
+    public function calculateFolderSize($path, $entry = null) {
265
+        if ($this->getCache() instanceof Cache) {
266
+            return $this->getCache()->calculateFolderSize($path, $entry);
267
+        } else {
268
+            return 0;
269
+        }
270
+    }
271 271
 
272
-	/**
273
-	 * get all file ids on the files on the storage
274
-	 *
275
-	 * @return int[]
276
-	 */
277
-	public function getAll() {
278
-		return $this->getCache()->getAll();
279
-	}
272
+    /**
273
+     * get all file ids on the files on the storage
274
+     *
275
+     * @return int[]
276
+     */
277
+    public function getAll() {
278
+        return $this->getCache()->getAll();
279
+    }
280 280
 
281
-	/**
282
-	 * find a folder in the cache which has not been fully scanned
283
-	 *
284
-	 * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
285
-	 * use the one with the highest id gives the best result with the background scanner, since that is most
286
-	 * likely the folder where we stopped scanning previously
287
-	 *
288
-	 * @return string|bool the path of the folder or false when no folder matched
289
-	 */
290
-	public function getIncomplete() {
291
-		return $this->getCache()->getIncomplete();
292
-	}
281
+    /**
282
+     * find a folder in the cache which has not been fully scanned
283
+     *
284
+     * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
285
+     * use the one with the highest id gives the best result with the background scanner, since that is most
286
+     * likely the folder where we stopped scanning previously
287
+     *
288
+     * @return string|bool the path of the folder or false when no folder matched
289
+     */
290
+    public function getIncomplete() {
291
+        return $this->getCache()->getIncomplete();
292
+    }
293 293
 
294
-	/**
295
-	 * get the path of a file on this storage by it's id
296
-	 *
297
-	 * @param int $id
298
-	 * @return string|null
299
-	 */
300
-	public function getPathById($id) {
301
-		return $this->getCache()->getPathById($id);
302
-	}
294
+    /**
295
+     * get the path of a file on this storage by it's id
296
+     *
297
+     * @param int $id
298
+     * @return string|null
299
+     */
300
+    public function getPathById($id) {
301
+        return $this->getCache()->getPathById($id);
302
+    }
303 303
 
304
-	/**
305
-	 * Returns the numeric storage id
306
-	 *
307
-	 * @return int
308
-	 */
309
-	public function getNumericStorageId() {
310
-		return $this->getCache()->getNumericStorageId();
311
-	}
304
+    /**
305
+     * Returns the numeric storage id
306
+     *
307
+     * @return int
308
+     */
309
+    public function getNumericStorageId() {
310
+        return $this->getCache()->getNumericStorageId();
311
+    }
312 312
 
313
-	/**
314
-	 * get the storage id of the storage for a file and the internal path of the file
315
-	 * unlike getPathById this does not limit the search to files on this storage and
316
-	 * instead does a global search in the cache table
317
-	 *
318
-	 * @param int $id
319
-	 * @return array first element holding the storage id, second the path
320
-	 */
321
-	static public function getById($id) {
322
-		return parent::getById($id);
323
-	}
313
+    /**
314
+     * get the storage id of the storage for a file and the internal path of the file
315
+     * unlike getPathById this does not limit the search to files on this storage and
316
+     * instead does a global search in the cache table
317
+     *
318
+     * @param int $id
319
+     * @return array first element holding the storage id, second the path
320
+     */
321
+    static public function getById($id) {
322
+        return parent::getById($id);
323
+    }
324 324
 }
Please login to merge, or discard this patch.
lib/private/Files/Cache/Storage.php 1 patch
Indentation   +158 added lines, -158 removed lines patch added patch discarded remove patch
@@ -43,162 +43,162 @@
 block discarded – undo
43 43
  * @package OC\Files\Cache
44 44
  */
45 45
 class Storage {
46
-	/** @var StorageGlobal|null */
47
-	private static $globalCache = null;
48
-	private $storageId;
49
-	private $numericId;
50
-
51
-	/**
52
-	 * @return StorageGlobal
53
-	 */
54
-	public static function getGlobalCache() {
55
-		if (is_null(self::$globalCache)) {
56
-			self::$globalCache = new StorageGlobal(\OC::$server->getDatabaseConnection());
57
-		}
58
-		return self::$globalCache;
59
-	}
60
-
61
-	/**
62
-	 * @param \OC\Files\Storage\Storage|string $storage
63
-	 * @param bool $isAvailable
64
-	 * @throws \RuntimeException
65
-	 */
66
-	public function __construct($storage, $isAvailable = true) {
67
-		if ($storage instanceof IStorage) {
68
-			$this->storageId = $storage->getId();
69
-		} else {
70
-			$this->storageId = $storage;
71
-		}
72
-		$this->storageId = self::adjustStorageId($this->storageId);
73
-
74
-		if ($row = self::getStorageById($this->storageId)) {
75
-			$this->numericId = (int)$row['numeric_id'];
76
-		} else {
77
-			$connection = \OC::$server->getDatabaseConnection();
78
-			$available = $isAvailable ? 1 : 0;
79
-			if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) {
80
-				$this->numericId = (int)$connection->lastInsertId('*PREFIX*storages');
81
-			} else {
82
-				if ($row = self::getStorageById($this->storageId)) {
83
-					$this->numericId = (int)$row['numeric_id'];
84
-				} else {
85
-					throw new \RuntimeException('Storage could neither be inserted nor be selected from the database: ' . $this->storageId);
86
-				}
87
-			}
88
-		}
89
-	}
90
-
91
-	/**
92
-	 * @param string $storageId
93
-	 * @return array
94
-	 */
95
-	public static function getStorageById($storageId) {
96
-		return self::getGlobalCache()->getStorageInfo($storageId);
97
-	}
98
-
99
-	/**
100
-	 * Adjusts the storage id to use md5 if too long
101
-	 * @param string $storageId storage id
102
-	 * @return string unchanged $storageId if its length is less than 64 characters,
103
-	 * else returns the md5 of $storageId
104
-	 */
105
-	public static function adjustStorageId($storageId) {
106
-		if (strlen($storageId) > 64) {
107
-			return md5($storageId);
108
-		}
109
-		return $storageId;
110
-	}
111
-
112
-	/**
113
-	 * Get the numeric id for the storage
114
-	 *
115
-	 * @return int
116
-	 */
117
-	public function getNumericId() {
118
-		return $this->numericId;
119
-	}
120
-
121
-	/**
122
-	 * Get the string id for the storage
123
-	 *
124
-	 * @param int $numericId
125
-	 * @return string|null either the storage id string or null if the numeric id is not known
126
-	 */
127
-	public static function getStorageId($numericId) {
128
-
129
-		$sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?';
130
-		$result = \OC_DB::executeAudited($sql, [$numericId]);
131
-		if ($row = $result->fetchRow()) {
132
-			return $row['id'];
133
-		} else {
134
-			return null;
135
-		}
136
-	}
137
-
138
-	/**
139
-	 * Get the numeric of the storage with the provided string id
140
-	 *
141
-	 * @param $storageId
142
-	 * @return int|null either the numeric storage id or null if the storage id is not knwon
143
-	 */
144
-	public static function getNumericStorageId($storageId) {
145
-		$storageId = self::adjustStorageId($storageId);
146
-
147
-		if ($row = self::getStorageById($storageId)) {
148
-			return (int)$row['numeric_id'];
149
-		} else {
150
-			return null;
151
-		}
152
-	}
153
-
154
-	/**
155
-	 * @return array|null [ available, last_checked ]
156
-	 */
157
-	public function getAvailability() {
158
-		if ($row = self::getStorageById($this->storageId)) {
159
-			return [
160
-				'available' => (int)$row['available'] === 1,
161
-				'last_checked' => $row['last_checked']
162
-			];
163
-		} else {
164
-			return null;
165
-		}
166
-	}
167
-
168
-	/**
169
-	 * @param bool $isAvailable
170
-	 * @param int $delay amount of seconds to delay reconsidering that storage further
171
-	 */
172
-	public function setAvailability($isAvailable, int $delay = 0) {
173
-		$sql = 'UPDATE `*PREFIX*storages` SET `available` = ?, `last_checked` = ? WHERE `id` = ?';
174
-		$available = $isAvailable ? 1 : 0;
175
-		\OC_DB::executeAudited($sql, [$available, time() + $delay, $this->storageId]);
176
-	}
177
-
178
-	/**
179
-	 * Check if a string storage id is known
180
-	 *
181
-	 * @param string $storageId
182
-	 * @return bool
183
-	 */
184
-	public static function exists($storageId) {
185
-		return !is_null(self::getNumericStorageId($storageId));
186
-	}
187
-
188
-	/**
189
-	 * remove the entry for the storage
190
-	 *
191
-	 * @param string $storageId
192
-	 */
193
-	public static function remove($storageId) {
194
-		$storageId = self::adjustStorageId($storageId);
195
-		$numericId = self::getNumericStorageId($storageId);
196
-		$sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
197
-		\OC_DB::executeAudited($sql, [$storageId]);
198
-
199
-		if (!is_null($numericId)) {
200
-			$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
201
-			\OC_DB::executeAudited($sql, [$numericId]);
202
-		}
203
-	}
46
+    /** @var StorageGlobal|null */
47
+    private static $globalCache = null;
48
+    private $storageId;
49
+    private $numericId;
50
+
51
+    /**
52
+     * @return StorageGlobal
53
+     */
54
+    public static function getGlobalCache() {
55
+        if (is_null(self::$globalCache)) {
56
+            self::$globalCache = new StorageGlobal(\OC::$server->getDatabaseConnection());
57
+        }
58
+        return self::$globalCache;
59
+    }
60
+
61
+    /**
62
+     * @param \OC\Files\Storage\Storage|string $storage
63
+     * @param bool $isAvailable
64
+     * @throws \RuntimeException
65
+     */
66
+    public function __construct($storage, $isAvailable = true) {
67
+        if ($storage instanceof IStorage) {
68
+            $this->storageId = $storage->getId();
69
+        } else {
70
+            $this->storageId = $storage;
71
+        }
72
+        $this->storageId = self::adjustStorageId($this->storageId);
73
+
74
+        if ($row = self::getStorageById($this->storageId)) {
75
+            $this->numericId = (int)$row['numeric_id'];
76
+        } else {
77
+            $connection = \OC::$server->getDatabaseConnection();
78
+            $available = $isAvailable ? 1 : 0;
79
+            if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) {
80
+                $this->numericId = (int)$connection->lastInsertId('*PREFIX*storages');
81
+            } else {
82
+                if ($row = self::getStorageById($this->storageId)) {
83
+                    $this->numericId = (int)$row['numeric_id'];
84
+                } else {
85
+                    throw new \RuntimeException('Storage could neither be inserted nor be selected from the database: ' . $this->storageId);
86
+                }
87
+            }
88
+        }
89
+    }
90
+
91
+    /**
92
+     * @param string $storageId
93
+     * @return array
94
+     */
95
+    public static function getStorageById($storageId) {
96
+        return self::getGlobalCache()->getStorageInfo($storageId);
97
+    }
98
+
99
+    /**
100
+     * Adjusts the storage id to use md5 if too long
101
+     * @param string $storageId storage id
102
+     * @return string unchanged $storageId if its length is less than 64 characters,
103
+     * else returns the md5 of $storageId
104
+     */
105
+    public static function adjustStorageId($storageId) {
106
+        if (strlen($storageId) > 64) {
107
+            return md5($storageId);
108
+        }
109
+        return $storageId;
110
+    }
111
+
112
+    /**
113
+     * Get the numeric id for the storage
114
+     *
115
+     * @return int
116
+     */
117
+    public function getNumericId() {
118
+        return $this->numericId;
119
+    }
120
+
121
+    /**
122
+     * Get the string id for the storage
123
+     *
124
+     * @param int $numericId
125
+     * @return string|null either the storage id string or null if the numeric id is not known
126
+     */
127
+    public static function getStorageId($numericId) {
128
+
129
+        $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?';
130
+        $result = \OC_DB::executeAudited($sql, [$numericId]);
131
+        if ($row = $result->fetchRow()) {
132
+            return $row['id'];
133
+        } else {
134
+            return null;
135
+        }
136
+    }
137
+
138
+    /**
139
+     * Get the numeric of the storage with the provided string id
140
+     *
141
+     * @param $storageId
142
+     * @return int|null either the numeric storage id or null if the storage id is not knwon
143
+     */
144
+    public static function getNumericStorageId($storageId) {
145
+        $storageId = self::adjustStorageId($storageId);
146
+
147
+        if ($row = self::getStorageById($storageId)) {
148
+            return (int)$row['numeric_id'];
149
+        } else {
150
+            return null;
151
+        }
152
+    }
153
+
154
+    /**
155
+     * @return array|null [ available, last_checked ]
156
+     */
157
+    public function getAvailability() {
158
+        if ($row = self::getStorageById($this->storageId)) {
159
+            return [
160
+                'available' => (int)$row['available'] === 1,
161
+                'last_checked' => $row['last_checked']
162
+            ];
163
+        } else {
164
+            return null;
165
+        }
166
+    }
167
+
168
+    /**
169
+     * @param bool $isAvailable
170
+     * @param int $delay amount of seconds to delay reconsidering that storage further
171
+     */
172
+    public function setAvailability($isAvailable, int $delay = 0) {
173
+        $sql = 'UPDATE `*PREFIX*storages` SET `available` = ?, `last_checked` = ? WHERE `id` = ?';
174
+        $available = $isAvailable ? 1 : 0;
175
+        \OC_DB::executeAudited($sql, [$available, time() + $delay, $this->storageId]);
176
+    }
177
+
178
+    /**
179
+     * Check if a string storage id is known
180
+     *
181
+     * @param string $storageId
182
+     * @return bool
183
+     */
184
+    public static function exists($storageId) {
185
+        return !is_null(self::getNumericStorageId($storageId));
186
+    }
187
+
188
+    /**
189
+     * remove the entry for the storage
190
+     *
191
+     * @param string $storageId
192
+     */
193
+    public static function remove($storageId) {
194
+        $storageId = self::adjustStorageId($storageId);
195
+        $numericId = self::getNumericStorageId($storageId);
196
+        $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
197
+        \OC_DB::executeAudited($sql, [$storageId]);
198
+
199
+        if (!is_null($numericId)) {
200
+            $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
201
+            \OC_DB::executeAudited($sql, [$numericId]);
202
+        }
203
+    }
204 204
 }
Please login to merge, or discard this patch.