Completed
Push — master ( dfe6d6...a56ec1 )
by Morris
28:57
created
apps/dav/lib/Connector/Sabre/File.php 2 patches
Indentation   +524 added lines, -524 removed lines patch added patch discarded remove patch
@@ -66,529 +66,529 @@
 block discarded – undo
66 66
 
67 67
 class File extends Node implements IFile {
68 68
 
69
-	protected $request;
70
-
71
-	/**
72
-	 * Sets up the node, expects a full path name
73
-	 *
74
-	 * @param \OC\Files\View $view
75
-	 * @param \OCP\Files\FileInfo $info
76
-	 * @param \OCP\Share\IManager $shareManager
77
-	 * @param \OC\AppFramework\Http\Request $request
78
-	 */
79
-	public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
80
-		parent::__construct($view, $info, $shareManager);
81
-
82
-		if (isset($request)) {
83
-			$this->request = $request;
84
-		} else {
85
-			$this->request = \OC::$server->getRequest();
86
-		}
87
-	}
88
-
89
-	/**
90
-	 * Updates the data
91
-	 *
92
-	 * The data argument is a readable stream resource.
93
-	 *
94
-	 * After a successful put operation, you may choose to return an ETag. The
95
-	 * etag must always be surrounded by double-quotes. These quotes must
96
-	 * appear in the actual string you're returning.
97
-	 *
98
-	 * Clients may use the ETag from a PUT request to later on make sure that
99
-	 * when they update the file, the contents haven't changed in the mean
100
-	 * time.
101
-	 *
102
-	 * If you don't plan to store the file byte-by-byte, and you return a
103
-	 * different object on a subsequent GET you are strongly recommended to not
104
-	 * return an ETag, and just return null.
105
-	 *
106
-	 * @param resource $data
107
-	 *
108
-	 * @throws Forbidden
109
-	 * @throws UnsupportedMediaType
110
-	 * @throws BadRequest
111
-	 * @throws Exception
112
-	 * @throws EntityTooLarge
113
-	 * @throws ServiceUnavailable
114
-	 * @throws FileLocked
115
-	 * @return string|null
116
-	 */
117
-	public function put($data) {
118
-		try {
119
-			$exists = $this->fileView->file_exists($this->path);
120
-			if ($this->info && $exists && !$this->info->isUpdateable()) {
121
-				throw new Forbidden();
122
-			}
123
-		} catch (StorageNotAvailableException $e) {
124
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
125
-		}
126
-
127
-		// verify path of the target
128
-		$this->verifyPath();
129
-
130
-		// chunked handling
131
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
132
-			try {
133
-				return $this->createFileChunked($data);
134
-			} catch (\Exception $e) {
135
-				$this->convertToSabreException($e);
136
-			}
137
-		}
138
-
139
-		/** @var Storage $partStorage */
140
-		list($partStorage) = $this->fileView->resolvePath($this->path);
141
-		$needsPartFile = $partStorage->needsPartFile() && (strlen($this->path) > 1);
142
-
143
-		if ($needsPartFile) {
144
-			// mark file as partial while uploading (ignored by the scanner)
145
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
146
-		} else {
147
-			// upload file directly as the final path
148
-			$partFilePath = $this->path;
149
-
150
-			$this->emitPreHooks($exists);
151
-		}
152
-
153
-		// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
154
-		/** @var \OC\Files\Storage\Storage $partStorage */
155
-		list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
156
-		/** @var \OC\Files\Storage\Storage $storage */
157
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
158
-		try {
159
-			$target = $partStorage->fopen($internalPartPath, 'wb');
160
-			if ($target === false) {
161
-				\OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']);
162
-				// because we have no clue about the cause we can only throw back a 500/Internal Server Error
163
-				throw new Exception('Could not write file contents');
164
-			}
165
-			list($count, $result) = \OC_Helper::streamCopy($data, $target);
166
-			fclose($target);
167
-
168
-			if ($result === false) {
169
-				$expected = -1;
170
-				if (isset($_SERVER['CONTENT_LENGTH'])) {
171
-					$expected = $_SERVER['CONTENT_LENGTH'];
172
-				}
173
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
174
-			}
175
-
176
-			// if content length is sent by client:
177
-			// double check if the file was fully received
178
-			// compare expected and actual size
179
-			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
180
-				$expected = (int) $_SERVER['CONTENT_LENGTH'];
181
-				if ($count !== $expected) {
182
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
183
-				}
184
-			}
185
-
186
-		} catch (\Exception $e) {
187
-			if ($needsPartFile) {
188
-				$partStorage->unlink($internalPartPath);
189
-			}
190
-			$this->convertToSabreException($e);
191
-		}
192
-
193
-		try {
194
-			$view = \OC\Files\Filesystem::getView();
195
-			$run = ($view && $needsPartFile) ? $this->emitPreHooks($exists) : true;
196
-
197
-			try {
198
-				$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
199
-			} catch (LockedException $e) {
200
-				if ($needsPartFile) {
201
-					$partStorage->unlink($internalPartPath);
202
-				}
203
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
204
-			}
205
-
206
-			if ($needsPartFile) {
207
-				// rename to correct path
208
-				try {
209
-					if ($run) {
210
-						$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
211
-						$fileExists = $storage->file_exists($internalPath);
212
-					}
213
-					if (!$run || $renameOkay === false || $fileExists === false) {
214
-						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
215
-						throw new Exception('Could not rename part file to final file');
216
-					}
217
-				} catch (ForbiddenException $ex) {
218
-					throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
219
-				} catch (\Exception $e) {
220
-					$partStorage->unlink($internalPartPath);
221
-					$this->convertToSabreException($e);
222
-				}
223
-			}
224
-
225
-			// since we skipped the view we need to scan and emit the hooks ourselves
226
-			$storage->getUpdater()->update($internalPath);
227
-
228
-			try {
229
-				$this->changeLock(ILockingProvider::LOCK_SHARED);
230
-			} catch (LockedException $e) {
231
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
232
-			}
233
-
234
-			// allow sync clients to send the mtime along in a header
235
-			if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
236
-				$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
237
-				if ($this->fileView->touch($this->path, $mtime)) {
238
-					$this->header('X-OC-MTime: accepted');
239
-				}
240
-			}
69
+    protected $request;
70
+
71
+    /**
72
+     * Sets up the node, expects a full path name
73
+     *
74
+     * @param \OC\Files\View $view
75
+     * @param \OCP\Files\FileInfo $info
76
+     * @param \OCP\Share\IManager $shareManager
77
+     * @param \OC\AppFramework\Http\Request $request
78
+     */
79
+    public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
80
+        parent::__construct($view, $info, $shareManager);
81
+
82
+        if (isset($request)) {
83
+            $this->request = $request;
84
+        } else {
85
+            $this->request = \OC::$server->getRequest();
86
+        }
87
+    }
88
+
89
+    /**
90
+     * Updates the data
91
+     *
92
+     * The data argument is a readable stream resource.
93
+     *
94
+     * After a successful put operation, you may choose to return an ETag. The
95
+     * etag must always be surrounded by double-quotes. These quotes must
96
+     * appear in the actual string you're returning.
97
+     *
98
+     * Clients may use the ETag from a PUT request to later on make sure that
99
+     * when they update the file, the contents haven't changed in the mean
100
+     * time.
101
+     *
102
+     * If you don't plan to store the file byte-by-byte, and you return a
103
+     * different object on a subsequent GET you are strongly recommended to not
104
+     * return an ETag, and just return null.
105
+     *
106
+     * @param resource $data
107
+     *
108
+     * @throws Forbidden
109
+     * @throws UnsupportedMediaType
110
+     * @throws BadRequest
111
+     * @throws Exception
112
+     * @throws EntityTooLarge
113
+     * @throws ServiceUnavailable
114
+     * @throws FileLocked
115
+     * @return string|null
116
+     */
117
+    public function put($data) {
118
+        try {
119
+            $exists = $this->fileView->file_exists($this->path);
120
+            if ($this->info && $exists && !$this->info->isUpdateable()) {
121
+                throw new Forbidden();
122
+            }
123
+        } catch (StorageNotAvailableException $e) {
124
+            throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
125
+        }
126
+
127
+        // verify path of the target
128
+        $this->verifyPath();
129
+
130
+        // chunked handling
131
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
132
+            try {
133
+                return $this->createFileChunked($data);
134
+            } catch (\Exception $e) {
135
+                $this->convertToSabreException($e);
136
+            }
137
+        }
138
+
139
+        /** @var Storage $partStorage */
140
+        list($partStorage) = $this->fileView->resolvePath($this->path);
141
+        $needsPartFile = $partStorage->needsPartFile() && (strlen($this->path) > 1);
142
+
143
+        if ($needsPartFile) {
144
+            // mark file as partial while uploading (ignored by the scanner)
145
+            $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
146
+        } else {
147
+            // upload file directly as the final path
148
+            $partFilePath = $this->path;
149
+
150
+            $this->emitPreHooks($exists);
151
+        }
152
+
153
+        // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
154
+        /** @var \OC\Files\Storage\Storage $partStorage */
155
+        list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
156
+        /** @var \OC\Files\Storage\Storage $storage */
157
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
158
+        try {
159
+            $target = $partStorage->fopen($internalPartPath, 'wb');
160
+            if ($target === false) {
161
+                \OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']);
162
+                // because we have no clue about the cause we can only throw back a 500/Internal Server Error
163
+                throw new Exception('Could not write file contents');
164
+            }
165
+            list($count, $result) = \OC_Helper::streamCopy($data, $target);
166
+            fclose($target);
167
+
168
+            if ($result === false) {
169
+                $expected = -1;
170
+                if (isset($_SERVER['CONTENT_LENGTH'])) {
171
+                    $expected = $_SERVER['CONTENT_LENGTH'];
172
+                }
173
+                throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
174
+            }
175
+
176
+            // if content length is sent by client:
177
+            // double check if the file was fully received
178
+            // compare expected and actual size
179
+            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
180
+                $expected = (int) $_SERVER['CONTENT_LENGTH'];
181
+                if ($count !== $expected) {
182
+                    throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
183
+                }
184
+            }
185
+
186
+        } catch (\Exception $e) {
187
+            if ($needsPartFile) {
188
+                $partStorage->unlink($internalPartPath);
189
+            }
190
+            $this->convertToSabreException($e);
191
+        }
192
+
193
+        try {
194
+            $view = \OC\Files\Filesystem::getView();
195
+            $run = ($view && $needsPartFile) ? $this->emitPreHooks($exists) : true;
196
+
197
+            try {
198
+                $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
199
+            } catch (LockedException $e) {
200
+                if ($needsPartFile) {
201
+                    $partStorage->unlink($internalPartPath);
202
+                }
203
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
204
+            }
205
+
206
+            if ($needsPartFile) {
207
+                // rename to correct path
208
+                try {
209
+                    if ($run) {
210
+                        $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
211
+                        $fileExists = $storage->file_exists($internalPath);
212
+                    }
213
+                    if (!$run || $renameOkay === false || $fileExists === false) {
214
+                        \OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
215
+                        throw new Exception('Could not rename part file to final file');
216
+                    }
217
+                } catch (ForbiddenException $ex) {
218
+                    throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
219
+                } catch (\Exception $e) {
220
+                    $partStorage->unlink($internalPartPath);
221
+                    $this->convertToSabreException($e);
222
+                }
223
+            }
224
+
225
+            // since we skipped the view we need to scan and emit the hooks ourselves
226
+            $storage->getUpdater()->update($internalPath);
227
+
228
+            try {
229
+                $this->changeLock(ILockingProvider::LOCK_SHARED);
230
+            } catch (LockedException $e) {
231
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
232
+            }
233
+
234
+            // allow sync clients to send the mtime along in a header
235
+            if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
236
+                $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
237
+                if ($this->fileView->touch($this->path, $mtime)) {
238
+                    $this->header('X-OC-MTime: accepted');
239
+                }
240
+            }
241 241
 					
