/// <summary> /// Calculates estimated update size in bytes based on local and remote build information. /// </summary> /// <returns>The estimated update size in bytes.</returns> private long GetUpdateSize() { // We don't take into account potential local modified or corrupted files, // instead we assume that all files listed in the local build info match // the actual files on the local file system. // This is because checking the actual hashes of the files would take too // long for a quick update check. Instead we'll check the actual file // hashes when actually downloading the update. // This is why the calculated update size could only be an estimate // (although it'll be correct for everyone who doesn't modify the product). long updateSize = 0; LocalBuildInfo lbi = localBuildInfo; RemoteBuildInfo rbi = remoteBuildInfo; foreach (var fileInfo in rbi.FileInfos) { var localMatch = lbi.FileInfos.Find(localFileInfo => localFileInfo.FilePath == fileInfo.FilePath); if (localMatch == null || !HashHelper.ByteArraysMatch(localMatch.Hash, fileInfo.UncompressedHash)) { updateSize += fileInfo.GetDownloadSize(); } } return(updateSize); }
/// <summary> /// Cleans the build directory from files that don't exist in the list /// of files for the build. /// </summary> public void CleanBuildDirectory() { char dsc = Path.DirectorySeparatorChar; string buildDirectory = Environment.CurrentDirectory + dsc + BuildDirectory; string[] files = Directory.GetFiles(buildDirectory, "*", SearchOption.AllDirectories); RemoteBuildInfo remoteBuildInfo = new RemoteBuildInfo(); if (File.Exists(buildDirectory + dsc + BuildHandler.REMOTE_BUILD_INFO_FILE)) { remoteBuildInfo.Parse(buildDirectory + dsc + BuildHandler.REMOTE_BUILD_INFO_FILE); } foreach (string path in files) { string relativePath = path.Substring(buildDirectory.Length + 1); if (relativePath == BuildHandler.LOCAL_BUILD_INFO_FILE || relativePath == BuildHandler.REMOTE_BUILD_INFO_FILE) { continue; } if (remoteBuildInfo.FileInfos.Find(f => f.GetFilePathWithCompression() == relativePath) == null) { Console.WriteLine("Deleting " + relativePath); File.Delete(path); } } }
/// <summary> /// Writes new local and remote version files into the build directory. /// </summary> public void WriteVersionFiles() { var localBuildInfo = new LocalBuildInfo(); localBuildInfo.ProductVersionInfo = new ProductVersionInfo(InternalVersion, DisplayedVersion); var remoteBuildInfo = new RemoteBuildInfo(); remoteBuildInfo.ProductVersionInfo = new ProductVersionInfo(InternalVersion, DisplayedVersion); string buildPath = Environment.CurrentDirectory + Path.DirectorySeparatorChar + BuildDirectory + Path.DirectorySeparatorChar; foreach (FileEntry file in FileEntries) { string originalFilePath = Environment.CurrentDirectory + Path.DirectorySeparatorChar + file.FilePath; byte[] hash = HashHelper.ComputeHashForFile(originalFilePath); long size = new FileInfo(originalFilePath).Length; localBuildInfo.AddFileInfo(new LocalFileInfo(file.FilePath, hash, size)); RemoteFileInfo remoteFileInfo; if (file.Compressed) { string compressedFilePath = buildPath + file.FilePath + RemoteFileInfo.COMPRESSED_FILE_EXTENSION; remoteFileInfo = new RemoteFileInfo(file.FilePath, hash, size, true, HashHelper.ComputeHashForFile(compressedFilePath), new FileInfo(compressedFilePath).Length); } else { remoteFileInfo = new RemoteFileInfo(file.FilePath, hash, size, false); } remoteBuildInfo.AddFileInfo(remoteFileInfo); } localBuildInfo.Write(buildPath + BuildHandler.LOCAL_BUILD_INFO_FILE); remoteBuildInfo.Write(buildPath + BuildHandler.REMOTE_BUILD_INFO_FILE); }
private void CheckForUpdatesInternal() { UpdaterLogger.Log("Checking for updates."); updateMirrors = updateMirrors.OrderBy(um => um.Rating).ToList(); using (WebClient webClient = CreateWebClient()) { webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); webClient.Encoding = Encoding.GetEncoding(1252); CreateTemporaryDirectory(); int i = 0; UpdateMirror updateMirror; string downloadDirectory = localBuildInfo.BuildPath + TEMPORARY_UPDATER_DIRECTORY + Path.DirectorySeparatorChar; while (i < updateMirrors.Count) { updateMirror = updateMirrors[i]; UpdaterLogger.Log("Attempting to download version information from " + updateMirror.UIName + " (" + updateMirror.URL + ")"); try { webClient.DownloadFile(updateMirror.URL + REMOTE_BUILD_INFO_FILE, downloadDirectory + REMOTE_BUILD_INFO_FILE); UpdaterLogger.Log("Version information downloaded, proceeding to parsing it."); remoteBuildInfo = new RemoteBuildInfo(); remoteBuildInfo.Parse(downloadDirectory + REMOTE_BUILD_INFO_FILE); lastUpdateMirrorId = i; lock (locker) { updateCheckInProgress = false; } if (remoteBuildInfo.ProductVersionInfo.VersionNumber == localBuildInfo.ProductVersionInfo.VersionNumber) { BuildState = BuildState.UPTODATE; BuildUpToDate?.Invoke(this, EventArgs.Empty); return; } else { BuildState = BuildState.OUTDATED; BuildOutdated?.Invoke(this, new BuildOutdatedEventArgs( remoteBuildInfo.ProductVersionInfo.DisplayString, GetUpdateSize())); return; } } catch (WebException ex) { UpdaterLogger.Log("WebException when downloading version information: " + ex.Message); i++; } catch (ParseException ex) { UpdaterLogger.Log("ParseException when parsing version information: " + ex.Message); i++; } catch (FormatException ex) { UpdaterLogger.Log("FormatException when parsing version information: " + ex.Message); i++; } } } UpdaterLogger.Log("Failed to download version information from all update mirrors. Aborting."); lock (locker) { updateCheckInProgress = false; } UpdateCheckFailed?.Invoke(this, EventArgs.Empty); }
/// <summary> /// Gathers a list of files that do not exist or are outdated in the /// build directory. /// </summary> public List <FileEntry> GetOutdatedFileList() { string targetDirectory = Environment.CurrentDirectory + Path.DirectorySeparatorChar + BuildDirectory; // If the build directory doesn't exist, we need to process all the files if (!Directory.Exists(targetDirectory)) { return(new List <FileEntry>(FileEntries)); } if (targetDirectory[targetDirectory.Length - 1] != Path.DirectorySeparatorChar) { targetDirectory = targetDirectory + Path.DirectorySeparatorChar; } RemoteBuildInfo remoteBuildInfo = new RemoteBuildInfo(); if (File.Exists(targetDirectory + BuildHandler.REMOTE_BUILD_INFO_FILE)) { remoteBuildInfo.Parse(targetDirectory + BuildHandler.REMOTE_BUILD_INFO_FILE); } List <FileEntry> outdatedList = new List <FileEntry>(); foreach (FileEntry file in FileEntries) { string filePath = targetDirectory + file.FilePath; string originalFilePath = Environment.CurrentDirectory + Path.DirectorySeparatorChar + file.FilePath; if (file.Compressed) { // Compressed files have an additional file extension filePath = filePath + RemoteFileInfo.COMPRESSED_FILE_EXTENSION; } if (!File.Exists(filePath)) { // If the file doesn't exist in the build, we obviously need // to process it outdatedList.Add(file); continue; } if (file.Compressed) { // If the file is compressed, check if the uncompressed hash // in RemoteVersion matches the hash of the original (uncompressed) file // If not (or there is no record of the file in RemoteVersion), we need // to process the file RemoteFileInfo existingFileInfo = remoteBuildInfo.FileInfos.Find( f => f.FilePath == file.FilePath); if (existingFileInfo == null || !HashHelper.ByteArraysMatch(existingFileInfo.UncompressedHash, HashHelper.ComputeHashForFile(originalFilePath))) { outdatedList.Add(file); } } else { // For uncompressed files we can just compare its hash // to the original file's hash directly if (!HashHelper.ByteArraysMatch(HashHelper.ComputeHashForFile(filePath), HashHelper.ComputeHashForFile(originalFilePath))) { outdatedList.Add(file); } } } return(outdatedList); }