295 lines
11 KiB
C++
295 lines
11 KiB
C++
/**
|
|
* @file shred.cpp
|
|
* @brief shred drive
|
|
* @author hendrik schutter
|
|
* @date 03.05.2020
|
|
*/
|
|
|
|
#include "../include/reHDD.h"
|
|
|
|
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();
|
|
|
|
//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;
|
|
}
|
|
|
|
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
|
|
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();; //set inital timestamp for speed metric
|
|
unsigned long 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
|
|
uint32_t u32ChunkDimensionIndex = 0U;
|
|
|
|
|
|
if(uiShredIterationCounter == (SHRED_ITERATIONS-1))
|
|
{
|
|
//last shred iteration --> overwrite with zeros instead with random data
|
|
memset(caChunk, 0U, CHUNK_DIMENSION*CHUNK_SIZE);
|
|
}
|
|
|
|
while (ulDriveByteCounter < ulDriveByteSize)
|
|
{
|
|
int iBytesToShred = 0; //Bytes that will be overwritten in this chunk-iteration
|
|
|
|
if((u32ChunkDimensionIndex == 0U) && (uiShredIterationCounter != (SHRED_ITERATIONS-1)))
|
|
{
|
|
//read new chunks from random source if needed and this is NOT the last shred iteration
|
|
unsigned long ulBytesInChunkBuffer = 0U;
|
|
|
|
while (ulBytesInChunkBuffer < CHUNK_DIMENSION*CHUNK_SIZE)
|
|
{
|
|
//read new random bytes
|
|
int iReadBytes = read(randomSrcFileDiscr, caChunk, ((CHUNK_DIMENSION*CHUNK_SIZE)-ulBytesInChunkBuffer));
|
|
if (iReadBytes > 0)
|
|
{
|
|
ulBytesInChunkBuffer += iReadBytes;
|
|
}
|
|
else
|
|
{
|
|
std::string errorMsg(strerror(iReadBytes));
|
|
Logger::logThis()->error("Shred-Task: Read from random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
|
|
perror("unable to read random data");
|
|
cleanup();
|
|
return -1;;
|
|
}
|
|
} //end chunk read
|
|
#ifdef LOG_LEVEL_HIGH
|
|
Logger::logThis()->info("Shred-Task: Read new random data - Drive: " + drive->getSerial());
|
|
#endif
|
|
|
|
}
|
|
|
|
if((ulDriveByteSize-ulDriveByteCounter) < CHUNK_SIZE)
|
|
{
|
|
iBytesToShred = (ulDriveByteSize-ulDriveByteCounter);
|
|
}
|
|
else
|
|
{
|
|
iBytesToShred = CHUNK_SIZE;
|
|
}
|
|
|
|
int iByteShredded = write(driveFileDiscr, caChunk[u32ChunkDimensionIndex], 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;
|
|
}
|
|
|
|
u32ChunkDimensionIndex = (u32ChunkDimensionIndex+1)%CHUNK_DIMENSION;
|
|
ulDriveByteCounter += iByteShredded;
|
|
ulDriveByteOverallCount += iByteShredded;
|
|
d32Percent = this->calcProgress();
|
|
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;
|
|
|
|
//set metrics for calculating shred speed
|
|
std::chrono::time_point<std::chrono::system_clock> chronoCurrentTimestamp = std::chrono::system_clock::now();
|
|
drive->sShredSpeed.u32ShredTimeDelta = (chronoCurrentTimestamp - drive->sShredSpeed.chronoShredTimestamp).count();
|
|
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
|
|
drive->sShredSpeed.ulWrittenBytes = ulSpeedMetricBytesWritten;
|
|
ulSpeedMetricBytesWritten = 0U;
|
|
|
|
//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))
|
|
{
|
|
cleanup();
|
|
return -1;
|
|
}
|
|
} //end one shred iteration
|
|
|
|
#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, caChunk, iBytesToCheck);
|
|
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
|
|
{
|
|
uiChecksum += caChunk[0][iReadBytesCounter];
|
|
}
|
|
ulDriveByteCounter += iReadBytes;
|
|
ulDriveByteOverallCount += iReadBytes;
|
|
d32Percent = this->calcProgress();
|
|
#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.9)
|
|
{
|
|
drive->setTaskPercentage(d32TmpPercent);
|
|
d32TmpPercent = d32Percent;
|
|
write(*ipSignalFd, "A",1);
|
|
}
|
|
}
|
|
return uiChecksum;
|
|
}
|
|
|
|
void Shred::cleanup()
|
|
{
|
|
close(driveFileDiscr);
|
|
close( randomSrcFileDiscr);
|
|
} |