Passed
Push — master ( a5c558...5094e2 )
by Julius
13:28 queued 12s
created
lib/public/Files/Storage.php 1 patch
Indentation   +413 added lines, -413 removed lines patch added patch discarded remove patch
@@ -51,417 +51,417 @@
 block discarded – undo
51 51
  * @deprecated 9.0.0 use \OCP\Files\Storage\IStorage instead
52 52
  */
53 53
 interface Storage extends IStorage {
54
-	/**
55
-	 * $parameters is a free form array with the configuration options needed to construct the storage
56
-	 *
57
-	 * @param array $parameters
58
-	 * @since 6.0.0
59
-	 */
60
-	public function __construct($parameters);
61
-
62
-	/**
63
-	 * Get the identifier for the storage,
64
-	 * the returned id should be the same for every storage object that is created with the same parameters
65
-	 * and two storage objects with the same id should refer to two storages that display the same files.
66
-	 *
67
-	 * @return string
68
-	 * @since 6.0.0
69
-	 */
70
-	public function getId();
71
-
72
-	/**
73
-	 * see http://php.net/manual/en/function.mkdir.php
74
-	 * implementations need to implement a recursive mkdir
75
-	 *
76
-	 * @param string $path
77
-	 * @return bool
78
-	 * @since 6.0.0
79
-	 */
80
-	public function mkdir($path);
81
-
82
-	/**
83
-	 * see http://php.net/manual/en/function.rmdir.php
84
-	 *
85
-	 * @param string $path
86
-	 * @return bool
87
-	 * @since 6.0.0
88
-	 */
89
-	public function rmdir($path);
90
-
91
-	/**
92
-	 * see http://php.net/manual/en/function.opendir.php
93
-	 *
94
-	 * @param string $path
95
-	 * @return resource|false
96
-	 * @since 6.0.0
97
-	 */
98
-	public function opendir($path);
99
-
100
-	/**
101
-	 * see http://php.net/manual/en/function.is-dir.php
102
-	 *
103
-	 * @param string $path
104
-	 * @return bool
105
-	 * @since 6.0.0
106
-	 */
107
-	public function is_dir($path);
108
-
109
-	/**
110
-	 * see http://php.net/manual/en/function.is-file.php
111
-	 *
112
-	 * @param string $path
113
-	 * @return bool
114
-	 * @since 6.0.0
115
-	 */
116
-	public function is_file($path);
117
-
118
-	/**
119
-	 * see http://php.net/manual/en/function.stat.php
120
-	 * only the following keys are required in the result: size and mtime
121
-	 *
122
-	 * @param string $path
123
-	 * @return array|false
124
-	 * @since 6.0.0
125
-	 */
126
-	public function stat($path);
127
-
128
-	/**
129
-	 * see http://php.net/manual/en/function.filetype.php
130
-	 *
131
-	 * @param string $path
132
-	 * @return string|false
133
-	 * @since 6.0.0
134
-	 */
135
-	public function filetype($path);
136
-
137
-	/**
138
-	 * see http://php.net/manual/en/function.filesize.php
139
-	 * The result for filesize when called on a folder is required to be 0
140
-	 *
141
-	 * @param string $path
142
-	 * @return int|false
143
-	 * @since 6.0.0
144
-	 */
145
-	public function filesize($path);
146
-
147
-	/**
148
-	 * check if a file can be created in $path
149
-	 *
150
-	 * @param string $path
151
-	 * @return bool
152
-	 * @since 6.0.0
153
-	 */
154
-	public function isCreatable($path);
155
-
156
-	/**
157
-	 * check if a file can be read
158
-	 *
159
-	 * @param string $path
160
-	 * @return bool
161
-	 * @since 6.0.0
162
-	 */
163
-	public function isReadable($path);
164
-
165
-	/**
166
-	 * check if a file can be written to
167
-	 *
168
-	 * @param string $path
169
-	 * @return bool
170
-	 * @since 6.0.0
171
-	 */
172
-	public function isUpdatable($path);
173
-
174
-	/**
175
-	 * check if a file can be deleted
176
-	 *
177
-	 * @param string $path
178
-	 * @return bool
179
-	 * @since 6.0.0
180
-	 */
181
-	public function isDeletable($path);
182
-
183
-	/**
184
-	 * check if a file can be shared
185
-	 *
186
-	 * @param string $path
187
-	 * @return bool
188
-	 * @since 6.0.0
189
-	 */
190
-	public function isSharable($path);
191
-
192
-	/**
193
-	 * get the full permissions of a path.
194
-	 * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
195
-	 *
196
-	 * @param string $path
197
-	 * @return int
198
-	 * @since 6.0.0
199
-	 */
200
-	public function getPermissions($path);
201
-
202
-	/**
203
-	 * see http://php.net/manual/en/function.file_exists.php
204
-	 *
205
-	 * @param string $path
206
-	 * @return bool
207
-	 * @since 6.0.0
208
-	 */
209
-	public function file_exists($path);
210
-
211
-	/**
212
-	 * see http://php.net/manual/en/function.filemtime.php
213
-	 *
214
-	 * @param string $path
215
-	 * @return int|false
216
-	 * @since 6.0.0
217
-	 */
218
-	public function filemtime($path);
219
-
220
-	/**
221
-	 * see http://php.net/manual/en/function.file_get_contents.php
222
-	 *
223
-	 * @param string $path
224
-	 * @return string|false
225
-	 * @since 6.0.0
226
-	 */
227
-	public function file_get_contents($path);
228
-
229
-	/**
230
-	 * see http://php.net/manual/en/function.file_put_contents.php
231
-	 *
232
-	 * @param string $path
233
-	 * @param mixed $data
234
-	 * @return int|false
235
-	 * @since 6.0.0
236
-	 */
237
-	public function file_put_contents($path, $data);
238
-
239
-	/**
240
-	 * see http://php.net/manual/en/function.unlink.php
241
-	 *
242
-	 * @param string $path
243
-	 * @return bool
244
-	 * @since 6.0.0
245
-	 */
246
-	public function unlink($path);
247
-
248
-	/**
249
-	 * see http://php.net/manual/en/function.rename.php
250
-	 *
251
-	 * @param string $path1
252
-	 * @param string $path2
253
-	 * @return bool
254
-	 * @since 6.0.0
255
-	 */
256
-	public function rename($path1, $path2);
257
-
258
-	/**
259
-	 * see http://php.net/manual/en/function.copy.php
260
-	 *
261
-	 * @param string $path1
262
-	 * @param string $path2
263
-	 * @return bool
264
-	 * @since 6.0.0
265
-	 */
266
-	public function copy($path1, $path2);
267
-
268
-	/**
269
-	 * see http://php.net/manual/en/function.fopen.php
270
-	 *
271
-	 * @param string $path
272
-	 * @param string $mode
273
-	 * @return resource|false
274
-	 * @since 6.0.0
275
-	 */
276
-	public function fopen($path, $mode);
277
-
278
-	/**
279
-	 * get the mimetype for a file or folder
280
-	 * The mimetype for a folder is required to be "httpd/unix-directory"
281
-	 *
282
-	 * @param string $path
283
-	 * @return string|false
284
-	 * @since 6.0.0
285
-	 */
286
-	public function getMimeType($path);
287
-
288
-	/**
289
-	 * see http://php.net/manual/en/function.hash-file.php
290
-	 *
291
-	 * @param string $type
292
-	 * @param string $path
293
-	 * @param bool $raw
294
-	 * @return string|false
295
-	 * @since 6.0.0
296
-	 */
297
-	public function hash($type, $path, $raw = false);
298
-
299
-	/**
300
-	 * see http://php.net/manual/en/function.free_space.php
301
-	 *
302
-	 * @param string $path
303
-	 * @return int|false
304
-	 * @since 6.0.0
305
-	 */
306
-	public function free_space($path);
307
-
308
-	/**
309
-	 * search for occurrences of $query in file names
310
-	 *
311
-	 * @param string $query
312
-	 * @return array|false
313
-	 * @since 6.0.0
314
-	 */
315
-	public function search($query);
316
-
317
-	/**
318
-	 * see http://php.net/manual/en/function.touch.php
319
-	 * If the backend does not support the operation, false should be returned
320
-	 *
321
-	 * @param string $path
322
-	 * @param int $mtime
323
-	 * @return bool
324
-	 * @since 6.0.0
325
-	 */
326
-	public function touch($path, $mtime = null);
327
-
328
-	/**
329
-	 * get the path to a local version of the file.
330
-	 * The local version of the file can be temporary and doesn't have to be persistent across requests
331
-	 *
332
-	 * @param string $path
333
-	 * @return string|false
334
-	 * @since 6.0.0
335
-	 */
336
-	public function getLocalFile($path);
337
-
338
-	/**
339
-	 * check if a file or folder has been updated since $time
340
-	 *
341
-	 * @param string $path
342
-	 * @param int $time
343
-	 * @return bool
344
-	 * @since 6.0.0
345
-	 *
346
-	 * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
347
-	 * returning true for other changes in the folder is optional
348
-	 */
349
-	public function hasUpdated($path, $time);
350
-
351
-	/**
352
-	 * get the ETag for a file or folder
353
-	 *
354
-	 * @param string $path
355
-	 * @return string|false
356
-	 * @since 6.0.0
357
-	 */
358
-	public function getETag($path);
359
-
360
-	/**
361
-	 * Returns whether the storage is local, which means that files
362
-	 * are stored on the local filesystem instead of remotely.
363
-	 * Calling getLocalFile() for local storages should always
364
-	 * return the local files, whereas for non-local storages
365
-	 * it might return a temporary file.
366
-	 *
367
-	 * @return bool true if the files are stored locally, false otherwise
368
-	 * @since 7.0.0
369
-	 */
370
-	public function isLocal();
371
-
372
-	/**
373
-	 * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
374
-	 *
375
-	 * @param string $class
376
-	 * @return bool
377
-	 * @since 7.0.0
378
-	 */
379
-	public function instanceOfStorage($class);
380
-
381
-	/**
382
-	 * A custom storage implementation can return an url for direct download of a give file.
383
-	 *
384
-	 * For now the returned array can hold the parameter url - in future more attributes might follow.
385
-	 *
386
-	 * @param string $path
387
-	 * @return array|false
388
-	 * @since 8.0.0
389
-	 */
390
-	public function getDirectDownload($path);
391
-
392
-	/**
393
-	 * @param string $path the path of the target folder
394
-	 * @param string $fileName the name of the file itself
395
-	 * @return void
396
-	 * @throws InvalidPathException
397
-	 * @since 8.1.0
398
-	 */
399
-	public function verifyPath($path, $fileName);
400
-
401
-	/**
402
-	 * @param IStorage $sourceStorage
403
-	 * @param string $sourceInternalPath
404
-	 * @param string $targetInternalPath
405
-	 * @return bool
406
-	 * @since 8.1.0
407
-	 */
408
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
409
-
410
-	/**
411
-	 * @param IStorage $sourceStorage
412
-	 * @param string $sourceInternalPath
413
-	 * @param string $targetInternalPath
414
-	 * @return bool
415
-	 * @since 8.1.0
416
-	 */
417
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
418
-
419
-	/**
420
-	 * @param string $path The path of the file to acquire the lock for
421
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
422
-	 * @param \OCP\Lock\ILockingProvider $provider
423
-	 * @throws \OCP\Lock\LockedException
424
-	 * @since 8.1.0
425
-	 */
426
-	public function acquireLock($path, $type, ILockingProvider $provider);
427
-
428
-	/**
429
-	 * @param string $path The path of the file to acquire the lock for
430
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
431
-	 * @param \OCP\Lock\ILockingProvider $provider
432
-	 * @throws \OCP\Lock\LockedException
433
-	 * @since 8.1.0
434
-	 */
435
-	public function releaseLock($path, $type, ILockingProvider $provider);
436
-
437
-	/**
438
-	 * @param string $path The path of the file to change the lock for
439
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
440
-	 * @param \OCP\Lock\ILockingProvider $provider
441
-	 * @throws \OCP\Lock\LockedException
442
-	 * @since 8.1.0
443
-	 */
444
-	public function changeLock($path, $type, ILockingProvider $provider);
445
-
446
-	/**
447
-	 * Test a storage for availability
448
-	 *
449
-	 * @since 8.2.0
450
-	 * @return bool
451
-	 */
452
-	public function test();
453
-
454
-	/**
455
-	 * @since 8.2.0
456
-	 * @return array [ available, last_checked ]
457
-	 */
458
-	public function getAvailability();
459
-
460
-	/**
461
-	 * @since 8.2.0
462
-	 * @param bool $isAvailable
463
-	 */
464
-	public function setAvailability($isAvailable);
465
-
466
-	public function needsPartFile();
54
+    /**
55
+     * $parameters is a free form array with the configuration options needed to construct the storage
56
+     *
57
+     * @param array $parameters
58
+     * @since 6.0.0
59
+     */
60
+    public function __construct($parameters);
61
+
62
+    /**
63
+     * Get the identifier for the storage,
64
+     * the returned id should be the same for every storage object that is created with the same parameters
65
+     * and two storage objects with the same id should refer to two storages that display the same files.
66
+     *
67
+     * @return string
68
+     * @since 6.0.0
69
+     */
70
+    public function getId();
71
+
72
+    /**
73
+     * see http://php.net/manual/en/function.mkdir.php
74
+     * implementations need to implement a recursive mkdir
75
+     *
76
+     * @param string $path
77
+     * @return bool
78
+     * @since 6.0.0
79
+     */
80
+    public function mkdir($path);
81
+
82
+    /**
83
+     * see http://php.net/manual/en/function.rmdir.php
84
+     *
85
+     * @param string $path
86
+     * @return bool
87
+     * @since 6.0.0
88
+     */
89
+    public function rmdir($path);
90
+
91
+    /**
92
+     * see http://php.net/manual/en/function.opendir.php
93
+     *
94
+     * @param string $path
95
+     * @return resource|false
96
+     * @since 6.0.0
97
+     */
98
+    public function opendir($path);
99
+
100
+    /**
101
+     * see http://php.net/manual/en/function.is-dir.php
102
+     *
103
+     * @param string $path
104
+     * @return bool
105
+     * @since 6.0.0
106
+     */
107
+    public function is_dir($path);
108
+
109
+    /**
110
+     * see http://php.net/manual/en/function.is-file.php
111
+     *
112
+     * @param string $path
113
+     * @return bool
114
+     * @since 6.0.0
115
+     */
116
+    public function is_file($path);
117
+
118
+    /**
119
+     * see http://php.net/manual/en/function.stat.php
120
+     * only the following keys are required in the result: size and mtime
121
+     *
122
+     * @param string $path
123
+     * @return array|false
124
+     * @since 6.0.0
125
+     */
126
+    public function stat($path);
127
+
128
+    /**
129
+     * see http://php.net/manual/en/function.filetype.php
130
+     *
131
+     * @param string $path
132
+     * @return string|false
133
+     * @since 6.0.0
134
+     */
135
+    public function filetype($path);
136
+
137
+    /**
138
+     * see http://php.net/manual/en/function.filesize.php
139
+     * The result for filesize when called on a folder is required to be 0
140
+     *
141
+     * @param string $path
142
+     * @return int|false
143
+     * @since 6.0.0
144
+     */
145
+    public function filesize($path);
146
+
147
+    /**
148
+     * check if a file can be created in $path
149
+     *
150
+     * @param string $path
151
+     * @return bool
152
+     * @since 6.0.0
153
+     */
154
+    public function isCreatable($path);
155
+
156
+    /**
157
+     * check if a file can be read
158
+     *
159
+     * @param string $path
160
+     * @return bool
161
+     * @since 6.0.0
162
+     */
163
+    public function isReadable($path);
164
+
165
+    /**
166
+     * check if a file can be written to
167
+     *
168
+     * @param string $path
169
+     * @return bool
170
+     * @since 6.0.0
171
+     */
172
+    public function isUpdatable($path);
173
+
174
+    /**
175
+     * check if a file can be deleted
176
+     *
177
+     * @param string $path
178
+     * @return bool
179
+     * @since 6.0.0
180
+     */
181
+    public function isDeletable($path);
182
+
183
+    /**
184
+     * check if a file can be shared
185
+     *
186
+     * @param string $path
187
+     * @return bool
188
+     * @since 6.0.0
189
+     */
190
+    public function isSharable($path);
191
+
192
+    /**
193
+     * get the full permissions of a path.
194
+     * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
195
+     *
196
+     * @param string $path
197
+     * @return int
198
+     * @since 6.0.0
199
+     */
200
+    public function getPermissions($path);
201
+
202
+    /**
203
+     * see http://php.net/manual/en/function.file_exists.php
204
+     *
205
+     * @param string $path
206
+     * @return bool
207
+     * @since 6.0.0
208
+     */
209
+    public function file_exists($path);
210
+
211
+    /**
212
+     * see http://php.net/manual/en/function.filemtime.php
213
+     *
214
+     * @param string $path
215
+     * @return int|false
216
+     * @since 6.0.0
217
+     */
218
+    public function filemtime($path);
219
+
220
+    /**
221
+     * see http://php.net/manual/en/function.file_get_contents.php
222
+     *
223
+     * @param string $path
224
+     * @return string|false
225
+     * @since 6.0.0
226
+     */
227
+    public function file_get_contents($path);
228
+
229
+    /**
230
+     * see http://php.net/manual/en/function.file_put_contents.php
231
+     *
232
+     * @param string $path
233
+     * @param mixed $data
234
+     * @return int|false
235
+     * @since 6.0.0
236
+     */
237
+    public function file_put_contents($path, $data);
238
+
239
+    /**
240
+     * see http://php.net/manual/en/function.unlink.php
241
+     *
242
+     * @param string $path
243
+     * @return bool
244
+     * @since 6.0.0
245
+     */
246
+    public function unlink($path);
247
+
248
+    /**
249
+     * see http://php.net/manual/en/function.rename.php
250
+     *
251
+     * @param string $path1
252
+     * @param string $path2
253
+     * @return bool
254
+     * @since 6.0.0
255
+     */
256
+    public function rename($path1, $path2);
257
+
258
+    /**
259
+     * see http://php.net/manual/en/function.copy.php
260
+     *
261
+     * @param string $path1
262
+     * @param string $path2
263
+     * @return bool
264
+     * @since 6.0.0
265
+     */
266
+    public function copy($path1, $path2);
267
+
268
+    /**
269
+     * see http://php.net/manual/en/function.fopen.php
270
+     *
271
+     * @param string $path
272
+     * @param string $mode
273
+     * @return resource|false
274
+     * @since 6.0.0
275
+     */
276
+    public function fopen($path, $mode);
277
+
278
+    /**
279
+     * get the mimetype for a file or folder
280
+     * The mimetype for a folder is required to be "httpd/unix-directory"
281
+     *
282
+     * @param string $path
283
+     * @return string|false
284
+     * @since 6.0.0
285
+     */
286
+    public function getMimeType($path);
287
+
288
+    /**
289
+     * see http://php.net/manual/en/function.hash-file.php
290
+     *
291
+     * @param string $type
292
+     * @param string $path
293
+     * @param bool $raw
294
+     * @return string|false
295
+     * @since 6.0.0
296
+     */
297
+    public function hash($type, $path, $raw = false);
298
+
299
+    /**
300
+     * see http://php.net/manual/en/function.free_space.php
301
+     *
302
+     * @param string $path
303
+     * @return int|false
304
+     * @since 6.0.0
305
+     */
306
+    public function free_space($path);
307
+
308
+    /**
309
+     * search for occurrences of $query in file names
310
+     *
311
+     * @param string $query
312
+     * @return array|false
313
+     * @since 6.0.0
314
+     */
315
+    public function search($query);
316
+
317
+    /**
318
+     * see http://php.net/manual/en/function.touch.php
319
+     * If the backend does not support the operation, false should be returned
320
+     *
321
+     * @param string $path
322
+     * @param int $mtime
323
+     * @return bool
324
+     * @since 6.0.0
325
+     */
326
+    public function touch($path, $mtime = null);
327
+
328
+    /**
329
+     * get the path to a local version of the file.
330
+     * The local version of the file can be temporary and doesn't have to be persistent across requests
331
+     *
332
+     * @param string $path
333
+     * @return string|false
334
+     * @since 6.0.0
335
+     */
336
+    public function getLocalFile($path);
337
+
338
+    /**
339
+     * check if a file or folder has been updated since $time
340
+     *
341
+     * @param string $path
342
+     * @param int $time
343
+     * @return bool
344
+     * @since 6.0.0
345
+     *
346
+     * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
347
+     * returning true for other changes in the folder is optional
348
+     */
349
+    public function hasUpdated($path, $time);
350
+
351
+    /**
352
+     * get the ETag for a file or folder
353
+     *
354
+     * @param string $path
355
+     * @return string|false
356
+     * @since 6.0.0
357
+     */
358
+    public function getETag($path);
359
+
360
+    /**
361
+     * Returns whether the storage is local, which means that files
362
+     * are stored on the local filesystem instead of remotely.
363
+     * Calling getLocalFile() for local storages should always
364
+     * return the local files, whereas for non-local storages
365
+     * it might return a temporary file.
366
+     *
367
+     * @return bool true if the files are stored locally, false otherwise
368
+     * @since 7.0.0
369
+     */
370
+    public function isLocal();
371
+
372
+    /**
373
+     * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
374
+     *
375
+     * @param string $class
376
+     * @return bool
377
+     * @since 7.0.0
378
+     */
379
+    public function instanceOfStorage($class);
380
+
381
+    /**
382
+     * A custom storage implementation can return an url for direct download of a give file.
383
+     *
384
+     * For now the returned array can hold the parameter url - in future more attributes might follow.
385
+     *
386
+     * @param string $path
387
+     * @return array|false
388
+     * @since 8.0.0
389
+     */
390
+    public function getDirectDownload($path);
391
+
392
+    /**
393
+     * @param string $path the path of the target folder
394
+     * @param string $fileName the name of the file itself
395
+     * @return void
396
+     * @throws InvalidPathException
397
+     * @since 8.1.0
398
+     */
399
+    public function verifyPath($path, $fileName);
400
+
401
+    /**
402
+     * @param IStorage $sourceStorage
403
+     * @param string $sourceInternalPath
404
+     * @param string $targetInternalPath
405
+     * @return bool
406
+     * @since 8.1.0
407
+     */
408
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
409
+
410
+    /**
411
+     * @param IStorage $sourceStorage
412
+     * @param string $sourceInternalPath
413
+     * @param string $targetInternalPath
414
+     * @return bool
415
+     * @since 8.1.0
416
+     */
417
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
418
+
419
+    /**
420
+     * @param string $path The path of the file to acquire the lock for
421
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
422
+     * @param \OCP\Lock\ILockingProvider $provider
423
+     * @throws \OCP\Lock\LockedException
424
+     * @since 8.1.0
425
+     */
426
+    public function acquireLock($path, $type, ILockingProvider $provider);
427
+
428
+    /**
429
+     * @param string $path The path of the file to acquire the lock for
430
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
431
+     * @param \OCP\Lock\ILockingProvider $provider
432
+     * @throws \OCP\Lock\LockedException
433
+     * @since 8.1.0
434
+     */
435
+    public function releaseLock($path, $type, ILockingProvider $provider);
436
+
437
+    /**
438
+     * @param string $path The path of the file to change the lock for
439
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
440
+     * @param \OCP\Lock\ILockingProvider $provider
441
+     * @throws \OCP\Lock\LockedException
442
+     * @since 8.1.0
443
+     */
444
+    public function changeLock($path, $type, ILockingProvider $provider);
445
+
446
+    /**
447
+     * Test a storage for availability
448
+     *
449
+     * @since 8.2.0
450
+     * @return bool
451
+     */
452
+    public function test();
453
+
454
+    /**
455
+     * @since 8.2.0
456
+     * @return array [ available, last_checked ]
457
+     */
458
+    public function getAvailability();
459
+
460
+    /**
461
+     * @since 8.2.0
462
+     * @param bool $isAvailable
463
+     */
464
+    public function setAvailability($isAvailable);
465
+
466
+    public function needsPartFile();
467 467
 }
Please login to merge, or discard this patch.
lib/public/Files/Storage/IStorage.php 1 patch
Indentation   +411 added lines, -411 removed lines patch added patch discarded remove patch
@@ -47,415 +47,415 @@
 block discarded – undo
47 47
  * @since 9.0.0
48 48
  */
