Beispiel #1
0
        /// <summary>
        /// Creates a new Active Directory database context.
        /// </summary>
        /// <param name="dbPath">dbFilePath must point to the DIT file on the local computer.</param>
        /// <param name="logPath">The path should point to a writeable folder on the local computer, where ESE log files will be created. If not specified, then temp folder will be used.</param>
        public DirectoryContext(string dbFilePath, bool readOnly, string logDirectoryPath = null)
        {
            if (!File.Exists(dbFilePath))
            {
                // TODO: Extract as resource
                throw new FileNotFoundException("The specified database file does not exist.", dbFilePath);
            }

            ValidateDatabaseState(dbFilePath);

            string dbDirectoryPath         = Path.GetDirectoryName(dbFilePath);
            string checkpointDirectoryPath = dbDirectoryPath;
            string tempDirectoryPath       = dbDirectoryPath;

            if (logDirectoryPath != null)
            {
                if (!Directory.Exists(logDirectoryPath))
                {
                    // TODO: Extract as resource
                    throw new FileNotFoundException("The specified log directory does not exist.", logDirectoryPath);
                }
            }
            else
            {
                logDirectoryPath = dbDirectoryPath;
            }
            // TODO: Exception handling?
            // HACK: IsamInstance constructor throws AccessDenied Exception when the path does not end with a backslash.
            this.instance = new IsamInstance(AddPathSeparator(checkpointDirectoryPath), AddPathSeparator(logDirectoryPath), AddPathSeparator(tempDirectoryPath), ADConstants.EseBaseName, JetInstanceName, readOnly, ADConstants.PageSize);
            try
            {
                var isamParameters = this.instance.IsamSystemParameters;
                // TODO: Add param explanations
                isamParameters.LogFileSize          = ADConstants.EseLogFileSize;
                isamParameters.DeleteOutOfRangeLogs = true;
                isamParameters.EnableIndexChecking  = 1;
                isamParameters.EnableIndexCleanup   = true;
                isamParameters.CircularLog          = true;
                // TODO: Configure additional ISAM parameters
                // this.instance.IsamSystemParameters.EnableOnlineDefrag = false;
                // JET_paramDeleteOldLogs =  1
                this.session = this.instance.CreateSession();
                this.session.AttachDatabase(dbFilePath);
                this.attachedDatabasePath = dbFilePath;
                this.database             = this.session.OpenDatabase(dbFilePath);
                this.Schema = new DirectorySchema(this.database);
                this.SecurityDescriptorRersolver = new SecurityDescriptorRersolver(this.database);
                this.DistinguishedNameResolver   = new DistinguishedNameResolver(this.database, this.Schema);
                this.LinkResolver     = new LinkResolver(this.database, this.Schema);
                this.DomainController = new DomainController(this);
            }
            catch
            {
                // Free resources if anything failed
                this.Dispose();
                throw;
            }
        }
Beispiel #2
0
        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
            {
                // Do nothing
                return;
            }

            if (this.LinkResolver != null)
            {
                this.LinkResolver.Dispose();
                this.LinkResolver = null;
            }

            if (this.SecurityDescriptorRersolver != null)
            {
                this.SecurityDescriptorRersolver.Dispose();
                this.SecurityDescriptorRersolver = null;
            }

            if (this.DistinguishedNameResolver != null)
            {
                this.DistinguishedNameResolver.Dispose();
                this.DistinguishedNameResolver = null;
            }

            if (this.DomainController != null)
            {
                this.DomainController.Dispose();
                this.DomainController = null;
            }

            if (this.database != null)
            {
                this.database.Dispose();
                this.database = null;
            }

            if (this.session != null)
            {
                if (this.isDBAttached)
                {
                    this.session.DetachDatabase(this.DSADatabaseFile);
                    this.isDBAttached = false;
                }

                this.session.Dispose();
                this.session = null;
            }

            if (this.instance != null)
            {
                this.instance.Dispose();
                this.instance = null;
            }
        }
Beispiel #3
0
        public DistinguishedNameResolver(IsamDatabase database, DirectorySchema schema)
        {
            // Initialize the DN cache, while pre-caching the root DN as a sentinel.
            this.dnCache = new Dictionary <int, DistinguishedName>();
            this.dnCache.Add(ADConstants.RootDNTag, new DistinguishedName());

            // Cache AD schema and datatable cursor
            this.schema = schema;
            this.cursor = database.OpenCursor(ADConstants.DataTableName);
        }
