Skip to content

Commit 8e742c7

Browse files
committed
add safeguard for too long path
1 parent e1d97cb commit 8e742c7

3 files changed

Lines changed: 33 additions & 2 deletions

File tree

‎mergin/common.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
# Maximum changes uploading to server
3434
MAX_UPLOAD_CHANGES = 100
3535

36+
# maximum length of a path supported by Windows without long paths enabled (MAX_PATH)
37+
WINDOWS_MAX_PATH = 260
38+
3639
# default URL for submitting logs
3740
MERGIN_DEFAULT_LOGS_URL = "https://g4pfq226j0.execute-api.eu-west-1.amazonaws.com/mergin_client_log_submit"
3841

‎mergin/merginproject.py‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .utils import (
2020
generate_checksum,
2121
is_versioned_file,
22+
is_path_too_long,
2223
int_version,
2324
do_sqlite_checkpoint,
2425
unique_path_name,
@@ -623,8 +624,14 @@ def get_local_delta(self, diff_directory: str) -> List[ProjectDeltaChange]:
623624
delta_item.size = checkpoint_size
624625
delta_item.checksum = checkpoint_checksum
625626

627+
diff_location = self.fpath(diff_file, diff_directory)
628+
if is_path_too_long(diff_location):
629+
raise ClientError(
630+
f"Cannot create changeset for '{path}': diff file path is too long "
631+
f"({len(diff_location)} characters) for this OS: {diff_location}\n"
632+
"Move the project to a directory with a shorter path and try again."
633+
)
626634
try:
627-
diff_location = self.fpath(diff_file, diff_directory)
628635
self.geodiff.create_changeset(origin_file, current_file, diff_location)
629636
if not self.geodiff.has_changes(diff_location):
630637
os.remove(diff_location)
@@ -677,6 +684,12 @@ def get_push_changes(self):
677684
diff_id = str(uuid.uuid4())
678685
diff_name = path + "-diff-" + diff_id
679686
diff_file = self.fpath_meta(diff_name)
687+
if is_path_too_long(diff_file):
688+
raise ClientError(
689+
f"Cannot create changeset for '{path}': diff file path is too long "
690+
f"({len(diff_file)} characters) for this OS: {diff_file}\n"
691+
"Move the project to a directory with a shorter path and try again."
692+
)
680693
try:
681694
self.geodiff.create_changeset(origin_file, current_file, diff_file)
682695
if self.geodiff.has_changes(diff_file):

‎mergin/utils.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import tempfile
1010
from enum import Enum
1111
from typing import Optional, Type, Union, ByteString
12-
from .common import ClientError
12+
from .common import ClientError, WINDOWS_MAX_PATH
1313

1414

1515
def generate_checksum(file, chunk_size=4096):
@@ -266,6 +266,21 @@ def is_versioned_file(path: str) -> bool:
266266
return f_extension.lower() in diff_extensions
267267

268268

269+
def is_path_too_long(path: str) -> bool:
270+
"""
271+
Check whether an absolute path is too long to be reliably created/opened on this OS.
272+
273+
Windows limits paths to WINDOWS_MAX_PATH (260) characters unless long paths have been
274+
explicitly enabled (which we cannot rely on being the case), so we treat that as the limit.
275+
276+
:param path: absolute path to check
277+
:type path: str
278+
:returns: whether the path is likely to be rejected by the OS
279+
:rtype: bool
280+
"""
281+
return os.name == "nt" and len(path) >= WINDOWS_MAX_PATH
282+
283+
269284
def is_qgis_file(path: str) -> bool:
270285
"""
271286
Check if file is a QGIS project file.

0 commit comments

Comments
 (0)