Merge pull request #36589 from safwansamsudeen/duplicate-save-file

fix: only duplicate file on disk if required
This commit is contained in:
Suraj Shetty 2026-02-03 14:01:41 +05:30 committed by GitHub
commit c935cf6cdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 6 deletions

View file

@ -738,6 +738,7 @@ class File(Document):
name=self.file_name,
suffix=self.content_hash[-6:],
is_private=self.is_private,
content_hash=self.content_hash,
)
call_hook_method("before_write_file", file_size=self.file_size)
write_file_method = get_hook_method("write_file")

View file

@ -172,7 +172,12 @@ def delete_file(path: str) -> None:
def remove_file_by_url(file_url: str, doctype: str | None = None, name: str | None = None) -> "Document":
if doctype and name:
fid = frappe.db.get_value(
"File", {"file_url": file_url, "attached_to_doctype": doctype, "attached_to_name": name}
"File",
{
"file_url": file_url,
"attached_to_doctype": doctype,
"attached_to_name": name,
},
)
else:
fid = frappe.db.get_value("File", {"file_url": file_url})
@ -189,20 +194,28 @@ def get_content_hash(content: bytes | str) -> str:
return hashlib.md5(content, usedforsecurity=False).hexdigest() # nosec
def generate_file_name(name: str, suffix: str | None = None, is_private: bool = False) -> str:
def generate_file_name(
name: str, suffix: str | None = None, is_private: bool = False, content_hash=None
) -> str:
"""Generate conflict-free file name. Suffix will be ignored if name available. If the
provided suffix doesn't result in an available path, a random suffix will be picked.
"""
def path_exists(name, is_private):
return os.path.exists(encode(get_files_path(name, is_private=is_private)))
def different_file_exists_at_path(name, is_private):
path = encode(get_files_path(name, is_private=is_private))
if not os.path.exists(path):
return False
if content_hash:
with open(path, "rb") as f:
return get_content_hash(f.read()) != content_hash
return True
if not path_exists(name, is_private):
if not different_file_exists_at_path(name, is_private):
return name
candidate_path = get_file_name(name, suffix)
if path_exists(candidate_path, is_private):
if different_file_exists_at_path(candidate_path, is_private):
return generate_file_name(name, is_private=is_private)
return candidate_path