/// <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)
        {
            var localPath = $"{DirectoryHelpers.GetLocalGameDirectory()}{entry.RelativePath}";

            if (!File.Exists(localPath))
            {
                return(false);
            }

            var 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);
        }
 /// <summary>
 /// Loads the old manifest from disk.
 /// </summary>
 private void LoadOldManifest()
 {
     try
     {
         lock (OldManifestLock)
         {
             if (File.Exists(ConfigHandler.GetOldManifestPath()))
             {
                 string[] rawOldManifest = File.ReadAllLines(ConfigHandler.GetOldManifestPath());
                 foreach (string rawEntry in rawOldManifest)
                 {
                     ManifestEntry newEntry = new ManifestEntry();
                     if (ManifestEntry.TryParse(rawEntry, out newEntry))
                     {
                         oldManifest.Add(newEntry);
                     }
                 }
             }
         }
     }
     catch (IOException ioex)
     {
         Console.WriteLine("IOException in LoadOldManifest(): " + ioex.Message);
     }
 }
        /// <summary>
        /// Attempts to parse an entry from a raw input.
        /// The input is expected to be in [path]:[hash]:[size] format.
        /// </summary>
        /// <returns><c>true</c>, if the input was successfully parse, <c>false</c> otherwise.</returns>
        /// <param name="rawInput">Raw input.</param>
        /// <param name="entry">The resulting entry.</param>
        public static bool TryParse(string rawInput, out ManifestEntry inEntry)
        {
            //clear out the entry for the new data
            inEntry = new ManifestEntry();

            if (!String.IsNullOrEmpty(rawInput))
            {
                //remove any and all bad characters from the input string,
                //such as \0, \n and \r.
                string cleanInput = Utilities.Clean(rawInput);

                //split the string into its three components - file, hash and size
                string[] entryElements = cleanInput.Split(':');

                //if we have three elements (which we should always have), set them in the provided entry
                if (entryElements.Length == 3)
                {
                    //clean the manifest path, converting \ to / on unix and / to \ on Windows.
                    if (ChecksHandler.IsRunningOnUnix())
                    {
                        inEntry.RelativePath = entryElements [0].Replace("\\", "/");
                    }
                    else
                    {
                        inEntry.RelativePath = entryElements [0].Replace("/", "\\");
                    }

                    //set the hash to the second element
                    inEntry.Hash = entryElements [1];

                    //attempt to parse the final element as a long-type byte count.
                    long parsedSize = 0;
                    if (long.TryParse(entryElements[2], out parsedSize))
                    {
                        inEntry.Size = parsedSize;
                        return(true);
                    }
                    else
                    {
                        //could not parse the size, parsing has failed.
                        return(false);
                    }
                }
                else
                {
                    //wrong number of raw entry elements, parsing has failed.
                    return(false);
                }
            }
            else
            {
                //no input, parsing has failed
                return(false);
            }
        }
        /// <summary>
        /// Attempts to parse an entry from a raw input.
        /// The input is expected to be in [path]:[hash]:[size] format.
        /// </summary>
        /// <returns><c>true</c>, if the input was successfully parse, <c>false</c> otherwise.</returns>
        /// <param name="rawInput">Raw input.</param>
        /// <param name="entry">The resulting entry.</param>
        public static bool TryParse(string rawInput, out ManifestEntry inEntry)
        {
            //clear out the entry for the new data
            inEntry = new ManifestEntry ();

            if (!String.IsNullOrEmpty(rawInput))
            {
                //remove any and all bad characters from the input string,
                //such as \0, \n and \r.
                string cleanInput = Utilities.Clean (rawInput);

                //split the string into its three components - file, hash and size
                string[] entryElements = cleanInput.Split (':');

                //if we have three elements (which we should always have), set them in the provided entry
                if (entryElements.Length == 3)
                {
                    //clean the manifest path, converting \ to / on unix and / to \ on Windows.
                    if (ChecksHandler.IsRunningOnUnix())
                    {
                        inEntry.RelativePath = entryElements [0].Replace ("\\", "/");
                    }
                    else
                    {
                        inEntry.RelativePath = entryElements [0].Replace("/", "\\");
                    }

                    //set the hash to the second element
                    inEntry.Hash = entryElements [1];

                    //attempt to parse the final element as a long-type byte count.
                    long parsedSize = 0;
                    if(long.TryParse(entryElements[2], out parsedSize))
                    {
                        inEntry.Size = parsedSize;
                        return true;
                    }
                    else
                    {
                        //could not parse the size, parsing has failed.
                        return false;
                    }
                }
                else
                {
                    //wrong number of raw entry elements, parsing has failed.
                    return false;
                }
            }
            else
            {
                //no input, parsing has failed
                return false;
            }
        }