242
-			if ($view) {
243
-				$this->emitPostHooks($exists);
244
-			}
245
-
246
-			$this->refreshInfo();
247
-
248
-			if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
249
-				$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
250
-				$this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
251
-				$this->refreshInfo();
252
-			} else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
253
-				$this->fileView->putFileInfo($this->path, ['checksum' => '']);
254
-				$this->refreshInfo();
255
-			}
256
-
257
-		} catch (StorageNotAvailableException $e) {
258
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
259
-		}
260
-
261
-		return '"' . $this->info->getEtag() . '"';
262
-	}
263
-
264
-	private function getPartFileBasePath($path) {
265
-		$partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
266
-		if ($partFileInStorage) {
267
-			return $path;
268
-		} else {
269
-			return md5($path); // will place it in the root of the view with a unique name
270
-		}
271
-	}
272
-
273
-	/**
274
-	 * @param string $path
275
-	 */
276
-	private function emitPreHooks($exists, $path = null) {
277
-		if (is_null($path)) {
278
-			$path = $this->path;
279
-		}
280
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
281
-		$run = true;
282
-
283
-		if (!$exists) {
284
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
285
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
286
-				\OC\Files\Filesystem::signal_param_run => &$run,
287
-			));
288
-		} else {
289
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
290
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
291
-				\OC\Files\Filesystem::signal_param_run => &$run,
292
-			));
293
-		}
294
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
295
-			\OC\Files\Filesystem::signal_param_path => $hookPath,
296
-			\OC\Files\Filesystem::signal_param_run => &$run,
297
-		));
298
-		return $run;
299
-	}
300
-
301
-	/**
302
-	 * @param string $path
303
-	 */
304
-	private function emitPostHooks($exists, $path = null) {
305
-		if (is_null($path)) {
306
-			$path = $this->path;
307
-		}
308
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
309
-		if (!$exists) {
310
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
311
-				\OC\Files\Filesystem::signal_param_path => $hookPath
312
-			));
313
-		} else {
314
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
315
-				\OC\Files\Filesystem::signal_param_path => $hookPath
316
-			));
317
-		}
318
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
319
-			\OC\Files\Filesystem::signal_param_path => $hookPath
320
-		));
321
-	}
322
-
323
-	/**
324
-	 * Returns the data
325
-	 *
326
-	 * @return resource
327
-	 * @throws Forbidden
328
-	 * @throws ServiceUnavailable
329
-	 */
330
-	public function get() {
331
-		//throw exception if encryption is disabled but files are still encrypted
332
-		try {
333
-			if (!$this->info->isReadable()) {
334
-				// do a if the file did not exist
335
-				throw new NotFound();
336
-			}
337
-			try {
338
-				$res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
339
-			} catch (\Exception $e) {
340
-				$this->convertToSabreException($e);
341
-			}
342
-			if ($res === false) {
343
-				throw new ServiceUnavailable("Could not open file");
344
-			}
345
-			return $res;
346
-		} catch (GenericEncryptionException $e) {
347
-			// returning 503 will allow retry of the operation at a later point in time
348
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
349
-		} catch (StorageNotAvailableException $e) {
350
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
351
-		} catch (ForbiddenException $ex) {
352
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
353
-		} catch (LockedException $e) {
354
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
355
-		}
356
-	}
357
-
358
-	/**
359
-	 * Delete the current file
360
-	 *
361
-	 * @throws Forbidden
362
-	 * @throws ServiceUnavailable
363
-	 */
364
-	public function delete() {
365
-		if (!$this->info->isDeletable()) {
366
-			throw new Forbidden();
367
-		}
368
-
369
-		try {
370
-			if (!$this->fileView->unlink($this->path)) {
371
-				// assume it wasn't possible to delete due to permissions
372
-				throw new Forbidden();
373
-			}
374
-		} catch (StorageNotAvailableException $e) {
375
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
376
-		} catch (ForbiddenException $ex) {
377
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
378
-		} catch (LockedException $e) {
379
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
380
-		}
381
-	}
382
-
383
-	/**
384
-	 * Returns the mime-type for a file
385
-	 *
386
-	 * If null is returned, we'll assume application/octet-stream
387
-	 *
388
-	 * @return string
389
-	 */
390
-	public function getContentType() {
391
-		$mimeType = $this->info->getMimetype();
392
-
393
-		// PROPFIND needs to return the correct mime type, for consistency with the web UI
394
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
395
-			return $mimeType;
396
-		}
397
-		return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
398
-	}
399
-
400
-	/**
401
-	 * @return array|false
402
-	 */
403
-	public function getDirectDownload() {
404
-		if (\OCP\App::isEnabled('encryption')) {
405
-			return [];
406
-		}
407
-		/** @var \OCP\Files\Storage $storage */
408
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
409
-		if (is_null($storage)) {
410
-			return [];
411
-		}
412
-
413
-		return $storage->getDirectDownload($internalPath);
414
-	}
415
-
416
-	/**
417
-	 * @param resource $data
418
-	 * @return null|string
419
-	 * @throws Exception
420
-	 * @throws BadRequest
421
-	 * @throws NotImplemented
422
-	 * @throws ServiceUnavailable
423
-	 */
424
-	private function createFileChunked($data) {
425
-		list($path, $name) = \Sabre\Uri\split($this->path);
426
-
427
-		$info = \OC_FileChunking::decodeName($name);
428
-		if (empty($info)) {
429
-			throw new NotImplemented('Invalid chunk name');
430
-		}
431
-
432
-		$chunk_handler = new \OC_FileChunking($info);
433
-		$bytesWritten = $chunk_handler->store($info['index'], $data);
434
-
435
-		//detect aborted upload
436
-		if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
437
-			if (isset($_SERVER['CONTENT_LENGTH'])) {
438
-				$expected = (int) $_SERVER['CONTENT_LENGTH'];
439
-				if ($bytesWritten !== $expected) {
440
-					$chunk_handler->remove($info['index']);
441
-					throw new BadRequest(
442
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
443
-				}
444
-			}
445
-		}
446
-
447
-		if ($chunk_handler->isComplete()) {
448
-			/** @var Storage $storage */
449
-			list($storage,) = $this->fileView->resolvePath($path);
450
-			$needsPartFile = $storage->needsPartFile();
451
-			$partFile = null;
452
-
453
-			$targetPath = $path . '/' . $info['name'];
454
-			/** @var \OC\Files\Storage\Storage $targetStorage */
455
-			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
456
-
457
-			$exists = $this->fileView->file_exists($targetPath);
458
-
459
-			try {
460
-				$this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
461
-
462
-				$this->emitPreHooks($exists, $targetPath);
463
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
464
-				/** @var \OC\Files\Storage\Storage $targetStorage */
465
-				list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
466
-
467
-				if ($needsPartFile) {
468
-					// we first assembly the target file as a part file
469
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
470
-					/** @var \OC\Files\Storage\Storage $targetStorage */
471
-					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
472
-
473
-
474
-					$chunk_handler->file_assemble($partStorage, $partInternalPath);
475
-
476
-					// here is the final atomic rename
477
-					$renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
478
-					$fileExists = $targetStorage->file_exists($targetInternalPath);
479
-					if ($renameOkay === false || $fileExists === false) {
480
-						\OC::$server->getLogger()->error('\OC\Files\Filesystem::rename() failed', ['app' => 'webdav']);
481
-						// only delete if an error occurred and the target file was already created
482
-						if ($fileExists) {
483
-							// set to null to avoid double-deletion when handling exception
484
-							// stray part file
485
-							$partFile = null;
486
-							$targetStorage->unlink($targetInternalPath);
487
-						}
488
-						$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
489
-						throw new Exception('Could not rename part file assembled from chunks');
490
-					}
491
-				} else {
492
-					// assemble directly into the final file
493
-					$chunk_handler->file_assemble($targetStorage, $targetInternalPath);
494
-				}
495
-
496
-				// allow sync clients to send the mtime along in a header
497
-				if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
498
-					$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
499
-					if ($targetStorage->touch($targetInternalPath, $mtime)) {
500
-						$this->header('X-OC-MTime: accepted');
501
-					}
502
-				}
503
-
504
-				// since we skipped the view we need to scan and emit the hooks ourselves
505
-				$targetStorage->getUpdater()->update($targetInternalPath);
506
-
507
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
508
-
509
-				$this->emitPostHooks($exists, $targetPath);
510
-
511
-				// FIXME: should call refreshInfo but can't because $this->path is not the of the final file
512
-				$info = $this->fileView->getFileInfo($targetPath);
513
-
514
-				if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
515
-					$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
516
-					$this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
517
-				} else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
518
-					$this->fileView->putFileInfo($this->path, ['checksum' => '']);
519
-				}
520
-
521
-				$this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
522
-
523
-				return $info->getEtag();
524
-			} catch (\Exception $e) {
525
-				if ($partFile !== null) {
526
-					$targetStorage->unlink($targetInternalPath);
527
-				}
528
-				$this->convertToSabreException($e);
529
-			}
530
-		}
531
-
532
-		return null;
533
-	}
534
-
535
-	/**
536
-	 * Convert the given exception to a SabreException instance
537
-	 *
538
-	 * @param \Exception $e
539
-	 *
540
-	 * @throws \Sabre\DAV\Exception
541
-	 */
542
-	private function convertToSabreException(\Exception $e) {
543
-		if ($e instanceof \Sabre\DAV\Exception) {
544
-			throw $e;
545
-		}
546
-		if ($e instanceof NotPermittedException) {
547
-			// a more general case - due to whatever reason the content could not be written
548
-			throw new Forbidden($e->getMessage(), 0, $e);
549
-		}
550
-		if ($e instanceof ForbiddenException) {
551
-			// the path for the file was forbidden
552
-			throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
553
-		}
554
-		if ($e instanceof EntityTooLargeException) {
555
-			// the file is too big to be stored
556
-			throw new EntityTooLarge($e->getMessage(), 0, $e);
557
-		}
558
-		if ($e instanceof InvalidContentException) {
559
-			// the file content is not permitted
560
-			throw new UnsupportedMediaType($e->getMessage(), 0, $e);
561
-		}
562
-		if ($e instanceof InvalidPathException) {
563
-			// the path for the file was not valid
564
-			// TODO: find proper http status code for this case
565
-			throw new Forbidden($e->getMessage(), 0, $e);
566
-		}
567
-		if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
568
-			// the file is currently being written to by another process
569
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
570
-		}
571
-		if ($e instanceof GenericEncryptionException) {
572
-			// returning 503 will allow retry of the operation at a later point in time
573
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
574
-		}
575
-		if ($e instanceof StorageNotAvailableException) {
576
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
577
-		}
578
-
579
-		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
580
-	}
581
-
582
-	/**
583
-	 * Get the checksum for this file
584
-	 *
585
-	 * @return string
586
-	 */
587
-	public function getChecksum() {
588
-		return $this->info->getChecksum();
589
-	}
590
-
591
-	protected function header($string) {
592
-		\header($string);
593
-	}
242
+            if ($view) {
243
+                $this->emitPostHooks($exists);
244
+            }
245
+
246
+            $this->refreshInfo();
247
+
248
+            if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
249
+                $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
250
+                $this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
251
+                $this->refreshInfo();
252
+            } else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
253
+                $this->fileView->putFileInfo($this->path, ['checksum' => '']);
254
+                $this->refreshInfo();
255
+            }
256
+
257
+        } catch (StorageNotAvailableException $e) {
258
+            throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
259
+        }
260
+
261
+        return '"' . $this->info->getEtag() . '"';
262
+    }
263
+
264
+    private function getPartFileBasePath($path) {
265
+        $partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
266
+        if ($partFileInStorage) {
267
+            return $path;
268
+        } else {
269
+            return md5($path); // will place it in the root of the view with a unique name
270
+        }
271
+    }
272
+
273
+    /**
274
+     * @param string $path
275
+     */
276
+    private function emitPreHooks($exists, $path = null) {
277
+        if (is_null($path)) {
278
+            $path = $this->path;
279
+        }
280
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
281
+        $run = true;
282
+
283
+        if (!$exists) {
284
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
285
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
286
+                \OC\Files\Filesystem::signal_param_run => &$run,
287
+            ));
288
+        } else {
289
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
290
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
291
+                \OC\Files\Filesystem::signal_param_run => &$run,
292
+            ));
293
+        }
294
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
295
+            \OC\Files\Filesystem::signal_param_path => $hookPath,
296
+            \OC\Files\Filesystem::signal_param_run => &$run,
297
+        ));
298
+        return $run;
299
+    }
300
+
301
+    /**
302
+     * @param string $path
303
+     */
304
+    private function emitPostHooks($exists, $path = null) {
305
+        if (is_null($path)) {
306
+            $path = $this->path;
307
+        }
308
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
309
+        if (!$exists) {
310
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
311
+                \OC\Files\Filesystem::signal_param_path => $hookPath
312
+            ));
313
+        } else {
314
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
315
+                \OC\Files\Filesystem::signal_param_path => $hookPath
316
+            ));
317
+        }
318
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
319
+            \OC\Files\Filesystem::signal_param_path => $hookPath
320
+        ));
321
+    }
322
+
323
+    /**
324
+     * Returns the data
325
+     *
326
+     * @return resource
327
+     * @throws Forbidden
328
+     * @throws ServiceUnavailable
329
+     */
330
+    public function get() {
331
+        //throw exception if encryption is disabled but files are still encrypted
332
+        try {
333
+            if (!$this->info->isReadable()) {
334
+                // do a if the file did not exist
335
+                throw new NotFound();
336
+            }
337
+            try {
338
+                $res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
339
+            } catch (\Exception $e) {
340
+                $this->convertToSabreException($e);
341
+            }
342
+            if ($res === false) {
343
+                throw new ServiceUnavailable("Could not open file");
344
+            }
345
+            return $res;
346
+        } catch (GenericEncryptionException $e) {
347
+            // returning 503 will allow retry of the operation at a later point in time
348
+            throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
349
+        } catch (StorageNotAvailableException $e) {
350
+            throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
351
+        } catch (ForbiddenException $ex) {
352
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
353
+        } catch (LockedException $e) {
354
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
355
+        }
356
+    }
357
+
358
+    /**
359
+     * Delete the current file
360
+     *
361
+     * @throws Forbidden
362
+     * @throws ServiceUnavailable
363
+     */
364
+    public function delete() {
365
+        if (!$this->info->isDeletable()) {
366
+            throw new Forbidden();
367
+        }
368
+
369
+        try {
370
+            if (!$this->fileView->unlink($this->path)) {
371
+                // assume it wasn't possible to delete due to permissions
372
+                throw new Forbidden();
373
+            }
374
+        } catch (StorageNotAvailableException $e) {
375
+            throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
376
+        } catch (ForbiddenException $ex) {
377
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
378
+        } catch (LockedException $e) {
379
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
380
+        }
381
+    }
382
+
383
+    /**
384
+     * Returns the mime-type for a file
385
+     *
386
+     * If null is returned, we'll assume application/octet-stream
387
+     *
388
+     * @return string
389
+     */
390
+    public function getContentType() {
391
+        $mimeType = $this->info->getMimetype();
392
+
393
+        // PROPFIND needs to return the correct mime type, for consistency with the web UI
394
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
395
+            return $mimeType;
396
+        }
397
+        return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
398
+    }
399
+
400
+    /**
401
+     * @return array|false
402
+     */
403
+    public function getDirectDownload() {
404
+        if (\OCP\App::isEnabled('encryption')) {
405
+            return [];
406
+        }
407
+        /** @var \OCP\Files\Storage $storage */
408
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
409
+        if (is_null($storage)) {
410
+            return [];
411
+        }
412
+
413
+        return $storage->getDirectDownload($internalPath);
414
+    }
415
+
416
+    /**
417
+     * @param resource $data
418
+     * @return null|string
419
+     * @throws Exception
420
+     * @throws BadRequest
421
+     * @throws NotImplemented
422
+     * @throws ServiceUnavailable
423
+     */
424
+    private function createFileChunked($data) {
425
+        list($path, $name) = \Sabre\Uri\split($this->path);
426
+
427
+        $info = \OC_FileChunking::decodeName($name);
428
+        if (empty($info)) {
429
+            throw new NotImplemented('Invalid chunk name');
430
+        }
431
+
432
+        $chunk_handler = new \OC_FileChunking($info);
433
+        $bytesWritten = $chunk_handler->store($info['index'], $data);
434
+
435
+        //detect aborted upload
436
+        if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
437
+            if (isset($_SERVER['CONTENT_LENGTH'])) {
438
+                $expected = (int) $_SERVER['CONTENT_LENGTH'];
439
+                if ($bytesWritten !== $expected) {
440
+                    $chunk_handler->remove($info['index']);
441
+                    throw new BadRequest(
442
+                        'expected filesize ' . $expected . ' got ' . $bytesWritten);
443
+                }
444
+            }
445
+        }
446
+
447
+        if ($chunk_handler->isComplete()) {
448
+            /** @var Storage $storage */
449
+            list($storage,) = $this->fileView->resolvePath($path);
450
+            $needsPartFile = $storage->needsPartFile();
451
+            $partFile = null;
452
+
453
+            $targetPath = $path . '/' . $info['name'];
454
+            /** @var \OC\Files\Storage\Storage $targetStorage */
455
+            list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
456
+
457
+            $exists = $this->fileView->file_exists($targetPath);
458
+
459
+            try {
460
+                $this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
461
+
462
+                $this->emitPreHooks($exists, $targetPath);
463
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
464
+                /** @var \OC\Files\Storage\Storage $targetStorage */
465
+                list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
466
+
467
+                if ($needsPartFile) {
468
+                    // we first assembly the target file as a part file
469
+                    $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
470
+                    /** @var \OC\Files\Storage\Storage $targetStorage */
471
+                    list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
472
+
473
+
474
+                    $chunk_handler->file_assemble($partStorage, $partInternalPath);
475
+
476
+                    // here is the final atomic rename
477
+                    $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
478
+                    $fileExists = $targetStorage->file_exists($targetInternalPath);
479
+                    if ($renameOkay === false || $fileExists === false) {
480
+                        \OC::$server->getLogger()->error('\OC\Files\Filesystem::rename() failed', ['app' => 'webdav']);
481
+                        // only delete if an error occurred and the target file was already created
482
+                        if ($fileExists) {
483
+                            // set to null to avoid double-deletion when handling exception
484
+                            // stray part file
485
+                            $partFile = null;
486
+                            $targetStorage->unlink($targetInternalPath);
487
+                        }
488
+                        $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
489
+                        throw new Exception('Could not rename part file assembled from chunks');
490
+                    }
491
+                } else {
492
+                    // assemble directly into the final file
493
+                    $chunk_handler->file_assemble($targetStorage, $targetInternalPath);
494
+                }
495
+
496
+                // allow sync clients to send the mtime along in a header
497
+                if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
498
+                    $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
499
+                    if ($targetStorage->touch($targetInternalPath, $mtime)) {
500
+                        $this->header('X-OC-MTime: accepted');
501
+                    }
502
+                }
503
+
504
+                // since we skipped the view we need to scan and emit the hooks ourselves
505
+                $targetStorage->getUpdater()->update($targetInternalPath);
506
+
507
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
508
+
509
+                $this->emitPostHooks($exists, $targetPath);
510
+
511
+                // FIXME: should call refreshInfo but can't because $this->path is not the of the final file
512
+                $info = $this->fileView->getFileInfo($targetPath);
513
+
514
+                if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
515
+                    $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
516
+                    $this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
517
+                } else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
518
+                    $this->fileView->putFileInfo($this->path, ['checksum' => '']);
519
+                }
520
+
521
+                $this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
522
+
523
+                return $info->getEtag();
524
+            } catch (\Exception $e) {
525
+                if ($partFile !== null) {
526
+                    $targetStorage->unlink($targetInternalPath);
527
+                }
528
+                $this->convertToSabreException($e);
529
+            }
530
+        }
531
+
532
+        return null;
533
+    }
534
+
535
+    /**
536
+     * Convert the given exception to a SabreException instance
537
+     *
538
+     * @param \Exception $e
539
+     *
540
+     * @throws \Sabre\DAV\Exception
541
+     */
542
+    private function convertToSabreException(\Exception $e) {
543
+        if ($e instanceof \Sabre\DAV\Exception) {
544
+            throw $e;
545
+        }
546
+        if ($e instanceof NotPermittedException) {
547
+            // a more general case - due to whatever reason the content could not be written
548
+            throw new Forbidden($e->getMessage(), 0, $e);
549
+        }
550
+        if ($e instanceof ForbiddenException) {
551
+            // the path for the file was forbidden
552
+            throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
553
+        }
554
+        if ($e instanceof EntityTooLargeException) {
555
+            // the file is too big to be stored
556
+            throw new EntityTooLarge($e->getMessage(), 0, $e);
557
+        }
558
+        if ($e instanceof InvalidContentException) {
559
+            // the file content is not permitted
560
+            throw new UnsupportedMediaType($e->getMessage(), 0, $e);
561
+        }
562
+        if ($e instanceof InvalidPathException) {
563
+            // the path for the file was not valid
564
+            // TODO: find proper http status code for this case
565
+            throw new Forbidden($e->getMessage(), 0, $e);
566
+        }
567
+        if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
568
+            // the file is currently being written to by another process
569
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
570
+        }
571
+        if ($e instanceof GenericEncryptionException) {
572
+            // returning 503 will allow retry of the operation at a later point in time
573
+            throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
574
+        }
575
+        if ($e instanceof StorageNotAvailableException) {
576
+            throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
577
+        }
578
+
579
+        throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
580
+    }
581
+
582
+    /**
583
+     * Get the checksum for this file
584
+     *
585
+     * @return string
586
+     */
587
+    public function getChecksum() {
588
+        return $this->info->getChecksum();
589
+    }
590
+
591
+    protected function header($string) {
592
+        \header($string);
593
+    }
594 594
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
 				throw new Forbidden();
