} //ReadHeader private void ReadManifest(BinaryReader reader) { header.manifestEntryCount = reader.ReadUInt32(); int manifestEntryCount = (int)header.manifestEntryCount; manifests = new Manifest[manifestEntryCount]; for (int i = 0; i < manifestEntryCount; i++) { Manifest manifest = manifests[i]; manifest.manifestEntries = new ManifestEntry[3]; int manifestEntriesLength = manifest.manifestEntries.Length; for (int j = 0; j < manifestEntriesLength; j++) { ManifestEntry entry = manifest.manifestEntries[j]; entry.groupId = reader.ReadByte(); entry.u1b = reader.ReadByte(); entry.u2 = reader.ReadUInt16(); entry.payloadOffset = reader.ReadUInt32(); entry.entrySize = reader.ReadByte(); entry.n4 = reader.ReadUInt16(); manifest.manifestEntries[j] = entry; } //for manifests[i] = manifest; } //for } //ReadManifest
public void TestInvalidTooManyElements() { ManifestEntry createdEntry; bool parsingSucceded = ManifestEntry.TryParse(InvalidInputTooManyElements, out createdEntry); Assert.That(!parsingSucceded); }
public void TestInvalidHashTooShort() { ManifestEntry createdEntry; bool parsingSucceded = ManifestEntry.TryParse(InvalidInputHashTooShort, out createdEntry); Assert.That(!parsingSucceded); }
public void TestInvalidNegativeSize() { ManifestEntry createdEntry; bool parsingSucceded = ManifestEntry.TryParse(InvalidInputNegativeSize, out createdEntry); Assert.That(!parsingSucceded); }
} //DisplayHeaderInfo public void DisplayManifestInfo() { int manifestCount = manifests.Length; for (int i = 0; i < manifestCount; i++) { Manifest manifest = manifests[i]; int entryCount = manifest.manifestEntries.Length; Console.WriteLine($"\nManifest: {i}"); Console.WriteLine("================================================================"); for (int j = 0; j < entryCount; j++) { ManifestEntry entry = manifest.manifestEntries[j]; Console.WriteLine($"\nEntry: {j}"); Console.WriteLine("----------------------------------------------------------------"); Console.WriteLine($"Group Id: 0x{entry.groupId.ToString("x")}"); Console.WriteLine($"u1b: 0x{entry.u1b.ToString("x")}"); Console.WriteLine($"u2: 0x{entry.u2.ToString("x")}"); Console.WriteLine($"Payload Offset: 0x{entry.payloadOffset.ToString("x")}"); Console.WriteLine($"Entry Size: 0x{entry.entrySize.ToString("x")}"); Console.WriteLine($"n4: 0x{entry.n4.ToString("x")}\n"); } //for } //for } //DisplayManifestInfo
private static Manifest _generateNewManifest(bool scanDir = false) { // No directory means no manifest file anyways. Manifest newManifest = new Manifest(); newManifest.Encrypted = false; newManifest.PeriodicCheckingInterval = 5; newManifest.PeriodicChecking = false; newManifest.AutoConfirmMarketTransactions = false; newManifest.AutoConfirmTrades = false; newManifest.Entries = new List <ManifestEntry>(); newManifest.FirstRun = true; // Take a pre-manifest version and generate a manifest for it. if (scanDir) { string maDir = Manifest.GetExecutableDir() + "/maFiles/"; if (Directory.Exists(maDir)) { DirectoryInfo dir = new DirectoryInfo(maDir); var files = dir.GetFiles(); foreach (var file in files) { if (file.Extension != ".maFile") { continue; } string contents = File.ReadAllText(file.FullName); try { SteamGuardAccount account = JsonConvert.DeserializeObject <SteamGuardAccount>(contents); ManifestEntry newEntry = new ManifestEntry() { Filename = file.Name, SteamID = account.Session.SteamID }; newManifest.Entries.Add(newEntry); } catch (Exception) { } } if (newManifest.Entries.Count > 0) { newManifest.Save(); newManifest.PromptSetupPassKey("This version of SDA has encryption. Please enter a passkey below, or hit cancel to remain unencrypted"); } } } if (newManifest.Save()) { return(newManifest); } return(null); }
private static void DownloadFile(ManifestEntry entry) { var fileLocation = m_downloadPath + entry.File; var DirectoryPath = Path.GetDirectoryName(fileLocation); if (string.IsNullOrWhiteSpace(DirectoryPath)) { throw new Exception($"The download location isn't in a folder. FileLocation:{fileLocation}"); } Directory.CreateDirectory(DirectoryPath); //TODO Should the file be deleted or over written it if exists? Throw an exception? using (System.IO.StreamWriter file = new System.IO.StreamWriter(fileLocation)) { var chunkNum = 1; IRestResponse response; do { var request = new RestRequest($"{entry.Id}/{chunkNum}", Method.GET); response = m_client.Execute(request); file.Write(response.Content); file.Flush(); chunkNum++; } while (response.Content.Length > 0); } }
public void MoveEntry(int from, int to) { if (UseMaFiles) { if (from < 0 || to < 0 || from > Entries.Count || to > Entries.Count - 1) { return; } ManifestEntry sel = Entries[from]; Entries.RemoveAt(from); Entries.Insert(to, sel); Save(); } else { credMan = CredManifest.GetManifest(); if (from < 0 || to < 0 || from > credMan.Entries.Count || to > credMan.Entries.Count - 1) { return; } CredManifestEntry sel = credMan.Entries[from]; credMan.Entries.RemoveAt(from); credMan.Entries.Insert(to, sel); credMan.Save(); } }
/// <summary> /// Verifies the integrity of the file in the manifest entry. /// </summary> /// <param name="entry">The manifest entry to test.</param> /// <returns><c>true</c>, if file was complete and undamaged, <c>false</c> otherwise.</returns> public static bool IsFileIntegrityIntact(this ManifestEntry entry) { string localPath = $"{ConfigHandler.Instance.GetGamePath()}{entry.RelativePath}"; if (!File.Exists(localPath)) { return(false); } FileInfo fileInfo = new FileInfo(localPath); if (fileInfo.Length != entry.Size) { return(false); } using (Stream file = File.OpenRead(localPath)) { string localHash = MD5Handler.GetStreamHash(file); if (localHash != entry.Hash) { return(false); } } return(true); }
private static Manifest ParseManifestStream(Stream secStream, ManifestEntry fileEntry, string password) { secStream.Seek(0, SeekOrigin.Begin); using (var zStream = GetDecryptStream(secStream, fileEntry, password)) { using (var gz = new ICSharpCode.SharpZipLib.GZip.GZipInputStream(zStream)) { var read = new MemoryStream(); var bytes = new byte[256]; do { var n = gz.Read(bytes, 0, bytes.Length); if (n <= 0) { break; } read.Write(bytes, 0, n); } while (true); var data = read.ToArray(); // Debug.LogFormat("read manifest data {0}", data.Length); var json = Encoding.UTF8.GetString(data); return(JsonUtility.FromJson <Manifest>(json)); } } }
public static void Setup() { if (!File.Exists(ManifestPath)) { File.WriteAllLines(ManifestPath, new[] { "# Asset manifest ", "# format:", "# asset name|asset type|relative path to asset" }); } foreach (string s in File.ReadAllLines(ManifestPath)) { if (s.StartsWith("#")) { continue; } string[] contents = s.Split('|'); manifest[contents[0]] = new ManifestEntry((AssetType)Enum.Parse(typeof(AssetType), contents[1]), IO.AssetsPath + contents[2]); } foreach (AssetType type in Enum.GetValues(typeof(AssetType))) { assets[type] = new Dictionary <string, object>(); } }
public static void Load(string assetName) { if (!string.IsNullOrEmpty(assetName) && NameInManifest(assetName)) { ManifestEntry assetManifest = manifest[assetName]; AssetType type = assetManifest.type; switch (type) { case AssetType.Text: assets[type][assetName] = File.ReadAllLines(assetManifest.path); break; case AssetType.StaticSprite: assets[type][assetName] = Sprite.Load(assetManifest.path); break; default: Debug.RaiseError($"Asset {assetName}'s type ({assetManifest.type}) cannot be parsed. The asset has not been loaded."); break; } } else { Debug.RaiseWarning($"Asset {assetName} not found in manifest. This will cause problems."); } }
public void TestInvalidMissingHash() { ManifestEntry createdEntry; bool parsingSucceded = ManifestEntry.TryParse(InvalidInputMissingHash, out createdEntry); Assert.That(!parsingSucceded); }
internal ManifestEntry?ResolveEntry(string path) { if (string.IsNullOrEmpty(path) || HasInvalidPathChars(path)) { return(null); } // trimmed is a string without leading nor trailing path separators // so if we find an empty string while iterating over the segments // we know for sure the path is invalid and we treat it as the above // case by returning null. // Examples of invalid paths are: //wwwroot /\wwwroot //wwwroot//jquery.js var trimmed = RemoveLeadingAndTrailingDirectorySeparators(path); // Paths consisting only of a single path separator like / or \ are ok. if (trimmed.Length == 0) { return(_rootDirectory); } var tokenizer = new StringTokenizer(trimmed, _separators); ManifestEntry currentEntry = _rootDirectory; foreach (var segment in tokenizer) { if (segment.Equals("")) { return(null); } currentEntry = currentEntry.Traverse(segment); } return(currentEntry); }
public void TestCreateFromValidInput() { bool parsingSucceded = ManifestEntry.TryParse(ValidInput, out var createdEntry); Assert.That(parsingSucceded); Assert.AreEqual(this.ExpectedObject, createdEntry); }
private static void EditSelectedManifestList() { GameObject selectedGameObject = Selection.activeGameObject; Debug.Log("selectedGameObject = " + selectedGameObject.name); //this is the WayPointList ManifestList meList = selectedGameObject.GetComponent <ManifestList> (); //this is the WayPointManager GameObject WayPointManagerObject = GameObject.Find("ManifestManager"); ManifestManager meManager = WayPointManagerObject.GetComponent <ManifestManager> (); int numPoints = meList.NumEntriesUsed; meManager.PrefabName = meList.PrefabName; meManager.NumPointsUsed = meList.NumEntriesUsed; Debug.Log("EditSelectedWayPoint : numPoints = " + numPoints); for (int i = 0; i < numPoints; i++) { ManifestEntry me = meList.GetManifestEntryAtIndex(i); ManifestManager.Instance.mManifestEntries [i] = me; } }
public IManifestEntry ProcessManifestEntry( IManifest manifest, ObjectType entryType, string path, dynamic jsonObject, IReferenceFinderService referenceFinderService) { var manifestEntry = new ManifestEntry(manifest, entryType, path, jsonObject, referenceFinderService); var di = new DirectoryInfo(Path.Combine(manifest.Mod.SourceDirectoryPath, manifestEntry.Path)); if (!di.Exists) { return(manifestEntry); } di.GetFiles("*.*").ToList().ForEach( fi => { var identifier = fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length); var objectDefinition = ObjectDefinitionFactory.ObjectDefinitionFactorySingleton.Get( entryType, new ObjectDefinitionDescription(identifier, identifier, jsonObject), (JObject)jsonObject, fi.FullName, referenceFinderService); manifestEntry.Objects.Add(objectDefinition); }); return(manifestEntry); }
public IManifestEntry ProcessManifestEntry( IManifest manifest, ObjectType entryType, string path, dynamic jsonObject, IReferenceFinderService referenceFinderService) { var manifestEntry = new ManifestEntry(manifest, entryType, path, jsonObject, referenceFinderService); var assetBundleDirectory = Path.Combine(manifest.Mod.SourceDirectoryPath, path); var di = new DirectoryInfo(assetBundleDirectory); if (!di.Exists) { throw new InvalidProgramException($"Expected asset bundle directory at [{di.FullName}]."); } di.GetFiles("*.").ToList().ForEach( fi => { var objectDefinition = ObjectDefinitionFactory.ObjectDefinitionFactorySingleton.Get( entryType, new ObjectDefinitionDescription(fi.Name, fi.Name, jsonObject), (JObject)jsonObject, fi.FullName, referenceFinderService); manifestEntry.Objects.Add(objectDefinition); }); return(manifestEntry); }
public bool RemoveAccount(SteamGuardAccount account, bool deleteMaFile = true) { ManifestEntry entry = (from e in this.Entries where e.SteamID == account.Session.SteamID select e).FirstOrDefault(); if (entry == null) { return(true); // If something never existed, did you do what they asked? } string maDir = Manifest.GetExecutableDir() + "/maFiles/"; string filename = maDir + entry.Filename; this.Entries.Remove(entry); if (this.Entries.Count == 0) { this.Encrypted = false; } if (this.Save() && deleteMaFile) { try { File.Delete(filename); return(true); } catch (Exception) { return(false); } } return(false); }
public static ManifestEntry ConvertToManifestEntry(this MbdbEntry item, ManifestEntryType includeType, bool isEncrypted) { ManifestEntry result = default; var entryType = CommonHelpers.GetManifestEntryTypeFromMode(item.Mode); if (entryType == includeType) { var id = item.GetSha1HashAsHexString(); result = new ManifestEntry { Id = id, Domain = item.Domain, RelativePath = item.RelativePath, EntryType = entryType, }; if (isEncrypted) { result.ProtectionClass = (ProtectionClass)item.Flags; result.WrappedKey = item.WrappedKey; } } return(result); }
/// <summary> /// Decrypts/Encrypts all account files (depending on DPAPI setting) /// </summary> /// <returns></returns> public bool UpdateDPAPI() { credMan = CredManifest.GetManifest(); if (UseMaFiles) { string maDir = GetExecutableDir() + "/maFiles/"; for (int i = 0; i < Entries.Count; i++) { ManifestEntry entry = Entries[i]; string filename = maDir + entry.FileName; if (!File.Exists(filename)) { continue; } string fileContents = File.ReadAllText(filename); fileContents = Encryptor.DPAPIUnprotect(fileContents, Encryptor.AccountEntropy); string toWriteFileContents = fileContents; if (UseDPAPI == true) { toWriteFileContents = Encryptor.DPAPIProtect(toWriteFileContents, Encryptor.AccountEntropy); } File.WriteAllText(filename, toWriteFileContents); if (UseWindowsFileEncryption) { File.Encrypt(filename); } else { File.Decrypt(filename); } } } else { foreach (CredManifestEntry entry in credMan.Entries) { string fileContents = entry.Contents; string toWriteFileContents = Encryptor.DPAPIUnprotect(fileContents, Encryptor.AccountEntropy); if (UseDPAPI) { toWriteFileContents = Encryptor.DPAPIProtect(toWriteFileContents, Encryptor.AccountEntropy); } entry.Contents = toWriteFileContents; } credMan.Save(); } Save(); return(true); }
private void RecurseStreamingAssetsDirectory(string path, ManifestEntry newEntry) { var di = new DirectoryInfo(path); // foreach (var fi in di.EnumerateFiles()) di.EnumerateFiles() .ToList().ForEach( //.AsParallel().ForAll( fi => { var validExtensions = new List <string>(new[] { ".json", ".csv" }); var fileName = fi.Name; var fileData = validExtensions.Contains(fi.Extension) ? File.ReadAllText(fi.FullName) : null; var hostDirectory = di.Name; var retVal = StreamingAssetProcessor.ProcessFile( newEntry, di, fi.FullName, fileData, hostDirectory, this.referenceFinderService, this.logger); if (retVal != null) { if (retVal is IObjectDefinition obj) { newEntry.Objects.Add(obj); if (retVal is AssetBundleObjectDefinition assetBundleObjectDefinition) { var stubJsonObject = JsonConvert.DeserializeObject($"{{\"AssetBundleName\": \"{assetBundleObjectDefinition.Id}\"}}"); var prefabObjectDefinition = ObjectDefinitionFactory.ObjectDefinitionFactorySingleton.Get( ObjectType.Prefab, new ObjectDefinitionDescription(null, null, null, null, (JObject)stubJsonObject), (JObject)stubJsonObject, Path.Combine(path, assetBundleObjectDefinition.Name), referenceFinderService); newEntry.Objects.Add(prefabObjectDefinition); } } else if (retVal is IResourceDefinition res) { newEntry.Resources.Add(res); } else { throw new InvalidProgramException($"Unknown streaming asset object."); } } }); di.GetDirectories() .ToList().ForEach( //.AsParallel().ForAll( subdi => this.RecurseStreamingAssetsDirectory(subdi.FullName, newEntry)); }
private void LoadAttackManifest() { string manifestName = "ManifestListArea1"; GameObject _meObj = Instantiate(Resources.Load("Prefabs/Manifests/" + manifestName, typeof(GameObject))) as GameObject; ManifestList manifestScript = _meObj.GetComponent <ManifestList> (); int numEntries = manifestScript.NumEntriesUsed; Debug.Log("LoadAttackManifest : numEntries = " + numEntries.ToString()); int runningIndex = 0; for (int e = 0; e < numEntries; e++) { ManifestEntry me = manifestScript.GetManifestEntryAtIndex(e); int numToLoad = me.NumToLoad; string alienPrefabName = me.PrefabName; WayPointList startingPoints = me.StartingPoints; GameObject _moduleDataObj = Instantiate(Resources.Load("Prefabs/AlienModuleData/" + alienPrefabName, typeof(GameObject))) as GameObject; AlienModuleContainer amc = _moduleDataObj.GetComponent <AlienModuleContainer> (); AlienModuleData amd = amc.mData; for (int i = 0; i < numToLoad; i++) { GameObject _aaObj = Instantiate(Resources.Load("Prefabs/AlienAttackObject", typeof(GameObject))) as GameObject; if (_aaObj != null) { if (AlienAttackObjectContainer != null) { _aaObj.transform.parent = AlienAttackObjectContainer.transform; } _aaObj.name = "attackObj" + runningIndex.ToString(); Vector3 startingVec = startingPoints.GetVector3AtIndex(i); //Debug.Log("vec = " + startingVec.x.ToString() + " " + startingVec.y.ToString() + " " + startingVec.z.ToString()); AlienAttackObject objectScript = _aaObj.GetComponent <AlienAttackObject> (); objectScript.StoragePosition = StoragePoint.transform.position; objectScript.StartPosition = startingVec; objectScript.AttachModuleData(amd); objectScript.FixUp(); //temp test objectScript.SetBaseSpriteScale(0.3f, 0.3f); AlienAttackObjectList.Add(_aaObj); runningIndex++; } } } }
// 比对两个 ManifestEntry 记录是否相同 public static bool IsManifestEntryEquals(ManifestEntry fileEntry1, ManifestEntry fileEntry2) { return(fileEntry1 != null && fileEntry2 != null && fileEntry1.checksum == fileEntry2.checksum && fileEntry1.size == fileEntry2.size && fileEntry1.rsize == fileEntry2.rsize && fileEntry1.chunkSize == fileEntry2.chunkSize); }
private static ManifestEntry AsManifestEntry(FileEntry entry, int chunkSize) { var manifestEntry = new ManifestEntry(); manifestEntry.name = entry.name; manifestEntry.size = entry.size; manifestEntry.rsize = entry.rsize; manifestEntry.checksum = entry.checksum; manifestEntry.chunkSize = chunkSize; return(manifestEntry); }
public ManifestEntry(ManifestEntry parent, string path, string id) { Path = path; Id = id; Type = parent.Type; AssetBundleName = parent.AssetBundleName; AssetBundlePersistent = parent.AssetBundlePersistent; ShouldMergeJSON = parent.ShouldMergeJSON; AddToAddendum = parent.AddToAddendum; }
public void MoveEntry(int from, int to) { if (from < 0 || to < 0 || from > Entries.Count || to > Entries.Count - 1) { return; } ManifestEntry sel = Entries[from]; Entries.RemoveAt(from); Entries.Insert(to, sel); Save(); }
private void AddStreamingAssetsManifestEntry(string simPath, Mod mod, Manifest manifest) { var newEntry = new ManifestEntry( manifest, ObjectType.StreamingAssetsData, simPath, null, this.referenceFinderService); this.RecurseStreamingAssetsDirectory(simPath, newEntry); manifest.Entries.Add(newEntry); }
// 基本流程: // 在不知道清单文件校验值和大小的情况下, 使用此接口尝试先下载 checksum 文件, 得到清单文件信息 public static void GetManifest(string localPathRoot, DownloadWorker worker, string checksum, int size, int rsize, string password, int chunkSize, Action <Manifest, ManifestEntry> callback) { if (checksum != null && size > 0 && rsize > 0 && chunkSize > 0) { var fileEntry = new ManifestEntry() { name = Manifest.ManifestFileName, checksum = checksum, size = size, rsize = rsize, chunkSize = chunkSize, }; GetManifestDirect(localPathRoot, worker, fileEntry, password, callback); return; } if (!Directory.Exists(localPathRoot)) { Directory.CreateDirectory(localPathRoot); } ReadRemoteFile(ResourceManager.urls, Manifest.ChecksumFileName, content => { try { if (string.IsNullOrEmpty(content)) { Debug.LogWarning("checksum 无内容"); } else { var fileEntry = JsonUtility.FromJson <ManifestEntry>(content); if (fileEntry != null) { // Debug.LogFormat("checksum {0} {1}", fileEntry.checksum, fileEntry.size); GetManifestDirect(localPathRoot, worker, fileEntry, password, callback); return(true); } Debug.LogWarningFormat("checksum 无法解析 {0}", content); } } catch (Exception exception) { Debug.LogErrorFormat("checksum 解析异常 {0}\n{1}", content, exception); } return(false); }); }
public bool ChangeEncryptionKey(string oldKey, string newKey) { if (this.Encrypted) { if (!this.VerifyPasskey(oldKey)) { return(false); } } bool toEncrypt = newKey != null; string maDir = Manifest.GetExecutableDir() + "/maFiles/"; for (int i = 0; i < this.Entries.Count; i++) { ManifestEntry entry = this.Entries[i]; string filename = maDir + entry.Filename; if (!File.Exists(filename)) { continue; } string fileContents = File.ReadAllText(filename); if (this.Encrypted) { fileContents = FileEncryptor.DecryptData(oldKey, entry.Salt, entry.IV, fileContents); } string newSalt = null; string newIV = null; string toWriteFileContents = fileContents; if (toEncrypt) { newSalt = FileEncryptor.GetRandomSalt(); newIV = FileEncryptor.GetInitializationVector(); toWriteFileContents = FileEncryptor.EncryptData(newKey, newSalt, newIV, fileContents); } File.WriteAllText(filename, toWriteFileContents); entry.IV = newIV; entry.Salt = newSalt; } this.Encrypted = toEncrypt; this.Save(); return(true); }
private ManifestEntry SwapManifestAlternates(ManifestEntry m) { if (m.Volumes.Count % 2 != 1 && m.Alternate != null) { m.Alternate.Incrementals.Clear(); m.Alternate.Incrementals.AddRange(m.Incrementals); m.Alternate.Volumes.Clear(); m.Alternate.Volumes.AddRange(m.Volumes); m.Incrementals.Clear(); m.Volumes.Clear(); m.Alternate.Alternate = m; return m.Alternate; } return m; }
/// <summary> /// Will attempt to read the manifest file, optionally reverting to the secondary manifest if reading one fails. /// </summary> /// <param name="backend">The backendwrapper to read from</param> /// <param name="entry">The manifest to read</param> /// <returns>The parsed manifest</returns> private Manifestfile GetManifest(BackendWrapper backend, ManifestEntry entry) { if (m_options.DontReadManifests) { Manifestfile mf = new Manifestfile(); mf.SignatureHashes = null; mf.ContentHashes = null; return mf; } if (entry.ParsedManifest != null) return entry.ParsedManifest; else if (entry.Alternate != null && entry.Alternate.ParsedManifest != null) return entry.Alternate.ParsedManifest; if (OperationProgress != null && backend.Statistics != null) OperationProgress(this, GetOperationType(), backend.Statistics.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusReadingManifest, entry.Time.ToShortDateString() + " " + entry.Time.ToShortTimeString()), ""); bool tryAlternateManifest = false; //This method has some very special logic to ensure correct handling of errors //The assumption is that it is possible to determine if the error occurred due to a // transfer problem or a corrupt file. If the former happens, the operation should // be retried, and thus an exception is thrown. If the latter, the file should // be ignored and the backup file should be used. // //We detect a parsing error, either directly or indirectly through CryptographicException, // and assume that a parsing error is an indication of a broken file. //All other errors are assumed to be transfer problems, and throws exceptions. // //This holds as long as the backend always throws an exception if a partial file // was downloaded. The FTP backend may not honor this, and some webservers // may ommit the "Content-Length" header, which will cause problems. //There is a guard agains partial downloads in BackendWrapper.GetInternal() using (new Logging.Timer("Get " + entry.Filename)) using (Utility.TempFile tf = new XervBackup.Library.Utility.TempFile()) { try { backend.Get(entry, null, tf, null); //We now have the file decrypted, if the next step fails, // its a broken xml or invalid content tryAlternateManifest = true; Manifestfile mf = new Manifestfile(tf, m_options.SkipFileHashChecks); if (string.IsNullOrEmpty(mf.SelfFilename)) mf.SelfFilename = entry.Filename; if (mf.ContentHashes != null && entry.Alternate != null) { //Special case, the manifest has not recorded all volumes, // we must see if the alternate manifest has more volumes if (entry.Volumes.Count > mf.ContentHashes.Count) { //Do not try the alternate, we just did tryAlternateManifest = false; Logging.Log.WriteMessage(string.Format(Strings.Interface.ReadingSecondaryManifestLogMessage, entry.Alternate.Filename), XervBackup.Library.Logging.LogMessageType.Information); Manifestfile amf = null; //Read the alternate file and try to differentiate between a defect file or a partial one bool defectFile = false; try { System.IO.File.Delete(tf); backend.Get(entry.Alternate, null, tf, null); } catch (System.Security.Cryptography.CryptographicException cex) { //We assume that CryptoException means partial file Logging.Log.WriteMessage(string.Format(Strings.Interface.SecondaryManifestReadErrorLogMessage, entry.Alternate.Filename, cex), XervBackup.Library.Logging.LogMessageType.Warning); defectFile = true; } if (!defectFile) { try { amf = new Manifestfile(tf, m_options.SkipFileHashChecks); } catch (Exception ex) { //Parsing error means partial file Logging.Log.WriteMessage(string.Format(Strings.Interface.SecondaryManifestReadErrorLogMessage, entry.Alternate.Filename, ex), XervBackup.Library.Logging.LogMessageType.Warning); defectFile = true; } } //If the alternate manifest is correct, assign it so we have a copy if (!defectFile && amf != null) { if (string.IsNullOrEmpty(amf.SelfFilename)) amf.SelfFilename = entry.Alternate.Filename; //If the alternate manifest has more files than the primary, we use that one if (amf.ContentHashes != null && amf.ContentHashes.Count > mf.ContentHashes.Count) { entry.Alternate.ParsedManifest = amf; if (m_options.SkipFileHashChecks) { mf.SignatureHashes = null; mf.ContentHashes = null; } return amf; } } } } if (m_options.SkipFileHashChecks) { mf.SignatureHashes = null; mf.ContentHashes = null; } entry.ParsedManifest = mf; return mf; } catch (Exception ex) { //Only try secondary if the parsing/decrypting fails, not if the transfer fails if (entry.Alternate != null && (ex is System.Security.Cryptography.CryptographicException || tryAlternateManifest)) { //TODO: If it is a version error, there is no need to read the alternate version Logging.Log.WriteMessage(string.Format(Strings.Interface.PrimaryManifestReadErrorLogMessage, entry.Filename, ex.Message), XervBackup.Library.Logging.LogMessageType.Warning); try { Logging.Log.WriteMessage(string.Format(Strings.Interface.ReadingSecondaryManifestLogMessage, entry.Alternate.Filename), XervBackup.Library.Logging.LogMessageType.Information); return GetManifest(backend, entry.Alternate); } catch (Exception ex2) { Logging.Log.WriteMessage(string.Format(Strings.Interface.SecondaryManifestReadErrorLogMessage, entry.Alternate.Filename, ex2.Message), XervBackup.Library.Logging.LogMessageType.Warning); } } //Report the original error throw; } } }
/// <summary> /// Verifies the backup chain for producing a new backup on top. /// This will check that all files are accounted for in the file list. /// </summary> /// <param name="entry">The newest entry to check</param> private void VerifyBackupChainWithFiles(BackendWrapper backend, ManifestEntry entry) { VerifyManifestChain(backend, entry); string errorMessage = Environment.NewLine + Strings.Interface.DeleteManifestsSuggestion + Environment.NewLine + Environment.NewLine; while (entry != null) { Manifestfile parsed = GetManifest(backend, entry); errorMessage += entry.Filename + Environment.NewLine; if (entry.Volumes.Count != parsed.SignatureHashes.Count || entry.Volumes.Count != parsed.ContentHashes.Count) { //If we have an extra set, the connection could have died right before the manifest was uploaded if (parsed.SignatureHashes.Count == parsed.ContentHashes.Count && entry.Volumes.Count - 1 == parsed.ContentHashes.Count) { backend.AddOrphan(entry.Volumes[entry.Volumes.Count - 1].Value); backend.AddOrphan(entry.Volumes[entry.Volumes.Count - 1].Key); entry.Volumes.RemoveAt(entry.Volumes.Count - 1); } else { throw new Exception( string.Format(Strings.Interface.ManifestAndFileCountMismatchError, entry.Filename, parsed.SignatureHashes.Count, entry.Volumes.Count) + errorMessage ); } } for(int i = 0; i < entry.Volumes.Count; i++) { if (entry.Volumes[i].Key.Filesize > 0 && parsed.SignatureHashes[i].Size > 0 && entry.Volumes[i].Key.Filesize != parsed.SignatureHashes[i].Size) throw new Exception( string.Format(Strings.Interface.FileSizeMismatchError, entry.Volumes[i].Key.Filename, entry.Volumes[i].Key.Filesize, parsed.SignatureHashes[i].Size) + errorMessage ); if (entry.Volumes[i].Value.Filesize >= 0 && parsed.ContentHashes[i].Size >= 0 && entry.Volumes[i].Value.Filesize != parsed.ContentHashes[i].Size) throw new Exception( string.Format(Strings.Interface.FileSizeMismatchError, entry.Volumes[i].Value.Filename, entry.Volumes[i].Value.Filesize, parsed.ContentHashes[i].Size) + errorMessage ); if (!string.IsNullOrEmpty(parsed.SignatureHashes[i].Name) && !parsed.SignatureHashes[i].Name.Equals(entry.Volumes[i].Key.Fileentry.Name, StringComparison.InvariantCultureIgnoreCase)) throw new Exception( string.Format(Strings.Interface.FilenameMismatchError, parsed.SignatureHashes[i].Name, entry.Volumes[i].Key.Fileentry.Name) + errorMessage ); if (!string.IsNullOrEmpty(parsed.ContentHashes[i].Name) && !parsed.ContentHashes[i].Name.Equals(entry.Volumes[i].Value.Fileentry.Name, StringComparison.InvariantCultureIgnoreCase)) throw new Exception( string.Format(Strings.Interface.FilenameMismatchError, parsed.ContentHashes[i].Name, entry.Volumes[i].Value.Fileentry.Name) + errorMessage ); } entry = entry.Previous; } }
/// <summary> /// Validates the manifest chain, starting by evaluating the current manifest and going backwards in the chain /// </summary> /// <param name="backend">The backend wrapper</param> /// <param name="entry">The entry to verify</param> private void VerifyManifestChain(BackendWrapper backend, ManifestEntry entry) { if (m_options.DontReadManifests) throw new InvalidOperationException(Strings.Interface.CannotVerifyChain); while (entry.Previous != null) { Manifestfile parsed = GetManifest(backend, entry); //If this manifest is not version 3, the chain verification stops here if (parsed.Version < 3) return; ManifestEntry previous = entry.Previous; if (entry.Previous.Alternate != null && entry.Previous.Alternate.Filename == parsed.PreviousManifestFilename) previous = entry.Previous.Alternate; if (parsed.PreviousManifestFilename != previous.Filename) throw new System.IO.InvalidDataException(string.Format(Strings.Interface.PreviousManifestFilenameMismatchError, entry.Filename, parsed.PreviousManifestFilename, previous.Filename)); if (!m_options.SkipFileHashChecks) { //Load the Remotehash property GetManifest(backend, previous); if (parsed.PreviousManifestHash != previous.RemoteHash) throw new System.IO.InvalidDataException(string.Format(Strings.Interface.PreviousManifestHashMismatchError, entry.Filename, parsed.PreviousManifestHash, previous.RemoteHash)); } entry = previous; } }
public void UpdateManifest(ManifestEntry manifest) { if (m_manifestEntry == null) { m_manifestEntry = m_node.AppendChild(m_doc.CreateElement("File")); m_manifestEntry.Attributes.Append(m_doc.CreateAttribute("type")).Value = "manifest"; m_manifestEntry.Attributes.Append(m_doc.CreateAttribute("name")).Value = manifest.Filename; m_manifestEntry.Attributes.Append(m_doc.CreateAttribute("size")).Value = manifest.Filesize.ToString(); } else { m_manifestEntry.Attributes["type"].Value = "manifest"; m_manifestEntry.Attributes["name"].Value = manifest.Filename; m_manifestEntry.Attributes["size"].Value = manifest.Filesize.ToString(); } m_manifestEntry.InnerText = Utility.Utility.ByteArrayAsHexString(Convert.FromBase64String(manifest.RemoteHash)); }
public string Backup(string[] sources) { BackupStatistics bs = new BackupStatistics(XervBackupOperationMode.Backup); SetupCommonOptions(bs); BackendWrapper backend = null; VerificationFile verification = null; if (m_options.DontReadManifests) throw new Exception(Strings.Interface.ManifestsMustBeReadOnBackups); if (m_options.SkipFileHashChecks) throw new Exception(Strings.Interface.CannotSkipHashChecksOnBackup); if (sources == null || sources.Length == 0) throw new Exception(Strings.Interface.NoSourceFoldersError); //Make sure they all have the same format and exist for (int i = 0; i < sources.Length; i++) { sources[i] = Utility.Utility.AppendDirSeparator(System.IO.Path.GetFullPath(sources[i])); if (!System.IO.Directory.Exists(sources[i])) throw new System.IO.IOException(String.Format(Strings.Interface.SourceFolderIsMissingError, sources[i])); } //Sanity check for duplicate folders and multiple inclusions of the same folder for (int i = 0; i < sources.Length - 1; i++) { for (int j = i + 1; j < sources.Length; j++) if (sources[i].Equals(sources[j], Utility.Utility.IsFSCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) throw new Exception(string.Format(Strings.Interface.SourceDirIsIncludedMultipleTimesError, sources[i])); else if (sources[i].StartsWith(sources[j], Utility.Utility.IsFSCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) throw new Exception(string.Format(Strings.Interface.SourceDirsAreRelatedError, sources[i], sources[j])); } if (m_options.AsynchronousUpload) { m_asyncReserved = ASYNC_RESERVED; m_allowUploadProgress = false; } //Unused, but triggers errors in the encryption setup here Library.Interface.IEncryption encryptionModule = m_options.NoEncryption ? null : DynamicLoader.EncryptionLoader.GetModule(m_options.EncryptionModule, m_options.Passphrase, m_options.RawOptions); using (new Logging.Timer("Backup from " + string.Join(";", sources) + " to " + m_backend)) { try { if (OperationStarted != null) OperationStarted(this, XervBackupOperation.Backup, bs.OperationMode, -1, -1, Strings.Interface.StatusLoadingFilelist, ""); OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, -1, -1, Strings.Interface.StatusLoadingFilelist, ""); CheckLiveControl(); bool full = m_options.Full; if (full) bs.SetTypeReason(string.Format(Strings.Interface.FullBecauseFlagWasSet, "full")); backend = new BackendWrapper(bs, m_backend, m_options); backend.ProgressEvent += new XervBackup.Library.Main.RSync.RSyncDir.ProgressEventDelegate(BackupTransfer_ProgressEvent); backend.AsyncItemProcessedEvent += new EventHandler(backend_AsyncItemProcessedEvent); m_progress = 0.0; OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusReadingIncrementals, ""); CheckLiveControl(); List<ManifestEntry> backupsets; if (full) { //This will create the target folder backend.List(false); backupsets = new List<ManifestEntry>(); } else { //This will list all files on the backend and create the target folder backupsets = backend.GetBackupSets(); } if (backupsets.Count == 0) { if (!full) bs.SetTypeReason(Strings.Interface.FullBecauseBackendIsEmpty); full = true; } else { //A prioir backup exists, extract the compression and encryption modules used in the most recent entry string compression = null; string encryption = null; for (int i = backupsets.Count - 1; compression == null && i >= 0; i--) { for (int j = backupsets[i].Incrementals.Count - 1; compression == null && j >= 0; j--) for (int k = backupsets[i].Incrementals[j].Volumes.Count - 1; compression == null && k >= 0; k--) { compression = backupsets[i].Incrementals[j].Volumes[k].Key.Compression; encryption = backupsets[i].Incrementals[j].Volumes[k].Key.EncryptionMode; if (compression != null) break; } for (int k = backupsets[i].Volumes.Count - 1; compression == null && k >= 0; k--) { compression = backupsets[i].Volumes[k].Key.Compression; encryption = backupsets[i].Volumes[k].Key.EncryptionMode; if (compression != null) break; } } if (compression != null) { m_options.SetEncryptionModuleDefault(encryption); m_options.SetCompressionModuleDefault(compression); } } string fullCriteria1 = null; string fullCriteria2 = null; if (!full) { full = DateTime.Now > m_options.FullIfOlderThan(backupsets[backupsets.Count - 1].Time); if (full) bs.SetTypeReason(string.Format(Strings.Interface.FullBecauseLastFullIsFrom, backupsets[backupsets.Count - 1].Time, m_options.FullIfOlderThanValue)); else if (!string.IsNullOrEmpty(m_options.FullIfOlderThanValue)) fullCriteria1 = string.Format(Strings.Interface.IncrementalBecauseLastFullIsFrom, backupsets[backupsets.Count - 1].Time, m_options.FullIfOlderThanValue); } if (!full && m_options.FullIfMoreThanNIncrementals > 0) { full = backupsets[backupsets.Count - 1].Incrementals.Count >= m_options.FullIfMoreThanNIncrementals; if (full) bs.SetTypeReason(string.Format(Strings.Interface.FullBecauseThereAreNIncrementals, backupsets[backupsets.Count - 1].Incrementals.Count, m_options.FullIfMoreThanNIncrementals)); else fullCriteria2 = string.Format(Strings.Interface.IncrementalBecauseThereAreNIncrementals, backupsets[backupsets.Count - 1].Incrementals.Count, m_options.FullIfMoreThanNIncrementals); } bs.Full = full; if (!full) { if (fullCriteria1 == null && fullCriteria2 == null) bs.SetTypeReason(Strings.Interface.IncrementalBecauseNoFlagsWereSet); else if (fullCriteria2 == null) bs.SetTypeReason(fullCriteria1); else if (fullCriteria1 == null) bs.SetTypeReason(fullCriteria2); else bs.SetTypeReason(fullCriteria1 + ". " + fullCriteria2); } List<string> controlfiles = new List<string>(); if (!string.IsNullOrEmpty(m_options.SignatureControlFiles)) controlfiles.AddRange(m_options.SignatureControlFiles.Split(System.IO.Path.PathSeparator)); int vol = 0; long totalsize = 0; Manifestfile manifest = new Manifestfile(); using (Utility.TempFolder tempfolder = new XervBackup.Library.Utility.TempFolder()) { List<KeyValuePair<ManifestEntry, Library.Interface.ICompression>> patches = new List<KeyValuePair<ManifestEntry, XervBackup.Library.Interface.ICompression>>(); if (!full) { m_incrementalFraction = INCREMENAL_COST; List<ManifestEntry> entries = new List<ManifestEntry>(); entries.Add(backupsets[backupsets.Count - 1]); entries.AddRange(backupsets[backupsets.Count - 1].Incrementals); //Check before we start the download CheckLiveControl(); VerifyBackupChainWithFiles(backend, entries[entries.Count - 1]); if (m_options.CreateVerificationFile) verification = new VerificationFile(entries, backend.FilenameStrategy); OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusReadingIncrementals, ""); patches = FindPatches(backend, entries, tempfolder, false, bs); //Check before we start the download CheckLiveControl(); Manifestfile latest = GetManifest(backend, backupsets[backupsets.Count - 1]); //Manifest version 1 does not support multiple folders if (latest.Version == 1) latest.SourceDirs = new string[] { sources[0] }; if (latest.SourceDirs.Length != sources.Length) { if (m_options.FullIfSourceFolderChanged) { Logging.Log.WriteMessage("Source folder count changed, issuing full backup", XervBackup.Library.Logging.LogMessageType.Information); if (!full) bs.SetTypeReason(Strings.Interface.FullBecauseSourceFoldersChanged); full = true; } else throw new Exception(string.Format(Strings.Interface.NumberOfSourceFoldersHasChangedError, latest.SourceDirs.Length, sources.Length)); } else { if (!m_options.AllowSourceFolderChange) { foreach (string s1 in latest.SourceDirs) { bool found = false; foreach (string s2 in sources) if (s1.Equals(s2, Utility.Utility.IsFSCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) { found = true; break; } if (!found) { if (m_options.FullIfSourceFolderChanged) { Logging.Log.WriteMessage("Source folders changed, issuing full backup", XervBackup.Library.Logging.LogMessageType.Information); if (!full) bs.SetTypeReason(Strings.Interface.FullBecauseSourceFoldersChanged); full = true; break; //Exit the folder loop } else throw new Exception(string.Format(Strings.Interface.SourceFoldersHasChangedError, s1)); } } manifest.SourceDirs = latest.SourceDirs; } else { manifest.SourceDirs = sources; } } } DateTime backuptime = DateTime.Now; DateTime backupchaintime; if (full) { patches.Clear(); m_incrementalFraction = 0.0; manifest.SourceDirs = sources; if (m_options.CreateVerificationFile) verification = new VerificationFile(new ManifestEntry[0], backend.FilenameStrategy); backupchaintime = backuptime; } else { backupchaintime = patches[0].Key.Time; manifest.PreviousManifestFilename = patches[patches.Count - 1].Key.Filename; manifest.PreviousManifestHash = patches[patches.Count - 1].Key.RemoteHash; } OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, -1, -1, Strings.Interface.StatusBuildingFilelist, ""); bool completedWithoutChanges; using (RSync.RSyncDir dir = new XervBackup.Library.Main.RSync.RSyncDir(manifest.SourceDirs, bs, m_options.Filter, patches)) { CheckLiveControl(); dir.ProgressEvent += new XervBackup.Library.Main.RSync.RSyncDir.ProgressEventDelegate(BackupRSyncDir_ProgressEvent); dir.DisableFiletimeCheck = m_options.DisableFiletimeCheck; dir.MaxFileSize = m_options.SkipFilesLargerThan; using (new Logging.Timer("Initiating multipass")) dir.InitiateMultiPassDiff(full, m_options); string tempVolumeFolder = m_options.AsynchronousUpload ? m_options.AsynchronousUploadFolder : m_options.TempDir; bool done = false; while (!done && totalsize < m_options.MaxSize) { using (new Logging.Timer("Multipass " + (vol + 1).ToString())) using (Utility.TempFile signaturefile = new XervBackup.Library.Utility.TempFile(System.IO.Path.Combine(tempVolumeFolder, Guid.NewGuid().ToString()))) using (Utility.TempFile contentfile = new XervBackup.Library.Utility.TempFile(System.IO.Path.Combine(tempVolumeFolder, Guid.NewGuid().ToString()))) { OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusCreatingVolume, vol + 1), ""); CheckLiveControl(); using (Library.Interface.ICompression signaturearchive = DynamicLoader.CompressionLoader.GetModule(m_options.CompressionModule, signaturefile, m_options.RawOptions)) using (Library.Interface.ICompression contentarchive = DynamicLoader.CompressionLoader.GetModule(m_options.CompressionModule, contentfile, m_options.RawOptions)) { //If we are all out, stop now, this may cause incomplete partial files if (m_options.MaxSize - totalsize < (contentarchive.FlushBufferSize + backend.FileSizeOverhead)) break; //Add signature files to archive foreach (string s in controlfiles) if (!string.IsNullOrEmpty(s)) using (System.IO.Stream cs = signaturearchive.CreateFile(System.IO.Path.Combine(RSync.RSyncDir.CONTROL_ROOT, System.IO.Path.GetFileName(s)))) using (System.IO.FileStream fs = System.IO.File.OpenRead(s)) Utility.Utility.CopyStream(fs, cs); //Only add control files to the very first volume controlfiles.Clear(); done = dir.MakeMultiPassDiff(signaturearchive, contentarchive, (Math.Min(m_options.VolumeSize, m_options.MaxSize - totalsize)) - backend.FileSizeOverhead); //TODO: This is not the correct size, we need to account for file size overhead as well totalsize += signaturearchive.Size; totalsize += contentarchive.Size; //TODO: This is not the best way to determine this if (totalsize >= m_options.MaxSize) dir.FinalizeMultiPass(signaturearchive, contentarchive, long.MaxValue); } completedWithoutChanges = done && !dir.AnyChangesFound; if (m_options.UploadUnchangedBackups || full) completedWithoutChanges = false; if (!completedWithoutChanges) { if (m_options.AsynchronousUpload) { m_lastProgressMessage = Strings.Interface.StatusWaitingForUpload; m_allowUploadProgress = true; m_allowUploadProgressAfter = DateTime.Now.AddSeconds(1); } else OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusUploadingContentVolume, vol + 1), ""); //Last check before we upload, we do not interrupt transfers CheckLiveControl(); //The backendwrapper will remove these signaturefile.Protected = true; contentfile.Protected = true; ContentEntry ce = new ContentEntry(backuptime, full, vol + 1); SignatureEntry se = new SignatureEntry(backuptime, full, vol + 1); using (new Logging.Timer("Writing delta file " + (vol + 1).ToString())) backend.Put(ce, contentfile); if (!m_options.AsynchronousUpload) OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusUploadingSignatureVolume, vol + 1), ""); using (new Logging.Timer("Writing remote signatures")) backend.Put(se, signaturefile); manifest.AddEntries(ce, se); if (verification != null) { verification.AddFile(ce); verification.AddFile(se); } } } if (!completedWithoutChanges) { //The backend wrapper will remove these Utility.TempFile mf = new XervBackup.Library.Utility.TempFile(); using (new Logging.Timer("Writing manifest " + backuptime.ToUniversalTime().ToString("yyyyMMddTHHmmssK"))) { //Alternate primary/secondary ManifestEntry mfe = new ManifestEntry(backuptime, full, manifest.SignatureHashes.Count % 2 != 0); manifest.SelfFilename = backend.GenerateFilename(mfe); manifest.Save(mf); if (!m_options.AsynchronousUpload) OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusUploadingManifestVolume, vol + 1), ""); //Write the file mf.Protected = true; backend.Put(mfe, mf); if (verification != null) verification.UpdateManifest(mfe); } if (verification != null) { using (new Logging.Timer("Writing verification " + backuptime.ToUniversalTime().ToString("yyyyMMddTHHmmssK"))) { Utility.TempFile vt = new XervBackup.Library.Utility.TempFile(); verification.Save(vt); if (!m_options.AsynchronousUpload) OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusUploadingVerificationVolume, ""); vt.Protected = true; backend.Put(new VerificationEntry(backupchaintime), vt); } } if (m_options.AsynchronousUpload) m_allowUploadProgress = false; //The file volume counter vol++; } } } //If we are running asynchronous, we now enter the end-game if (m_options.AsynchronousUpload) { m_lastProgressMessage = Strings.Interface.StatusWaitingForUpload; m_allowUploadProgress = true; m_allowUploadProgressAfter = DateTime.Now; //Before we clear the temp folder, we need to ensure that all volumes are uploaded. //To allow the UI to show some progress while uploading, we perform the remaining // uploads synchronous List<KeyValuePair<BackupEntryBase, string>> pendingUploads = backend.ExtractPendingUploads(); //Figure out what volume number we are at foreach (KeyValuePair<BackupEntryBase, string> p in pendingUploads) if (p.Key is ManifestEntry) vol--; double unitcost = m_asyncReserved / pendingUploads.Count; //The upload each remaining volume in order foreach (KeyValuePair<BackupEntryBase, string> p in pendingUploads) { string msg; if (p.Key is ManifestEntry) { vol++; msg = string.Format(Strings.Interface.StatusUploadingManifestVolume, vol); } else if (p.Key is SignatureEntry) msg = string.Format(Strings.Interface.StatusUploadingSignatureVolume, ((SignatureEntry)p.Key).Volumenumber); else if (p.Key is ContentEntry) { msg = string.Format(Strings.Interface.StatusUploadingContentVolume, ((ContentEntry)p.Key).Volumenumber); //We allow a stop or pause request here CheckLiveControl(); } else if (p.Key is VerificationEntry) msg = Strings.Interface.StatusUploadingVerificationVolume; else throw new InvalidOperationException(); OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, (int)(m_progress * 100), -1, msg, ""); backend.Put(p.Key, p.Value); m_asyncReserved -= unitcost; m_progress += unitcost; } } } } catch(Exception ex) { //If this is a controlled user-requested stop, wait for the current upload to complete if (backend != null && ex is LiveControl.ExecutionStoppedException) { try { if (m_options.AsynchronousUpload) { m_lastProgressMessage = Strings.Interface.StatusWaitingForUpload; m_allowUploadProgress = true; m_allowUploadProgressAfter = DateTime.Now; //Wait for the current upload to complete and then delete all remaining temporary files foreach (KeyValuePair<BackupEntryBase, string> p in backend.ExtractPendingUploads()) try { if (System.IO.File.Exists(p.Value)) System.IO.File.Delete(p.Value); } catch { } //Better to delete as many as possible rather than choke on a single file } } catch { } //We already have an exception, just go with that } if (backend == null || backend.ManifestUploads == 0) { Logging.Log.WriteMessage(string.Format(Strings.Interface.ErrorRunningBackup, ex.Message), Logging.LogMessageType.Error); throw; //This also activates "finally", unlike in other languages... } Logging.Log.WriteMessage(string.Format(Strings.Interface.PartialUploadMessage, backend.ManifestUploads, ex.Message), Logging.LogMessageType.Warning); bs.LogError(string.Format(Strings.Interface.PartialUploadMessage, backend.ManifestUploads, ex.Message), ex); } finally { m_progress = 100.0; if (backend != null) try { backend.Dispose(); } catch { } if (OperationCompleted != null) OperationCompleted(this, XervBackupOperation.Backup, bs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); OperationProgress(this, XervBackupOperation.Backup, bs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); } } bs.EndTime = DateTime.Now; return bs.ToString(); }
public bool SaveAccount(SteamGuardAccount account, bool encrypt, string passKey = null) { if (encrypt && String.IsNullOrEmpty(passKey)) return false; if (!encrypt && this.Encrypted) return false; string salt = null; string iV = null; string jsonAccount = JsonConvert.SerializeObject(account); if (encrypt) { salt = FileEncryptor.GetRandomSalt(); iV = FileEncryptor.GetInitializationVector(); string encrypted = FileEncryptor.EncryptData(passKey, salt, iV, jsonAccount); if (encrypted == null) return false; jsonAccount = encrypted; } string maDir = Manifest.GetExecutableDir() + "/maFiles/"; string filename = account.Session.SteamID.ToString() + ".maFile"; ManifestEntry newEntry = new ManifestEntry() { SteamID = account.Session.SteamID, IV = iV, Salt = salt, Filename = filename }; bool foundExistingEntry = false; for (int i = 0; i < this.Entries.Count; i++) { if (this.Entries[i].SteamID == account.Session.SteamID) { this.Entries[i] = newEntry; foundExistingEntry = true; break; } } if (!foundExistingEntry) this.Entries.Add(newEntry); bool wasEncrypted = this.Encrypted; this.Encrypted = encrypt || this.Encrypted; if (!this.Save()) { this.Encrypted = wasEncrypted; return false; } try { File.WriteAllText(maDir + filename, jsonAccount); return true; } catch (Exception e) { return false; } }
private static Manifest _generateNewManifest(bool scanDir = false) { //No directory means no manifest file anyways. Manifest newManifest = new Manifest(); newManifest.Encrypted = false; newManifest.Entries = new List<ManifestEntry>(); //Take a pre-manifest version and generate a manifest for it. if (scanDir) { string maDir = Manifest.GetExecutableDir() + "/maFiles/"; if (Directory.Exists(maDir)) { DirectoryInfo dir = new DirectoryInfo(maDir); var files = dir.GetFiles(); foreach (var file in files) { if (file.Extension != ".maFile") continue; string contents = File.ReadAllText(file.FullName); try { SteamGuardAccount account = JsonConvert.DeserializeObject<SteamGuardAccount>(contents); ManifestEntry newEntry = new ManifestEntry() { Filename = file.Name, SteamID = account.Session.SteamID }; newManifest.Entries.Add(newEntry); } catch (Exception e) { } } if (newManifest.Entries.Count > 0) { newManifest.Save(); newManifest.PromptSetupPassKey("This version of SDA has encryption. Please enter a passkey below, or hit cancel to remain unencrypted"); } } } if (newManifest.Save()) return newManifest; return null; }