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