add new class PartitionAlignment and move all alignment related stuff there
svn path=/trunk/extragear/sysadmin/partitionmanager/; revision=1114380
This commit is contained in:
parent
17809b5107
commit
9426e3afec
|
@ -33,6 +33,7 @@
|
|||
class Device;
|
||||
class OperationStack;
|
||||
class CoreBackendPartitionTable;
|
||||
class PartitionAlignment;
|
||||
|
||||
class PartResizerWidget;
|
||||
class InsertDialog;
|
||||
|
@ -76,6 +77,7 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT Partition : public PartitionNode
|
|||
friend class Device;
|
||||
friend class PartitionNode;
|
||||
friend class CoreBackendPartitionTable;
|
||||
friend class PartitionAlignment;
|
||||
|
||||
friend class PartResizerWidget;
|
||||
friend class InsertDialog;
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "core/partitionalignment.h"
|
||||
|
||||
#include "core/partition.h"
|
||||
#include "core/partitiontable.h"
|
||||
#include "core/device.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
|
||||
#include "util/globallog.h"
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <config.h>
|
||||
|
||||
PartitionAlignment::PartitionAlignment(const Device& d, const Partition& p, const Partition* op) :
|
||||
m_FirstDelta(0),
|
||||
m_LastDelta(0),
|
||||
m_LengthAligned(false),
|
||||
m_OriginalPartition(op),
|
||||
m_OriginalLength(0)
|
||||
{
|
||||
if (d.partitionTable()->type() == PartitionTable::msdos)
|
||||
{
|
||||
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
|
||||
{
|
||||
m_FirstDelta = (p.firstSector() - (2 * d.sectorsPerTrack())) % sectorAlignment(d);
|
||||
m_LengthAligned = (p.length() + (2 * d.sectorsPerTrack())) % sectorAlignment(d) == 0;
|
||||
}
|
||||
else if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
|
||||
{
|
||||
m_FirstDelta = (p.firstSector() - d.sectorsPerTrack()) % sectorAlignment(d);
|
||||
m_LengthAligned = (p.length() + d.sectorsPerTrack()) % sectorAlignment(d) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FirstDelta = p.firstSector() % sectorAlignment(d);
|
||||
m_LengthAligned = p.length() % sectorAlignment(d) == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FirstDelta = p.firstSector() % sectorAlignment(d);
|
||||
m_LengthAligned = p.length() % sectorAlignment(d) == 0;
|
||||
}
|
||||
|
||||
m_LastDelta = (p.lastSector() + 1) % sectorAlignment(d);
|
||||
}
|
||||
|
||||
/** Aligns the given Partition on the given Device to the PartitionTable's required alignment.
|
||||
|
||||
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 @p 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 aligning to any sector allocated by it.
|
||||
|
||||
@see canAlignToSector(), isAligned()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to align
|
||||
@param originalPartition pointer to a Partition object @p p has just been copied from or NULL
|
||||
@return true if Partition is now properly aligned
|
||||
*/
|
||||
bool PartitionAlignment::alignPartition(const Device& d, Partition& p, const Partition* originalPartition)
|
||||
{
|
||||
PartitionAlignment pa(d, p, originalPartition);
|
||||
|
||||
pa.alignFirstSector(d, p);
|
||||
pa.alignLastSector(d, p);
|
||||
pa.checkAlignConstraints(d, p);
|
||||
pa.alignChildren(d, p);
|
||||
|
||||
return pa.isAligned(d, p);
|
||||
}
|
||||
|
||||
|
||||
/** Checks if a given Partition on a given Device is properly aligned to the PartitionTable's
|
||||
alignment requirements.
|
||||
|
||||
Will print warning messages to GlobalLog if the Partition's first sector is not aligned and
|
||||
another one if the last sector is not aligned.
|
||||
|
||||
@see alignPartition(), canAlignToSector()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to check
|
||||
@return true if propertly aligned
|
||||
*/
|
||||
bool PartitionAlignment::isAligned(const Device& d, const Partition& p)
|
||||
{
|
||||
// don't bother with unallocated space here.
|
||||
if (p.roles().has(PartitionRole::Unallocated))
|
||||
return true;
|
||||
|
||||
qint64 delta = 0;
|
||||
|
||||
if (d.partitionTable()->type() == PartitionTable::msdos)
|
||||
{
|
||||
// TODO: verify the following comment and code
|
||||
// There are some special cases for aligning partitions:
|
||||
// 1) If an extended partition starts at the beginning of the device (that would be sector 63
|
||||
// on modern drives, equivalent to sectorsPerTrack() in any case), the first logical partition
|
||||
// at the beginning of this extended partition starts at 2 * sectorsPerTrack().
|
||||
// 2) If a primary or extended starts at the beginning of a device, it starts at sectorsPerTrack().
|
||||
// 3) Any logical partition is always preceded by the extended partition table entry in the
|
||||
// sectorsPerTrack() before it, so it's always sectorsPerTrack() "late"
|
||||
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
|
||||
delta = (p.firstSector() - (2 * d.sectorsPerTrack())) % sectorAlignment(d);
|
||||
else if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
|
||||
delta = (p.firstSector() - d.sectorsPerTrack()) % sectorAlignment(d);
|
||||
else
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
}
|
||||
else
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
|
||||
bool rval = true;
|
||||
|
||||
if (delta)
|
||||
{
|
||||
Log(Log::warning) << i18nc("@info/plain", "Partition <filename>%1</filename> is not properly aligned (first sector: %2, modulo: %3).", p.deviceNode(), p.firstSector(), delta);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
delta = (p.lastSector() + 1) % sectorAlignment(d);
|
||||
|
||||
if (delta)
|
||||
{
|
||||
Log(Log::warning) << i18nc("@info/plain", "Partition <filename>%1</filename> is not properly aligned (last sector: %2, modulo: %3).", p.deviceNode(), p.lastSector(), delta);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
/** @return the sector size to align the partition start and end to
|
||||
*/
|
||||
qint64 PartitionAlignment::sectorAlignment(const Device& d)
|
||||
{
|
||||
return d.partitionTable()->type() == PartitionTable::msdos ? d.cylinderSize() : Config::sectorAlignment();
|
||||
}
|
||||
|
||||
bool PartitionAlignment::alignFirstSector(const Device& d, Partition& p)
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
if (firstDelta())
|
||||
{
|
||||
/** @todo Don't assume we always want to align to the front.
|
||||
Always trying to align 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 align 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 alignedFirst = p.firstSector() - firstDelta();
|
||||
|
||||
// If we're now before the first usable sector, just take the first usable sector. This
|
||||
// will happen if we're already below cylinder one and align to the front
|
||||
if (alignedFirst < d.partitionTable()->firstUsable())
|
||||
alignedFirst = d.partitionTable()->firstUsable();
|
||||
|
||||
// Now if the cylinder boundary at the front is occupied...
|
||||
if (!canAlignToSector(d, p, alignedFirst))
|
||||
{
|
||||
// ... move to the cylinder towards the end of the device ...
|
||||
alignedFirst = p.firstSector() - firstDelta() + sectorAlignment(d);
|
||||
|
||||
// ... 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 = sectorAlignment(d) - firstDelta();
|
||||
if (canAlignToSector(d, p, p.lastSector() + numTooShort))
|
||||
{
|
||||
p.setLastSector(p.lastSector() + numTooShort);
|
||||
p.fileSystem().setLastSector(p.fileSystem().lastSector() + numTooShort);
|
||||
}
|
||||
}
|
||||
|
||||
rval = alignedFirst != p.firstSector();
|
||||
|
||||
p.setFirstSector(alignedFirst);
|
||||
p.fileSystem().setFirstSector(alignedFirst);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool PartitionAlignment::alignLastSector(const Device& d, Partition& p)
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
if (lastDelta())
|
||||
{
|
||||
// Try to align to the back first...
|
||||
qint64 alignedLast = p.lastSector() + sectorAlignment(d) - lastDelta();
|
||||
|
||||
// .. but if we can retain the partition length exactly by aligning to the front ...
|
||||
if (isLengthAligned() && p.length() - originalLength() == lastDelta())
|
||||
alignedLast -= sectorAlignment(d);
|
||||
// ... or if there's something there already, align to the front.
|
||||
else if (!canAlignToSector(d, p, alignedLast))
|
||||
alignedLast -= sectorAlignment(d);
|
||||
|
||||
rval = alignedLast != p.lastSector();
|
||||
p.setLastSector(alignedLast);
|
||||
p.fileSystem().setLastSector(alignedLast);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool PartitionAlignment::checkAlignConstraints(const Device& d, Partition& p)
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
// Now, did we make the partition too big for its file system?
|
||||
while (p.length() > originalLength() && p.capacity() > p.fileSystem().maxCapacity() && canAlignToSector(d, p, p.lastSector() - sectorAlignment(d)))
|
||||
{
|
||||
rval = true;
|
||||
p.setLastSector(p.lastSector() - sectorAlignment(d));
|
||||
p.fileSystem().setLastSector(p.fileSystem().lastSector() - sectorAlignment(d));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool PartitionAlignment::alignChildren(const Device& d, Partition& p)
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
// In an extended partition we also need to align unallocated children at the beginning and at the end
|
||||
// (there should never be a need to align non-unallocated children)
|
||||
if (p.roles().has(PartitionRole::Extended))
|
||||
{
|
||||
if (p.children().size() > 0)
|
||||
{
|
||||
if (p.children().first()->roles().has(PartitionRole::Unallocated))
|
||||
{
|
||||
rval = true;
|
||||
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))
|
||||
{
|
||||
rval = true;
|
||||
p.children().last()->setLastSector(p.lastSector());
|
||||
p.children().last()->fileSystem().setLastSector(p.fileSystem().lastSector());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/** Checks if a Partition can be aligned to a given sector on a given Device.
|
||||
|
||||
@see PartitionTable::alignPartition(), PartitionTable::isAligned()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to align
|
||||
@param s the sector to align to
|
||||
@return true if aligning to @p s is possible
|
||||
*/
|
||||
bool PartitionAlignment::canAlignToSector(const Device& d, const Partition& p, qint64 s) const
|
||||
{
|
||||
Q_ASSERT(d.partitionTable());
|
||||
|
||||
if (s < d.partitionTable()->firstUsable() || s >= d.partitionTable()->lastUsable())
|
||||
return false;
|
||||
|
||||
const Partition* other = d.partitionTable()->findPartitionBySector(s, PartitionRole(PartitionRole::Any));
|
||||
|
||||
if (other && other->roles().has(PartitionRole::Unallocated) &&
|
||||
((p.roles().has(PartitionRole::Logical) && other->roles().has(PartitionRole::Logical)) ||
|
||||
(p.roles().has(PartitionRole::Primary) && other->roles().has(PartitionRole::Primary))))
|
||||
other = NULL;
|
||||
|
||||
return other == NULL || other == &p || other == originalPartition();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#if !defined(PARTITIONALIGNMENT__H)
|
||||
|
||||
#define PARTITIONALIGNMENT__H
|
||||
|
||||
#include "qglobal.h"
|
||||
|
||||
#include "util/libpartitionmanagerexport.h"
|
||||
|
||||
class Device;
|
||||
class Partition;
|
||||
|
||||
class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionAlignment
|
||||
{
|
||||
public:
|
||||
PartitionAlignment(const Device& d, const Partition& p, const Partition* op = NULL);
|
||||
|
||||
public:
|
||||
bool alignFirstSector(const Device& d, Partition& p);
|
||||
bool alignLastSector(const Device& d, Partition& p);
|
||||
bool checkAlignConstraints(const Device& d, Partition& p);
|
||||
bool alignChildren(const Device& d, Partition& p);
|
||||
bool canAlignToSector(const Device& d, const Partition& p, qint64 s) const;
|
||||
|
||||
static qint64 sectorAlignment(const Device& d);
|
||||
static bool isAligned(const Device& d, const Partition& p);
|
||||
static bool alignPartition(const Device& d, Partition& p, const Partition* originalPartition = NULL);
|
||||
|
||||
qint64 firstDelta() const { return m_FirstDelta; }
|
||||
qint64 lastDelta() const { return m_LastDelta; }
|
||||
bool isLengthAligned() const { return m_LengthAligned; }
|
||||
const Partition* originalPartition() const { return m_OriginalPartition; }
|
||||
qint64 originalLength() const { return m_OriginalLength; }
|
||||
|
||||
private:
|
||||
qint64 m_FirstDelta;
|
||||
qint64 m_LastDelta;
|
||||
bool m_LengthAligned;
|
||||
const Partition* m_OriginalPartition;
|
||||
qint64 m_OriginalLength;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@
|
|||
#include "core/partitiontable.h"
|
||||
#include "core/partition.h"
|
||||
#include "core/device.h"
|
||||
#include "core/partitionalignment.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
#include "fs/filesystemfactory.h"
|
||||
|
@ -210,238 +211,6 @@ QStringList PartitionTable::flagNames(Flags flags)
|
|||
return rval;
|
||||
}
|
||||
|
||||
/** @return the sector size to align the partition start and end to
|
||||
*/
|
||||
qint64 PartitionTable::sectorAlignment(const Device& d)
|
||||
{
|
||||
return d.partitionTable()->type() == PartitionTable::msdos ? d.cylinderSize() : Config::sectorAlignment();
|
||||
}
|
||||
|
||||
/** Checks if a given Partition on a given Device is properly aligned to the PartitionTable's
|
||||
alignment requirements.
|
||||
|
||||
Will print warning messages to GlobalLog if the Partition's first sector is not aligned and
|
||||
another one if the last sector is not aligned.
|
||||
|
||||
@see alignPartition(), canAlignToSector()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to check
|
||||
@return true if propertly aligned
|
||||
*/
|
||||
bool PartitionTable::isAligned(const Device& d, const Partition& p)
|
||||
{
|
||||
// don't bother with unallocated space here.
|
||||
if (p.roles().has(PartitionRole::Unallocated))
|
||||
return true;
|
||||
|
||||
qint64 delta = 0;
|
||||
|
||||
if (d.partitionTable()->type() == msdos)
|
||||
{
|
||||
// TODO: verify the following comment and code
|
||||
// There are some special cases for aligning partitions:
|
||||
// 1) If an extended partition starts at the beginning of the device (that would be sector 63
|
||||
// on modern drives, equivalent to sectorsPerTrack() in any case), the first logical partition
|
||||
// at the beginning of this extended partition starts at 2 * sectorsPerTrack().
|
||||
// 2) If a primary or extended starts at the beginning of a device, it starts at sectorsPerTrack().
|
||||
// 3) Any logical partition is always preceded by the extended partition table entry in the
|
||||
// sectorsPerTrack() before it, so it's always sectorsPerTrack() "late"
|
||||
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
|
||||
delta = (p.firstSector() - (2 * d.sectorsPerTrack())) % sectorAlignment(d);
|
||||
else if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
|
||||
delta = (p.firstSector() - d.sectorsPerTrack()) % sectorAlignment(d);
|
||||
else
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
}
|
||||
else
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
|
||||
bool rval = true;
|
||||
|
||||
if (delta)
|
||||
{
|
||||
Log(Log::warning) << i18nc("@info/plain", "Partition <filename>%1</filename> is not properly aligned (first sector: %2, modulo: %3).", p.deviceNode(), p.firstSector(), delta);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
delta = (p.lastSector() + 1) % sectorAlignment(d);
|
||||
|
||||
if (delta)
|
||||
{
|
||||
Log(Log::warning) << i18nc("@info/plain", "Partition <filename>%1</filename> is not properly aligned (last sector: %2, modulo: %3).", p.deviceNode(), p.lastSector(), delta);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/** Checks if a Partition can be aligned to a given sector on a given Device.
|
||||
|
||||
@see PartitionTable::alignPartition(), PartitionTable::isAligned()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to align
|
||||
@param s the sector to align to
|
||||
@param originalPartition pointer to another Partition @p p has just been copied from or NULL
|
||||
@return true if aligning to @p s is possible
|
||||
*/
|
||||
static bool canAlignToSector(const Device& d, const Partition& p, qint64 s, const Partition* originalPartition)
|
||||
{
|
||||
Q_ASSERT(d.partitionTable());
|
||||
|
||||
if (s < d.partitionTable()->firstUsable() || s >= d.partitionTable()->lastUsable())
|
||||
return false;
|
||||
|
||||
const Partition* other = d.partitionTable()->findPartitionBySector(s, PartitionRole(PartitionRole::Any));
|
||||
|
||||
if (other && other->roles().has(PartitionRole::Unallocated) &&
|
||||
((p.roles().has(PartitionRole::Logical) && other->roles().has(PartitionRole::Logical)) ||
|
||||
(p.roles().has(PartitionRole::Primary) && other->roles().has(PartitionRole::Primary))))
|
||||
other = NULL;
|
||||
|
||||
return other == NULL || other == &p || other == originalPartition;
|
||||
}
|
||||
|
||||
/** Aligns the given Partition on the given Device to the PartitionTable's required alignment.
|
||||
|
||||
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 @p 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 aligning to any sector allocated by it.
|
||||
|
||||
@see canAlignToSector(), isAligned()
|
||||
|
||||
@param d the Device the Partition is on
|
||||
@param p the Partition to align
|
||||
@param originalPartition pointer to a Partition object @p p has just been copied from or NULL
|
||||
@return true if Partition is now aligned to cylinder boundaries
|
||||
*/
|
||||
bool PartitionTable::alignPartition(const Device& d, Partition& p, const Partition* originalPartition)
|
||||
{
|
||||
const qint64 originalLength = p.length();
|
||||
qint64 delta = 0;
|
||||
bool lengthIsAligned = false;
|
||||
|
||||
// This is the same as in isAligned(), only we additionally have to remember if the
|
||||
// partition's _length_ is "aligned", so to speak (i.e., evenly divisable by
|
||||
// the sectorAlignment()
|
||||
if (d.partitionTable()->type() == msdos)
|
||||
{
|
||||
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
|
||||
{
|
||||
delta = (p.firstSector() - (2 * d.sectorsPerTrack())) % sectorAlignment(d);
|
||||
lengthIsAligned = (p.length() + (2 * d.sectorsPerTrack())) % sectorAlignment(d) == 0;
|
||||
}
|
||||
else if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
|
||||
{
|
||||
delta = (p.firstSector() - d.sectorsPerTrack()) % sectorAlignment(d);
|
||||
lengthIsAligned = (p.length() + d.sectorsPerTrack()) % sectorAlignment(d) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
lengthIsAligned = p.length() % sectorAlignment(d) == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = p.firstSector() % sectorAlignment(d);
|
||||
lengthIsAligned = p.length() % sectorAlignment(d) == 0;
|
||||
}
|
||||
|
||||
if (delta)
|
||||
{
|
||||
/** @todo Don't assume we always want to align to the front.
|
||||
Always trying to align 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 align 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 alignedFirst = p.firstSector() - delta;
|
||||
|
||||
// If we're now before the first usable sector, just take the first usable sector. This
|
||||
// will happen if we're already below cylinder one and align to the front
|
||||
if (alignedFirst < d.partitionTable()->firstUsable())
|
||||
alignedFirst = d.partitionTable()->firstUsable();
|
||||
|
||||
// Now if the cylinder boundary at the front is occupied...
|
||||
if (!canAlignToSector(d, p, alignedFirst, originalPartition))
|
||||
{
|
||||
// ... move to the cylinder towards the end of the device ...
|
||||
alignedFirst = p.firstSector() - delta + sectorAlignment(d);
|
||||
|
||||
// ... 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 = sectorAlignment(d) - delta;
|
||||
if (canAlignToSector(d, p, p.lastSector() + numTooShort, originalPartition))
|
||||
{
|
||||
p.setLastSector(p.lastSector() + numTooShort);
|
||||
p.fileSystem().setLastSector(p.fileSystem().lastSector() + numTooShort);
|
||||
}
|
||||
}
|
||||
|
||||
p.setFirstSector(alignedFirst);
|
||||
p.fileSystem().setFirstSector(alignedFirst);
|
||||
}
|
||||
|
||||
delta = (p.lastSector() + 1) % sectorAlignment(d);
|
||||
|
||||
if (delta)
|
||||
{
|
||||
// Try to align to the back first...
|
||||
qint64 alignedLast = p.lastSector() + sectorAlignment(d) - delta;
|
||||
|
||||
// .. but if we can retain the partition length exactly by aligning to the front ...
|
||||
if (lengthIsAligned && p.length() - originalLength == delta)
|
||||
alignedLast -= sectorAlignment(d);
|
||||
// ... or if there's something there already, align to the front.
|
||||
else if (!canAlignToSector(d, p, alignedLast, originalPartition))
|
||||
alignedLast -= sectorAlignment(d);
|
||||
|
||||
p.setLastSector(alignedLast);
|
||||
p.fileSystem().setLastSector(alignedLast);
|
||||
}
|
||||
|
||||
// Now, did we make the partition too big for its file system?
|
||||
while (p.length() > originalLength && p.capacity() > p.fileSystem().maxCapacity() && canAlignToSector(d, p, p.lastSector() - sectorAlignment(d), originalPartition))
|
||||
{
|
||||
p.setLastSector(p.lastSector() - sectorAlignment(d));
|
||||
p.fileSystem().setLastSector(p.fileSystem().lastSector() - sectorAlignment(d));
|
||||
}
|
||||
|
||||
// In an extended partition we also need to align unallocated children at the beginning and at the end
|
||||
// (there should never be a need to align 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 isAligned(d, p);
|
||||
}
|
||||
|
||||
/** Creates a new unallocated Partition on the given Device.
|
||||
@param device the Device to create the new Partition on
|
||||
@param parent the parent PartitionNode for the new Partition
|
||||
|
@ -465,17 +234,17 @@ Partition* createUnallocated(const Device& device, PartitionNode& parent, qint64
|
|||
|
||||
// Leave a track (cylinder aligned) or sector alignment sectors (sector based) free at the
|
||||
// start for a new partition's metadata
|
||||
start += device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionTable::sectorAlignment(device);
|
||||
start += device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionAlignment::sectorAlignment(device);
|
||||
|
||||
// .. and also at the end for the metadata for a partition to follow us, if we're not
|
||||
// at the end of the extended partition
|
||||
if (end < extended->lastSector())
|
||||
end -= device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionTable::sectorAlignment(device);
|
||||
end -= device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionAlignment::sectorAlignment(device);
|
||||
|
||||
r |= PartitionRole::Logical;
|
||||
}
|
||||
|
||||
if (end - start + 1 < PartitionTable::sectorAlignment(device))
|
||||
if (end - start + 1 < PartitionAlignment::sectorAlignment(device))
|
||||
return NULL;
|
||||
|
||||
return new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Unknown, start, end), start, end, -1);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
|
||||
* Copyright (C) 2008,2010 by Volker Lanz <vl@fidra.de> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -135,9 +135,6 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionTable : public PartitionNode
|
|||
static void removeUnallocated(PartitionNode* p);
|
||||
void removeUnallocated();
|
||||
|
||||
static bool isAligned(const Device& d, const Partition& p);
|
||||
static bool alignPartition(const Device& d, Partition& p, const Partition* originalPartition = NULL);
|
||||
|
||||
static qint64 defaultFirstUsable(const Device& d, TableType t);
|
||||
static qint64 defaultLastUsable(const Device& d, TableType t);
|
||||
|
||||
|
@ -146,7 +143,6 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionTable : public PartitionNode
|
|||
static qint64 maxPrimariesForTableType(TableType l);
|
||||
static bool tableTypeSupportsExtended(TableType l);
|
||||
static bool tableTypeIsReadOnly(TableType l);
|
||||
static qint64 sectorAlignment(const Device& d);
|
||||
|
||||
protected:
|
||||
void setMaxPrimaries(qint32 n) { m_MaxPrimaries = n; }
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "core/partition.h"
|
||||
#include "core/device.h"
|
||||
#include "core/partitiontable.h"
|
||||
#include "core/partitionalignment.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
|
||||
|
@ -230,7 +231,7 @@ bool PartResizerWidget::movePartition(qint64 newFirstSector)
|
|||
|
||||
if (align())
|
||||
{
|
||||
device().partitionTable()->alignPartition(device(), partition());
|
||||
PartitionAlignment::alignPartition(device(), partition());
|
||||
|
||||
if (!checkConstraints(partition().firstSector(), partition().lastSector()))
|
||||
{
|
||||
|
@ -312,7 +313,7 @@ bool PartResizerWidget::updateFirstSector(qint64 newFirstSector)
|
|||
partition().fileSystem().setFirstSector(newFirstSector);
|
||||
|
||||
if (align())
|
||||
device().partitionTable()->alignPartition(device(), partition());
|
||||
PartitionAlignment::alignPartition(device(), partition());
|
||||
|
||||
if (originalFirst != partition().firstSector())
|
||||
{
|
||||
|
@ -334,7 +335,7 @@ bool PartResizerWidget::checkAlignment(const Partition& child, qint64 delta) con
|
|||
if (child.roles().has(PartitionRole::Unallocated))
|
||||
return true;
|
||||
|
||||
return qAbs(delta) >= PartitionTable::sectorAlignment(device());
|
||||
return qAbs(delta) >= PartitionAlignment::sectorAlignment(device());
|
||||
}
|
||||
|
||||
void PartResizerWidget::resizeLogicals()
|
||||
|
@ -374,7 +375,7 @@ bool PartResizerWidget::updateLastSector(qint64 newLastSector)
|
|||
partition().fileSystem().setLastSector(newLastSector);
|
||||
|
||||
if (align())
|
||||
device().partitionTable()->alignPartition(device(), partition());
|
||||
PartitionAlignment::alignPartition(device(), partition());
|
||||
|
||||
if (partition().lastSector() != originalLast)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "core/device.h"
|
||||
#include "core/partition.h"
|
||||
#include "core/partitiontable.h"
|
||||
#include "core/partitionalignment.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
#include "fs/filesystemfactory.h"
|
||||
|
@ -357,7 +358,7 @@ void LibPartedBackend::scanDevicePartitions(PedDevice* pedDevice, Device& d, Ped
|
|||
d.partitionTable()->setType(d, PartitionTable::msdos_sectorbased);
|
||||
|
||||
foreach(const Partition* part, partitions)
|
||||
PartitionTable::isAligned(d, *part);
|
||||
PartitionAlignment::isAligned(d, *part);
|
||||
|
||||
ped_disk_destroy(pedDisk);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue