/** * @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 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); }