122 122
 			}
123 123
 		} catch (StorageNotAvailableException $e) {
124
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
124
+			throw new ServiceUnavailable("File is not updatable: ".$e->getMessage());
125 125
 		}
126 126
 
127 127
 		// verify path of the target
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 
143 143
 		if ($needsPartFile) {
144 144
 			// mark file as partial while uploading (ignored by the scanner)
145
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
145
+			$partFilePath = $this->getPartFileBasePath($this->path).'.ocTransferId'.rand().'.part';
146 146
 		} else {
147 147
 			// upload file directly as the final path
148 148
 			$partFilePath = $this->path;
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
 				if (isset($_SERVER['CONTENT_LENGTH'])) {
171 171
 					$expected = $_SERVER['CONTENT_LENGTH'];
172 172
 				}
173
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
173
+				throw new Exception('Error while copying file to target location (copied bytes: '.$count.', expected filesize: '.$expected.' )');
174 174
 			}
175 175
 
176 176
 			// if content length is sent by client:
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
 			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
180 180
 				$expected = (int) $_SERVER['CONTENT_LENGTH'];
181 181
 				if ($count !== $expected) {
182
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
182
+					throw new BadRequest('expected filesize '.$expected.' got '.$count);
183 183
 				}
184 184
 			}
185 185
 
