Logo Search packages:      
Sourcecode: partitionmanager version File versions  Download package

bool PartitionTable::snap ( const Device d,
Partition p,
const Partition originalPartition = NULL 
) [static]

Snaps the given Partition on the given Device to cylinder boundaries.

Tries under all accounts to keep the Partition's length equal to the original length or to increase it, if that is not possible. Will print a warning message to GlobalLog if this is not possible.

The parameter originalPartition is required for cases where a Partition has just been duplicated to resize or move it. This method needs to know the original because of course the original does not prevent snapping to any sector allocated by it.

See also:
canSnapToSector(), isSnapped()
Parameters:
d the Device the Partition is on
p the Partition to snap
originalPartition pointer to a Partition object p has just been copied from or NULL
Returns:
true if Partition is now snapped to cylinder boundaries

Todo:
Don't assume we always want to snap to the front. Always trying to snap to the front solves the problem that a partition does get too small to take another one that's copied to it, but it introduces a new bug: The user might create a partition aligned at the end of a device, extended partition or at the start of the next one, but we snap to the back and leave some space in between.

Definition at line 304 of file partitiontable.cpp.

References canSnapToSector(), Partition::capacity(), Partition::children(), Device::cylinderSize(), PartitionRole::Extended, Partition::fileSystem(), FileSystem::firstSector(), Partition::firstSector(), PartitionRole::has(), isSnapped(), FileSystem::lastSector(), Partition::lastSector(), Partition::length(), PartitionRole::Logical, FileSystem::maxCapacity(), Partition::roles(), Device::sectorsPerTrack(), FileSystem::setFirstSector(), Partition::setFirstSector(), FileSystem::setLastSector(), Partition::setLastSector(), and PartitionRole::Unallocated.

{
      const qint64 originalLength = p.length();
      qint64 delta = 0;
      bool lengthIsSnapped = false;

      // This is the same as in isSnapped(), only we additionally have to remember if the
      // partition's _length_ is "snapped", so to speak (i.e., evenly divisable by
      // the cylinder size)
      if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
      {
            delta = (p.firstSector() - (2 * d.sectorsPerTrack())) % d.cylinderSize();
            lengthIsSnapped = (p.length() + (2 * d.sectorsPerTrack())) % d.cylinderSize() == 0;
      }
      else if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
      {
            delta = (p.firstSector() - d.sectorsPerTrack()) % d.cylinderSize();
            lengthIsSnapped = (p.length() + d.sectorsPerTrack()) % d.cylinderSize() == 0;
      }
      else
      {
            delta = p.firstSector() % d.cylinderSize();
            lengthIsSnapped = p.length() % d.cylinderSize() == 0;
      }

      if (delta)
      {
            /** @todo Don't assume we always want to snap to the front.
                  Always trying to snap to the front solves the problem that a partition does
                  get too small to take another one that's copied to it, but it introduces
                  a new bug: The user might create a partition aligned at the end of a device,
                  extended partition or at the start of the next one, but we snap to the back
                  and leave some space in between.
            */
            // We always want to make the partition larger, not smaller. Making it smaller
            // might, in case it's a partition that another is being copied to, mean the partition
            // ends up too small. So try to move the start to the front first.
            qint64 snappedFirst = p.firstSector() - delta;

            // Now if the cylinder boundary at the front is occupied...
            if (!canSnapToSector(d, p, p.firstSector() - delta, originalPartition))
            {
                  // ... move to the cylinder towards the end of the device ...
                  snappedFirst += d.cylinderSize();

                  // ... and move the end of the partition towards the end, too, if that is possible.
                  // By doing this, we still try to keep the length >= the original length. If the
                  // last sector ends up not being on a cylinder boundary by doing so, the code
                  // below will deal with that.
                  qint64 numTooShort = d.cylinderSize() - delta;
                  if (canSnapToSector(d, p, p.lastSector() + numTooShort, originalPartition))
                  {
                        p.setLastSector(p.lastSector() + numTooShort);
                        p.fileSystem().setLastSector(p.fileSystem().lastSector() + numTooShort);
                  }
            }

            p.setFirstSector(snappedFirst);
            p.fileSystem().setFirstSector(snappedFirst);
      }

      delta = (p.lastSector() + 1) % d.cylinderSize();

      if (delta)
      {
            // Try to snap to the back first...
            qint64 snappedLast = p.lastSector() + d.cylinderSize() - delta;

            // .. but if we can retain the partition length exactly by snapping to the front ...
            if (lengthIsSnapped && p.length() - originalLength == delta)
                  snappedLast -= d.cylinderSize();
            // ... or if there's something there already, snap to the front.
            else if (!canSnapToSector(d, p, snappedLast, originalPartition))
                  snappedLast -= d.cylinderSize();

            p.setLastSector(snappedLast);
            p.fileSystem().setLastSector(snappedLast);
      }

      // Now, did we make the partition too big for its file system?
      while (p.length() > originalLength && p.capacity() > p.fileSystem().maxCapacity() && canSnapToSector(d, p, p.lastSector() - d.cylinderSize(), originalPartition))
      {
            p.setLastSector(p.lastSector() - d.cylinderSize());
            p.fileSystem().setLastSector(p.fileSystem().lastSector() - d.cylinderSize());
      }

      if (p.length() < originalLength)
            log(log::warning) <<  i18ncp("@info/plain", "The partition cannot be created with the requested length of 1 sector, ", "The partition cannot be created with the requested length of %1 sectors, ", originalLength)
                                    + i18ncp("@info/plain", "and will instead only be 1 sector long.", "and will instead only be %1 sectors long.", p.length());

      // In an extended partition we also need to snap unallocated children at the beginning and at the end
      // (there should never be a need to snap non-unallocated children)
      if (p.roles().has(PartitionRole::Extended))
      {
            if (p.children().size() > 0)
            {
                  if (p.children().first()->roles().has(PartitionRole::Unallocated))
                  {
                        p.children().first()->setFirstSector(p.firstSector() + d.sectorsPerTrack());
                        p.children().first()->fileSystem().setFirstSector(p.fileSystem().firstSector() + d.sectorsPerTrack());
                  }

                  if (p.children().last()->roles().has(PartitionRole::Unallocated))
                  {
                        p.children().last()->setLastSector(p.lastSector());
                        p.children().last()->fileSystem().setLastSector(p.fileSystem().lastSector());
                  }
            }
      }

      return isSnapped(d, p);
}


Generated by  Doxygen 1.6.0   Back to index