@@ -169,6 +169,21 @@ impl LocalBackend {
169
169
}
170
170
Ok ( ( ) )
171
171
}
172
+
173
+ /// Returns the parent path of the given file type and id.
174
+ ///
175
+ /// # Arguments
176
+ ///
177
+ /// * `tpe` - The type of the file.
178
+ /// * `id` - The id of the file.
179
+ ///
180
+ /// # Returns
181
+ ///
182
+ /// The parent path of the file or `None` if the file does not have a parent.
183
+ fn parent_path ( & self , tpe : FileType , id : & Id ) -> Option < PathBuf > {
184
+ let path = self . path ( tpe, id) ;
185
+ path. parent ( ) . map ( Path :: to_path_buf)
186
+ }
172
187
}
173
188
174
189
impl ReadBackend for LocalBackend {
@@ -355,13 +370,14 @@ impl ReadBackend for LocalBackend {
355
370
length : u32 ,
356
371
) -> RusticResult < Bytes > {
357
372
trace ! ( "reading tpe: {tpe:?}, id: {id}, offset: {offset}, length: {length}" ) ;
358
- let mut file = File :: open ( self . path ( tpe, id) ) . map_err ( |err| {
373
+ let filename = self . path ( tpe, id) ;
374
+ let mut file = File :: open ( filename. clone ( ) ) . map_err ( |err| {
359
375
RusticError :: with_source (
360
376
ErrorKind :: Backend ,
361
377
"Failed to open the file `{path}`. Please check the file and try again." ,
362
378
err,
363
379
)
364
- . attach_context ( "path" , self . path ( tpe , id ) . to_string_lossy ( ) )
380
+ . attach_context ( "path" , filename . to_string_lossy ( ) )
365
381
} ) ?;
366
382
_ = file. seek ( SeekFrom :: Start ( offset. into ( ) ) ) . map_err ( |err| {
367
383
RusticError :: with_source (
@@ -459,6 +475,10 @@ impl WriteBackend for LocalBackend {
459
475
/// * If the length of the file could not be set.
460
476
/// * If the bytes could not be written to the file.
461
477
/// * If the OS Metadata could not be synced to disk.
478
+ /// * If the file does not have a parent directory.
479
+ /// * If the parent directory could not be created.
480
+ /// * If the file cannot be opened, due to missing permissions.
481
+ /// * If the file cannot be written to, due to lack of space on the disk.
462
482
fn write_bytes (
463
483
& self ,
464
484
tpe : FileType ,
@@ -469,6 +489,28 @@ impl WriteBackend for LocalBackend {
469
489
trace ! ( "writing tpe: {:?}, id: {}" , & tpe, & id) ;
470
490
let filename = self . path ( tpe, id) ;
471
491
492
+ let Some ( parent) = self . parent_path ( tpe, id) else {
493
+ return Err (
494
+ RusticError :: new (
495
+ ErrorKind :: Backend ,
496
+ "The file `{path}` does not have a parent directory. This may be empty or a root path. Please check the file and try again." ,
497
+ )
498
+ . attach_context ( "path" , filename. display ( ) . to_string ( ) )
499
+ . ask_report ( )
500
+ ) ;
501
+ } ;
502
+
503
+ // create parent directory if it does not exist
504
+ fs:: create_dir_all ( parent. clone ( ) ) . map_err ( |err| {
505
+ RusticError :: with_source (
506
+ ErrorKind :: InputOutput ,
507
+ "Failed to create directories `{path}`. Does the directory already exist? Please check the file and try again." ,
508
+ err,
509
+ )
510
+ . attach_context ( "path" , parent. display ( ) . to_string ( ) )
511
+ . ask_report ( )
512
+ } ) ?;
513
+
472
514
let mut file = fs:: OpenOptions :: new ( )
473
515
. create ( true )
474
516
. truncate ( true )
0 commit comments