49 49
 interface IStorage {
50
-	/**
51
-	 * $parameters is a free form array with the configuration options needed to construct the storage
52
-	 *
53
-	 * @param array $parameters
54
-	 * @since 9.0.0
55
-	 */
56
-	public function __construct($parameters);
57
-
58
-	/**
59
-	 * Get the identifier for the storage,
60
-	 * the returned id should be the same for every storage object that is created with the same parameters
61
-	 * and two storage objects with the same id should refer to two storages that display the same files.
62
-	 *
63
-	 * @return string
64
-	 * @since 9.0.0
65
-	 */
66
-	public function getId();
67
-
68
-	/**
69
-	 * see http://php.net/manual/en/function.mkdir.php
70
-	 * implementations need to implement a recursive mkdir
71
-	 *
72
-	 * @param string $path
73
-	 * @return bool
74
-	 * @since 9.0.0
75
-	 */
76
-	public function mkdir($path);
77
-
78
-	/**
79
-	 * see http://php.net/manual/en/function.rmdir.php
80
-	 *
81
-	 * @param string $path
82
-	 * @return bool
83
-	 * @since 9.0.0
84
-	 */
85
-	public function rmdir($path);
86
-
87
-	/**
88
-	 * see http://php.net/manual/en/function.opendir.php
89
-	 *
90
-	 * @param string $path
91
-	 * @return resource|false
92
-	 * @since 9.0.0
93
-	 */
94
-	public function opendir($path);
95
-
96
-	/**
97
-	 * see http://php.net/manual/en/function.is-dir.php
98
-	 *
99
-	 * @param string $path
100
-	 * @return bool
101
-	 * @since 9.0.0
102
-	 */
103
-	public function is_dir($path);
104
-
105
-	/**
106
-	 * see http://php.net/manual/en/function.is-file.php
107
-	 *
108
-	 * @param string $path
109
-	 * @return bool
110
-	 * @since 9.0.0
111
-	 */
112
-	public function is_file($path);
113
-
114
-	/**
115
-	 * see http://php.net/manual/en/function.stat.php
116
-	 * only the following keys are required in the result: size and mtime
117
-	 *
118
-	 * @param string $path
119
-	 * @return array|false
120
-	 * @since 9.0.0
121
-	 */
122
-	public function stat($path);
123
-
124
-	/**
125
-	 * see http://php.net/manual/en/function.filetype.php
126
-	 *
127
-	 * @param string $path
128
-	 * @return string|false
129
-	 * @since 9.0.0
130
-	 */
131
-	public function filetype($path);
132
-
133
-	/**
134
-	 * see http://php.net/manual/en/function.filesize.php
135
-	 * The result for filesize when called on a folder is required to be 0
136
-	 *
137
-	 * @param string $path
138
-	 * @return int|false
139
-	 * @since 9.0.0
140
-	 */
141
-	public function filesize($path);
142
-
143
-	/**
144
-	 * check if a file can be created in $path
145
-	 *
146
-	 * @param string $path
147
-	 * @return bool
148
-	 * @since 9.0.0
149
-	 */
150
-	public function isCreatable($path);
151
-
152
-	/**
153
-	 * check if a file can be read
154
-	 *
155
-	 * @param string $path
156
-	 * @return bool
157
-	 * @since 9.0.0
158
-	 */
159
-	public function isReadable($path);
160
-
161
-	/**
162
-	 * check if a file can be written to
163
-	 *
164
-	 * @param string $path
165
-	 * @return bool
166
-	 * @since 9.0.0
167
-	 */
168
-	public function isUpdatable($path);
169
-
170
-	/**
171
-	 * check if a file can be deleted
172
-	 *
173
-	 * @param string $path
174
-	 * @return bool
175
-	 * @since 9.0.0
176
-	 */
177
-	public function isDeletable($path);
178
-
179
-	/**
180
-	 * check if a file can be shared
181
-	 *
182
-	 * @param string $path
183
-	 * @return bool
184
-	 * @since 9.0.0
185
-	 */
186
-	public function isSharable($path);
187
-
188
-	/**
189
-	 * get the full permissions of a path.
190
-	 * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
191
-	 *
192
-	 * @param string $path
193
-	 * @return int
194
-	 * @since 9.0.0
195
-	 */
196
-	public function getPermissions($path);
197
-
198
-	/**
199
-	 * see http://php.net/manual/en/function.file_exists.php
200
-	 *
201
-	 * @param string $path
202
-	 * @return bool
203
-	 * @since 9.0.0
204
-	 */
205
-	public function file_exists($path);
206
-
207
-	/**
208
-	 * see http://php.net/manual/en/function.filemtime.php
209
-	 *
210
-	 * @param string $path
211
-	 * @return int|false
212
-	 * @since 9.0.0
213
-	 */
214
-	public function filemtime($path);
215
-
216
-	/**
217
-	 * see http://php.net/manual/en/function.file_get_contents.php
218
-	 *
219
-	 * @param string $path
220
-	 * @return string|false
221
-	 * @since 9.0.0
222
-	 */
223
-	public function file_get_contents($path);
224
-
225
-	/**
226
-	 * see http://php.net/manual/en/function.file_put_contents.php
227
-	 *
228
-	 * @param string $path
229
-	 * @param mixed $data
230
-	 * @return int|false
231
-	 * @since 9.0.0
232
-	 */
233
-	public function file_put_contents($path, $data);
234
-
235
-	/**
236
-	 * see http://php.net/manual/en/function.unlink.php
237
-	 *
238
-	 * @param string $path
239
-	 * @return bool
240
-	 * @since 9.0.0
241
-	 */
242
-	public function unlink($path);
243
-
244
-	/**
245
-	 * see http://php.net/manual/en/function.rename.php
246
-	 *
247
-	 * @param string $path1
248
-	 * @param string $path2
249
-	 * @return bool
250
-	 * @since 9.0.0
251
-	 */
252
-	public function rename($path1, $path2);
253
-
254
-	/**
255
-	 * see http://php.net/manual/en/function.copy.php
256
-	 *
257
-	 * @param string $path1
258
-	 * @param string $path2
259
-	 * @return bool
260
-	 * @since 9.0.0
261
-	 */
262
-	public function copy($path1, $path2);
263
-
264
-	/**
265
-	 * see http://php.net/manual/en/function.fopen.php
266
-	 *
267
-	 * @param string $path
268
-	 * @param string $mode
269
-	 * @return resource|false
270
-	 * @since 9.0.0
271
-	 */
272
-	public function fopen($path, $mode);
273
-
274
-	/**
275
-	 * get the mimetype for a file or folder
276
-	 * The mimetype for a folder is required to be "httpd/unix-directory"
277
-	 *
278
-	 * @param string $path
279
-	 * @return string|false
280
-	 * @since 9.0.0
281
-	 */
282
-	public function getMimeType($path);
283
-
284
-	/**
285
-	 * see http://php.net/manual/en/function.hash-file.php
286
-	 *
287
-	 * @param string $type
288
-	 * @param string $path
289
-	 * @param bool $raw
290
-	 * @return string|false
291
-	 * @since 9.0.0
292
-	 */
293
-	public function hash($type, $path, $raw = false);
294
-
295
-	/**
296
-	 * see http://php.net/manual/en/function.free_space.php
297
-	 *
298
-	 * @param string $path
299
-	 * @return int|false
300
-	 * @since 9.0.0
301
-	 */
302
-	public function free_space($path);
303
-
304
-	/**
305
-	 * see http://php.net/manual/en/function.touch.php
306
-	 * If the backend does not support the operation, false should be returned
307
-	 *
308
-	 * @param string $path
309
-	 * @param int $mtime
310
-	 * @return bool
311
-	 * @since 9.0.0
312
-	 */
313
-	public function touch($path, $mtime = null);
314
-
315
-	/**
316
-	 * get the path to a local version of the file.
317
-	 * The local version of the file can be temporary and doesn't have to be persistent across requests
318
-	 *
319
-	 * @param string $path
320
-	 * @return string|false
321
-	 * @since 9.0.0
322
-	 */
323
-	public function getLocalFile($path);
324
-
325
-	/**
326
-	 * check if a file or folder has been updated since $time
327
-	 *
328
-	 * @param string $path
329
-	 * @param int $time
330
-	 * @return bool
331
-	 * @since 9.0.0
332
-	 *
333
-	 * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
334
-	 * returning true for other changes in the folder is optional
335
-	 */
336
-	public function hasUpdated($path, $time);
337
-
338
-	/**
339
-	 * get the ETag for a file or folder
340
-	 *
341
-	 * @param string $path
342
-	 * @return string|false
343
-	 * @since 9.0.0
344
-	 */
345
-	public function getETag($path);
346
-
347
-	/**
348
-	 * Returns whether the storage is local, which means that files
349
-	 * are stored on the local filesystem instead of remotely.
350
-	 * Calling getLocalFile() for local storages should always
351
-	 * return the local files, whereas for non-local storages
352
-	 * it might return a temporary file.
353
-	 *
354
-	 * @return bool true if the files are stored locally, false otherwise
355
-	 * @since 9.0.0
356
-	 */
357
-	public function isLocal();
358
-
359
-	/**
360
-	 * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
361
-	 *
362
-	 * @param string $class
363
-	 * @return bool
364
-	 * @since 9.0.0
365
-	 */
366
-	public function instanceOfStorage($class);
367
-
368
-	/**
369
-	 * A custom storage implementation can return an url for direct download of a give file.
370
-	 *
371
-	 * For now the returned array can hold the parameter url - in future more attributes might follow.
372
-	 *
373
-	 * @param string $path
374
-	 * @return array|false
375
-	 * @since 9.0.0
376
-	 */
377
-	public function getDirectDownload($path);
378
-
379
-	/**
380
-	 * @param string $path the path of the target folder
381
-	 * @param string $fileName the name of the file itself
382
-	 * @return void
383
-	 * @throws InvalidPathException
384
-	 * @since 9.0.0
385
-	 */
386
-	public function verifyPath($path, $fileName);
387
-
388
-	/**
389
-	 * @param IStorage $sourceStorage
390
-	 * @param string $sourceInternalPath
391
-	 * @param string $targetInternalPath
392
-	 * @return bool
393
-	 * @since 9.0.0
394
-	 */
395
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
396
-
397
-	/**
398
-	 * @param IStorage $sourceStorage
399
-	 * @param string $sourceInternalPath
400
-	 * @param string $targetInternalPath
401
-	 * @return bool
402
-	 * @since 9.0.0
403
-	 */
404
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
405
-
406
-	/**
407
-	 * Test a storage for availability
408
-	 *
409
-	 * @since 9.0.0
410
-	 * @return bool
411
-	 */
412
-	public function test();
413
-
414
-	/**
415
-	 * @since 9.0.0
416
-	 * @return array [ available, last_checked ]
417
-	 */
418
-	public function getAvailability();
419
-
420
-	/**
421
-	 * @since 9.0.0
422
-	 * @param bool $isAvailable
423
-	 */
424
-	public function setAvailability($isAvailable);
425
-
426
-	/**
427
-	 * @param string $path path for which to retrieve the owner
428
-	 * @since 9.0.0
429
-	 */
430
-	public function getOwner($path);
431
-
432
-	/**
433
-	 * @return ICache
434
-	 * @since 9.0.0
435
-	 */
436
-	public function getCache();
437
-
438
-	/**
439
-	 * @return IPropagator
440
-	 * @since 9.0.0
441
-	 */
442
-	public function getPropagator();
443
-
444
-	/**
445
-	 * @return IScanner
446
-	 * @since 9.0.0
447
-	 */
448
-	public function getScanner();
449
-
450
-	/**
451
-	 * @return IUpdater
452
-	 * @since 9.0.0
453
-	 */
454
-	public function getUpdater();
455
-
456
-	/**
457
-	 * @return IWatcher
458
-	 * @since 9.0.0
459
-	 */
460
-	public function getWatcher();
50
+    /**
51
+     * $parameters is a free form array with the configuration options needed to construct the storage
52
+     *
53
+     * @param array $parameters
54
+     * @since 9.0.0
55
+     */
56
+    public function __construct($parameters);
57
+
58
+    /**
59
+     * Get the identifier for the storage,
60
+     * the returned id should be the same for every storage object that is created with the same parameters
61
+     * and two storage objects with the same id should refer to two storages that display the same files.
62
+     *
63
+     * @return string
64
+     * @since 9.0.0
65
+     */
66
+    public function getId();
67
+
68
+    /**
69
+     * see http://php.net/manual/en/function.mkdir.php
70
+     * implementations need to implement a recursive mkdir
71
+     *
72
+     * @param string $path
73
+     * @return bool
74
+     * @since 9.0.0
75
+     */
76
+    public function mkdir($path);
77
+
78
+    /**
79
+     * see http://php.net/manual/en/function.rmdir.php
80
+     *
81
+     * @param string $path
82
+     * @return bool
83
+     * @since 9.0.0
84
+     */
85
+    public function rmdir($path);
86
+
87
+    /**
88
+     * see http://php.net/manual/en/function.opendir.php
89
+     *
90
+     * @param string $path
91
+     * @return resource|false
92
+     * @since 9.0.0
93
+     */
94
+    public function opendir($path);
95
+
96
+    /**
97
+     * see http://php.net/manual/en/function.is-dir.php
98
+     *
99
+     * @param string $path
100
+     * @return bool
101
+     * @since 9.0.0
102
+     */
103
+    public function is_dir($path);
104
+
105
+    /**
106
+     * see http://php.net/manual/en/function.is-file.php
107
+     *
108
+     * @param string $path
109
+     * @return bool
110
+     * @since 9.0.0
111
+     */
112
+    public function is_file($path);
113
+
114
+    /**
115
+     * see http://php.net/manual/en/function.stat.php
116
+     * only the following keys are required in the result: size and mtime
117
+     *
118
+     * @param string $path
119
+     * @return array|false
120
+     * @since 9.0.0
121
+     */
122
+    public function stat($path);
123
+
124
+    /**
125
+     * see http://php.net/manual/en/function.filetype.php
126
+     *
127
+     * @param string $path
128
+     * @return string|false
129
+     * @since 9.0.0
130
+     */
131
+    public function filetype($path);
132
+
133
+    /**
134
+     * see http://php.net/manual/en/function.filesize.php
135
+     * The result for filesize when called on a folder is required to be 0
136
+     *
137
+     * @param string $path
138
+     * @return int|false
139
+     * @since 9.0.0
140
+     */
141
+    public function filesize($path);
142
+
143
+    /**
144
+     * check if a file can be created in $path
145
+     *
146
+     * @param string $path
147
+     * @return bool
148
+     * @since 9.0.0
149
+     */
150
+    public function isCreatable($path);
151
+
152
+    /**
153
+     * check if a file can be read
154
+     *
155
+     * @param string $path
156
+     * @return bool
157
+     * @since 9.0.0
158
+     */
159
+    public function isReadable($path);
160
+
161
+    /**
162
+     * check if a file can be written to
163
+     *
164
+     * @param string $path
165
+     * @return bool
166
+     * @since 9.0.0
167
+     */
168
+    public function isUpdatable($path);
169
+
170
+    /**
171
+     * check if a file can be deleted
172
+     *
173
+     * @param string $path
174
+     * @return bool
175
+     * @since 9.0.0
176
+     */
177
+    public function isDeletable($path);
178
+
179
+    /**
180
+     * check if a file can be shared
181
+     *
182
+     * @param string $path
183
+     * @return bool
184
+     * @since 9.0.0
185
+     */
186
+    public function isSharable($path);
187
+
188
+    /**
189
+     * get the full permissions of a path.
190
+     * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
191
+     *
192
+     * @param string $path
193
+     * @return int
194
+     * @since 9.0.0
195
+     */
196
+    public function getPermissions($path);
197
+
198
+    /**
199
+     * see http://php.net/manual/en/function.file_exists.php
200
+     *
201
+     * @param string $path
202
+     * @return bool
203
+     * @since 9.0.0
204
+     */
205
+    public function file_exists($path);
206
+
207
+    /**
208
+     * see http://php.net/manual/en/function.filemtime.php
209
+     *
210
+     * @param string $path
211
+     * @return int|false
212
+     * @since 9.0.0
213
+     */
214
+    public function filemtime($path);
215
+
216
+    /**
217
+     * see http://php.net/manual/en/function.file_get_contents.php
218
+     *
219
+     * @param string $path
220
+     * @return string|false
221
+     * @since 9.0.0
222
+     */
223
+    public function file_get_contents($path);
224
+
225
+    /**
226
+     * see http://php.net/manual/en/function.file_put_contents.php
227
+     *
228
+     * @param string $path
229
+     * @param mixed $data
230
+     * @return int|false
231
+     * @since 9.0.0
232
+     */
233
+    public function file_put_contents($path, $data);
234
+
235
+    /**
236
+     * see http://php.net/manual/en/function.unlink.php
237
+     *
238
+     * @param string $path
239
+     * @return bool
240
+     * @since 9.0.0
241
+     */
242
+    public function unlink($path);
243
+
244
+    /**
245
+     * see http://php.net/manual/en/function.rename.php
246
+     *
247
+     * @param string $path1
248
+     * @param string $path2
249
+     * @return bool
250
+     * @since 9.0.0
251
+     */
252
+    public function rename($path1, $path2);
253
+
254
+    /**
255
+     * see http://php.net/manual/en/function.copy.php
256
+     *
257
+     * @param string $path1
258
+     * @param string $path2
259
+     * @return bool
260
+     * @since 9.0.0
261
+     */
262
+    public function copy($path1, $path2);
263
+
264
+    /**
265
+     * see http://php.net/manual/en/function.fopen.php
266
+     *
267
+     * @param string $path
268
+     * @param string $mode
269
+     * @return resource|false
270
+     * @since 9.0.0
271
+     */
272
+    public function fopen($path, $mode);
273
+
274
+    /**
275
+     * get the mimetype for a file or folder
276
+     * The mimetype for a folder is required to be "httpd/unix-directory"
277
+     *
278
+     * @param string $path
279
+     * @return string|false
280
+     * @since 9.0.0
281
+     */
282
+    public function getMimeType($path);
283
+
284
+    /**
285
+     * see http://php.net/manual/en/function.hash-file.php
286
+     *
287
+     * @param string $type
288
+     * @param string $path
289
+     * @param bool $raw
290
+     * @return string|false
291
+     * @since 9.0.0
292
+     */
293
+    public function hash($type, $path, $raw = false);
294
+
295
+    /**
296
+     * see http://php.net/manual/en/function.free_space.php
297
+     *
298
+     * @param string $path
299
+     * @return int|false
300
+     * @since 9.0.0
301
+     */
302
+    public function free_space($path);
303
+
304
+    /**
305
+     * see http://php.net/manual/en/function.touch.php
306
+     * If the backend does not support the operation, false should be returned
307
+     *
308
+     * @param string $path
309
+     * @param int $mtime
310
+     * @return bool
311
+     * @since 9.0.0
312
+     */
313
+    public function touch($path, $mtime = null);
314
+
315
+    /**
316
+     * get the path to a local version of the file.
317
+     * The local version of the file can be temporary and doesn't have to be persistent across requests
318
+     *
319
+     * @param string $path
320
+     * @return string|false
321
+     * @since 9.0.0
322
+     */
323
+    public function getLocalFile($path);
324
+
325
+    /**
326
+     * check if a file or folder has been updated since $time
327
+     *
328
+     * @param string $path
329
+     * @param int $time
330
+     * @return bool
331
+     * @since 9.0.0
332
+     *
333
+     * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
334
+     * returning true for other changes in the folder is optional
335
+     */
336
+    public function hasUpdated($path, $time);
337
+
338
+    /**
339
+     * get the ETag for a file or folder
340
+     *
341
+     * @param string $path
342
+     * @return string|false
343
+     * @since 9.0.0
344
+     */
345
+    public function getETag($path);
346
+
347
+    /**
348
+     * Returns whether the storage is local, which means that files
349
+     * are stored on the local filesystem instead of remotely.
350
+     * Calling getLocalFile() for local storages should always
351
+     * return the local files, whereas for non-local storages
352
+     * it might return a temporary file.
353
+     *
354
+     * @return bool true if the files are stored locally, false otherwise
355
+     * @since 9.0.0
356
+     */
357
+    public function isLocal();
358
+
359
+    /**
360
+     * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
361
+     *
362
+     * @param string $class
363
+     * @return bool
364
+     * @since 9.0.0
365
+     */
366
+    public function instanceOfStorage($class);
367
+
368
+    /**
369
+     * A custom storage implementation can return an url for direct download of a give file.
370
+     *
371
+     * For now the returned array can hold the parameter url - in future more attributes might follow.
372
+     *
373
+     * @param string $path
374
+     * @return array|false
375
+     * @since 9.0.0
376
+     */
377
+    public function getDirectDownload($path);
378
+
379
+    /**
380
+     * @param string $path the path of the target folder
381
+     * @param string $fileName the name of the file itself
382
+     * @return void
383
+     * @throws InvalidPathException
384
+     * @since 9.0.0
385
+     */
386
+    public function verifyPath($path, $fileName);
387
+
388
+    /**
389
+     * @param IStorage $sourceStorage
390
+     * @param string $sourceInternalPath
391
+     * @param string $targetInternalPath
392
+     * @return bool
393
+     * @since 9.0.0
394
+     */
395
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
396
+
397
+    /**
398
+     * @param IStorage $sourceStorage
399
+     * @param string $sourceInternalPath
400
+     * @param string $targetInternalPath
401
+     * @return bool
402
+     * @since 9.0.0
403
+     */
404
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath);
405
+
406
+    /**
407
+     * Test a storage for availability
408
+     *
409
+     * @since 9.0.0
410
+     * @return bool
411
+     */
412
+    public function test();
413
+
414
+    /**
415
+     * @since 9.0.0
416
+     * @return array [ available, last_checked ]
417
+     */
418
+    public function getAvailability();
419
+
420
+    /**
421
+     * @since 9.0.0
422
+     * @param bool $isAvailable
423
+     */
424
+    public function setAvailability($isAvailable);
425
+
426
+    /**
427
+     * @param string $path path for which to retrieve the owner
428
+     * @since 9.0.0
429
+     */
430
+    public function getOwner($path);
431
+
432
+    /**
433
+     * @return ICache
434
+     * @since 9.0.0
435
+     */
436
+    public function getCache();
437
+
438
+    /**
439
+     * @return IPropagator
440
+     * @since 9.0.0
441
+     */
442
+    public function getPropagator();
443
+
444
+    /**
445
+     * @return IScanner
446
+     * @since 9.0.0
447
+     */
448
+    public function getScanner();
449
+
450
+    /**
451
+     * @return IUpdater
452
+     * @since 9.0.0
453
+     */
454
+    public function getUpdater();
455
+
456
+    /**
457
+     * @return IWatcher
458
+     * @since 9.0.0
459
+     */
460
+    public function getWatcher();
461 461
 }
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/ObjectStoreStorage.php 1 patch
Indentation   +540 added lines, -540 removed lines patch added patch discarded remove patch
@@ -40,547 +40,547 @@
 block discarded – undo
40 40
 use OCP\Files\ObjectStore\IObjectStore;
41 41
 
42 42
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
43
-	use CopyDirectory;
44
-
45
-	/**
46
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
47
-	 */
48
-	protected $objectStore;
49
-	/**
50
-	 * @var string $id
51
-	 */
52
-	protected $id;
53
-	/**
54
-	 * @var \OC\User\User $user
55
-	 */
56
-	protected $user;
57
-
58
-	private $objectPrefix = 'urn:oid:';
59
-
60
-	private $logger;
61
-
62
-	public function __construct($params) {
63
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
64
-			$this->objectStore = $params['objectstore'];
65
-		} else {
66
-			throw new \Exception('missing IObjectStore instance');
67
-		}
68
-		if (isset($params['storageid'])) {
69
-			$this->id = 'object::store:' . $params['storageid'];
70
-		} else {
71
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
72
-		}
73
-		if (isset($params['objectPrefix'])) {
74
-			$this->objectPrefix = $params['objectPrefix'];
75
-		}
76
-		//initialize cache with root directory in cache
77
-		if (!$this->is_dir('/')) {
78
-			$this->mkdir('/');
79
-		}
80
-
81
-		$this->logger = \OC::$server->getLogger();
82
-	}
83
-
84
-	public function mkdir($path) {
85
-		$path = $this->normalizePath($path);
86
-
87
-		if ($this->file_exists($path)) {
88
-			return false;
89
-		}
90
-
91
-		$mTime = time();
92
-		$data = [
93
-			'mimetype' => 'httpd/unix-directory',
94
-			'size' => 0,
95
-			'mtime' => $mTime,
96
-			'storage_mtime' => $mTime,
97
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
98
-		];
99
-		if ($path === '') {
100
-			//create root on the fly
101
-			$data['etag'] = $this->getETag('');
102
-			$this->getCache()->put('', $data);
103
-			return true;
104
-		} else {
105
-			// if parent does not exist, create it
106
-			$parent = $this->normalizePath(dirname($path));
107
-			$parentType = $this->filetype($parent);
108
-			if ($parentType === false) {
109
-				if (!$this->mkdir($parent)) {
110
-					// something went wrong
111
-					return false;
112
-				}
113
-			} elseif ($parentType === 'file') {
114
-				// parent is a file
115
-				return false;
116
-			}
117
-			// finally create the new dir
118
-			$mTime = time(); // update mtime
119
-			$data['mtime'] = $mTime;
120
-			$data['storage_mtime'] = $mTime;
121
-			$data['etag'] = $this->getETag($path);
122
-			$this->getCache()->put($path, $data);
123
-			return true;
124
-		}
125
-	}
126
-
127
-	/**
128
-	 * @param string $path
129
-	 * @return string
130
-	 */
131
-	private function normalizePath($path) {
132
-		$path = trim($path, '/');
133
-		//FIXME why do we sometimes get a path like 'files//username'?
134
-		$path = str_replace('//', '/', $path);
135
-
136
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
137
-		if (!$path || $path === '.') {
138
-			$path = '';
139
-		}
140
-
141
-		return $path;
142
-	}
143
-
144
-	/**
145
-	 * Object Stores use a NoopScanner because metadata is directly stored in
146
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
147
-	 *
148
-	 * @param string $path
149
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
150
-	 * @return \OC\Files\ObjectStore\NoopScanner
151
-	 */
152
-	public function getScanner($path = '', $storage = null) {
153
-		if (!$storage) {
154
-			$storage = $this;
155
-		}
156
-		if (!isset($this->scanner)) {
157
-			$this->scanner = new NoopScanner($storage);
158
-		}
159
-		return $this->scanner;
160
-	}
161
-
162
-	public function getId() {
163
-		return $this->id;
164
-	}
165
-
166
-	public function rmdir($path) {
167
-		$path = $this->normalizePath($path);
168
-
169
-		if (!$this->is_dir($path)) {
170
-			return false;
171
-		}
172
-
173
-		if (!$this->rmObjects($path)) {
174
-			return false;
175
-		}
176
-
177
-		$this->getCache()->remove($path);
178
-
179
-		return true;
180
-	}
181
-
182
-	private function rmObjects($path) {
183
-		$children = $this->getCache()->getFolderContents($path);
184
-		foreach ($children as $child) {
185
-			if ($child['mimetype'] === 'httpd/unix-directory') {
186
-				if (!$this->rmObjects($child['path'])) {
187
-					return false;
188
-				}
189
-			} else {
190
-				if (!$this->unlink($child['path'])) {
191
-					return false;
192
-				}
193
-			}
194
-		}
195
-
196
-		return true;
197
-	}
198
-
199
-	public function unlink($path) {
200
-		$path = $this->normalizePath($path);
201
-		$stat = $this->stat($path);
202
-
203
-		if ($stat && isset($stat['fileid'])) {
204
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
205
-				return $this->rmdir($path);
206
-			}
207
-			try {
208
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
209
-			} catch (\Exception $ex) {
210
-				if ($ex->getCode() !== 404) {
211
-					$this->logger->logException($ex, [
212
-						'app' => 'objectstore',
213
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
214
-					]);
215
-					return false;
216
-				}
217
-				//removing from cache is ok as it does not exist in the objectstore anyway
218
-			}
219
-			$this->getCache()->remove($path);
220
-			return true;
221
-		}
222
-		return false;
223
-	}
224
-
225
-	public function stat($path) {
226
-		$path = $this->normalizePath($path);
227
-		$cacheEntry = $this->getCache()->get($path);
228
-		if ($cacheEntry instanceof CacheEntry) {
229
-			return $cacheEntry->getData();
230
-		} else {
231
-			return false;
232
-		}
233
-	}
234
-
235
-	public function getPermissions($path) {
236
-		$stat = $this->stat($path);
237
-
238
-		if (is_array($stat) && isset($stat['permissions'])) {
239
-			return $stat['permissions'];
240
-		}
241
-
242
-		return parent::getPermissions($path);
243
-	}
244
-
245
-	/**
246
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
247
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
248
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
249
-	 *
250
-	 * @param int $fileId the fileid
251
-	 * @return null|string the unified resource name used to identify the object
252
-	 */
253
-	public function getURN($fileId) {
254
-		if (is_numeric($fileId)) {
255
-			return $this->objectPrefix . $fileId;
256
-		}
257
-		return null;
258
-	}
259
-
260
-	public function opendir($path) {
261
-		$path = $this->normalizePath($path);
262
-
263
-		try {
264
-			$files = [];
265
-			$folderContents = $this->getCache()->getFolderContents($path);
266
-			foreach ($folderContents as $file) {
267
-				$files[] = $file['name'];
268
-			}
269
-
270
-			return IteratorDirectory::wrap($files);
271
-		} catch (\Exception $e) {
272
-			$this->logger->logException($e);
273
-			return false;
274
-		}
275
-	}
276
-
277
-	public function filetype($path) {
278
-		$path = $this->normalizePath($path);
279
-		$stat = $this->stat($path);
280
-		if ($stat) {
281
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
282
-				return 'dir';
283
-			}
284
-			return 'file';
285
-		} else {
286
-			return false;
287
-		}
288
-	}
289
-
290
-	public function fopen($path, $mode) {
291
-		$path = $this->normalizePath($path);
292
-
293
-		if (strrpos($path, '.') !== false) {
294
-			$ext = substr($path, strrpos($path, '.'));
295
-		} else {
296
-			$ext = '';
297
-		}
298
-
299
-		switch ($mode) {
300
-			case 'r':
301
-			case 'rb':
302
-				$stat = $this->stat($path);
303
-				if (is_array($stat)) {
304
-					// Reading 0 sized files is a waste of time
305
-					if (isset($stat['size']) && $stat['size'] === 0) {
306
-						return fopen('php://memory', $mode);
307
-					}
308
-
309
-					try {
310
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
311
-					} catch (NotFoundException $e) {
312
-						$this->logger->logException($e, [
313
-							'app' => 'objectstore',
314
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
315
-						]);
316
-						throw $e;
317
-					} catch (\Exception $ex) {
318
-						$this->logger->logException($ex, [
319
-							'app' => 'objectstore',
320
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
321
-						]);
322
-						return false;
323
-					}
324
-				} else {
325
-					return false;
326
-				}
327
-			// no break
328
-			case 'w':
329
-			case 'wb':
330
-			case 'w+':
331
-			case 'wb+':
332
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
333
-				$handle = fopen($tmpFile, $mode);
334
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
335
-					$this->writeBack($tmpFile, $path);
336
-				});
337
-			case 'a':
338
-			case 'ab':
339
-			case 'r+':
340
-			case 'a+':
341
-			case 'x':
342
-			case 'x+':
343
-			case 'c':
344
-			case 'c+':
345
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
346
-				if ($this->file_exists($path)) {
347
-					$source = $this->fopen($path, 'r');
348
-					file_put_contents($tmpFile, $source);
349
-				}
350
-				$handle = fopen($tmpFile, $mode);
351
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
352
-					$this->writeBack($tmpFile, $path);
353
-				});
354
-		}
355
-		return false;
356
-	}
357
-
358
-	public function file_exists($path) {
359
-		$path = $this->normalizePath($path);
360
-		return (bool)$this->stat($path);
361
-	}
362
-
363
-	public function rename($source, $target) {
364
-		$source = $this->normalizePath($source);
365
-		$target = $this->normalizePath($target);
366
-		$this->remove($target);
367
-		$this->getCache()->move($source, $target);
368
-		$this->touch(dirname($target));
369
-		return true;
370
-	}
371
-
372
-	public function getMimeType($path) {
373
-		$path = $this->normalizePath($path);
374
-		return parent::getMimeType($path);
375
-	}
376
-
377
-	public function touch($path, $mtime = null) {
378
-		if (is_null($mtime)) {
379
-			$mtime = time();
380
-		}
381
-
382
-		$path = $this->normalizePath($path);
383
-		$dirName = dirname($path);
384
-		$parentExists = $this->is_dir($dirName);
385
-		if (!$parentExists) {
386
-			return false;
387
-		}
388
-
389
-		$stat = $this->stat($path);
390
-		if (is_array($stat)) {
391
-			// update existing mtime in db
392
-			$stat['mtime'] = $mtime;
393
-			$this->getCache()->update($stat['fileid'], $stat);
394
-		} else {
395
-			try {
396
-				//create a empty file, need to have at least on char to make it
397
-				// work with all object storage implementations
398
-				$this->file_put_contents($path, ' ');
399
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
400
-				$stat = [
401
-					'etag' => $this->getETag($path),
402
-					'mimetype' => $mimeType,
403
-					'size' => 0,
404
-					'mtime' => $mtime,
405
-					'storage_mtime' => $mtime,
406
-					'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
407
-				];
408
-				$this->getCache()->put($path, $stat);
409
-			} catch (\Exception $ex) {
410
-				$this->logger->logException($ex, [
411
-					'app' => 'objectstore',
412
-					'message' => 'Could not create object for ' . $path,
413
-				]);
414
-				throw $ex;
415
-			}
416
-		}
417
-		return true;
418
-	}
419
-
420
-	public function writeBack($tmpFile, $path) {
421
-		$size = filesize($tmpFile);
422
-		$this->writeStream($path, fopen($tmpFile, 'r'), $size);
423
-	}
424
-
425
-	/**
426
-	 * external changes are not supported, exclusive access to the object storage is assumed
427
-	 *
428
-	 * @param string $path
429
-	 * @param int $time
430
-	 * @return false
431
-	 */
432
-	public function hasUpdated($path, $time) {
433
-		return false;
434
-	}
435
-
436
-	public function needsPartFile() {
437
-		return false;
438
-	}
439
-
440
-	public function file_put_contents($path, $data) {
441
-		$handle = $this->fopen($path, 'w+');
442
-		$result = fwrite($handle, $data);
443
-		fclose($handle);
444
-		return $result;
445
-	}
446
-
447
-	public function writeStream(string $path, $stream, int $size = null): int {
448
-		$stat = $this->stat($path);
449
-		if (empty($stat)) {
450
-			// create new file
451
-			$stat = [
452
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
453
-			];
454
-		}
455
-		// update stat with new data
456
-		$mTime = time();
457
-		$stat['size'] = (int)$size;
458
-		$stat['mtime'] = $mTime;
459
-		$stat['storage_mtime'] = $mTime;
460
-
461
-		$mimetypeDetector = \OC::$server->getMimeTypeDetector();
462
-		$mimetype = $mimetypeDetector->detectPath($path);
463
-
464
-		$stat['mimetype'] = $mimetype;
465
-		$stat['etag'] = $this->getETag($path);
466
-
467
-		$exists = $this->getCache()->inCache($path);
468
-		$uploadPath = $exists ? $path : $path . '.part';
469
-
470
-		if ($exists) {
471
-			$fileId = $stat['fileid'];
472
-		} else {
473
-			$fileId = $this->getCache()->put($uploadPath, $stat);
474
-		}
475
-
476
-		$urn = $this->getURN($fileId);
477
-		try {
478
-			//upload to object storage
479
-			if ($size === null) {
480
-				$countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
481
-					$this->getCache()->update($fileId, [
482
-						'size' => $writtenSize,
483
-					]);
484
-					$size = $writtenSize;
485
-				});
486
-				$this->objectStore->writeObject($urn, $countStream);
487
-				if (is_resource($countStream)) {
488
-					fclose($countStream);
489
-				}
490
-				$stat['size'] = $size;
491
-			} else {
492
-				$this->objectStore->writeObject($urn, $stream);
493
-			}
494
-		} catch (\Exception $ex) {
495
-			if (!$exists) {
496
-				/*
43
+    use CopyDirectory;
44
+
45
+    /**
46
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
47
+     */
48
+    protected $objectStore;
49
+    /**
50
+     * @var string $id
51
+     */
52
+    protected $id;
53
+    /**
54
+     * @var \OC\User\User $user
55
+     */
56
+    protected $user;
57
+
58
+    private $objectPrefix = 'urn:oid:';
59
+
60
+    private $logger;
61
+
62
+    public function __construct($params) {
63
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
64
+            $this->objectStore = $params['objectstore'];
65
+        } else {
66
+            throw new \Exception('missing IObjectStore instance');
67
+        }
68
+        if (isset($params['storageid'])) {
69
+            $this->id = 'object::store:' . $params['storageid'];
70
+        } else {
71
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
72
+        }
73
+        if (isset($params['objectPrefix'])) {
74
+            $this->objectPrefix = $params['objectPrefix'];
75
+        }
76
+        //initialize cache with root directory in cache
77
+        if (!$this->is_dir('/')) {
78
+            $this->mkdir('/');
79
+        }
80
+
81
+        $this->logger = \OC::$server->getLogger();
82
+    }
83
+
84
+    public function mkdir($path) {
85
+        $path = $this->normalizePath($path);
86
+
87
+        if ($this->file_exists($path)) {
88
+            return false;
89
+        }
90
+
91
+        $mTime = time();
92
+        $data = [
93
+            'mimetype' => 'httpd/unix-directory',
94
+            'size' => 0,
95
+            'mtime' => $mTime,
96
+            'storage_mtime' => $mTime,
97
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
98
+        ];
99
+        if ($path === '') {
100
+            //create root on the fly
101
+            $data['etag'] = $this->getETag('');
102
+            $this->getCache()->put('', $data);
103
+            return true;
104
+        } else {
105
+            // if parent does not exist, create it
106
+            $parent = $this->normalizePath(dirname($path));
107
+            $parentType = $this->filetype($parent);
108
+            if ($parentType === false) {
109
+                if (!$this->mkdir($parent)) {
110
+                    // something went wrong
111
+                    return false;
112
+                }
113
+            } elseif ($parentType === 'file') {
114
+                // parent is a file
115
+                return false;
116
+            }
117
+            // finally create the new dir
118
+            $mTime = time(); // update mtime
119
+            $data['mtime'] = $mTime;
120
+            $data['storage_mtime'] = $mTime;
121
+            $data['etag'] = $this->getETag($path);
122
+            $this->getCache()->put($path, $data);
123
+            return true;
124
+        }
125
+    }
126
+
127
+    /**
128
+     * @param string $path
129
+     * @return string
130
+     */
131
+    private function normalizePath($path) {
132
+        $path = trim($path, '/');
133
+        //FIXME why do we sometimes get a path like 'files//username'?
134
+        $path = str_replace('//', '/', $path);
135
+
136
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
137
+        if (!$path || $path === '.') {
138
+            $path = '';
139
+        }
140
+
141
+        return $path;
142
+    }
143
+
144
+    /**
145
+     * Object Stores use a NoopScanner because metadata is directly stored in
146
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
147
+     *
148
+     * @param string $path
149
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
150
+     * @return \OC\Files\ObjectStore\NoopScanner
151
+     */
152
+    public function getScanner($path = '', $storage = null) {
153
+        if (!$storage) {
154
+            $storage = $this;
155
+        }
156
+        if (!isset($this->scanner)) {
157
+            $this->scanner = new NoopScanner($storage);
158
+        }
159
+        return $this->scanner;
160
+    }
161
+
162
+    public function getId() {
163
+        return $this->id;
164
+    }
165
+
166
+    public function rmdir($path) {
167
+        $path = $this->normalizePath($path);
168
+
169
+        if (!$this->is_dir($path)) {
170
+            return false;
171
+        }
172
+
173
+        if (!$this->rmObjects($path)) {
174
+            return false;
175
+        }
176
+
177
+        $this->getCache()->remove($path);
178
+
179
+        return true;
180
+    }
181
+
182
+    private function rmObjects($path) {
183
+        $children = $this->getCache()->getFolderContents($path);
184
+        foreach ($children as $child) {
185
+            if ($child['mimetype'] === 'httpd/unix-directory') {
186
+                if (!$this->rmObjects($child['path'])) {
187
+                    return false;
188
+                }
189
+            } else {
190
+                if (!$this->unlink($child['path'])) {
191
+                    return false;
192
+                }
193
+            }
194
+        }
195
+
196
+        return true;
197
+    }
198
+
199
+    public function unlink($path) {
200
+        $path = $this->normalizePath($path);
201
+        $stat = $this->stat($path);
202
+
203
+        if ($stat && isset($stat['fileid'])) {
204
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
205
+                return $this->rmdir($path);
206
+            }
207
+            try {
208
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
209
+            } catch (\Exception $ex) {
210
+                if ($ex->getCode() !== 404) {
211
+                    $this->logger->logException($ex, [
212
+                        'app' => 'objectstore',
213
+                        'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
214
+                    ]);
215
+                    return false;
216
+                }
217
+                //removing from cache is ok as it does not exist in the objectstore anyway
218
+            }
219
+            $this->getCache()->remove($path);
220
+            return true;
221
+        }
222
+        return false;
223
+    }
224
+
225
+    public function stat($path) {
226
+        $path = $this->normalizePath($path);
227
+        $cacheEntry = $this->getCache()->get($path);
228
+        if ($cacheEntry instanceof CacheEntry) {
229
+            return $cacheEntry->getData();
230
+        } else {
231
+            return false;
232
+        }
233
+    }
234
+
235
+    public function getPermissions($path) {
236
+        $stat = $this->stat($path);
237
+
238
+        if (is_array($stat) && isset($stat['permissions'])) {
239
+            return $stat['permissions'];
240
+        }
241
+
242
+        return parent::getPermissions($path);
243
+    }
244
+
245
+    /**
246
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
247
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
248
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
249
+     *
250
+     * @param int $fileId the fileid
251
+     * @return null|string the unified resource name used to identify the object
252
+     */
253
+    public function getURN($fileId) {
254
+        if (is_numeric($fileId)) {
255
+            return $this->objectPrefix . $fileId;
256
+        }
257
+        return null;
258
+    }
259
+
260
+    public function opendir($path) {
261
+        $path = $this->normalizePath($path);
262
+
263
+        try {
264
+            $files = [];
265
+            $folderContents = $this->getCache()->getFolderContents($path);
266
+            foreach ($folderContents as $file) {
267
+                $files[] = $file['name'];
268
+            }
269
+
270
+            return IteratorDirectory::wrap($files);
271
+        } catch (\Exception $e) {
272
+            $this->logger->logException($e);
273
+            return false;
274
+        }
275
+    }
276
+
277
+    public function filetype($path) {
278
+        $path = $this->normalizePath($path);
279
+        $stat = $this->stat($path);
280
+        if ($stat) {
281
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
282
+                return 'dir';
283
+            }
284
+            return 'file';
285
+        } else {
286
+            return false;
287
+        }
288
+    }
289
+
290
+    public function fopen($path, $mode) {
291
+        $path = $this->normalizePath($path);
292
+
293
+        if (strrpos($path, '.') !== false) {
294
+            $ext = substr($path, strrpos($path, '.'));
295
+        } else {
296
+            $ext = '';
297
+        }
298
+
299
+        switch ($mode) {
300
+            case 'r':
301
+            case 'rb':
302
+                $stat = $this->stat($path);
303
+                if (is_array($stat)) {
304
+                    // Reading 0 sized files is a waste of time
305
+                    if (isset($stat['size']) && $stat['size'] === 0) {
306
+                        return fopen('php://memory', $mode);
307
+                    }
308
+
309
+                    try {
310
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
311
+                    } catch (NotFoundException $e) {
312
+                        $this->logger->logException($e, [
313
+                            'app' => 'objectstore',
314
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
315
+                        ]);
316
+                        throw $e;
317
+                    } catch (\Exception $ex) {
318
+                        $this->logger->logException($ex, [
319
+                            'app' => 'objectstore',
320
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
321
+                        ]);
322
+                        return false;
323
+                    }
324
+                } else {
325
+                    return false;
326
+                }
327
+            // no break
328
+            case 'w':
329
+            case 'wb':
330
+            case 'w+':
331
+            case 'wb+':
332
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
333
+                $handle = fopen($tmpFile, $mode);
334
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
335
+                    $this->writeBack($tmpFile, $path);
336
+                });
337
+            case 'a':
338
+            case 'ab':
339
+            case 'r+':
340
+            case 'a+':
341
+            case 'x':
342
+            case 'x+':
343
+            case 'c':
344
+            case 'c+':
345
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
346
+                if ($this->file_exists($path)) {
347
+                    $source = $this->fopen($path, 'r');
348
+                    file_put_contents($tmpFile, $source);
349
+                }
350
+                $handle = fopen($tmpFile, $mode);
351
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
352
+                    $this->writeBack($tmpFile, $path);
353
+                });
354
+        }
355
+        return false;
356
+    }
357
+
358
+    public function file_exists($path) {
359
+        $path = $this->normalizePath($path);
360
+        return (bool)$this->stat($path);
361
+    }
362
+
363
+    public function rename($source, $target) {
364
+        $source = $this->normalizePath($source);
365
+        $target = $this->normalizePath($target);
366
+        $this->remove($target);
367
+        $this->getCache()->move($source, $target);
368
+        $this->touch(dirname($target));
369
+        return true;
370
+    }
371
+
372
+    public function getMimeType($path) {
373
+        $path = $this->normalizePath($path);
374
+        return parent::getMimeType($path);
375
+    }
376
+
377
+    public function touch($path, $mtime = null) {
378
+        if (is_null($mtime)) {
379
+            $mtime = time();
380
+        }
381
+
382
+        $path = $this->normalizePath($path);
383
+        $dirName = dirname($path);
384
+        $parentExists = $this->is_dir($dirName);
385
+        if (!$parentExists) {
386
+            return false;
387
+        }
388
+
389
+        $stat = $this->stat($path);
390
+        if (is_array($stat)) {
391
+            // update existing mtime in db
392
+            $stat['mtime'] = $mtime;
393
+            $this->getCache()->update($stat['fileid'], $stat);
394
+        } else {
395
+            try {
396
+                //create a empty file, need to have at least on char to make it
397
+                // work with all object storage implementations
398
+                $this->file_put_contents($path, ' ');
399
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
400
+                $stat = [
401
+                    'etag' => $this->getETag($path),
402
+                    'mimetype' => $mimeType,
403
+                    'size' => 0,
404
+                    'mtime' => $mtime,
405
+                    'storage_mtime' => $mtime,
406
+                    'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
407
+                ];
408
+                $this->getCache()->put($path, $stat);
409
+            } catch (\Exception $ex) {
410
+                $this->logger->logException($ex, [
411
+                    'app' => 'objectstore',
412
+                    'message' => 'Could not create object for ' . $path,
413
+                ]);
414
+                throw $ex;
415
+            }
416
+        }
417
+        return true;
418
+    }
419
+
420
+    public function writeBack($tmpFile, $path) {
421
+        $size = filesize($tmpFile);
422
+        $this->writeStream($path, fopen($tmpFile, 'r'), $size);
423
+    }
424
+
425
+    /**
426
+     * external changes are not supported, exclusive access to the object storage is assumed
427
+     *
428
+     * @param string $path
429
+     * @param int $time
430
+     * @return false
431
+     */
432
+    public function hasUpdated($path, $time) {
433
+        return false;
434
+    }
435
+
436
+    public function needsPartFile() {
437
+        return false;
438
+    }
439
+
440
+    public function file_put_contents($path, $data) {
441
+        $handle = $this->fopen($path, 'w+');
442
+        $result = fwrite($handle, $data);
443
+        fclose($handle);
444
+        return $result;
445
+    }
446
+
447
+    public function writeStream(string $path, $stream, int $size = null): int {
448
+        $stat = $this->stat($path);
449
+        if (empty($stat)) {
450
+            // create new file
451
+            $stat = [
452
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
453
+            ];
454
+        }
455
+        // update stat with new data
456
+        $mTime = time();
457
+        $stat['size'] = (int)$size;
458
+        $stat['mtime'] = $mTime;
459
+        $stat['storage_mtime'] = $mTime;
460
+
461
+        $mimetypeDetector = \OC::$server->getMimeTypeDetector();
462
+        $mimetype = $mimetypeDetector->detectPath($path);
463
+
464
+        $stat['mimetype'] = $mimetype;
465
+        $stat['etag'] = $this->getETag($path);
466
+
467
+        $exists = $this->getCache()->inCache($path);
468
+        $uploadPath = $exists ? $path : $path . '.part';
469
+
470
+        if ($exists) {
471
+            $fileId = $stat['fileid'];
472
+        } else {
473
+            $fileId = $this->getCache()->put($uploadPath, $stat);
474
+        }
475
+
476
+        $urn = $this->getURN($fileId);
477
+        try {
478
+            //upload to object storage
479
+            if ($size === null) {
480
+                $countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
481
+                    $this->getCache()->update($fileId, [
482
+                        'size' => $writtenSize,
483
+                    ]);
484
+                    $size = $writtenSize;
485
+                });
486
+                $this->objectStore->writeObject($urn, $countStream);
487
+                if (is_resource($countStream)) {
488
+                    fclose($countStream);
489
+                }
490
+                $stat['size'] = $size;
491
+            } else {
492
+                $this->objectStore->writeObject($urn, $stream);
493
+            }
494
+        } catch (\Exception $ex) {
495
+            if (!$exists) {
496
+                /*
497 497
 				 * Only remove the entry if we are dealing with a new file.
498 498
 				 * Else people lose access to existing files
499 499
 				 */
500
-				$this->getCache()->remove($uploadPath);
501
-				$this->logger->logException($ex, [
502
-					'app' => 'objectstore',
503
-					'message' => 'Could not create object ' . $urn . ' for ' . $path,
504
-				]);
505
-			} else {
506
-				$this->logger->logException($ex, [
507
-					'app' => 'objectstore',
508
-					'message' => 'Could not update object ' . $urn . ' for ' . $path,
509
-				]);
510
-			}
511
-			throw $ex; // make this bubble up
512
-		}
513
-
514
-		if ($exists) {
515
-			$this->getCache()->update($fileId, $stat);
516
-		} else {
517
-			if ($this->objectStore->objectExists($urn)) {
518
-				$this->getCache()->move($uploadPath, $path);
519
-			} else {
520
-				$this->getCache()->remove($uploadPath);
521
-				throw new \Exception("Object not found after writing (urn: $urn, path: $path)", 404);
522
-			}
523
-		}
524
-
525
-		return $size;
526
-	}
527
-
528
-	public function getObjectStore(): IObjectStore {
529
-		return $this->objectStore;
530
-	}
531
-
532
-	public function copy($path1, $path2) {
533
-		$path1 = $this->normalizePath($path1);
534
-		$path2 = $this->normalizePath($path2);
535
-
536
-		$cache = $this->getCache();
537
-		$sourceEntry = $cache->get($path1);
538
-		if (!$sourceEntry) {
539
-			throw new NotFoundException('Source object not found');
540
-		}
541
-
542
-		$this->copyInner($sourceEntry, $path2);
543
-
544
-		return true;
545
-	}
546
-
547
-	private function copyInner(ICacheEntry $sourceEntry, string $to) {
548
-		$cache = $this->getCache();
549
-
550
-		if ($sourceEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
551
-			if ($cache->inCache($to)) {
552
-				$cache->remove($to);
553
-			}
554
-			$this->mkdir($to);
555
-
556
-			foreach ($cache->getFolderContentsById($sourceEntry->getId()) as $child) {
557
-				$this->copyInner($child, $to . '/' . $child->getName());
558
-			}
559
-		} else {
560
-			$this->copyFile($sourceEntry, $to);
561
-		}
562
-	}
563
-
564
-	private function copyFile(ICacheEntry $sourceEntry, string $to) {
565
-		$cache = $this->getCache();
566
-
567
-		$sourceUrn = $this->getURN($sourceEntry->getId());
568
-
569
-		$cache->copyFromCache($cache, $sourceEntry, $to);
570
-		$targetEntry = $cache->get($to);
571
-
572
-		if (!$targetEntry) {
573
-			throw new \Exception('Target not in cache after copy');
574
-		}
575
-
576
-		$targetUrn = $this->getURN($targetEntry->getId());
577
-
578
-		try {
579
-			$this->objectStore->copyObject($sourceUrn, $targetUrn);
580
-		} catch (\Exception $e) {
581
-			$cache->remove($to);
582
-
583
-			throw $e;
584
-		}
585
-	}
500
+                $this->getCache()->remove($uploadPath);
501
+                $this->logger->logException($ex, [
502
+                    'app' => 'objectstore',
503
+                    'message' => 'Could not create object ' . $urn . ' for ' . $path,
504
+                ]);
505
+            } else {
506
+                $this->logger->logException($ex, [
507
+                    'app' => 'objectstore',
508
+                    'message' => 'Could not update object ' . $urn . ' for ' . $path,
509
+                ]);
510
+            }
511
+            throw $ex; // make this bubble up
512
+        }
513
+
514
+        if ($exists) {
515
+            $this->getCache()->update($fileId, $stat);
516
+        } else {
517
+            if ($this->objectStore->objectExists($urn)) {
518
+                $this->getCache()->move($uploadPath, $path);
519
+            } else {
520
+                $this->getCache()->remove($uploadPath);
521
+                throw new \Exception("Object not found after writing (urn: $urn, path: $path)", 404);
522
+            }
523
+        }
524
+
525
+        return $size;
526
+    }
527
+
528
+    public function getObjectStore(): IObjectStore {
529
+        return $this->objectStore;
530
+    }
531
+
532
+    public function copy($path1, $path2) {
533
+        $path1 = $this->normalizePath($path1);
534
+        $path2 = $this->normalizePath($path2);
535
+
536
+        $cache = $this->getCache();
537
+        $sourceEntry = $cache->get($path1);
538
+        if (!$sourceEntry) {
539
+            throw new NotFoundException('Source object not found');
540
+        }
541
+
542
+        $this->copyInner($sourceEntry, $path2);
543
+
544
+        return true;
545
+    }
546
+
547
+    private function copyInner(ICacheEntry $sourceEntry, string $to) {
548
+        $cache = $this->getCache();
549
+
550
+        if ($sourceEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
551
+            if ($cache->inCache($to)) {
552
+                $cache->remove($to);
553
+            }
554
+            $this->mkdir($to);
555
+
556
+            foreach ($cache->getFolderContentsById($sourceEntry->getId()) as $child) {
557
+                $this->copyInner($child, $to . '/' . $child->getName());
558
+            }
559
+        } else {
560
+            $this->copyFile($sourceEntry, $to);
561
+        }
562
+    }
563
+
564
+    private function copyFile(ICacheEntry $sourceEntry, string $to) {
565
+        $cache = $this->getCache();
566
+
567
+        $sourceUrn = $this->getURN($sourceEntry->getId());
568
+
569
+        $cache->copyFromCache($cache, $sourceEntry, $to);
570
+        $targetEntry = $cache->get($to);
571
+
572
+        if (!$targetEntry) {
573
+            throw new \Exception('Target not in cache after copy');
574
+        }
575
+
576
+        $targetUrn = $this->getURN($targetEntry->getId());
577
+
578
+        try {
579
+            $this->objectStore->copyObject($sourceUrn, $targetUrn);
580
+        } catch (\Exception $e) {
581
+            $cache->remove($to);
582
+
583
+            throw $e;
584
+        }
585
+    }
586 586
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Local.php 1 patch
Indentation   +510 added lines, -510 removed lines patch added patch discarded remove patch
@@ -54,514 +54,514 @@
 block discarded – undo
