示例#1
0
        void UpdateEntry(ref AppliedFileEntry entry, uint speed = 0)
        {
            var update = "REPLACE INTO `updates` (`name`, `hash`, `state`, `speed`) VALUES (\"" +
                         entry.Name + "\", \"" + entry.Hash + "\", \'" + entry.State.ToString() + "\', " + speed.ToString() + ")";

            // Update database
            _apply(update);
        }
示例#2
0
        AppliedFileStorage ReceiveAppliedFiles()
        {
            var map = new Dictionary <string, AppliedFileEntry>();

            var result = _retrieve("SELECT `name`, `hash`, `state`, UNIX_TIMESTAMP(`timestamp`) FROM `updates` ORDER BY `name` ASC");

            if (result == null)
            {
                return(map);
            }

            do
            {
                var field = result.Fetch();
                var entry = new AppliedFileEntry(field[0].GetString(), field[1].GetString(),
                                                 field[2].GetString().ToEnum <State>(), field[3].GetUInt32());
                map.Add(entry.Name, entry);
            }while (result.NextRow());

            result.Dispose();

            return(map);
        }
示例#3
0
        public UpdateResult Update(bool redundancyChecks, bool allowRehash, bool archivedRedundancy, int cleanDeadReferencesMaxCount)
        {
            var available = GetFileList();
            AppliedFileStorage applied = ReceiveAppliedFiles();

            int countRecentUpdates   = 0;
            int countArchivedUpdates = 0;

            // Count updates
            foreach (var entry in applied.Values)
            {
                if (entry.State == State.RELEASED)
                {
                    ++countRecentUpdates;
                }
                else
                {
                    ++countArchivedUpdates;
                }
            }

            // Fill hash to name cache
            HashToFileNameStorage hashToName = new HashToFileNameStorage();

            foreach (var entry in applied)
            {
                hashToName[entry.Value.Hash] = entry.Key;
            }

            int importedUpdates = 0;

            foreach (var availableQuery in available)
            {
                var filename = availableQuery.GetFileName();
                FEL_LOG_DEBUG("sql.updates", "Checking update \"{0}\"...", filename);

                AppliedFileEntry appliedFile;
                bool             filenameApplied = applied.TryGetValue(filename, out appliedFile);

                if (filenameApplied)
                {
                    // If redundancy is disabled, skip it, because the update is already applied.
                    if (!redundancyChecks)
                    {
                        FEL_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks.");
                        applied.Remove(filename);
                        continue;
                    }

                    // If the update is in an archived directory and is marked as archived in our database, skip redundancy checks (archived updates never change).
                    if (!archivedRedundancy && (appliedFile.State == State.ARCHIVED) && (availableQuery.State == State.ARCHIVED))
                    {
                        FEL_LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks.");
                        applied.Remove(filename);
                        continue;
                    }
                }

                // Calculate a Sha1 hash based on query content.
                string hash = ByteArrayToHexStr(DigestSHA1(ReadSQLUpdate(availableQuery.FilePath)));

                UpdateMode mode = UpdateMode.MODE_APPLY;

                // Update is not in our applied list
                if (!filenameApplied)
                {
                    // Catch renames (different filename, but same hash)
                    if (hashToName.TryGetValue(hash, out filename))
                    {
                        // Check if the original file was removed. If not, we've got a problem.
                        LocaleFileEntry?renameFile = null;
                        foreach (var item in available)
                        {
                            if (item.GetFileName() == filename)
                            {
                                renameFile = item;
                                break;
                            }
                        }

                        // Conflict!
                        if (renameFile != null)
                        {
                            FEL_LOG_WARN("sql.updates", ">> It seems like the update \"{0}\" \'{1}\' was renamed, but the old file is still there! Treating it as a new file! (It is probably an unmodified copy of the file \"{2}\")",
                                         availableQuery.GetFileName(), hash.Substring(0, 7), renameFile.Value.GetFileName());
                        }
                        // It is safe to treat the file as renamed here
                        else
                        {
                            FEL_LOG_INFO("sql.updates", ">> Renaming update \"{0}\" to \"{1}\" \'{2}\'.", filename, availableQuery.GetFileName(), hash.Substring(0, 7));

                            RenameEntry(filename, availableQuery.GetFileName());
                            applied.Remove(filename);
                            continue;
                        }
                    }
                    // Apply the update if it was never seen before.
                    else
                    {
                        FEL_LOG_INFO("sql.updates", ">> Applying update \"{0}\" \'{1}\'...", availableQuery.GetFileName(), hash.Substring(0, 7));
                    }
                }
                // Rehash the update entry if it exists in our database with an empty hash.
                else if (allowRehash && string.IsNullOrEmpty(appliedFile.Hash))
                {
                    mode = UpdateMode.MODE_REHASH;

                    FEL_LOG_INFO("sql.updates", ">> Re-hashing update \"{0}\" \'{1}\'...", availableQuery.GetFileName(), hash.Substring(0, 7));
                }
                else
                {
                    // If the hash of the files differs from the one stored in our database, reapply the update (because it changed).
                    if (appliedFile.Hash != hash)
                    {
                        FEL_LOG_INFO("sql.updates", ">> Reapplying update \"{0}\" \'{1}\' -> \'{2}\' (it changed)...", availableQuery.GetFileName(),
                                     appliedFile.Hash.Substring(0, 7), hash.Substring(0, 7));
                    }
                    else
                    {
                        // If the file wasn't changed and just moved, update its state (if necessary).
                        if (appliedFile.State != availableQuery.State)
                        {
                            FEL_LOG_DEBUG("sql.updates", ">> Updating the state of \"{0}\" to \'{1}\'...", availableQuery.GetFileName(), availableQuery.State);

                            UpdateState(availableQuery.GetFileName(), availableQuery.State);
                        }

                        FEL_LOG_DEBUG("sql.updates", ">> Update is already applied and matches the hash \'{0}\'.", hash.Substring(0, 7));

                        applied.Remove(appliedFile.Name);
                        continue;
                    }
                }

                uint speed = 0;
                var  file  = new AppliedFileEntry(availableQuery.GetFileName(), hash, availableQuery.State, 0);

                switch (mode)
                {
                case UpdateMode.MODE_APPLY:
                    speed = Apply(availableQuery.FilePath);
                    goto case UpdateMode.MODE_REHASH;

                case UpdateMode.MODE_REHASH:
                    UpdateEntry(ref file, speed);
                    break;
                }

                if (filenameApplied)
                {
                    applied.Remove(appliedFile.Name);
                }

                if (mode == UpdateMode.MODE_APPLY)
                {
                    ++importedUpdates;
                }
            }

            // Cleanup up orphaned entries (if enabled)
            if (applied.Count > 0)
            {
                bool doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.Count <= cleanDeadReferencesMaxCount);

                foreach (var entry in applied)
                {
                    FEL_LOG_WARN("sql.updates", ">> The file \'{0}\' was applied to the database, but is missing in your update directory now!", entry.Key);

                    if (doCleanup)
                    {
                        FEL_LOG_INFO("sql.updates", "Deleting orphaned entry \'{0}\'...", entry.Key);
                    }
                }

                if (doCleanup)
                {
                    CleanUp(applied);
                }
                else
                {
                    FEL_LOG_ERROR("sql.updates", "Cleanup is disabled! There were {0} dirty files applied to your database, but they are now missing in your source directory!", applied.Count);
                }
            }

            return(new UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates));
        }