|
31 | 31 | use OCP\Files\LockNotAcquiredException; |
32 | 32 | use OCP\Files\NotFoundException; |
33 | 33 | use OCP\Files\NotPermittedException; |
| 34 | +use OCP\Files\Storage\IStorage; |
34 | 35 | use OCP\Files\Storage\IWriteStreamStorage; |
35 | 36 | use OCP\Files\StorageNotAvailableException; |
36 | 37 | use OCP\IConfig; |
@@ -334,56 +335,64 @@ public function put($data) { |
334 | 335 | } |
335 | 336 | } |
336 | 337 |
|
337 | | - // since we skipped the view we need to scan and emit the hooks ourselves |
338 | | - $storage->getUpdater()->update($internalPath); |
339 | | - |
340 | | - try { |
341 | | - $this->changeLock(ILockingProvider::LOCK_SHARED); |
342 | | - } catch (LockedException $e) { |
343 | | - throw new FileLocked($e->getMessage(), $e->getCode(), $e); |
344 | | - } |
345 | | - |
346 | | - // allow sync clients to send the mtime along in a header |
347 | | - $mtimeHeader = $this->request->getHeader('x-oc-mtime'); |
348 | | - if ($mtimeHeader !== '') { |
349 | | - $mtime = $this->sanitizeMtime($mtimeHeader); |
350 | | - if ($this->fileView->touch($this->path, $mtime)) { |
351 | | - $this->header('X-OC-MTime: accepted'); |
352 | | - } |
353 | | - } |
| 338 | + $this->finalizeUpload($storage, $internalPath, $exists, $view); |
| 339 | + } catch (StorageNotAvailableException $e) { |
| 340 | + throw new ServiceUnavailable($this->l10n->t('Failed to check file size: %1$s', [$e->getMessage()]), 0, $e); |
| 341 | + } |
354 | 342 |
|
355 | | - $fileInfoUpdate = [ |
356 | | - 'upload_time' => time() |
357 | | - ]; |
| 343 | + return '"' . $this->info->getEtag() . '"'; |
| 344 | + } |
358 | 345 |
|
359 | | - // allow sync clients to send the creation time along in a header |
360 | | - $ctimeHeader = $this->request->getHeader('x-oc-ctime'); |
361 | | - if ($ctimeHeader) { |
362 | | - $ctime = $this->sanitizeMtime($ctimeHeader); |
363 | | - $fileInfoUpdate['creation_time'] = $ctime; |
364 | | - $this->header('X-OC-CTime: accepted'); |
| 346 | + private function finalizeUpload(IStorage $storage, string $internalPath, bool $exists, ?View $view): void { |
| 347 | + // Since we skipped the view for the final publish step, finalize the file |
| 348 | + // state explicitly here: update cache/bookkeeping, persist metadata, then |
| 349 | + // downgrade to a shared lock before emitting post-write hooks so listeners |
| 350 | + // can still access the file. |
| 351 | + $storage->getUpdater()->update($internalPath); |
| 352 | + |
| 353 | + $fileInfoUpdate = [ |
| 354 | + 'upload_time' => time(), |
| 355 | + ]; |
| 356 | + |
| 357 | + // allow sync clients to send the mtime along in a header |
| 358 | + $mtimeHeader = $this->request->getHeader('x-oc-mtime'); |
| 359 | + if ($mtimeHeader !== '') { |
| 360 | + $mtime = $this->sanitizeMtime($mtimeHeader); |
| 361 | + if ($this->fileView->touch($this->path, $mtime)) { |
| 362 | + $this->header('X-OC-MTime: accepted'); |
365 | 363 | } |
| 364 | + } |
366 | 365 |
|
367 | | - $this->fileView->putFileInfo($this->path, $fileInfoUpdate); |
| 366 | + // allow sync clients to send the creation time along in a header |
| 367 | + $ctimeHeader = $this->request->getHeader('x-oc-ctime'); |
| 368 | + if ($ctimeHeader !== '') { |
| 369 | + $ctime = $this->sanitizeMtime($ctimeHeader); |
| 370 | + $fileInfoUpdate['creation_time'] = $ctime; |
| 371 | + $this->header('X-OC-CTime: accepted'); |
| 372 | + } |
368 | 373 |
|
369 | | - if ($view) { |
370 | | - $this->emitPostHooks($exists); |
371 | | - } |
| 374 | + // Persist checksum before post hooks so observers see fully finalized metadata. |
| 375 | + $checksumHeader = $this->request->getHeader('oc-checksum'); |
| 376 | + if ($checksumHeader) { |
| 377 | + $fileInfoUpdate['checksum'] = trim($checksumHeader); |
| 378 | + } elseif ($this->getChecksum() !== null && $this->getChecksum() !== '') { |
| 379 | + $fileInfoUpdate['checksum'] = ''; |
| 380 | + } |
372 | 381 |
|
373 | | - $this->refreshInfo(); |
| 382 | + $this->fileView->putFileInfo($this->path, $fileInfoUpdate); |
| 383 | + $this->refreshInfo(); |
374 | 384 |
|
375 | | - $checksumHeader = $this->request->getHeader('oc-checksum'); |
376 | | - if ($checksumHeader) { |
377 | | - $checksum = trim($checksumHeader); |
378 | | - $this->setChecksum($checksum); |
379 | | - } elseif ($this->getChecksum() !== null && $this->getChecksum() !== '') { |
380 | | - $this->setChecksum(''); |
381 | | - } |
382 | | - } catch (StorageNotAvailableException $e) { |
383 | | - throw new ServiceUnavailable($this->l10n->t('Failed to check file size: %1$s', [$e->getMessage()]), 0, $e); |
| 385 | + // Downgrade to shared lock before post hooks so legacy hook consumers can |
| 386 | + // still access the file during post_write. |
| 387 | + try { |
| 388 | + $this->changeLock(ILockingProvider::LOCK_SHARED); |
| 389 | + } catch (LockedException $e) { |
| 390 | + throw new FileLocked($e->getMessage(), $e->getCode(), $e); |
384 | 391 | } |
385 | 392 |
|
386 | | - return '"' . $this->info->getEtag() . '"'; |
| 393 | + if ($view) { |
| 394 | + $this->emitPostHooks($exists); |
| 395 | + } |
387 | 396 | } |
388 | 397 |
|
389 | 398 | private function getPartFileBasePath($path) { |
|
0 commit comments