Skip to content

Commit 329b179

Browse files
chore: check data folder write permission
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 08a8631 commit 329b179

File tree

5 files changed

+63
-8
lines changed

5 files changed

+63
-8
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ figment={version="0.10", features=["toml", "env"]}
4747
tracing={version="0.1", default-features=false, features=["std"]}
4848
tracing-subscriber={version="0.3", features=["env-filter"]}
4949
ahash="0.8"
50+
nix={version="0.31", features=["user"]}
5051

5152
# web
5253
axum={version="0.8", default-features=false, features=[

src/app/mod.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ pub mod models;
55
pub use core::reports;
66
use std::sync::Arc;
77

8-
use crate::config::Config;
8+
use crate::{config::Config, utils::writable::check_directory_writable};
99

1010
use crate::utils::r2d2_sqlite::SqliteConnectionManager;
11-
use anyhow::Result;
11+
use anyhow::{Context, Result};
1212
use core::{LiwanEntities, LiwanEvents, LiwanOnboarding, LiwanProjects, LiwanSessions, LiwanUsers};
1313
use duckdb::DuckdbConnectionManager;
1414

@@ -41,16 +41,18 @@ const EVENT_BATCH_INTERVAL: std::time::Duration = std::time::Duration::from_secs
4141
impl Liwan {
4242
pub fn try_new(config: Config) -> Result<Arc<Self>> {
4343
tracing::debug!("Initializing app");
44-
let folder = std::path::Path::new(&config.data_dir);
45-
if !folder.exists() {
46-
tracing::debug!(path = config.data_dir, "Creating database folder since it doesn't exist");
47-
std::fs::create_dir_all(folder)?;
44+
let dir = std::path::Path::new(&config.data_dir);
45+
46+
if !dir.exists() {
47+
tracing::debug!(path = config.data_dir, "Creating data directory since it doesn't exist");
48+
std::fs::create_dir_all(dir).context("Failed to create data directory")?;
4849
}
50+
check_directory_writable(dir);
4951

5052
tracing::debug!("Initializing databases");
51-
let conn_app = db::init_sqlite(&folder.join("liwan-app.sqlite"), embedded::app::migrations::runner())?;
53+
let conn_app = db::init_sqlite(&dir.join("liwan-app.sqlite"), embedded::app::migrations::runner())?;
5254
let conn_events = db::init_duckdb(
53-
&folder.join("liwan-events.duckdb"),
55+
&dir.join("liwan-events.duckdb"),
5456
config.duckdb.clone(),
5557
embedded::events::migrations::runner(),
5658
)?;

src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod seed;
99
pub mod signals;
1010
pub mod useragent;
1111
pub mod validate;
12+
pub mod writable;
1213

1314
pub fn to_sorted<T: Clone + Ord>(v: &[T]) -> Vec<T> {
1415
let mut v = v.to_vec();

src/utils/writable.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::{fs, io::Write, path::Path};
2+
3+
/// Checks if the directory is writable by attempting to create a temporary file.
4+
pub fn check_directory_writable(dir: &Path) {
5+
let test_path = dir.join(".liwan_write_test");
6+
7+
match fs::OpenOptions::new().create_new(true).write(true).open(&test_path) {
8+
Ok(mut f) => {
9+
let _ = f.write_all(b"test");
10+
let _ = fs::remove_file(&test_path);
11+
}
12+
Err(err) => {
13+
#[cfg(unix)]
14+
{
15+
let uid = nix::unistd::geteuid();
16+
let gid = nix::unistd::getegid();
17+
18+
let path = dir.display();
19+
tracing::warn!(
20+
%path,
21+
uid = uid.as_raw(),
22+
gid = gid.as_raw(),
23+
error = %err,
24+
"Directory is not writable"
25+
);
26+
}
27+
28+
#[cfg(not(unix))]
29+
{
30+
tracing::warn!(
31+
path = dir.display(),
32+
error = %err,
33+
"Directory is not writable"
34+
);
35+
}
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)