@@ -6,17 +6,17 @@ use sqlx::any::{AnyKind, AnyStatement, AnyTypeInfo};
66use sqlx:: postgres:: types:: PgTimeTz ;
77use sqlx:: { Postgres , Statement , Type } ;
88use std:: io:: ErrorKind ;
9- use std:: path:: { Path , PathBuf } ;
9+ use std:: path:: { Component , Path , PathBuf } ;
1010
1111pub ( crate ) struct FileSystem {
1212 local_root : PathBuf ,
1313 db_fs_queries : Option < DbFsQueries > ,
1414}
1515
1616impl FileSystem {
17- pub async fn init ( db : & Database ) -> Self {
17+ pub async fn init ( local_root : & Path , db : & Database ) -> Self {
1818 Self {
19- local_root : PathBuf :: new ( ) ,
19+ local_root : PathBuf :: from ( local_root ) ,
2020 db_fs_queries : match DbFsQueries :: init ( db) . await {
2121 Ok ( q) => Some ( q) ,
2222 Err ( e) => {
@@ -37,7 +37,8 @@ impl FileSystem {
3737 path : & Path ,
3838 since : DateTime < Utc > ,
3939 ) -> anyhow:: Result < bool > {
40- let local_result = file_modified_since_local ( & self . local_root . join ( path) , since) . await ;
40+ let local_path = self . safe_local_path ( path) ?;
41+ let local_result = file_modified_since_local ( & local_path, since) . await ;
4142 match ( local_result, & self . db_fs_queries ) {
4243 ( Ok ( modified) , _) => Ok ( modified) ,
4344 ( Err ( e) , Some ( db_fs) ) if e. kind ( ) == ErrorKind :: NotFound => {
@@ -53,7 +54,8 @@ impl FileSystem {
5354 }
5455
5556 pub async fn read_file ( & self , app_state : & AppState , path : & Path ) -> anyhow:: Result < String > {
56- let local_result = tokio:: fs:: read_to_string ( & self . local_root . join ( path) ) . await ;
57+ let local_path = self . safe_local_path ( path) ?;
58+ let local_result = tokio:: fs:: read_to_string ( & local_path) . await ;
5759 match ( local_result, & self . db_fs_queries ) {
5860 ( Ok ( f) , _) => Ok ( f) ,
5961 ( Err ( e) , Some ( db_fs) ) if e. kind ( ) == ErrorKind :: NotFound => {
@@ -63,6 +65,14 @@ impl FileSystem {
6365 ( Err ( e) , _) => Err ( e) . with_context ( || format ! ( "Unable to read local file {path:?}" ) ) ,
6466 }
6567 }
68+
69+ fn safe_local_path ( & self , path : & Path ) -> anyhow:: Result < PathBuf > {
70+ anyhow:: ensure!(
71+ path. components( ) . all( |c| matches!( c, Component :: Normal ( _) ) ) ,
72+ "Unsupported path: {path:?}"
73+ ) ;
74+ Ok ( self . local_root . join ( path) )
75+ }
6676}
6777
6878async fn file_modified_since_local ( path : & Path , since : DateTime < Utc > ) -> tokio:: io:: Result < bool > {
0 commit comments