Exemple #5
0
        private void InstallGameAsync()
        {
            //This value is filled with either a path to the last downloaded file, or with an exception message
            //this message is used in the main UI to determine how it responds to a failed download.
            string fileReturn = "";

            try
            {
                FTPHandler           FTP             = new FTPHandler();
                ManifestHandler      manifestHandler = new ManifestHandler();
                List <ManifestEntry> Manifest        = manifestHandler.Manifest;

                //create the .install file to mark that an installation has begun
                //if it exists, do nothing.
                ConfigHandler.CreateInstallCookie();


                //raise the progress changed event by binding to the
                //event in the FTP class
                FTP.FileProgressChanged += OnDownloadProgressChanged;

                //in order to be able to resume downloading, we check if there is an entry
                //stored in the install cookie.
                ManifestEntry lastDownloadedFile = null;
                string        installCookiePath  = ConfigHandler.GetInstallCookiePath();

                //attempt to parse whatever is inside the install cookie
                if (ManifestEntry.TryParse(File.ReadAllText(installCookiePath), out lastDownloadedFile))
                {
                    //loop through all the entries in the manifest until we encounter
                    //an entry which matches the one in the install cookie

                    foreach (ManifestEntry Entry in Manifest)
                    {
                        if (lastDownloadedFile == Entry)
                        {
                            //remove all entries before the one we were last at.
                            Manifest.RemoveRange(0, Manifest.IndexOf(Entry));
                        }
                    }
                }

                //then, start downloading the entries that remain in the manifest.
                foreach (ManifestEntry Entry in Manifest)
                {
                    string RemotePath = String.Format("{0}{1}",
                                                      Config.GetGameURL(true),
                                                      Entry.RelativePath);

                    string LocalPath = String.Format("{0}{1}{2}",
                                                     Config.GetGamePath(true),
                                                     System.IO.Path.DirectorySeparatorChar,
                                                     Entry.RelativePath);

                    //make sure we have a game directory to put files in
                    Directory.CreateDirectory(Path.GetDirectoryName(LocalPath));

                    //write the current file progress to the install cookie
                    TextWriter textWriterProgress = new StreamWriter(ConfigHandler.GetInstallCookiePath());
                    textWriterProgress.WriteLine(Entry.ToString());
                    textWriterProgress.Close();

                    if (File.Exists(LocalPath))
                    {
                        FileInfo fileInfo = new FileInfo(LocalPath);
                        if (fileInfo.Length != Entry.Size)
                        {
                            //Resume the download of this partial file.
                            OnProgressChanged();
                            fileReturn = FTP.DownloadFTPFile(RemotePath, LocalPath, fileInfo.Length, false);

                            //Now verify the file
                            string localHash = MD5Handler.GetFileHash(File.OpenRead(LocalPath));

                            if (localHash != Entry.Hash)
                            {
                                Console.WriteLine("InstallGameAsync: Resumed file hash was invalid, downloading fresh copy from server.");
                                OnProgressChanged();
                                fileReturn = FTP.DownloadFTPFile(RemotePath, LocalPath, false);
                            }
                        }
                    }
                    else
                    {
                        //no file, download it
                        OnProgressChanged();
                        fileReturn = FTP.DownloadFTPFile(RemotePath, LocalPath, false);
                    }

                    if (ChecksHandler.IsRunningOnUnix())
                    {
                        //if we're dealing with a file that should be executable,
                        string gameName = Config.GetGameName();
                        bool   bFileIsGameExecutable = (Path.GetFileName(LocalPath).EndsWith(".exe")) || (Path.GetFileNameWithoutExtension(LocalPath) == gameName);
                        if (bFileIsGameExecutable)
                        {
                            //set the execute bits
                            UnixHandler.MakeExecutable(LocalPath);
                        }
                    }
                }

                //we've finished the download, so empty the cookie
                File.WriteAllText(ConfigHandler.GetInstallCookiePath(), String.Empty);

                //raise the finished event
                OnGameDownloadFinished();

                //clear out the event handler
                FTP.FileProgressChanged -= OnDownloadProgressChanged;
            }
            catch (IOException ioex)
            {
                Console.WriteLine("IOException in InstallGameAsync(): " + ioex.Message);

                DownloadFailedArgs.Result     = "1";
                DownloadFailedArgs.ResultType = "Install";
                DownloadFinishedArgs.Metadata = fileReturn;

                OnGameDownloadFailed();
            }
        }
 /// <summary>
 /// Loads the old manifest from disk.
 /// </summary>
 private void LoadOldManifest()
 {
     try
     {
         lock (OldManifestLock)
         {
             if (File.Exists(ConfigHandler.GetOldManifestPath()))
             {
                 string[] rawOldManifest = File.ReadAllLines (ConfigHandler.GetOldManifestPath ());
                 foreach (string rawEntry in rawOldManifest)
                 {
                     ManifestEntry newEntry = new ManifestEntry ();
                     if (ManifestEntry.TryParse (rawEntry, out newEntry))
                     {
                         oldManifest.Add (newEntry);
                     }
                 }
             }
         }
     }
     catch (IOException ioex)
     {
         Console.WriteLine ("IOException in LoadOldManifest(): " + ioex.Message);
     }
 }