diff --git a/src/core/lvmdevice.cpp b/src/core/lvmdevice.cpp index a54a40f..ee1f99e 100644 --- a/src/core/lvmdevice.cpp +++ b/src/core/lvmdevice.cpp @@ -1,198 +1,243 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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 .* *************************************************************************/ #include "core/lvmdevice.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "core/partition.h" #include "core/partitiontable.h" #include "util/externalcommand.h" #include "util/helpers.h" #include #include #include +#include /** Constructs a representation of LVM device with functionning LV as Partition - @param name Volume Group name -*/ + * + * @param name Volume Group name + */ LvmDevice::LvmDevice(const QString& name, const QString& iconname) : VolumeManagerDevice(name, (QStringLiteral("/dev/") + name), getPeSize(name), getTotalPE(name), iconname, Device::LVM_Device) , m_peSize(getPeSize(name)) , m_totalPE(getTotalPE(name)) , m_allocPE(getAllocatedPE(name)) , m_freePE(getFreePE(name)) , m_UUID(getUUID(name)) { initPartitions(); } void LvmDevice::initPartitions() { qint64 firstUsable = 0; qint64 lastusable = totalPE() - 1; PartitionTable* pTable = new PartitionTable(PartitionTable::vmd, firstUsable, lastusable); foreach (Partition* p, scanPartitions(*this, pTable)) { pTable->append(p); } - setPartitionTable(pTable); } /** - return sorted Partition(LV) Array -*/ + * @returns sorted Partition(LV) Array + */ QList LvmDevice::scanPartitions(const Device& dev, PartitionTable* pTable) const { QList pList; - QList lvNodeList; - - lvNodeList = getField(QStringLiteral("lv_path"), dev.name()).split(QStringLiteral("\n")); - - foreach (QString lvNode, lvNodeList) { - pList.append(scanPartition(lvNode.trimmed(), dev, pTable)); + foreach (QString lvPath, lvPathList()) { + pList.append(scanPartition(lvPath, dev, pTable)); } - return pList; } /** - return sorted Partition(LV) Array -*/ -Partition* LvmDevice::scanPartition(const QString& lvPath, const Device& dev, PartitionTable* pTable) const + * @returns sorted Partition(LV) Array + */ +Partition* LvmDevice::scanPartition(const QString& lvpath, const Device& dev, PartitionTable* pTable) const { + /* + * NOTE: + * LVM partition have 2 different start and end sector value + * 1. representing the actual LV start from 0 -> size of LV - 1 + * 2. representing abstract LV's sector inside a VG partitionTable + * start from size of last Partitions -> size of LV - 1 + * Reason for this is for the LV Partition to worrks nicely with other parts of the codebase + * without too many special cases. + */ + qint64 startSector; qint64 endSector; + qint64 lvSize; + + bool mounted = isMounted(lvpath); QString mountPoint = QString(); - bool mounted = isMounted(lvPath); KMountPoint::List mountPointList = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); mountPointList.append(KMountPoint::possibleMountPoints(KMountPoint::NeedRealDeviceName)); - mountPoint = mountPointList.findByDevice(lvPath) ? - mountPointList.findByDevice(lvPath)->mountPoint() : + mountPoint = mountPointList.findByDevice(lvpath) ? + mountPointList.findByDevice(lvpath)->mountPoint() : QString(); - ExternalCommand cmd(QStringLiteral("lvm"), - { QStringLiteral("lvdisplay"), - QStringLiteral("--units"), - QStringLiteral("B"), - QStringLiteral("--maps"), - lvPath}); + lvSize = getTotalLE(lvpath); + startSector = mappedSector(lvpath,0); + endSector = startSector + (lvSize - 1); - if (cmd.run(-1) && cmd.exitCode() == 0) { + const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); - //TODO: regex for first and last sector of the LV - //TODO: stringing PE into one large contingiuous array of PE ?? - QRegularExpression re(QStringLiteral("Physical extents\\h+(\\d+)\\sto\\s(\\d+)")); - QRegularExpressionMatch match = re.match(cmd.output()); - if (match.hasMatch()) { - startSector = match.captured(1).toLongLong(); - endSector = match.captured(2).toLongLong(); - } + FileSystem* fs = FileSystemFactory::create(FileSystem::detectFileSystem(lvpath), 0, lvSize - 1); + if (mounted && freeSpaceInfo.isValid() && mountPoint != QString()) { + //TODO: fix used space report. currently incorrect + fs->setSectorsUsed(freeSpaceInfo.used() / logicalSize()); } - FileSystem* fs = FileSystemFactory::create(FileSystem::detectFileSystem(lvPath), startSector, endSector); - Partition* part = new Partition(pTable, dev, PartitionRole(PartitionRole::Lvm_Lv), fs, startSector, endSector, - lvPath, + lvpath, PartitionTable::Flag::FlagLvm, mountPoint, mounted); return part; } +qint64 LvmDevice::mappedSector(const QString& lvpath, qint64 sector) const +{ + qint64 mSector = 0; + QList lvpathList = lvPathList(); + qint32 devIndex = lvpathList.indexOf(lvpath); + + if (devIndex) { + for (int i = 0; i < devIndex; i++) { + //TODO: currently going over the same LV again and again is wasteful. Could use some more optimization + mSector += getTotalLE(lvpathList[i]); + } + mSector += sector; + } + return mSector; +} + QList LvmDevice::deviceNodeList() const { QList devPathList; QString cmdOutput = getField(QStringLiteral("pv_name"), name()); if (cmdOutput.size()) { QList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts); foreach(QString devPath, tempPathList) { devPathList.append(devPath.trimmed()); } } - return devPathList; } +QList LvmDevice::lvPathList() const +{ + QList lvPathList; + QString cmdOutput = getField(QStringLiteral("lv_path"), name()); + + if (cmdOutput.size()) { + QList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts); + foreach(QString lvPath, tempPathList) { + lvPathList.append(lvPath.trimmed()); + } + } + return lvPathList; +} + qint32 LvmDevice::getPeSize(const QString& vgname) { QString val = getField(QStringLiteral("vg_extent_size"), vgname); return val.isEmpty() ? -1 : val.toInt(); } qint32 LvmDevice::getTotalPE(const QString& vgname) { QString val = getField(QStringLiteral("vg_extent_count"), vgname); return val.isEmpty() ? -1 : val.toInt(); } qint32 LvmDevice::getAllocatedPE(const QString& vgname) { return getTotalPE(vgname) - getFreePE(vgname); } qint32 LvmDevice::getFreePE(const QString& vgname) { QString val = getField(QStringLiteral("vg_free_count"), vgname); return val.isEmpty() ? -1 : val.toInt(); } QString LvmDevice::getUUID(const QString& vgname) { QString val = getField(QStringLiteral("vg_uuid"), vgname); return val.isEmpty() ? QStringLiteral("---") : val; } + /** Query LVM details with field name * * @param fieldName lvm field name * @param vgname * @returns raw output of command output, usully with manay spaces within the returned string * */ QString LvmDevice::getField(const QString& fieldName, const QString& vgname) { ExternalCommand cmd(QStringLiteral("lvm"), { QStringLiteral("vgs"), QStringLiteral("--foreign"), QStringLiteral("--readonly"), QStringLiteral("--noheadings"), QStringLiteral("--units"), QStringLiteral("B"), QStringLiteral("--nosuffix"), QStringLiteral("--options"), fieldName, vgname }); if (cmd.run(-1) && cmd.exitCode() == 0) { return cmd.output().trimmed(); } return QString(); } + +qint32 LvmDevice::getTotalLE(const QString& lvpath) +{ + ExternalCommand cmd(QStringLiteral("lvm"), + { QStringLiteral("lvdisplay"), + lvpath}); + + if (cmd.run(-1) && cmd.exitCode() == 0) { + QRegularExpression re(QStringLiteral("Current LE\\h+(\\d+)")); + QRegularExpressionMatch match = re.match(cmd.output()); + if (match.hasMatch()) { + return match.captured(1).toInt(); + } + } + return -1; +} diff --git a/src/core/lvmdevice.h b/src/core/lvmdevice.h index 47ab17d..d352be6 100644 --- a/src/core/lvmdevice.h +++ b/src/core/lvmdevice.h @@ -1,91 +1,97 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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 .* *************************************************************************/ #if !defined(LVMDEVICE__H) #define LVMDEVICE__H #include "core/volumemanagerdevice.h" #include "util/libpartitionmanagerexport.h" #include #include #include class PartitionTable; class CreatePartitionTableOperation; class SmartStatus; /** A device. Represents a device like /dev/sda. Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. @see PartitionTable, Partition @author Volker Lanz */ class LIBKPMCORE_EXPORT LvmDevice : public VolumeManagerDevice { Q_DISABLE_COPY(LvmDevice) public: LvmDevice(const QString& name, const QString& iconname = QString()); public: QList scanPartitions(const Device& dev, PartitionTable* pTable) const; Partition* scanPartition(const QString& lvPath, const Device& dev, PartitionTable* pTable) const; - static qint32 getPeSize(const QString& name); - static qint32 getTotalPE(const QString& name); - static qint32 getAllocatedPE(const QString& name); - static qint32 getFreePE(const QString& name); - static QString getUUID(const QString& name); + static qint32 getPeSize(const QString& vgname); + static qint32 getTotalPE(const QString& vgname); + static qint32 getAllocatedPE(const QString& vgname); + static qint32 getFreePE(const QString& vgname); + static QString getUUID(const QString& vgname); static QString getField(const QString& fieldName, const QString& vgname = QString()); + static qint32 getTotalLE(const QString& lvpath); + protected: void initPartitions(); QList deviceNodeList() const override; + qint64 mappedSector(const QString& lvpath, qint64 sector) const override; + + QList lvPathList() const; public: qint32 peSize() const { return m_peSize; } qint32 totalPE() const { return m_totalPE; } qint32 allocatedPE() const { return m_allocPE; } qint32 freePE() const { return m_freePE; } QString UUID() const { return m_UUID; } private: qint32 m_peSize; qint32 m_totalPE; qint32 m_allocPE; qint32 m_freePE; QString m_UUID; + }; #endif diff --git a/src/core/partitiontable.cpp b/src/core/partitiontable.cpp index bd139c1..d39a3c1 100644 --- a/src/core/partitiontable.cpp +++ b/src/core/partitiontable.cpp @@ -1,531 +1,536 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * Copyright (C) 2016 by Teo Mrnjavac * * * * 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 .* *************************************************************************/ /** @file */ #include "core/partitiontable.h" #include "core/partition.h" #include "core/device.h" #include "core/diskdevice.h" #include "core/partitionalignment.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/globallog.h" #include #include #include /** Creates a new PartitionTable object with type MSDOS @param type name of the PartitionTable type (e.g. "msdos" or "gpt") */ PartitionTable::PartitionTable(TableType type, qint64 first_usable, qint64 last_usable) : PartitionNode(), m_Children(), m_MaxPrimaries(maxPrimariesForTableType(type)), m_Type(type), m_FirstUsable(first_usable), m_LastUsable(last_usable) { } /** Destroys a PartitionTable object, destroying all children */ PartitionTable::~PartitionTable() { clearChildren(); } /** Gets the number of free sectors before a given child Partition in this PartitionTable. @param p the Partition for which to get the free sectors before @returns the number of free sectors before the Partition */ qint64 PartitionTable::freeSectorsBefore(const Partition& p) const { const Partition* pred = predecessor(p); // due to the space required for extended boot records the // below is NOT the same as pred->length() if (pred && pred->roles().has(PartitionRole::Unallocated)) return p.firstSector() - pred->firstSector(); return 0; } /** Gets the number of free sectors after a given child Partition in this PartitionTable. @param p the Partition for which to get the free sectors after @returns the number of free sectors after the Partition */ qint64 PartitionTable::freeSectorsAfter(const Partition& p) const { const Partition* succ = successor(p); // due to the space required for extended boot records the // below is NOT the same as succ->length() if (succ && succ->roles().has(PartitionRole::Unallocated)) return succ->lastSector() - p.lastSector(); return 0; } /** @return true if the PartitionTable has an extended Partition */ bool PartitionTable::hasExtended() const { for (int i = 0; i < children().size(); i++) if (children()[i]->roles().has(PartitionRole::Extended)) return true; return false; } /** @return pointer to the PartitionTable's extended Partition or nullptr if none exists */ Partition* PartitionTable::extended() const { for (int i = 0; i < children().size(); i++) if (children()[i]->roles().has(PartitionRole::Extended)) return children()[i]; return nullptr; } /** Gets valid PartitionRoles for a Partition @param p the Partition @return valid roles for the given Partition */ PartitionRole::Roles PartitionTable::childRoles(const Partition& p) const { Q_ASSERT(p.parent()); PartitionRole::Roles r = p.parent()->isRoot() ? PartitionRole::Primary : PartitionRole::Logical; if (r == PartitionRole::Primary && hasExtended() == false && tableTypeSupportsExtended(type())) r |= PartitionRole::Extended; return r; } /** @return the number of primaries in this PartitionTable */ int PartitionTable::numPrimaries() const { int result = 0; foreach(const Partition * p, children()) if (p->roles().has(PartitionRole::Primary) || p->roles().has(PartitionRole::Extended)) result++; return result; } /** Appends a Partition to this PartitionTable @param partition pointer of the partition to append. Must not be nullptr. */ void PartitionTable::append(Partition* partition) { children().append(partition); } /** @param f the flag to get the name for @returns the flags name or an empty QString if the flag is not known */ QString PartitionTable::flagName(Flag f) { switch (f) { case PartitionTable::FlagBoot: return i18nc("@item partition flag", "boot"); case PartitionTable::FlagRoot: return i18nc("@item partition flag", "root"); case PartitionTable::FlagSwap: return i18nc("@item partition flag", "swap"); case PartitionTable::FlagHidden: return i18nc("@item partition flag", "hidden"); case PartitionTable::FlagRaid: return i18nc("@item partition flag", "raid"); case PartitionTable::FlagLvm: return i18nc("@item partition flag", "lvm"); case PartitionTable::FlagLba: return i18nc("@item partition flag", "lba"); case PartitionTable::FlagHpService: return i18nc("@item partition flag", "hpservice"); case PartitionTable::FlagPalo: return i18nc("@item partition flag", "palo"); case PartitionTable::FlagPrep: return i18nc("@item partition flag", "prep"); case PartitionTable::FlagMsftReserved: return i18nc("@item partition flag", "msft-reserved"); case PartitionTable::FlagBiosGrub: return i18nc("@item partition flag", "bios-grub"); case PartitionTable::FlagAppleTvRecovery: return i18nc("@item partition flag", "apple-tv-recovery"); case PartitionTable::FlagDiag: return i18nc("@item partition flag", "diag"); case PartitionTable::FlagLegacyBoot: return i18nc("@item partition flag", "legacy-boot"); case PartitionTable::FlagMsftData: return i18nc("@item partition flag", "msft-data"); case PartitionTable::FlagIrst: return i18nc("@item partition flag", "irst"); case PartitionTable::FlagEsp: return i18nc("@item partition flag", "esp"); default: break; } return QString(); } /** @return list of all flags */ QList PartitionTable::flagList() { QList rval; rval.append(PartitionTable::FlagBoot); rval.append(PartitionTable::FlagRoot); rval.append(PartitionTable::FlagSwap); rval.append(PartitionTable::FlagHidden); rval.append(PartitionTable::FlagRaid); rval.append(PartitionTable::FlagLvm); rval.append(PartitionTable::FlagLba); rval.append(PartitionTable::FlagHpService); rval.append(PartitionTable::FlagPalo); rval.append(PartitionTable::FlagPrep); rval.append(PartitionTable::FlagMsftReserved); rval.append(PartitionTable::FlagBiosGrub); rval.append(PartitionTable::FlagAppleTvRecovery); rval.append(PartitionTable::FlagDiag); rval.append(PartitionTable::FlagLegacyBoot); rval.append(PartitionTable::FlagMsftData); rval.append(PartitionTable::FlagIrst); rval.append(PartitionTable::FlagEsp); return rval; } /** @param flags the flags to get the names for @returns QStringList of the flags' names */ QStringList PartitionTable::flagNames(Flags flags) { QStringList rval; int f = 1; QString s; while (!(s = flagName(static_cast(f))).isEmpty()) { if (flags & f) rval.append(s); f <<= 1; } return rval; } bool PartitionTable::getUnallocatedRange(const Device& d, PartitionNode& parent, qint64& start, qint64& end) { //TODO: alignment for LVM device if (d.type() == Device::Disk_Device) { const DiskDevice& device = dynamic_cast(d); if (!parent.isRoot()) { Partition* extended = dynamic_cast(&parent); if (extended == nullptr) { qWarning() << "extended is null. start: " << start << ", end: " << end << ", device: " << device.deviceNode(); return false; } // 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() : 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() : PartitionAlignment::sectorAlignment(device); } return end - start + 1 >= PartitionAlignment::sectorAlignment(device); } else if (d.type() == Device::LVM_Device) { return false; + //TODO: return range from last LE to last allocated LE } return false; } /** 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 @param start the new Partition's start sector @param end the new Partition's end sector @return pointer to the newly created Partition object or nullptr if the Partition could not be created */ Partition* createUnallocated(const Device& device, PartitionNode& parent, qint64 start, qint64 end) { PartitionRole::Roles r = PartitionRole::Unallocated; if (!parent.isRoot()) r |= PartitionRole::Logical; if (!PartitionTable::getUnallocatedRange(device, parent, start, end)) return nullptr; return new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Unknown, start, end), start, end, QString()); } /** Removes all unallocated children from a PartitionNode @param p pointer to the parent to remove unallocated children from */ void PartitionTable::removeUnallocated(PartitionNode* p) { Q_ASSERT(p); qint32 i = 0; while (i < p->children().size()) { Partition* child = p->children()[i]; if (child->roles().has(PartitionRole::Unallocated)) { p->remove(child); delete child; continue; } if (child->roles().has(PartitionRole::Extended)) removeUnallocated(child); i++; } } /** @overload */ void PartitionTable::removeUnallocated() { removeUnallocated(this); } /** Inserts unallocated children for a Device's PartitionTable with the given parent. This method inserts unallocated Partitions for a parent, usually the Device this PartitionTable is on. It will also insert unallocated Partitions in any extended Partitions it finds. @warning This method assumes that no unallocated Partitions exist when it is called. @param d the Device this PartitionTable and @p p are on @param p the parent PartitionNode (may be this or an extended Partition) @param start the first sector to begin looking for free space */ void PartitionTable::insertUnallocated(const Device& d, PartitionNode* p, qint64 start) const { Q_ASSERT(p); qint64 lastEnd = start; foreach(Partition * child, p->children()) { p->insert(createUnallocated(d, *p, lastEnd, child->firstSector() - 1)); if (child->roles().has(PartitionRole::Extended)) insertUnallocated(d, child, child->firstSector()); lastEnd = child->lastSector() + 1; } // Take care of the free space between the end of the last child and the end // of the device or the extended partition. qint64 parentEnd = lastUsable(); if (!p->isRoot()) { Partition* extended = dynamic_cast(p); parentEnd = extended ? extended->lastSector() : -1; Q_ASSERT(extended); } if (parentEnd >= firstUsable()) p->insert(createUnallocated(d, *p, lastEnd, parentEnd)); } /** Updates the unallocated Partitions for this PartitionTable. @param d the Device this PartitionTable is on */ void PartitionTable::updateUnallocated(const Device& d) { removeUnallocated(); insertUnallocated(d, this, firstUsable()); } qint64 PartitionTable::defaultFirstUsable(const Device& d, TableType t) { Q_UNUSED(t) - const DiskDevice& diskDevice = dynamic_cast(d); - return PartitionAlignment::sectorAlignment(diskDevice); + if (d.type() == Device::LVM_Device) { + return 0; + } else { + const DiskDevice& diskDevice = dynamic_cast(d); + return PartitionAlignment::sectorAlignment(diskDevice); + } } qint64 PartitionTable::defaultLastUsable(const Device& d, TableType t) { if (t == gpt) return d.totalLogical() - 1 - 32 - 1; return d.totalLogical() - 1; } static struct { const QString name; /**< name of partition table type */ quint32 maxPrimaries; /**< max numbers of primary partitions supported */ bool canHaveExtended; /**< does partition table type support extended partitions */ bool isReadOnly; /**< does KDE Partition Manager support this only in read only mode */ PartitionTable::TableType type; /**< enum type */ } tableTypes[] = { { QStringLiteral("aix"), 4, false, true, PartitionTable::aix }, { QStringLiteral("bsd"), 8, false, true, PartitionTable::bsd }, { QStringLiteral("dasd"), 1, false, true, PartitionTable::dasd }, { QStringLiteral("msdos"), 4, true, false, PartitionTable::msdos }, { QStringLiteral("msdos"), 4, true, false, PartitionTable::msdos_sectorbased }, { QStringLiteral("dvh"), 16, true, true, PartitionTable::dvh }, { QStringLiteral("gpt"), 128, false, false, PartitionTable::gpt }, { QStringLiteral("loop"), 1, false, true, PartitionTable::loop }, { QStringLiteral("mac"), 0xffff, false, true, PartitionTable::mac }, { QStringLiteral("pc98"), 16, false, true, PartitionTable::pc98 }, { QStringLiteral("amiga"), 128, false, true, PartitionTable::amiga }, { QStringLiteral("sun"), 8, false, true, PartitionTable::sun } }; PartitionTable::TableType PartitionTable::nameToTableType(const QString& n) { for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++) if (n == tableTypes[i].name) return tableTypes[i].type; return PartitionTable::unknownTableType; } QString PartitionTable::tableTypeToName(TableType l) { for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++) if (l == tableTypes[i].type) return tableTypes[i].name; return i18nc("@item partition table name", "unknown"); } qint64 PartitionTable::maxPrimariesForTableType(TableType l) { for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++) if (l == tableTypes[i].type) return tableTypes[i].maxPrimaries; return 1; } bool PartitionTable::tableTypeSupportsExtended(TableType l) { for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++) if (l == tableTypes[i].type) return tableTypes[i].canHaveExtended; return false; } bool PartitionTable::tableTypeIsReadOnly(TableType l) { for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++) if (l == tableTypes[i].type) return tableTypes[i].isReadOnly; return false; } /** Simple heuristic to determine if the PartitionTable is sector aligned (i.e. if its Partitions begin at sectors evenly divisable by PartitionAlignment::sectorAlignment(). @return true if is sector aligned, otherwise false */ bool PartitionTable::isSectorBased(const Device& d) const { if (d.type() == Device::Disk_Device) { const DiskDevice& diskDevice = dynamic_cast(d); if (type() == PartitionTable::msdos) { // the default for empty partition tables is sector based if (numPrimaries() == 0) return true; quint32 numCylinderAligned = 0; quint32 numSectorAligned = 0; // see if we have more cylinder aligned partitions than sector // aligned ones. foreach(const Partition * p, children()) if (p->firstSector() % PartitionAlignment::sectorAlignment(diskDevice) == 0) numSectorAligned++; else if (p->firstSector() % diskDevice.cylinderSize() == 0) numCylinderAligned++; return numSectorAligned >= numCylinderAligned; } return type() == PartitionTable::msdos_sectorbased; } return false; } void PartitionTable::setType(const Device& d, TableType t) { setFirstUsableSector(defaultFirstUsable(d, t)); setLastUsableSector(defaultLastUsable(d, t)); m_Type = t; updateUnallocated(d); } static bool isPartitionLessThan(const Partition* p1, const Partition* p2) { return p1->number() < p2->number(); } QTextStream& operator<<(QTextStream& stream, const PartitionTable& ptable) { stream << "type: \"" << ptable.typeName() << "\"\n" << "align: \"" << (ptable.type() == PartitionTable::msdos ? "cylinder" : "sector") << "\"\n" << "\n# number start end type roles label flags\n"; QList partitions; foreach(const Partition * p, ptable.children()) if (!p->roles().has(PartitionRole::Unallocated)) { partitions.append(p); if (p->roles().has(PartitionRole::Extended)) foreach(const Partition * child, p->children()) if (!child->roles().has(PartitionRole::Unallocated)) partitions.append(child); } qSort(partitions.begin(), partitions.end(), isPartitionLessThan); foreach(const Partition * p, partitions) stream << *p; return stream; } diff --git a/src/core/volumemanagerdevice.cpp b/src/core/volumemanagerdevice.cpp index 255c692..d110708 100644 --- a/src/core/volumemanagerdevice.cpp +++ b/src/core/volumemanagerdevice.cpp @@ -1,49 +1,49 @@ /************************************************************************* - * Copyright (C) 2008 by Volker Lanz * - * Copyright (C) 2016 by Andrius Štikonas * + * Copyright (C) 2016 by Chantara Tith * * * * 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 .* *************************************************************************/ #include "core/volumemanagerdevice.h" #include "core/partitiontable.h" #include "core/smartstatus.h" #include "util/capacity.h" /** Constructs a Device with an empty PartitionTable. */ VolumeManagerDevice::VolumeManagerDevice(const QString& name, const QString& devicenode, const qint32 logicalSize, const qint64 totalLogical, const QString& iconname, Device::Type type) : Device(name, devicenode, logicalSize, totalLogical, iconname, type) { } QString VolumeManagerDevice::prettyDeviceNodeList() const { QString rval; foreach (QString devNode, deviceNodeList()) { rval += devNode + QStringLiteral(","); } if (rval.size()) { + //chop off the trailing colon rval.chop(1); } return rval; } diff --git a/src/core/volumemanagerdevice.h b/src/core/volumemanagerdevice.h index da5764f..89ae87c 100644 --- a/src/core/volumemanagerdevice.h +++ b/src/core/volumemanagerdevice.h @@ -1,59 +1,62 @@ /************************************************************************* + * Copyright (C) 2016 by Chantara Tith * + * * * 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 .* *************************************************************************/ #if !defined(VOLUMEMANAGERDEVICE__H) #define VOLUMEMANAGERDEVICE__H #include "util/libpartitionmanagerexport.h" #include "core/device.h" #include #include #include class PartitionTable; class CreatePartitionTableOperation; class CoreBackend; class SmartStatus; class Partition; -/** A device. +/** A abstract device represeting real physical devices. - Represents a device like /dev/sda. + Represents a device like /dev/sda, /dev/sdb1. Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. @see PartitionTable, Partition - @author Volker Lanz */ class LIBKPMCORE_EXPORT VolumeManagerDevice : public Device { Q_DISABLE_COPY(VolumeManagerDevice) protected: VolumeManagerDevice(const QString& name, const QString& devicenode, const qint32 logicalSize, const qint64 totalLogical, const QString& iconname = QString(), Device::Type type = Device::Unknown_Device); virtual QList deviceNodeList() const = 0; /** Return list of physical device or partitions that makes up volumeManagerDevice */ + virtual qint64 mappedSector(const QString& devNode, qint64 sector) const = 0; public: - //virtual void refresh() const = 0; /* VG infos can be changed, unlike disk_device */ - //virtual Qlist listDevices() const = 0; + /** string deviceNodeList together into comma-sperated list */ virtual QString prettyDeviceNodeList() const; + /** Mapper return absolute sector representing the VG */ private: + //QMap deviceSizeMapper; }; #endif