From a9d03c409406f3f95f692bc5545ebacc7f4e2e4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABl=20Utard?= <gael.utard@eedf.fr>
Date: Sat, 15 Feb 2025 15:55:33 +0100
Subject: [PATCH] [5.1.x] Fixed #36191 -- Truncated the overwritten file
 content in FileSystemStorage.

Backport of 0d1dd6bba0c18b7feb6caa5cbd8df80fbac54afd from main.
---
 AUTHORS                                 |  1 +
 django/core/files/storage/filesystem.py |  4 ++--
 docs/releases/5.1.7.txt                 |  4 ++++
 tests/file_storage/tests.py             | 12 ++++++++++++
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 0ba20a211b..02b9707cd4 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -361,6 +361,7 @@ answer newbie questions, and generally made Django that much better:
     Fraser Nevett <mail@nevett.org>
     Gabriel Grant <g@briel.ca>
     Gabriel Hurley <gabriel@strikeawe.com>
+    Gaƫl Utard
     gandalf@owca.info
     Garry Lawrence
     Garry Polley <garrympolley@gmail.com>
diff --git a/django/core/files/storage/filesystem.py b/django/core/files/storage/filesystem.py
index bf2b9caad4..1bd9aa0a6c 100644
--- a/django/core/files/storage/filesystem.py
+++ b/django/core/files/storage/filesystem.py
@@ -129,11 +129,11 @@ class FileSystemStorage(Storage, StorageSettingsMixin):
                     )
                     # RemovedInDjango60Warning: when the deprecation ends, replace with:
                     # if self._allow_overwrite:
-                    #     open_flags = open_flags & ~os.O_EXCL
+                    #     open_flags = open_flags & ~os.O_EXCL | os.O_TRUNC
                     if self.OS_OPEN_FLAGS != open_flags:
                         open_flags = self.OS_OPEN_FLAGS
                     elif self._allow_overwrite:
-                        open_flags = open_flags & ~os.O_EXCL
+                        open_flags = open_flags & ~os.O_EXCL | os.O_TRUNC
                     fd = os.open(full_path, open_flags, 0o666)
                     _file = None
                     try:
diff --git a/docs/releases/5.1.7.txt b/docs/releases/5.1.7.txt
index e184da6aca..deda4f2f92 100644
--- a/docs/releases/5.1.7.txt
+++ b/docs/releases/5.1.7.txt
@@ -12,3 +12,7 @@ Bugfixes
 * Fixed a bug in Django 5.1 where the ``{% querystring %}`` template tag
   returned an empty string rather than ``"?"`` when all parameters had been
   removed from the query string (:ticket:`36182`).
+
+* Fixed a bug in Django 5.1 where ``FileSystemStorage``, with
+  ``allow_overwrite`` set to ``True``, did not truncate the overwritten file
+  content (:ticket:`36191`).
diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
index 9b643128d1..7f0a68b0c5 100644
--- a/tests/file_storage/tests.py
+++ b/tests/file_storage/tests.py
@@ -704,6 +704,18 @@ class OverwritingStorageTests(FileStorageTests):
         finally:
             self.storage.delete(name)
 
+    def test_save_overwrite_behavior_truncate(self):
+        name = "test.file"
+        original_content = b"content extra extra extra"
+        new_smaller_content = b"content"
+        self.storage.save(name, ContentFile(original_content))
+        try:
+            self.storage.save(name, ContentFile(new_smaller_content))
+            with self.storage.open(name) as fp:
+                self.assertEqual(fp.read(), new_smaller_content)
+        finally:
+            self.storage.delete(name)
+
     def test_save_overwrite_behavior_temp_file(self):
         """Saving to same file name twice overwrites the first file."""
         name = "test.file"