54 54
  * for local filestore, we only have to map the paths
55 55
  */
56 56
 class Local extends \OC\Files\Storage\Common {
57
-	protected $datadir;
58
-
59
-	protected $dataDirLength;
60
-
61
-	protected $allowSymlinks = false;
62
-
63
-	protected $realDataDir;
64
-
65
-	public function __construct($arguments) {
66
-		if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
67
-			throw new \InvalidArgumentException('No data directory set for local storage');
68
-		}
69
-		$this->datadir = str_replace('//', '/', $arguments['datadir']);
70
-		// some crazy code uses a local storage on root...
71
-		if ($this->datadir === '/') {
72
-			$this->realDataDir = $this->datadir;
73
-		} else {
74
-			$realPath = realpath($this->datadir) ?: $this->datadir;
75
-			$this->realDataDir = rtrim($realPath, '/') . '/';
76
-		}
77
-		if (substr($this->datadir, -1) !== '/') {
78
-			$this->datadir .= '/';
79
-		}
80
-		$this->dataDirLength = strlen($this->realDataDir);
81
-	}
82
-
83
-	public function __destruct() {
84
-	}
85
-
86
-	public function getId() {
87
-		return 'local::' . $this->datadir;
88
-	}
89
-
90
-	public function mkdir($path) {
91
-		return @mkdir($this->getSourcePath($path), 0777, true);
92
-	}
93
-
94
-	public function rmdir($path) {
95
-		if (!$this->isDeletable($path)) {
96
-			return false;
97
-		}
98
-		try {
99
-			$it = new \RecursiveIteratorIterator(
100
-				new \RecursiveDirectoryIterator($this->getSourcePath($path)),
101
-				\RecursiveIteratorIterator::CHILD_FIRST
102
-			);
103
-			/**
104
-			 * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
105
-			 * This bug is fixed in PHP 5.5.9 or before
106
-			 * See #8376
107
-			 */
108
-			$it->rewind();
109
-			while ($it->valid()) {
110
-				/**
111
-				 * @var \SplFileInfo $file
112
-				 */
113
-				$file = $it->current();
114
-				clearstatcache(true, $this->getSourcePath($file));
115
-				if (in_array($file->getBasename(), ['.', '..'])) {
116
-					$it->next();
117
-					continue;
118
-				} elseif ($file->isDir()) {
119
-					rmdir($file->getPathname());
120
-				} elseif ($file->isFile() || $file->isLink()) {
121
-					unlink($file->getPathname());
122
-				}
123
-				$it->next();
124
-			}
125
-			clearstatcache(true, $this->getSourcePath($path));
126
-			return rmdir($this->getSourcePath($path));
127
-		} catch (\UnexpectedValueException $e) {
128
-			return false;
129
-		}
130
-	}
131
-
132
-	public function opendir($path) {
133
-		return opendir($this->getSourcePath($path));
134
-	}
135
-
136
-	public function is_dir($path) {
137
-		if (substr($path, -1) == '/') {
138
-			$path = substr($path, 0, -1);
139
-		}
140
-		return is_dir($this->getSourcePath($path));
141
-	}
142
-
143
-	public function is_file($path) {
144
-		return is_file($this->getSourcePath($path));
145
-	}
146
-
147
-	public function stat($path) {
148
-		$fullPath = $this->getSourcePath($path);
149
-		clearstatcache(true, $fullPath);
150
-		$statResult = @stat($fullPath);
151
-		if (PHP_INT_SIZE === 4 && $statResult && !$this->is_dir($path)) {
152
-			$filesize = $this->filesize($path);
153
-			$statResult['size'] = $filesize;
154
-			$statResult[7] = $filesize;
155
-		}
156
-		return $statResult;
157
-	}
158
-
159
-	/**
160
-	 * @inheritdoc
161
-	 */
162
-	public function getMetaData($path) {
163
-		$stat = $this->stat($path);
164
-		if (!$stat) {
165
-			return null;
166
-		}
167
-
168
-		$permissions = Constants::PERMISSION_SHARE;
169
-		$statPermissions = $stat['mode'];
170
-		$isDir = ($statPermissions & 0x4000) === 0x4000;
171
-		if ($statPermissions & 0x0100) {
172
-			$permissions += Constants::PERMISSION_READ;
173
-		}
174
-		if ($statPermissions & 0x0080) {
175
-			$permissions += Constants::PERMISSION_UPDATE;
176
-			if ($isDir) {
177
-				$permissions += Constants::PERMISSION_CREATE;
178
-			}
179
-		}
180
-
181
-		if (!($path === '' || $path === '/')) { // deletable depends on the parents unix permissions
182
-			$fullPath = $this->getSourcePath($path);
183
-			$parent = dirname($fullPath);
184
-			if (is_writable($parent)) {
185
-				$permissions += Constants::PERMISSION_DELETE;
186
-			}
187
-		}
188
-
189
-		$data = [];
190
-		$data['mimetype'] = $isDir ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($path);
191
-		$data['mtime'] = $stat['mtime'];
192
-		if ($data['mtime'] === false) {
193
-			$data['mtime'] = time();
194
-		}
195
-		if ($isDir) {
196
-			$data['size'] = -1; //unknown
197
-		} else {
198
-			$data['size'] = $stat['size'];
199
-		}
200
-		$data['etag'] = $this->calculateEtag($path, $stat);
201
-		$data['storage_mtime'] = $data['mtime'];
202
-		$data['permissions'] = $permissions;
203
-		$data['name'] = basename($path);
204
-
205
-		return $data;
206
-	}
207
-
208
-	public function filetype($path) {
209
-		$filetype = filetype($this->getSourcePath($path));
210
-		if ($filetype == 'link') {
211
-			$filetype = filetype(realpath($this->getSourcePath($path)));
212
-		}
213
-		return $filetype;
214
-	}
215
-
216
-	public function filesize($path) {
217
-		if ($this->is_dir($path)) {
218
-			return 0;
219
-		}
220
-		$fullPath = $this->getSourcePath($path);
221
-		if (PHP_INT_SIZE === 4) {
222
-			$helper = new \OC\LargeFileHelper;
223
-			return $helper->getFileSize($fullPath);
224
-		}
225
-		return filesize($fullPath);
226
-	}
227
-
228
-	public function isReadable($path) {
229
-		return is_readable($this->getSourcePath($path));
230
-	}
231
-
232
-	public function isUpdatable($path) {
233
-		return is_writable($this->getSourcePath($path));
234
-	}
235
-
236
-	public function file_exists($path) {
237
-		return file_exists($this->getSourcePath($path));
238
-	}
239
-
240
-	public function filemtime($path) {
241
-		$fullPath = $this->getSourcePath($path);
242
-		clearstatcache(true, $fullPath);
243
-		if (!$this->file_exists($path)) {
244
-			return false;
245
-		}
246
-		if (PHP_INT_SIZE === 4) {
247
-			$helper = new \OC\LargeFileHelper();
248
-			return $helper->getFileMtime($fullPath);
249
-		}
250
-		return filemtime($fullPath);
251
-	}
252
-
253
-	public function touch($path, $mtime = null) {
254
-		// sets the modification time of the file to the given value.
255
-		// If mtime is nil the current time is set.
256
-		// note that the access time of the file always changes to the current time.
257
-		if ($this->file_exists($path) and !$this->isUpdatable($path)) {
258
-			return false;
259
-		}
260
-		if (!is_null($mtime)) {
261
-			$result = @touch($this->getSourcePath($path), $mtime);
262
-		} else {
263
-			$result = @touch($this->getSourcePath($path));
264
-		}
265
-		if ($result) {
266
-			clearstatcache(true, $this->getSourcePath($path));
267
-		}
268
-
269
-		return $result;
270
-	}
271
-
272
-	public function file_get_contents($path) {
273
-		return file_get_contents($this->getSourcePath($path));
274
-	}
275
-
276
-	public function file_put_contents($path, $data) {
277
-		return file_put_contents($this->getSourcePath($path), $data);
278
-	}
279
-
280
-	public function unlink($path) {
281
-		if ($this->is_dir($path)) {
282
-			return $this->rmdir($path);
283
-		} elseif ($this->is_file($path)) {
284
-			return unlink($this->getSourcePath($path));
285
-		} else {
286
-			return false;
287
-		}
288
-	}
289
-
290
-	private function treeContainsBlacklistedFile(string $path): bool {
291
-		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
292
-		foreach ($iterator as $file) {
293
-			/** @var \SplFileInfo $file */
294
-			if (Filesystem::isFileBlacklisted($file->getBasename())) {
295
-				return true;
296
-			}
297
-		}
298
-
299
-		return false;
300
-	}
301
-
302
-	public function rename($path1, $path2) {
303
-		$srcParent = dirname($path1);
304
-		$dstParent = dirname($path2);
305
-
306
-		if (!$this->isUpdatable($srcParent)) {
307
-			\OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, ILogger::ERROR);
308
-			return false;
309
-		}
310
-
311
-		if (!$this->isUpdatable($dstParent)) {
312
-			\OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, ILogger::ERROR);
313
-			return false;
314
-		}
315
-
316
-		if (!$this->file_exists($path1)) {
317
-			\OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, ILogger::ERROR);
318
-			return false;
319
-		}
320
-
321
-		if ($this->is_dir($path2)) {
322
-			$this->rmdir($path2);
323
-		} elseif ($this->is_file($path2)) {
324
-			$this->unlink($path2);
325
-		}
326
-
327
-		if ($this->is_dir($path1)) {
328
-			// we can't move folders across devices, use copy instead
329
-			$stat1 = stat(dirname($this->getSourcePath($path1)));
330
-			$stat2 = stat(dirname($this->getSourcePath($path2)));
331
-			if ($stat1['dev'] !== $stat2['dev']) {
332
-				$result = $this->copy($path1, $path2);
333
-				if ($result) {
334
-					$result &= $this->rmdir($path1);
335
-				}
336
-				return $result;
337
-			}
338
-
339
-			if ($this->treeContainsBlacklistedFile($this->getSourcePath($path1))) {
340
-				throw new ForbiddenException('Invalid path', false);
341
-			}
342
-		}
343
-
344
-		return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
345
-	}
346
-
347
-	public function copy($path1, $path2) {
348
-		if ($this->is_dir($path1)) {
349
-			return parent::copy($path1, $path2);
350
-		} else {
351
-			return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
352
-		}
353
-	}
354
-
355
-	public function fopen($path, $mode) {
356
-		return fopen($this->getSourcePath($path), $mode);
357
-	}
358
-
359
-	public function hash($type, $path, $raw = false) {
360
-		return hash_file($type, $this->getSourcePath($path), $raw);
361
-	}
362
-
363
-	public function free_space($path) {
364
-		$sourcePath = $this->getSourcePath($path);
365
-		// using !is_dir because $sourcePath might be a part file or
366
-		// non-existing file, so we'd still want to use the parent dir
367
-		// in such cases
368
-		if (!is_dir($sourcePath)) {
369
-			// disk_free_space doesn't work on files
370
-			$sourcePath = dirname($sourcePath);
371
-		}
372
-		$space = @disk_free_space($sourcePath);
373
-		if ($space === false || is_null($space)) {
374
-			return \OCP\Files\FileInfo::SPACE_UNKNOWN;
375
-		}
376
-		return $space;
377
-	}
378
-
379
-	public function search($query) {
380
-		return $this->searchInDir($query);
381
-	}
382
-
383
-	public function getLocalFile($path) {
384
-		return $this->getSourcePath($path);
385
-	}
386
-
387
-	public function getLocalFolder($path) {
388
-		return $this->getSourcePath($path);
389
-	}
390
-
391
-	/**
392
-	 * @param string $query
393
-	 * @param string $dir
394
-	 * @return array
395
-	 */
396
-	protected function searchInDir($query, $dir = '') {
397
-		$files = [];
398
-		$physicalDir = $this->getSourcePath($dir);
399
-		foreach (scandir($physicalDir) as $item) {
400
-			if (\OC\Files\Filesystem::isIgnoredDir($item)) {
401
-				continue;
402
-			}
403
-			$physicalItem = $physicalDir . '/' . $item;
404
-
405
-			if (strstr(strtolower($item), strtolower($query)) !== false) {
406
-				$files[] = $dir . '/' . $item;
407
-			}
408
-			if (is_dir($physicalItem)) {
409
-				$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
410
-			}
411
-		}
412
-		return $files;
413
-	}
414
-
415
-	/**
416
-	 * check if a file or folder has been updated since $time
417
-	 *
418
-	 * @param string $path
419
-	 * @param int $time
420
-	 * @return bool
421
-	 */
422
-	public function hasUpdated($path, $time) {
423
-		if ($this->file_exists($path)) {
424
-			return $this->filemtime($path) > $time;
425
-		} else {
426
-			return true;
427
-		}
428
-	}
429
-
430
-	/**
431
-	 * Get the source path (on disk) of a given path
432
-	 *
433
-	 * @param string $path
434
-	 * @return string
435
-	 * @throws ForbiddenException
436
-	 */
437
-	public function getSourcePath($path) {
438
-		if (Filesystem::isFileBlacklisted($path)) {
439
-			throw new ForbiddenException('Invalid path', false);
440
-		}
441
-
442
-		$fullPath = $this->datadir . $path;
443
-		$currentPath = $path;
444
-		if ($this->allowSymlinks || $currentPath === '') {
445
-			return $fullPath;
446
-		}
447
-		$pathToResolve = $fullPath;
448
-		$realPath = realpath($pathToResolve);
449
-		while ($realPath === false) { // for non existing files check the parent directory
450
-			$currentPath = dirname($currentPath);
451
-			if ($currentPath === '' || $currentPath === '.') {
452
-				return $fullPath;
453
-			}
454
-			$realPath = realpath($this->datadir . $currentPath);
455
-		}
456
-		if ($realPath) {
457
-			$realPath = $realPath . '/';
458
-		}
459
-		if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
460
-			return $fullPath;
461
-		}
462
-
463
-		\OCP\Util::writeLog('core', "Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", ILogger::ERROR);
464
-		throw new ForbiddenException('Following symlinks is not allowed', false);
465
-	}
466
-
467
-	/**
468
-	 * {@inheritdoc}
469
-	 */
470
-	public function isLocal() {
471
-		return true;
472
-	}
473
-
474
-	/**
475
-	 * get the ETag for a file or folder
476
-	 *
477
-	 * @param string $path
478
-	 * @return string
479
-	 */
480
-	public function getETag($path) {
481
-		return $this->calculateEtag($path, $this->stat($path));
482
-	}
483
-
484
-	private function calculateEtag(string $path, array $stat): string {
485
-		if ($stat['mode'] & 0x4000) { // is_dir
486
-			return parent::getETag($path);
487
-		} else {
488
-			if ($stat === false) {
489
-				return md5('');
490
-			}
491
-
492
-			$toHash = '';
493
-			if (isset($stat['mtime'])) {
494
-				$toHash .= $stat['mtime'];
495
-			}
496
-			if (isset($stat['ino'])) {
497
-				$toHash .= $stat['ino'];
498
-			}
499
-			if (isset($stat['dev'])) {
500
-				$toHash .= $stat['dev'];
501
-			}
502
-			if (isset($stat['size'])) {
503
-				$toHash .= $stat['size'];
504
-			}
505
-
506
-			return md5($toHash);
507
-		}
508
-	}
509
-
510
-	/**
511
-	 * @param IStorage $sourceStorage
512
-	 * @param string $sourceInternalPath
513
-	 * @param string $targetInternalPath
514
-	 * @param bool $preserveMtime
515
-	 * @return bool
516
-	 */
517
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
518
-		if ($sourceStorage->instanceOfStorage(Local::class)) {
519
-			if ($sourceStorage->instanceOfStorage(Jail::class)) {
520
-				/**
521
-				 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
522
-				 */
523
-				$sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
524
-			}
525
-			/**
526
-			 * @var \OC\Files\Storage\Local $sourceStorage
527
-			 */
528
-			$rootStorage = new Local(['datadir' => '/']);
529
-			return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
530
-		} else {
531
-			return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
532
-		}
533
-	}
534
-
535
-	/**
536
-	 * @param IStorage $sourceStorage
537
-	 * @param string $sourceInternalPath
538
-	 * @param string $targetInternalPath
539
-	 * @return bool
540
-	 */
541
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
542
-		if ($sourceStorage->instanceOfStorage(Local::class)) {
543
-			if ($sourceStorage->instanceOfStorage(Jail::class)) {
544
-				/**
545
-				 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
546
-				 */
547
-				$sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
548
-			}
549
-			/**
550
-			 * @var \OC\Files\Storage\Local $sourceStorage
551
-			 */
552
-			$rootStorage = new Local(['datadir' => '/']);
553
-			return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
554
-		} else {
555
-			return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
556
-		}
557
-	}
558
-
559
-	public function writeStream(string $path, $stream, int $size = null): int {
560
-		$result = $this->file_put_contents($path, $stream);
561
-		if ($result === false) {
562
-			throw new GenericFileException("Failed write steam to $path");
563
-		} else {
564
-			return $result;
565
-		}
566
-	}
57
+    protected $datadir;
58
+
59
+    protected $dataDirLength;
60
+
61
+    protected $allowSymlinks = false;
62
+
63
+    protected $realDataDir;
64
+
65
+    public function __construct($arguments) {
66
+        if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
67
+            throw new \InvalidArgumentException('No data directory set for local storage');
68
+        }
69
+        $this->datadir = str_replace('//', '/', $arguments['datadir']);
70
+        // some crazy code uses a local storage on root...
71
+        if ($this->datadir === '/') {
72
+            $this->realDataDir = $this->datadir;
73
+        } else {
74
+            $realPath = realpath($this->datadir) ?: $this->datadir;
75
+            $this->realDataDir = rtrim($realPath, '/') . '/';
76
+        }
77
+        if (substr($this->datadir, -1) !== '/') {
78
+            $this->datadir .= '/';
79
+        }
80
+        $this->dataDirLength = strlen($this->realDataDir);
81
+    }
82
+
83
+    public function __destruct() {
84
+    }
85
+
86
+    public function getId() {
87
+        return 'local::' . $this->datadir;
88
+    }
89
+
90
+    public function mkdir($path) {
91
+        return @mkdir($this->getSourcePath($path), 0777, true);
92
+    }
93
+
94
+    public function rmdir($path) {
95
+        if (!$this->isDeletable($path)) {
96
+            return false;
97
+        }
98
+        try {
99
+            $it = new \RecursiveIteratorIterator(
100
+                new \RecursiveDirectoryIterator($this->getSourcePath($path)),
101
+                \RecursiveIteratorIterator::CHILD_FIRST
102
+            );
103
+            /**
104
+             * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
105
+             * This bug is fixed in PHP 5.5.9 or before
106
+             * See #8376
107
+             */
108
+            $it->rewind();
109
+            while ($it->valid()) {
110
+                /**
111
+                 * @var \SplFileInfo $file
112
+                 */
113
+                $file = $it->current();
114
+                clearstatcache(true, $this->getSourcePath($file));
115
+                if (in_array($file->getBasename(), ['.', '..'])) {
116
+                    $it->next();
117
+                    continue;
118
+                } elseif ($file->isDir()) {
119
+                    rmdir($file->getPathname());
120
+                } elseif ($file->isFile() || $file->isLink()) {
121
+                    unlink($file->getPathname());
122
+                }
123
+                $it->next();
124
+            }
125
+            clearstatcache(true, $this->getSourcePath($path));
126
+            return rmdir($this->getSourcePath($path));
127
+        } catch (\UnexpectedValueException $e) {
128
+            return false;
129
+        }
130
+    }
131
+
132
+    public function opendir($path) {
133
+        return opendir($this->getSourcePath($path));
134
+    }
135
+
136
+    public function is_dir($path) {
137
+        if (substr($path, -1) == '/') {
138
+            $path = substr($path, 0, -1);
139
+        }
140
+        return is_dir($this->getSourcePath($path));
141
+    }
142
+
143
+    public function is_file($path) {
144
+        return is_file($this->getSourcePath($path));
145
+    }
146
+
147
+    public function stat($path) {
148
+        $fullPath = $this->getSourcePath($path);
149
+        clearstatcache(true, $fullPath);
150
+        $statResult = @stat($fullPath);
151
+        if (PHP_INT_SIZE === 4 && $statResult && !$this->is_dir($path)) {
152
+            $filesize = $this->filesize($path);
153
+            $statResult['size'] = $filesize;
154
+            $statResult[7] = $filesize;
155
+        }
156
+        return $statResult;
157
+    }
158
+
159
+    /**
160
+     * @inheritdoc
161
+     */
162
+    public function getMetaData($path) {
163
+        $stat = $this->stat($path);
164
+        if (!$stat) {
165
+            return null;
166
+        }
167
+
168
+        $permissions = Constants::PERMISSION_SHARE;
169
+        $statPermissions = $stat['mode'];
170
+        $isDir = ($statPermissions & 0x4000) === 0x4000;
171
+        if ($statPermissions & 0x0100) {
172
+            $permissions += Constants::PERMISSION_READ;
173
+        }
174
+        if ($statPermissions & 0x0080) {
175
+            $permissions += Constants::PERMISSION_UPDATE;
176
+            if ($isDir) {
177
+                $permissions += Constants::PERMISSION_CREATE;
178
+            }
179
+        }
180
+
181
+        if (!($path === '' || $path === '/')) { // deletable depends on the parents unix permissions
182
+            $fullPath = $this->getSourcePath($path);
183
+            $parent = dirname($fullPath);
184
+            if (is_writable($parent)) {
185
+                $permissions += Constants::PERMISSION_DELETE;
186
+            }
187
+        }
188
+
189
+        $data = [];
190
+        $data['mimetype'] = $isDir ? 'httpd/unix-directory' : \OC::$server->getMimeTypeDetector()->detectPath($path);
191
+        $data['mtime'] = $stat['mtime'];
192
+        if ($data['mtime'] === false) {
193
+            $data['mtime'] = time();
194
+        }
195
+        if ($isDir) {
196
+            $data['size'] = -1; //unknown
197
+        } else {
198
+            $data['size'] = $stat['size'];
199
+        }
200
+        $data['etag'] = $this->calculateEtag($path, $stat);
201
+        $data['storage_mtime'] = $data['mtime'];
202
+        $data['permissions'] = $permissions;
203
+        $data['name'] = basename($path);
204
+
205
+        return $data;
206
+    }
207
+
208
+    public function filetype($path) {
209
+        $filetype = filetype($this->getSourcePath($path));
210
+        if ($filetype == 'link') {
211
+            $filetype = filetype(realpath($this->getSourcePath($path)));
212
+        }
213
+        return $filetype;
214
+    }
215
+
216
+    public function filesize($path) {
217
+        if ($this->is_dir($path)) {
218
+            return 0;
219
+        }
220
+        $fullPath = $this->getSourcePath($path);
221
+        if (PHP_INT_SIZE === 4) {
222
+            $helper = new \OC\LargeFileHelper;
223
+            return $helper->getFileSize($fullPath);
224
+        }
225
+        return filesize($fullPath);
226
+    }
227
+
228
+    public function isReadable($path) {
229
+        return is_readable($this->getSourcePath($path));
230
+    }
231
+
232
+    public function isUpdatable($path) {
233
+        return is_writable($this->getSourcePath($path));
234
+    }
235
+
236
+    public function file_exists($path) {
237
+        return file_exists($this->getSourcePath($path));
238
+    }
239
+
240
+    public function filemtime($path) {
241
+        $fullPath = $this->getSourcePath($path);
242
+        clearstatcache(true, $fullPath);
243
+        if (!$this->file_exists($path)) {
244
+            return false;
245
+        }
246
+        if (PHP_INT_SIZE === 4) {
247
+            $helper = new \OC\LargeFileHelper();
248
+            return $helper->getFileMtime($fullPath);
249
+        }
250
+        return filemtime($fullPath);
251
+    }
252
+
253
+    public function touch($path, $mtime = null) {
254
+        // sets the modification time of the file to the given value.
255
+        // If mtime is nil the current time is set.
256
+        // note that the access time of the file always changes to the current time.
257
+        if ($this->file_exists($path) and !$this->isUpdatable($path)) {
258
+            return false;
259
+        }
260
+        if (!is_null($mtime)) {
261
+            $result = @touch($this->getSourcePath($path), $mtime);
262
+        } else {
263
+            $result = @touch($this->getSourcePath($path));
264
+        }
265
+        if ($result) {
266
+            clearstatcache(true, $this->getSourcePath($path));
267
+        }
268
+
269
+        return $result;
270
+    }
271
+
272
+    public function file_get_contents($path) {
273
+        return file_get_contents($this->getSourcePath($path));
274
+    }
275
+
276
+    public function file_put_contents($path, $data) {
277
+        return file_put_contents($this->getSourcePath($path), $data);
278
+    }
279
+
280
+    public function unlink($path) {
281
+        if ($this->is_dir($path)) {
282
+            return $this->rmdir($path);
283
+        } elseif ($this->is_file($path)) {
284
+            return unlink($this->getSourcePath($path));
285
+        } else {
286
+            return false;
287
+        }
288
+    }
289
+
290
+    private function treeContainsBlacklistedFile(string $path): bool {
291
+        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
292
+        foreach ($iterator as $file) {
293
+            /** @var \SplFileInfo $file */
294
+            if (Filesystem::isFileBlacklisted($file->getBasename())) {
295
+                return true;
296
+            }
297
+        }
298
+
299
+        return false;
300
+    }
301
+
302
+    public function rename($path1, $path2) {
303
+        $srcParent = dirname($path1);
304
+        $dstParent = dirname($path2);
305
+
306
+        if (!$this->isUpdatable($srcParent)) {
307
+            \OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, ILogger::ERROR);
308
+            return false;
309
+        }
310
+
311
+        if (!$this->isUpdatable($dstParent)) {
312
+            \OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, ILogger::ERROR);
313
+            return false;
314
+        }
315
+
316
+        if (!$this->file_exists($path1)) {
317
+            \OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, ILogger::ERROR);
318
+            return false;
319
+        }
320
+
321
+        if ($this->is_dir($path2)) {
322
+            $this->rmdir($path2);
323
+        } elseif ($this->is_file($path2)) {
324
+            $this->unlink($path2);
325
+        }
326
+
327
+        if ($this->is_dir($path1)) {
328
+            // we can't move folders across devices, use copy instead
329
+            $stat1 = stat(dirname($this->getSourcePath($path1)));
330
+            $stat2 = stat(dirname($this->getSourcePath($path2)));
331
+            if ($stat1['dev'] !== $stat2['dev']) {
332
+                $result = $this->copy($path1, $path2);
333
+                if ($result) {
334
+                    $result &= $this->rmdir($path1);
335
+                }
336
+                return $result;
337
+            }
338
+
339
+            if ($this->treeContainsBlacklistedFile($this->getSourcePath($path1))) {
340
+                throw new ForbiddenException('Invalid path', false);
341
+            }
342
+        }
343
+
344
+        return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
345
+    }
346
+
347
+    public function copy($path1, $path2) {
348
+        if ($this->is_dir($path1)) {
349
+            return parent::copy($path1, $path2);
350
+        } else {
351
+            return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
352
+        }
353
+    }
354
+
355
+    public function fopen($path, $mode) {
356
+        return fopen($this->getSourcePath($path), $mode);
357
+    }
358
+
359
+    public function hash($type, $path, $raw = false) {
360
+        return hash_file($type, $this->getSourcePath($path), $raw);
361
+    }
362
+
363
+    public function free_space($path) {
364
+        $sourcePath = $this->getSourcePath($path);
365
+        // using !is_dir because $sourcePath might be a part file or
366
+        // non-existing file, so we'd still want to use the parent dir
367
+        // in such cases
368
+        if (!is_dir($sourcePath)) {
369
+            // disk_free_space doesn't work on files
370
+            $sourcePath = dirname($sourcePath);
371
+        }
372
+        $space = @disk_free_space($sourcePath);
373
+        if ($space === false || is_null($space)) {
374
+            return \OCP\Files\FileInfo::SPACE_UNKNOWN;
375
+        }
376
+        return $space;
377
+    }
378
+
379
+    public function search($query) {
380
+        return $this->searchInDir($query);
381
+    }
382
+
383
+    public function getLocalFile($path) {
384
+        return $this->getSourcePath($path);
385
+    }
386
+
387
+    public function getLocalFolder($path) {
388
+        return $this->getSourcePath($path);
389
+    }
390
+
391
+    /**
392
+     * @param string $query
393
+     * @param string $dir
394
+     * @return array
395
+     */
396
+    protected function searchInDir($query, $dir = '') {
397
+        $files = [];
398
+        $physicalDir = $this->getSourcePath($dir);
399
+        foreach (scandir($physicalDir) as $item) {
400
+            if (\OC\Files\Filesystem::isIgnoredDir($item)) {
401
+                continue;
402
+            }
403
+            $physicalItem = $physicalDir . '/' . $item;
404
+
405
+            if (strstr(strtolower($item), strtolower($query)) !== false) {
406
+                $files[] = $dir . '/' . $item;
407
+            }
408
+            if (is_dir($physicalItem)) {
409
+                $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
410
+            }
411
+        }
412
+        return $files;
413
+    }
414
+
415
+    /**
416
+     * check if a file or folder has been updated since $time
417
+     *
418
+     * @param string $path
419
+     * @param int $time
420
+     * @return bool
421
+     */
422
+    public function hasUpdated($path, $time) {
423
+        if ($this->file_exists($path)) {
424
+            return $this->filemtime($path) > $time;
425
+        } else {
426
+            return true;
427
+        }
428
+    }
429
+
430
+    /**
431
+     * Get the source path (on disk) of a given path
432
+     *
433
+     * @param string $path
434
+     * @return string
435
+     * @throws ForbiddenException
436
+     */
437
+    public function getSourcePath($path) {
438
+        if (Filesystem::isFileBlacklisted($path)) {
439
+            throw new ForbiddenException('Invalid path', false);
440
+        }
441
+
442
+        $fullPath = $this->datadir . $path;
443
+        $currentPath = $path;
444
+        if ($this->allowSymlinks || $currentPath === '') {
445
+            return $fullPath;
446
+        }
447
+        $pathToResolve = $fullPath;
448
+        $realPath = realpath($pathToResolve);
449
+        while ($realPath === false) { // for non existing files check the parent directory
450
+            $currentPath = dirname($currentPath);
451
+            if ($currentPath === '' || $currentPath === '.') {
452
+                return $fullPath;
453
+            }
454
+            $realPath = realpath($this->datadir . $currentPath);
455
+        }
456
+        if ($realPath) {
457
+            $realPath = $realPath . '/';
458
+        }
459
+        if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
460
+            return $fullPath;
461
+        }
462
+
463
+        \OCP\Util::writeLog('core', "Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", ILogger::ERROR);
464
+        throw new ForbiddenException('Following symlinks is not allowed', false);
465
+    }
466
+
467
+    /**
468
+     * {@inheritdoc}
469
+     */
470
+    public function isLocal() {
471
+        return true;
472
+    }
473
+
474
+    /**
475
+     * get the ETag for a file or folder
476
+     *
477
+     * @param string $path
478
+     * @return string
479
+     */
480
+    public function getETag($path) {
481
+        return $this->calculateEtag($path, $this->stat($path));
482
+    }
483
+
484
+    private function calculateEtag(string $path, array $stat): string {
485
+        if ($stat['mode'] & 0x4000) { // is_dir
486
+            return parent::getETag($path);
487
+        } else {
488
+            if ($stat === false) {
489
+                return md5('');
490
+            }
491
+
492
+            $toHash = '';
493
+            if (isset($stat['mtime'])) {
494
+                $toHash .= $stat['mtime'];
495
+            }
496
+            if (isset($stat['ino'])) {
497
+                $toHash .= $stat['ino'];
498
+            }
499
+            if (isset($stat['dev'])) {
500
+                $toHash .= $stat['dev'];
501
+            }
502
+            if (isset($stat['size'])) {
503
+                $toHash .= $stat['size'];
504
+            }
505
+
506
+            return md5($toHash);
507
+        }
508
+    }
509
+
510
+    /**
511
+     * @param IStorage $sourceStorage
512
+     * @param string $sourceInternalPath
513
+     * @param string $targetInternalPath
514
+     * @param bool $preserveMtime
515
+     * @return bool
516
+     */
517
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
518
+        if ($sourceStorage->instanceOfStorage(Local::class)) {
519
+            if ($sourceStorage->instanceOfStorage(Jail::class)) {
520
+                /**
521
+                 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
522
+                 */
523
+                $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
524
+            }
525
+            /**
526
+             * @var \OC\Files\Storage\Local $sourceStorage
527
+             */
528
+            $rootStorage = new Local(['datadir' => '/']);
529
+            return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
530
+        } else {
531
+            return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
532
+        }
533
+    }
534
+
535
+    /**
536
+     * @param IStorage $sourceStorage
537
+     * @param string $sourceInternalPath
538
+     * @param string $targetInternalPath
539
+     * @return bool
540
+     */
541
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
542
+        if ($sourceStorage->instanceOfStorage(Local::class)) {
543
+            if ($sourceStorage->instanceOfStorage(Jail::class)) {
544
+                /**
545
+                 * @var \OC\Files\Storage\Wrapper\Jail $sourceStorage
546
+                 */
547
+                $sourceInternalPath = $sourceStorage->getUnjailedPath($sourceInternalPath);
548
+            }
549
+            /**
550
+             * @var \OC\Files\Storage\Local $sourceStorage
551
+             */
552
+            $rootStorage = new Local(['datadir' => '/']);
553
+            return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
554
+        } else {
555
+            return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
556
+        }
557
+    }
558
+
559
+    public function writeStream(string $path, $stream, int $size = null): int {
560
+        $result = $this->file_put_contents($path, $stream);
561
+        if ($result === false) {
562
+            throw new GenericFileException("Failed write steam to $path");
563
+        } else {
564
+            return $result;
565
+        }
566
+    }
567 567
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Flysystem.php 1 patch
Indentation   +206 added lines, -206 removed lines patch added patch discarded remove patch
@@ -37,228 +37,228 @@
 block discarded – undo