Beispiel #4
0
        // TODO: Internal?
        // TODO: ISchema
        public DirectorySchema(IsamDatabase database)
        {
            TableDefinition dataTable = database.Tables[ADConstants.DataTableName];

            this.LoadColumnList(dataTable.Columns);
            this.LoadAttributeIndices(dataTable.Indices2);
            using (var cursor = database.OpenCursor(ADConstants.DataTableName))
            {
                this.LoadClassList(cursor);
                this.LoadAttributeProperties(cursor);
                this.LoadPrefixMap(cursor);
            }
            // TODO: Load Ext-Int Map from hiddentable
        }
Beispiel #5
0
        public LinkResolver(IsamDatabase database, DirectorySchema schema)
        {
            this.schema = schema;
            this.cursor = database.OpenCursor(ADConstants.LinkTableName);
            if (this.cursor.TableDefinition.Indices.Contains(linkIndex2008))
            {
                this.cursor.SetCurrentIndex(linkIndex2008);
            }
            else
            {
                // Fallback to the old index if the newer one does not exist
                cursor.SetCurrentIndex(linkIndex2003);
            }

            // TODO: Load column ids instead of names
        }
 public DistinguishedNameResolver(IsamDatabase database, DirectorySchema schema)
 {
     this.dnCache = new Dictionary <int, string>();
     this.schema  = schema;
     this.cursor  = database.OpenCursor(ADConstants.DataTableName);
 }
