Result Par2Creator::Process(const CommandLine &commandline) { // Get information from commandline noiselevel = commandline.GetNoiseLevel(); blocksize = commandline.GetBlockSize(); sourceblockcount = commandline.GetBlockCount(); const list<CommandLine::ExtraFile> extrafiles = commandline.GetExtraFiles(); sourcefilecount = (u32)extrafiles.size(); u32 redundancy = commandline.GetRedundancy(); recoveryblockcount = commandline.GetRecoveryBlockCount(); recoveryfilecount = commandline.GetRecoveryFileCount(); firstrecoveryblock = commandline.GetFirstRecoveryBlock(); recoveryfilescheme = commandline.GetRecoveryFileScheme(); string par2filename = commandline.GetParFilename(); size_t memorylimit = commandline.GetMemoryLimit(); largestfilesize = commandline.GetLargestSourceSize(); // Compute block size from block count or vice versa depending on which was // specified on the command line if (!ComputeBlockSizeAndBlockCount(extrafiles)) return eInvalidCommandLineArguments; // Determine how many recovery blocks to create based on the source block // count and the requested level of redundancy. if (redundancy > 0 && !ComputeRecoveryBlockCount(redundancy)) return eInvalidCommandLineArguments; // Determine how much recovery data can be computed on one pass if (!CalculateProcessBlockSize(memorylimit)) return eLogicError; // Determine how many recovery files to create. if (!ComputeRecoveryFileCount()) return eInvalidCommandLineArguments; if (noiselevel > CommandLine::nlQuiet) { // Display information. cout << "Block size: " << blocksize << endl; cout << "Source file count: " << sourcefilecount << endl; cout << "Source block count: " << sourceblockcount << endl; if (redundancy>0 || recoveryblockcount==0) cout << "Redundancy: " << redundancy << '%' << endl; cout << "Recovery block count: " << recoveryblockcount << endl; cout << "Recovery file count: " << recoveryfilecount << endl; cout << endl; } // Open all of the source files, compute the Hashes and CRC values, and store // the results in the file verification and file description packets. if (!OpenSourceFiles(extrafiles)) return eFileIOError; // Create the main packet and determine the setid to use with all packets if (!CreateMainPacket()) return eLogicError; // Create the creator packet. if (!CreateCreatorPacket()) return eLogicError; // Initialise all of the source blocks ready to start reading data from the source files. if (!CreateSourceBlocks()) return eLogicError; // Create all of the output files and allocate all packets to appropriate file offets. if (!InitialiseOutputFiles(par2filename)) return eFileIOError; if (recoveryblockcount > 0) { // Allocate memory buffers for reading and writing data to disk. if (!AllocateBuffers()) return eMemoryError; // Compute the Reed Solomon matrix if (!ComputeRSMatrix()) return eLogicError; // Set the total amount of data to be processed. progress = 0; totaldata = blocksize * sourceblockcount * recoveryblockcount; previouslyReportedFraction = -10000000; // Big negative // Start at an offset of 0 within a block. u64 blockoffset = 0; while (blockoffset < blocksize) // Continue until the end of the block. { // Work out how much data to process this time. size_t blocklength = (size_t)min((u64)chunksize, blocksize-blockoffset); // Read source data, process it through the RS matrix and write it to disk. if (!ProcessData(blockoffset, blocklength)) return eFileIOError; blockoffset += blocklength; } if (noiselevel > CommandLine::nlQuiet) cout << "Writing recovery packets" << endl; // Finish computation of the recovery packets and write the headers to disk. if (!WriteRecoveryPacketHeaders()) return eFileIOError; // Finish computing the full file hash values of the source files if (!FinishFileHashComputation()) return eLogicError; } // Fill in all remaining details in the critical packets. if (!FinishCriticalPackets()) return eLogicError; if (noiselevel > CommandLine::nlQuiet) cout << "Writing verification packets" << endl; // Write all other critical packets to disk. if (!WriteCriticalPackets()) return eFileIOError; // Close all files. if (!CloseFiles()) return eFileIOError; if (noiselevel > CommandLine::nlSilent) cout << "Done" << endl; return eSuccess; }
Result Par1Repairer::Process(const CommandLine &commandline, bool dorepair) { // How noisy should we be noiselevel = commandline.GetNoiseLevel(); // Do we want to purge par files on success ? bool purgefiles = commandline.GetPurgeFiles(); // Get filesnames from the command line string par1filename = commandline.GetParFilename(); const list<CommandLine::ExtraFile> &extrafiles = commandline.GetExtraFiles(); // Determine the searchpath from the location of the main PAR file string name; DiskFile::SplitFilename(par1filename, searchpath, name); // Load the main PAR file if (!LoadRecoveryFile(searchpath + name)) return eLogicError; // Load other PAR files related to the main PAR file if (!LoadOtherRecoveryFiles(par1filename)) return eLogicError; // Load any extra PAR files specified on the command line if (!LoadExtraRecoveryFiles(extrafiles)) return eLogicError; if (noiselevel > CommandLine::nlQuiet) cout << endl << "Verifying source files:" << endl << endl; // Check for the existence of and verify each of the source files if (!VerifySourceFiles()) return eFileIOError; if (completefilecount<sourcefiles.size()) { if (noiselevel > CommandLine::nlQuiet) cout << endl << "Scanning extra files:" << endl << endl; // Check any other files specified on the command line to see if they are // actually copies of the source files that have the wrong filename if (!VerifyExtraFiles(extrafiles)) return eLogicError; } // Find out how much data we have found UpdateVerificationResults(); if (noiselevel > CommandLine::nlSilent) cout << endl; // Check the verification results and report the details if (!CheckVerificationResults()) return eRepairNotPossible; // Are any of the files incomplete if (completefilecount<sourcefiles.size()) { // Do we want to carry out a repair if (dorepair) { if (noiselevel > CommandLine::nlSilent) cout << endl; // Rename any damaged or missnamed target files. if (!RenameTargetFiles()) return eFileIOError; // Are we still missing any files if (completefilecount<sourcefiles.size()) { // Work out which files are being repaired, create them, and allocate // target DataBlocks to them, and remember them for later verification. if (!CreateTargetFiles()) return eFileIOError; // Work out which data blocks are available, which need to be recreated, // and compute the appropriate Reed Solomon matrix. if (!ComputeRSmatrix()) { // Delete all of the partly reconstructed files DeleteIncompleteTargetFiles(); return eFileIOError; } // Allocate memory buffers for reading and writing data to disk. if (!AllocateBuffers(commandline.GetMemoryLimit())) { // Delete all of the partly reconstructed files DeleteIncompleteTargetFiles(); return eMemoryError; } if (noiselevel > CommandLine::nlSilent) cout << endl; // Set the total amount of data to be processed. progress = 0; totaldata = blocksize * sourcefiles.size() * verifylist.size(); // Start at an offset of 0 within a block. u64 blockoffset = 0; while (blockoffset < blocksize) { // Continue until the end of the block. // Work out how much data to process this time. size_t blocklength = (size_t)min((u64)chunksize, blocksize-blockoffset); // Read source data, process it through the RS matrix and write it to disk. if (!ProcessData(blockoffset, blocklength)) { // Delete all of the partly reconstructed files DeleteIncompleteTargetFiles(); return eFileIOError; } // Advance to the need offset within each block blockoffset += blocklength; } if (noiselevel > CommandLine::nlSilent) cout << endl << "Verifying repaired files:" << endl << endl; // Verify that all of the reconstructed target files are now correct if (!VerifyTargetFiles()) { // Delete all of the partly reconstructed files DeleteIncompleteTargetFiles(); return eFileIOError; } } // Are all of the target files now complete? if (completefilecount<sourcefiles.size()) { cerr << "Repair Failed." << endl; return eRepairFailed; } else { if (noiselevel > CommandLine::nlSilent) cout << endl << "Repair complete." << endl; } } else { return eRepairPossible; } } if (purgefiles == true) { RemoveBackupFiles(); RemoveParFiles(); } return eSuccess; }