|
|
|
@ -31,6 +31,7 @@
|
|
|
|
|
namespace OCA\DAV\Connector\Sabre;
|
|
|
|
|
|
|
|
|
|
use OCA\DAV\Upload\FutureFile;
|
|
|
|
|
use OCA\DAV\Upload\UploadFolder;
|
|
|
|
|
use OCP\Files\StorageNotAvailableException;
|
|
|
|
|
use Sabre\DAV\Exception\InsufficientStorage;
|
|
|
|
|
use Sabre\DAV\Exception\ServiceUnavailable;
|
|
|
|
@ -90,6 +91,19 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
* @param bool $modified modified
|
|
|
|
|
*/
|
|
|
|
|
public function beforeCreateFile($uri, $data, INode $parent, $modified) {
|
|
|
|
|
$request = $this->server->httpRequest;
|
|
|
|
|
if ($parent instanceof UploadFolder && $request->getHeader('Destination')) {
|
|
|
|
|
// If chunked upload and Total-Length header is set, use that
|
|
|
|
|
// value for quota check. This allows us to also check quota while
|
|
|
|
|
// uploading chunks and not only when the file is assembled.
|
|
|
|
|
$length = $request->getHeader('OC-Total-Length');
|
|
|
|
|
$destinationPath = $this->server->calculateUri($request->getHeader('Destination'));
|
|
|
|
|
$quotaPath = $this->getPathForDestination($destinationPath);
|
|
|
|
|
if ($quotaPath && is_numeric($length)) {
|
|
|
|
|
return $this->checkQuota($quotaPath, (int)$length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$parent instanceof Node) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -114,29 +128,20 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if we're moving a Futurefile in which case we need to check
|
|
|
|
|
* Check if we're moving a FutureFile in which case we need to check
|
|
|
|
|
* the quota on the target destination.
|
|
|
|
|
*
|
|
|
|
|
* @param string $source source path
|
|
|
|
|
* @param string $destination destination path
|
|
|
|
|
*/
|
|
|
|
|
public function beforeMove($source, $destination) {
|
|
|
|
|
$sourceNode = $this->server->tree->getNodeForPath($source);
|
|
|
|
|
public function beforeMove(string $sourcePath, string $destinationPath): bool {
|
|
|
|
|
$sourceNode = $this->server->tree->getNodeForPath($sourcePath);
|
|
|
|
|
if (!$sourceNode instanceof FutureFile) {
|
|
|
|
|
return;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get target node for proper path conversion
|
|
|
|
|
if ($this->server->tree->nodeExists($destination)) {
|
|
|
|
|
$destinationNode = $this->server->tree->getNodeForPath($destination);
|
|
|
|
|
$path = $destinationNode->getPath();
|
|
|
|
|
} else {
|
|
|
|
|
$parent = dirname($destination);
|
|
|
|
|
if ($parent === '.') {
|
|
|
|
|
$parent = '';
|
|
|
|
|
}
|
|
|
|
|
$parentNode = $this->server->tree->getNodeForPath($parent);
|
|
|
|
|
$path = $parentNode->getPath();
|
|
|
|
|
try {
|
|
|
|
|
// The final path is not known yet, we check the quota on the parent
|
|
|
|
|
$path = $this->getPathForDestination($destinationPath);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->checkQuota($path, $sourceNode->getSize());
|
|
|
|
@ -151,26 +156,36 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$path = $this->getPathForDestination($destinationPath);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->checkQuota($path, $sourceNode->getSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getPathForDestination(string $destinationPath): string {
|
|
|
|
|
// get target node for proper path conversion
|
|
|
|
|
if ($this->server->tree->nodeExists($destinationPath)) {
|
|
|
|
|
$destinationNode = $this->server->tree->getNodeForPath($destinationPath);
|
|
|
|
|
if (!$destinationNode instanceof Node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
$path = $destinationNode->getPath();
|
|
|
|
|
} else {
|
|
|
|
|
$parent = dirname($destinationPath);
|
|
|
|
|
if ($parent === '.') {
|
|
|
|
|
$parent = '';
|
|
|
|
|
}
|
|
|
|
|
$parentNode = $this->server->tree->getNodeForPath($parent);
|
|
|
|
|
if (!$parentNode instanceof Node) {
|
|
|
|
|
return true;
|
|
|
|
|
throw new \Exception('Invalid destination node');
|
|
|
|
|
}
|
|
|
|
|
$path = $parentNode->getPath();
|
|
|
|
|
return $destinationNode->getPath();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->checkQuota($path, $sourceNode->getSize());
|
|
|
|
|
$parent = dirname($destinationPath);
|
|
|
|
|
if ($parent === '.') {
|
|
|
|
|
$parent = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$parentNode = $this->server->tree->getNodeForPath($parent);
|
|
|
|
|
if (!$parentNode instanceof Node) {
|
|
|
|
|
throw new \Exception('Invalid destination node');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $parentNode->getPath();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -182,7 +197,7 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
* @throws InsufficientStorage
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function checkQuota($path, $length = null) {
|
|
|
|
|
public function checkQuota(string $path, $length = null) {
|
|
|
|
|
if ($length === null) {
|
|
|
|
|
$length = $this->getLength();
|
|
|
|
|
}
|
|
|
|
@ -194,7 +209,7 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
}
|
|
|
|
|
$req = $this->server->httpRequest;
|
|
|
|
|
|
|
|
|
|
// If chunked upload
|
|
|
|
|
// If LEGACY chunked upload
|
|
|
|
|
if ($req->getHeader('OC-Chunked')) {
|
|
|
|
|
$info = \OC_FileChunking::decodeName($newName);
|
|
|
|
|
$chunkHandler = $this->getFileChunking($info);
|
|
|
|
@ -210,12 +225,14 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|
|
|
|
|
|
|
|
|
$freeSpace = $this->getFreeSpace($path);
|
|
|
|
|
if ($freeSpace >= 0 && $length > $freeSpace) {
|
|
|
|
|
// If LEGACY chunked upload, clean up
|
|
|
|
|
if (isset($chunkHandler)) {
|
|
|
|
|
$chunkHandler->cleanup();
|
|
|
|
|
}
|
|
|
|
|
throw new InsufficientStorage("Insufficient space in $path, $length required, $freeSpace available");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|