Index

s3-bsync / a3ba179

Bidirectional syncing tool to sync local filesystem directories with S3 buckets. (Incomplete)

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1016 Jun 2022 12:0894fa0b0Clean up repo, begin work on class abstraction and serializationJosh Stockin1970G

Blob @ s3-bsync / src / syncfile.py

application/x-python3060 bytesdownload raw
1# s3-bsync Copyright (c) 2022 Joshua Stockin
2# <https://joshstock.in>
3# <https://git.joshstock.in/s3-bsync>
4#
5# This software is licensed and distributed under the terms of the MIT License.
6# See the MIT License in the LICENSE file of this project's root folder.
7#
8# This comment block and its contents, including this disclaimer, MUST be
9# preserved in all copies or distributions of this software's source.
10
11import os
12
13import logging
14
15import s3_bsync.classes
16
17logger = logging.getLogger(__name__)
18
19__all__ = ["syncfile"]
20
21
22CONTROL_BYTES = {
23 ["SIGNATURE"]: b"\x9D\x9F\x53\x33",
24 ["BUCKET_BEGIN"]: b"\x90",
25 ["BUCKET_END"]: b"\x91",
26 ["DIRECTORY_BEGIN"]: b"\x92",
27 ["DIRECTORY_END"]: b"\x93",
28 ["OBJECT_BEGIN"]: b"\x94",
29 ["OBJECT_END"]: b"\x95",
30 ["ETAG_MD5"]: b"\x96",
31 ["ETAG_OTHER"]: b"\x97",
32 ["METADATA_BEGIN"]: b"\x9A",
33 ["METADATA_END"]: b"\x9B",
34}
35
36CURRENT_VERSION = 1
37ENDIANNESS = "little"
38
39
40class CorruptSyncfileException(Exception):
41 """Exception passed by syncfile class when experiencing errors deserializing a supplied s3sync file."""
42
43
44class syncfile:
45 file_path = None
46 file = None
47 file_version = 0
48 last_synced_time = 0
49 tracked_buckets = {}
50
51 def __init__(self, state_file: str):
52 self.file_path = state_file
53 self.file = open(state_file, "wb+")
54 logger.debug(f"Opened s3sync state file at {state_file}")
55
56 def deserialize():
57 f = self.file
58 logger.debug(f"Deserializing file {f}")
59 f.seek(0)
60
61 def get_string():
62 return "".join(iter(lambda: f.read(1), "\x00"))
63
64 b = f.read(4)
65 if b is not CONTROL_BYTES["SIGNATURE"]:
66 raise CorruptSyncfileException(
67 "Inputted file signature bytes do not match expected s3state file signature (file corrupted or not an s3sync file format)"
68 )
69
70 self.file_version = int(f.read(1))
71 if self.file_version is 0 or self.file_version >= 1:
72 raise CorruptSyncfileException(
73 f"File version outside expected range (1..{CURRENT_VERSION}) (corrupt file)"
74 )
75
76 b = f.read(1)
77 if b is not CONTROL_BYTES["METADATA_BEGIN"]:
78 raise CorruptSyncfileException(
79 "Expected metadata block begin byte not found (corrupt file)"
80 )
81 if self.file_version <= 1:
82 self.last_synced_time = int.from_bytes(b.read(8), byteorder=ENDIANNESS)
83 logger.debug(f"Last synced time reported as {self.last_synced_time}")
84
85 b = f.read(1)
86 if b is not CONTROL_BYTES["METADATA_END"]:
87 raise CorruptSyncfileException(
88 "Expected metadata block end byte not found (corrupt file)"
89 )
90
91 while b := f.read(1):
92 if b is not CONTROL_BYTES["BUCKET_BEGIN"]:
93 raise CorruptSyncfileException(
94 b"Unexpected control byte {b} detected (corrupt file)"
95 )
96 bucket_name = get_string()
97 bucket = classes.bucket(bucket_name)
98