Просмотр исходного кода

make sure all segment file offsets fit into uint32, fixes #3592

C code and the repo index use uint32 type for segment file offsets,
so when opening a repo and the config max_segment_size is too big,
fail early.

Also disallow setting a too big value via "borg config".
Thomas Waldmann 7 лет назад
Родитель
Сommit
0e0e6da585
3 измененных файлов с 12 добавлено и 0 удалено
  1. 3 0
      src/borg/archiver.py
  2. 3 0
      src/borg/constants.py
  3. 6 0
      src/borg/repository.py

+ 3 - 0
src/borg/archiver.py

@@ -1533,6 +1533,9 @@ class Archiver:
                         int(value)
                         int(value)
                     except ValueError:
                     except ValueError:
                         raise ValueError('Invalid value') from None
                         raise ValueError('Invalid value') from None
+                    if name == 'max_segment_size':
+                        if int(value) >= MAX_SEGMENT_SIZE_LIMIT:
+                            raise ValueError('Invalid value: max_segment_size >= %d' % MAX_SEGMENT_SIZE_LIMIT)
             elif name in ['additional_free_space', ]:
             elif name in ['additional_free_space', ]:
                 if check_value:
                 if check_value:
                     try:
                     try:

+ 3 - 0
src/borg/constants.py

@@ -36,6 +36,9 @@ MAX_DATA_SIZE = 20971479
 MAX_OBJECT_SIZE = MAX_DATA_SIZE + 41  # see LoggedIO.put_header_fmt.size assertion in repository module
 MAX_OBJECT_SIZE = MAX_DATA_SIZE + 41  # see LoggedIO.put_header_fmt.size assertion in repository module
 assert MAX_OBJECT_SIZE == 20 * 1024 * 1024
 assert MAX_OBJECT_SIZE == 20 * 1024 * 1024
 
 
+# repo config max_segment_size value must be below this limit to stay within uint32 offsets:
+MAX_SEGMENT_SIZE_LIMIT = 2 ** 32 - MAX_OBJECT_SIZE
+
 # borg.remote read() buffer size
 # borg.remote read() buffer size
 BUFSIZE = 10 * 1024 * 1024
 BUFSIZE = 10 * 1024 * 1024
 
 

+ 6 - 0
src/borg/repository.py

@@ -122,6 +122,9 @@ class Repository:
     class InvalidRepository(Error):
     class InvalidRepository(Error):
         """{} is not a valid repository. Check repo config."""
         """{} is not a valid repository. Check repo config."""
 
 
+    class InvalidRepositoryConfig(Error):
+        """{} does not have a valid configuration. Check repo config [{}]."""
+
     class AtticRepository(Error):
     class AtticRepository(Error):
         """Attic repository detected. Please run "borg upgrade {}"."""
         """Attic repository detected. Please run "borg upgrade {}"."""
 
 
@@ -383,6 +386,9 @@ class Repository:
             self.close()
             self.close()
             raise self.InvalidRepository(path)
             raise self.InvalidRepository(path)
         self.max_segment_size = self.config.getint('repository', 'max_segment_size')
         self.max_segment_size = self.config.getint('repository', 'max_segment_size')
+        if self.max_segment_size >= MAX_SEGMENT_SIZE_LIMIT:
+            self.close()
+            raise self.InvalidRepositoryConfig(path, 'max_segment_size >= %d' % MAX_SEGMENT_SIZE_LIMIT)  # issue 3592
         self.segments_per_dir = self.config.getint('repository', 'segments_per_dir')
         self.segments_per_dir = self.config.getint('repository', 'segments_per_dir')
         self.additional_free_space = parse_file_size(self.config.get('repository', 'additional_free_space', fallback=0))
         self.additional_free_space = parse_file_size(self.config.get('repository', 'additional_free_space', fallback=0))
         # append_only can be set in the constructor
         # append_only can be set in the constructor