From 953a5fdf1e0c6fc2f2ae9a8f409ed18d1604e3bf Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:44:33 +0200 Subject: [PATCH] Configurationmanager.php: atomic write for configuration.json to prevent truncation on low disk (#7888) * fix: use atomic temp-file write to prevent configuration.json truncation Agent-Logs-Url: https://github.com/nextcloud/all-in-one/sessions/ea144d2f-2533-4001-8d10-d17168bb8bec Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com> * fix: improve error messages with specific file paths for config write failures Agent-Logs-Url: https://github.com/nextcloud/all-in-one/sessions/ea144d2f-2533-4001-8d10-d17168bb8bec Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Pablo Zmdl <57864086+pabzm@users.noreply.github.com> Signed-off-by: Simon L. --------- Signed-off-by: Simon L. Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com> Co-authored-by: Simon L. Co-authored-by: Pablo Zmdl <57864086+pabzm@users.noreply.github.com> --- php/src/Data/ConfigurationManager.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/php/src/Data/ConfigurationManager.php b/php/src/Data/ConfigurationManager.php index cd29c205..029a377f 100644 --- a/php/src/Data/ConfigurationManager.php +++ b/php/src/Data/ConfigurationManager.php @@ -302,6 +302,9 @@ class ConfigurationManager if ($this->config === [] && file_exists(DataConst::GetConfigFile())) { $configContent = (string)file_get_contents(DataConst::GetConfigFile()); + if ($configContent === '') { + throw new \RuntimeException("The config file " . DataConst::GetConfigFile() . " is empty. It may have been truncated due to low disk space. Please restore it from a backup."); + } $this->config = json_decode($configContent, true, 512, JSON_THROW_ON_ERROR); } @@ -702,7 +705,21 @@ class ConfigurationManager if ($df !== false && (int)$df < $size) { throw new InvalidSettingConfigurationException(DataConst::GetDataDirectory() . " does not have enough space for writing the config file! Not writing it back!"); } - file_put_contents(DataConst::GetConfigFile(), $content); + // Write to a temp file first to avoid truncating the config file if the + // disk fills up mid-write. rename() is atomic on POSIX filesystems, so the + // original config is never touched until the new content is fully on disk. + $tempFile = DataConst::GetConfigFile() . '.tmp'; + if (file_put_contents($tempFile, $content) === false) { + // The file probably wasn't created, but better check nonetheless. + if (file_exists($tempFile)) { + unlink($tempFile); + } + throw new InvalidSettingConfigurationException("Failed to write temporary config file: " . $tempFile); + } + if (!rename($tempFile, DataConst::GetConfigFile())) { + unlink($tempFile); + throw new InvalidSettingConfigurationException("Failed to rename " . $tempFile . " to " . DataConst::GetConfigFile()); + } $this->config = []; }