@@ -211,7 +211,7 @@  discard block
 block discarded – undo
211 211
 						$fileExists = $storage->file_exists($internalPath);
212 212
 					}
213 213
 					if (!$run || $renameOkay === false || $fileExists === false) {
214
-						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
214
+						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: '.($run ? 'true' : 'false').', $renameOkay: '.($renameOkay ? 'true' : 'false').', $fileExists: '.($fileExists ? 'true' : 'false').')', ['app' => 'webdav']);
215 215
 						throw new Exception('Could not rename part file to final file');
216 216
 					}
217 217
 				} catch (ForbiddenException $ex) {
@@ -255,10 +255,10 @@  discard block
 block discarded – undo
255 255
 			}
256 256
 
257 257
 		} catch (StorageNotAvailableException $e) {
258
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
258
+			throw new ServiceUnavailable("Failed to check file size: ".$e->getMessage());
259 259
 		}
260 260
 
261
-		return '"' . $this->info->getEtag() . '"';
261
+		return '"'.$this->info->getEtag().'"';
262 262
 	}
263 263
 
264 264
 	private function getPartFileBasePath($path) {
@@ -345,9 +345,9 @@  discard block
 block discarded – undo
345 345
 			return $res;
346 346
 		} catch (GenericEncryptionException $e) {
347 347
 			// returning 503 will allow retry of the operation at a later point in time
348
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
348
+			throw new ServiceUnavailable("Encryption not ready: ".$e->getMessage());
349 349
 		} catch (StorageNotAvailableException $e) {
350
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
350
+			throw new ServiceUnavailable("Failed to open file: ".$e->getMessage());
351 351
 		} catch (ForbiddenException $ex) {
352 352
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
353 353
 		} catch (LockedException $e) {
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
 				throw new Forbidden();
373 373
 			}
