use super::*;
#[cfg(any(unix, windows))]
pub(super) fn verify_before_open(
config: &PoolConfig,
at_path: Option<DatabaseFileIdentity>,
) -> Result<(), SqliteError> {
if let Some(expected) = config.expected_file_identity {
if Some(expected) != at_path {
return Err(SqliteError::InvalidData(
"database file identity differs from the caller's held claim before SQLite open"
.into(),
));
}
}
Ok(())
}
#[cfg(windows)]
fn verify_opened(
config: &PoolConfig,
writer: &Connection,
path: Option<&Path>,
) -> Result<(), SqliteError> {
if let Some(expected) = config.expected_file_identity {
let path = path.ok_or_else(|| {
SqliteError::InvalidConfig("a claimed file identity requires a file-backed pool".into())
})?;
if opened_sqlite_file_identity(writer, path)? != expected {
return Err(SqliteError::InvalidData(
"opened SQLite file identity differs from the caller's held claim".into(),
));
}
}
Ok(())
}
pub(super) fn open_writer(
config: &PoolConfig,
read_only_open_target: Option<&Path>,
identity_path: Option<&Path>,
) -> Result<Connection, SqliteError> {
let Some(_) = config.path.as_ref() else {
return Connection::open_in_memory().map_err(Into::into);
};
let flags = if config.read_only {
writer_read_only_open_flags()
} else {
writer_open_flags()
};
let target = if config.read_only {
read_only_open_target.ok_or_else(|| {
SqliteError::InvalidData(
"file-backed read-only pool has no canonical open target".into(),
)
})?
} else {
identity_path.ok_or_else(|| {
SqliteError::InvalidData(
"file-backed writable pool has no canonical open target".into(),
)
})?
};
open_connection(config, target, flags, identity_path)
}
pub(super) fn open_connection(
config: &PoolConfig,
target: &Path,
flags: OpenFlags,
identity_path: Option<&Path>,
) -> Result<Connection, SqliteError> {
#[cfg(any(unix, windows))]
let flags = if config.expected_file_identity.is_some() {
flags - OpenFlags::SQLITE_OPEN_CREATE
} else {
flags
};
#[cfg(not(windows))]
let _ = identity_path;
#[cfg(unix)]
let observation = config
.expected_file_identity
.map(super::claimed_file_observer::begin)
.transpose()?;
#[cfg(all(test, unix))]
BEFORE_NATIVE_OPEN.with(|hook| {
if let Some(hook) = hook.borrow_mut().take() {
hook();
}
});
let writer = config.open_file_connection(target, flags)?;
#[cfg(unix)]
if let Some(observation) = observation {
observation.finish()?;
}
#[cfg(windows)]
verify_opened(config, &writer, identity_path)?;
Ok(writer)
}
#[cfg(all(test, unix))]
thread_local! {
pub(super) static BEFORE_NATIVE_OPEN: std::cell::RefCell<Option<Box<dyn FnOnce()>>> =
const { std::cell::RefCell::new(None) };
}