File indexing completed on 2024-04-28 05:45:44

0001 /*
0002     SPDX-FileCopyrightText: 2008-2010 Volker Lanz <vl@fidra.de>
0003     SPDX-FileCopyrightText: 2012-2018 Andrius Štikonas <andrius@stikonas.eu>
0004     SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
0005     SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "core/diskdevice.h"
0011 #include "core/device_p.h"
0012 
0013 #include "core/partitiontable.h"
0014 #include "core/smartstatus.h"
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QFile>
0019 #include <QByteArray>
0020 
0021 #include <sys/ioctl.h>
0022 #include <sys/types.h>
0023 #include <sys/stat.h>
0024 #include <fcntl.h>
0025 #include <unistd.h>
0026 #ifdef __gnu_linux__
0027   #include <linux/fs.h>
0028 #endif
0029 
0030 #if !defined(BLKPBSZGET)
0031 #define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */
0032 #endif
0033 
0034 #define d_ptr std::static_pointer_cast<DiskDevicePrivate>(d)
0035 
0036 class DiskDevicePrivate : public DevicePrivate
0037 {
0038 public:
0039     qint32 m_Heads;
0040     qint32 m_SectorsPerTrack;
0041     qint32 m_Cylinders;
0042     qint64 m_LogicalSectorSize;
0043     qint64 m_PhysicalSectorSize;
0044 };
0045 
0046 static qint64 getPhysicalSectorSize(const QString& device_node)
0047 {
0048     /*
0049      * possible ways of getting the physical sector size for a drive:
0050      * - ioctl(BLKPBSZGET) -- supported with Linux 2.6.32 and later
0051      * - /sys/block/sda/queue/physical_block_size
0052      * - libblkid from util-linux 2.17 or later (not implemented)
0053      */
0054 
0055 #if defined(BLKPBSZGET)
0056     int phSectorSize = -1;
0057     int fd = open(device_node.toLocal8Bit().constData(), O_RDONLY);
0058     if (fd != -1) {
0059         if (ioctl(fd, BLKPBSZGET, &phSectorSize) >= 0) {
0060             close(fd);
0061             return phSectorSize;
0062         }
0063 
0064         close(fd);
0065     }
0066 #endif
0067 
0068     QFile f(QStringLiteral("/sys/block/%1/queue/physical_block_size").arg(QString(device_node).remove(QStringLiteral("/dev/"))));
0069 
0070     if (f.open(QIODevice::ReadOnly)) {
0071         QByteArray a = f.readLine();
0072         return a.trimmed().toInt();
0073     }
0074 
0075     return -1;
0076 }
0077 
0078 /** Constructs a Disk Device with an empty PartitionTable.
0079     @param name the Device's name, usually some string defined by the manufacturer
0080     @param deviceNode the Device's node, for example "/dev/sda"
0081     @param heads the number of heads in CHS notation
0082     @param numSectors the number of sectors in CHS notation
0083     @param cylinders the number of cylinders in CHS notation
0084     @param sectorSize the size of a sector in bytes
0085 */
0086 DiskDevice::DiskDevice(const QString& name,
0087                        const QString& deviceNode,
0088                        qint32 heads,
0089                        qint32 numSectors,
0090                        qint32 cylinders,
0091                        qint64 sectorSize,
0092                        const QString& iconName)
0093     : Device(std::make_shared<DiskDevicePrivate>(), name, deviceNode, sectorSize, (static_cast<qint64>(heads) * cylinders * numSectors), iconName, Device::Type::Disk_Device)
0094 {
0095     d_ptr->m_Heads = heads;
0096     d_ptr->m_SectorsPerTrack = numSectors;
0097     d_ptr->m_Cylinders = cylinders;
0098     d_ptr->m_LogicalSectorSize = sectorSize;
0099     d_ptr->m_PhysicalSectorSize = getPhysicalSectorSize(deviceNode);
0100 }
0101 
0102 qint32 DiskDevice::heads() const
0103 {
0104     return d_ptr->m_Heads;
0105 }
0106 
0107 qint32 DiskDevice::cylinders() const
0108 {
0109     return d_ptr->m_Cylinders;
0110 }
0111 
0112 qint32 DiskDevice::sectorsPerTrack() const
0113 {
0114     return d_ptr->m_SectorsPerTrack;
0115 }
0116 
0117 qint64 DiskDevice::physicalSectorSize() const
0118 {
0119     return d_ptr->m_PhysicalSectorSize;
0120 }
0121 
0122 qint64 DiskDevice::logicalSectorSize() const
0123 {
0124     return d_ptr->m_LogicalSectorSize;
0125 }
0126 
0127 qint64 DiskDevice::totalSectors() const
0128 {
0129     return static_cast<qint64>(d_ptr->m_Heads) * d_ptr->m_Cylinders * d_ptr->m_SectorsPerTrack;
0130 }
0131 
0132 qint64 DiskDevice::cylinderSize() const
0133 {
0134     return static_cast<qint64>(d_ptr->m_Heads) * d_ptr->m_SectorsPerTrack;
0135 }