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;
}
Example #2
0
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;
}
Example #3
0
int main(int argc, char *argv[])
{
#ifdef _MSC_VER
  // Memory leak checking
  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_ALLOC_MEM_DF | /*_CRTDBG_CHECK_CRT_DF | */_CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

  // Parse the command line
  CommandLine *commandline = new CommandLine;

  Result result = eInvalidCommandLineArguments;
  
  if (!commandline->Parse(argc, argv))
  {
    banner();
    CommandLine::usage();
  }
  else
  {
    if (commandline->GetNoiseLevel() > CommandLine::nlSilent)
      banner();

    // Which operation was selected
    switch (commandline->GetOperation())
    {
    case CommandLine::opCreate:
      {
        // Create recovery data

        Par2Creator *creator = new Par2Creator;
        result = creator->Process(*commandline);
        delete creator;
      }
      break;
    case CommandLine::opVerify:
      {
        // Verify damaged files
        switch (commandline->GetVersion())
        {
        case CommandLine::verPar1:
          {
            Par1Repairer *repairer = new Par1Repairer;
            result = repairer->Process(*commandline, false);
            delete repairer;
          }
          break;
        case CommandLine::verPar2:
          {
            Par2Repairer *repairer = new Par2Repairer;
            result = repairer->Process(*commandline, false);
            delete repairer;
          }
          break;
        case CommandLine::opNone:
          break;
        }
      }
      break;
    case CommandLine::opRepair:
      {
        // Repair damaged files
        switch (commandline->GetVersion())
        {
        case CommandLine::verPar1:
          {
            Par1Repairer *repairer = new Par1Repairer;
            result = repairer->Process(*commandline, true);
            delete repairer;
          }
          break;
        case CommandLine::verPar2:
          {
            Par2Repairer *repairer = new Par2Repairer;
            result = repairer->Process(*commandline, true);
            delete repairer;
          }
          break;
        case CommandLine::opNone:
          break;
        }
      }
      break;
    case CommandLine::opNone:
      break;
    }
  }

  delete commandline;

  return result;
}