// Open the source file, compute the MD5 Hash of the whole file and the first // 16k of the file, and then compute the FileId and store the results // in a file description packet and a file verification packet. public bool Open(string filename, ulong blocksize, bool deferhashcomputation) { // Get the filename and filesize targetfilename = filename; filesize = (ulong)new FileInfo(filename).Length; // Work out how many blocks the file will be sliced into blockcount = (uint)((filesize + blocksize - 1) / blocksize); // Determine what filename to record in the PAR2 files parfilename = Path.GetFileName(filename); // Create the Description and Verification packets FileDescriptionPacket = Packets.FileDescriptionPacket.Create(parfilename, filesize); FileVerificationPacket = Packets.FileVerificationPacket.Create(blockcount); // Create the diskfile object targetfile = new DiskFile(); // Open the source file if (!targetfile.Open(targetfilename, filesize)) { return(false); } // Do we want to defer the computation of the full file hash, and // the block crc and hashes. This is only permitted if there // is sufficient memory available to create all recovery blocks // in one pass of the source files (i.e. chunksize == blocksize) if (deferhashcomputation) { // Initialise a buffer to read the first 16k of the source file uint buffersize = Math.Min((uint)filesize, 16 * 1024); byte[] buffer = new byte[buffersize]; // Read the data from the file if (!targetfile.Read(0, buffer, buffersize)) { targetfile.Close(); return(false); } // Compute the hash of the data read from the file // Store the hash in the descriptionpacket and compute the file id MD5 md5Hasher = MD5.Create(); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer); // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); //// Allocate an MD5 context for computing the file hash //// during the recovery data generation phase contextfull = MD5.Create(); //contextfull = new MD5Context; } else { // Compute 16k MD5 hash using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5Hasher = MD5.Create(); byte[] buffer16k = br.ReadBytes(16 * 1024); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer16k); } // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); // Compute full file MD5 hash & block CRC32 and MD5 hashes //long readSize = 5 * (long)blocksize; long readSize = (long)blocksize; long fileSize = new FileInfo(filename).Length; long nbSteps = fileSize / readSize; long remaining = fileSize % readSize; uint blocknumber = 0; // TODO : switch to async filestream using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5FullHasher = MD5.Create(); MD5 md5Hasher = MD5.Create(); //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32(blocksize); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance(blocksize); byte[] blockHash = new byte[16]; uint blockCRC32 = 0; for (int i = 0; i < nbSteps + 1; ++i) { byte[] buffer = br.ReadBytes((int)(i == nbSteps ? remaining : readSize)); // Global MD5 hash if (i == nbSteps) { md5FullHasher.TransformFinalBlock(buffer, 0, buffer.Length); } else { md5FullHasher.TransformBlock(buffer, 0, buffer.Length, null, 0); } //for (uint j = 0; j < 5; ++j) //{ // Block MD5 hash & CRC32 uint length = (uint)blocksize; //if (i == nbSteps && j == 4) //if (i == nbSteps && (buffer.Length - (uint)(j * blocksize)) < (int)blocksize) if (i == nbSteps && remaining != 0) { // We need arry padding since calculation **MUST** always be done on blocksize-length buffers byte[] smallBuffer = buffer; buffer = new byte[blocksize]; Buffer.BlockCopy(smallBuffer, 0, buffer, 0, smallBuffer.Length); } blockCRC32 = crc32.CRCUpdateBlock(0xFFFFFFFF, (uint)blocksize, buffer, 0) ^ 0xFFFFFFFF; blockHash = md5Hasher.ComputeHash(buffer, 0, (int)blocksize); //Console.WriteLine("blocknumber:{0},hash:{1},crc32:{2}", blocknumber, blockHash, blockCRC32); FileVerificationPacket.SetBlockHashAndCRC(blocknumber++, blockHash, blockCRC32); //} } FileDescriptionPacket.hashfull = md5FullHasher.Hash; } } return(true); }
// Open the source file, compute the MD5 Hash of the whole file and the first // 16k of the file, and then compute the FileId and store the results // in a file description packet and a file verification packet. public bool Open(string filename, ulong blocksize, bool deferhashcomputation) { // Get the filename and filesize targetfilename = filename; filesize = (ulong)new FileInfo(filename).Length; // Work out how many blocks the file will be sliced into blockcount = (uint)((filesize + blocksize - 1) / blocksize); // Determine what filename to record in the PAR2 files parfilename = Path.GetFileName(filename); // Create the Description and Verification packets FileDescriptionPacket = Packets.FileDescriptionPacket.Create(parfilename, filesize); FileVerificationPacket = Packets.FileVerificationPacket.Create(blockcount); // Create the diskfile object targetfile = new DiskFile(); // Open the source file if (!targetfile.Open(targetfilename, filesize)) return false; // Do we want to defer the computation of the full file hash, and // the block crc and hashes. This is only permitted if there // is sufficient memory available to create all recovery blocks // in one pass of the source files (i.e. chunksize == blocksize) if (deferhashcomputation) { // Initialise a buffer to read the first 16k of the source file uint buffersize = Math.Min((uint)filesize, 16 * 1024); byte[] buffer = new byte[buffersize]; // Read the data from the file if (!targetfile.Read(0, buffer, buffersize)) { targetfile.Close(); return false; } // Compute the hash of the data read from the file // Store the hash in the descriptionpacket and compute the file id MD5 md5Hasher = MD5.Create(); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer); // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); //// Allocate an MD5 context for computing the file hash //// during the recovery data generation phase contextfull = MD5.Create(); //contextfull = new MD5Context; } else { // Compute 16k MD5 hash using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5Hasher = MD5.Create(); byte[] buffer16k = br.ReadBytes(16 * 1024); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer16k); } // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); // Compute full file MD5 hash & block CRC32 and MD5 hashes //long readSize = 5 * (long)blocksize; long readSize = (long)blocksize; long fileSize = new FileInfo(filename).Length; long nbSteps = fileSize / readSize; long remaining = fileSize % readSize; uint blocknumber = 0; // TODO : switch to async filestream using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5FullHasher = MD5.Create(); MD5 md5Hasher = MD5.Create(); //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32(blocksize); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance(blocksize); byte[] blockHash = new byte[16]; uint blockCRC32 = 0; for (int i = 0; i < nbSteps + 1; ++i) { byte[] buffer = br.ReadBytes((int)(i == nbSteps ? remaining : readSize)); // Global MD5 hash if (i == nbSteps) md5FullHasher.TransformFinalBlock(buffer, 0, buffer.Length); else md5FullHasher.TransformBlock(buffer, 0, buffer.Length, null, 0); //for (uint j = 0; j < 5; ++j) //{ // Block MD5 hash & CRC32 uint length = (uint)blocksize; //if (i == nbSteps && j == 4) //if (i == nbSteps && (buffer.Length - (uint)(j * blocksize)) < (int)blocksize) if (i == nbSteps && remaining != 0) { // We need arry padding since calculation **MUST** always be done on blocksize-length buffers byte[] smallBuffer = buffer; buffer = new byte[blocksize]; Buffer.BlockCopy(smallBuffer, 0, buffer, 0, smallBuffer.Length); } blockCRC32 = crc32.CRCUpdateBlock(0xFFFFFFFF, (uint)blocksize, buffer, 0) ^ 0xFFFFFFFF; blockHash = md5Hasher.ComputeHash(buffer, 0, (int)blocksize); //Console.WriteLine("blocknumber:{0},hash:{1},crc32:{2}", blocknumber, blockHash, blockCRC32); FileVerificationPacket.SetBlockHashAndCRC(blocknumber++, blockHash, blockCRC32); //} } FileDescriptionPacket.hashfull = md5FullHasher.Hash; } } return true; }
internal void Close() { targetfile.Close(); }