37 37
  * To use: subclass and call $this->buildFlysystem with the flysystem adapter of choice
38 38
  */
39 39
 abstract class Flysystem extends Common {
40
-	/**
41
-	 * @var Filesystem
42
-	 */
43
-	protected $flysystem;
40
+    /**
41
+     * @var Filesystem
42
+     */
43
+    protected $flysystem;
44 44
 
45
-	/**
46
-	 * @var string
47
-	 */
48
-	protected $root = '';
45
+    /**
46
+     * @var string
47
+     */
48
+    protected $root = '';
49 49
 
50
-	/**
51
-	 * Initialize the storage backend with a flyssytem adapter
52
-	 *
53
-	 * @param \League\Flysystem\AdapterInterface $adapter
54
-	 */
55
-	protected function buildFlySystem(AdapterInterface $adapter) {
56
-		$this->flysystem = new Filesystem($adapter);
57
-		$this->flysystem->addPlugin(new GetWithMetadata());
58
-	}
50
+    /**
51
+     * Initialize the storage backend with a flyssytem adapter
52
+     *
53
+     * @param \League\Flysystem\AdapterInterface $adapter
54
+     */
55
+    protected function buildFlySystem(AdapterInterface $adapter) {
56
+        $this->flysystem = new Filesystem($adapter);
57
+        $this->flysystem->addPlugin(new GetWithMetadata());
58
+    }
59 59
 
60
-	protected function buildPath($path) {
61
-		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
62
-		return ltrim($fullPath, '/');
63
-	}
60
+    protected function buildPath($path) {
61
+        $fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
62
+        return ltrim($fullPath, '/');
63
+    }
64 64
 
65
-	/**
66
-	 * {@inheritdoc}
67
-	 */
68
-	public function file_get_contents($path) {
69
-		return $this->flysystem->read($this->buildPath($path));
70
-	}
65
+    /**
66
+     * {@inheritdoc}
67
+     */
68
+    public function file_get_contents($path) {
69
+        return $this->flysystem->read($this->buildPath($path));
70
+    }
71 71
 
72
-	/**
73
-	 * {@inheritdoc}
74
-	 */
75
-	public function file_put_contents($path, $data) {
76
-		$result = $this->flysystem->put($this->buildPath($path), $data);
77
-		if ($result === true) {
78
-			return strlen($data);
79
-		}
80
-		return $result;
81
-	}
72
+    /**
73
+     * {@inheritdoc}
74
+     */
75
+    public function file_put_contents($path, $data) {
76
+        $result = $this->flysystem->put($this->buildPath($path), $data);
77
+        if ($result === true) {
78
+            return strlen($data);
79
+        }
80
+        return $result;
81
+    }
82 82
 
83
-	/**
84
-	 * {@inheritdoc}
85
-	 */
86
-	public function file_exists($path) {
87
-		return $this->flysystem->has($this->buildPath($path));
88
-	}
83
+    /**
84
+     * {@inheritdoc}
85
+     */
86
+    public function file_exists($path) {
87
+        return $this->flysystem->has($this->buildPath($path));
88
+    }
89 89
 
90
-	/**
91
-	 * {@inheritdoc}
92
-	 */
93
-	public function unlink($path) {
94
-		if ($this->is_dir($path)) {
95
-			return $this->rmdir($path);
96
-		}
97
-		try {
98
-			return $this->flysystem->delete($this->buildPath($path));
99
-		} catch (FileNotFoundException $e) {
100
-			return false;
101
-		}
102
-	}
90
+    /**
91
+     * {@inheritdoc}
92
+     */
93
+    public function unlink($path) {
94
+        if ($this->is_dir($path)) {
95
+            return $this->rmdir($path);
96
+        }
97
+        try {
98
+            return $this->flysystem->delete($this->buildPath($path));
99
+        } catch (FileNotFoundException $e) {
100
+            return false;
101
+        }
102
+    }
103 103
 
104
-	/**
105
-	 * {@inheritdoc}
106
-	 */
107
-	public function rename($source, $target) {
108
-		if ($this->file_exists($target)) {
109
-			$this->unlink($target);
110
-		}
111
-		return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
112
-	}
104
+    /**
105
+     * {@inheritdoc}
106
+     */
107
+    public function rename($source, $target) {
108
+        if ($this->file_exists($target)) {
109
+            $this->unlink($target);
110
+        }
111
+        return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
112
+    }
113 113
 
114
-	/**
115
-	 * {@inheritdoc}
116
-	 */
117
-	public function copy($source, $target) {
118
-		if ($this->file_exists($target)) {
119
-			$this->unlink($target);
120
-		}
121
-		return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
122
-	}
114
+    /**
115
+     * {@inheritdoc}
116
+     */
117
+    public function copy($source, $target) {
118
+        if ($this->file_exists($target)) {
119
+            $this->unlink($target);
120
+        }
121
+        return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
122
+    }
123 123
 
124
-	/**
125
-	 * {@inheritdoc}
126
-	 */
127
-	public function filesize($path) {
128
-		if ($this->is_dir($path)) {
129
-			return 0;
130
-		} else {
131
-			return $this->flysystem->getSize($this->buildPath($path));
132
-		}
133
-	}
124
+    /**
125
+     * {@inheritdoc}
126
+     */
127
+    public function filesize($path) {
128
+        if ($this->is_dir($path)) {
129
+            return 0;
130
+        } else {
131
+            return $this->flysystem->getSize($this->buildPath($path));
132
+        }
133
+    }
134 134
 
135
-	/**
136
-	 * {@inheritdoc}
137
-	 */
138
-	public function mkdir($path) {
139
-		if ($this->file_exists($path)) {
140
-			return false;
141
-		}
142
-		return $this->flysystem->createDir($this->buildPath($path));
143
-	}
135
+    /**
136
+     * {@inheritdoc}
137
+     */
138
+    public function mkdir($path) {
139
+        if ($this->file_exists($path)) {
140
+            return false;
141
+        }
142
+        return $this->flysystem->createDir($this->buildPath($path));
143
+    }
144 144
 
145
-	/**
146
-	 * {@inheritdoc}
147
-	 */
148
-	public function filemtime($path) {
149
-		return $this->flysystem->getTimestamp($this->buildPath($path));
150
-	}
145
+    /**
146
+     * {@inheritdoc}
147
+     */
148
+    public function filemtime($path) {
149
+        return $this->flysystem->getTimestamp($this->buildPath($path));
150
+    }
151 151
 
152
-	/**
153
-	 * {@inheritdoc}
154
-	 */
155
-	public function rmdir($path) {
156
-		try {
157
-			return @$this->flysystem->deleteDir($this->buildPath($path));
158
-		} catch (FileNotFoundException $e) {
159
-			return false;
160
-		}
161
-	}
152
+    /**
153
+     * {@inheritdoc}
154
+     */
155
+    public function rmdir($path) {
156
+        try {
157
+            return @$this->flysystem->deleteDir($this->buildPath($path));
158
+        } catch (FileNotFoundException $e) {
159
+            return false;
160
+        }
161
+    }
162 162
 
163
-	/**
164
-	 * {@inheritdoc}
165
-	 */
166
-	public function opendir($path) {
167
-		try {
168
-			$content = $this->flysystem->listContents($this->buildPath($path));
169
-		} catch (FileNotFoundException $e) {
170
-			return false;
171
-		}
172
-		$names = array_map(function ($object) {
173
-			return $object['basename'];
174
-		}, $content);
175
-		return IteratorDirectory::wrap($names);
176
-	}
163
+    /**
164
+     * {@inheritdoc}
165
+     */
166
+    public function opendir($path) {
167
+        try {
168
+            $content = $this->flysystem->listContents($this->buildPath($path));
169
+        } catch (FileNotFoundException $e) {
170
+            return false;
171
+        }
172
+        $names = array_map(function ($object) {
173
+            return $object['basename'];
174
+        }, $content);
175
+        return IteratorDirectory::wrap($names);
176
+    }
177 177
 
178
-	/**
179
-	 * {@inheritdoc}
180
-	 */
181
-	public function fopen($path, $mode) {
182
-		$fullPath = $this->buildPath($path);
183
-		$useExisting = true;
184
-		switch ($mode) {
185
-			case 'r':
186
-			case 'rb':
187
-				try {
188
-					return $this->flysystem->readStream($fullPath);
189
-				} catch (FileNotFoundException $e) {
190
-					return false;
191
-				}
192
-			case 'w':
193
-			case 'w+':
194
-			case 'wb':
195
-			case 'wb+':
196
-				$useExisting = false;
197
-				// no break
198
-			case 'a':
199
-			case 'ab':
200
-			case 'r+':
201
-			case 'a+':
202
-			case 'x':
203
-			case 'x+':
204
-			case 'c':
205
-			case 'c+':
206
-				//emulate these
207
-				if ($useExisting and $this->file_exists($path)) {
208
-					if (!$this->isUpdatable($path)) {
209
-						return false;
210
-					}
211
-					$tmpFile = $this->getCachedFile($path);
212
-				} else {
213
-					if (!$this->isCreatable(dirname($path))) {
214
-						return false;
215
-					}
216
-					$tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
217
-				}
218
-				$source = fopen($tmpFile, $mode);
219
-				return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
220
-					$this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
221
-					unlink($tmpFile);
222
-				});
223
-		}
224
-		return false;
225
-	}
178
+    /**
179
+     * {@inheritdoc}
180
+     */
181
+    public function fopen($path, $mode) {
182
+        $fullPath = $this->buildPath($path);
183
+        $useExisting = true;
184
+        switch ($mode) {
185
+            case 'r':
186
+            case 'rb':
187
+                try {
188
+                    return $this->flysystem->readStream($fullPath);
189
+                } catch (FileNotFoundException $e) {
190
+                    return false;
191
+                }
192
+            case 'w':
193
+            case 'w+':
194
+            case 'wb':
195
+            case 'wb+':
196
+                $useExisting = false;
197
+                // no break
198
+            case 'a':
199
+            case 'ab':
200
+            case 'r+':
201
+            case 'a+':
202
+            case 'x':
203
+            case 'x+':
204
+            case 'c':
205
+            case 'c+':
206
+                //emulate these
207
+                if ($useExisting and $this->file_exists($path)) {
208
+                    if (!$this->isUpdatable($path)) {
209
+                        return false;
210
+                    }
211
+                    $tmpFile = $this->getCachedFile($path);
212
+                } else {
213
+                    if (!$this->isCreatable(dirname($path))) {
214
+                        return false;
215
+                    }
216
+                    $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
217
+                }
218
+                $source = fopen($tmpFile, $mode);
219
+                return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
220
+                    $this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
221
+                    unlink($tmpFile);
222
+                });
223
+        }
224
+        return false;
225
+    }
226 226
 
227
-	/**
228
-	 * {@inheritdoc}
229
-	 */
230
-	public function touch($path, $mtime = null) {
231
-		if ($this->file_exists($path)) {
232
-			return false;
233
-		} else {
234
-			$this->file_put_contents($path, '');
235
-			return true;
236
-		}
237
-	}
227
+    /**
228
+     * {@inheritdoc}
229
+     */
230
+    public function touch($path, $mtime = null) {
231
+        if ($this->file_exists($path)) {
232
+            return false;
233
+        } else {
234
+            $this->file_put_contents($path, '');
235
+            return true;
236
+        }
237
+    }
238 238
 
239
-	/**
240
-	 * {@inheritdoc}
241
-	 */
242
-	public function stat($path) {
243
-		$info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
244
-		return [
245
-			'mtime' => $info['timestamp'],
246
-			'size' => $info['size']
247
-		];
248
-	}
239
+    /**
240
+     * {@inheritdoc}
241
+     */
242
+    public function stat($path) {
243
+        $info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
244
+        return [
245
+            'mtime' => $info['timestamp'],
246
+            'size' => $info['size']
247
+        ];
248
+    }
249 249
 
250
-	/**
251
-	 * {@inheritdoc}
252
-	 */
253
-	public function filetype($path) {
254
-		if ($path === '' or $path === '/' or $path === '.') {
255
-			return 'dir';
256
-		}
257
-		try {
258
-			$info = $this->flysystem->getMetadata($this->buildPath($path));
259
-		} catch (FileNotFoundException $e) {
260
-			return false;
261
-		}
262
-		return $info['type'];
263
-	}
250
+    /**
251
+     * {@inheritdoc}
252
+     */
253
+    public function filetype($path) {
254
+        if ($path === '' or $path === '/' or $path === '.') {
255
+            return 'dir';
256
+        }
257
+        try {
258
+            $info = $this->flysystem->getMetadata($this->buildPath($path));
259
+        } catch (FileNotFoundException $e) {
260
+            return false;
261
+        }
262
+        return $info['type'];
263
+    }
264 264
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/DAV.php 1 patch
Indentation   +809 added lines, -809 removed lines patch added patch discarded remove patch
@@ -64,813 +64,813 @@
 block discarded – undo
64 64
  * @package OC\Files\Storage
65 65
  */
