Esempio n. 1
0
        } //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
Esempio n. 2
0
        public void TestInvalidTooManyElements()
        {
            ManifestEntry createdEntry;
            bool          parsingSucceded = ManifestEntry.TryParse(InvalidInputTooManyElements, out createdEntry);

            Assert.That(!parsingSucceded);
        }
Esempio n. 3
0
        public void TestInvalidHashTooShort()
        {
            ManifestEntry createdEntry;
            bool          parsingSucceded = ManifestEntry.TryParse(InvalidInputHashTooShort, out createdEntry);

            Assert.That(!parsingSucceded);
        }
Esempio n. 4
0
        public void TestInvalidNegativeSize()
        {
            ManifestEntry createdEntry;
            bool          parsingSucceded = ManifestEntry.TryParse(InvalidInputNegativeSize, out createdEntry);

            Assert.That(!parsingSucceded);
        }
Esempio n. 5
0
        } //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
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
            }
        }
Esempio n. 8
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);
        }
Esempio n. 10
0
        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));
                }
            }
        }
Esempio n. 11
0
        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>();
            }
        }
Esempio n. 12
0
        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.");
            }
        }
Esempio n. 13
0
        public void TestInvalidMissingHash()
        {
            ManifestEntry createdEntry;
            bool          parsingSucceded = ManifestEntry.TryParse(InvalidInputMissingHash, out createdEntry);

            Assert.That(!parsingSucceded);
        }
Esempio n. 14
0
    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);
    }
Esempio n. 15
0
        public void TestCreateFromValidInput()
        {
            bool parsingSucceded = ManifestEntry.TryParse(ValidInput, out var createdEntry);

            Assert.That(parsingSucceded);
            Assert.AreEqual(this.ExpectedObject, createdEntry);
        }
Esempio n. 16
0
    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);
        }
Esempio n. 20
0
        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);
        }
Esempio n. 21
0
        /// <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);
        }
Esempio n. 22
0
        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++;
                }
            }
        }
    }
Esempio n. 24
0
 // 比对两个 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);
 }
Esempio n. 25
0
        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);
        }
Esempio n. 26
0
            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();
        }
Esempio n. 28
0
        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);
        }
Esempio n. 29
0
        // 基本流程:
        // 在不知道清单文件校验值和大小的情况下, 使用此接口尝试先下载 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);
        }
Esempio n. 31
0
        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;
        }
Esempio n. 32
0
        /// <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;
                }
            }
        }
Esempio n. 33
0
        /// <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;
            }
        }
Esempio n. 34
0
        /// <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;
            }
        }
Esempio n. 35
0
 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));
 }
Esempio n. 36
0
        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;
        }