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)
Esempio n. 2
0
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)