reHDD/src/shred.cpp

291 lines
9.9 KiB
C++

/**
* @file shred.cpp
* @brief shred drive
* @author hendrik schutter
* @date 22.08.2022
*/
#include "../include/reHDD.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "../tfnoisegen/tfprng.h"
#ifdef __cplusplus
}
#endif
const static char *randomsrc = (char*) "/dev/urandom";
Shred::Shred()
{
}
Shred::~Shred()
{
}
/**
* \brief shred drive with shred
* \param pointer of Drive instance
* \return void
*/
int Shred::shredDrive(Drive* drive, int* ipSignalFd)
{
ostringstream address;
address << (void const *)&(*drive);
Logger::logThis()->info("Shred-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
#ifdef DRYRUN
for(int i = 0; i<=500; i++)
{
if(drive->state != Drive::SHRED_ACTIVE)
{
return 0;
}
drive->setTaskPercentage(i+0.05);
write(*ipSignalFd, "A",1);
usleep(20000);
}
#endif
#ifndef DRYRUN
const char *cpDrivePath = drive->getPath().c_str();
unsigned char ucKey[TFNG_KEY_SIZE];
//open random source
randomSrcFileDiscr = open(randomsrc, O_RDONLY | O_LARGEFILE);
if (randomSrcFileDiscr == -1)
{
std::string errorMsg(strerror(randomSrcFileDiscr));
Logger::logThis()->error("Shred-Task: Open random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(randomsrc);
cleanup();
return -1;
}
//open disk
driveFileDiscr = open(cpDrivePath, O_RDWR | O_LARGEFILE);
if (driveFileDiscr == -1)
{
std::string errorMsg(strerror(driveFileDiscr));
Logger::logThis()->error("Shred-Task: Open drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(cpDrivePath);
cleanup();
return -1;
}
//read key for random generator
ssize_t readRet = read(randomSrcFileDiscr, ucKey, sizeof(ucKey)) ;
if (readRet <= 0)
{
std::string errorMsg(strerror(readRet));
Logger::logThis()->error("Shred-Task: Read random key failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(randomsrc);
cleanup();
return -1;
}
tfng_prng_seedkey(ucKey);
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();; //set inital timestamp for speed metric
drive->sShredSpeed.ulSpeedMetricBytesWritten = 0U; //uses to calculate speed metric
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: Bytes-Size of Drive: " + to_string(this->ulDriveByteSize) + " - Drive: " + drive->getSerial());
#endif
for (unsigned int uiShredIterationCounter = 0U; uiShredIterationCounter < SHRED_ITERATIONS; uiShredIterationCounter++)
{
unsigned long ulDriveByteCounter = 0U; //used for one shred-iteration to keep track of the current drive position
if(uiShredIterationCounter == (SHRED_ITERATIONS-1))
{
//last shred iteration --> overwrite (just the write chunk) bytes with zeros instead with random data
memset(caTfngData, 0U, CHUNK_SIZE);
}
while (ulDriveByteCounter < ulDriveByteSize)
{
int iBytesToShred = 0; //Bytes that will be overwritten in this chunk-iteration
if(uiShredIterationCounter != (SHRED_ITERATIONS-1))
{
//NOT last shred iteration --> generate new random data
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
}
if((ulDriveByteSize-ulDriveByteCounter) < CHUNK_SIZE)
{
iBytesToShred = (ulDriveByteSize-ulDriveByteCounter);
}
else
{
iBytesToShred = CHUNK_SIZE;
}
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
if(iByteShredded <= 0)
{
std::string errorMsg(strerror(iByteShredded));
Logger::logThis()->error("Shred-Task: Write to drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror("unable to write random data");
cleanup();
return -1;
}
ulDriveByteCounter += iByteShredded;
ulDriveByteOverallCount += iByteShredded;
d32Percent = this->calcProgress();
drive->sShredSpeed.ulSpeedMetricBytesWritten += iByteShredded;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: ByteCount: " + to_string(ulDriveByteCounter) + " - iteration: " + to_string((uiShredIterationCounter+1)) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
#endif
if((d32Percent-d32TmpPercent) >= 0.01)
{
//set shred percantage
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
//signal process in shreding
write(*ipSignalFd, "A",1);
}
if(drive->state != Drive::SHRED_ACTIVE)
{
drive->setTaskPercentage(0);
d32Percent = 0.00;
d32TmpPercent = 0.00;
ulDriveByteCounter = 0U;
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
cleanup();
return -1;
}
//end one chunk write
}
if(0 != iRewindDrive(driveFileDiscr))
{
Logger::logThis()->error("Shred-Task: Unable to rewind drive! - Drive: " + drive->getSerial());
cleanup();
return -1;
}
//end one shred iteration
}
//end of all shred iteratio
tfng_prng_seedkey(NULL); //reset random generator
#ifdef ZERO_CHECK_ALERT
drive->u32DriveChecksumAferShredding = uiCalcChecksum(driveFileDiscr, drive, ipSignalFd);
#ifdef LOG_LEVEL_HIGH
if (drive->u32DriveChecksumAferShredding != 0)
{
Logger::logThis()->info("Shred-Task: Checksum not zero: " + to_string(drive->u32DriveChecksumAferShredding) + " - Drive: " + drive->getSerial());
}
else
{
Logger::logThis()->info("Shred-Task: Checksum zero: " + to_string(drive->u32DriveChecksumAferShredding) + " - Drive: " + drive->getSerial());
}
#endif
#endif
#endif
cleanup();
if(drive->state == Drive::SHRED_ACTIVE)
{
drive->bWasShredded = true;
drive->state= Drive::NONE;
drive->setTaskPercentage(0.0);
Logger::logThis()->info("Finished shred for: " + drive->getModelName() + "-" + drive->getSerial());
}
return 0;
}
/**
* \brief calc shredding progress in %
* \param current byte index of the drive
* \param current shred iteration
* \return double percentage
*/
double Shred::calcProgress()
{
unsigned int uiMaxShredIteration = SHRED_ITERATIONS;
#ifdef ZERO_CHECK_ALERT
uiMaxShredIteration++; //increment because we will check after SHRED_ITERATIONS the drive for non-zero bytes
#endif
return (double) (((double) ulDriveByteOverallCount) / ((double)this->ulDriveByteSize*uiMaxShredIteration))*100.0f;
}
int Shred::iRewindDrive(fileDescriptor file)
{
if(0 != lseek(file, 0L, SEEK_SET))
{
perror("unable to rewind drive");
return -1;
}
else
{
return 0;
}
}
unsigned long Shred::getDriveSizeInBytes(fileDescriptor file)
{
unsigned long ulDriveSizeTmp = lseek(file, 0L, SEEK_END);
if(0 != iRewindDrive(file))
{
ulDriveSizeTmp = 0U;
}
#ifdef DEMO_DRIVE_SIZE
ulDriveSizeTmp = DEMO_DRIVE_SIZE;
#endif
return ulDriveSizeTmp;
}
unsigned int Shred::uiCalcChecksum(fileDescriptor file,Drive* drive, int* ipSignalFd)
{
unsigned int uiChecksum = 0;
unsigned long ulDriveByteCounter = 0U;
while (ulDriveByteCounter < ulDriveByteSize)
{
int iBytesToCheck = 0;
if((ulDriveByteSize-ulDriveByteCounter) < CHUNK_SIZE)
{
iBytesToCheck = (ulDriveByteSize-ulDriveByteCounter);
}
else
{
iBytesToCheck = CHUNK_SIZE;
}
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
{
uiChecksum += caReadBuffer[iReadBytesCounter];
}
ulDriveByteCounter += iReadBytes;
ulDriveByteOverallCount += iReadBytes;
d32Percent = this->calcProgress();
drive->sShredSpeed.ulSpeedMetricBytesWritten += iReadBytes;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task (Checksum): ByteCount: " + to_string(ulDriveByteCounter) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
#endif
if((d32Percent-d32TmpPercent) >= 0.01)
{
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
write(*ipSignalFd, "A",1);
}
}
return uiChecksum;
}
void Shred::cleanup()
{
close(driveFileDiscr);
close(randomSrcFileDiscr);
}