66 66
 class DAV extends Common {
67
-	/** @var string */
68
-	protected $password;
69
-	/** @var string */
70
-	protected $user;
71
-	/** @var string */
72
-	protected $authType;
73
-	/** @var string */
74
-	protected $host;
75
-	/** @var bool */
76
-	protected $secure;
77
-	/** @var string */
78
-	protected $root;
79
-	/** @var string */
80
-	protected $certPath;
81
-	/** @var bool */
82
-	protected $ready;
83
-	/** @var Client */
84
-	protected $client;
85
-	/** @var ArrayCache */
86
-	protected $statCache;
87
-	/** @var IClientService */
88
-	protected $httpClientService;
89
-	/** @var ICertificateManager */
90
-	protected $certManager;
91
-
92
-	/**
93
-	 * @param array $params
94
-	 * @throws \Exception
95
-	 */
96
-	public function __construct($params) {
97
-		$this->statCache = new ArrayCache();
98
-		$this->httpClientService = \OC::$server->getHTTPClientService();
99
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
100
-			$host = $params['host'];
101
-			//remove leading http[s], will be generated in createBaseUri()
102
-			if (substr($host, 0, 8) == "https://") {
103
-				$host = substr($host, 8);
104
-			} elseif (substr($host, 0, 7) == "http://") {
105
-				$host = substr($host, 7);
106
-			}
107
-			$this->host = $host;
108
-			$this->user = $params['user'];
109
-			$this->password = $params['password'];
110
-			if (isset($params['authType'])) {
111
-				$this->authType = $params['authType'];
112
-			}
113
-			if (isset($params['secure'])) {
114
-				if (is_string($params['secure'])) {
115
-					$this->secure = ($params['secure'] === 'true');
116
-				} else {
117
-					$this->secure = (bool)$params['secure'];
118
-				}
119
-			} else {
120
-				$this->secure = false;
121
-			}
122
-			if ($this->secure === true) {
123
-				// inject mock for testing
124
-				$this->certManager = \OC::$server->getCertificateManager();
125
-			}
126
-			$this->root = $params['root'] ?? '/';
127
-			$this->root = '/' . ltrim($this->root, '/');
128
-			$this->root = rtrim($this->root, '/') . '/';
129
-		} else {
130
-			throw new \Exception('Invalid webdav storage configuration');
131
-		}
132
-	}
133
-
134
-	protected function init() {
135
-		if ($this->ready) {
136
-			return;
137
-		}
138
-		$this->ready = true;
139
-
140
-		$settings = [
141
-			'baseUri' => $this->createBaseUri(),
142
-			'userName' => $this->user,
143
-			'password' => $this->password,
144
-		];
145
-		if (isset($this->authType)) {
146
-			$settings['authType'] = $this->authType;
147
-		}
148
-
149
-		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
150
-		if ($proxy !== '') {
151
-			$settings['proxy'] = $proxy;
152
-		}
153
-
154
-		$this->client = new Client($settings);
155
-		$this->client->setThrowExceptions(true);
156
-
157
-		if ($this->secure === true) {
158
-			$certPath = $this->certManager->getAbsoluteBundlePath();
159
-			if (file_exists($certPath)) {
160
-				$this->certPath = $certPath;
161
-			}
162
-			if ($this->certPath) {
163
-				$this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
164
-			}
165
-		}
166
-	}
167
-
168
-	/**
169
-	 * Clear the stat cache
170
-	 */
171
-	public function clearStatCache() {
172
-		$this->statCache->clear();
173
-	}
174
-
175
-	/** {@inheritdoc} */
176
-	public function getId() {
177
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
178
-	}
179
-
180
-	/** {@inheritdoc} */
181
-	public function createBaseUri() {
182
-		$baseUri = 'http';
183
-		if ($this->secure) {
184
-			$baseUri .= 's';
185
-		}
186
-		$baseUri .= '://' . $this->host . $this->root;
187
-		return $baseUri;
188
-	}
189
-
190
-	/** {@inheritdoc} */
191
-	public function mkdir($path) {
192
-		$this->init();
193
-		$path = $this->cleanPath($path);
194
-		$result = $this->simpleResponse('MKCOL', $path, null, 201);
195
-		if ($result) {
196
-			$this->statCache->set($path, true);
197
-		}
198
-		return $result;
199
-	}
200
-
201
-	/** {@inheritdoc} */
202
-	public function rmdir($path) {
203
-		$this->init();
204
-		$path = $this->cleanPath($path);
205
-		// FIXME: some WebDAV impl return 403 when trying to DELETE
206
-		// a non-empty folder
207
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
208
-		$this->statCache->clear($path . '/');
209
-		$this->statCache->remove($path);
210
-		return $result;
211
-	}
212
-
213
-	/** {@inheritdoc} */
214
-	public function opendir($path) {
215
-		$this->init();
216
-		$path = $this->cleanPath($path);
217
-		try {
218
-			$response = $this->client->propFind(
219
-				$this->encodePath($path),
220
-				['{DAV:}getetag'],
221
-				1
222
-			);
223
-			if ($response === false) {
224
-				return false;
225
-			}
226
-			$content = [];
227
-			$files = array_keys($response);
228
-			array_shift($files); //the first entry is the current directory
229
-
230
-			if (!$this->statCache->hasKey($path)) {
231
-				$this->statCache->set($path, true);
232
-			}
233
-			foreach ($files as $file) {
234
-				$file = urldecode($file);
235
-				// do not store the real entry, we might not have all properties
236
-				if (!$this->statCache->hasKey($path)) {
237
-					$this->statCache->set($file, true);
238
-				}
239
-				$file = basename($file);
240
-				$content[] = $file;
241
-			}
242
-			return IteratorDirectory::wrap($content);
243
-		} catch (\Exception $e) {
244
-			$this->convertException($e, $path);
245
-		}
246
-		return false;
247
-	}
248
-
249
-	/**
250
-	 * Propfind call with cache handling.
251
-	 *
252
-	 * First checks if information is cached.
253
-	 * If not, request it from the server then store to cache.
254
-	 *
255
-	 * @param string $path path to propfind
256
-	 *
257
-	 * @return array|boolean propfind response or false if the entry was not found
258
-	 *
259
-	 * @throws ClientHttpException
260
-	 */
261
-	protected function propfind($path) {
262
-		$path = $this->cleanPath($path);
263
-		$cachedResponse = $this->statCache->get($path);
264
-		// we either don't know it, or we know it exists but need more details
265
-		if (is_null($cachedResponse) || $cachedResponse === true) {
266
-			$this->init();
267
-			try {
268
-				$response = $this->client->propFind(
269
-					$this->encodePath($path),
270
-					[
271
-						'{DAV:}getlastmodified',
272
-						'{DAV:}getcontentlength',
273
-						'{DAV:}getcontenttype',
274
-						'{http://owncloud.org/ns}permissions',
275
-						'{http://open-collaboration-services.org/ns}share-permissions',
276
-						'{DAV:}resourcetype',
277
-						'{DAV:}getetag',
278
-					]
279
-				);
280
-				$this->statCache->set($path, $response);
281
-			} catch (ClientHttpException $e) {
282
-				if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
283
-					$this->statCache->clear($path . '/');
284
-					$this->statCache->set($path, false);
285
-					return false;
286
-				}
287
-				$this->convertException($e, $path);
288
-			} catch (\Exception $e) {
289
-				$this->convertException($e, $path);
290
-			}
291
-		} else {
292
-			$response = $cachedResponse;
293
-		}
294
-		return $response;
295
-	}
296
-
297
-	/** {@inheritdoc} */
298
-	public function filetype($path) {
299
-		try {
300
-			$response = $this->propfind($path);
301
-			if ($response === false) {
302
-				return false;
303
-			}
304
-			$responseType = [];
305
-			if (isset($response["{DAV:}resourcetype"])) {
306
-				/** @var ResourceType[] $response */
307
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
308
-			}
309
-			return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
310
-		} catch (\Exception $e) {
311
-			$this->convertException($e, $path);
312
-		}
313
-		return false;
314
-	}
315
-
316
-	/** {@inheritdoc} */
317
-	public function file_exists($path) {
318
-		try {
319
-			$path = $this->cleanPath($path);
320
-			$cachedState = $this->statCache->get($path);
321
-			if ($cachedState === false) {
322
-				// we know the file doesn't exist
323
-				return false;
324
-			} elseif (!is_null($cachedState)) {
325
-				return true;
326
-			}
327
-			// need to get from server
328
-			return ($this->propfind($path) !== false);
329
-		} catch (\Exception $e) {
330
-			$this->convertException($e, $path);
331
-		}
332
-		return false;
333
-	}
334
-
335
-	/** {@inheritdoc} */
336
-	public function unlink($path) {
337
-		$this->init();
338
-		$path = $this->cleanPath($path);
339
-		$result = $this->simpleResponse('DELETE', $path, null, 204);
340
-		$this->statCache->clear($path . '/');
341
-		$this->statCache->remove($path);
342
-		return $result;
343
-	}
344
-
345
-	/** {@inheritdoc} */
346
-	public function fopen($path, $mode) {
347
-		$this->init();
348
-		$path = $this->cleanPath($path);
349
-		switch ($mode) {
350
-			case 'r':
351
-			case 'rb':
352
-				try {
353
-					$response = $this->httpClientService
354
-						->newClient()
355
-						->get($this->createBaseUri() . $this->encodePath($path), [
356
-							'auth' => [$this->user, $this->password],
357
-							'stream' => true
358
-						]);
359
-				} catch (\GuzzleHttp\Exception\ClientException $e) {
360
-					if ($e->getResponse() instanceof ResponseInterface
361
-						&& $e->getResponse()->getStatusCode() === 404) {
362
-						return false;
363
-					} else {
364
-						throw $e;
365
-					}
366
-				}
367
-
368
-				if ($response->getStatusCode() !== Http::STATUS_OK) {
369
-					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
370
-						throw new \OCP\Lock\LockedException($path);
371
-					} else {
372
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), ILogger::ERROR);
373
-					}
374
-				}
375
-
376
-				return $response->getBody();
377
-			case 'w':
378
-			case 'wb':
379
-			case 'a':
380
-			case 'ab':
381
-			case 'r+':
382
-			case 'w+':
383
-			case 'wb+':
384
-			case 'a+':
385
-			case 'x':
386
-			case 'x+':
387
-			case 'c':
388
-			case 'c+':
389
-				//emulate these
390
-				$tempManager = \OC::$server->getTempManager();
391
-				if (strrpos($path, '.') !== false) {
392
-					$ext = substr($path, strrpos($path, '.'));
393
-				} else {
394
-					$ext = '';
395
-				}
396
-				if ($this->file_exists($path)) {
397
-					if (!$this->isUpdatable($path)) {
398
-						return false;
399
-					}
400
-					if ($mode === 'w' or $mode === 'w+') {
401
-						$tmpFile = $tempManager->getTemporaryFile($ext);
402
-					} else {
403
-						$tmpFile = $this->getCachedFile($path);
404
-					}
405
-				} else {
406
-					if (!$this->isCreatable(dirname($path))) {
407
-						return false;
408
-					}
409
-					$tmpFile = $tempManager->getTemporaryFile($ext);
410
-				}
411
-				$handle = fopen($tmpFile, $mode);
412
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
413
-					$this->writeBack($tmpFile, $path);
414
-				});
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * @param string $tmpFile
420
-	 */
421
-	public function writeBack($tmpFile, $path) {
422
-		$this->uploadFile($tmpFile, $path);
423
-		unlink($tmpFile);
424
-	}
425
-
426
-	/** {@inheritdoc} */
427
-	public function free_space($path) {
428
-		$this->init();
429
-		$path = $this->cleanPath($path);
430
-		try {
431
-			// TODO: cacheable ?
432
-			$response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
433
-			if ($response === false) {
434
-				return FileInfo::SPACE_UNKNOWN;
435
-			}
436
-			if (isset($response['{DAV:}quota-available-bytes'])) {
437
-				return (int)$response['{DAV:}quota-available-bytes'];
438
-			} else {
439
-				return FileInfo::SPACE_UNKNOWN;
440
-			}
441
-		} catch (\Exception $e) {
442
-			return FileInfo::SPACE_UNKNOWN;
443
-		}
444
-	}
445
-
446
-	/** {@inheritdoc} */
447
-	public function touch($path, $mtime = null) {
448
-		$this->init();
449
-		if (is_null($mtime)) {
450
-			$mtime = time();
451
-		}
452
-		$path = $this->cleanPath($path);
453
-
454
-		// if file exists, update the mtime, else create a new empty file
455
-		if ($this->file_exists($path)) {
456
-			try {
457
-				$this->statCache->remove($path);
458
-				$this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
459
-				// non-owncloud clients might not have accepted the property, need to recheck it
460
-				$response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
461
-				if ($response === false) {
462
-					return false;
463
-				}
464
-				if (isset($response['{DAV:}getlastmodified'])) {
465
-					$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
466
-					if ($remoteMtime !== $mtime) {
467
-						// server has not accepted the mtime
468
-						return false;
469
-					}
470
-				}
471
-			} catch (ClientHttpException $e) {
472
-				if ($e->getHttpStatus() === 501) {
473
-					return false;
474
-				}
475
-				$this->convertException($e, $path);
476
-				return false;
477
-			} catch (\Exception $e) {
478
-				$this->convertException($e, $path);
479
-				return false;
480
-			}
481
-		} else {
482
-			$this->file_put_contents($path, '');
483
-		}
484
-		return true;
485
-	}
486
-
487
-	/**
488
-	 * @param string $path
489
-	 * @param mixed $data
490
-	 * @return int|false
491
-	 */
492
-	public function file_put_contents($path, $data) {
493
-		$path = $this->cleanPath($path);
494
-		$result = parent::file_put_contents($path, $data);
495
-		$this->statCache->remove($path);
496
-		return $result;
497
-	}
498
-
499
-	/**
500
-	 * @param string $path
501
-	 * @param string $target
502
-	 */
503
-	protected function uploadFile($path, $target) {
504
-		$this->init();
505
-
506
-		// invalidate
507
-		$target = $this->cleanPath($target);
508
-		$this->statCache->remove($target);
509
-		$source = fopen($path, 'r');
510
-
511
-		$this->httpClientService
512
-			->newClient()
513
-			->put($this->createBaseUri() . $this->encodePath($target), [
514
-				'body' => $source,
515
-				'auth' => [$this->user, $this->password]
516
-			]);
517
-
518
-		$this->removeCachedFile($target);
519
-	}
520
-
521
-	/** {@inheritdoc} */
522
-	public function rename($path1, $path2) {
523
-		$this->init();
524
-		$path1 = $this->cleanPath($path1);
525
-		$path2 = $this->cleanPath($path2);
526
-		try {
527
-			// overwrite directory ?
528
-			if ($this->is_dir($path2)) {
529
-				// needs trailing slash in destination
530
-				$path2 = rtrim($path2, '/') . '/';
531
-			}
532
-			$this->client->request(
533
-				'MOVE',
534
-				$this->encodePath($path1),
535
-				null,
536
-				[
537
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
538
-				]
539
-			);
540
-			$this->statCache->clear($path1 . '/');
541
-			$this->statCache->clear($path2 . '/');
542
-			$this->statCache->set($path1, false);
543
-			$this->statCache->set($path2, true);
544
-			$this->removeCachedFile($path1);
545
-			$this->removeCachedFile($path2);
546
-			return true;
547
-		} catch (\Exception $e) {
548
-			$this->convertException($e);
549
-		}
550
-		return false;
551
-	}
552
-
553
-	/** {@inheritdoc} */
554
-	public function copy($path1, $path2) {
555
-		$this->init();
556
-		$path1 = $this->cleanPath($path1);
557
-		$path2 = $this->cleanPath($path2);
558
-		try {
559
-			// overwrite directory ?
560
-			if ($this->is_dir($path2)) {
561
-				// needs trailing slash in destination
562
-				$path2 = rtrim($path2, '/') . '/';
563
-			}
564
-			$this->client->request(
565
-				'COPY',
566
-				$this->encodePath($path1),
567
-				null,
568
-				[
569
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
570
-				]
571
-			);
572
-			$this->statCache->clear($path2 . '/');
573
-			$this->statCache->set($path2, true);
574
-			$this->removeCachedFile($path2);
575
-			return true;
576
-		} catch (\Exception $e) {
577
-			$this->convertException($e);
578
-		}
579
-		return false;
580
-	}
581
-
582
-	/** {@inheritdoc} */
583
-	public function stat($path) {
584
-		try {
585
-			$response = $this->propfind($path);
586
-			if (!$response) {
587
-				return false;
588
-			}
589
-			return [
590
-				'mtime' => strtotime($response['{DAV:}getlastmodified']),
591
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
592
-			];
593
-		} catch (\Exception $e) {
594
-			$this->convertException($e, $path);
595
-		}
596
-		return [];
597
-	}
598
-
599
-	/** {@inheritdoc} */
600
-	public function getMimeType($path) {
601
-		$remoteMimetype = $this->getMimeTypeFromRemote($path);
602
-		if ($remoteMimetype === 'application/octet-stream') {
603
-			return \OC::$server->getMimeTypeDetector()->detectPath($path);
604
-		} else {
605
-			return $remoteMimetype;
606
-		}
607
-	}
608
-
609
-	public function getMimeTypeFromRemote($path) {
610
-		try {
611
-			$response = $this->propfind($path);
612
-			if ($response === false) {
613
-				return false;
614
-			}
615
-			$responseType = [];
616
-			if (isset($response["{DAV:}resourcetype"])) {
617
-				/** @var ResourceType[] $response */
618
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
619
-			}
620
-			$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
621
-			if ($type == 'dir') {
622
-				return 'httpd/unix-directory';
623
-			} elseif (isset($response['{DAV:}getcontenttype'])) {
624
-				return $response['{DAV:}getcontenttype'];
625
-			} else {
626
-				return 'application/octet-stream';
627
-			}
628
-		} catch (\Exception $e) {
629
-			return false;
630
-		}
631
-	}
632
-
633
-	/**
634
-	 * @param string $path
635
-	 * @return string
636
-	 */
637
-	public function cleanPath($path) {
638
-		if ($path === '') {
639
-			return $path;
640
-		}
641
-		$path = Filesystem::normalizePath($path);
642
-		// remove leading slash
643
-		return substr($path, 1);
644
-	}
645
-
646
-	/**
647
-	 * URL encodes the given path but keeps the slashes
648
-	 *
649
-	 * @param string $path to encode
650
-	 * @return string encoded path
651
-	 */
652
-	protected function encodePath($path) {
653
-		// slashes need to stay
654
-		return str_replace('%2F', '/', rawurlencode($path));
655
-	}
656
-
657
-	/**
658
-	 * @param string $method
659
-	 * @param string $path
660
-	 * @param string|resource|null $body
661
-	 * @param int $expected
662
-	 * @return bool
663
-	 * @throws StorageInvalidException
664
-	 * @throws StorageNotAvailableException
665
-	 */
666
-	protected function simpleResponse($method, $path, $body, $expected) {
667
-		$path = $this->cleanPath($path);
668
-		try {
669
-			$response = $this->client->request($method, $this->encodePath($path), $body);
670
-			return $response['statusCode'] == $expected;
671
-		} catch (ClientHttpException $e) {
672
-			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
673
-				$this->statCache->clear($path . '/');
674
-				$this->statCache->set($path, false);
675
-				return false;
676
-			}
677
-
678
-			$this->convertException($e, $path);
679
-		} catch (\Exception $e) {
680
-			$this->convertException($e, $path);
681
-		}
682
-		return false;
683
-	}
684
-
685
-	/**
686
-	 * check if curl is installed
687
-	 */
688
-	public static function checkDependencies() {
689
-		return true;
690
-	}
691
-
692
-	/** {@inheritdoc} */
693
-	public function isUpdatable($path) {
694
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
695
-	}
696
-
697
-	/** {@inheritdoc} */
698
-	public function isCreatable($path) {
699
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
700
-	}
701
-
702
-	/** {@inheritdoc} */
703
-	public function isSharable($path) {
704
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
705
-	}
706
-
707
-	/** {@inheritdoc} */
708
-	public function isDeletable($path) {
709
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
710
-	}
711
-
712
-	/** {@inheritdoc} */
713
-	public function getPermissions($path) {
714
-		$this->init();
715
-		$path = $this->cleanPath($path);
716
-		$response = $this->propfind($path);
717
-		if ($response === false) {
718
-			return 0;
719
-		}
720
-		if (isset($response['{http://owncloud.org/ns}permissions'])) {
721
-			return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
722
-		} elseif ($this->is_dir($path)) {
723
-			return Constants::PERMISSION_ALL;
724
-		} elseif ($this->file_exists($path)) {
725
-			return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
726
-		} else {
727
-			return 0;
728
-		}
729
-	}
730
-
731
-	/** {@inheritdoc} */
732
-	public function getETag($path) {
733
-		$this->init();
734
-		$path = $this->cleanPath($path);
735
-		$response = $this->propfind($path);
736
-		if ($response === false) {
737
-			return null;
738
-		}
739
-		if (isset($response['{DAV:}getetag'])) {
740
-			$etag = trim($response['{DAV:}getetag'], '"');
741
-			if (strlen($etag) > 40) {
742
-				$etag = md5($etag);
743
-			}
744
-			return $etag;
745
-		}
746
-		return parent::getEtag($path);
747
-	}
748
-
749
-	/**
750
-	 * @param string $permissionsString
751
-	 * @return int
752
-	 */
753
-	protected function parsePermissions($permissionsString) {
754
-		$permissions = Constants::PERMISSION_READ;
755
-		if (strpos($permissionsString, 'R') !== false) {
756
-			$permissions |= Constants::PERMISSION_SHARE;
757
-		}
758
-		if (strpos($permissionsString, 'D') !== false) {
759
-			$permissions |= Constants::PERMISSION_DELETE;
760
-		}
761
-		if (strpos($permissionsString, 'W') !== false) {
762
-			$permissions |= Constants::PERMISSION_UPDATE;
763
-		}
764
-		if (strpos($permissionsString, 'CK') !== false) {
765
-			$permissions |= Constants::PERMISSION_CREATE;
766
-			$permissions |= Constants::PERMISSION_UPDATE;
767
-		}
768
-		return $permissions;
769
-	}
770
-
771
-	/**
772
-	 * check if a file or folder has been updated since $time
773
-	 *
774
-	 * @param string $path
775
-	 * @param int $time
776
-	 * @throws \OCP\Files\StorageNotAvailableException
777
-	 * @return bool
778
-	 */
779
-	public function hasUpdated($path, $time) {
780
-		$this->init();
781
-		$path = $this->cleanPath($path);
782
-		try {
783
-			// force refresh for $path
784
-			$this->statCache->remove($path);
785
-			$response = $this->propfind($path);
786
-			if ($response === false) {
787
-				if ($path === '') {
788
-					// if root is gone it means the storage is not available
789
-					throw new StorageNotAvailableException('root is gone');
790
-				}
791
-				return false;
792
-			}
793
-			if (isset($response['{DAV:}getetag'])) {
794
-				$cachedData = $this->getCache()->get($path);
795
-				$etag = null;
796
-				if (isset($response['{DAV:}getetag'])) {
797
-					$etag = trim($response['{DAV:}getetag'], '"');
798
-				}
799
-				if (!empty($etag) && $cachedData['etag'] !== $etag) {
800
-					return true;
801
-				} elseif (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
802
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
803
-					return $sharePermissions !== $cachedData['permissions'];
804
-				} elseif (isset($response['{http://owncloud.org/ns}permissions'])) {
805
-					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
806
-					return $permissions !== $cachedData['permissions'];
807
-				} else {
808
-					return false;
809
-				}
810
-			} else {
811
-				$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
812
-				return $remoteMtime > $time;
813
-			}
814
-		} catch (ClientHttpException $e) {
815
-			if ($e->getHttpStatus() === 405) {
816
-				if ($path === '') {
817
-					// if root is gone it means the storage is not available
818
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
819
-				}
820
-				return false;
821
-			}
822
-			$this->convertException($e, $path);
823
-			return false;
824
-		} catch (\Exception $e) {
825
-			$this->convertException($e, $path);
826
-			return false;
827
-		}
828
-	}
829
-
830
-	/**
831
-	 * Interpret the given exception and decide whether it is due to an
832
-	 * unavailable storage, invalid storage or other.
833
-	 * This will either throw StorageInvalidException, StorageNotAvailableException
834
-	 * or do nothing.
835
-	 *
836
-	 * @param Exception $e sabre exception
837
-	 * @param string $path optional path from the operation
838
-	 *
839
-	 * @throws StorageInvalidException if the storage is invalid, for example
840
-	 * when the authentication expired or is invalid
841
-	 * @throws StorageNotAvailableException if the storage is not available,
842
-	 * which might be temporary
843
-	 * @throws ForbiddenException if the action is not allowed
844
-	 */
845
-	protected function convertException(Exception $e, $path = '') {
846
-		\OC::$server->getLogger()->logException($e, ['app' => 'files_external', 'level' => ILogger::DEBUG]);
847
-		if ($e instanceof ClientHttpException) {
848
-			if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
849
-				throw new \OCP\Lock\LockedException($path);
850
-			}
851
-			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
852
-				// either password was changed or was invalid all along
853
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
854
-			} elseif ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
855
-				// ignore exception for MethodNotAllowed, false will be returned
856
-				return;
857
-			} elseif ($e->getHttpStatus() === Http::STATUS_FORBIDDEN) {
858
-				// The operation is forbidden. Fail somewhat gracefully
859
-				throw new ForbiddenException(get_class($e) . ':' . $e->getMessage(), false);
860
-			}
861
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
862
-		} elseif ($e instanceof ClientException) {
863
-			// connection timeout or refused, server could be temporarily down
864
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
865
-		} elseif ($e instanceof \InvalidArgumentException) {
866
-			// parse error because the server returned HTML instead of XML,
867
-			// possibly temporarily down
868
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
869
-		} elseif (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
870
-			// rethrow
871
-			throw $e;
872
-		}
873
-
874
-		// TODO: only log for now, but in the future need to wrap/rethrow exception
875
-	}
67
+    /** @var string */
68
+    protected $password;
69
+    /** @var string */
70
+    protected $user;
71
+    /** @var string */
72
+    protected $authType;
73
+    /** @var string */
74
+    protected $host;
75
+    /** @var bool */
76
+    protected $secure;
77
+    /** @var string */
78
+    protected $root;
79
+    /** @var string */
80
+    protected $certPath;
81
+    /** @var bool */
82
+    protected $ready;
83
+    /** @var Client */
84
+    protected $client;
85
+    /** @var ArrayCache */
86
+    protected $statCache;
87
+    /** @var IClientService */
88
+    protected $httpClientService;
89
+    /** @var ICertificateManager */
90
+    protected $certManager;
91
+
92
+    /**
93
+     * @param array $params
94
+     * @throws \Exception
95
+     */
96
+    public function __construct($params) {
97
+        $this->statCache = new ArrayCache();
98
+        $this->httpClientService = \OC::$server->getHTTPClientService();
99
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
100
+            $host = $params['host'];
101
+            //remove leading http[s], will be generated in createBaseUri()
102
+            if (substr($host, 0, 8) == "https://") {
103
+                $host = substr($host, 8);
104
+            } elseif (substr($host, 0, 7) == "http://") {
105
+                $host = substr($host, 7);
106
+            }
107
+            $this->host = $host;
108
+            $this->user = $params['user'];
109
+            $this->password = $params['password'];
110
+            if (isset($params['authType'])) {
111
+                $this->authType = $params['authType'];
112
+            }
113
+            if (isset($params['secure'])) {
114
+                if (is_string($params['secure'])) {
115
+                    $this->secure = ($params['secure'] === 'true');
116
+                } else {
117
+                    $this->secure = (bool)$params['secure'];
118
+                }
119
+            } else {
120
+                $this->secure = false;
121
+            }
122
+            if ($this->secure === true) {
123
+                // inject mock for testing
124
+                $this->certManager = \OC::$server->getCertificateManager();
125
+            }
126
+            $this->root = $params['root'] ?? '/';
127
+            $this->root = '/' . ltrim($this->root, '/');
128
+            $this->root = rtrim($this->root, '/') . '/';
129
+        } else {
130
+            throw new \Exception('Invalid webdav storage configuration');
131
+        }
132
+    }
133
+
134
+    protected function init() {
135
+        if ($this->ready) {
136
+            return;
137
+        }
138
+        $this->ready = true;
139
+
140
+        $settings = [
141
+            'baseUri' => $this->createBaseUri(),
142
+            'userName' => $this->user,
143
+            'password' => $this->password,
144
+        ];
145
+        if (isset($this->authType)) {
146
+            $settings['authType'] = $this->authType;
147
+        }
148
+
149
+        $proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
150
+        if ($proxy !== '') {
151
+            $settings['proxy'] = $proxy;
152
+        }
153
+
154
+        $this->client = new Client($settings);
155
+        $this->client->setThrowExceptions(true);
156
+
157
+        if ($this->secure === true) {
158
+            $certPath = $this->certManager->getAbsoluteBundlePath();
159
+            if (file_exists($certPath)) {
160
+                $this->certPath = $certPath;
161
+            }
162
+            if ($this->certPath) {
163
+                $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
164
+            }
165
+        }
166
+    }
167
+
168
+    /**
169
+     * Clear the stat cache
170
+     */
171
+    public function clearStatCache() {
172
+        $this->statCache->clear();
173
+    }
174
+
175
+    /** {@inheritdoc} */
176
+    public function getId() {
177
+        return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
178
+    }
179
+
180
+    /** {@inheritdoc} */
181
+    public function createBaseUri() {
182
+        $baseUri = 'http';
183
+        if ($this->secure) {
184
+            $baseUri .= 's';
185
+        }
186
+        $baseUri .= '://' . $this->host . $this->root;
187
+        return $baseUri;
188
+    }
189
+
190
+    /** {@inheritdoc} */
191
+    public function mkdir($path) {
192
+        $this->init();
193
+        $path = $this->cleanPath($path);
194
+        $result = $this->simpleResponse('MKCOL', $path, null, 201);
195
+        if ($result) {
196
+            $this->statCache->set($path, true);
197
+        }
198
+        return $result;
199
+    }
200
+
201
+    /** {@inheritdoc} */
202
+    public function rmdir($path) {
203
+        $this->init();
204
+        $path = $this->cleanPath($path);
205
+        // FIXME: some WebDAV impl return 403 when trying to DELETE
206
+        // a non-empty folder
207
+        $result = $this->simpleResponse('DELETE', $path . '/', null, 204);
208
+        $this->statCache->clear($path . '/');
209
+        $this->statCache->remove($path);
210
+        return $result;
211
+    }
212
+
213
+    /** {@inheritdoc} */
214
+    public function opendir($path) {
215
+        $this->init();
216
+        $path = $this->cleanPath($path);
217
+        try {
218
+            $response = $this->client->propFind(
219
+                $this->encodePath($path),
220
+                ['{DAV:}getetag'],
221
+                1
222
+            );
223
+            if ($response === false) {
224
+                return false;
225
+            }
226
+            $content = [];
227
+            $files = array_keys($response);
228
+            array_shift($files); //the first entry is the current directory
229
+
230
+            if (!$this->statCache->hasKey($path)) {
231
+                $this->statCache->set($path, true);
232
+            }
233
+            foreach ($files as $file) {
234
+                $file = urldecode($file);
235
+                // do not store the real entry, we might not have all properties
236
+                if (!$this->statCache->hasKey($path)) {
237
+                    $this->statCache->set($file, true);
238
+                }
239
+                $file = basename($file);
240
+                $content[] = $file;
241
+            }
242
+            return IteratorDirectory::wrap($content);
243
+        } catch (\Exception $e) {
244
+            $this->convertException($e, $path);
245
+        }
246
+        return false;
247
+    }
248
+
249
+    /**
250
+     * Propfind call with cache handling.
251
+     *
252
+     * First checks if information is cached.
253
+     * If not, request it from the server then store to cache.
254
+     *
255
+     * @param string $path path to propfind
256
+     *
257
+     * @return array|boolean propfind response or false if the entry was not found
258
+     *
259
+     * @throws ClientHttpException
260
+     */
261
+    protected function propfind($path) {
262
+        $path = $this->cleanPath($path);
263
+        $cachedResponse = $this->statCache->get($path);
264
+        // we either don't know it, or we know it exists but need more details
265
+        if (is_null($cachedResponse) || $cachedResponse === true) {
266
+            $this->init();
267
+            try {
268
+                $response = $this->client->propFind(
269
+                    $this->encodePath($path),
270
+                    [
271
+                        '{DAV:}getlastmodified',
272
+                        '{DAV:}getcontentlength',
273
+                        '{DAV:}getcontenttype',
274
+                        '{http://owncloud.org/ns}permissions',
275
+                        '{http://open-collaboration-services.org/ns}share-permissions',
276
+                        '{DAV:}resourcetype',
277
+                        '{DAV:}getetag',
278
+                    ]
279
+                );
280
+                $this->statCache->set($path, $response);
281
+            } catch (ClientHttpException $e) {
282
+                if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
283
+                    $this->statCache->clear($path . '/');
284
+                    $this->statCache->set($path, false);
285
+                    return false;
286
+                }
287
+                $this->convertException($e, $path);
288
+            } catch (\Exception $e) {
289
+                $this->convertException($e, $path);
290
+            }
291
+        } else {
292
+            $response = $cachedResponse;
293
+        }
294
+        return $response;
295
+    }
296
+
297
+    /** {@inheritdoc} */
298
+    public function filetype($path) {
299
+        try {
300
+            $response = $this->propfind($path);
301
+            if ($response === false) {
302
+                return false;
303
+            }
304
+            $responseType = [];
305
+            if (isset($response["{DAV:}resourcetype"])) {
306
+                /** @var ResourceType[] $response */
307
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
308
+            }
309
+            return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
310
+        } catch (\Exception $e) {
311
+            $this->convertException($e, $path);
312
+        }
313
+        return false;
314
+    }
315
+
316
+    /** {@inheritdoc} */
317
+    public function file_exists($path) {
318
+        try {
319
+            $path = $this->cleanPath($path);
320
+            $cachedState = $this->statCache->get($path);
321
+            if ($cachedState === false) {
322
+                // we know the file doesn't exist
323
+                return false;
324
+            } elseif (!is_null($cachedState)) {
325
+                return true;
326
+            }
327
+            // need to get from server
328
+            return ($this->propfind($path) !== false);
329
+        } catch (\Exception $e) {
330
+            $this->convertException($e, $path);
331
+        }
332
+        return false;
333
+    }
334
+
335
+    /** {@inheritdoc} */
336
+    public function unlink($path) {
337
+        $this->init();
338
+        $path = $this->cleanPath($path);
339
+        $result = $this->simpleResponse('DELETE', $path, null, 204);
340
+        $this->statCache->clear($path . '/');
341
+        $this->statCache->remove($path);
342
+        return $result;
343
+    }
344
+
345
+    /** {@inheritdoc} */
346
+    public function fopen($path, $mode) {
347
+        $this->init();
348
+        $path = $this->cleanPath($path);
349
+        switch ($mode) {
350
+            case 'r':
351
+            case 'rb':
352
+                try {
353
+                    $response = $this->httpClientService
354
+                        ->newClient()
355
+                        ->get($this->createBaseUri() . $this->encodePath($path), [
356
+                            'auth' => [$this->user, $this->password],
357
+                            'stream' => true
358
+                        ]);
359
+                } catch (\GuzzleHttp\Exception\ClientException $e) {
360
+                    if ($e->getResponse() instanceof ResponseInterface
361
+                        && $e->getResponse()->getStatusCode() === 404) {
362
+                        return false;
363
+                    } else {
364
+                        throw $e;
365
+                    }
366
+                }
367
+
368
+                if ($response->getStatusCode() !== Http::STATUS_OK) {
369
+                    if ($response->getStatusCode() === Http::STATUS_LOCKED) {
370
+                        throw new \OCP\Lock\LockedException($path);
371
+                    } else {
372
+                        Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), ILogger::ERROR);
373
+                    }
374
+                }
375
+
376
+                return $response->getBody();
377
+            case 'w':
378
+            case 'wb':
379
+            case 'a':
380
+            case 'ab':
381
+            case 'r+':
382
+            case 'w+':
383
+            case 'wb+':
384
+            case 'a+':
385
+            case 'x':
386
+            case 'x+':
387
+            case 'c':
388
+            case 'c+':
389
+                //emulate these
390
+                $tempManager = \OC::$server->getTempManager();
391
+                if (strrpos($path, '.') !== false) {
392
+                    $ext = substr($path, strrpos($path, '.'));
393
+                } else {
394
+                    $ext = '';
395
+                }
396
+                if ($this->file_exists($path)) {
397
+                    if (!$this->isUpdatable($path)) {
398
+                        return false;
399
+                    }
400
+                    if ($mode === 'w' or $mode === 'w+') {
401
+                        $tmpFile = $tempManager->getTemporaryFile($ext);
402
+                    } else {
403
+                        $tmpFile = $this->getCachedFile($path);
404
+                    }
405
+                } else {
406
+                    if (!$this->isCreatable(dirname($path))) {
407
+                        return false;
408
+                    }
409
+                    $tmpFile = $tempManager->getTemporaryFile($ext);
410
+                }
411
+                $handle = fopen($tmpFile, $mode);
412
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
413
+                    $this->writeBack($tmpFile, $path);
414
+                });
415
+        }
416
+    }
417
+
418
+    /**
419
+     * @param string $tmpFile
420
+     */
421
+    public function writeBack($tmpFile, $path) {
422
+        $this->uploadFile($tmpFile, $path);
423
+        unlink($tmpFile);
424
+    }
425
+
426
+    /** {@inheritdoc} */
427
+    public function free_space($path) {
428
+        $this->init();
429
+        $path = $this->cleanPath($path);
430
+        try {
431
+            // TODO: cacheable ?
432
+            $response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
433
+            if ($response === false) {
434
+                return FileInfo::SPACE_UNKNOWN;
435
+            }
436
+            if (isset($response['{DAV:}quota-available-bytes'])) {
437
+                return (int)$response['{DAV:}quota-available-bytes'];
438
+            } else {
439
+                return FileInfo::SPACE_UNKNOWN;
440
+            }
441
+        } catch (\Exception $e) {
442
+            return FileInfo::SPACE_UNKNOWN;
443
+        }
444
+    }
445
+
446
+    /** {@inheritdoc} */
447
+    public function touch($path, $mtime = null) {
448
+        $this->init();
449
+        if (is_null($mtime)) {
450
+            $mtime = time();
451
+        }
452
+        $path = $this->cleanPath($path);
453
+
454
+        // if file exists, update the mtime, else create a new empty file
455
+        if ($this->file_exists($path)) {
456
+            try {
457
+                $this->statCache->remove($path);
458
+                $this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
459
+                // non-owncloud clients might not have accepted the property, need to recheck it
460
+                $response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
461
+                if ($response === false) {
462
+                    return false;
463
+                }
464
+                if (isset($response['{DAV:}getlastmodified'])) {
465
+                    $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
466
+                    if ($remoteMtime !== $mtime) {
467
+                        // server has not accepted the mtime
468
+                        return false;
469
+                    }
470
+                }
471
+            } catch (ClientHttpException $e) {
472
+                if ($e->getHttpStatus() === 501) {
473
+                    return false;
474
+                }
475
+                $this->convertException($e, $path);
476
+                return false;
477
+            } catch (\Exception $e) {
478
+                $this->convertException($e, $path);
479
+                return false;
480
+            }
481
+        } else {
482
+            $this->file_put_contents($path, '');
483
+        }
484
+        return true;
485
+    }
486
+
487
+    /**
488
+     * @param string $path
489
+     * @param mixed $data
490
+     * @return int|false
491
+     */
492
+    public function file_put_contents($path, $data) {
493
+        $path = $this->cleanPath($path);
494
+        $result = parent::file_put_contents($path, $data);
495
+        $this->statCache->remove($path);
496
+        return $result;
497
+    }
498
+
499
+    /**
500
+     * @param string $path
501
+     * @param string $target
502
+     */
503
+    protected function uploadFile($path, $target) {
504
+        $this->init();
505
+
506
+        // invalidate
507
+        $target = $this->cleanPath($target);
508
+        $this->statCache->remove($target);
509
+        $source = fopen($path, 'r');
510
+
511
+        $this->httpClientService
512
+            ->newClient()
513
+            ->put($this->createBaseUri() . $this->encodePath($target), [
514
+                'body' => $source,
515
+                'auth' => [$this->user, $this->password]
516
+            ]);
517
+
518
+        $this->removeCachedFile($target);
519
+    }
520
+
521
+    /** {@inheritdoc} */
522
+    public function rename($path1, $path2) {
523
+        $this->init();
524
+        $path1 = $this->cleanPath($path1);
525
+        $path2 = $this->cleanPath($path2);
526
+        try {
527
+            // overwrite directory ?
528
+            if ($this->is_dir($path2)) {
529
+                // needs trailing slash in destination
530
+                $path2 = rtrim($path2, '/') . '/';
531
+            }
532
+            $this->client->request(
533
+                'MOVE',
534
+                $this->encodePath($path1),
535
+                null,
536
+                [
537
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
538
+                ]
539
+            );
540
+            $this->statCache->clear($path1 . '/');
541
+            $this->statCache->clear($path2 . '/');
542
+            $this->statCache->set($path1, false);
543
+            $this->statCache->set($path2, true);
544
+            $this->removeCachedFile($path1);
545
+            $this->removeCachedFile($path2);
546
+            return true;
547
+        } catch (\Exception $e) {
548
+            $this->convertException($e);
549
+        }
550
+        return false;
551
+    }
552
+
553
+    /** {@inheritdoc} */
554
+    public function copy($path1, $path2) {
555
+        $this->init();
556
+        $path1 = $this->cleanPath($path1);
557
+        $path2 = $this->cleanPath($path2);
558
+        try {
559
+            // overwrite directory ?
560
+            if ($this->is_dir($path2)) {
561
+                // needs trailing slash in destination
562
+                $path2 = rtrim($path2, '/') . '/';
563
+            }
564
+            $this->client->request(
565
+                'COPY',
566
+                $this->encodePath($path1),
567
+                null,
568
+                [
569
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
570
+                ]
571
+            );
572
+            $this->statCache->clear($path2 . '/');
573
+            $this->statCache->set($path2, true);
574
+            $this->removeCachedFile($path2);
575
+            return true;
576
+        } catch (\Exception $e) {
577
+            $this->convertException($e);
578
+        }
579
+        return false;
580
+    }
581
+
582
+    /** {@inheritdoc} */
583
+    public function stat($path) {
584
+        try {
585
+            $response = $this->propfind($path);
586
+            if (!$response) {
587
+                return false;
588
+            }
589
+            return [
590
+                'mtime' => strtotime($response['{DAV:}getlastmodified']),
591
+                'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
592
+            ];
593
+        } catch (\Exception $e) {
594
+            $this->convertException($e, $path);
595
+        }
596
+        return [];
597
+    }
598
+
599
+    /** {@inheritdoc} */
600
+    public function getMimeType($path) {
601
+        $remoteMimetype = $this->getMimeTypeFromRemote($path);
602
+        if ($remoteMimetype === 'application/octet-stream') {
603
+            return \OC::$server->getMimeTypeDetector()->detectPath($path);
604
+        } else {
605
+            return $remoteMimetype;
606
+        }
607
+    }
608
+
609
+    public function getMimeTypeFromRemote($path) {
610
+        try {
611
+            $response = $this->propfind($path);
612
+            if ($response === false) {
613
+                return false;
614
+            }
615
+            $responseType = [];
616
+            if (isset($response["{DAV:}resourcetype"])) {
617
+                /** @var ResourceType[] $response */
618
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
619
+            }
620
+            $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
621
+            if ($type == 'dir') {
622
+                return 'httpd/unix-directory';
623
+            } elseif (isset($response['{DAV:}getcontenttype'])) {
624
+                return $response['{DAV:}getcontenttype'];
625
+            } else {
626
+                return 'application/octet-stream';
627
+            }
628
+        } catch (\Exception $e) {
629
+            return false;
630
+        }
631
+    }
632
+
633
+    /**
634
+     * @param string $path
635
+     * @return string
636
+     */
637
+    public function cleanPath($path) {
638
+        if ($path === '') {
639
+            return $path;
640
+        }
641
+        $path = Filesystem::normalizePath($path);
642
+        // remove leading slash
643
+        return substr($path, 1);
644
+    }
645
+
646
+    /**
647
+     * URL encodes the given path but keeps the slashes
648
+     *
649
+     * @param string $path to encode
650
+     * @return string encoded path
651
+     */
652
+    protected function encodePath($path) {
653
+        // slashes need to stay
654
+        return str_replace('%2F', '/', rawurlencode($path));
655
+    }
656
+
657
+    /**
658
+     * @param string $method
659
+     * @param string $path
660
+     * @param string|resource|null $body
661
+     * @param int $expected
662
+     * @return bool
663
+     * @throws StorageInvalidException
664
+     * @throws StorageNotAvailableException
665
+     */
666
+    protected function simpleResponse($method, $path, $body, $expected) {
667
+        $path = $this->cleanPath($path);
668
+        try {
669
+            $response = $this->client->request($method, $this->encodePath($path), $body);
670
+            return $response['statusCode'] == $expected;
671
+        } catch (ClientHttpException $e) {
672
+            if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
673
+                $this->statCache->clear($path . '/');
674
+                $this->statCache->set($path, false);
675
+                return false;
676
+            }
677
+
678
+            $this->convertException($e, $path);
679
+        } catch (\Exception $e) {
680
+            $this->convertException($e, $path);
681
+        }
682
+        return false;
683
+    }
684
+
685
+    /**
686
+     * check if curl is installed
687
+     */
688
+    public static function checkDependencies() {
689
+        return true;
690
+    }
691
+
692
+    /** {@inheritdoc} */
693
+    public function isUpdatable($path) {
694
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
695
+    }
696
+
697
+    /** {@inheritdoc} */
698
+    public function isCreatable($path) {
699
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
700
+    }
701
+
702
+    /** {@inheritdoc} */
703
+    public function isSharable($path) {
704
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
705
+    }
706
+
707
+    /** {@inheritdoc} */
708
+    public function isDeletable($path) {
709
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
710
+    }
711
+
712
+    /** {@inheritdoc} */
713
+    public function getPermissions($path) {
714
+        $this->init();
715
+        $path = $this->cleanPath($path);
716
+        $response = $this->propfind($path);
717
+        if ($response === false) {
718
+            return 0;
719
+        }
720
+        if (isset($response['{http://owncloud.org/ns}permissions'])) {
721
+            return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
722
+        } elseif ($this->is_dir($path)) {
723
+            return Constants::PERMISSION_ALL;
724
+        } elseif ($this->file_exists($path)) {
725
+            return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
726
+        } else {
727
+            return 0;
728
+        }
729
+    }
730
+
731
+    /** {@inheritdoc} */
732
+    public function getETag($path) {
733
+        $this->init();
734
+        $path = $this->cleanPath($path);
735
+        $response = $this->propfind($path);
736
+        if ($response === false) {
737
+            return null;
738
+        }
739
+        if (isset($response['{DAV:}getetag'])) {
740
+            $etag = trim($response['{DAV:}getetag'], '"');
741
+            if (strlen($etag) > 40) {
742
+                $etag = md5($etag);
743
+            }
744
+            return $etag;
745
+        }
746
+        return parent::getEtag($path);
747
+    }
748
+
749
+    /**
750
+     * @param string $permissionsString
751
+     * @return int
752
+     */
753
+    protected function parsePermissions($permissionsString) {
754
+        $permissions = Constants::PERMISSION_READ;
755
+        if (strpos($permissionsString, 'R') !== false) {
756
+            $permissions |= Constants::PERMISSION_SHARE;
757
+        }
758
+        if (strpos($permissionsString, 'D') !== false) {
759
+            $permissions |= Constants::PERMISSION_DELETE;
760
+        }
761
+        if (strpos($permissionsString, 'W') !== false) {
762
+            $permissions |= Constants::PERMISSION_UPDATE;
763
+        }
764
+        if (strpos($permissionsString, 'CK') !== false) {
765
+            $permissions |= Constants::PERMISSION_CREATE;
766
+            $permissions |= Constants::PERMISSION_UPDATE;
767
+        }
768
+        return $permissions;
769
+    }
770
+
771
+    /**
772
+     * check if a file or folder has been updated since $time
773
+     *
774
+     * @param string $path
775
+     * @param int $time
776
+     * @throws \OCP\Files\StorageNotAvailableException
777
+     * @return bool
778
+     */
779
+    public function hasUpdated($path, $time) {
780
+        $this->init();
781
+        $path = $this->cleanPath($path);
782
+        try {
783
+            // force refresh for $path
784
+            $this->statCache->remove($path);
785
+            $response = $this->propfind($path);
786
+            if ($response === false) {
787
+                if ($path === '') {
788
+                    // if root is gone it means the storage is not available
789
+                    throw new StorageNotAvailableException('root is gone');
790
+                }
791
+                return false;
792
+            }
793
+            if (isset($response['{DAV:}getetag'])) {
794
+                $cachedData = $this->getCache()->get($path);
795
+                $etag = null;
796
+                if (isset($response['{DAV:}getetag'])) {
797
+                    $etag = trim($response['{DAV:}getetag'], '"');
798
+                }
799
+                if (!empty($etag) && $cachedData['etag'] !== $etag) {
800
+                    return true;
801
+                } elseif (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
802
+                    $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
803
+                    return $sharePermissions !== $cachedData['permissions'];
804
+                } elseif (isset($response['{http://owncloud.org/ns}permissions'])) {
805
+                    $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
806
+                    return $permissions !== $cachedData['permissions'];
807
+                } else {
808
+                    return false;
809
+                }
810
+            } else {
811
+                $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
812
+                return $remoteMtime > $time;
813
+            }
814
+        } catch (ClientHttpException $e) {
815
+            if ($e->getHttpStatus() === 405) {
816
+                if ($path === '') {
817
+                    // if root is gone it means the storage is not available
818
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
819
+                }
820
+                return false;
821
+            }
822
+            $this->convertException($e, $path);
823
+            return false;
824
+        } catch (\Exception $e) {
825
+            $this->convertException($e, $path);
826
+            return false;
827
+        }
828
+    }
829
+
830
+    /**
831
+     * Interpret the given exception and decide whether it is due to an
832
+     * unavailable storage, invalid storage or other.
833
+     * This will either throw StorageInvalidException, StorageNotAvailableException
834
+     * or do nothing.
835
+     *
836
+     * @param Exception $e sabre exception
837
+     * @param string $path optional path from the operation
838
+     *
839
+     * @throws StorageInvalidException if the storage is invalid, for example
840
+     * when the authentication expired or is invalid
841
+     * @throws StorageNotAvailableException if the storage is not available,
842
+     * which might be temporary
843
+     * @throws ForbiddenException if the action is not allowed
844
+     */
845
+    protected function convertException(Exception $e, $path = '') {
846
+        \OC::$server->getLogger()->logException($e, ['app' => 'files_external', 'level' => ILogger::DEBUG]);
847
+        if ($e instanceof ClientHttpException) {
848
+            if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
849
+                throw new \OCP\Lock\LockedException($path);
850
+            }
851
+            if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
852
+                // either password was changed or was invalid all along
853
+                throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
854
+            } elseif ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
855
+                // ignore exception for MethodNotAllowed, false will be returned
856
+                return;
857
+            } elseif ($e->getHttpStatus() === Http::STATUS_FORBIDDEN) {
858
+                // The operation is forbidden. Fail somewhat gracefully
859
+                throw new ForbiddenException(get_class($e) . ':' . $e->getMessage(), false);
860
+            }
861
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
862
+        } elseif ($e instanceof ClientException) {
863
+            // connection timeout or refused, server could be temporarily down
864
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
865
+        } elseif ($e instanceof \InvalidArgumentException) {
866
+            // parse error because the server returned HTML instead of XML,
867
+            // possibly temporarily down
868
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
869
+        } elseif (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
870
+            // rethrow
871
+            throw $e;
872
+        }
873
+
874
+        // TODO: only log for now, but in the future need to wrap/rethrow exception
875
+    }
876 876
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Encoding.php 1 patch
Indentation   +502 added lines, -502 removed lines patch added patch discarded remove patch
@@ -37,506 +37,506 @@
 block discarded – undo