Beispiel #7
0
        /// <summary>
        /// Creates a new Active Directory database context.
        /// </summary>
        /// <param name="dbPath">dbFilePath must point to the DIT file on the local computer.</param>
        /// <param name="logPath">The path should point to a writeable folder on the local computer, where ESE log files will be created. If not specified, then temp folder will be used.</param>
        public DirectoryContext(string dbFilePath, bool readOnly, string logDirectoryPath = null)
        {
            if (!File.Exists(dbFilePath))
            {
                // TODO: Extract as resource
                throw new FileNotFoundException("The specified database file does not exist.", dbFilePath);
            }

            this.DSADatabaseFile = dbFilePath;
            ValidateDatabaseState(this.DSADatabaseFile);

            this.DSAWorkingDirectory = Path.GetDirectoryName(this.DSADatabaseFile);
            string checkpointDirectoryPath = this.DSAWorkingDirectory;
            string tempDirectoryPath       = this.DSAWorkingDirectory;

            this.DatabaseLogFilesPath = logDirectoryPath;
            if (this.DatabaseLogFilesPath != null)
            {
                if (!Directory.Exists(this.DatabaseLogFilesPath))
                {
                    // TODO: Extract as resource
                    throw new FileNotFoundException("The specified log directory does not exist.", this.DatabaseLogFilesPath);
                }
            }
            else
            {
                this.DatabaseLogFilesPath = this.DSAWorkingDirectory;
            }

            // TODO: Exception handling?
            // HACK: IsamInstance constructor throws AccessDenied Exception when the path does not end with a backslash.
            this.instance = new IsamInstance(AddPathSeparator(checkpointDirectoryPath), AddPathSeparator(this.DatabaseLogFilesPath), AddPathSeparator(tempDirectoryPath), ADConstants.EseBaseName, JetInstanceName, readOnly, ADConstants.PageSize);
            try
            {
                var isamParameters = this.instance.IsamSystemParameters;

                // Set the size of the transaction log files to AD defaults.
                isamParameters.LogFileSize = ADConstants.EseLogFileSize;

                // Delete the log files that are not matching (generation wise) during soft recovery.
                isamParameters.DeleteOutOfRangeLogs = true;

                // Check the database for indexes over Unicode key columns that were built using an older version of the NLS library.
                isamParameters.EnableIndexChecking = true;

                // Automatically clean up indexes over Unicode key columns as necessary to avoid database format changes caused by changes to the NLS library.
                isamParameters.EnableIndexCleanup = true;

                // Retain only transaction log files that are younger than the current checkpoint.
                isamParameters.CircularLog = true;

                // Disable all database engine callbacks to application provided functions. This enables us to open Win2016 DBs on non-DC systems.
                isamParameters.DisableCallbacks = true;

                // TODO: Configure additional ISAM parameters
                // this.instance.IsamSystemParameters.EnableOnlineDefrag = false;

                this.session = this.instance.CreateSession();
                this.session.AttachDatabase(this.DSADatabaseFile);
                this.isDBAttached = true;
                this.database     = this.session.OpenDatabase(this.DSADatabaseFile);
                this.Schema       = new DirectorySchema(this.database);
                this.SecurityDescriptorRersolver = new SecurityDescriptorRersolver(this.database);
                this.DistinguishedNameResolver   = new DistinguishedNameResolver(this.database, this.Schema);
                this.LinkResolver     = new LinkResolver(this.database, this.Schema);
                this.DomainController = new DomainController(this);
            }
            catch (EsentUnicodeTranslationFailException unicodeException)
            {
                // This typically happens while opening a Windows Server 2003 DIT on a newer system.
                this.Dispose();
                throw new InvalidDatabaseStateException("There was a problem reading the database, which probably comes from a legacy system. Try defragmenting it first by running the 'esentutl /d ntds.dit' command.", this.DSADatabaseFile, unicodeException);
            }
            catch
            {
                // Free resources if anything failed
                this.Dispose();
                throw;
            }
        }
        /// <summary>
        /// Creates a new Active Directory database context.
        /// </summary>
        /// <param name="dbPath">dbFilePath must point to the DIT file on the local computer.</param>
        /// <param name="logPath">The path should point to a writeable folder on the local computer, where ESE log files will be created. If not specified, then temp folder will be used.</param>
        public DirectoryContext(string dbFilePath, bool readOnly, string logDirectoryPath = null)
        {
            if (!File.Exists(dbFilePath))
            {
                throw new FileNotFoundException("The specified database file does not exist.", dbFilePath);
            }

            this.DSADatabaseFile = dbFilePath;
            ValidateDatabaseState(this.DSADatabaseFile);

            this.DSAWorkingDirectory = Path.GetDirectoryName(this.DSADatabaseFile);
            string checkpointDirectoryPath = this.DSAWorkingDirectory;
            string tempDatabasePath        = Path.Combine(this.DSAWorkingDirectory, ADConstants.EseTempDatabaseName);

            this.DatabaseLogFilesPath = logDirectoryPath;
            if (this.DatabaseLogFilesPath != null)
            {
                if (!Directory.Exists(this.DatabaseLogFilesPath))
                {
                    throw new FileNotFoundException("The specified log directory does not exist.", this.DatabaseLogFilesPath);
                }
            }
            else
            {
                // Use the default location if an alternate log directory is not provided.
                this.DatabaseLogFilesPath = this.DSAWorkingDirectory;
            }

            // Note: IsamInstance constructor throws AccessDenied Exception when the path does not end with a backslash.
            this.instance = new IsamInstance(AddPathSeparator(checkpointDirectoryPath), AddPathSeparator(this.DatabaseLogFilesPath), tempDatabasePath, ADConstants.EseBaseName, JetInstanceName, readOnly, ADConstants.PageSize);
            try
            {
                var isamParameters = this.instance.IsamSystemParameters;

                // Set the size of the transaction log files to AD defaults.
                isamParameters.LogFileSize = ADConstants.EseLogFileSize;

                // Delete the log files that are not matching (generation wise) during soft recovery.
                isamParameters.DeleteOutOfRangeLogs = true;

                // Check the database for indexes over Unicode key columns that were built using an older version of the NLS library.
                isamParameters.EnableIndexChecking2 = true;

                // Automatically clean up indexes over Unicode key columns as necessary to avoid database format changes caused by changes to the NLS library.
                isamParameters.EnableIndexCleanup = true;

                // Retain only transaction log files that are younger than the current checkpoint.
                isamParameters.CircularLog = true;

                // Disable all database engine callbacks to application provided functions. This enables us to open Win2016 DBs on non-DC systems.
                isamParameters.DisableCallbacks = true;

                // Increase the limit of maximum open tables.
                isamParameters.MaxOpenTables = ADConstants.EseMaxOpenTables;

                // Enable backwards compatibility with the file naming conventions of earlier releases of the database engine.
                isamParameters.LegacyFileNames = ADConstants.EseLegacyFileNames;

                // Set EN-US to be used by any index over a Unicode key column.
                isamParameters.UnicodeIndexDefault = new JET_UNICODEINDEX()
                {
                    lcid       = ADConstants.EseIndexDefaultLocale,
                    dwMapFlags = ADConstants.EseIndexDefaultCompareOptions
                };

                // Force crash recovery to look for the database referenced in the transaction log in the specified folder.
                isamParameters.AlternateDatabaseRecoveryPath = this.DSAWorkingDirectory;

                if (!readOnly)
                {
                    // Delete obsolete log files.
                    isamParameters.DeleteOldLogs = true;

                    if (EsentVersion.SupportsWindows10Features)
                    {
                        try
                        {
                            // Required for Windows Server 2022 compatibility, as it limits the transaction log file format to 8920.
                            // Note: Usage of JET_efvUsePersistedFormat still causes minor DB format upgrade.
                            // isamParameters.EngineFormatVersion = 0x40000002; // JET_efvUsePersistedFormat: Instructs the engine to use the minimal Engine Format Version of all loaded log and DB files.
                        }
                        catch (EsentInvalidParameterException)
                        {
                            // JET_efvUsePersistedFormat should be supported since Windows Server 2016.
                            // Just continue even if it is not supported on the current Windows build.
                        }
                    }
                }

                this.session = this.instance.CreateSession();
                this.session.AttachDatabase(this.DSADatabaseFile);
                this.isDBAttached = true;
                this.database     = this.session.OpenDatabase(this.DSADatabaseFile);
                this.Schema       = new DirectorySchema(this.database);
                this.SecurityDescriptorRersolver = new SecurityDescriptorRersolver(this.database);
                this.DistinguishedNameResolver   = new DistinguishedNameResolver(this.database, this.Schema);
                this.LinkResolver     = new LinkResolver(this.database, this.Schema);
                this.DomainController = new DomainController(this);
            }
            catch (EsentFileAccessDeniedException e)
            {
                // This exception was probably thrown by the OpenDatabase method
                // HACK: Do not dispose the IsamSession object. Its Dispose method would throw an exception, which is a bug in ISAM.
                GC.SuppressFinalize(this.session);
                this.session = null;

                // Free resources if anything failed
                this.Dispose();

                throw;
            }
            catch (EsentErrorException e)
            {
                // Free resources if anything failed
                this.Dispose();

                // EsentUnicodeTranslationFailException - This typically happens while opening a Windows Server 2003 DIT on a newer system.
                // EsentSecondaryIndexCorruptedException - This typically happens when opening a Windows Server 2012 R2 DIT on Windows 7.
                throw new InvalidDatabaseStateException("There was a problem reading the database, which probably comes from a different OS. Try defragmenting it first by running the 'esentutl /d ntds.dit' command.", this.DSADatabaseFile, e);
            }
            catch
            {
                // Free resources if anything failed
                this.Dispose();
                throw;
            }
        }
        public void Setup()
        {
            this.directory    = SetupHelper.CreateRandomDirectory();
            this.databaseName = Path.Combine(this.directory, "database.edb");
            this.tableName    = "table";
            this.instance     = SetupHelper.CreateNewInstance(this.directory);

            IsamSystemParameters isamSystemParameters = this.instance.IsamSystemParameters;

            isamSystemParameters.Recovery = "off";

            this.sesid = this.instance.CreateSession();

            this.sesid.CreateDatabase(this.databaseName);
            this.sesid.AttachDatabase(this.databaseName);

            this.dbid = this.sesid.OpenDatabase(this.databaseName);

            using (IsamTransaction transaction = new IsamTransaction(this.sesid))
            {
                var tabledef = new TableDefinition(this.tableName);
                this.testColumnid = new ColumnDefinition(TestColumnName)
                {
                    Type = typeof(string),
                };

                tabledef.Columns.Add(this.testColumnid);
                tabledef.Columns.Add(new ColumnDefinition("TestColumn1")
                {
                    Type = typeof(int),
                });
                tabledef.Columns.Add(new ColumnDefinition("TestColumn2")
                {
                    Type = typeof(int),
                });

                var primaryIndex = new IndexDefinition("PrimaryIndex")
                {
                    KeyColumns =
                    {
                        new KeyColumn(
                            "TestColumn1",
                            true),
                    },
                };
                primaryIndex.Flags = IndexFlags.Primary;
                tabledef.Indices.Add(primaryIndex);

                var textIndex = new IndexDefinition("TextIndex")
                {
                    KeyColumns =
                    {
                        new KeyColumn(
                            "StringTestColumn",
                            true),
                    },
                    CultureInfo = new CultureInfo("en-CA"),
                };
                tabledef.Indices.Add(textIndex);

                this.dbid.CreateTable(tabledef);

                transaction.Commit();
            }

            this.tableid = this.dbid.OpenCursor(this.tableName);
        }
 public SecurityDescriptorRersolver(IsamDatabase database)
 {
     this.cursor = database.OpenCursor(ADConstants.SecurityDescriptorTableName);
 }