374 374
 		} catch (StorageNotAvailableException $e) {
375
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
375
+			throw new ServiceUnavailable("Failed to unlink: ".$e->getMessage());
376 376
 		} catch (ForbiddenException $ex) {
377 377
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
378 378
 		} catch (LockedException $e) {
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
 				if ($bytesWritten !== $expected) {
440 440
 					$chunk_handler->remove($info['index']);
441 441
 					throw new BadRequest(
442
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
442
+						'expected filesize '.$expected.' got '.$bytesWritten);
443 443
 				}
444 444
 			}
445 445
 		}
@@ -450,7 +450,7 @@  discard block
 block discarded – undo
450 450
 			$needsPartFile = $storage->needsPartFile();
451 451
 			$partFile = null;
452 452
 
453
-			$targetPath = $path . '/' . $info['name'];
453
+			$targetPath = $path.'/'.$info['name'];
454 454
 			/** @var \OC\Files\Storage\Storage $targetStorage */
455 455
 			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
456 456
 
@@ -466,7 +466,7 @@  discard block
 block discarded – undo
466 466
 
467 467
 				if ($needsPartFile) {
468 468
 					// we first assembly the target file as a part file
469
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
469
+					$partFile = $this->getPartFileBasePath($path.'/'.$info['name']).'.ocTransferId'.$info['transferid'].'.part';
470 470
 					/** @var \OC\Files\Storage\Storage $targetStorage */
471 471
 					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
472 472
 
@@ -570,10 +570,10 @@  discard block
 block discarded – undo
570 570
 		}
571 571
 		if ($e instanceof GenericEncryptionException) {
572 572
 			// returning 503 will allow retry of the operation at a later point in time
573
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
573
+			throw new ServiceUnavailable('Encryption not ready: '.$e->getMessage(), 0, $e);
574 574
 		}
575 575
 		if ($e instanceof StorageNotAvailableException) {
576
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
576
+			throw new ServiceUnavailable('Failed to write file contents: '.$e->getMessage(), 0, $e);
577 577
 		}
578 578
 
579 579
 		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
Please login to merge, or discard this patch.
apps/files_sharing/lib/External/Storage.php 1 patch
Indentation   +327 added lines, -327 removed lines patch added patch discarded remove patch
@@ -42,331 +42,331 @@
 block discarded – undo
42 42
 use OCP\Files\StorageNotAvailableException;
43 43
 