37 37
  */
38 38
 class Encoding extends Wrapper {
39 39
 
40
-	/**
41
-	 * @var ICache
42
-	 */
43
-	private $namesCache;
44
-
45
-	/**
46
-	 * @param array $parameters
47
-	 */
48
-	public function __construct($parameters) {
49
-		$this->storage = $parameters['storage'];
50
-		$this->namesCache = new CappedMemoryCache();
51
-	}
52
-
53
-	/**
54
-	 * Returns whether the given string is only made of ASCII characters
55
-	 *
56
-	 * @param string $str string
57
-	 *
58
-	 * @return bool true if the string is all ASCII, false otherwise
59
-	 */
60
-	private function isAscii($str) {
61
-		return (bool) !preg_match('/[\\x80-\\xff]+/', $str);
62
-	}
63
-
64
-	/**
65
-	 * Checks whether the given path exists in NFC or NFD form after checking
66
-	 * each form for each path section and returns the correct form.
67
-	 * If no existing path found, returns the path as it was given.
68
-	 *
69
-	 * @param string $fullPath path to check
70
-	 *
71
-	 * @return string original or converted path
72
-	 */
73
-	private function findPathToUse($fullPath) {
74
-		$cachedPath = $this->namesCache[$fullPath];
75
-		if ($cachedPath !== null) {
76
-			return $cachedPath;
77
-		}
78
-
79
-		$sections = explode('/', $fullPath);
80
-		$path = '';
81
-		foreach ($sections as $section) {
82
-			$convertedPath = $this->findPathToUseLastSection($path, $section);
83
-			if ($convertedPath === null) {
84
-				// no point in continuing if the section was not found, use original path
85
-				return $fullPath;
86
-			}
87
-			$path = $convertedPath . '/';
88
-		}
89
-		$path = rtrim($path, '/');
90
-		return $path;
91
-	}
92
-
93
-	/**
94
-	 * Checks whether the last path section of the given path exists in NFC or NFD form
95
-	 * and returns the correct form. If no existing path found, returns null.
96
-	 *
97
-	 * @param string $basePath base path to check
98
-	 * @param string $lastSection last section of the path to check for NFD/NFC variations
99
-	 *
100
-	 * @return string|null original or converted path, or null if none of the forms was found
101
-	 */
102
-	private function findPathToUseLastSection($basePath, $lastSection) {
103
-		$fullPath = $basePath . $lastSection;
104
-		if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) {
105
-			$this->namesCache[$fullPath] = $fullPath;
106
-			return $fullPath;
107
-		}
108
-
109
-		// swap encoding
110
-		if (\Normalizer::isNormalized($lastSection, \Normalizer::FORM_C)) {
111
-			$otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_D);
112
-		} else {
113
-			$otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_C);
114
-		}
115
-		$otherFullPath = $basePath . $otherFormPath;
116
-		if ($this->storage->file_exists($otherFullPath)) {
117
-			$this->namesCache[$fullPath] = $otherFullPath;
118
-			return $otherFullPath;
119
-		}
120
-
121
-		// return original path, file did not exist at all
122
-		$this->namesCache[$fullPath] = $fullPath;
123
-		return null;
124
-	}
125
-
126
-	/**
127
-	 * see http://php.net/manual/en/function.mkdir.php
128
-	 *
129
-	 * @param string $path
130
-	 * @return bool
131
-	 */
132
-	public function mkdir($path) {
133
-		// note: no conversion here, method should not be called with non-NFC names!
134
-		$result = $this->storage->mkdir($path);
135
-		if ($result) {
136
-			$this->namesCache[$path] = $path;
137
-		}
138
-		return $result;
139
-	}
140
-
141
-	/**
142
-	 * see http://php.net/manual/en/function.rmdir.php
143
-	 *
144
-	 * @param string $path
145
-	 * @return bool
146
-	 */
147
-	public function rmdir($path) {
148
-		$result = $this->storage->rmdir($this->findPathToUse($path));
149
-		if ($result) {
150
-			unset($this->namesCache[$path]);
151
-		}
152
-		return $result;
153
-	}
154
-
155
-	/**
156
-	 * see http://php.net/manual/en/function.opendir.php
157
-	 *
158
-	 * @param string $path
159
-	 * @return resource
160
-	 */
161
-	public function opendir($path) {
162
-		return $this->storage->opendir($this->findPathToUse($path));
163
-	}
164
-
165
-	/**
166
-	 * see http://php.net/manual/en/function.is_dir.php
167
-	 *
168
-	 * @param string $path
169
-	 * @return bool
170
-	 */
171
-	public function is_dir($path) {
172
-		return $this->storage->is_dir($this->findPathToUse($path));
173
-	}
174
-
175
-	/**
176
-	 * see http://php.net/manual/en/function.is_file.php
177
-	 *
178
-	 * @param string $path
179
-	 * @return bool
180
-	 */
181
-	public function is_file($path) {
182
-		return $this->storage->is_file($this->findPathToUse($path));
183
-	}
184
-
185
-	/**
186
-	 * see http://php.net/manual/en/function.stat.php
187
-	 * only the following keys are required in the result: size and mtime
188
-	 *
189
-	 * @param string $path
190
-	 * @return array
191
-	 */
192
-	public function stat($path) {
193
-		return $this->storage->stat($this->findPathToUse($path));
194
-	}
195
-
196
-	/**
197
-	 * see http://php.net/manual/en/function.filetype.php
198
-	 *
199
-	 * @param string $path
200
-	 * @return bool
201
-	 */
202
-	public function filetype($path) {
203
-		return $this->storage->filetype($this->findPathToUse($path));
204
-	}
205
-
206
-	/**
207
-	 * see http://php.net/manual/en/function.filesize.php
208
-	 * The result for filesize when called on a folder is required to be 0
209
-	 *
210
-	 * @param string $path
211
-	 * @return int
212
-	 */
213
-	public function filesize($path) {
214
-		return $this->storage->filesize($this->findPathToUse($path));
215
-	}
216
-
217
-	/**
218
-	 * check if a file can be created in $path
219
-	 *
220
-	 * @param string $path
221
-	 * @return bool
222
-	 */
223
-	public function isCreatable($path) {
224
-		return $this->storage->isCreatable($this->findPathToUse($path));
225
-	}
226
-
227
-	/**
228
-	 * check if a file can be read
229
-	 *
230
-	 * @param string $path
231
-	 * @return bool
232
-	 */
233
-	public function isReadable($path) {
234
-		return $this->storage->isReadable($this->findPathToUse($path));
235
-	}
236
-
237
-	/**
238
-	 * check if a file can be written to
239
-	 *
240
-	 * @param string $path
241
-	 * @return bool
242
-	 */
243
-	public function isUpdatable($path) {
244
-		return $this->storage->isUpdatable($this->findPathToUse($path));
245
-	}
246
-
247
-	/**
248
-	 * check if a file can be deleted
249
-	 *
250
-	 * @param string $path
251
-	 * @return bool
252
-	 */
253
-	public function isDeletable($path) {
254
-		return $this->storage->isDeletable($this->findPathToUse($path));
255
-	}
256
-
257
-	/**
258
-	 * check if a file can be shared
259
-	 *
260
-	 * @param string $path
261
-	 * @return bool
262
-	 */
263
-	public function isSharable($path) {
264
-		return $this->storage->isSharable($this->findPathToUse($path));
265
-	}
266
-
267
-	/**
268
-	 * get the full permissions of a path.
269
-	 * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
270
-	 *
271
-	 * @param string $path
272
-	 * @return int
273
-	 */
274
-	public function getPermissions($path) {
275
-		return $this->storage->getPermissions($this->findPathToUse($path));
276
-	}
277
-
278
-	/**
279
-	 * see http://php.net/manual/en/function.file_exists.php
280
-	 *
281
-	 * @param string $path
282
-	 * @return bool
283
-	 */
284
-	public function file_exists($path) {
285
-		return $this->storage->file_exists($this->findPathToUse($path));
286
-	}
287
-
288
-	/**
289
-	 * see http://php.net/manual/en/function.filemtime.php
290
-	 *
291
-	 * @param string $path
292
-	 * @return int
293
-	 */
294
-	public function filemtime($path) {
295
-		return $this->storage->filemtime($this->findPathToUse($path));
296
-	}
297
-
298
-	/**
299
-	 * see http://php.net/manual/en/function.file_get_contents.php
300
-	 *
301
-	 * @param string $path
302
-	 * @return string
303
-	 */
304
-	public function file_get_contents($path) {
305
-		return $this->storage->file_get_contents($this->findPathToUse($path));
306
-	}
307
-
308
-	/**
309
-	 * see http://php.net/manual/en/function.file_put_contents.php
310
-	 *
311
-	 * @param string $path
312
-	 * @param mixed $data
313
-	 * @return int|false
314
-	 */
315
-	public function file_put_contents($path, $data) {
316
-		return $this->storage->file_put_contents($this->findPathToUse($path), $data);
317
-	}
318
-
319
-	/**
320
-	 * see http://php.net/manual/en/function.unlink.php
321
-	 *
322
-	 * @param string $path
323
-	 * @return bool
324
-	 */
325
-	public function unlink($path) {
326
-		$result = $this->storage->unlink($this->findPathToUse($path));
327
-		if ($result) {
328
-			unset($this->namesCache[$path]);
329
-		}
330
-		return $result;
331
-	}
332
-
333
-	/**
334
-	 * see http://php.net/manual/en/function.rename.php
335
-	 *
336
-	 * @param string $path1
337
-	 * @param string $path2
338
-	 * @return bool
339
-	 */
340
-	public function rename($path1, $path2) {
341
-		// second name always NFC
342
-		return $this->storage->rename($this->findPathToUse($path1), $this->findPathToUse($path2));
343
-	}
344
-
345
-	/**
346
-	 * see http://php.net/manual/en/function.copy.php
347
-	 *
348
-	 * @param string $path1
349
-	 * @param string $path2
350
-	 * @return bool
351
-	 */
352
-	public function copy($path1, $path2) {
353
-		return $this->storage->copy($this->findPathToUse($path1), $this->findPathToUse($path2));
354
-	}
355
-
356
-	/**
357
-	 * see http://php.net/manual/en/function.fopen.php
358
-	 *
359
-	 * @param string $path
360
-	 * @param string $mode
361
-	 * @return resource
362
-	 */
363
-	public function fopen($path, $mode) {
364
-		$result = $this->storage->fopen($this->findPathToUse($path), $mode);
365
-		if ($result && $mode !== 'r' && $mode !== 'rb') {
366
-			unset($this->namesCache[$path]);
367
-		}
368
-		return $result;
369
-	}
370
-
371
-	/**
372
-	 * get the mimetype for a file or folder
373
-	 * The mimetype for a folder is required to be "httpd/unix-directory"
374
-	 *
375
-	 * @param string $path
376
-	 * @return string
377
-	 */
378
-	public function getMimeType($path) {
379
-		return $this->storage->getMimeType($this->findPathToUse($path));
380
-	}
381
-
382
-	/**
383
-	 * see http://php.net/manual/en/function.hash.php
384
-	 *
385
-	 * @param string $type
386
-	 * @param string $path
387
-	 * @param bool $raw
388
-	 * @return string
389
-	 */
390
-	public function hash($type, $path, $raw = false) {
391
-		return $this->storage->hash($type, $this->findPathToUse($path), $raw);
392
-	}
393
-
394
-	/**
395
-	 * see http://php.net/manual/en/function.free_space.php
396
-	 *
397
-	 * @param string $path
398
-	 * @return int
399
-	 */
400
-	public function free_space($path) {
401
-		return $this->storage->free_space($this->findPathToUse($path));
402
-	}
403
-
404
-	/**
405
-	 * search for occurrences of $query in file names
406
-	 *
407
-	 * @param string $query
408
-	 * @return array
409
-	 */
410
-	public function search($query) {
411
-		return $this->storage->search($query);
412
-	}
413
-
414
-	/**
415
-	 * see http://php.net/manual/en/function.touch.php
416
-	 * If the backend does not support the operation, false should be returned
417
-	 *
418
-	 * @param string $path
419
-	 * @param int $mtime
420
-	 * @return bool
421
-	 */
422
-	public function touch($path, $mtime = null) {
423
-		return $this->storage->touch($this->findPathToUse($path), $mtime);
424
-	}
425
-
426
-	/**
427
-	 * get the path to a local version of the file.
428
-	 * The local version of the file can be temporary and doesn't have to be persistent across requests
429
-	 *
430
-	 * @param string $path
431
-	 * @return string
432
-	 */
433
-	public function getLocalFile($path) {
434
-		return $this->storage->getLocalFile($this->findPathToUse($path));
435
-	}
436
-
437
-	/**
438
-	 * check if a file or folder has been updated since $time
439
-	 *
440
-	 * @param string $path
441
-	 * @param int $time
442
-	 * @return bool
443
-	 *
444
-	 * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
445
-	 * returning true for other changes in the folder is optional
446
-	 */
447
-	public function hasUpdated($path, $time) {
448
-		return $this->storage->hasUpdated($this->findPathToUse($path), $time);
449
-	}
450
-
451
-	/**
452
-	 * get a cache instance for the storage
453
-	 *
454
-	 * @param string $path
455
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
456
-	 * @return \OC\Files\Cache\Cache
457
-	 */
458
-	public function getCache($path = '', $storage = null) {
459
-		if (!$storage) {
460
-			$storage = $this;
461
-		}
462
-		return $this->storage->getCache($this->findPathToUse($path), $storage);
463
-	}
464
-
465
-	/**
466
-	 * get a scanner instance for the storage
467
-	 *
468
-	 * @param string $path
469
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
470
-	 * @return \OC\Files\Cache\Scanner
471
-	 */
472
-	public function getScanner($path = '', $storage = null) {
473
-		if (!$storage) {
474
-			$storage = $this;
475
-		}
476
-		return $this->storage->getScanner($this->findPathToUse($path), $storage);
477
-	}
478
-
479
-	/**
480
-	 * get the ETag for a file or folder
481
-	 *
482
-	 * @param string $path
483
-	 * @return string
484
-	 */
485
-	public function getETag($path) {
486
-		return $this->storage->getETag($this->findPathToUse($path));
487
-	}
488
-
489
-	/**
490
-	 * @param IStorage $sourceStorage
491
-	 * @param string $sourceInternalPath
492
-	 * @param string $targetInternalPath
493
-	 * @return bool
494
-	 */
495
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
496
-		if ($sourceStorage === $this) {
497
-			return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath));
498
-		}
499
-
500
-		$result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
501
-		if ($result) {
502
-			unset($this->namesCache[$targetInternalPath]);
503
-		}
504
-		return $result;
505
-	}
506
-
507
-	/**
508
-	 * @param IStorage $sourceStorage
509
-	 * @param string $sourceInternalPath
510
-	 * @param string $targetInternalPath
511
-	 * @return bool
512
-	 */
513
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
514
-		if ($sourceStorage === $this) {
515
-			$result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath));
516
-			if ($result) {
517
-				unset($this->namesCache[$sourceInternalPath]);
518
-				unset($this->namesCache[$targetInternalPath]);
519
-			}
520
-			return $result;
521
-		}
522
-
523
-		$result = $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
524
-		if ($result) {
525
-			unset($this->namesCache[$sourceInternalPath]);
526
-			unset($this->namesCache[$targetInternalPath]);
527
-		}
528
-		return $result;
529
-	}
530
-
531
-	/**
532
-	 * @param string $path
533
-	 * @return array
534
-	 */
535
-	public function getMetaData($path) {
536
-		return $this->storage->getMetaData($this->findPathToUse($path));
537
-	}
538
-
539
-	public function getDirectoryContent($directory): \Traversable {
540
-		return $this->storage->getDirectoryContent($this->findPathToUse($directory));
541
-	}
40
+    /**
41
+     * @var ICache
42
+     */
43
+    private $namesCache;
44
+
45
+    /**
46
+     * @param array $parameters
47
+     */
48
+    public function __construct($parameters) {
49
+        $this->storage = $parameters['storage'];
50
+        $this->namesCache = new CappedMemoryCache();
51
+    }
52
+
53
+    /**
54
+     * Returns whether the given string is only made of ASCII characters
55
+     *
56
+     * @param string $str string
57
+     *
58
+     * @return bool true if the string is all ASCII, false otherwise
59
+     */
60
+    private function isAscii($str) {
61
+        return (bool) !preg_match('/[\\x80-\\xff]+/', $str);
62
+    }
63
+
64
+    /**
65
+     * Checks whether the given path exists in NFC or NFD form after checking
66
+     * each form for each path section and returns the correct form.
67
+     * If no existing path found, returns the path as it was given.
68
+     *
69
+     * @param string $fullPath path to check
70
+     *
71
+     * @return string original or converted path
72
+     */
73
+    private function findPathToUse($fullPath) {
74
+        $cachedPath = $this->namesCache[$fullPath];
75
+        if ($cachedPath !== null) {
76
+            return $cachedPath;
77
+        }
78
+
79
+        $sections = explode('/', $fullPath);
80
+        $path = '';
81
+        foreach ($sections as $section) {
82
+            $convertedPath = $this->findPathToUseLastSection($path, $section);
83
+            if ($convertedPath === null) {
84
+                // no point in continuing if the section was not found, use original path
85
+                return $fullPath;
86
+            }
87
+            $path = $convertedPath . '/';
88
+        }
89
+        $path = rtrim($path, '/');
90
+        return $path;
91
+    }
92
+
93
+    /**
94
+     * Checks whether the last path section of the given path exists in NFC or NFD form
95
+     * and returns the correct form. If no existing path found, returns null.
96
+     *
97
+     * @param string $basePath base path to check
98
+     * @param string $lastSection last section of the path to check for NFD/NFC variations
99
+     *
100
+     * @return string|null original or converted path, or null if none of the forms was found
101
+     */
102
+    private function findPathToUseLastSection($basePath, $lastSection) {
103
+        $fullPath = $basePath . $lastSection;
104
+        if ($lastSection === '' || $this->isAscii($lastSection) || $this->storage->file_exists($fullPath)) {
105
+            $this->namesCache[$fullPath] = $fullPath;
106
+            return $fullPath;
107
+        }
108
+
109
+        // swap encoding
110
+        if (\Normalizer::isNormalized($lastSection, \Normalizer::FORM_C)) {
111
+            $otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_D);
112
+        } else {
113
+            $otherFormPath = \Normalizer::normalize($lastSection, \Normalizer::FORM_C);
114
+        }
115
+        $otherFullPath = $basePath . $otherFormPath;
116
+        if ($this->storage->file_exists($otherFullPath)) {
117
+            $this->namesCache[$fullPath] = $otherFullPath;
118
+            return $otherFullPath;
119
+        }
120
+
121
+        // return original path, file did not exist at all
122
+        $this->namesCache[$fullPath] = $fullPath;
123
+        return null;
124
+    }
125
+
126
+    /**
127
+     * see http://php.net/manual/en/function.mkdir.php
128
+     *
129
+     * @param string $path
130
+     * @return bool
131
+     */
132
+    public function mkdir($path) {
133
+        // note: no conversion here, method should not be called with non-NFC names!
134
+        $result = $this->storage->mkdir($path);
135
+        if ($result) {
136
+            $this->namesCache[$path] = $path;
137
+        }
138
+        return $result;
139
+    }
140
+
141
+    /**
142
+     * see http://php.net/manual/en/function.rmdir.php
143
+     *
144
+     * @param string $path
145
+     * @return bool
146
+     */
147
+    public function rmdir($path) {
148
+        $result = $this->storage->rmdir($this->findPathToUse($path));
149
+        if ($result) {
150
+            unset($this->namesCache[$path]);
151
+        }
152
+        return $result;
153
+    }
154
+
155
+    /**
156
+     * see http://php.net/manual/en/function.opendir.php
157
+     *
158
+     * @param string $path
159
+     * @return resource
160
+     */
161
+    public function opendir($path) {
162
+        return $this->storage->opendir($this->findPathToUse($path));
163
+    }
164
+
165
+    /**
166
+     * see http://php.net/manual/en/function.is_dir.php
167
+     *
168
+     * @param string $path
169
+     * @return bool
170
+     */
171
+    public function is_dir($path) {
172
+        return $this->storage->is_dir($this->findPathToUse($path));
173
+    }
174
+
175
+    /**
176
+     * see http://php.net/manual/en/function.is_file.php
177
+     *
178
+     * @param string $path
179
+     * @return bool
180
+     */
181
+    public function is_file($path) {
182
+        return $this->storage->is_file($this->findPathToUse($path));
183
+    }
184
+
185
+    /**
186
+     * see http://php.net/manual/en/function.stat.php
187
+     * only the following keys are required in the result: size and mtime
188
+     *
189
+     * @param string $path
190
+     * @return array
191
+     */
192
+    public function stat($path) {
193
+        return $this->storage->stat($this->findPathToUse($path));
194
+    }
195
+
196
+    /**
197
+     * see http://php.net/manual/en/function.filetype.php
198
+     *
199
+     * @param string $path
200
+     * @return bool
201
+     */
202
+    public function filetype($path) {
203
+        return $this->storage->filetype($this->findPathToUse($path));
204
+    }
205
+
206
+    /**
207
+     * see http://php.net/manual/en/function.filesize.php
208
+     * The result for filesize when called on a folder is required to be 0
209
+     *
210
+     * @param string $path
211
+     * @return int
212
+     */
213
+    public function filesize($path) {
214
+        return $this->storage->filesize($this->findPathToUse($path));
215
+    }
216
+
217
+    /**
218
+     * check if a file can be created in $path
219
+     *
220
+     * @param string $path
221
+     * @return bool
222
+     */
223
+    public function isCreatable($path) {
224
+        return $this->storage->isCreatable($this->findPathToUse($path));
225
+    }
226
+
227
+    /**
228
+     * check if a file can be read
229
+     *
230
+     * @param string $path
231
+     * @return bool
232
+     */
233
+    public function isReadable($path) {
234
+        return $this->storage->isReadable($this->findPathToUse($path));
235
+    }
236
+
237
+    /**
238
+     * check if a file can be written to
239
+     *
240
+     * @param string $path
241
+     * @return bool
242
+     */
243
+    public function isUpdatable($path) {
244
+        return $this->storage->isUpdatable($this->findPathToUse($path));
245
+    }
246
+
247
+    /**
248
+     * check if a file can be deleted
249
+     *
250
+     * @param string $path
251
+     * @return bool
252
+     */
253
+    public function isDeletable($path) {
254
+        return $this->storage->isDeletable($this->findPathToUse($path));
255
+    }
256
+
257
+    /**
258
+     * check if a file can be shared
259
+     *
260
+     * @param string $path
261
+     * @return bool
262
+     */
263
+    public function isSharable($path) {
264
+        return $this->storage->isSharable($this->findPathToUse($path));
265
+    }
266
+
267
+    /**
268
+     * get the full permissions of a path.
269
+     * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
270
+     *
271
+     * @param string $path
272
+     * @return int
273
+     */
274
+    public function getPermissions($path) {
275
+        return $this->storage->getPermissions($this->findPathToUse($path));
276
+    }
277
+
278
+    /**
279
+     * see http://php.net/manual/en/function.file_exists.php
280
+     *
281
+     * @param string $path
282
+     * @return bool
283
+     */
284
+    public function file_exists($path) {
285
+        return $this->storage->file_exists($this->findPathToUse($path));
286
+    }
287
+
288
+    /**
289
+     * see http://php.net/manual/en/function.filemtime.php
290
+     *
291
+     * @param string $path
292
+     * @return int
293
+     */
294
+    public function filemtime($path) {
295
+        return $this->storage->filemtime($this->findPathToUse($path));
296
+    }
297
+
298
+    /**
299
+     * see http://php.net/manual/en/function.file_get_contents.php
300
+     *
301
+     * @param string $path
302
+     * @return string
303
+     */
304
+    public function file_get_contents($path) {
305
+        return $this->storage->file_get_contents($this->findPathToUse($path));
306
+    }
307
+
308
+    /**
309
+     * see http://php.net/manual/en/function.file_put_contents.php
310
+     *
311
+     * @param string $path
312
+     * @param mixed $data
313
+     * @return int|false
314
+     */
315
+    public function file_put_contents($path, $data) {
316
+        return $this->storage->file_put_contents($this->findPathToUse($path), $data);
317
+    }
318
+
319
+    /**
320
+     * see http://php.net/manual/en/function.unlink.php
321
+     *
322
+     * @param string $path
323
+     * @return bool
324
+     */
325
+    public function unlink($path) {
326
+        $result = $this->storage->unlink($this->findPathToUse($path));
327
+        if ($result) {
328
+            unset($this->namesCache[$path]);
329
+        }
330
+        return $result;
331
+    }
332
+
333
+    /**
334
+     * see http://php.net/manual/en/function.rename.php
335
+     *
336
+     * @param string $path1
337
+     * @param string $path2
338
+     * @return bool
339
+     */
340
+    public function rename($path1, $path2) {
341
+        // second name always NFC
342
+        return $this->storage->rename($this->findPathToUse($path1), $this->findPathToUse($path2));
343
+    }
344
+
345
+    /**
346
+     * see http://php.net/manual/en/function.copy.php
347
+     *
348
+     * @param string $path1
349
+     * @param string $path2
350
+     * @return bool
351
+     */
352
+    public function copy($path1, $path2) {
353
+        return $this->storage->copy($this->findPathToUse($path1), $this->findPathToUse($path2));
354
+    }
355
+
356
+    /**
357
+     * see http://php.net/manual/en/function.fopen.php
358
+     *
359
+     * @param string $path
360
+     * @param string $mode
361
+     * @return resource
362
+     */
363
+    public function fopen($path, $mode) {
364
+        $result = $this->storage->fopen($this->findPathToUse($path), $mode);
365
+        if ($result && $mode !== 'r' && $mode !== 'rb') {
366
+            unset($this->namesCache[$path]);
367
+        }
368
+        return $result;
369
+    }
370
+
371
+    /**
372
+     * get the mimetype for a file or folder
373
+     * The mimetype for a folder is required to be "httpd/unix-directory"
374
+     *
375
+     * @param string $path
376
+     * @return string
377
+     */
378
+    public function getMimeType($path) {
379
+        return $this->storage->getMimeType($this->findPathToUse($path));
380
+    }
381
+
382
+    /**
383
+     * see http://php.net/manual/en/function.hash.php
384
+     *
385
+     * @param string $type
386
+     * @param string $path
387
+     * @param bool $raw
388
+     * @return string
389
+     */
390
+    public function hash($type, $path, $raw = false) {
391
+        return $this->storage->hash($type, $this->findPathToUse($path), $raw);
392
+    }
393
+
394
+    /**
395
+     * see http://php.net/manual/en/function.free_space.php
396
+     *
397
+     * @param string $path
398
+     * @return int
399
+     */
400
+    public function free_space($path) {
401
+        return $this->storage->free_space($this->findPathToUse($path));
402
+    }
403
+
404
+    /**
405
+     * search for occurrences of $query in file names
406
+     *
407
+     * @param string $query
408
+     * @return array
409
+     */
410
+    public function search($query) {
411
+        return $this->storage->search($query);
412
+    }
413
+
414
+    /**
415
+     * see http://php.net/manual/en/function.touch.php
416
+     * If the backend does not support the operation, false should be returned
417
+     *
418
+     * @param string $path
419
+     * @param int $mtime
420
+     * @return bool
421
+     */
422
+    public function touch($path, $mtime = null) {
423
+        return $this->storage->touch($this->findPathToUse($path), $mtime);
424
+    }
425
+
426
+    /**
427
+     * get the path to a local version of the file.
428
+     * The local version of the file can be temporary and doesn't have to be persistent across requests
429
+     *
430
+     * @param string $path
431
+     * @return string
432
+     */
433
+    public function getLocalFile($path) {
434
+        return $this->storage->getLocalFile($this->findPathToUse($path));
435
+    }
436
+
437
+    /**
438
+     * check if a file or folder has been updated since $time
439
+     *
440
+     * @param string $path
441
+     * @param int $time
442
+     * @return bool
443
+     *
444
+     * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
445
+     * returning true for other changes in the folder is optional
446
+     */
447
+    public function hasUpdated($path, $time) {
448
+        return $this->storage->hasUpdated($this->findPathToUse($path), $time);
449
+    }
450
+
451
+    /**
452
+     * get a cache instance for the storage
453
+     *
454
+     * @param string $path
455
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
456
+     * @return \OC\Files\Cache\Cache
457
+     */
458
+    public function getCache($path = '', $storage = null) {
459
+        if (!$storage) {
460
+            $storage = $this;
461
+        }
462
+        return $this->storage->getCache($this->findPathToUse($path), $storage);
463
+    }
464
+
465
+    /**
466
+     * get a scanner instance for the storage
467
+     *
468
+     * @param string $path
469
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
470
+     * @return \OC\Files\Cache\Scanner
471
+     */
472
+    public function getScanner($path = '', $storage = null) {
473
+        if (!$storage) {
474
+            $storage = $this;
475
+        }
476
+        return $this->storage->getScanner($this->findPathToUse($path), $storage);
477
+    }
478
+
479
+    /**
480
+     * get the ETag for a file or folder
481
+     *
482
+     * @param string $path
483
+     * @return string
484
+     */
485
+    public function getETag($path) {
486
+        return $this->storage->getETag($this->findPathToUse($path));
487
+    }
488
+
489
+    /**
490
+     * @param IStorage $sourceStorage
491
+     * @param string $sourceInternalPath
492
+     * @param string $targetInternalPath
493
+     * @return bool
494
+     */
495
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
496
+        if ($sourceStorage === $this) {
497
+            return $this->copy($sourceInternalPath, $this->findPathToUse($targetInternalPath));
498
+        }
499
+
500
+        $result = $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
501
+        if ($result) {
502
+            unset($this->namesCache[$targetInternalPath]);
503
+        }
504
+        return $result;
505
+    }
506
+
507
+    /**
508
+     * @param IStorage $sourceStorage
509
+     * @param string $sourceInternalPath
510
+     * @param string $targetInternalPath
511
+     * @return bool
512
+     */
513
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
514
+        if ($sourceStorage === $this) {
515
+            $result = $this->rename($sourceInternalPath, $this->findPathToUse($targetInternalPath));
516
+            if ($result) {
517
+                unset($this->namesCache[$sourceInternalPath]);
518
+                unset($this->namesCache[$targetInternalPath]);
519
+            }
520
+            return $result;
521
+        }
522
+
523
+        $result = $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $this->findPathToUse($targetInternalPath));
524
+        if ($result) {
525
+            unset($this->namesCache[$sourceInternalPath]);
526
+            unset($this->namesCache[$targetInternalPath]);
527
+        }
528
+        return $result;
529
+    }
530
+
531
+    /**
532
+     * @param string $path
533
+     * @return array
534
+     */
535
+    public function getMetaData($path) {
536
+        return $this->storage->getMetaData($this->findPathToUse($path));
537
+    }
538
+
539
+    public function getDirectoryContent($directory): \Traversable {
540
+        return $this->storage->getDirectoryContent($this->findPathToUse($directory));
541
+    }
542 542
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Quota.php 1 patch
Indentation   +204 added lines, -204 removed lines patch added patch discarded remove patch
@@ -36,208 +36,208 @@
 block discarded – undo
