public async Task ValidateAndFixAsync()

in Core/src/Impl/Commands/StorageManager.cs [184:285]


    public async Task<(Statistics statistics, long deleted)> ValidateAndFixAsync(
      int degreeOfParallelism,
      IEnumerable<TagFileData> items,
      IEnumerable<SymbolStoragePath> files,
      StorageFormat storageFormat,
      ValidateMode mode,
      bool verifyAcl = false)
    {
      myLogger.Info($"[{DateTime.Now:s}] Validating storage{myId}...");
      var fix = mode == ValidateMode.Fix || mode == ValidateMode.Delete;
      var statistics = new Statistics();
      ILogger logger = new LoggerWithStatistics(myLogger, statistics);
      files = await ValidateAndFixDataFilesAsync(logger, degreeOfParallelism, files, storageFormat, fix);
      var tree = CreateDirectoryTree(degreeOfParallelism, files);
      await items.ParallelForAsync(degreeOfParallelism, async item =>
        {
          var tagFile = item.TagFile;
          var tag = item.Tag;
          logger.Verbose($"  Validating {tagFile}");
          var isDirty = false;

          if (!TagUtil.ValidateProduct(tag.Product))
            logger.Error($"Invalid product {tag.Product} in file {tagFile}");

          if (!TagUtil.ValidateVersion(tag.Version))
            logger.Error($"Invalid version {tag.Version} in file {tagFile}");

          if (tag.CreationUtcTime == DateTime.MinValue)
          {
            logger.Error($"The empty creation time in {tagFile}");
            if (fix)
            {
              var newCreationUtcTime = TryFixCreationTime(tag);
              if (newCreationUtcTime != null)
              {
                logger.Fix($"The creation time will be assigned to tag {tagFile}");
                isDirty = true;
                tag.CreationUtcTime = newCreationUtcTime.Value;
              }
            }
          }

          if (tag.Directories.Length == 0)
          {
            logger.Error($"The empty directory list in {tagFile}");
            if (fix)
            {
              logger.Fix($"The tag will be deleted {tagFile}");
              await myStorage.DeleteAsync(tagFile);
              return;
            }
          }
          else
          {
            for (var index = 0; index < tag.Directories.Length; index++)
            {
              var dir = tag.Directories[index];

              switch (dir.ValidateAndFixDataPath(StorageFormat.Normal, out var fixedDir))
              {
              case PathUtil.ValidateAndFixErrors.Ok:
                break;
              case PathUtil.ValidateAndFixErrors.Error:
                logger.Error($"The tag directory {dir} from {tagFile} has invalid format");
                break;
              case PathUtil.ValidateAndFixErrors.CanBeFixed:
                logger.Error($"The tag directory {dir} from {tagFile} has invalid format");
                if (fix)
                {
                  isDirty = true;
                  tag.Directories[index] = fixedDir;
                }

                break;
              default:
                throw new ArgumentException("Unknown ValidateAndFixErrors value");
              }

              var dstDir = dir.ValidateAndFixDataPath(storageFormat, out fixedDir) == PathUtil.ValidateAndFixErrors.CanBeFixed ? fixedDir : dir;
              var node = tree.LookupPathRecursive(dstDir);
              
              if (node == null)
                logger.Error($"The directory {dir} from {tagFile} id wasn't found");
              else
                node.IncrementReferences();
            }
          }

          if (isDirty)
          {
            logger.Info($"The tag file {tagFile} will be overwritten");
            using var stream = new MemoryStream();
            await TagUtil.WriteTagScriptAsync(tag, stream);
            await myStorage.CreateForWritingAsync(tagFile, AccessMode.Private, stream);
          }
        });

      var deleted = await ValidateAndDeleteUnreachableAsync(logger, tree, mode);
      if (verifyAcl)
        await ValidateAndFixAclAsync(logger, degreeOfParallelism, files, fix);
      return (statistics, deleted);
    }