diff --git a/tools/backup.py b/tools/backup.py new file mode 100644 index 0000000..c1e1394 --- /dev/null +++ b/tools/backup.py @@ -0,0 +1,94 @@ +#!/usr/bin/python + +# Copyright 2016 Sam Yaple +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copied and licensed from https://github.com/SamYaple/osdk + + +from hashlib import sha1 +from osdk import osdk +from uuid import uuid4 as uuid + + +def get_disk_size(device): + with open(device, 'rb') as f: + return f.seek(0, 2) + + +def read_segments(f, lst, size, o): + zero_hash = sha1(bytes([0] * size)).hexdigest() + + for segment in lst: + f.seek(segment * size, 0) + data = f.read(size) + if not data: + raise Exception('Failed to read data') + + sha1_hash = sha1(data) + if sha1_hash.hexdigest() != zero_hash: + meta = dict() + meta['incremental'] = o.metadata['incremental'] + meta['base'] = len(o.metadata['bases']) - 1 + meta['encryption'] = 0 + meta['compression'] = 0 + meta['sha1_hash'] = sha1_hash.digest() + o.segments[segment] = meta + else: + try: + del o.segments[segment] + except KeyError: + pass + + +def main(): + device = '/dev/loop0' + old_manifest = 'manifest0.osdk' + manifest = 'manifest0.osdk' + manifest = 'manifest1.osdk' + segment_size = 4 * 1024**2 # 4MiB + size_of_disk = get_disk_size(device) + num_of_sectors = int(size_of_disk / 512) + num_of_segments = int(size_of_disk / segment_size) + + o = osdk(manifest) + o.metadata['sectors'] = num_of_sectors + + new = True + new = False + existing = True + existing_full = True + existing_full = False + + if new: + o.metadata['incremental'] = 0 + o.metadata['segment_size'] = segment_size + o.metadata['bases'] = [uuid().bytes] + segments_to_read = range(0, num_of_segments - 1) + elif existing: + o.read_manifest(old_manifest) + o.metadata['incremental'] += 1 + segments_to_read = range(1, num_of_segments - 1) + elif existing_full: + o.read_manifest(old_manifest) + o.metadata['incremental'] += 1 + segments_to_read = range(0, num_of_segments - 1) + + with open(device, 'rb+') as f: + read_segments(f, segments_to_read, segment_size, o) + + o.write_manifest() + +if __name__ == '__main__': + main() diff --git a/tools/osdk.py b/tools/osdk.py new file mode 100644 index 0000000..eaf7b9e --- /dev/null +++ b/tools/osdk.py @@ -0,0 +1,184 @@ +#!/usr/bin/python + +# Copyright 2016 Sam Yaple +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copied and licensed from https://github.com/SamYaple/osdk + + +from binascii import b2a_hex +from binascii import crc32 +from datetime import datetime +from struct import pack +from struct import unpack +from uuid import UUID + + +class osdk(object): + + def __init__(self, manifest): + self.manifest = manifest + self.segments = dict() + self.metadata = dict() + self.metadata['signature'] = \ + UUID('d326503ab5ca49adac56c89eb0b8ef08').bytes + self.metadata['version'] = 0 + + def write_manifest(self): + with open(self.manifest, 'wb') as f: + self.write_header(f) + self.write_body(f) + + def build_header(self): + timestamp = utctimestamp() + padding = str.encode('\0\0' * 14) + + data = pack( + ' 0: + break + + return str(size) + sizes[i] + + +def print_header(o): + formated_out = """Version:\t%(version)s +Creation Date:\t%(timestamp)s +Incremental:\t%(incremental)s +Volume Size:\t%(volume_size)s +Segment Size:\t%(segment_size)s +Backup Set:\t%(backup_set)s""" + + dict_out = dict() + dict_out['backup_set'] = UUID(bytes=o.metadata['bases'][-1]) + dict_out['version'] = o.metadata['version'] + dict_out['incremental'] = o.metadata['incremental'] + dict_out['timestamp'] = get_timestamp(o) + dict_out['volume_size'] = convert_size(o.metadata['sectors'] * 512) + dict_out['segment_size'] = convert_size(o.metadata['segment_size']) + + print(formated_out % dict_out) + + +def main(): + manifest = 'manifest1.osdk' + o = osdk(manifest) + o.read_manifest() + + print_header(o) + +if __name__ == '__main__': + main()