Пример #1
0
        /// <summary>
        /// XORs the data from the given file with the parity data.  This either adds the file to 
        /// parity or removes it from parity if it was already there.  If checkHash is true,
        /// it verifies the file's hash matches the hash on record before commiting the parity.
        /// If false, it updates the file's hash on record.
        /// </summary>
        private bool XORFileWithParity(FileRecord r, bool checkHash)
        {
            if (!File.Exists(r.FullPath))
            return false;
              if (r.Length == 0)
            return true;

              using (ParityChange change = new ParityChange(parity, Config, r.StartBlock, r.LengthInBlocks)) {
            byte[] data = new byte[Parity.BLOCK_SIZE];
            MD5 hash = MD5.Create();
            hash.Initialize();
            UInt32 endBlock = r.StartBlock + r.LengthInBlocks;
            UInt32 totalProgresBlocks = r.LengthInBlocks + (UInt32)(TEMP_FLUSH_PERCENT * r.LengthInBlocks);

            FileStream f;
            try {
              f = new FileStream(r.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read);
            }
            catch (Exception e) {
              FireErrorMessage(String.Format("Error opening {0}: {1}", r.FullPath, e.Message));
              return false;
            }
            try {
              for (UInt32 b = r.StartBlock; b < endBlock; b++) {
            Int32 bytesRead;
            try {
              bytesRead = f.Read(data, 0, Parity.BLOCK_SIZE);
            }
            catch (Exception e) {
              FireErrorMessage(String.Format("Error reading {0}: {1}", r.FullPath, e.Message));
              return false;
            }
            if (b == (endBlock - 1))
              hash.TransformFinalBlock(data, 0, bytesRead);
            else
              hash.TransformBlock(data, 0, bytesRead, data, 0);
            while (bytesRead < Parity.BLOCK_SIZE)
              data[bytesRead++] = 0;
            change.Reset(true);
            change.AddData(data);
            change.Write();
            currentUpdateBlocks++;
            r.Drive.Progress = (double)(b - r.StartBlock) / totalProgresBlocks;
            Progress = (double)currentUpdateBlocks / totalUpdateBlocks;
            if (cancel)
              return false;
              }
            }
            catch (Exception e) {
              env.LogCrash(e);
              FireErrorMessage(String.Format("Unexpected error while processing {0}: {1}", r.FullPath, e.Message));
              return false;
            }
            finally {
              f.Dispose();
            }

            if (checkHash) {
              if (!Utils.HashCodesMatch(hash.Hash, r.HashCode)) {
            LogFile.Log("Tried to remove existing file but hash codes don't match.");
            return false;
              }
            }
            else
              r.HashCode = hash.Hash;

            FlushTempParity(r.Drive, change); // commit the parity change to disk
              }
              r.Drive.Progress = 0;
              return true;
        }
Пример #2
0
        private void FlushTempParity(DataDrive drive, ParityChange change)
        {
            bool saveInProgress = true;
              Task.Factory.StartNew(() =>
              {
            try {
              change.Save();
            }
            catch {
            }
            finally {
              saveInProgress = false;
            }
              });

              while (saveInProgress) {
            Thread.Sleep(20);
            drive.Progress = (1.0 - TEMP_FLUSH_PERCENT) + TEMP_FLUSH_PERCENT * change.SaveProgress;
              }
              drive.Progress = 0;
        }
Пример #3
0
        private bool RemoveFromParity(FileRecord r)
        {
            // make a backup copy of the meta file first.  If this fails, we know we won't be able to complete the remove.
              if (!r.Drive.BackupMetaFile()) {
            FireErrorMessage("Error removing " + r.FullPath + ": could not back up " + r.Drive.MetaFile);
            return false;
              }

              bool success = false;
              try {
            if (r.Length > 0) {
              string fullPath = r.FullPath;
              UInt32 startBlock = r.StartBlock;
              UInt32 endBlock = startBlock + r.LengthInBlocks;
              if (LogFile.Verbose)
            LogFile.Log("Removing {0} from blocks {1} to {2}...", fullPath, startBlock, endBlock - 1);
              else
            LogFile.Log("Removing {0}...", fullPath);

              r.Drive.Status = "Removing  " + fullPath;

              // Optimization: if the file still exists and is unmodified, we can remove it much faster this way
              if (!r.Modified && XORFileWithParity(r, true)) {
            r.Drive.RemoveFile(r);
            r.Drive.SaveFileList();
            success = true; // so finally() clause doesn't try to restore backup
            return true;
              }

              UInt32 totalProgresBlocks = r.LengthInBlocks + (UInt32)(TEMP_FLUSH_PERCENT * r.LengthInBlocks);

              // Recalulate parity from scratch for all blocks that contained the deleted file's data.
              using (ParityChange change = new ParityChange(parity, Config, startBlock, r.LengthInBlocks))
            try {

              byte[] data = new byte[Parity.BLOCK_SIZE];
              for (UInt32 b = startBlock; b < endBlock; b++) {
                change.Reset(false);
                foreach (DataDrive d in drives) {
                  if (d == r.Drive)
                    continue;
                  // Note it's possible that this file may also have been deleted. That's OK, ReadFileData
                  // returns false and we don't try to add the deleted file to the parity.
                  FileRecord f;
                  try {
                    if (d.ReadBlock(b, data, out f))
                      change.AddData(data);
                  }
                  catch (Exception e) {
                    FireErrorMessage(e.Message);
                    return false;
                  }
                }
                change.Write();
                currentUpdateBlocks++;
                r.Drive.Progress = (double)(b - startBlock) / totalProgresBlocks;
                Progress = (double)currentUpdateBlocks / totalUpdateBlocks;
                if (cancel)
                  return false;
              }

              FlushTempParity(r.Drive, change);

            }
            catch (Exception e) {
              env.LogCrash(e);
              FireErrorMessage(String.Format("Error removing {0}: {1}", r.FullPath, e.Message));
              return false;
            }
            }
            r.Drive.RemoveFile(r);
            r.Drive.SaveFileList();
            success = true;
              }
              finally {
            if (!success)
              r.Drive.RestoreMetaFile(); // restore the backup filesX.dat created by BackupMetaFile()
              }
              return true;
        }