public static TrrntZipStatus ReZipFiles(List <ZippedFile> zippedFiles, ICompress originalZipFile, byte[] buffer, StatusCallback StatusCallBack, LogCallback LogCallback, int ThreadID) { int bufferSize = buffer.Length; string filename = originalZipFile.ZipFilename; string tmpFilename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename) + ".tmp"; string outfilename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename) + ".zip"; if (Path.GetExtension(filename) == ".7z") { if (File.Exists(outfilename)) { LogCallback?.Invoke(ThreadID, "Error output .zip file already exists"); return(TrrntZipStatus.RepeatFilesFound); } } if (IO.File.Exists(tmpFilename)) { IO.File.Delete(tmpFilename); } ICompress zipFileOut = new ZipFile(); try { zipFileOut.ZipFileCreate(tmpFilename); // by now the zippedFiles have been sorted so just loop over them for (int i = 0; i < zippedFiles.Count; i++) { StatusCallBack?.Invoke(ThreadID, (int)((double)(i + 1) / (zippedFiles.Count) * 100)); ZippedFile t = zippedFiles[i]; if (Program.VerboseLogging) { LogCallback?.Invoke(ThreadID, $"{t.Size,15} {t.StringCRC} {t.Name}"); } Stream readStream = null; ulong streamSize = 0; ushort compMethod; ZipFile z = originalZipFile as ZipFile; ZipReturn zrInput = ZipReturn.ZipUntested; if (z != null) { zrInput = z.ZipFileOpenReadStream(t.Index, false, out readStream, out streamSize, out compMethod); } SevenZ z7 = originalZipFile as SevenZ; if (z7 != null) { zrInput = z7.ZipFileOpenReadStream(t.Index, out readStream, out streamSize); } Stream writeStream; ZipReturn zrOutput = zipFileOut.ZipFileOpenWriteStream(false, true, t.Name, streamSize, 8, out writeStream); if (zrInput != ZipReturn.ZipGood || zrOutput != ZipReturn.ZipGood) { //Error writing local File. zipFileOut.ZipFileClose(); originalZipFile.ZipFileClose(); IO.File.Delete(tmpFilename); return(TrrntZipStatus.CorruptZip); } Stream crcCs = new CrcCalculatorStream(readStream, true); ulong sizetogo = streamSize; while (sizetogo > 0) { int sizenow = sizetogo > (ulong)bufferSize ? bufferSize : (int)sizetogo; crcCs.Read(buffer, 0, sizenow); writeStream.Write(buffer, 0, sizenow); sizetogo = sizetogo - (ulong)sizenow; } writeStream.Flush(); crcCs.Close(); if (z != null) { originalZipFile.ZipFileCloseReadStream(); } uint crc = (uint)((CrcCalculatorStream)crcCs).Crc; if (crc != t.CRC) { return(TrrntZipStatus.CorruptZip); } zipFileOut.ZipFileCloseWriteStream(t.ByteCRC); } zipFileOut.ZipFileClose(); originalZipFile.ZipFileClose(); IO.File.Delete(filename); IO.File.Move(tmpFilename, outfilename); return(TrrntZipStatus.ValidTrrntzip); } catch (Exception) { zipFileOut?.ZipFileCloseFailed(); originalZipFile?.ZipFileClose(); return(TrrntZipStatus.CorruptZip); } }
public static TrrntZipStatus CheckZipFiles(ref List <ZippedFile> zippedFiles) { TrrntZipStatus tzStatus = TrrntZipStatus.Unknown; // ***************************** RULE 1 ************************************* // Directory separator should be a '/' a '\' is invalid and should be replaced with '/' // // check if any '\' = 92 need converted to '/' = 47 // this needs done before the sort, so that the sort is correct. // return BadDirectorySeparator if errors found. bool error1 = false; foreach (ZippedFile t in zippedFiles) { char[] bytes = t.Name.ToCharArray(); bool fixDir = false; for (int j = 0; j < bytes.Length; j++) { if (bytes[j] != 92) { continue; } fixDir = true; bytes[j] = (char)47; tzStatus |= TrrntZipStatus.BadDirectorySeparator; if (!error1 && Program.VerboseLogging) { error1 = true; Console.WriteLine("Incorrect directory separator found"); } } if (fixDir) { t.Name = new string(bytes); } } // ***************************** RULE 2 ************************************* // All Files in a torrentzip should be sorted with a lower case file compare. // // if needed sort the files correctly, and return Unsorted if errors found. bool error2 = false; bool thisSortFound = true; while (thisSortFound) { thisSortFound = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { int c = TrrntZipStringCompare(zippedFiles[i].Name, zippedFiles[i + 1].Name); if (c > 0) { ZippedFile T = zippedFiles[i]; zippedFiles[i] = zippedFiles[i + 1]; zippedFiles[i + 1] = T; tzStatus |= TrrntZipStatus.Unsorted; thisSortFound = true; if (!error2 && Program.VerboseLogging) { error2 = true; Console.WriteLine("Incorrect file order found"); } } } } // ***************************** RULE 3 ************************************* // Directory marker files are only needed if they are empty directories. // // now that the files are sorted correctly, we can see if there are unneeded // directory files, by first finding directory files (these end in a '\' character ascii 92) // and then checking if the next file is a file in that found directory. // If we find this 2 entry pattern (directory followed by file in that directory) // then the directory entry should not be present and the torrentzip is incorrect. // return ExtraDirectoryEnteries if error is found. bool error3 = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { // check if this is a directory entry if (zippedFiles[i].Name[zippedFiles[i].Name.Length - 1] != 47) { continue; } // check if the next filename is shorter or equal to this filename. // if it is shorter or equal it cannot be a file in the directory. if (zippedFiles[i + 1].Name.Length <= zippedFiles[i].Name.Length) { continue; } // check if the directory part of the two file enteries match // if they do we found an incorrect directory entry. bool delete = true; for (int j = 0; j < zippedFiles[i].Name.Length; j++) { if (zippedFiles[i].Name[j] != zippedFiles[i + 1].Name[j]) { delete = false; break; } } // we found an incorrect directory so remove it. if (delete) { zippedFiles.RemoveAt(i); tzStatus |= TrrntZipStatus.ExtraDirectoryEnteries; if (!error3 && Program.VerboseLogging) { error3 = true; Console.WriteLine("Un-needed directory records found"); } i--; } } // check for repeat files bool error4 = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { if (zippedFiles[i].Name == zippedFiles[i + 1].Name) { tzStatus |= TrrntZipStatus.RepeatFilesFound; if (!error4 && Program.VerboseLogging) { error4 = true; Console.WriteLine("Duplcate file enteries found"); } } } return(tzStatus); }