36 36
 
37 37
 class Quota extends Wrapper {
38 38
 
39
-	/**
40
-	 * @var int $quota
41
-	 */
42
-	protected $quota;
43
-
44
-	/**
45
-	 * @var string $sizeRoot
46
-	 */
47
-	protected $sizeRoot;
48
-
49
-	private $config;
50
-
51
-	/**
52
-	 * @param array $parameters
53
-	 */
54
-	public function __construct($parameters) {
55
-		parent::__construct($parameters);
56
-		$this->quota = $parameters['quota'];
57
-		$this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
58
-		$this->config = \OC::$server->getSystemConfig();
59
-	}
60
-
61
-	/**
62
-	 * @return int quota value
63
-	 */
64
-	public function getQuota() {
65
-		return $this->quota;
66
-	}
67
-
68
-	/**
69
-	 * @param string $path
70
-	 * @param \OC\Files\Storage\Storage $storage
71
-	 */
72
-	protected function getSize($path, $storage = null) {
73
-		if ($this->config->getValue('quota_include_external_storage', false)) {
74
-			$rootInfo = Filesystem::getFileInfo('', 'ext');
75
-			if ($rootInfo) {
76
-				return $rootInfo->getSize(true);
77
-			}
78
-			return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
79
-		} else {
80
-			if (is_null($storage)) {
81
-				$cache = $this->getCache();
82
-			} else {
83
-				$cache = $storage->getCache();
84
-			}
85
-			$data = $cache->get($path);
86
-			if ($data instanceof ICacheEntry and isset($data['size'])) {
87
-				return $data['size'];
88
-			} else {
89
-				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
90
-			}
91
-		}
92
-	}
93
-
94
-	/**
95
-	 * Get free space as limited by the quota
96
-	 *
97
-	 * @param string $path
98
-	 * @return int
99
-	 */
100
-	public function free_space($path) {
101
-		if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
102
-			return $this->storage->free_space($path);
103
-		} else {
104
-			$used = $this->getSize($this->sizeRoot);
105
-			if ($used < 0) {
106
-				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
107
-			} else {
108
-				$free = $this->storage->free_space($path);
109
-				$quotaFree = max($this->quota - $used, 0);
110
-				// if free space is known
111
-				if ($free >= 0) {
112
-					$free = min($free, $quotaFree);
113
-				} else {
114
-					$free = $quotaFree;
115
-				}
116
-				return $free;
117
-			}
118
-		}
119
-	}
120
-
121
-	/**
122
-	 * see http://php.net/manual/en/function.file_put_contents.php
123
-	 *
124
-	 * @param string $path
125
-	 * @param mixed $data
126
-	 * @return int|false
127
-	 */
128
-	public function file_put_contents($path, $data) {
129
-		$free = $this->free_space($path);
130
-		if ($free < 0 or strlen($data) < $free) {
131
-			return $this->storage->file_put_contents($path, $data);
132
-		} else {
133
-			return false;
134
-		}
135
-	}
136
-
137
-	/**
138
-	 * see http://php.net/manual/en/function.copy.php
139
-	 *
140
-	 * @param string $source
141
-	 * @param string $target
142
-	 * @return bool
143
-	 */
144
-	public function copy($source, $target) {
145
-		$free = $this->free_space($target);
146
-		if ($free < 0 or $this->getSize($source) < $free) {
147
-			return $this->storage->copy($source, $target);
148
-		} else {
149
-			return false;
150
-		}
151
-	}
152
-
153
-	/**
154
-	 * see http://php.net/manual/en/function.fopen.php
155
-	 *
156
-	 * @param string $path
157
-	 * @param string $mode
158
-	 * @return resource
159
-	 */
160
-	public function fopen($path, $mode) {
161
-		$source = $this->storage->fopen($path, $mode);
162
-
163
-		// don't apply quota for part files
164
-		if (!$this->isPartFile($path)) {
165
-			$free = $this->free_space($path);
166
-			if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
167
-				// only apply quota for files, not metadata, trash or others
168
-				if ($this->shouldApplyQuota($path)) {
169
-					return \OC\Files\Stream\Quota::wrap($source, $free);
170
-				}
171
-			}
172
-		}
173
-		return $source;
174
-	}
175
-
176
-	/**
177
-	 * Checks whether the given path is a part file
178
-	 *
179
-	 * @param string $path Path that may identify a .part file
180
-	 * @return string File path without .part extension
181
-	 * @note this is needed for reusing keys
182
-	 */
183
-	private function isPartFile($path) {
184
-		$extension = pathinfo($path, PATHINFO_EXTENSION);
185
-
186
-		return ($extension === 'part');
187
-	}
188
-
189
-	/**
190
-	 * Only apply quota for files, not metadata, trash or others
191
-	 */
192
-	private function shouldApplyQuota(string $path): bool {
193
-		return strpos(ltrim($path, '/'), 'files/') === 0;
194
-	}
195
-
196
-	/**
197
-	 * @param IStorage $sourceStorage
198
-	 * @param string $sourceInternalPath
199
-	 * @param string $targetInternalPath
200
-	 * @return bool
201
-	 */
202
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
203
-		$free = $this->free_space($targetInternalPath);
204
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
205
-			return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
206
-		} else {
207
-			return false;
208
-		}
209
-	}
210
-
211
-	/**
212
-	 * @param IStorage $sourceStorage
213
-	 * @param string $sourceInternalPath
214
-	 * @param string $targetInternalPath
215
-	 * @return bool
216
-	 */
217
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
218
-		$free = $this->free_space($targetInternalPath);
219
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
220
-			return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
221
-		} else {
222
-			return false;
223
-		}
224
-	}
225
-
226
-	public function mkdir($path) {
227
-		$free = $this->free_space($path);
228
-		if ($this->shouldApplyQuota($path) && $free === 0.0) {
229
-			return false;
230
-		}
231
-
232
-		return parent::mkdir($path);
233
-	}
234
-
235
-	public function touch($path, $mtime = null) {
236
-		$free = $this->free_space($path);
237
-		if ($free === 0.0) {
238
-			return false;
239
-		}
240
-
241
-		return parent::touch($path, $mtime);
242
-	}
39
+    /**
40
+     * @var int $quota
41
+     */
42
+    protected $quota;
43
+
44
+    /**
45
+     * @var string $sizeRoot
46
+     */
47
+    protected $sizeRoot;
48
+
49
+    private $config;
50
+
51
+    /**
52
+     * @param array $parameters
53
+     */
54
+    public function __construct($parameters) {
55
+        parent::__construct($parameters);
56
+        $this->quota = $parameters['quota'];
57
+        $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
58
+        $this->config = \OC::$server->getSystemConfig();
59
+    }
60
+
61
+    /**
62
+     * @return int quota value
63
+     */
64
+    public function getQuota() {
65
+        return $this->quota;
66
+    }
67
+
68
+    /**
69
+     * @param string $path
70
+     * @param \OC\Files\Storage\Storage $storage
71
+     */
72
+    protected function getSize($path, $storage = null) {
73
+        if ($this->config->getValue('quota_include_external_storage', false)) {
74
+            $rootInfo = Filesystem::getFileInfo('', 'ext');
75
+            if ($rootInfo) {
76
+                return $rootInfo->getSize(true);
77
+            }
78
+            return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
79
+        } else {
80
+            if (is_null($storage)) {
81
+                $cache = $this->getCache();
82
+            } else {
83
+                $cache = $storage->getCache();
84
+            }
85
+            $data = $cache->get($path);
86
+            if ($data instanceof ICacheEntry and isset($data['size'])) {
87
+                return $data['size'];
88
+            } else {
89
+                return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
90
+            }
91
+        }
92
+    }
93
+
94
+    /**
95
+     * Get free space as limited by the quota
96
+     *
97
+     * @param string $path
98
+     * @return int
99
+     */
100
+    public function free_space($path) {
101
+        if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
102
+            return $this->storage->free_space($path);
103
+        } else {
104
+            $used = $this->getSize($this->sizeRoot);
105
+            if ($used < 0) {
106
+                return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
107
+            } else {
108
+                $free = $this->storage->free_space($path);
109
+                $quotaFree = max($this->quota - $used, 0);
110
+                // if free space is known
111
+                if ($free >= 0) {
112
+                    $free = min($free, $quotaFree);
113
+                } else {
114
+                    $free = $quotaFree;
115
+                }
116
+                return $free;
117
+            }
118
+        }
119
+    }
120
+
121
+    /**
122
+     * see http://php.net/manual/en/function.file_put_contents.php
123
+     *
124
+     * @param string $path
125
+     * @param mixed $data
126
+     * @return int|false
127
+     */
128
+    public function file_put_contents($path, $data) {
129
+        $free = $this->free_space($path);
130
+        if ($free < 0 or strlen($data) < $free) {
131
+            return $this->storage->file_put_contents($path, $data);
132
+        } else {
133
+            return false;
134
+        }
135
+    }
136
+
137
+    /**
138
+     * see http://php.net/manual/en/function.copy.php
139
+     *
140
+     * @param string $source
141
+     * @param string $target
142
+     * @return bool
143
+     */
144
+    public function copy($source, $target) {
145
+        $free = $this->free_space($target);
146
+        if ($free < 0 or $this->getSize($source) < $free) {
147
+            return $this->storage->copy($source, $target);
148
+        } else {
149
+            return false;
150
+        }
151
+    }
152
+
153
+    /**
154
+     * see http://php.net/manual/en/function.fopen.php
155
+     *
156
+     * @param string $path
157
+     * @param string $mode
158
+     * @return resource
159
+     */
160
+    public function fopen($path, $mode) {
161
+        $source = $this->storage->fopen($path, $mode);
162
+
163
+        // don't apply quota for part files
164
+        if (!$this->isPartFile($path)) {
165
+            $free = $this->free_space($path);
166
+            if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
167
+                // only apply quota for files, not metadata, trash or others
168
+                if ($this->shouldApplyQuota($path)) {
169
+                    return \OC\Files\Stream\Quota::wrap($source, $free);
170
+                }
171
+            }
172
+        }
173
+        return $source;
174
+    }
175
+
176
+    /**
177
+     * Checks whether the given path is a part file
178
+     *
179
+     * @param string $path Path that may identify a .part file
180
+     * @return string File path without .part extension
181
+     * @note this is needed for reusing keys
182
+     */
183
+    private function isPartFile($path) {
184
+        $extension = pathinfo($path, PATHINFO_EXTENSION);
185
+
186
+        return ($extension === 'part');
187
+    }
188
+
189
+    /**
190
+     * Only apply quota for files, not metadata, trash or others
191
+     */
192
+    private function shouldApplyQuota(string $path): bool {
193
+        return strpos(ltrim($path, '/'), 'files/') === 0;
194
+    }
195
+
196
+    /**
197
+     * @param IStorage $sourceStorage
198
+     * @param string $sourceInternalPath
199
+     * @param string $targetInternalPath
200
+     * @return bool
201
+     */
202
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
203
+        $free = $this->free_space($targetInternalPath);
204
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
205
+            return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
206
+        } else {
207
+            return false;
208
+        }
209
+    }
210
+
211
+    /**
212
+     * @param IStorage $sourceStorage
213
+     * @param string $sourceInternalPath
214
+     * @param string $targetInternalPath
215
+     * @return bool
216
+     */
217
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
218
+        $free = $this->free_space($targetInternalPath);
219
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
220
+            return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
221
+        } else {
222
+            return false;
223
+        }
224
+    }
225
+
226
+    public function mkdir($path) {
227
+        $free = $this->free_space($path);
228
+        if ($this->shouldApplyQuota($path) && $free === 0.0) {
229
+            return false;
230
+        }
231
+
232
+        return parent::mkdir($path);
233
+    }
234
+
235
+    public function touch($path, $mtime = null) {
236
+        $free = $this->free_space($path);
237
+        if ($free === 0.0) {
238
+            return false;
239
+        }
240
+
241
+        return parent::touch($path, $mtime);
242
+    }
243 243
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Wrapper.php 1 patch
Indentation   +604 added lines, -604 removed lines patch added patch discarded remove patch
@@ -37,608 +37,608 @@
 block discarded – undo
37 37
 use OCP\Lock\ILockingProvider;
38 38
 