44 44
 class Storage extends DAV implements ISharedStorage {
45
-	/** @var ICloudId */
46
-	private $cloudId;
47
-	/** @var string */
48
-	private $mountPoint;
49
-	/** @var string */
50
-	private $token;
51
-	/** @var \OCP\ICacheFactory */
52
-	private $memcacheFactory;
53
-	/** @var \OCP\Http\Client\IClientService */
54
-	private $httpClient;
55
-	/** @var bool */
56
-	private $updateChecked = false;
57
-
58
-	/**
59
-	 * @var \OCA\Files_Sharing\External\Manager
60
-	 */
61
-	private $manager;
62
-
63
-	public function __construct($options) {
64
-		$this->memcacheFactory = \OC::$server->getMemCacheFactory();
65
-		$this->httpClient = $options['HttpClientService'];
66
-
67
-		$this->manager = $options['manager'];
68
-		$this->cloudId = $options['cloudId'];
69
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
70
-
71
-		list($protocol, $remote) = explode('://', $this->cloudId->getRemote());
72
-		if (strpos($remote, '/')) {
73
-			list($host, $root) = explode('/', $remote, 2);
74
-		} else {
75
-			$host = $remote;
76
-			$root = '';
77
-		}
78
-		$secure = $protocol === 'https';
79
-		$federatedSharingEndpoints = $discoveryService->discover($this->cloudId->getRemote(), 'FEDERATED_SHARING');
80
-		$webDavEndpoint = isset($federatedSharingEndpoints['webdav']) ? $federatedSharingEndpoints['webdav'] : '/public.php/webdav';
81
-		$root = rtrim($root, '/') . $webDavEndpoint;
82
-		$this->mountPoint = $options['mountpoint'];
83
-		$this->token = $options['token'];
84
-
85
-		parent::__construct(array(
86
-			'secure' => $secure,
87
-			'host' => $host,
88
-			'root' => $root,
89
-			'user' => $options['token'],
90
-			'password' => (string)$options['password']
91
-		));
92
-	}
93
-
94
-	public function getWatcher($path = '', $storage = null) {
95
-		if (!$storage) {
96
-			$storage = $this;
97
-		}
98
-		if (!isset($this->watcher)) {
99
-			$this->watcher = new Watcher($storage);
100
-			$this->watcher->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE);
101
-		}
102
-		return $this->watcher;
103
-	}
104
-
105
-	public function getRemoteUser() {
106
-		return $this->cloudId->getUser();
107
-	}
108
-
109
-	public function getRemote() {
110
-		return $this->cloudId->getRemote();
111
-	}
112
-
113
-	public function getMountPoint() {
114
-		return $this->mountPoint;
115
-	}
116
-
117
-	public function getToken() {
118
-		return $this->token;
119
-	}
120
-
121
-	public function getPassword() {
122
-		return $this->password;
123
-	}
124
-
125
-	/**
126
-	 * @brief get id of the mount point
127
-	 * @return string
128
-	 */
129
-	public function getId() {
130
-		return 'shared::' . md5($this->token . '@' . $this->getRemote());
131
-	}
132
-
133
-	public function getCache($path = '', $storage = null) {
134
-		if (is_null($this->cache)) {
135
-			$this->cache = new Cache($this, $this->cloudId);
136
-		}
137
-		return $this->cache;
138
-	}
139
-
140
-	/**
141
-	 * @param string $path
142
-	 * @param \OC\Files\Storage\Storage $storage
143
-	 * @return \OCA\Files_Sharing\External\Scanner
144
-	 */
145
-	public function getScanner($path = '', $storage = null) {
146
-		if (!$storage) {
147
-			$storage = $this;
148
-		}
149
-		if (!isset($this->scanner)) {
150
-			$this->scanner = new Scanner($storage);
151
-		}
152
-		return $this->scanner;
153
-	}
154
-
155
-	/**
156
-	 * check if a file or folder has been updated since $time
157
-	 *
158
-	 * @param string $path
159
-	 * @param int $time
160
-	 * @throws \OCP\Files\StorageNotAvailableException
161
-	 * @throws \OCP\Files\StorageInvalidException
162
-	 * @return bool
163
-	 */
164
-	public function hasUpdated($path, $time) {
165
-		// since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage
166
-		// because of that we only do one check for the entire storage per request
167
-		if ($this->updateChecked) {
168
-			return false;
169
-		}
170
-		$this->updateChecked = true;
171
-		try {
172
-			return parent::hasUpdated('', $time);
173
-		} catch (StorageInvalidException $e) {
174
-			// check if it needs to be removed
175
-			$this->checkStorageAvailability();
176
-			throw $e;
177
-		} catch (StorageNotAvailableException $e) {
178
-			// check if it needs to be removed or just temp unavailable
179
-			$this->checkStorageAvailability();
180
-			throw $e;
181
-		}
182
-	}
183
-
184
-	public function test() {
185
-		try {
186
-			return parent::test();
187
-		} catch (StorageInvalidException $e) {
188
-			// check if it needs to be removed
189
-			$this->checkStorageAvailability();
190
-			throw $e;
191
-		} catch (StorageNotAvailableException $e) {
192
-			// check if it needs to be removed or just temp unavailable
193
-			$this->checkStorageAvailability();
194
-			throw $e;
195
-		}
196
-	}
197
-
198
-	/**
199
-	 * Check whether this storage is permanently or temporarily
200
-	 * unavailable
201
-	 *
202
-	 * @throws \OCP\Files\StorageNotAvailableException
203
-	 * @throws \OCP\Files\StorageInvalidException
204
-	 */
205
-	public function checkStorageAvailability() {
206
-		// see if we can find out why the share is unavailable
207
-		try {
208
-			$this->getShareInfo();
209
-		} catch (NotFoundException $e) {
210
-			// a 404 can either mean that the share no longer exists or there is no Nextcloud on the remote
211
-			if ($this->testRemote()) {
212
-				// valid Nextcloud instance means that the public share no longer exists
213
-				// since this is permanent (re-sharing the file will create a new token)
214
-				// we remove the invalid storage
215
-				$this->manager->removeShare($this->mountPoint);
216
-				$this->manager->getMountManager()->removeMount($this->mountPoint);
217
-				throw new StorageInvalidException();
218
-			} else {
219
-				// Nextcloud instance is gone, likely to be a temporary server configuration error
220
-				throw new StorageNotAvailableException();
221
-			}
222
-		} catch (ForbiddenException $e) {
223
-			// auth error, remove share for now (provide a dialog in the future)
224
-			$this->manager->removeShare($this->mountPoint);
225
-			$this->manager->getMountManager()->removeMount($this->mountPoint);
226
-			throw new StorageInvalidException();
227
-		} catch (\GuzzleHttp\Exception\ConnectException $e) {
228
-			throw new StorageNotAvailableException();
229
-		} catch (\GuzzleHttp\Exception\RequestException $e) {
230
-			throw new StorageNotAvailableException();
231
-		} catch (\Exception $e) {
232
-			throw $e;
233
-		}
234
-	}
235
-
236
-	public function file_exists($path) {
237
-		if ($path === '') {
238
-			return true;
239
-		} else {
240
-			return parent::file_exists($path);
241
-		}
242
-	}
243
-
244
-	/**
245
-	 * check if the configured remote is a valid federated share provider
246
-	 *
247
-	 * @return bool
248
-	 */
249
-	protected function testRemote() {
250
-		try {
251
-			return $this->testRemoteUrl($this->getRemote() . '/ocs-provider/index.php')
252
-				|| $this->testRemoteUrl($this->getRemote() . '/ocs-provider/')
253
-				|| $this->testRemoteUrl($this->getRemote() . '/status.php');
254
-		} catch (\Exception $e) {
255
-			return false;
256
-		}
257
-	}
258
-
259
-	/**
260
-	 * @param string $url
261
-	 * @return bool
262
-	 */
263
-	private function testRemoteUrl($url) {
264
-		$cache = $this->memcacheFactory->createDistributed('files_sharing_remote_url');
265
-		if($cache->hasKey($url)) {
266
-			return (bool)$cache->get($url);
267
-		}
268
-
269
-		$client = $this->httpClient->newClient();
270
-		try {
271
-			$result = $client->get($url, [
272
-				'timeout' => 10,
273
-				'connect_timeout' => 10,
274
-			])->getBody();
275
-			$data = json_decode($result);
276
-			$returnValue = (is_object($data) && !empty($data->version));
277
-		} catch (ConnectException $e) {
278
-			$returnValue = false;
279
-		} catch (ClientException $e) {
280
-			$returnValue = false;
281
-		}
282
-
283
-		$cache->set($url, $returnValue, 60*60*24);
284
-		return $returnValue;
285
-	}
286
-
287
-	/**
288
-	 * Whether the remote is an ownCloud/Nextcloud, used since some sharing features are not
289
-	 * standardized. Let's use this to detect whether to use it.
290
-	 *
291
-	 * @return bool
292
-	 */
293
-	public function remoteIsOwnCloud() {
294
-		if(defined('PHPUNIT_RUN') || !$this->testRemoteUrl($this->getRemote() . '/status.php')) {
295
-			return false;
296
-		}
297
-		return true;
298
-	}
299
-
300
-	/**
301
-	 * @return mixed
302
-	 * @throws ForbiddenException
303
-	 * @throws NotFoundException
304
-	 * @throws \Exception
305
-	 */
306
-	public function getShareInfo() {
307
-		$remote = $this->getRemote();
308
-		$token = $this->getToken();
309
-		$password = $this->getPassword();
310
-
311
-		// If remote is not an ownCloud do not try to get any share info
312
-		if(!$this->remoteIsOwnCloud()) {
313
-			return ['status' => 'unsupported'];
314
-		}
315
-
316
-		$url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
317
-
318
-		// TODO: DI
319
-		$client = \OC::$server->getHTTPClientService()->newClient();
320
-		try {
321
-			$response = $client->post($url, [
322
-				'body' => ['password' => $password],
323
-				'timeout' => 10,
324
-				'connect_timeout' => 10,
325
-			]);
326
-		} catch (\GuzzleHttp\Exception\RequestException $e) {
327
-			if ($e->getCode() === Http::STATUS_UNAUTHORIZED || $e->getCode() === Http::STATUS_FORBIDDEN) {
328
-				throw new ForbiddenException();
329
-			}
330
-			if ($e->getCode() === Http::STATUS_NOT_FOUND) {
331
-				throw new NotFoundException();
332
-			}
333
-			// throw this to be on the safe side: the share will still be visible
334
-			// in the UI in case the failure is intermittent, and the user will
335
-			// be able to decide whether to remove it if it's really gone
336
-			throw new StorageNotAvailableException();
337
-		}
338
-
339
-		return json_decode($response->getBody(), true);
340
-	}
341
-
342
-	public function getOwner($path) {
343
-		return $this->cloudId->getDisplayId();
344
-	}
345
-
346
-	public function isSharable($path) {
347
-		if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
348
-			return false;
349
-		}
350
-		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
351
-	}
352
-
353
-	public function getPermissions($path) {
354
-		$response = $this->propfind($path);
355
-		if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
356
-			$permissions = $response['{http://open-collaboration-services.org/ns}share-permissions'];
357
-		} else {
358
-			// use default permission if remote server doesn't provide the share permissions
359
-			if ($this->is_dir($path)) {
360
-				$permissions = \OCP\Constants::PERMISSION_ALL;
361
-			} else {
362
-				$permissions = \OCP\Constants::PERMISSION_ALL & ~\OCP\Constants::PERMISSION_CREATE;
363
-			}
364
-		}
365
-
366
-		return $permissions;
367
-	}
368
-
369
-	public function needsPartFile() {
370
-		return false;
371
-	}
45
+    /** @var ICloudId */
46
+    private $cloudId;
47
+    /** @var string */
48
+    private $mountPoint;
49
+    /** @var string */
50
+    private $token;
51
+    /** @var \OCP\ICacheFactory */
52
+    private $memcacheFactory;
53
+    /** @var \OCP\Http\Client\IClientService */
54
+    private $httpClient;
55
+    /** @var bool */
56
+    private $updateChecked = false;
57
+
58
+    /**
59
+     * @var \OCA\Files_Sharing\External\Manager
60
+     */
61
+    private $manager;
62
+
63
+    public function __construct($options) {
64
+        $this->memcacheFactory = \OC::$server->getMemCacheFactory();
65
+        $this->httpClient = $options['HttpClientService'];
66
+
67
+        $this->manager = $options['manager'];
68
+        $this->cloudId = $options['cloudId'];
69
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
70
+
71
+        list($protocol, $remote) = explode('://', $this->cloudId->getRemote());
72
+        if (strpos($remote, '/')) {
73
+            list($host, $root) = explode('/', $remote, 2);
74
+        } else {
75
+            $host = $remote;
76
+            $root = '';
77
+        }
78
+        $secure = $protocol === 'https';
79
+        $federatedSharingEndpoints = $discoveryService->discover($this->cloudId->getRemote(), 'FEDERATED_SHARING');
80
+        $webDavEndpoint = isset($federatedSharingEndpoints['webdav']) ? $federatedSharingEndpoints['webdav'] : '/public.php/webdav';
81
+        $root = rtrim($root, '/') . $webDavEndpoint;
82
+        $this->mountPoint = $options['mountpoint'];
83
+        $this->token = $options['token'];
84
+
85
+        parent::__construct(array(
86
+            'secure' => $secure,
87
+            'host' => $host,
88
+            'root' => $root,
89
+            'user' => $options['token'],
90
+            'password' => (string)$options['password']
91
+        ));
92
+    }
93
+
94
+    public function getWatcher($path = '', $storage = null) {
95
+        if (!$storage) {
96
+            $storage = $this;
97
+        }
98
+        if (!isset($this->watcher)) {
99
+            $this->watcher = new Watcher($storage);
100
+            $this->watcher->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE);
101
+        }
102
+        return $this->watcher;
103
+    }
104
+
105
+    public function getRemoteUser() {
106
+        return $this->cloudId->getUser();
107
+    }
108
+
109
+    public function getRemote() {
110
+        return $this->cloudId->getRemote();
111
+    }
112
+
113
+    public function getMountPoint() {
114
+        return $this->mountPoint;
115
+    }
116
+
117
+    public function getToken() {
118
+        return $this->token;
119
+    }
120
+
121
+    public function getPassword() {
122
+        return $this->password;
123
+    }
124
+
125
+    /**
126
+     * @brief get id of the mount point
127
+     * @return string
128
+     */
129
+    public function getId() {
130
+        return 'shared::' . md5($this->token . '@' . $this->getRemote());
131
+    }
132
+
133
+    public function getCache($path = '', $storage = null) {
134
+        if (is_null($this->cache)) {
135
+            $this->cache = new Cache($this, $this->cloudId);
136
+        }
137
+        return $this->cache;
138
+    }
139
+
140
+    /**
141
+     * @param string $path
142
+     * @param \OC\Files\Storage\Storage $storage
143
+     * @return \OCA\Files_Sharing\External\Scanner
144
+     */
145
+    public function getScanner($path = '', $storage = null) {
146
+        if (!$storage) {
147
+            $storage = $this;
148
+        }
149
+        if (!isset($this->scanner)) {
150
+            $this->scanner = new Scanner($storage);
151
+        }
152
+        return $this->scanner;
153
+    }
154
+
155
+    /**
156
+     * check if a file or folder has been updated since $time
157
+     *
158
+     * @param string $path
159
+     * @param int $time
160
+     * @throws \OCP\Files\StorageNotAvailableException
161
+     * @throws \OCP\Files\StorageInvalidException
162
+     * @return bool
163
+     */
164
+    public function hasUpdated($path, $time) {
165
+        // since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage
166
+        // because of that we only do one check for the entire storage per request
167
+        if ($this->updateChecked) {
168
+            return false;
169
+        }
170
+        $this->updateChecked = true;
171
+        try {
172
+            return parent::hasUpdated('', $time);
173
+        } catch (StorageInvalidException $e) {
174
+            // check if it needs to be removed
175
+            $this->checkStorageAvailability();
176
+            throw $e;
177
+        } catch (StorageNotAvailableException $e) {
178
+            // check if it needs to be removed or just temp unavailable
179
+            $this->checkStorageAvailability();
180
+            throw $e;
181
+        }
182
+    }
183
+
184
+    public function test() {
185
+        try {
186
+            return parent::test();
187
+        } catch (StorageInvalidException $e) {
188
+            // check if it needs to be removed
189
+            $this->checkStorageAvailability();
190
+            throw $e;
191
+        } catch (StorageNotAvailableException $e) {
192
+            // check if it needs to be removed or just temp unavailable
193
+            $this->checkStorageAvailability();
194
+            throw $e;
195
+        }
196
+    }
197
+
198
+    /**
199
+     * Check whether this storage is permanently or temporarily
200
+     * unavailable
201
+     *
202
+     * @throws \OCP\Files\StorageNotAvailableException
203
+     * @throws \OCP\Files\StorageInvalidException
204
+     */
205
+    public function checkStorageAvailability() {
206
+        // see if we can find out why the share is unavailable
207
+        try {
208
+            $this->getShareInfo();
209
+        } catch (NotFoundException $e) {
210
+            // a 404 can either mean that the share no longer exists or there is no Nextcloud on the remote
211
+            if ($this->testRemote()) {
212
+                // valid Nextcloud instance means that the public share no longer exists
213
+                // since this is permanent (re-sharing the file will create a new token)
214
+                // we remove the invalid storage
215
+                $this->manager->removeShare($this->mountPoint);
216
+                $this->manager->getMountManager()->removeMount($this->mountPoint);
217
+                throw new StorageInvalidException();
218
+            } else {
219
+                // Nextcloud instance is gone, likely to be a temporary server configuration error
220
+                throw new StorageNotAvailableException();
221
+            }
222
+        } catch (ForbiddenException $e) {
223
+            // auth error, remove share for now (provide a dialog in the future)
224
+            $this->manager->removeShare($this->mountPoint);
225
+            $this->manager->getMountManager()->removeMount($this->mountPoint);
226
+            throw new StorageInvalidException();
227
+        } catch (\GuzzleHttp\Exception\ConnectException $e) {
228
+            throw new StorageNotAvailableException();
229
+        } catch (\GuzzleHttp\Exception\RequestException $e) {
230
+            throw new StorageNotAvailableException();
231
+        } catch (\Exception $e) {
232
+            throw $e;
233
+        }
234
+    }
235
+
236
+    public function file_exists($path) {
237
+        if ($path === '') {
238
+            return true;
239
+        } else {
240
+            return parent::file_exists($path);
241
+        }
242
+    }
243
+
244
+    /**
245
+     * check if the configured remote is a valid federated share provider
246
+     *
247
+     * @return bool
248
+     */
249
+    protected function testRemote() {
250
+        try {
251
+            return $this->testRemoteUrl($this->getRemote() . '/ocs-provider/index.php')
252
+                || $this->testRemoteUrl($this->getRemote() . '/ocs-provider/')
253
+                || $this->testRemoteUrl($this->getRemote() . '/status.php');
254
+        } catch (\Exception $e) {
255
+            return false;
256
+        }
257
+    }
258
+
259
+    /**
260
+     * @param string $url
261
+     * @return bool
262
+     */
263
+    private function testRemoteUrl($url) {
264
+        $cache = $this->memcacheFactory->createDistributed('files_sharing_remote_url');
265
+        if($cache->hasKey($url)) {
266
+            return (bool)$cache->get($url);
267
+        }
268
+
269
+        $client = $this->httpClient->newClient();
270
+        try {
271
+            $result = $client->get($url, [
272
+                'timeout' => 10,
273
+                'connect_timeout' => 10,
274
+            ])->getBody();
275
+            $data = json_decode($result);
276
+            $returnValue = (is_object($data) && !empty($data->version));
277
+        } catch (ConnectException $e) {
278
+            $returnValue = false;
279
+        } catch (ClientException $e) {
280
+            $returnValue = false;
281
+        }
282
+
283
+        $cache->set($url, $returnValue, 60*60*24);
284
+        return $returnValue;
285
+    }
286
+
287
+    /**
288
+     * Whether the remote is an ownCloud/Nextcloud, used since some sharing features are not
289
+     * standardized. Let's use this to detect whether to use it.
290
+     *
291
+     * @return bool
292
+     */
293
+    public function remoteIsOwnCloud() {
294
+        if(defined('PHPUNIT_RUN') || !$this->testRemoteUrl($this->getRemote() . '/status.php')) {
295
+            return false;
296
+        }
297
+        return true;
298
+    }
299
+
300
+    /**
301
+     * @return mixed
302
+     * @throws ForbiddenException
303
+     * @throws NotFoundException
304
+     * @throws \Exception
305
+     */
306
+    public function getShareInfo() {
307
+        $remote = $this->getRemote();
308
+        $token = $this->getToken();
309
+        $password = $this->getPassword();
310
+
311
+        // If remote is not an ownCloud do not try to get any share info
312
+        if(!$this->remoteIsOwnCloud()) {
313
+            return ['status' => 'unsupported'];
314
+        }
315
+
316
+        $url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
317
+
318
+        // TODO: DI
319
+        $client = \OC::$server->getHTTPClientService()->newClient();
320
+        try {
321
+            $response = $client->post($url, [
322
+                'body' => ['password' => $password],
323
+                'timeout' => 10,
324
+                'connect_timeout' => 10,
325
+            ]);
326
+        } catch (\GuzzleHttp\Exception\RequestException $e) {
327
+            if ($e->getCode() === Http::STATUS_UNAUTHORIZED || $e->getCode() === Http::STATUS_FORBIDDEN) {
328
+                throw new ForbiddenException();
329
+            }
330
+            if ($e->getCode() === Http::STATUS_NOT_FOUND) {
331
+                throw new NotFoundException();
332
+            }
333
+            // throw this to be on the safe side: the share will still be visible
334
+            // in the UI in case the failure is intermittent, and the user will
335
+            // be able to decide whether to remove it if it's really gone
336
+            throw new StorageNotAvailableException();
337
+        }
338
+
339
+        return json_decode($response->getBody(), true);
340
+    }
341
+
342
+    public function getOwner($path) {
343
+        return $this->cloudId->getDisplayId();
344
+    }
345
+
346
+    public function isSharable($path) {
347
+        if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
348
+            return false;
349
+        }
350
+        return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
351
+    }
352
+
353
+    public function getPermissions($path) {
354
+        $response = $this->propfind($path);
355
+        if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
356
+            $permissions = $response['{http://open-collaboration-services.org/ns}share-permissions'];
357
+        } else {
358
+            // use default permission if remote server doesn't provide the share permissions
359
+            if ($this->is_dir($path)) {
360
+                $permissions = \OCP\Constants::PERMISSION_ALL;
361
+            } else {
362
+                $permissions = \OCP\Constants::PERMISSION_ALL & ~\OCP\Constants::PERMISSION_CREATE;
363
+            }
364
+        }
365
+
366
+        return $permissions;
367
+    }
368
+
369
+    public function needsPartFile() {
370
+        return false;
371
+    }
372 372
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/OwnCloud.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -35,46 +35,46 @@
 block discarded – undo
