private NativeData CheckSuperMemoExecutable()
        {
            var nativeDataCfg = LoadNativeDataConfig();
            var smFile        = new FilePath(StartupConfig.SMBinPath);

            if (smFile.Exists() == false)
            {
                throw new SMAException(
                          $"Invalid file path for sm executable file: '{StartupConfig.SMBinPath}' could not be found. SMA cannot continue.");
            }

            if (smFile.HasPermission(FileIOPermissionAccess.Read) == false)
            {
                throw new SMAException($"SMA needs read access to execute SM executable at {smFile.FullPath}.");
            }

            if (smFile.IsLocked())
            {
                throw new SMAException($"{smFile.FullPath} is locked. Make sure it isn't already running.");
            }

            var smFileCrc32 = FileEx.GetCrc32(smFile.FullPath);
            var nativeData  = nativeDataCfg.SafeGet(smFileCrc32.ToUpper(CultureInfo.InvariantCulture));

            if (nativeData == null)
            {
                throw new SMAException($"Unknown SM executable version with crc32 {smFileCrc32}.");
            }

            LogTo.Information($"SuperMemo version {nativeData.SMVersion} detected");

            return(nativeData);
        }
        public static bool CheckSuperMemoExecutable(
            NativeDataCfg nativeDataCfg,
            FilePath smFile,
            out NativeData nativeData,
            out SMAException ex)
        {
            nativeData = null;

            if (smFile == null)
            {
                ex = new SMAException("SM exe file path is null", new ArgumentNullException(nameof(smFile)));
                return(false);
            }

            if (smFile.Exists() == false)
            {
                ex = new SMAException(
                    $"Invalid file path for sm executable file: '{smFile}' could not be found. SMA cannot continue.");
                return(false);
            }

            if (smFile.HasPermission(FileIOPermissionAccess.Read) == false)
            {
                ex = new SMAException($"SMA needs read access to execute SM executable at {smFile.FullPath}.");
                return(false);
            }

            if (smFile.IsLocked())
            {
                ex = new SMAException($"{smFile.FullPath} is locked. Make sure it isn't already running.");
                return(false);
            }

            var smFileCrc32 = FileEx.GetCrc32(smFile.FullPath);

            nativeData = nativeDataCfg.SafeGet(smFileCrc32.ToUpper(CultureInfo.InvariantCulture));

            if (nativeData == null)
            {
                ex = new SMAException($"Unknown SM executable version with crc32 {smFileCrc32}.");
                return(false);
            }

            ex = null;

            return(true);
        }
        public CollectionFile Create(
            [NotNull] ISMAPlugin requester,
            int elementId,
            [NotNull] Action <Stream> streamWriter,
            string extension,
            string crc32 = null)
        {
            if (elementId <= 0)
            {
                return(null);
            }

            CollectionFSFile dbFile = null;

            try
            {
                extension = extension?.TrimStart('.');

                dbFile = new CollectionFSFile
                {
                    ElementId = elementId,
                    Extension = extension ?? string.Empty,
                    PluginId  = requester.Id
                };

                dbFile.Id = DbFiles.Insert(dbFile).AsInt32;

                CollectionFile colFile = FromDbFile(dbFile);

                DirectoryEx.EnsureExists(Path.GetDirectoryName(colFile.Path));

                using (var stream = File.Open(colFile.Path,
                                              System.IO.FileMode.Create,
                                              FileAccess.ReadWrite))
                    streamWriter(stream);

                if (crc32 != null)
                {
                    var fsCrc32 = FileEx.GetCrc32(colFile.Path);

                    if (fsCrc32 != crc32)
                    {
                        throw new IOException($"CRC32 did not match for file {colFile.Path}. Expected {crc32}, got {fsCrc32}");
                    }
                }

                return(colFile);
            }
            catch (Exception ex)
            {
                LogTo.Error(ex,
                            "CollectionFS: Create threw an exception.");

                try
                {
                    if (dbFile != null)
                    {
                        DbFiles.Delete(dbFile.Id);
                    }
                }
                catch (Exception dbEx)
                {
                    LogTo.Error(dbEx,
                                "CollectionFS: Create threw an exception. Exception's DB cleanup code threw an exception");
                }

                throw;
            }
        }