39 39
 class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStreamStorage {
40
-	/**
41
-	 * @var \OC\Files\Storage\Storage $storage
42
-	 */
43
-	protected $storage;
44
-
45
-	public $cache;
46
-	public $scanner;
47
-	public $watcher;
48
-	public $propagator;
49
-	public $updater;
50
-
51
-	/**
52
-	 * @param array $parameters
53
-	 */
54
-	public function __construct($parameters) {
55
-		$this->storage = $parameters['storage'];
56
-	}
57
-
58
-	/**
59
-	 * @return \OC\Files\Storage\Storage
60
-	 */
61
-	public function getWrapperStorage() {
62
-		return $this->storage;
63
-	}
64
-
65
-	/**
66
-	 * Get the identifier for the storage,
67
-	 * the returned id should be the same for every storage object that is created with the same parameters
68
-	 * and two storage objects with the same id should refer to two storages that display the same files.
69
-	 *
70
-	 * @return string
71
-	 */
72
-	public function getId() {
73
-		return $this->getWrapperStorage()->getId();
74
-	}
75
-
76
-	/**
77
-	 * see http://php.net/manual/en/function.mkdir.php
78
-	 *
79
-	 * @param string $path
80
-	 * @return bool
81
-	 */
82
-	public function mkdir($path) {
83
-		return $this->getWrapperStorage()->mkdir($path);
84
-	}
85
-
86
-	/**
87
-	 * see http://php.net/manual/en/function.rmdir.php
88
-	 *
89
-	 * @param string $path
90
-	 * @return bool
91
-	 */
92
-	public function rmdir($path) {
93
-		return $this->getWrapperStorage()->rmdir($path);
94
-	}
95
-
96
-	/**
97
-	 * see http://php.net/manual/en/function.opendir.php
98
-	 *
99
-	 * @param string $path
100
-	 * @return resource
101
-	 */
102
-	public function opendir($path) {
103
-		return $this->getWrapperStorage()->opendir($path);
104
-	}
105
-
106
-	/**
107
-	 * see http://php.net/manual/en/function.is_dir.php
108
-	 *
109
-	 * @param string $path
110
-	 * @return bool
111
-	 */
112
-	public function is_dir($path) {
113
-		return $this->getWrapperStorage()->is_dir($path);
114
-	}
115
-
116
-	/**
117
-	 * see http://php.net/manual/en/function.is_file.php
118
-	 *
119
-	 * @param string $path
120
-	 * @return bool
121
-	 */
122
-	public function is_file($path) {
123
-		return $this->getWrapperStorage()->is_file($path);
124
-	}
125
-
126
-	/**
127
-	 * see http://php.net/manual/en/function.stat.php
128
-	 * only the following keys are required in the result: size and mtime
129
-	 *
130
-	 * @param string $path
131
-	 * @return array
132
-	 */
133
-	public function stat($path) {
134
-		return $this->getWrapperStorage()->stat($path);
135
-	}
136
-
137
-	/**
138
-	 * see http://php.net/manual/en/function.filetype.php
139
-	 *
140
-	 * @param string $path
141
-	 * @return bool
142
-	 */
143
-	public function filetype($path) {
144
-		return $this->getWrapperStorage()->filetype($path);
145
-	}
146
-
147
-	/**
148
-	 * see http://php.net/manual/en/function.filesize.php
149
-	 * The result for filesize when called on a folder is required to be 0
150
-	 *
151
-	 * @param string $path
152
-	 * @return int
153
-	 */
154
-	public function filesize($path) {
155
-		return $this->getWrapperStorage()->filesize($path);
156
-	}
157
-
158
-	/**
159
-	 * check if a file can be created in $path
160
-	 *
161
-	 * @param string $path
162
-	 * @return bool
163
-	 */
164
-	public function isCreatable($path) {
165
-		return $this->getWrapperStorage()->isCreatable($path);
166
-	}
167
-
168
-	/**
169
-	 * check if a file can be read
170
-	 *
171
-	 * @param string $path
172
-	 * @return bool
173
-	 */
174
-	public function isReadable($path) {
175
-		return $this->getWrapperStorage()->isReadable($path);
176
-	}
177
-
178
-	/**
179
-	 * check if a file can be written to
180
-	 *
181
-	 * @param string $path
182
-	 * @return bool
183
-	 */
184
-	public function isUpdatable($path) {
185
-		return $this->getWrapperStorage()->isUpdatable($path);
186
-	}
187
-
188
-	/**
189
-	 * check if a file can be deleted
190
-	 *
191
-	 * @param string $path
192
-	 * @return bool
193
-	 */
194
-	public function isDeletable($path) {
195
-		return $this->getWrapperStorage()->isDeletable($path);
196
-	}
197
-
198
-	/**
199
-	 * check if a file can be shared
200
-	 *
201
-	 * @param string $path
202
-	 * @return bool
203
-	 */
204
-	public function isSharable($path) {
205
-		return $this->getWrapperStorage()->isSharable($path);
206
-	}
207
-
208
-	/**
209
-	 * get the full permissions of a path.
210
-	 * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
211
-	 *
212
-	 * @param string $path
213
-	 * @return int
214
-	 */
215
-	public function getPermissions($path) {
216
-		return $this->getWrapperStorage()->getPermissions($path);
217
-	}
218
-
219
-	/**
220
-	 * see http://php.net/manual/en/function.file_exists.php
221
-	 *
222
-	 * @param string $path
223
-	 * @return bool
224
-	 */
225
-	public function file_exists($path) {
226
-		return $this->getWrapperStorage()->file_exists($path);
227
-	}
228
-
229
-	/**
230
-	 * see http://php.net/manual/en/function.filemtime.php
231
-	 *
232
-	 * @param string $path
233
-	 * @return int
234
-	 */
235
-	public function filemtime($path) {
236
-		return $this->getWrapperStorage()->filemtime($path);
237
-	}
238
-
239
-	/**
240
-	 * see http://php.net/manual/en/function.file_get_contents.php
241
-	 *
242
-	 * @param string $path
243
-	 * @return string
244
-	 */
245
-	public function file_get_contents($path) {
246
-		return $this->getWrapperStorage()->file_get_contents($path);
247
-	}
248
-
249
-	/**
250
-	 * see http://php.net/manual/en/function.file_put_contents.php
251
-	 *
252
-	 * @param string $path
253
-	 * @param mixed $data
254
-	 * @return int|false
255
-	 */
256
-	public function file_put_contents($path, $data) {
257
-		return $this->getWrapperStorage()->file_put_contents($path, $data);
258
-	}
259
-
260
-	/**
261
-	 * see http://php.net/manual/en/function.unlink.php
262
-	 *
263
-	 * @param string $path
264
-	 * @return bool
265
-	 */
266
-	public function unlink($path) {
267
-		return $this->getWrapperStorage()->unlink($path);
268
-	}
269
-
270
-	/**
271
-	 * see http://php.net/manual/en/function.rename.php
272
-	 *
273
-	 * @param string $path1
274
-	 * @param string $path2
275
-	 * @return bool
276
-	 */
277
-	public function rename($path1, $path2) {
278
-		return $this->getWrapperStorage()->rename($path1, $path2);
279
-	}
280
-
281
-	/**
282
-	 * see http://php.net/manual/en/function.copy.php
283
-	 *
284
-	 * @param string $path1
285
-	 * @param string $path2
286
-	 * @return bool
287
-	 */
288
-	public function copy($path1, $path2) {
289
-		return $this->getWrapperStorage()->copy($path1, $path2);
290
-	}
291
-
292
-	/**
293
-	 * see http://php.net/manual/en/function.fopen.php
294
-	 *
295
-	 * @param string $path
296
-	 * @param string $mode
297
-	 * @return resource
298
-	 */
299
-	public function fopen($path, $mode) {
300
-		return $this->getWrapperStorage()->fopen($path, $mode);
301
-	}
302
-
303
-	/**
304
-	 * get the mimetype for a file or folder
305
-	 * The mimetype for a folder is required to be "httpd/unix-directory"
306
-	 *
307
-	 * @param string $path
308
-	 * @return string
309
-	 */
310
-	public function getMimeType($path) {
311
-		return $this->getWrapperStorage()->getMimeType($path);
312
-	}
313
-
314
-	/**
315
-	 * see http://php.net/manual/en/function.hash.php
316
-	 *
317
-	 * @param string $type
318
-	 * @param string $path
319
-	 * @param bool $raw
320
-	 * @return string
321
-	 */
322
-	public function hash($type, $path, $raw = false) {
323
-		return $this->getWrapperStorage()->hash($type, $path, $raw);
324
-	}
325
-
326
-	/**
327
-	 * see http://php.net/manual/en/function.free_space.php
328
-	 *
329
-	 * @param string $path
330
-	 * @return int
331
-	 */
332
-	public function free_space($path) {
333
-		return $this->getWrapperStorage()->free_space($path);
334
-	}
335
-
336
-	/**
337
-	 * search for occurrences of $query in file names
338
-	 *
339
-	 * @param string $query
340
-	 * @return array
341
-	 */
342
-	public function search($query) {
343
-		return $this->getWrapperStorage()->search($query);
344
-	}
345
-
346
-	/**
347
-	 * see http://php.net/manual/en/function.touch.php
348
-	 * If the backend does not support the operation, false should be returned
349
-	 *
350
-	 * @param string $path
351
-	 * @param int $mtime
352
-	 * @return bool
353
-	 */
354
-	public function touch($path, $mtime = null) {
355
-		return $this->getWrapperStorage()->touch($path, $mtime);
356
-	}
357
-
358
-	/**
359
-	 * get the path to a local version of the file.
360
-	 * The local version of the file can be temporary and doesn't have to be persistent across requests
361
-	 *
362
-	 * @param string $path
363
-	 * @return string
364
-	 */
365
-	public function getLocalFile($path) {
366
-		return $this->getWrapperStorage()->getLocalFile($path);
367
-	}
368
-
369
-	/**
370
-	 * check if a file or folder has been updated since $time
371
-	 *
372
-	 * @param string $path
373
-	 * @param int $time
374
-	 * @return bool
375
-	 *
376
-	 * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
377
-	 * returning true for other changes in the folder is optional
378
-	 */
379
-	public function hasUpdated($path, $time) {
380
-		return $this->getWrapperStorage()->hasUpdated($path, $time);
381
-	}
382
-
383
-	/**
384
-	 * get a cache instance for the storage
385
-	 *
386
-	 * @param string $path
387
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
388
-	 * @return \OC\Files\Cache\Cache
389
-	 */
390
-	public function getCache($path = '', $storage = null) {
391
-		if (!$storage) {
392
-			$storage = $this;
393
-		}
394
-		return $this->getWrapperStorage()->getCache($path, $storage);
395
-	}
396
-
397
-	/**
398
-	 * get a scanner instance for the storage
399
-	 *
400
-	 * @param string $path
401
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
402
-	 * @return \OC\Files\Cache\Scanner
403
-	 */
404
-	public function getScanner($path = '', $storage = null) {
405
-		if (!$storage) {
406
-			$storage = $this;
407
-		}
408
-		return $this->getWrapperStorage()->getScanner($path, $storage);
409
-	}
410
-
411
-
412
-	/**
413
-	 * get the user id of the owner of a file or folder
414
-	 *
415
-	 * @param string $path
416
-	 * @return string
417
-	 */
418
-	public function getOwner($path) {
419
-		return $this->getWrapperStorage()->getOwner($path);
420
-	}
421
-
422
-	/**
423
-	 * get a watcher instance for the cache
424
-	 *
425
-	 * @param string $path
426
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
427
-	 * @return \OC\Files\Cache\Watcher
428
-	 */
429
-	public function getWatcher($path = '', $storage = null) {
430
-		if (!$storage) {
431
-			$storage = $this;
432
-		}
433
-		return $this->getWrapperStorage()->getWatcher($path, $storage);
434
-	}
435
-
436
-	public function getPropagator($storage = null) {
437
-		if (!$storage) {
438
-			$storage = $this;
439
-		}
440
-		return $this->getWrapperStorage()->getPropagator($storage);
441
-	}
442
-
443
-	public function getUpdater($storage = null) {
444
-		if (!$storage) {
445
-			$storage = $this;
446
-		}
447
-		return $this->getWrapperStorage()->getUpdater($storage);
448
-	}
449
-
450
-	/**
451
-	 * @return \OC\Files\Cache\Storage
452
-	 */
453
-	public function getStorageCache() {
454
-		return $this->getWrapperStorage()->getStorageCache();
455
-	}
456
-
457
-	/**
458
-	 * get the ETag for a file or folder
459
-	 *
460
-	 * @param string $path
461
-	 * @return string
462
-	 */
463
-	public function getETag($path) {
464
-		return $this->getWrapperStorage()->getETag($path);
465
-	}
466
-
467
-	/**
468
-	 * Returns true
469
-	 *
470
-	 * @return true
471
-	 */
472
-	public function test() {
473
-		return $this->getWrapperStorage()->test();
474
-	}
475
-
476
-	/**
477
-	 * Returns the wrapped storage's value for isLocal()
478
-	 *
479
-	 * @return bool wrapped storage's isLocal() value
480
-	 */
481
-	public function isLocal() {
482
-		return $this->getWrapperStorage()->isLocal();
483
-	}
484
-
485
-	/**
486
-	 * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
487
-	 *
488
-	 * @param string $class
489
-	 * @return bool
490
-	 */
491
-	public function instanceOfStorage($class) {
492
-		if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
493
-			// FIXME Temporary fix to keep existing checks working
494
-			$class = '\OCA\Files_Sharing\SharedStorage';
495
-		}
496
-		return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class);
497
-	}
498
-
499
-	/**
500
-	 * Pass any methods custom to specific storage implementations to the wrapped storage
501
-	 *
502
-	 * @param string $method
503
-	 * @param array $args
504
-	 * @return mixed
505
-	 */
506
-	public function __call($method, $args) {
507
-		return call_user_func_array([$this->getWrapperStorage(), $method], $args);
508
-	}
509
-
510
-	/**
511
-	 * A custom storage implementation can return an url for direct download of a give file.
512
-	 *
513
-	 * For now the returned array can hold the parameter url - in future more attributes might follow.
514
-	 *
515
-	 * @param string $path
516
-	 * @return array
517
-	 */
518
-	public function getDirectDownload($path) {
519
-		return $this->getWrapperStorage()->getDirectDownload($path);
520
-	}
521
-
522
-	/**
523
-	 * Get availability of the storage
524
-	 *
525
-	 * @return array [ available, last_checked ]
526
-	 */
527
-	public function getAvailability() {
528
-		return $this->getWrapperStorage()->getAvailability();
529
-	}
530
-
531
-	/**
532
-	 * Set availability of the storage
533
-	 *
534
-	 * @param bool $isAvailable
535
-	 */
536
-	public function setAvailability($isAvailable) {
537
-		$this->getWrapperStorage()->setAvailability($isAvailable);
538
-	}
539
-
540
-	/**
541
-	 * @param string $path the path of the target folder
542
-	 * @param string $fileName the name of the file itself
543
-	 * @return void
544
-	 * @throws InvalidPathException
545
-	 */
546
-	public function verifyPath($path, $fileName) {
547
-		$this->getWrapperStorage()->verifyPath($path, $fileName);
548
-	}
549
-
550
-	/**
551
-	 * @param IStorage $sourceStorage
552
-	 * @param string $sourceInternalPath
553
-	 * @param string $targetInternalPath
554
-	 * @return bool
555
-	 */
556
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
557
-		if ($sourceStorage === $this) {
558
-			return $this->copy($sourceInternalPath, $targetInternalPath);
559
-		}
560
-
561
-		return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
562
-	}
563
-
564
-	/**
565
-	 * @param IStorage $sourceStorage
566
-	 * @param string $sourceInternalPath
567
-	 * @param string $targetInternalPath
568
-	 * @return bool
569
-	 */
570
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
571
-		if ($sourceStorage === $this) {
572
-			return $this->rename($sourceInternalPath, $targetInternalPath);
573
-		}
574
-
575
-		return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
576
-	}
577
-
578
-	/**
579
-	 * @param string $path
580
-	 * @return array
581
-	 */
582
-	public function getMetaData($path) {
583
-		return $this->getWrapperStorage()->getMetaData($path);
584
-	}
585
-
586
-	/**
587
-	 * @param string $path
588
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
589
-	 * @param \OCP\Lock\ILockingProvider $provider
590
-	 * @throws \OCP\Lock\LockedException
591
-	 */
592
-	public function acquireLock($path, $type, ILockingProvider $provider) {
593
-		if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
594
-			$this->getWrapperStorage()->acquireLock($path, $type, $provider);
595
-		}
596
-	}
597
-
598
-	/**
599
-	 * @param string $path
600
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
601
-	 * @param \OCP\Lock\ILockingProvider $provider
602
-	 */
603
-	public function releaseLock($path, $type, ILockingProvider $provider) {
604
-		if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
605
-			$this->getWrapperStorage()->releaseLock($path, $type, $provider);
606
-		}
607
-	}
608
-
609
-	/**
610
-	 * @param string $path
611
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
612
-	 * @param \OCP\Lock\ILockingProvider $provider
613
-	 */
614
-	public function changeLock($path, $type, ILockingProvider $provider) {
615
-		if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
616
-			$this->getWrapperStorage()->changeLock($path, $type, $provider);
617
-		}
618
-	}
619
-
620
-	/**
621
-	 * @return bool
622
-	 */
623
-	public function needsPartFile() {
624
-		return $this->getWrapperStorage()->needsPartFile();
625
-	}
626
-
627
-	public function writeStream(string $path, $stream, int $size = null): int {
628
-		$storage = $this->getWrapperStorage();
629
-		if ($storage->instanceOfStorage(IWriteStreamStorage::class)) {
630
-			/** @var IWriteStreamStorage $storage */
631
-			return $storage->writeStream($path, $stream, $size);
632
-		} else {
633
-			$target = $this->fopen($path, 'w');
634
-			list($count, $result) = \OC_Helper::streamCopy($stream, $target);
635
-			fclose($stream);
636
-			fclose($target);
637
-			return $count;
638
-		}
639
-	}
640
-
641
-	public function getDirectoryContent($directory): \Traversable {
642
-		return $this->getWrapperStorage()->getDirectoryContent($directory);
643
-	}
40
+    /**
41
+     * @var \OC\Files\Storage\Storage $storage
42
+     */
43
+    protected $storage;
44
+
45
+    public $cache;
46
+    public $scanner;
47
+    public $watcher;
48
+    public $propagator;
49
+    public $updater;
50
+
51
+    /**
52
+     * @param array $parameters
53
+     */
54
+    public function __construct($parameters) {
55
+        $this->storage = $parameters['storage'];
56
+    }
57
+
58
+    /**
59
+     * @return \OC\Files\Storage\Storage
60
+     */
61
+    public function getWrapperStorage() {
62
+        return $this->storage;
63
+    }
64
+
65
+    /**
66
+     * Get the identifier for the storage,
67
+     * the returned id should be the same for every storage object that is created with the same parameters
68
+     * and two storage objects with the same id should refer to two storages that display the same files.
69
+     *
70
+     * @return string
71
+     */
72
+    public function getId() {
73
+        return $this->getWrapperStorage()->getId();
74
+    }
75
+
76
+    /**
77
+     * see http://php.net/manual/en/function.mkdir.php
78
+     *
79
+     * @param string $path
80
+     * @return bool
81
+     */
82
+    public function mkdir($path) {
83
+        return $this->getWrapperStorage()->mkdir($path);
84
+    }
85
+
86
+    /**
87
+     * see http://php.net/manual/en/function.rmdir.php
88
+     *
89
+     * @param string $path
90
+     * @return bool
91
+     */
92
+    public function rmdir($path) {
93
+        return $this->getWrapperStorage()->rmdir($path);
94
+    }
95
+
96
+    /**
97
+     * see http://php.net/manual/en/function.opendir.php
98
+     *
99
+     * @param string $path
100
+     * @return resource
101
+     */
102
+    public function opendir($path) {
103
+        return $this->getWrapperStorage()->opendir($path);
104
+    }
105
+
106
+    /**
107
+     * see http://php.net/manual/en/function.is_dir.php
108
+     *
109
+     * @param string $path
110
+     * @return bool
111
+     */
112
+    public function is_dir($path) {
113
+        return $this->getWrapperStorage()->is_dir($path);
114
+    }
115
+
116
+    /**
117
+     * see http://php.net/manual/en/function.is_file.php
118
+     *
119
+     * @param string $path
120
+     * @return bool
121
+     */
122
+    public function is_file($path) {
123
+        return $this->getWrapperStorage()->is_file($path);
124
+    }
125
+
126
+    /**
127
+     * see http://php.net/manual/en/function.stat.php
128
+     * only the following keys are required in the result: size and mtime
129
+     *
130
+     * @param string $path
131
+     * @return array
132
+     */
133
+    public function stat($path) {
134
+        return $this->getWrapperStorage()->stat($path);
135
+    }
136
+
137
+    /**
138
+     * see http://php.net/manual/en/function.filetype.php
139
+     *
140
+     * @param string $path
141
+     * @return bool
142
+     */
143
+    public function filetype($path) {
144
+        return $this->getWrapperStorage()->filetype($path);
145
+    }
146
+
147
+    /**
148
+     * see http://php.net/manual/en/function.filesize.php
149
+     * The result for filesize when called on a folder is required to be 0
150
+     *
151
+     * @param string $path
152
+     * @return int
153
+     */
154
+    public function filesize($path) {
155
+        return $this->getWrapperStorage()->filesize($path);
156
+    }
157
+
158
+    /**
159
+     * check if a file can be created in $path
160
+     *
161
+     * @param string $path
162
+     * @return bool
163
+     */
164
+    public function isCreatable($path) {
165
+        return $this->getWrapperStorage()->isCreatable($path);
166
+    }
167
+
168
+    /**
169
+     * check if a file can be read
170
+     *
171
+     * @param string $path
172
+     * @return bool
173
+     */
174
+    public function isReadable($path) {
175
+        return $this->getWrapperStorage()->isReadable($path);
176
+    }
177
+
178
+    /**
179
+     * check if a file can be written to
180
+     *
181
+     * @param string $path
182
+     * @return bool
183
+     */
184
+    public function isUpdatable($path) {
185
+        return $this->getWrapperStorage()->isUpdatable($path);
186
+    }
187
+
188
+    /**
189
+     * check if a file can be deleted
190
+     *
191
+     * @param string $path
192
+     * @return bool
193
+     */
194
+    public function isDeletable($path) {
195
+        return $this->getWrapperStorage()->isDeletable($path);
196
+    }
197
+
198
+    /**
199
+     * check if a file can be shared
200
+     *
201
+     * @param string $path
202
+     * @return bool
203
+     */
204
+    public function isSharable($path) {
205
+        return $this->getWrapperStorage()->isSharable($path);
206
+    }
207
+
208
+    /**
209
+     * get the full permissions of a path.
210
+     * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php
211
+     *
212
+     * @param string $path
213
+     * @return int
214
+     */
215
+    public function getPermissions($path) {
216
+        return $this->getWrapperStorage()->getPermissions($path);
217
+    }
218
+
219
+    /**
220
+     * see http://php.net/manual/en/function.file_exists.php
221
+     *
222
+     * @param string $path
223
+     * @return bool
224
+     */
225
+    public function file_exists($path) {
226
+        return $this->getWrapperStorage()->file_exists($path);
227
+    }
228
+
229
+    /**
230
+     * see http://php.net/manual/en/function.filemtime.php
231
+     *
232
+     * @param string $path
233
+     * @return int
234
+     */
235
+    public function filemtime($path) {
236
+        return $this->getWrapperStorage()->filemtime($path);
237
+    }
238
+
239
+    /**
240
+     * see http://php.net/manual/en/function.file_get_contents.php
241
+     *
242
+     * @param string $path
243
+     * @return string
244
+     */
245
+    public function file_get_contents($path) {
246
+        return $this->getWrapperStorage()->file_get_contents($path);
247
+    }
248
+
249
+    /**
250
+     * see http://php.net/manual/en/function.file_put_contents.php
251
+     *
252
+     * @param string $path
253
+     * @param mixed $data
254
+     * @return int|false
255
+     */
256
+    public function file_put_contents($path, $data) {
257
+        return $this->getWrapperStorage()->file_put_contents($path, $data);
258
+    }
259
+
260
+    /**
261
+     * see http://php.net/manual/en/function.unlink.php
262
+     *
263
+     * @param string $path
264
+     * @return bool
265
+     */
266
+    public function unlink($path) {
267
+        return $this->getWrapperStorage()->unlink($path);
268
+    }
269
+
270
+    /**
271
+     * see http://php.net/manual/en/function.rename.php
272
+     *
273
+     * @param string $path1
274
+     * @param string $path2
275
+     * @return bool
276
+     */
277
+    public function rename($path1, $path2) {
278
+        return $this->getWrapperStorage()->rename($path1, $path2);
279
+    }
280
+
281
+    /**
282
+     * see http://php.net/manual/en/function.copy.php
283
+     *
284
+     * @param string $path1
285
+     * @param string $path2
286
+     * @return bool
287
+     */
288
+    public function copy($path1, $path2) {
289
+        return $this->getWrapperStorage()->copy($path1, $path2);
290
+    }
291
+
292
+    /**
293
+     * see http://php.net/manual/en/function.fopen.php
294
+     *
295
+     * @param string $path
296
+     * @param string $mode
297
+     * @return resource
298
+     */
299
+    public function fopen($path, $mode) {
300
+        return $this->getWrapperStorage()->fopen($path, $mode);
301
+    }
302
+
303
+    /**
304
+     * get the mimetype for a file or folder
305
+     * The mimetype for a folder is required to be "httpd/unix-directory"
306
+     *
307
+     * @param string $path
308
+     * @return string
309
+     */
310
+    public function getMimeType($path) {
311
+        return $this->getWrapperStorage()->getMimeType($path);
312
+    }
313
+
314
+    /**
315
+     * see http://php.net/manual/en/function.hash.php
316
+     *
317
+     * @param string $type
318
+     * @param string $path
319
+     * @param bool $raw
320
+     * @return string
321
+     */
322
+    public function hash($type, $path, $raw = false) {
323
+        return $this->getWrapperStorage()->hash($type, $path, $raw);
324
+    }
325
+
326
+    /**
327
+     * see http://php.net/manual/en/function.free_space.php
328
+     *
329
+     * @param string $path
330
+     * @return int
331
+     */
332
+    public function free_space($path) {
333
+        return $this->getWrapperStorage()->free_space($path);
334
+    }
335
+
336
+    /**
337
+     * search for occurrences of $query in file names
338
+     *
339
+     * @param string $query
340
+     * @return array
341
+     */
342
+    public function search($query) {
343
+        return $this->getWrapperStorage()->search($query);
344
+    }
345
+
346
+    /**
347
+     * see http://php.net/manual/en/function.touch.php
348
+     * If the backend does not support the operation, false should be returned
349
+     *
350
+     * @param string $path
351
+     * @param int $mtime
352
+     * @return bool
353
+     */
354
+    public function touch($path, $mtime = null) {
355
+        return $this->getWrapperStorage()->touch($path, $mtime);
356
+    }
357
+
358
+    /**
359
+     * get the path to a local version of the file.
360
+     * The local version of the file can be temporary and doesn't have to be persistent across requests
361
+     *
362
+     * @param string $path
363
+     * @return string
364
+     */
365
+    public function getLocalFile($path) {
366
+        return $this->getWrapperStorage()->getLocalFile($path);
367
+    }
368
+
369
+    /**
370
+     * check if a file or folder has been updated since $time
371
+     *
372
+     * @param string $path
373
+     * @param int $time
374
+     * @return bool
375
+     *
376
+     * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
377
+     * returning true for other changes in the folder is optional
378
+     */
379
+    public function hasUpdated($path, $time) {
380
+        return $this->getWrapperStorage()->hasUpdated($path, $time);
381
+    }
382
+
383
+    /**
384
+     * get a cache instance for the storage
385
+     *
386
+     * @param string $path
387
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
388
+     * @return \OC\Files\Cache\Cache
389
+     */
390
+    public function getCache($path = '', $storage = null) {
391
+        if (!$storage) {
392
+            $storage = $this;
393
+        }
394
+        return $this->getWrapperStorage()->getCache($path, $storage);
395
+    }
396
+
397
+    /**
398
+     * get a scanner instance for the storage
399
+     *
400
+     * @param string $path
401
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
402
+     * @return \OC\Files\Cache\Scanner
403
+     */
404
+    public function getScanner($path = '', $storage = null) {
405
+        if (!$storage) {
406
+            $storage = $this;
407
+        }
408
+        return $this->getWrapperStorage()->getScanner($path, $storage);
409
+    }
410
+
411
+
412
+    /**
413
+     * get the user id of the owner of a file or folder
414
+     *
415
+     * @param string $path
416
+     * @return string
417
+     */
418
+    public function getOwner($path) {
419
+        return $this->getWrapperStorage()->getOwner($path);
420
+    }
421
+
422
+    /**
423
+     * get a watcher instance for the cache
424
+     *
425
+     * @param string $path
426
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
427
+     * @return \OC\Files\Cache\Watcher
428
+     */
429
+    public function getWatcher($path = '', $storage = null) {
430
+        if (!$storage) {
431
+            $storage = $this;
432
+        }
433
+        return $this->getWrapperStorage()->getWatcher($path, $storage);
434
+    }
435
+
436
+    public function getPropagator($storage = null) {
437
+        if (!$storage) {
438
+            $storage = $this;
439
+        }
440
+        return $this->getWrapperStorage()->getPropagator($storage);
441
+    }
442
+
443
+    public function getUpdater($storage = null) {
444
+        if (!$storage) {
445
+            $storage = $this;
446
+        }
447
+        return $this->getWrapperStorage()->getUpdater($storage);
448
+    }
449
+
450
+    /**
451
+     * @return \OC\Files\Cache\Storage
452
+     */
453
+    public function getStorageCache() {
454
+        return $this->getWrapperStorage()->getStorageCache();
455
+    }
456
+
457
+    /**
458
+     * get the ETag for a file or folder
459
+     *
460
+     * @param string $path
461
+     * @return string
462
+     */
463
+    public function getETag($path) {
464
+        return $this->getWrapperStorage()->getETag($path);
465
+    }
466
+
467
+    /**
468
+     * Returns true
469
+     *
470
+     * @return true
471
+     */
472
+    public function test() {
473
+        return $this->getWrapperStorage()->test();
474
+    }
475
+
476
+    /**
477
+     * Returns the wrapped storage's value for isLocal()
478
+     *
479
+     * @return bool wrapped storage's isLocal() value
480
+     */
481
+    public function isLocal() {
482
+        return $this->getWrapperStorage()->isLocal();
483
+    }
484
+
485
+    /**
486
+     * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
487
+     *
488
+     * @param string $class
489
+     * @return bool
490
+     */
491
+    public function instanceOfStorage($class) {
492
+        if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
493
+            // FIXME Temporary fix to keep existing checks working
494
+            $class = '\OCA\Files_Sharing\SharedStorage';
495
+        }
496
+        return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class);
497
+    }
498
+
499
+    /**
500
+     * Pass any methods custom to specific storage implementations to the wrapped storage
501
+     *
502
+     * @param string $method
503
+     * @param array $args
504
+     * @return mixed
505
+     */
506
+    public function __call($method, $args) {
507
+        return call_user_func_array([$this->getWrapperStorage(), $method], $args);
508
+    }
509
+
510
+    /**
511
+     * A custom storage implementation can return an url for direct download of a give file.
512
+     *
513
+     * For now the returned array can hold the parameter url - in future more attributes might follow.
514
+     *
515
+     * @param string $path
516
+     * @return array
517
+     */
518
+    public function getDirectDownload($path) {
519
+        return $this->getWrapperStorage()->getDirectDownload($path);
520
+    }
521
+
522
+    /**
523
+     * Get availability of the storage
524
+     *
525
+     * @return array [ available, last_checked ]
526
+     */
527
+    public function getAvailability() {
528
+        return $this->getWrapperStorage()->getAvailability();
529
+    }
530
+
531
+    /**
532
+     * Set availability of the storage
533
+     *
534
+     * @param bool $isAvailable
535
+     */
536
+    public function setAvailability($isAvailable) {
537
+        $this->getWrapperStorage()->setAvailability($isAvailable);
538
+    }
539
+
540
+    /**
541
+     * @param string $path the path of the target folder
542
+     * @param string $fileName the name of the file itself
543
+     * @return void
544
+     * @throws InvalidPathException
545
+     */
546
+    public function verifyPath($path, $fileName) {
547
+        $this->getWrapperStorage()->verifyPath($path, $fileName);
548
+    }
549
+
550
+    /**
551
+     * @param IStorage $sourceStorage
552
+     * @param string $sourceInternalPath
553
+     * @param string $targetInternalPath
554
+     * @return bool
555
+     */
556
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
557
+        if ($sourceStorage === $this) {
558
+            return $this->copy($sourceInternalPath, $targetInternalPath);
559
+        }
560
+
561
+        return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
562
+    }
563
+
564
+    /**
565
+     * @param IStorage $sourceStorage
566
+     * @param string $sourceInternalPath
567
+     * @param string $targetInternalPath
568
+     * @return bool
569
+     */
570
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
571
+        if ($sourceStorage === $this) {
572
+            return $this->rename($sourceInternalPath, $targetInternalPath);
573
+        }
574
+
575
+        return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
576
+    }
577
+
578
+    /**
579
+     * @param string $path
580
+     * @return array
581
+     */
582
+    public function getMetaData($path) {
583
+        return $this->getWrapperStorage()->getMetaData($path);
584
+    }
585
+
586
+    /**
587
+     * @param string $path
588
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
589
+     * @param \OCP\Lock\ILockingProvider $provider
590
+     * @throws \OCP\Lock\LockedException
591
+     */
592
+    public function acquireLock($path, $type, ILockingProvider $provider) {
593
+        if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
594
+            $this->getWrapperStorage()->acquireLock($path, $type, $provider);
595
+        }
596
+    }
597
+
598
+    /**
599
+     * @param string $path
600
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
601
+     * @param \OCP\Lock\ILockingProvider $provider
602
+     */
603
+    public function releaseLock($path, $type, ILockingProvider $provider) {
604
+        if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
605
+            $this->getWrapperStorage()->releaseLock($path, $type, $provider);
606
+        }
607
+    }
608
+
609
+    /**
610
+     * @param string $path
611
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
612
+     * @param \OCP\Lock\ILockingProvider $provider
613
+     */
614
+    public function changeLock($path, $type, ILockingProvider $provider) {
615
+        if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
616
+            $this->getWrapperStorage()->changeLock($path, $type, $provider);
617
+        }
618
+    }
619
+
620
+    /**
621
+     * @return bool
622
+     */
623
+    public function needsPartFile() {
624
+        return $this->getWrapperStorage()->needsPartFile();
625
+    }
626
+
627
+    public function writeStream(string $path, $stream, int $size = null): int {
628
+        $storage = $this->getWrapperStorage();
629
+        if ($storage->instanceOfStorage(IWriteStreamStorage::class)) {
630
+            /** @var IWriteStreamStorage $storage */
631
+            return $storage->writeStream($path, $stream, $size);
632
+        } else {
633
+            $target = $this->fopen($path, 'w');
634
+            list($count, $result) = \OC_Helper::streamCopy($stream, $target);
635
+            fclose($stream);
636
+            fclose($target);
637
+            return $count;
638
+        }
639
+    }
640
+
641
+    public function getDirectoryContent($directory): \Traversable {
642
+        return $this->getWrapperStorage()->getDirectoryContent($directory);
643
+    }
644 644
 }
Please login to merge, or discard this patch.