File indexing completed on 2024-04-28 05:45:46
0001 /* 0002 SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de> 0003 SPDX-FileCopyrightText: 2014-2018 Andrius Štikonas <andrius@stikonas.eu> 0004 SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org> 0005 SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com> 0006 SPDX-FileCopyrightText: 2019 Yuri Chornoivan <yurchor@ukr.net> 0007 0008 SPDX-License-Identifier: GPL-3.0-or-later 0009 */ 0010 0011 #include "core/partitionalignment.h" 0012 0013 #include "core/partition.h" 0014 #include "core/partitiontable.h" 0015 #include "core/device.h" 0016 #include "core/diskdevice.h" 0017 0018 #include "fs/filesystem.h" 0019 0020 #include "util/globallog.h" 0021 0022 #include <KLocalizedString> 0023 0024 int PartitionAlignment::s_sectorAlignment = 2048; 0025 0026 qint64 PartitionAlignment::firstDelta(const Device& d, const Partition& p, qint64 s) 0027 { 0028 if (d.partitionTable()->type() == PartitionTable::msdos) { 0029 const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d); 0030 if (p.roles().has(PartitionRole::Logical) && s == 2 * diskDevice.sectorsPerTrack()) 0031 return (s - (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d); 0032 0033 if (p.roles().has(PartitionRole::Logical) || s == diskDevice.sectorsPerTrack()) 0034 return (s - diskDevice.sectorsPerTrack()) % sectorAlignment(d); 0035 } 0036 0037 return s % sectorAlignment(d); 0038 } 0039 0040 qint64 PartitionAlignment::lastDelta(const Device& d, const Partition&, qint64 s) 0041 { 0042 return (s + 1) % sectorAlignment(d); 0043 } 0044 0045 bool PartitionAlignment::isLengthAligned(const Device& d, const Partition& p) 0046 { 0047 if (d.partitionTable()->type() == PartitionTable::msdos) { 0048 const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d); 0049 if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * diskDevice.sectorsPerTrack()) 0050 return (p.length() + (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d) == 0; 0051 0052 if (p.roles().has(PartitionRole::Logical) || p.firstSector() == diskDevice.sectorsPerTrack()) 0053 return (p.length() + diskDevice.sectorsPerTrack()) % sectorAlignment(d) == 0; 0054 } 0055 0056 return p.length() % sectorAlignment(d) == 0; 0057 } 0058 0059 /** Checks if the Partition is properly aligned to the PartitionTable's alignment requirements. 0060 0061 Will print warning messages to GlobalLog if the Partition's first sector is not aligned and 0062 another one if the last sector is not aligned. This can be suppressed with setting the @p quiet to 0063 true. 0064 0065 @see alignPartition(), canAlignToSector() 0066 0067 @param d device the partition is on 0068 @param p the partition to check 0069 @param quiet if true, will not print warning 0070 @return true if properly aligned 0071 */ 0072 bool PartitionAlignment::isAligned(const Device& d, const Partition& p, bool quiet) 0073 { 0074 return isAligned(d, p, p.firstSector(), p.lastSector(), quiet); 0075 } 0076 0077 bool PartitionAlignment::isAligned(const Device& d, const Partition& p, qint64 newFirst, qint64 newLast, bool quiet) 0078 { 0079 if (firstDelta(d, p, newFirst) && !quiet) 0080 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)); 0081 0082 if (lastDelta(d, p, newLast) && !quiet) 0083 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)); 0084 0085 return firstDelta(d, p, newFirst) == 0 && lastDelta(d, p, newLast) == 0; 0086 } 0087 0088 /** @return the sector size to align the partition start and end to 0089 */ 0090 qint64 PartitionAlignment::sectorAlignment(const Device& d) 0091 { 0092 Q_UNUSED(d) 0093 return s_sectorAlignment; 0094 } 0095 0096 void PartitionAlignment::setSectorAlignment(int sectorAlignment) 0097 { 0098 if (sectorAlignment > 0) 0099 s_sectorAlignment = sectorAlignment; 0100 } 0101 0102 qint64 PartitionAlignment::alignedFirstSector(const Device& d, const Partition& p, qint64 s, qint64 min_first, qint64 max_first, qint64 min_length, qint64 max_length) 0103 { 0104 if (firstDelta(d, p, s) == 0) 0105 return s; 0106 0107 /** @todo Don't assume we always want to align to the front. 0108 Always trying to align to the front solves the problem that a partition does 0109 get too small to take another one that's copied to it, but it introduces 0110 a new bug: The user might create a partition aligned at the end of a device, 0111 extended partition or at the start of the next one, but we align to the back 0112 and leave some space in between. 0113 */ 0114 // We always want to make the partition larger, not smaller. Making it smaller 0115 // might, in case it's a partition that another is being copied to, mean the partition 0116 // ends up too small. So try to move the start to the front first. 0117 s = s - firstDelta(d, p, s); 0118 0119 while (s < d.partitionTable()->firstUsable() || s < min_first || (max_length > -1 && p.lastSector() - s + 1 > max_length)) 0120 s += sectorAlignment(d); 0121 0122 while (s > d.partitionTable()->lastUsable() || (max_first > -1 && s > max_first) || p.lastSector() - s + 1 < min_length) 0123 s -= sectorAlignment(d); 0124 0125 return s; 0126 } 0127 0128 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) 0129 { 0130 if (lastDelta(d, p, s) == 0) 0131 return s; 0132 0133 s = s + sectorAlignment(d) - lastDelta(d, p, s); 0134 0135 // if we can retain the partition length exactly by aligning to the front, do that 0136 if (original_aligned && p.length() - original_length == lastDelta(d, p, s)) 0137 s -= sectorAlignment(d); 0138 0139 while (s < d.partitionTable()->firstUsable() || s < min_last || s - p.firstSector() + 1 < min_length) 0140 s += sectorAlignment(d); 0141 0142 while (s > d.partitionTable()->lastUsable() || (max_last > -1 && s > max_last) || (max_length > -1 && s - p.firstSector() + 1 > max_length)) 0143 s -= sectorAlignment(d); 0144 0145 return s; 0146 }