2015-06-04 01:29:22 +01:00
|
|
|
/*************************************************************************
|
|
|
|
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
|
2016-03-02 19:00:31 +00:00
|
|
|
* Copyright (C) 2016 by Andrius Štikonas <andrius@stikonas.eu> *
|
2015-06-04 01:29:22 +01:00
|
|
|
* *
|
|
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.*
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
#include "core/partitionalignment.h"
|
|
|
|
|
|
|
|
#include "core/partition.h"
|
|
|
|
#include "core/partitiontable.h"
|
|
|
|
#include "core/device.h"
|
2016-05-31 19:28:31 +01:00
|
|
|
#include "core/diskdevice.h"
|
2015-06-04 01:29:22 +01:00
|
|
|
|
|
|
|
#include "fs/filesystem.h"
|
|
|
|
|
|
|
|
#include "util/globallog.h"
|
|
|
|
|
|
|
|
#include <KLocalizedString>
|
|
|
|
|
2015-07-15 17:33:35 +01:00
|
|
|
int PartitionAlignment::s_sectorAlignment = 2048;
|
|
|
|
|
2015-06-04 01:29:22 +01:00
|
|
|
qint64 PartitionAlignment::firstDelta(const Device& d, const Partition& p, qint64 s)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
if (d.partitionTable()->type() == PartitionTable::msdos) {
|
2016-05-31 19:28:31 +01:00
|
|
|
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
|
|
|
|
if (p.roles().has(PartitionRole::Logical) && s == 2 * diskDevice.sectorsPerTrack())
|
|
|
|
return (s - (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2016-05-31 19:28:31 +01:00
|
|
|
if (p.roles().has(PartitionRole::Logical) || s == diskDevice.sectorsPerTrack())
|
|
|
|
return (s - diskDevice.sectorsPerTrack()) % sectorAlignment(d);
|
2015-07-13 15:16:36 +01:00
|
|
|
}
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
return s % sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 PartitionAlignment::lastDelta(const Device& d, const Partition&, qint64 s)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
return (s + 1) % sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PartitionAlignment::isLengthAligned(const Device& d, const Partition& p)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
if (d.partitionTable()->type() == PartitionTable::msdos) {
|
2016-05-31 19:28:31 +01:00
|
|
|
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
|
|
|
|
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * diskDevice.sectorsPerTrack())
|
|
|
|
return (p.length() + (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d) == 0;
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2016-05-31 19:28:31 +01:00
|
|
|
if (p.roles().has(PartitionRole::Logical) || p.firstSector() == diskDevice.sectorsPerTrack())
|
|
|
|
return (p.length() + diskDevice.sectorsPerTrack()) % sectorAlignment(d) == 0;
|
2015-07-13 15:16:36 +01:00
|
|
|
}
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
return p.length() % sectorAlignment(d) == 0;
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Checks if the Partition is properly aligned to the PartitionTable's alignment requirements.
|
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
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. This can be suppressed with setting the @p quiet to
|
|
|
|
true.
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
@see alignPartition(), canAlignToSector()
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
@param d device the partition is on
|
|
|
|
@param p the partition to check
|
|
|
|
@param quiet if true, will not print warning
|
2019-11-22 13:43:36 +00:00
|
|
|
@return true if properly aligned
|
2015-06-04 01:29:22 +01:00
|
|
|
*/
|
|
|
|
bool PartitionAlignment::isAligned(const Device& d, const Partition& p, bool quiet)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
return isAligned(d, p, p.firstSector(), p.lastSector(), quiet);
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PartitionAlignment::isAligned(const Device& d, const Partition& p, qint64 newFirst, qint64 newLast, bool quiet)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
if (firstDelta(d, p, newFirst) && !quiet)
|
2018-04-09 15:14:34 +01:00
|
|
|
Log(Log::Level::warning) << xi18nc("@info:status", "Partition <filename>%1</filename> is not properly aligned (first sector: %2, modulo: %3).", p.deviceNode(), newFirst, firstDelta(d, p, newFirst));
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
if (lastDelta(d, p, newLast) && !quiet)
|
2018-04-09 15:14:34 +01:00
|
|
|
Log(Log::Level::warning) << xi18nc("@info:status", "Partition <filename>%1</filename> is not properly aligned (last sector: %2, modulo: %3).", p.deviceNode(), newLast, lastDelta(d, p, newLast));
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
return firstDelta(d, p, newFirst) == 0 && lastDelta(d, p, newLast) == 0;
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @return the sector size to align the partition start and end to
|
|
|
|
*/
|
|
|
|
qint64 PartitionAlignment::sectorAlignment(const Device& d)
|
|
|
|
{
|
2015-07-20 16:11:22 +01:00
|
|
|
Q_UNUSED(d)
|
2015-07-15 17:33:35 +01:00
|
|
|
return s_sectorAlignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartitionAlignment::setSectorAlignment(int sectorAlignment)
|
|
|
|
{
|
|
|
|
s_sectorAlignment = sectorAlignment;
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 PartitionAlignment::alignedFirstSector(const Device& d, const Partition& p, qint64 s, qint64 min_first, qint64 max_first, qint64 min_length, qint64 max_length)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
if (firstDelta(d, p, s) == 0)
|
|
|
|
return s;
|
|
|
|
|
|
|
|
/** @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.
|
|
|
|
s = s - firstDelta(d, p, s);
|
|
|
|
|
|
|
|
while (s < d.partitionTable()->firstUsable() || s < min_first || (max_length > -1 && p.lastSector() - s + 1 > max_length))
|
|
|
|
s += sectorAlignment(d);
|
|
|
|
|
|
|
|
while (s > d.partitionTable()->lastUsable() || (max_first > -1 && s > max_first) || p.lastSector() - s + 1 < min_length)
|
|
|
|
s -= sectorAlignment(d);
|
|
|
|
|
|
|
|
return s;
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 PartitionAlignment::alignedLastSector(const Device& d, const Partition& p, qint64 s, qint64 min_last, qint64 max_last, qint64 min_length, qint64 max_length, qint64 original_length, bool original_aligned)
|
|
|
|
{
|
2015-07-13 15:16:36 +01:00
|
|
|
if (lastDelta(d, p, s) == 0)
|
|
|
|
return s;
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
s = s + sectorAlignment(d) - lastDelta(d, p, s);
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
// if we can retain the partition length exactly by aligning to the front, do that
|
|
|
|
if (original_aligned && p.length() - original_length == lastDelta(d, p, s))
|
|
|
|
s -= sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
while (s < d.partitionTable()->firstUsable() || s < min_last || s - p.firstSector() + 1 < min_length)
|
|
|
|
s += sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
while (s > d.partitionTable()->lastUsable() || (max_last > -1 && s > max_last) || (max_length > -1 && s - p.firstSector() + 1 > max_length))
|
|
|
|
s -= sectorAlignment(d);
|
2015-06-04 01:29:22 +01:00
|
|
|
|
2015-07-13 15:16:36 +01:00
|
|
|
return s;
|
2015-06-04 01:29:22 +01:00
|
|
|
}
|
|
|
|
|