pos1 = self.fileobj.tell ()
dpos = pos1 - self.lasthdr
assert dpos == crypto.I2N_HDR_SIZE
- data, hdr = self.encryption.done (dummy)
- self.fileobj.seek_set (self.lasthdr)
- self.__write_to_file(hdr)
self.fileobj.seek_set (pos0)
+ data, hdr = self.encryption.done (dummy)
+ self.__write_to_file(hdr, pos=self.lasthdr)
self.__write_to_file(data) # append remainder of data
self.lasthdr = -1
if self.comptype == "gz":
self._new_gz_block(True)
elif self.encryption is not None:
- pass # XXX
- #self._new_aes_block(True)
+ pass
else:
raise CompressionError("Concat compression only available for comptype 'gz'")
# if aes, we encrypt after compression
if self.encryption is not None:
- #self._new_aes_block(set_last_block_offset)
raise Exception ("XXX sorry, no can do")
elif set_last_block_offset:
self.last_block_offset = self.fileobj.tell()
self.__write(b"\037\213\010\000" + timestamp + b"\002\377")
- # !!! THIS DOES **NOT** HANDLE ACTUAL AES BLOCKS WHICH HAVE A FIXED
- # !!! SIZE OF 16 BYTES
- def _new_aes_block(self, set_last_block_offset=False):
- # TODO do kill this off along with the entirety of aescrypto.py
- # this basically checks if it comes from new_compression_block() call,
- # in which case we have to call to close
- if self.comptype == "tar":
- self.close(close_fileobj=False)
- self.closed = False
-
- if set_last_block_offset: # XXX does this belong before the header or after?
- self.last_block_offset = self.fileobj.tell()
-
- hdr = self.encryption.next (self.name,
- version=DELTATAR_HEADER_VERSION,
- paramversion=self.encver,
- nacl=self.encryption.nacl)
- if hdr is None:
- raise EncryptionError ("Crypto.next(): bad header")
- self.__write_to_file(hdr)
-
def write(self, s):
"""Write string s to the stream.
"""
self.__enc_write(self.buf[:self.bufsize])
self.buf = self.buf[self.bufsize:]
- def __write_to_file(self, s):
+ def __write_to_file(self, s, pos=None):
'''
- Writes directly to the fileobj; updates self.bytes_written
+ Writes directly to the fileobj; updates self.bytes_written. If “pos” is
+ given, the streem will seek to that position first and back afterwards,
+ and the total of bytes written is not updated.
'''
- self.bytes_written += len(s)
+ % (len (s),
+ ("" if pos is None else (" at 0x%x" % pos))))
+ if pos is not None:
+ self.fileobj
+ p0 = self.fileobj.tell ()
+ self.fileobj.seek_set (pos)
self.fileobj.write(s)
+ if pos is None:
+ self.bytes_written += len(s)
+ else:
+ self.fileobj.seek_set (p0)
def __enc_write(self, s):
'''
else:
self.last_block_offset = self.fileobj.tell()
+ # below attributes aren’t present with other compression methods
+ init_e = getattr (self.fileobj, "_init_write_encrypt", None)
+ init_c = getattr (self.fileobj, "_init_write_gz" , None)
+ finalize_e = getattr (self.fileobj, "_finalize_write_encrypt", None)
+ finalize_c = getattr (self.fileobj, "_finalize_write_gz" , None)
+
+ def new_item_hook (): # crypto is outer, compress is inner
+ if init_e is not None: init_e (tarinfo.name)
+ if init_c is not None: init_c ()
+
+ def end_item_hook (): # crypto is outer, compress is inner
+ if finalize_c is not None: finalize_c ()
+ if finalize_e is not None: finalize_e ()
+
+ end_item_hook () # finalize current object
+
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
self.fileobj.write(buf)
self.offset += len(buf)
else:
_size_left = lambda: tarinfo.size
- # below attributes aren’t present with other compression methods
- init_e = getattr (self.fileobj, "_init_write_encrypt", None)
- init_c = getattr (self.fileobj, "_init_write_gz" , None)
- finalize_e = getattr (self.fileobj, "_finalize_write_encrypt", None)
- finalize_c = getattr (self.fileobj, "_finalize_write_gz" , None)
-
- def new_item_hook (): # crypto is outer, compress is inner
- # We cannot finalize symmetrically after encryption because
- # tar(5) mandates a trailer of “two records consisting entirely
- # of zero bytes” which the stream appends as part of the
- # .close() operation.
- if finalize_c is not None: finalize_c ()
- if finalize_e is not None: finalize_e ()
- if init_e is not None: init_e (tarinfo.name)
- if init_c is not None: init_c ()
-
# If there's no data to follow, finish
if not fileobj:
new_item_hook ()
if target_size_left < BLOCKSIZE:
target_size_left = BLOCKSIZE
+ new_item_hook ()
# loop over multiple volumes
while source_size_left > 0:
size_can_write = min(target_size_left, source_size_left)
while size_can_write > 0:
- new_item_hook ()
copyfileobj(fileobj, self.fileobj, size_can_write)
self.offset += size_can_write
source_size_left -= size_can_write
# if there is data left to write, we need to create a new volume
if source_size_left > 0:
+ # Only finalize the crypto entry here if we’re continuing with
+ # another one; otherwise, the encryption must include the block
+ # padding below.
+ end_item_hook ()
tarinfo.type = GNUTYPE_MULTIVOL
self.volume_tarinfo = None
+ new_item_hook ()
+
# write new volume header
buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
self.fileobj.write(buf)