firebird: keep each embedded database's files in one directory

Give the driver a directory of its own, extract each embedded database
into a subdirectory of it, and set DatabaseAccess so firebird keeps any
associated files it makes for a database in the same directory.

A distro firebird reads only firebird.conf from the directory the
FIREBIRD variable names and finds its other resources at their normal
absolute paths. A bundled firebird finds everything relative to it.

Change-Id: If082a30d2426e7942fc9dd48f7124928fc984434
Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/6701
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 520d8173cef39a4da85b3ba21bdaaa3150384c25)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208039
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Caolán McNamara
2026-07-14 10:29:05 +02:00
committed by Xisco Fauli
parent ce70528a73
commit c656bab4c9
4 changed files with 57 additions and 4 deletions
@@ -121,7 +121,8 @@ struct ConnectionGuard
}
void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info)
void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info,
const OUString& rDatabaseDataDirectoryURL)
{
ConnectionGuard aGuard(m_refCount);
@@ -158,7 +159,7 @@ void Connection::construct(const OUString& url, const Sequence< PropertyValue >&
bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
m_pDatabaseFileDir.reset(new ::utl::TempFileNamed(nullptr, true));
m_pDatabaseFileDir.reset(new ::utl::TempFileNamed(&rDatabaseDataDirectoryURL, true));
m_pDatabaseFileDir->EnableKillingFile();
m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
@@ -165,7 +165,8 @@ namespace connectivity::firebird
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
void construct( const OUString& url,
const css::uno::Sequence< css::beans::PropertyValue >& info);
const css::uno::Sequence< css::beans::PropertyValue >& info,
const OUString& rDatabaseDataDirectoryURL);
const OUString& getConnectionURL() const {return m_sConnectionURL;}
bool isEmbedded() const {return m_bIsEmbedded;}
@@ -48,6 +48,7 @@ namespace {
constexpr OUString our_sFirebirdTmpVar = u"FIREBIRD_TMP"_ustr;
constexpr OUString our_sFirebirdLockVar = u"FIREBIRD_LOCK"_ustr;
constexpr OUString our_sFirebirdMsgVar = u"FIREBIRD_MSG"_ustr;
constexpr OUString our_sFirebirdRootVar = u"FIREBIRD"_ustr;
#ifdef MACOSX
constexpr OUString our_sFirebirdLibVar = u"LIBREOFFICE_FIREBIRD_LIB"_ustr;
#endif
@@ -58,12 +59,15 @@ FirebirdDriver::FirebirdDriver(const css::uno::Reference< css::uno::XComponentCo
, m_aContext(_rxContext)
, m_firebirdTMPDirectory(nullptr, true)
, m_firebirdLockDirectory(nullptr, true)
, m_firebirdDataDirectory(nullptr, true)
, m_bConfined(false)
{
// ::utl::TempFile uses a unique temporary directory (subdirectory of
// /tmp or other user specific tmp directory) per instance in which
// we can create directories for firebird at will.
m_firebirdTMPDirectory.EnableKillingFile(true);
m_firebirdLockDirectory.EnableKillingFile(true);
m_firebirdDataDirectory.EnableKillingFile(true);
// Overrides firebird's default of /tmp or c:\temp
osl_setEnvironment(our_sFirebirdTmpVar.pData, m_firebirdTMPDirectory.GetFileName().pData);
@@ -71,6 +75,35 @@ FirebirdDriver::FirebirdDriver(const css::uno::Reference< css::uno::XComponentCo
// Overrides firebird's default of /tmp/firebird or c:\temp\firebird
osl_setEnvironment(our_sFirebirdLockVar.pData, m_firebirdLockDirectory.GetFileName().pData);
// Keep the files firebird opens or creates together in one directory.
// Embedded databases are extracted here, and DatabaseAccess = Restrict
// keeps any associated files firebird makes for it under the same
// directory. firebird reads this firebird.conf from the directory the
// FIREBIRD variable names, once, on its first use, so it has to be set
// before the first connection.
OUString sDataDirPath;
::osl::FileBase::getSystemPathFromFileURL(m_firebirdDataDirectory.GetURL(), sDataDirPath);
OString sConf = "DatabaseAccess = Restrict "
+ OUStringToOString(sDataDirPath, RTL_TEXTENCODING_UTF8) + "\n";
OUString sConfURL = m_firebirdDataDirectory.GetURL() + "/firebird.conf";
::osl::File aConfFile(sConfURL);
if (aConfFile.open(osl_File_OpenFlag_Create | osl_File_OpenFlag_Write) == ::osl::FileBase::E_None)
{
sal_uInt64 nWritten = 0;
if (aConfFile.write(sConf.getStr(), sConf.getLength(), nWritten) == ::osl::FileBase::E_None
&& nWritten == static_cast<sal_uInt64>(sConf.getLength()))
{
osl_setEnvironment(our_sFirebirdRootVar.pData, sDataDirPath.pData);
m_bConfined = true;
}
aConfFile.close();
}
SAL_WARN_IF(!m_bConfined, "connectivity.firebird",
"could not write " << sConfURL << ", firebird connections will be refused");
#ifndef SYSTEM_FIREBIRD
// Overrides firebird's hardcoded default of /usr/local/firebird on *nix,
// however on Windows it seems to use the current directory as a default.
@@ -107,6 +140,7 @@ void FirebirdDriver::disposing()
osl_clearEnvironment(our_sFirebirdTmpVar.pData);
osl_clearEnvironment(our_sFirebirdLockVar.pData);
osl_clearEnvironment(our_sFirebirdRootVar.pData);
#ifndef SYSTEM_FIREBIRD
osl_clearEnvironment(our_sFirebirdMsgVar.pData);
@@ -148,8 +182,18 @@ Reference< XConnection > SAL_CALL FirebirdDriver::connect(
if ( ! acceptsURL(url) )
return nullptr;
// Without the firebird.conf that keeps firebird inside its own directory
// we do not open any database.
if (!m_bConfined)
{
::connectivity::SharedResources aResources;
const OUString sMessage = aResources.getResourceString(STR_COULD_NOT_LOAD_FILE).replaceFirst(
"$filename$", u"firebird.conf");
::dbtools::throwGenericSQLException(sMessage, *this);
}
rtl::Reference<Connection> pCon = new Connection();
pCon->construct(url, info);
pCon->construct(url, info, getDatabaseDataDirectoryURL());
m_xConnections.push_back(pCon);
@@ -48,6 +48,8 @@ namespace connectivity::firebird
css::uno::Reference<css::uno::XComponentContext> m_aContext;
::utl::TempFileNamed m_firebirdTMPDirectory;
::utl::TempFileNamed m_firebirdLockDirectory;
::utl::TempFileNamed m_firebirdDataDirectory;
bool m_bConfined;
protected:
::osl::Mutex m_aMutex; // mutex is need to control member access
@@ -62,6 +64,11 @@ namespace connectivity::firebird
virtual ~FirebirdDriver() override;
const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; }
// The directory that embedded databases are extracted into. Each
// connection makes its own subdirectory here, and firebird keeps
// associated files it creates for them under this directory as well.
OUString getDatabaseDataDirectoryURL() const { return m_firebirdDataDirectory.GetURL(); }
// OComponentHelper
virtual void SAL_CALL disposing() override;