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 Device;
|
||||||
class OperationStack;
|
class OperationStack;
|
||||||
class CoreBackendPartitionTable;
|
class CoreBackendPartitionTable;
|
||||||
|
class PartitionAlignment;
|
||||||
|
|
||||||
class PartResizerWidget;
|
class PartResizerWidget;
|
||||||
class InsertDialog;
|
class InsertDialog;
|
||||||
|
@ -76,6 +77,7 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT Partition : public PartitionNode
|
||||||
friend class Device;
|
friend class Device;
|
||||||
friend class PartitionNode;
|
friend class PartitionNode;
|
||||||
friend class CoreBackendPartitionTable;
|
friend class CoreBackendPartitionTable;
|
||||||
|
friend class PartitionAlignment;
|
||||||
|
|
||||||
friend class PartResizerWidget;
|
friend class PartResizerWidget;
|
||||||
friend class InsertDialog;
|
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/partitiontable.h"
|
||||||
#include "core/partition.h"
|
#include "core/partition.h"
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
#include "core/partitionalignment.h"
|
||||||
|
|
||||||
#include "fs/filesystem.h"
|
#include "fs/filesystem.h"
|
||||||
#include "fs/filesystemfactory.h"
|
#include "fs/filesystemfactory.h"
|
||||||
|
@ -210,238 +211,6 @@ QStringList PartitionTable::flagNames(Flags flags)
|
||||||
return rval;
|
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.
|
/** Creates a new unallocated Partition on the given Device.
|
||||||
@param device the Device to create the new Partition on
|
@param device the Device to create the new Partition on
|
||||||
@param parent the parent PartitionNode for the new Partition
|
@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
|
// Leave a track (cylinder aligned) or sector alignment sectors (sector based) free at the
|
||||||
// start for a new partition's metadata
|
// 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
|
// .. 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
|
// at the end of the extended partition
|
||||||
if (end < extended->lastSector())
|
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;
|
r |= PartitionRole::Logical;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end - start + 1 < PartitionTable::sectorAlignment(device))
|
if (end - start + 1 < PartitionAlignment::sectorAlignment(device))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Unknown, start, end), start, end, -1);
|
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 *
|
* 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 *
|
* 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);
|
static void removeUnallocated(PartitionNode* p);
|
||||||
void removeUnallocated();
|
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 defaultFirstUsable(const Device& d, TableType t);
|
||||||
static qint64 defaultLastUsable(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 qint64 maxPrimariesForTableType(TableType l);
|
||||||
static bool tableTypeSupportsExtended(TableType l);
|
static bool tableTypeSupportsExtended(TableType l);
|
||||||
static bool tableTypeIsReadOnly(TableType l);
|
static bool tableTypeIsReadOnly(TableType l);
|
||||||
static qint64 sectorAlignment(const Device& d);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setMaxPrimaries(qint32 n) { m_MaxPrimaries = n; }
|
void setMaxPrimaries(qint32 n) { m_MaxPrimaries = n; }
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "core/partition.h"
|
#include "core/partition.h"
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
#include "core/partitiontable.h"
|
#include "core/partitiontable.h"
|
||||||
|
#include "core/partitionalignment.h"
|
||||||
|
|
||||||
#include "fs/filesystem.h"
|
#include "fs/filesystem.h"
|
||||||
|
|
||||||
|
@ -230,7 +231,7 @@ bool PartResizerWidget::movePartition(qint64 newFirstSector)
|
||||||
|
|
||||||
if (align())
|
if (align())
|
||||||
{
|
{
|
||||||
device().partitionTable()->alignPartition(device(), partition());
|
PartitionAlignment::alignPartition(device(), partition());
|
||||||
|
|
||||||
if (!checkConstraints(partition().firstSector(), partition().lastSector()))
|
if (!checkConstraints(partition().firstSector(), partition().lastSector()))
|
||||||
{
|
{
|
||||||
|
@ -312,7 +313,7 @@ bool PartResizerWidget::updateFirstSector(qint64 newFirstSector)
|
||||||
partition().fileSystem().setFirstSector(newFirstSector);
|
partition().fileSystem().setFirstSector(newFirstSector);
|
||||||
|
|
||||||
if (align())
|
if (align())
|
||||||
device().partitionTable()->alignPartition(device(), partition());
|
PartitionAlignment::alignPartition(device(), partition());
|
||||||
|
|
||||||
if (originalFirst != partition().firstSector())
|
if (originalFirst != partition().firstSector())
|
||||||
{
|
{
|
||||||
|
@ -334,7 +335,7 @@ bool PartResizerWidget::checkAlignment(const Partition& child, qint64 delta) con
|
||||||
if (child.roles().has(PartitionRole::Unallocated))
|
if (child.roles().has(PartitionRole::Unallocated))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return qAbs(delta) >= PartitionTable::sectorAlignment(device());
|
return qAbs(delta) >= PartitionAlignment::sectorAlignment(device());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartResizerWidget::resizeLogicals()
|
void PartResizerWidget::resizeLogicals()
|
||||||
|
@ -374,7 +375,7 @@ bool PartResizerWidget::updateLastSector(qint64 newLastSector)
|
||||||
partition().fileSystem().setLastSector(newLastSector);
|
partition().fileSystem().setLastSector(newLastSector);
|
||||||
|
|
||||||
if (align())
|
if (align())
|
||||||
device().partitionTable()->alignPartition(device(), partition());
|
PartitionAlignment::alignPartition(device(), partition());
|
||||||
|
|
||||||
if (partition().lastSector() != originalLast)
|
if (partition().lastSector() != originalLast)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
#include "core/partition.h"
|
#include "core/partition.h"
|
||||||
#include "core/partitiontable.h"
|
#include "core/partitiontable.h"
|
||||||
|
#include "core/partitionalignment.h"
|
||||||
|
|
||||||
#include "fs/filesystem.h"
|
#include "fs/filesystem.h"
|
||||||
#include "fs/filesystemfactory.h"
|
#include "fs/filesystemfactory.h"
|
||||||
|
@ -357,7 +358,7 @@ void LibPartedBackend::scanDevicePartitions(PedDevice* pedDevice, Device& d, Ped
|
||||||
d.partitionTable()->setType(d, PartitionTable::msdos_sectorbased);
|
d.partitionTable()->setType(d, PartitionTable::msdos_sectorbased);
|
||||||
|
|
||||||
foreach(const Partition* part, partitions)
|
foreach(const Partition* part, partitions)
|
||||||
PartitionTable::isAligned(d, *part);
|
PartitionAlignment::isAligned(d, *part);
|
||||||
|
|
||||||
ped_disk_destroy(pedDisk);
|
ped_disk_destroy(pedDisk);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue