/** * @file drive.cpp * @brief represent physical drive * @author hendrik schutter * @date 01.05.2020 */ #include "../include/reHDD.h" using namespace std; // Copy constructor Drive::Drive(const Drive &other) : state(other.state.load()), connectionType(other.connectionType.load()), sShredSpeed(other.sShredSpeed.load()), bWasShredded(other.bWasShredded), bWasShredStarted(other.bWasShredStarted), bWasChecked(other.bWasChecked), bWasDeleted(other.bWasDeleted), bIsOffline(other.bIsOffline), u32DriveChecksumAfterShredding(other.u32DriveChecksumAfterShredding), sPath(other.sPath), u32Timestamp(other.u32Timestamp), d32TaskPercentage(other.d32TaskPercentage), u32TimestampTaskStart(other.u32TimestampTaskStart), u32TaskDuration(other.u32TaskDuration), sSmartData(other.sSmartData) { } // Copy assignment operator Drive &Drive::operator=(const Drive &other) { if (this != &other) { state = other.state.load(); connectionType = other.connectionType.load(); sShredSpeed = other.sShredSpeed.load(); bWasShredded = other.bWasShredded; bWasShredStarted = other.bWasShredStarted; bWasChecked = other.bWasChecked; bWasDeleted = other.bWasDeleted; bIsOffline = other.bIsOffline; u32DriveChecksumAfterShredding = other.u32DriveChecksumAfterShredding; sPath = other.sPath; u32Timestamp = other.u32Timestamp; d32TaskPercentage = other.d32TaskPercentage; u32TimestampTaskStart = other.u32TimestampTaskStart; u32TaskDuration = other.u32TaskDuration; sSmartData = other.sSmartData; } return *this; } // Move constructor Drive::Drive(Drive &&other) noexcept : state(other.state.load()), connectionType(other.connectionType.load()), sShredSpeed(other.sShredSpeed.load()), bWasShredded(other.bWasShredded), bWasShredStarted(other.bWasShredStarted), bWasChecked(other.bWasChecked), bWasDeleted(other.bWasDeleted), bIsOffline(other.bIsOffline), u32DriveChecksumAfterShredding(other.u32DriveChecksumAfterShredding), sPath(std::move(other.sPath)), u32Timestamp(other.u32Timestamp), d32TaskPercentage(other.d32TaskPercentage), u32TimestampTaskStart(other.u32TimestampTaskStart), u32TaskDuration(other.u32TaskDuration), sSmartData(std::move(other.sSmartData)) { } // Move assignment operator Drive &Drive::operator=(Drive &&other) noexcept { if (this != &other) { state = other.state.load(); connectionType = other.connectionType.load(); sShredSpeed = other.sShredSpeed.load(); bWasShredded = other.bWasShredded; bWasShredStarted = other.bWasShredStarted; bWasChecked = other.bWasChecked; bWasDeleted = other.bWasDeleted; bIsOffline = other.bIsOffline; u32DriveChecksumAfterShredding = other.u32DriveChecksumAfterShredding; sPath = std::move(other.sPath); u32Timestamp = other.u32Timestamp; d32TaskPercentage = other.d32TaskPercentage; u32TimestampTaskStart = other.u32TimestampTaskStart; u32TaskDuration = other.u32TaskDuration; sSmartData = std::move(other.sSmartData); } return *this; } string Drive::getPath(void) { return sPath; } string Drive::getModelFamily(void) { return sSmartData.sModelFamily; } string Drive::getModelName(void) { return sSmartData.sModelName; } string Drive::getSerial(void) { return sSmartData.sSerial; } uint64_t Drive::getCapacity(void) { return sSmartData.u64Capacity; } uint32_t Drive::getErrorCount(void) { return sSmartData.u32ErrorCount; } uint32_t Drive::getPowerOnHours(void) { return sSmartData.u32PowerOnHours; } uint32_t Drive::getPowerCycles(void) { return sSmartData.u32PowerCycles; } uint32_t Drive::getTemperature(void) { return sSmartData.u32Temperature; } uint32_t Drive::getReallocatedSectors(void) { return sSmartData.u32ReallocatedSectors; } uint32_t Drive::getPendingSectors(void) { return sSmartData.u32PendingSectors; } uint32_t Drive::getUncorrectableSectors(void) { return sSmartData.u32UncorrectableSectors; } string Drive::sCapacityToText() { char acBuffer[16]; double dSize = (double)getCapacity(); uint16_t u16UnitIndex = 0; const char *units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; while (dSize >= 1000) // using the marketing capacity { dSize /= 1000; u16UnitIndex++; } if (u16UnitIndex >= 9) { u16UnitIndex = 8; } int precision = (u16UnitIndex >= 3) ? (u16UnitIndex - 3) : 0; sprintf(acBuffer, "%.*f %s", precision, dSize, units[u16UnitIndex]); return acBuffer; } string Drive::sErrorCountToText() { return to_string(getErrorCount()); } string Drive::sPowerOnHoursToText() { double dDays = 0U; double dYears = 0U; uint32_t u32Hours = getPowerOnHours(); stringstream streamDays; stringstream streamYears; dDays = (double)((double)u32Hours / (double)24U); dYears = (double)((double)u32Hours / (double)8760U); streamDays << fixed << setprecision(0) << dDays; streamYears << fixed << setprecision(1) << dYears; string sRet = to_string(getPowerOnHours()) + " hours or " + streamDays.str() + " days or " + streamYears.str() + " years"; return sRet; } string Drive::sPowerCyclesToText() { return to_string(getPowerCycles()); } string Drive::sTemperatureToText() { return to_string(getTemperature()) + " C"; } void Drive::setTaskPercentage(double d32TaskPercentage) { if (d32TaskPercentage <= 100) { this->d32TaskPercentage = d32TaskPercentage; this->setTimestamp(); // set timestamp for this progress for detecting a frozen drive } } double Drive::getTaskPercentage(void) { return this->d32TaskPercentage; } /** * \brief set S.M.A.R.T. values in model * \param string modelFamily * \param string modelName * \param string serial * \param uint64_t capacity * \param uint32_t errorCount * \param uint32_t powerOnHours * \param uint32_t powerCycle * \param uint32_t temperature * \return void */ void Drive::setDriveSMARTData(string modelFamily, string modelName, string serial, uint64_t capacity, uint32_t errorCount, uint32_t powerOnHours, uint32_t powerCycle, uint32_t temperature, uint32_t reallocatedSectors, uint32_t pendingSectors, uint32_t uncorrectableSectors) { this->sSmartData.sModelFamily = modelFamily; this->sSmartData.sModelName = modelName; this->sSmartData.sSerial = serial; this->sSmartData.u64Capacity = capacity; this->sSmartData.u32ErrorCount = errorCount; this->sSmartData.u32PowerOnHours = powerOnHours; this->sSmartData.u32PowerCycles = powerCycle; this->sSmartData.u32Temperature = temperature; this->sSmartData.u32ReallocatedSectors = reallocatedSectors; this->sSmartData.u32PendingSectors = pendingSectors; this->sSmartData.u32UncorrectableSectors = uncorrectableSectors; } void Drive::setTimestamp() { if (time(&this->u32Timestamp) == -1) { // handle error this->u32Timestamp = 0U; } } void Drive::setActionStartTimestamp() { if (time(&this->u32TimestampTaskStart) == -1) { // handle error this->u32TimestampTaskStart = 0U; } } time_t Drive::getActionStartTimestamp() { return this->u32TimestampTaskStart; } void Drive::calculateTaskDuration() { time_t u32localtime; if (time(&u32localtime) == -1) { // handle error u32localtime = 0U; } this->u32TaskDuration = u32localtime - this->u32TimestampTaskStart; } time_t Drive::getTaskDuration() { return this->u32TaskDuration; } void Drive::checkFrozenDrive(void) { time_t u32localtime; time(&u32localtime); if (time(&u32localtime) == -1) { // handle error u32localtime = 0U; } if ((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT * 60) && (this->u32Timestamp > 0) && (this->getTaskPercentage() < 100.0)) { Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial()); this->bWasDeleted = false; this->bWasShredded = false; this->state = Drive::TaskState::FROZEN; } }