Passed
Push — master ( a1f329...b8b53a )
by Roeland
40:17 queued 29:06
created
apps/dav/lib/Connector/Sabre/Directory.php 1 patch
Indentation   +396 added lines, -396 removed lines patch added patch discarded remove patch
@@ -52,400 +52,400 @@
 block discarded – undo
52 52
 
53 53
 class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota, \Sabre\DAV\IMoveTarget {
54 54
 
55
-	/**
56
-	 * Cached directory content
57
-	 *
58
-	 * @var \OCP\Files\FileInfo[]
59
-	 */
60
-	private $dirContent;
61
-
62
-	/**
63
-	 * Cached quota info
64
-	 *
65
-	 * @var array
66
-	 */
67
-	private $quotaInfo;
68
-
69
-	/**
70
-	 * @var ObjectTree|null
71
-	 */
72
-	private $tree;
73
-
74
-	/**
75
-	 * Sets up the node, expects a full path name
76
-	 *
77
-	 * @param \OC\Files\View $view
78
-	 * @param \OCP\Files\FileInfo $info
79
-	 * @param ObjectTree|null $tree
80
-	 * @param \OCP\Share\IManager $shareManager
81
-	 */
82
-	public function __construct(View $view, FileInfo $info, $tree = null, $shareManager = null) {
83
-		parent::__construct($view, $info, $shareManager);
84
-		$this->tree = $tree;
85
-	}
86
-
87
-	/**
88
-	 * Creates a new file in the directory
89
-	 *
90
-	 * Data will either be supplied as a stream resource, or in certain cases
91
-	 * as a string. Keep in mind that you may have to support either.
92
-	 *
93
-	 * After successful creation of the file, you may choose to return the ETag
94
-	 * of the new file here.
95
-	 *
96
-	 * The returned ETag must be surrounded by double-quotes (The quotes should
97
-	 * be part of the actual string).
98
-	 *
99
-	 * If you cannot accurately determine the ETag, you should not return it.
100
-	 * If you don't store the file exactly as-is (you're transforming it
101
-	 * somehow) you should also not return an ETag.
102
-	 *
103
-	 * This means that if a subsequent GET to this new file does not exactly
104
-	 * return the same contents of what was submitted here, you are strongly
105
-	 * recommended to omit the ETag.
106
-	 *
107
-	 * @param string $name Name of the file
108
-	 * @param resource|string $data Initial payload
109
-	 * @return null|string
110
-	 * @throws Exception\EntityTooLarge
111
-	 * @throws Exception\UnsupportedMediaType
112
-	 * @throws FileLocked
113
-	 * @throws InvalidPath
114
-	 * @throws \Sabre\DAV\Exception
115
-	 * @throws \Sabre\DAV\Exception\BadRequest
116
-	 * @throws \Sabre\DAV\Exception\Forbidden
117
-	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
118
-	 */
119
-	public function createFile($name, $data = null) {
120
-		try {
121
-			// for chunked upload also updating a existing file is a "createFile"
122
-			// because we create all the chunks before re-assemble them to the existing file.
123
-			if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
124
-
125
-				// exit if we can't create a new file and we don't updatable existing file
126
-				$chunkInfo = \OC_FileChunking::decodeName($name);
127
-				if (!$this->fileView->isCreatable($this->path) &&
128
-					!$this->fileView->isUpdatable($this->path . '/' . $chunkInfo['name'])
129
-				) {
130
-					throw new \Sabre\DAV\Exception\Forbidden();
131
-				}
132
-			} else {
133
-				// For non-chunked upload it is enough to check if we can create a new file
134
-				if (!$this->fileView->isCreatable($this->path)) {
135
-					throw new \Sabre\DAV\Exception\Forbidden();
136
-				}
137
-			}
138
-
139
-			$this->fileView->verifyPath($this->path, $name);
140
-
141
-			$path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
142
-			// in case the file already exists/overwriting
143
-			$info = $this->fileView->getFileInfo($this->path . '/' . $name);
144
-			if (!$info) {
145
-				// use a dummy FileInfo which is acceptable here since it will be refreshed after the put is complete
146
-				$info = new \OC\Files\FileInfo($path, null, null, [], null);
147
-			}
148
-			$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
149
-
150
-			// only allow 1 process to upload a file at once but still allow reading the file while writing the part file
151
-			$node->acquireLock(ILockingProvider::LOCK_SHARED);
152
-			$this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
153
-
154
-			$result = $node->put($data);
155
-
156
-			$this->fileView->unlockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
157
-			$node->releaseLock(ILockingProvider::LOCK_SHARED);
158
-			return $result;
159
-		} catch (\OCP\Files\StorageNotAvailableException $e) {
160
-			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage(), $e->getCode(), $e);
161
-		} catch (InvalidPathException $ex) {
162
-			throw new InvalidPath($ex->getMessage(), false, $ex);
163
-		} catch (ForbiddenException $ex) {
164
-			throw new Forbidden($ex->getMessage(), $ex->getRetry(), $ex);
165
-		} catch (LockedException $e) {
166
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
167
-		}
168
-	}
169
-
170
-	/**
171
-	 * Creates a new subdirectory
172
-	 *
173
-	 * @param string $name
174
-	 * @throws FileLocked
175
-	 * @throws InvalidPath
176
-	 * @throws \Sabre\DAV\Exception\Forbidden
177
-	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
178
-	 */
179
-	public function createDirectory($name) {
180
-		try {
181
-			if (!$this->info->isCreatable()) {
182
-				throw new \Sabre\DAV\Exception\Forbidden();
183
-			}
184
-
185
-			$this->fileView->verifyPath($this->path, $name);
186
-			$newPath = $this->path . '/' . $name;
187
-			if (!$this->fileView->mkdir($newPath)) {
188
-				throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath);
189
-			}
190
-		} catch (\OCP\Files\StorageNotAvailableException $e) {
191
-			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
192
-		} catch (InvalidPathException $ex) {
193
-			throw new InvalidPath($ex->getMessage());
194
-		} catch (ForbiddenException $ex) {
195
-			throw new Forbidden($ex->getMessage(), $ex->getRetry());
196
-		} catch (LockedException $e) {
197
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
198
-		}
199
-	}
200
-
201
-	/**
202
-	 * Returns a specific child node, referenced by its name
203
-	 *
204
-	 * @param string $name
205
-	 * @param \OCP\Files\FileInfo $info
206
-	 * @return \Sabre\DAV\INode
207
-	 * @throws InvalidPath
208
-	 * @throws \Sabre\DAV\Exception\NotFound
209
-	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
210
-	 */
211
-	public function getChild($name, $info = null) {
212
-		if (!$this->info->isReadable()) {
213
-			// avoid detecting files through this way
214
-			throw new NotFound();
215
-		}
216
-
217
-		$path = $this->path . '/' . $name;
218
-		if (is_null($info)) {
219
-			try {
220
-				$this->fileView->verifyPath($this->path, $name);
221
-				$info = $this->fileView->getFileInfo($path);
222
-			} catch (\OCP\Files\StorageNotAvailableException $e) {
223
-				throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
224
-			} catch (InvalidPathException $ex) {
225
-				throw new InvalidPath($ex->getMessage());
226
-			} catch (ForbiddenException $e) {
227
-				throw new \Sabre\DAV\Exception\Forbidden();
228
-			}
229
-		}
230
-
231
-		if (!$info) {
232
-			throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
233
-		}
234
-
235
-		if ($info['mimetype'] === 'httpd/unix-directory') {
236
-			$node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this->tree, $this->shareManager);
237
-		} else {
238
-			$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info, $this->shareManager);
239
-		}
240
-		if ($this->tree) {
241
-			$this->tree->cacheNode($node);
242
-		}
243
-		return $node;
244
-	}
245
-
246
-	/**
247
-	 * Returns an array with all the child nodes
248
-	 *
249
-	 * @return \Sabre\DAV\INode[]
250
-	 * @throws \Sabre\DAV\Exception\Locked
251
-	 * @throws \OCA\DAV\Connector\Sabre\Exception\Forbidden
252
-	 */
253
-	public function getChildren() {
254
-		if (!is_null($this->dirContent)) {
255
-			return $this->dirContent;
256
-		}
257
-		try {
258
-			if (!$this->info->isReadable()) {
259
-				// return 403 instead of 404 because a 404 would make
260
-				// the caller believe that the collection itself does not exist
261
-				throw new Forbidden('No read permissions');
262
-			}
263
-			$folderContent = $this->fileView->getDirectoryContent($this->path);
264
-		} catch (LockedException $e) {
265
-			throw new Locked();
266
-		}
267
-
268
-		$nodes = [];
269
-		foreach ($folderContent as $info) {
270
-			$node = $this->getChild($info->getName(), $info);
271
-			$nodes[] = $node;
272
-		}
273
-		$this->dirContent = $nodes;
274
-		return $this->dirContent;
275
-	}
276
-
277
-	/**
278
-	 * Checks if a child exists.
279
-	 *
280
-	 * @param string $name
281
-	 * @return bool
282
-	 */
283
-	public function childExists($name) {
284
-		// note: here we do NOT resolve the chunk file name to the real file name
285
-		// to make sure we return false when checking for file existence with a chunk
286
-		// file name.
287
-		// This is to make sure that "createFile" is still triggered
288
-		// (required old code) instead of "updateFile".
289
-		//
290
-		// TODO: resolve chunk file name here and implement "updateFile"
291
-		$path = $this->path . '/' . $name;
292
-		return $this->fileView->file_exists($path);
293
-	}
294
-
295
-	/**
296
-	 * Deletes all files in this directory, and then itself
297
-	 *
298
-	 * @return void
299
-	 * @throws FileLocked
300
-	 * @throws \Sabre\DAV\Exception\Forbidden
301
-	 */
302
-	public function delete() {
303
-		if ($this->path === '' || $this->path === '/' || !$this->info->isDeletable()) {
304
-			throw new \Sabre\DAV\Exception\Forbidden();
305
-		}
306
-
307
-		try {
308
-			if (!$this->fileView->rmdir($this->path)) {
309
-				// assume it wasn't possible to remove due to permission issue
310
-				throw new \Sabre\DAV\Exception\Forbidden();
311
-			}
312
-		} catch (ForbiddenException $ex) {
313
-			throw new Forbidden($ex->getMessage(), $ex->getRetry());
314
-		} catch (LockedException $e) {
315
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
316
-		}
317
-	}
318
-
319
-	/**
320
-	 * Returns available diskspace information
321
-	 *
322
-	 * @return array
323
-	 */
324
-	public function getQuotaInfo() {
325
-		if ($this->quotaInfo) {
326
-			return $this->quotaInfo;
327
-		}
328
-		try {
329
-			$info = $this->fileView->getFileInfo($this->path, false);
330
-			$storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $info);
331
-			if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
332
-				$free = \OCP\Files\FileInfo::SPACE_UNLIMITED;
333
-			} else {
334
-				$free = $storageInfo['free'];
335
-			}
336
-			$this->quotaInfo = [
337
-				$storageInfo['used'],
338
-				$free
339
-			];
340
-			return $this->quotaInfo;
341
-		} catch (\OCP\Files\StorageNotAvailableException $e) {
342
-			return [0, 0];
343
-		}
344
-	}
345
-
346
-	/**
347
-	 * Moves a node into this collection.
348
-	 *
349
-	 * It is up to the implementors to:
350
-	 *   1. Create the new resource.
351
-	 *   2. Remove the old resource.
352
-	 *   3. Transfer any properties or other data.
353
-	 *
354
-	 * Generally you should make very sure that your collection can easily move
355
-	 * the move.
356
-	 *
357
-	 * If you don't, just return false, which will trigger sabre/dav to handle
358
-	 * the move itself. If you return true from this function, the assumption
359
-	 * is that the move was successful.
360
-	 *
361
-	 * @param string $targetName New local file/collection name.
362
-	 * @param string $fullSourcePath Full path to source node
363
-	 * @param INode $sourceNode Source node itself
364
-	 * @return bool
365
-	 * @throws BadRequest
366
-	 * @throws ServiceUnavailable
367
-	 * @throws Forbidden
368
-	 * @throws FileLocked
369
-	 * @throws \Sabre\DAV\Exception\Forbidden
370
-	 */
371
-	public function moveInto($targetName, $fullSourcePath, INode $sourceNode) {
372
-		if (!$sourceNode instanceof Node) {
373
-			// it's a file of another kind, like FutureFile
374
-			if ($sourceNode instanceof IFile) {
375
-				// fallback to default copy+delete handling
376
-				return false;
377
-			}
378
-			throw new BadRequest('Incompatible node types');
379
-		}
380
-
381
-		if (!$this->fileView) {
382
-			throw new ServiceUnavailable('filesystem not setup');
383
-		}
384
-
385
-		$destinationPath = $this->getPath() . '/' . $targetName;
386
-
387
-
388
-		$targetNodeExists = $this->childExists($targetName);
389
-
390
-		// at getNodeForPath we also check the path for isForbiddenFileOrDir
391
-		// with that we have covered both source and destination
392
-		if ($sourceNode instanceof Directory && $targetNodeExists) {
393
-			throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
394
-		}
395
-
396
-		list($sourceDir,) = \Sabre\Uri\split($sourceNode->getPath());
397
-		$destinationDir = $this->getPath();
398
-
399
-		$sourcePath = $sourceNode->getPath();
400
-
401
-		$isMovableMount = false;
402
-		$sourceMount = \OC::$server->getMountManager()->find($this->fileView->getAbsolutePath($sourcePath));
403
-		$internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
404
-		if ($sourceMount instanceof MoveableMount && $internalPath === '') {
405
-			$isMovableMount = true;
406
-		}
407
-
408
-		try {
409
-			$sameFolder = ($sourceDir === $destinationDir);
410
-			// if we're overwriting or same folder
411
-			if ($targetNodeExists || $sameFolder) {
412
-				// note that renaming a share mount point is always allowed
413
-				if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) {
414
-					throw new \Sabre\DAV\Exception\Forbidden();
415
-				}
416
-			} else {
417
-				if (!$this->fileView->isCreatable($destinationDir)) {
418
-					throw new \Sabre\DAV\Exception\Forbidden();
419
-				}
420
-			}
421
-
422
-			if (!$sameFolder) {
423
-				// moving to a different folder, source will be gone, like a deletion
424
-				// note that moving a share mount point is always allowed
425
-				if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
426
-					throw new \Sabre\DAV\Exception\Forbidden();
427
-				}
428
-			}
429
-
430
-			$fileName = basename($destinationPath);
431
-			try {
432
-				$this->fileView->verifyPath($destinationDir, $fileName);
433
-			} catch (InvalidPathException $ex) {
434
-				throw new InvalidPath($ex->getMessage());
435
-			}
436
-
437
-			$renameOkay = $this->fileView->rename($sourcePath, $destinationPath);
438
-			if (!$renameOkay) {
439
-				throw new \Sabre\DAV\Exception\Forbidden('');
440
-			}
441
-		} catch (StorageNotAvailableException $e) {
442
-			throw new ServiceUnavailable($e->getMessage());
443
-		} catch (ForbiddenException $ex) {
444
-			throw new Forbidden($ex->getMessage(), $ex->getRetry());
445
-		} catch (LockedException $e) {
446
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
447
-		}
448
-
449
-		return true;
450
-	}
55
+    /**
56
+     * Cached directory content
57
+     *
58
+     * @var \OCP\Files\FileInfo[]
59
+     */
60
+    private $dirContent;
61
+
62
+    /**
63
+     * Cached quota info
64
+     *
65
+     * @var array
66
+     */
67
+    private $quotaInfo;
68
+
69
+    /**
70
+     * @var ObjectTree|null
71
+     */
72
+    private $tree;
73
+
74
+    /**
75
+     * Sets up the node, expects a full path name
76
+     *
77
+     * @param \OC\Files\View $view
78
+     * @param \OCP\Files\FileInfo $info
79
+     * @param ObjectTree|null $tree
80
+     * @param \OCP\Share\IManager $shareManager
81
+     */
82
+    public function __construct(View $view, FileInfo $info, $tree = null, $shareManager = null) {
83
+        parent::__construct($view, $info, $shareManager);
84
+        $this->tree = $tree;
85
+    }
86
+
87
+    /**
88
+     * Creates a new file in the directory
89
+     *
90
+     * Data will either be supplied as a stream resource, or in certain cases
91
+     * as a string. Keep in mind that you may have to support either.
92
+     *
93
+     * After successful creation of the file, you may choose to return the ETag
94
+     * of the new file here.
95
+     *
96
+     * The returned ETag must be surrounded by double-quotes (The quotes should
97
+     * be part of the actual string).
98
+     *
99
+     * If you cannot accurately determine the ETag, you should not return it.
100
+     * If you don't store the file exactly as-is (you're transforming it
101
+     * somehow) you should also not return an ETag.
102
+     *
103
+     * This means that if a subsequent GET to this new file does not exactly
104
+     * return the same contents of what was submitted here, you are strongly
105
+     * recommended to omit the ETag.
106
+     *
107
+     * @param string $name Name of the file
108
+     * @param resource|string $data Initial payload
109
+     * @return null|string
110
+     * @throws Exception\EntityTooLarge
111
+     * @throws Exception\UnsupportedMediaType
112
+     * @throws FileLocked
113
+     * @throws InvalidPath
114
+     * @throws \Sabre\DAV\Exception
115
+     * @throws \Sabre\DAV\Exception\BadRequest
116
+     * @throws \Sabre\DAV\Exception\Forbidden
117
+     * @throws \Sabre\DAV\Exception\ServiceUnavailable
118
+     */
119
+    public function createFile($name, $data = null) {
120
+        try {
121
+            // for chunked upload also updating a existing file is a "createFile"
122
+            // because we create all the chunks before re-assemble them to the existing file.
123
+            if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
124
+
125
+                // exit if we can't create a new file and we don't updatable existing file
126
+                $chunkInfo = \OC_FileChunking::decodeName($name);
127
+                if (!$this->fileView->isCreatable($this->path) &&
128
+                    !$this->fileView->isUpdatable($this->path . '/' . $chunkInfo['name'])
129
+                ) {
130
+                    throw new \Sabre\DAV\Exception\Forbidden();
131
+                }
132
+            } else {
133
+                // For non-chunked upload it is enough to check if we can create a new file
134
+                if (!$this->fileView->isCreatable($this->path)) {
135
+                    throw new \Sabre\DAV\Exception\Forbidden();
136
+                }
137
+            }
138
+
139
+            $this->fileView->verifyPath($this->path, $name);
140
+
141
+            $path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
142
+            // in case the file already exists/overwriting
143
+            $info = $this->fileView->getFileInfo($this->path . '/' . $name);
144
+            if (!$info) {
145
+                // use a dummy FileInfo which is acceptable here since it will be refreshed after the put is complete
146
+                $info = new \OC\Files\FileInfo($path, null, null, [], null);
147
+            }
148
+            $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
149
+
150
+            // only allow 1 process to upload a file at once but still allow reading the file while writing the part file
151
+            $node->acquireLock(ILockingProvider::LOCK_SHARED);
152
+            $this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
153
+
154
+            $result = $node->put($data);
155
+
156
+            $this->fileView->unlockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
157
+            $node->releaseLock(ILockingProvider::LOCK_SHARED);
158
+            return $result;
159
+        } catch (\OCP\Files\StorageNotAvailableException $e) {
160
+            throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage(), $e->getCode(), $e);
161
+        } catch (InvalidPathException $ex) {
162
+            throw new InvalidPath($ex->getMessage(), false, $ex);
163
+        } catch (ForbiddenException $ex) {
164
+            throw new Forbidden($ex->getMessage(), $ex->getRetry(), $ex);
165
+        } catch (LockedException $e) {
166
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
167
+        }
168
+    }
169
+
170
+    /**
171
+     * Creates a new subdirectory
172
+     *
173
+     * @param string $name
174
+     * @throws FileLocked
175
+     * @throws InvalidPath
176
+     * @throws \Sabre\DAV\Exception\Forbidden
177
+     * @throws \Sabre\DAV\Exception\ServiceUnavailable
178
+     */
179
+    public function createDirectory($name) {
180
+        try {
181
+            if (!$this->info->isCreatable()) {
182
+                throw new \Sabre\DAV\Exception\Forbidden();
183
+            }
184
+
185
+            $this->fileView->verifyPath($this->path, $name);
186
+            $newPath = $this->path . '/' . $name;
187
+            if (!$this->fileView->mkdir($newPath)) {
188
+                throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath);
189
+            }
190
+        } catch (\OCP\Files\StorageNotAvailableException $e) {
191
+            throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
192
+        } catch (InvalidPathException $ex) {
193
+            throw new InvalidPath($ex->getMessage());
194
+        } catch (ForbiddenException $ex) {
195
+            throw new Forbidden($ex->getMessage(), $ex->getRetry());
196
+        } catch (LockedException $e) {
197
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
198
+        }
199
+    }
200
+
201
+    /**
202
+     * Returns a specific child node, referenced by its name
203
+     *
204
+     * @param string $name
205
+     * @param \OCP\Files\FileInfo $info
206
+     * @return \Sabre\DAV\INode
207
+     * @throws InvalidPath
208
+     * @throws \Sabre\DAV\Exception\NotFound
209
+     * @throws \Sabre\DAV\Exception\ServiceUnavailable
210
+     */
211
+    public function getChild($name, $info = null) {
212
+        if (!$this->info->isReadable()) {
213
+            // avoid detecting files through this way
214
+            throw new NotFound();
215
+        }
216
+
217
+        $path = $this->path . '/' . $name;
218
+        if (is_null($info)) {
219
+            try {
220
+                $this->fileView->verifyPath($this->path, $name);
221
+                $info = $this->fileView->getFileInfo($path);
222
+            } catch (\OCP\Files\StorageNotAvailableException $e) {
223
+                throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
224
+            } catch (InvalidPathException $ex) {
225
+                throw new InvalidPath($ex->getMessage());
226
+            } catch (ForbiddenException $e) {
227
+                throw new \Sabre\DAV\Exception\Forbidden();
228
+            }
229
+        }
230
+
231
+        if (!$info) {
232
+            throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
233
+        }
234
+
235
+        if ($info['mimetype'] === 'httpd/unix-directory') {
236
+            $node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this->tree, $this->shareManager);
237
+        } else {
238
+            $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info, $this->shareManager);
239
+        }
240
+        if ($this->tree) {
241
+            $this->tree->cacheNode($node);
242
+        }
243
+        return $node;
244
+    }
245
+
246
+    /**
247
+     * Returns an array with all the child nodes
248
+     *
249
+     * @return \Sabre\DAV\INode[]
250
+     * @throws \Sabre\DAV\Exception\Locked
251
+     * @throws \OCA\DAV\Connector\Sabre\Exception\Forbidden
252
+     */
253
+    public function getChildren() {
254
+        if (!is_null($this->dirContent)) {
255
+            return $this->dirContent;
256
+        }
257
+        try {
258
+            if (!$this->info->isReadable()) {
259
+                // return 403 instead of 404 because a 404 would make
260
+                // the caller believe that the collection itself does not exist
261
+                throw new Forbidden('No read permissions');
262
+            }
263
+            $folderContent = $this->fileView->getDirectoryContent($this->path);
264
+        } catch (LockedException $e) {
265
+            throw new Locked();
266
+        }
267
+
268
+        $nodes = [];
269
+        foreach ($folderContent as $info) {
270
+            $node = $this->getChild($info->getName(), $info);
271
+            $nodes[] = $node;
272
+        }
273
+        $this->dirContent = $nodes;
274
+        return $this->dirContent;
275
+    }
276
+
277
+    /**
278
+     * Checks if a child exists.
279
+     *
280
+     * @param string $name
281
+     * @return bool
282
+     */
283
+    public function childExists($name) {
284
+        // note: here we do NOT resolve the chunk file name to the real file name
285
+        // to make sure we return false when checking for file existence with a chunk
286
+        // file name.
287
+        // This is to make sure that "createFile" is still triggered
288
+        // (required old code) instead of "updateFile".
289
+        //
290
+        // TODO: resolve chunk file name here and implement "updateFile"
291
+        $path = $this->path . '/' . $name;
292
+        return $this->fileView->file_exists($path);
293
+    }
294
+
295
+    /**
296
+     * Deletes all files in this directory, and then itself
297
+     *
298
+     * @return void
299
+     * @throws FileLocked
300
+     * @throws \Sabre\DAV\Exception\Forbidden
301
+     */
302
+    public function delete() {
303
+        if ($this->path === '' || $this->path === '/' || !$this->info->isDeletable()) {
304
+            throw new \Sabre\DAV\Exception\Forbidden();
305
+        }
306
+
307
+        try {
308
+            if (!$this->fileView->rmdir($this->path)) {
309
+                // assume it wasn't possible to remove due to permission issue
310
+                throw new \Sabre\DAV\Exception\Forbidden();
311
+            }
312
+        } catch (ForbiddenException $ex) {
313
+            throw new Forbidden($ex->getMessage(), $ex->getRetry());
314
+        } catch (LockedException $e) {
315
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
316
+        }
317
+    }
318
+
319
+    /**
320
+     * Returns available diskspace information
321
+     *
322
+     * @return array
323
+     */
324
+    public function getQuotaInfo() {
325
+        if ($this->quotaInfo) {
326
+            return $this->quotaInfo;
327
+        }
328
+        try {
329
+            $info = $this->fileView->getFileInfo($this->path, false);
330
+            $storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $info);
331
+            if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
332
+                $free = \OCP\Files\FileInfo::SPACE_UNLIMITED;
333
+            } else {
334
+                $free = $storageInfo['free'];
335
+            }
336
+            $this->quotaInfo = [
337
+                $storageInfo['used'],
338
+                $free
339
+            ];
340
+            return $this->quotaInfo;
341
+        } catch (\OCP\Files\StorageNotAvailableException $e) {
342
+            return [0, 0];
343
+        }
344
+    }
345
+
346
+    /**
347
+     * Moves a node into this collection.
348
+     *
349
+     * It is up to the implementors to:
350
+     *   1. Create the new resource.
351
+     *   2. Remove the old resource.
352
+     *   3. Transfer any properties or other data.
353
+     *
354
+     * Generally you should make very sure that your collection can easily move
355
+     * the move.
356
+     *
357
+     * If you don't, just return false, which will trigger sabre/dav to handle
358
+     * the move itself. If you return true from this function, the assumption
359
+     * is that the move was successful.
360
+     *
361
+     * @param string $targetName New local file/collection name.
362
+     * @param string $fullSourcePath Full path to source node
363
+     * @param INode $sourceNode Source node itself
364
+     * @return bool
365
+     * @throws BadRequest
366
+     * @throws ServiceUnavailable
367
+     * @throws Forbidden
368
+     * @throws FileLocked
369
+     * @throws \Sabre\DAV\Exception\Forbidden
370
+     */
371
+    public function moveInto($targetName, $fullSourcePath, INode $sourceNode) {
372
+        if (!$sourceNode instanceof Node) {
373
+            // it's a file of another kind, like FutureFile
374
+            if ($sourceNode instanceof IFile) {
375
+                // fallback to default copy+delete handling
376
+                return false;
377
+            }
378
+            throw new BadRequest('Incompatible node types');
379
+        }
380
+
381
+        if (!$this->fileView) {
382
+            throw new ServiceUnavailable('filesystem not setup');
383
+        }
384
+
385
+        $destinationPath = $this->getPath() . '/' . $targetName;
386
+
387
+
388
+        $targetNodeExists = $this->childExists($targetName);
389
+
390
+        // at getNodeForPath we also check the path for isForbiddenFileOrDir
391
+        // with that we have covered both source and destination
392
+        if ($sourceNode instanceof Directory && $targetNodeExists) {
393
+            throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
394
+        }
395
+
396
+        list($sourceDir,) = \Sabre\Uri\split($sourceNode->getPath());
397
+        $destinationDir = $this->getPath();
398
+
399
+        $sourcePath = $sourceNode->getPath();
400
+
401
+        $isMovableMount = false;
402
+        $sourceMount = \OC::$server->getMountManager()->find($this->fileView->getAbsolutePath($sourcePath));
403
+        $internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
404
+        if ($sourceMount instanceof MoveableMount && $internalPath === '') {
405
+            $isMovableMount = true;
406
+        }
407
+
408
+        try {
409
+            $sameFolder = ($sourceDir === $destinationDir);
410
+            // if we're overwriting or same folder
411
+            if ($targetNodeExists || $sameFolder) {
412
+                // note that renaming a share mount point is always allowed
413
+                if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) {
414
+                    throw new \Sabre\DAV\Exception\Forbidden();
415
+                }
416
+            } else {
417
+                if (!$this->fileView->isCreatable($destinationDir)) {
418
+                    throw new \Sabre\DAV\Exception\Forbidden();
419
+                }
420
+            }
421
+
422
+            if (!$sameFolder) {
423
+                // moving to a different folder, source will be gone, like a deletion
424
+                // note that moving a share mount point is always allowed
425
+                if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
426
+                    throw new \Sabre\DAV\Exception\Forbidden();
427
+                }
428
+            }
429
+
430
+            $fileName = basename($destinationPath);
431
+            try {
432
+                $this->fileView->verifyPath($destinationDir, $fileName);
433
+            } catch (InvalidPathException $ex) {
434
+                throw new InvalidPath($ex->getMessage());
435
+            }
436
+
437
+            $renameOkay = $this->fileView->rename($sourcePath, $destinationPath);
438
+            if (!$renameOkay) {
439
+                throw new \Sabre\DAV\Exception\Forbidden('');
440
+            }
441
+        } catch (StorageNotAvailableException $e) {
442
+            throw new ServiceUnavailable($e->getMessage());
443
+        } catch (ForbiddenException $ex) {
444
+            throw new Forbidden($ex->getMessage(), $ex->getRetry());
445
+        } catch (LockedException $e) {
446
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
447
+        }
448
+
449
+        return true;
450
+    }
451 451
 }
Please login to merge, or discard this patch.