def test_iterExterior(self): """Tests the iterExterior method.""" atoms = [(0, 2), (4, 2), (8, 2)] ival = Interval.fromAtoms(atoms) self.assertEquals(list(ival.iterExterior()), [(2, 2), (6, 2)]) self.assertEquals(list(ival.iterExterior(10)), [(2, 2), (6, 2)]) self.assertRaises(AssertionError, lambda: list(ival.iterExterior(9))) self.assertEquals(list(ival.iterExterior(11)), [(2, 2), (6, 2), (10, 1)]) self.assertEquals(list(ival.iterExterior(3000)), [(2, 2), (6, 2), (10, 2990)]) # Length identities cmpl = Interval.fromAtoms(ival.iterExterior(50)) self.assertEquals(len(cmpl) + len(ival), 50) self.assertEquals(cmpl.union(ival), Interval.fromAtom(0, 50)) empty = Interval() for length in (0, 1, 2, 5): self.assertEquals(len(Interval.fromAtoms(empty.iterExterior(length))), \ length) ival = Interval.fromAtom(0, 1) for length in (1, 2, 5): self.assertEquals(len(Interval.fromAtoms(ival.iterExterior(length))), \ length - 1)
class File(object): """Holds data on what parts of a file have already been used.""" __metaclass__ = invariant.EnforceInvariant def __init__(self, filename, size, subdir): # Total size of the file self.size = size # Number of bytes in the file that have been used already. self.used = 0 # Relative name of the file. self.filename = filename # Regions of the file in use. self._extents = Interval() # Subdir the file is currently in. self.subdir = subdir def _checkInvariant(self): assert self.size >= self.used assert len(self._extents) == self.used @property def free(self): return self.size - self.used @property def path(self): """Returns the path of the padfile relative to the paddir.""" return (self.subdir, self.filename) def getAllocation(self, requested): """Requests an allocation from the file of the given size. Raises OutOfPad if the file is out of space.""" if requested > self.free: raise OutOfPad("File %s has %i bytes but you requested %i." % \ (self.filename, self.free, requested)) alloc = Allocation() for (start, length) in self._extents.iterExterior(self.size): interval = Interval.fromAtom(start, min(requested - len(alloc), length)) seg = Allocation(self, interval) alloc.unionUpdate(seg) if len(alloc) >= requested: assert len(alloc) == requested break assert len(alloc) == requested return alloc def commitAllocation(self, ival): """Mark the specified interval as used. Error if overlaps with currently used area.""" self._extents = self._extents.union(ival) self.used += len(ival) def consumeEntireFile(self): """Mark the entire file as consumed. Used to prevent its use for encryption while keeping it around for decryption.""" self.used = self.size self._extents = Interval.fromAtom(0, self.size)