35 35
  *
36 36
  */
37 37
 class OwnCloud extends \OC\Files\Storage\DAV{
38
-	const OC_URL_SUFFIX = 'remote.php/webdav';
38
+    const OC_URL_SUFFIX = 'remote.php/webdav';
39 39
 
40
-	public function __construct($params) {
41
-		// extract context path from host if specified
42
-		// (owncloud install path on host)
43
-		$host = $params['host'];
44
-		// strip protocol
45
-		if (substr($host, 0, 8) === "https://") {
46
-			$host = substr($host, 8);
47
-			$params['secure'] = true;
48
-		} else if (substr($host, 0, 7) === "http://") {
49
-			$host = substr($host, 7);
50
-			$params['secure'] = false;
51
-		}
52
-		$contextPath = '';
53
-		$hostSlashPos = strpos($host, '/');
54
-		if ($hostSlashPos !== false){
55
-			$contextPath = substr($host, $hostSlashPos);
56
-			$host = substr($host, 0, $hostSlashPos);
57
-		}
40
+    public function __construct($params) {
41
+        // extract context path from host if specified
42
+        // (owncloud install path on host)
43
+        $host = $params['host'];
44
+        // strip protocol
45
+        if (substr($host, 0, 8) === "https://") {
46
+            $host = substr($host, 8);
47
+            $params['secure'] = true;
48
+        } else if (substr($host, 0, 7) === "http://") {
49
+            $host = substr($host, 7);
50
+            $params['secure'] = false;
51
+        }
52
+        $contextPath = '';
53
+        $hostSlashPos = strpos($host, '/');
54
+        if ($hostSlashPos !== false){
55
+            $contextPath = substr($host, $hostSlashPos);
56
+            $host = substr($host, 0, $hostSlashPos);
57
+        }
58 58
 
59
-		if (substr($contextPath, -1) !== '/'){
60
-			$contextPath .= '/';
61
-		}
59
+        if (substr($contextPath, -1) !== '/'){
60
+            $contextPath .= '/';
61
+        }
62 62
 
63
-		if (isset($params['root'])){
64
-			$root = '/' . ltrim($params['root'], '/');
65
-		}
66
-		else{
67
-			$root = '/';
68
-		}
63
+        if (isset($params['root'])){
64
+            $root = '/' . ltrim($params['root'], '/');
65
+        }
66
+        else{
67
+            $root = '/';
68
+        }
69 69
 
70
-		$params['host'] = $host;
71
-		$params['root'] = $contextPath . self::OC_URL_SUFFIX . $root;
72
-		$params['authType'] = Client::AUTH_BASIC;
70
+        $params['host'] = $host;
71
+        $params['root'] = $contextPath . self::OC_URL_SUFFIX . $root;
72
+        $params['authType'] = Client::AUTH_BASIC;
73 73
 
74
-		parent::__construct($params);
75
-	}
74
+        parent::__construct($params);
75
+    }
76 76
 
77
-	public function needsPartFile() {
78
-		return false;
79
-	}
77
+    public function needsPartFile() {
78
+        return false;
79
+    }
80 80
 }
Please login to merge, or discard this patch.