private byte[] md5Zeros; // 16 bytes of zeros used for writing MD5 placeholder //--------------------------------------------------------------------- // Implementation Note // // The QueuedMsgInfo.ProviderData property is set to the fully // path to the message's file and the PersistID is the message's ID. /// <summary> /// Constructor. /// </summary> /// <param name="messageFolder">The path to the folder where the messages files will be located.</param> public MsgQueueFileStore(string messageFolder) { this.messages = null; this.fsIndex = null; this.root = Helper.AddTrailingSlash(Path.GetFullPath(messageFolder)); this.md5Zeros = new byte[MD5Hasher.DigestSize]; }
/// <summary> /// Updates a message file's metadata. /// </summary> /// <param name="path">The file path.</param> /// <param name="msgInfo">The message metadata.</param> internal void WriteMessageMetadata(string path, QueuedMsgInfo msgInfo) { using (var fsMsg = new EnhancedFileStream(path, FileMode.Open, FileAccess.ReadWrite)) { // Seek past the message's header and body. int cbBody; byte[] md5Hash; fsMsg.Position = MsgHeaderSize; cbBody = fsMsg.ReadInt32(); fsMsg.Position = fsMsg.Position + cbBody; // Write the metadata and truncate the file. fsMsg.WriteString16(msgInfo.ToString()); fsMsg.SetLength(fsMsg.Position); // Regenerate the MD5 Hash fsMsg.Position = MsgMD5Offset + MD5Hasher.DigestSize; md5Hash = MD5Hasher.Compute(fsMsg, fsMsg.Length - fsMsg.Position); fsMsg.Position = MsgMD5Offset; fsMsg.WriteBytesNoLen(md5Hash); } }
private void WriteFile(string path, byte[] data) { var es = new EnhancedFileStream(path, FileMode.Create); es.WriteBytesNoLen(data); es.Close(); }
/// <summary> /// Writes a message file. /// </summary> /// <param name="path">The file path.</param> /// <param name="msg">The message.</param> /// <param name="msgInfo">The message metadata.</param> internal void WriteMessage(string path, QueuedMsg msg, QueuedMsgInfo msgInfo) { byte[] md5Hash; using (var fsMsg = new EnhancedFileStream(path, FileMode.Create, FileAccess.ReadWrite)) { // Write the file header fsMsg.WriteInt32(MsgMagic); // Magic Number fsMsg.WriteInt32(0); // Format Version fsMsg.WriteInt32(0); // Reserved fsMsg.WriteBytesNoLen(md5Zeros); // MD5 hash placeholder // Write the message body. fsMsg.WriteBytes32(msg.BodyRaw); // Write the metadata. fsMsg.WriteString16(msgInfo.ToString()); // Compute and save the MD5 hash fsMsg.Position = MsgHeaderSize; md5Hash = MD5Hasher.Compute(fsMsg, fsMsg.Length - fsMsg.Position); fsMsg.Position = MsgMD5Offset; fsMsg.WriteBytesNoLen(md5Hash); } }
private static int Hash(string fileName) { try { byte[] hash; using (EnhancedStream es = new EnhancedFileStream(fileName, FileMode.Open, FileAccess.Read)) { hash = MD5Hasher.Compute(es, es.Length); } using (StreamWriter writer = new StreamWriter(fileName + ".md5", false, Helper.AnsiEncoding)) { writer.WriteLine("MD5={0}", Helper.ToHex(hash)); } File.Copy(fileName, fileName + ".setup"); return(0); } catch (Exception e) { Program.Error("Error ({0}): {1}", e.GetType().Name, e.Message); return(1); } }
private void CompareFiles(string path1, string path2) { EnhancedFileStream es1 = null; EnhancedFileStream es2 = null; try { es1 = new EnhancedFileStream(path1, FileMode.Open, FileAccess.Read); es2 = new EnhancedFileStream(path2, FileMode.Open, FileAccess.Read); Assert.AreEqual(es1.Length, es2.Length); CollectionAssert.AreEqual(MD5Hasher.Compute(es1, es1.Length), MD5Hasher.Compute(es2, es2.Length)); } finally { if (es1 != null) { es1.Close(); } if (es2 != null) { es2.Close(); } } }
private OperationLogMode mode; // The current mode /// <summary> /// Opens or creates a file operation log file. /// </summary> /// <param name="path">The path to the log file.</param> /// <param name="transactionID">The log's transaction <see cref="Guid" />.</param> /// <remarks> /// New logs will be created in <see cref="OperationLogMode.Undo" /> mode. /// </remarks> public FileOperationLog(string path, Guid transactionID) { this.path = Path.GetFullPath(path); this.file = new EnhancedFileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite); if (file.Length == 0) { // Initialize a new file file.WriteInt32(Magic); file.WriteInt32(0); file.WriteInt32(0); file.WriteInt32((int)OperationLogMode.Undo); file.WriteBytesNoLen(transactionID.ToByteArray()); file.Flush(); } else { // Open an existing file. try { if (file.ReadInt32() != Magic || // Magic number file.ReadInt32() != 0) { // Format Versopn throw new Exception(); } file.ReadInt32(); // Reserved switch (file.ReadInt32()) // Mode { case (int)OperationLogMode.Undo: mode = OperationLogMode.Undo; break; case (int)OperationLogMode.Redo: mode = OperationLogMode.Redo; break; default: throw new Exception(); } this.transactionID = new Guid(file.ReadBytes(16)); if (transactionID != this.transactionID) { throw new Exception(); } } catch { throw new TransactionException(CorruptMsg); } } }
/// <summary> /// Reads the metadata from a message file. /// </summary> /// <param name="msgID">The message ID.</param> /// <param name="path">Fully qualified path to the message file.</param> /// <returns>The <see cref="QueuedMsgInfo" />.</returns> internal QueuedMsgInfo ReadMessageMetadata(Guid msgID, string path) { QueuedMsgInfo msgInfo; int cbBody; byte[] md5Hash; long savePos; using (var fsMsg = new EnhancedFileStream(path, FileMode.Open, FileAccess.ReadWrite)) { try { // Read the message file header if (fsMsg.ReadInt32() != MsgMagic) // Magic Number { throw new Exception(); } if (fsMsg.ReadInt32() != 0) // Format Version { throw new Exception(); } fsMsg.ReadInt32(); // Reserved // Verify that the MD5 hash saved in then file matches the // hash computed for the remainder of the file as it exists // right now. md5Hash = fsMsg.ReadBytes(MD5Hasher.DigestSize); savePos = fsMsg.Position; if (!Helper.ArrayEquals(md5Hash, MD5Hasher.Compute(fsMsg, fsMsg.Length - fsMsg.Position))) { throw new FormatException(string.Format("Message file [{0}] is corrupt. MD5 digests do not match.", path)); } fsMsg.Position = savePos; // Skip over the message body data cbBody = fsMsg.ReadInt32(); fsMsg.Position = fsMsg.Position + cbBody; // Read the metadata and add the provider specific information msgInfo = new QueuedMsgInfo(fsMsg.ReadString16()); msgInfo.PersistID = msgInfo.ID; msgInfo.ProviderData = path; return(msgInfo); } catch { throw new FormatException(string.Format("Bad message file [{0}].", path)); } } }
private void GetFileInfo(string fileName, out int size, out byte[] md5) { using (var es = new EnhancedFileStream(tempFolder + "\\" + fileName, FileMode.Open, FileAccess.Read)) { size = (int)es.Length; md5 = MD5Hasher.Compute(es, size); } }
public override void SendResponseFromFile(IntPtr handle, long offset, long length) { using (var fsSrc = new EnhancedFileStream(new SafeFileHandle(handle, false), FileAccess.Read)) { fsSrc.Position = offset; fsSrc.CopyTo(context.Response.OutputStream, (int)length); } }
public override void SendResponseFromFile(string filename, long offset, long length) { using (var fsSrc = new EnhancedFileStream(filename, FileMode.Open, FileAccess.Read)) { fsSrc.Position = offset; fsSrc.CopyTo(context.Response.OutputStream, (int)length); } }
/// <summary> /// Extracts files from a ZIP archive file. /// </summary> /// <param name="zipPath">Path to the input ZIP archive.</param> /// <param name="targetFolder">Path to the output folder.</param> /// <param name="createFolder">Pass <c>true</c> to place the output in a subfolder named for the ZIP archive.</param> public static void Unzip(string zipPath, string targetFolder, bool createFolder) { ZipFile archive = null; string outPath; try { archive = new ZipFile(zipPath); outPath = targetFolder; if (createFolder) { outPath = Path.Combine(outPath, Helper.GetFileNameWithoutExtension(zipPath)); } foreach (ZipEntry entry in archive) { Stream inStream = null; EnhancedStream outStream = null; string outFile; outFile = Path.Combine(outPath, entry.Name); Helper.CreateFileTree(outFile); try { inStream = archive.GetInputStream(entry); outStream = new EnhancedFileStream(outFile, FileMode.Create, FileAccess.ReadWrite); outStream.CopyFrom(inStream, -1); } finally { if (inStream != null) { inStream.Close(); } if (outStream != null) { outStream.Close(); } File.SetCreationTime(outFile, entry.DateTime); File.SetLastWriteTime(outFile, entry.DateTime); } } } finally { if (archive != null) { archive.Close(); } } }
public void SecureFile_File_Validate() { string originalName = Path.GetTempFileName(); string encryptName = Path.GetTempFileName(); string privateKey = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024); string publicKey = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey); EnhancedStream original = null; EnhancedStream encrypted = null; SecureFile secure = null; byte b; try { original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite); for (int i = 0; i < 100; i++) { original.WriteByte((byte)i); } original.Close(); original = null; secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey); secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256); secure.Close(); secure = null; Assert.IsTrue(SecureFile.Validate(encryptName, privateKey)); encrypted = new EnhancedFileStream(encryptName, FileMode.Open, FileAccess.ReadWrite); encrypted.Position = encrypted.Length - 1; b = (byte)encrypted.ReadByte(); encrypted.Position = encrypted.Length - 1; encrypted.WriteByte((byte)(~b)); encrypted.Close(); Assert.IsFalse(SecureFile.Validate(encryptName, privateKey)); } finally { if (original != null) { original.Close(); } if (encrypted != null) { encrypted.Close(); } System.IO.File.Delete(originalName); System.IO.File.Delete(encryptName); } }
//--------------------------------------------------------------------- // Static members /// <summary> /// Verifies that a log file is not corrupt. /// </summary> /// <param name="path">The path to the log file.</param> /// <param name="transactionID">Returns as the file's transaction <see cref="Guid" />.</param> /// <returns><c>true</c> if the log file is valid, <c>false</c> if it is corrupt.</returns> public static bool Validate(string path, out Guid transactionID) { int cb; try { using (var file = new EnhancedFileStream(path, FileMode.Open, FileAccess.ReadWrite)) { if (file.ReadInt32() != Magic || // Magic number file.ReadInt32() != 0) { // Format Versopn throw new Exception(); } switch (file.ReadInt32()) // Mode { case (int)OperationLogMode.Undo: case (int)OperationLogMode.Redo: break; default: throw new Exception(); } file.ReadInt32(); // Reserved transactionID = new Guid(file.ReadBytes(16)); while (!file.Eof) { if (file.ReadInt32() != Magic) { throw new Exception(); } cb = file.ReadInt32(); if (cb < 0 || cb + file.Position > file.Length) { throw new Exception(); } file.Position += cb; } return(true); } } catch { transactionID = Guid.Empty; return(false); } }
/// <summary> /// Closes the log file if it's open. /// </summary> public void Close() { using (TimedLock.Lock(this)) { if (file != null) { file.Close(); file = null; } } }
public void AppPackage_MD5() { string tempPath = GetTempFileName(); string tempDir = Helper.AddTrailingSlash(Path.GetTempPath()); AppPackage package = null; MemoryStream ms; byte[] md5; try { package = AppPackage.Create(tempPath, AppRef.Parse("appref://myapps/mypackage.zip?version=1.2.3.4"), @" LaunchType = Test.MyType:MyAssembly.dll; LaunchMethod = Foo; LaunchArgs = Bar; "); using (ms = new MemoryStream(4096)) { for (int i = 0; i < 4096; i++) { ms.WriteByte((byte)i); } ms.Position = 0; package.AddFile("Test.dat", ms); } package.Close(); package = null; // Verify that a MD5 hash computed manually on the package file jibes // with what AppPackage computes. using (var fs = new EnhancedFileStream(tempPath, FileMode.Open, FileAccess.Read)) { md5 = MD5Hasher.Compute(fs, fs.Length); } package = AppPackage.Open(tempPath); CollectionAssert.AreEqual(md5, package.MD5); package.Close(); package = null; } finally { if (package != null) { package.Close(); } Delete(tempPath); } }
/// <summary> /// Closes the store, releasing any resources. /// </summary> public void Close() { if (fsIndex != null) { SaveIndex(false); fsIndex.Close(); fsIndex = null; } messages = null; }
/// <summary> /// Opens the store, preparing it for reading and writing messages and /// metadata to the backing store. /// </summary> public void Open() { bool newIndexFile; using (TimedLock.Lock(this)) { if (this.messages != null) { throw new InvalidOperationException("Message store is already open."); } indexPath = root + "messages.index"; Helper.CreateFileTree(indexPath); newIndexFile = !File.Exists(indexPath); fsIndex = new EnhancedFileStream(indexPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); LoadIndex(newIndexFile); } }
/// <summary> /// Queues an email message for deliver, /// </summary> /// <param name="message">The outbound message.</param> /// <remarks> /// <note> /// This message will do nothing but log a warning if the agent was started /// with a <b>Any</b> network binding. /// </note> /// </remarks> public void Enqueue(MailMessage message) { // Generate a unique file name that will sort roughly in the order // that the messages were added to the queue so that messages were // are delivered to the relay server in rougly the order that the // were queued. string fileName = string.Format("{0}-{1}.msg", Helper.ToIsoDate(DateTime.UtcNow).Replace(':', '-'), Guid.NewGuid()); if (smtpServer.IsAny) { // Email transmission is disabled SysLog.LogWarning("Email transmission is disabled."); return; } using (var output = new EnhancedFileStream(Path.Combine(queueFolder, fileName), FileMode.Create, FileAccess.ReadWrite)) MailHelper.WriteMessage(output, message); }
/// <summary> /// Writes the index file. /// </summary> /// <param name="path">The target file path.</param> /// <param name="phrases">The phrases to be written.</param> private void SaveIndexTo(string path, Phrase[] phrases) { using (var fs = new EnhancedFileStream(path, FileMode.Create)) { fs.WriteInt32(Magic); fs.WriteInt32(phrases.Length); foreach (var phrase in phrases) { fs.WriteString16(phrase.PhraseType.ToString()); fs.WriteString32(phrase.Text); fs.WriteString16(phrase.Voice); fs.WriteString16(phrase.ActualVoice); fs.WriteString16(phrase.Encoding.ToString()); fs.WriteString16(phrase.SampleRate.ToString()); fs.WriteInt64(phrase.LastAccessUtc.Ticks); fs.WriteString16(phrase.Path); } } }
public void SecureFile_File_BadHash() { string originalName = Path.GetTempFileName(); string encryptName = Path.GetTempFileName(); string decryptName = Path.GetTempFileName(); string privateKey = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024); string publicKey = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey); EnhancedStream original = null; EnhancedStream encrypted = null; SecureFile secure = null; byte b; try { original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite); for (int i = 0; i < 100; i++) { original.WriteByte((byte)i); } original.Close(); original = null; secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey); secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256); secure.Close(); secure = null; // Munge the last byte of the hash digest and then confirm // that the bad hash is detected. encrypted = new EnhancedFileStream(encryptName, FileMode.Open, FileAccess.ReadWrite); encrypted.Position = encrypted.Length - 1; b = (byte)encrypted.ReadByte(); encrypted.Position = encrypted.Length - 1; encrypted.WriteByte((byte)(~b)); encrypted.Close(); encrypted = null; ExtendedAssert.Throws <CryptographicException>( () => { secure = new SecureFile(encryptName, SecureFileMode.Decrypt, privateKey); secure.DecryptTo(decryptName); }); } finally { if (original != null) { original.Close(); } if (encrypted != null) { encrypted.Close(); } try { System.IO.File.Delete(originalName); } catch { } try { System.IO.File.Delete(encryptName); } catch { } try { System.IO.File.Delete(decryptName); } catch { } } }
public void MsgQueueFileStore_Corrupt_Messages() { MsgQueueFileStore store = null; int count; QueuedMsgInfo msgInfo; QueuedMsg msg; object persistID; Guid[] ids; Dictionary <Guid, bool> corruptIDs; List <string> corruptFiles; // Create a store with a bunch of messages then close // it and corrupt some of the message files. Then attempt // to open the files and verify that the corrupted files // are detected. ClearFolders(); try { store = new MsgQueueFileStore(root); store.Open(); ids = new Guid[MessageCount]; for (int i = 0; i < MessageCount; i++) { msg = new QueuedMsg(); msg.TargetEP = "logical://test/" + i.ToString(); msg.Body = i; msgInfo = new QueuedMsgInfo(null, msg); store.Add(msgInfo, msg); ids[i] = msg.ID; } Assert.AreEqual(MessageCount, store.Count); count = 0; foreach (QueuedMsgInfo i in store) { count++; } Assert.AreEqual(MessageCount, count); for (int i = 0; i < ids.Length; i++) { Guid id = ids[i]; persistID = store.GetPersistID(id); Assert.IsNotNull(persistID); msgInfo = store.GetInfo(persistID); Assert.IsNotNull(msgInfo); Assert.AreEqual((MsgEP)("logical://test/" + i.ToString()), msgInfo.TargetEP); msg = store.Get(persistID); msg.DeserializedBody(); Assert.AreEqual(i, (int)msg.Body); } // Corrupt 1/2 of the message files in various ways. corruptIDs = new Dictionary <Guid, bool>(); corruptFiles = new List <string>(); for (int i = 0; i < MessageCount / 2; i++) { corruptIDs.Add(ids[i], true); corruptFiles.Add(store.GetMessagePath(ids[i], false)); } int cbTruncate = 0; for (int i = 0; i < corruptFiles.Count; i++) { string file = corruptFiles[i]; using (EnhancedFileStream fs = new EnhancedFileStream(file, FileMode.Open, FileAccess.ReadWrite)) { if ((i & 1) == 0) { // Truncate the file by at least one byte int cb; cb = Math.Min((int)fs.Length - 1, cbTruncate++); fs.SetLength(cb); } else { // Mess with a byte at random position in the file. int pos = Helper.Rand((int)fs.Length); byte b; fs.Position = pos; b = (byte)fs.ReadByte(); fs.Position = pos; fs.WriteByte((byte)(~b)); } } } // Load all of the message files and verify that the corrupt files // are detected. for (int i = 0; i < ids.Length; i++) { Guid id = ids[i]; if (corruptIDs.ContainsKey(id)) { try { persistID = store.GetPersistID(id); Assert.IsNotNull(persistID); msgInfo = store.GetInfo(persistID); Assert.IsNotNull(msgInfo); Assert.AreEqual((MsgEP)("logical://test/" + i.ToString()), msgInfo.TargetEP); msg = store.Get(persistID); Assert.Fail("Exception expected"); } catch { // Expecting an exception } } else { persistID = store.GetPersistID(id); Assert.IsNotNull(persistID); msgInfo = store.GetInfo(persistID); Assert.IsNotNull(msgInfo); Assert.AreEqual((MsgEP)("logical://test/" + i.ToString()), msgInfo.TargetEP); msg = store.Get(persistID); msg.DeserializedBody(); Assert.AreEqual(i, (int)msg.Body); } } } finally { if (store != null) { store.Close(); } } }
/// <summary> /// Loads the cache index file. /// </summary> private void LoadIndex() { var indexPath = Path.Combine(settings.PhraseCacheFolder, IndexFileName); try { if (!File.Exists(indexPath)) { // No index exists yet, so create an empty one. SaveIndex(false); return; } using (var fs = new EnhancedFileStream(indexPath, FileMode.Open)) { int count; if (fs.ReadInt32() != Magic) { throw new SwitchException("[PhraseCache] cannot read index file [{0}] due to an invalid magic number. The existing cache will be purged.", indexPath); } count = fs.ReadInt32(); for (int i = 0; i < count; i++) { string text; string voice; string actualVoice; PhraseType phraseType; TtsEncoding encoding; TtsSampleRate rate; DateTime lastAccessUtc; string path; Phrase phrase; phraseType = (PhraseType)Enum.Parse(typeof(PhraseType), fs.ReadString16()); text = fs.ReadString32(); voice = fs.ReadString16(); actualVoice = fs.ReadString16(); encoding = (TtsEncoding)Enum.Parse(typeof(TtsEncoding), fs.ReadString16()); rate = (TtsSampleRate)Enum.Parse(typeof(TtsSampleRate), fs.ReadString16()); lastAccessUtc = new DateTime(fs.ReadInt64()); path = fs.ReadString16(); phrase = new Phrase(phraseType, voice, encoding, rate, text) { Path = path, ActualVoice = actualVoice, LastAccessUtc = lastAccessUtc, }; index[GetCacheKey(phrase)] = phrase; } } } catch (Exception e) { // We're going to handle all exceptions leaving the loaded phrase // table empty. This will have the effect of starting the cache // from scratch. Eventually, all of the existing files will be // purged and the presumably bad index file will be overwritten. index.Clear(); SysLog.LogException(e); } }
/// <summary> /// Handles the actual email transmission from the queue. /// </summary> /// <param name="state">Not used.</param> private void OnQueueTimer(object state) { try { string[] messageFiles = Helper.GetFilesByPattern(Path.Combine(queueFolder, "*.*"), SearchOption.TopDirectoryOnly); if (messageFiles.Length == 0) { return; } foreach (string messagePath in messageFiles) { MailMessage message; if (queueTimer == null) { break; // The agent is no longer running. } try { using (var input = new EnhancedFileStream(messagePath, FileMode.Open)) { try { message = MailHelper.ReadMessage(input); } catch (Exception e) { // Delete messages that could not be deserialized. SysLog.LogException(e); Helper.DeleteFile(messagePath); continue; } } } catch (IOException) { continue; // Ignore files that may be locked for writing } try { smtp.Send(message); Helper.DeleteFile(messagePath); } catch (SmtpException e) { // Delete messages that couldn't be delivered due to non-transient // problems with the destination mailbox. These errors won't typically // occur when we're fowarding mail to a pure relay server but may // occur if the relay server may also host actual mailboxes. switch (e.StatusCode) { case SmtpStatusCode.MailboxUnavailable: SysLog.LogWarning("MailAgent: {0}", e.Message); Helper.DeleteFile(messagePath); break; } } catch (Exception e) { // Abort all transmissions for the remaining exceptions types. SysLog.LogException(e); break; } } } catch (Exception e) { SysLog.LogException(e); } }
public void Package_AddFile() { Package package; EnhancedStream fs; EnhancedMemoryStream es = new EnhancedMemoryStream(); PackageEntry entry; byte[] buf; string inputFile; string outputFile; inputFile = Path.GetTempFileName(); outputFile = Path.GetTempFileName(); try { buf = new byte[37000]; for (int i = 0; i < buf.Length; i++) { buf[i] = (byte)i; } fs = new EnhancedFileStream(inputFile, FileMode.OpenOrCreate); fs.WriteBytes32(buf); fs.Close(); //------------------------- package = new Package(); package.Create(es); entry = package.AddFile("/Foo/Bar/Test1.dat", inputFile); Assert.IsTrue(entry.IsFile); Assert.IsTrue(package["/Foo"].IsFolder); Assert.IsTrue(package["/Foo/Bar"].IsFolder); Assert.IsTrue(package["/Foo/Bar/Test1.dat"].IsFile); package.Close(true); //------------------------- package = new Package(es); Assert.IsTrue(entry.IsFile); Assert.IsTrue(package["/Foo"].IsFolder); Assert.IsTrue(package["/Foo/Bar"].IsFolder); Assert.IsTrue(package["/Foo/Bar/Test1.dat"].IsFile); package["/Foo/Bar/Test1.dat"].GetContents(outputFile); fs = new EnhancedFileStream(outputFile, FileMode.Open); try { CollectionAssert.AreEqual(buf, fs.ReadBytes32()); } finally { fs.Close(); } package.Close(); } finally { File.Delete(inputFile); File.Delete(outputFile); } }
/// <summary> /// Handles the installation of an application's configuration file. /// </summary> /// <param name="iniFile">The application INI file name (e.g. "MyApp.ini").</param> /// <remarks> /// <para> /// This method provides the mechanism by which setup won't overwrite /// user changes to an configuration file when installing an updated /// version of the application. The method compares the MD5 hash of the /// base version of the INI file to the hash of the currently installed /// INI file. If the hashes match, the installed version will be overwritten /// by the base version. If the hashes differ, then the user will be /// notified and given the opportunity to choose whether to overwrite /// the installed INI. In either case, any installed INI file will be /// backed up. /// </para> /// <para> /// This method assumes that the base version of the INI file is named /// <b><file>.ini.base</b> and the file with the base MD5 hash is /// named <b><file>.ini.md5</b>. The method generates a new MD5 /// file as necessary. /// </para> /// </remarks> public void InstallIniFile(string iniFile) { string baseFile = iniFile + ".base"; byte[] baseMD5; byte[] curMD5; if (!File.Exists(installIniFolder + baseFile)) { throw new IOException(string.Format("[{0}] file needs to be added to the setup project.", baseFile)); } if (!File.Exists(installIniFolder + iniFile)) { // No INI file exists, so simply copy the base file over and generate // the MD5 hash. File.Copy(installIniFolder + baseFile, installIniFolder + iniFile); using (EnhancedStream es = new EnhancedFileStream(installIniFolder + iniFile, FileMode.Open, FileAccess.Read)) { curMD5 = MD5Hasher.Compute(es, es.Length); } using (StreamWriter writer = new StreamWriter(installIniFolder + iniFile + ".md5", false, Helper.AnsiEncoding)) { writer.WriteLine("MD5={0}", Helper.ToHex(curMD5)); } return; } // Compute the MD5 hash for the existing file and compare it to the // hash for the original base file (if there is one). using (EnhancedFileStream es = new EnhancedFileStream(installIniFolder + iniFile, FileMode.Open, FileAccess.Read)) { curMD5 = MD5Hasher.Compute(es, es.Length); } try { using (var reader = new StreamReader(installIniFolder + iniFile + ".md5", Helper.AnsiEncoding)) { string line; line = reader.ReadLine(); if (line == null) { throw new Exception(); } if (!line.StartsWith("MD5=")) { throw new Exception(); } baseMD5 = Helper.FromHex(line.Substring(4)); } } catch { baseMD5 = new byte[0]; // The hashes will always differ if the MD5 file doesn't exist or isn't valid. } // Make a backup copy of the current INI file. File.Copy(installIniFolder + iniFile, installIniFolder + Helper.ToIsoDate(DateTime.UtcNow).Replace(':', '-') + "-" + iniFile); if (Helper.ArrayEquals(baseMD5, curMD5)) { // If the base and current MD5 hashes are the same, we can be assured that the // user has not customized the INI file. In this case, we'll simply overwrite // the existing INI file with the new version. File.Delete(installIniFolder + iniFile); File.Copy(installIniFolder + baseFile, installIniFolder + iniFile); } else { // It looks like the user has modified the INI file. So prompt the user // to see if he wants to overwrite or not. if (MessageBox.Show(string.Format("The application configuration file [{0}] has been customized.\r\n\r\nDo you want to overwrite this with the new version?", iniFile), setupTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes) { File.Delete(installIniFolder + iniFile); File.Copy(installIniFolder + baseFile, installIniFolder + iniFile); } } // Generate the MD5 hash file from the base INI file. using (var es = new EnhancedFileStream(installIniFolder + baseFile, FileMode.Open, FileAccess.Read)) { baseMD5 = MD5Hasher.Compute(es, es.Length); } using (var writer = new StreamWriter(installIniFolder + iniFile + ".md5", false, Helper.AnsiEncoding)) { writer.WriteLine("MD5={0}", Helper.ToHex(baseMD5)); } // Perform any macro replacements. if (iniMacroReplacements.Count > 0) { using (var fs = new EnhancedFileStream(installIniFolder + iniFile, FileMode.Open, FileAccess.ReadWrite)) { foreach (var replacement in iniMacroReplacements) { fs.Position = 0; Config.EditMacro(fs, Helper.AnsiEncoding, replacement.Key, replacement.Value); } } } }
public void SecureFile_File_Metadata() { string originalName = Path.GetTempFileName(); string encryptName = Path.GetTempFileName(); string decryptName = Path.GetTempFileName(); string privateKey = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024); string publicKey = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey); EnhancedStream original = null; EnhancedStream encrypted = null; EnhancedStream decrypted = null; SecureFile secure = null; DateTime createTime = Helper.UtcNowRounded - TimeSpan.FromMinutes(1); DateTime writeTime = Helper.UtcNowRounded; try { original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite); for (int i = 0; i < 100; i++) { original.WriteByte((byte)i); } original.Close(); original = null; Directory.SetCreationTimeUtc(originalName, createTime); Directory.SetLastWriteTimeUtc(originalName, writeTime); secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey); secure.Properties["Foo"] = "Bar"; secure.Properties["Hello"] = "World"; secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256); Assert.AreEqual(Path.GetFileName(originalName), secure.FileName); Assert.AreEqual(createTime, secure.CreateTimeUtc); Assert.AreEqual(writeTime, secure.WriteTimeUtc); secure.Close(); secure = null; secure = new SecureFile(encryptName, SecureFileMode.Decrypt, privateKey); Assert.AreEqual("Bar", secure.Properties["Foo"]); Assert.AreEqual("World", secure.Properties["Hello"]); Assert.AreEqual(Path.GetFileName(originalName), secure.FileName); Assert.AreEqual(createTime, secure.CreateTimeUtc); Assert.AreEqual(writeTime, secure.WriteTimeUtc); secure.DecryptTo(decryptName); secure.Close(); secure = null; Assert.AreEqual(createTime, Directory.GetCreationTimeUtc(decryptName)); Assert.AreEqual(writeTime, Directory.GetLastWriteTimeUtc(decryptName)); original = new EnhancedFileStream(originalName, FileMode.Open, FileAccess.Read); encrypted = new EnhancedFileStream(encryptName, FileMode.Open, FileAccess.Read); decrypted = new EnhancedFileStream(decryptName, FileMode.Open, FileAccess.Read); original.Position = 0; encrypted.Position = 0; Assert.AreNotEqual(original.ReadBytesToEnd(), encrypted.ReadBytesToEnd()); original.Position = 0; decrypted.Position = 0; CollectionAssert.AreEqual(original.ReadBytesToEnd(), decrypted.ReadBytesToEnd()); } finally { if (original != null) { original.Close(); } if (encrypted != null) { encrypted.Close(); } if (decrypted != null) { decrypted.Close(); } System.IO.File.Delete(originalName); System.IO.File.Delete(encryptName); System.IO.File.Delete(decryptName); } }
/// <summary> /// Executes the specified UNZIP command. /// </summary> /// <param name="args">The command arguments.</param> /// <returns>0 on success, a non-zero error code otherwise.</returns> public static int Execute(string[] args) { const string usage = @" Usage: ------------------------------------------------------------------------------- vegomatic unzip [-o:<path>] [-r] [-fn] <pattern> Unzips the specified files to the current directory. -o:<path> specifies the folder where extracted files will be written. Files will be written to the current directory if this option is not present. -r indicates that the file pattern should be searched recursively. -fn indicates that zip files will be extracted to a folder named by the zip archive file. <pattern> specifies the wildcarded pattern for the files to be extracted. "; bool recursive = false; bool folderName = false; string outFolder = Environment.CurrentDirectory; string pattern; string[] files; int cExtracted; if (args.Length < 1) { Program.Error(usage); return(1); } for (int i = 0; i < args.Length - 1; i++) { string arg = args[i]; if (arg.StartsWith("-o:")) { outFolder = Path.GetFullPath(arg.Substring(3)); } else if (arg == "-r") { recursive = true; } else if (arg == "-fn") { folderName = true; } else { Program.Error(usage); return(1); } } pattern = args[args.Length - 1]; files = Helper.GetFilesByPattern(pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); cExtracted = 0; Program.Output("[{0}] files found.", files.Length); foreach (string file in files) { ZipFile archive = null; string outPath; try { archive = new ZipFile(file); outPath = Helper.AddTrailingSlash(outFolder); if (folderName) { outPath += Helper.AddTrailingSlash(Helper.GetFileNameWithoutExtension(file)); } foreach (ZipEntry entry in archive) { Stream inStream = null; EnhancedStream outStream = null; string outFile; outFile = outPath + entry.Name; Helper.CreateFileTree(outFile); Program.Output("Extract: {0}", entry.Name); try { inStream = archive.GetInputStream(entry); outStream = new EnhancedFileStream(outFile, FileMode.Create, FileAccess.ReadWrite); outStream.CopyFrom(inStream, -1); cExtracted++; } finally { if (inStream != null) { inStream.Close(); } if (outStream != null) { outStream.Close(); } File.SetCreationTime(outFile, entry.DateTime); File.SetLastWriteTime(outFile, entry.DateTime); } } } catch (Exception e) { Program.Error("{0}: {1}", e.Message, file); } finally { if (archive != null) { archive.Close(); } } } Program.Output("[{0}] files extracted from [{1}] zip archives.", cExtracted, files.Length); return(0); }
public void SecureFile_File_GetPublicKey() { string originalName = Path.GetTempFileName(); string encryptName = Path.GetTempFileName(); string privateKey = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024); string publicKey = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey); EnhancedStream original = null; EnhancedStream encrypted = null; SecureFile secure = null; try { original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite); for (int i = 0; i < 100; i++) { original.WriteByte((byte)i); } original.Close(); original = null; // Verify that the public key is saved if requested secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey); Assert.IsTrue(secure.SavePublicKey); Assert.AreEqual(publicKey, secure.PublicKey); secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256); secure.Close(); secure = null; Assert.AreEqual(publicKey, SecureFile.GetPublicKey(encryptName)); // Verify that the public key is not saved, if SavePublicKey=false System.IO.File.Delete(encryptName); secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey); secure.SavePublicKey = false; secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256); secure.Close(); secure = null; Assert.IsNull(SecureFile.GetPublicKey(encryptName)); } finally { if (original != null) { original.Close(); } if (encrypted != null) { encrypted.Close(); } System.IO.File.Delete(originalName); System.IO.File.Delete(encryptName); } }