@@ -14,7 +14,7 @@ use std::{
1414use bytes:: Bytes ;
1515use itertools:: Itertools ;
1616use lru:: LruCache ;
17- use tracing:: { debug, error , info, warn} ;
17+ use tracing:: { debug, info, warn} ;
1818use windows_projfs:: {
1919 DirectoryEntry , DirectoryInfo , FileInfo , Notification , ProjectedFileSystem ,
2020 ProjectedFileSystemSource ,
@@ -23,10 +23,10 @@ use windows_projfs::{
2323use crate :: {
2424 hunk_index:: IndexHunkIndex ,
2525 monitor:: { void:: VoidMonitor , Monitor } ,
26- Apath , Archive , BandId , BandSelectionPolicy , IndexEntry , Kind , Result , StoredTree ,
26+ Apath , Archive , BandId , BandSelectionPolicy , Error , IndexEntry , Kind , Result , StoredTree ,
2727} ;
2828
29- use super :: MountOptions ;
29+ use super :: { MountHandle , MountOptions } ;
3030
3131struct StoredFileReader {
3232 iter : Peekable < Box < dyn Iterator < Item = Result < Bytes > > > > ,
@@ -161,7 +161,7 @@ struct ArchiveProjectionSource {
161161 hunk_index_cache : Mutex < LruCache < BandId , Arc < IndexHunkIndex > > > ,
162162
163163 /*
164- * Cache the last accessed hunks to improve directory travesal speed.
164+ * Cache the last accessed hunks to improve directory traversal speed.
165165 */
166166 #[ allow( clippy:: type_complexity) ]
167167 hunk_content_cache : Mutex < LruCache < ( BandId , u32 ) , Arc < Vec < IndexEntry > > > > ,
@@ -216,7 +216,7 @@ impl ArchiveProjectionSource {
216216 . lock ( )
217217 . unwrap ( )
218218 . try_get_or_insert ( band_id, || {
219- /* Inform the user that this band has been cached as this is most likely a heavy operaton (cpu and memory wise) */
219+ /* Inform the user that this band has been cached as this is most likely a heavy operation (cpu and memory wise) */
220220 info ! ( "Caching files for band {}" , stored_tree. band( ) . id( ) ) ;
221221
222222 let helper = IndexHunkIndex :: from_index ( & stored_tree. band ( ) . index ( ) ) ?;
@@ -450,7 +450,7 @@ impl ProjectedFileSystemSource for ArchiveProjectionSource {
450450 if notification. is_cancelable ( )
451451 && !matches ! ( notification, Notification :: FilePreConvertToFull ( _) )
452452 {
453- /* try to cancel everything, except retriving data */
453+ /* try to cancel everything, except retrieving data */
454454 ControlFlow :: Break ( ( ) )
455455 } else {
456456 ControlFlow :: Continue ( ( ) )
@@ -459,19 +459,51 @@ impl ProjectedFileSystemSource for ArchiveProjectionSource {
459459}
460460
461461const ERROR_CODE_VIRTUALIZATION_TEMPORARILY_UNAVAILABLE : i32 = 369 ;
462- pub fn mount ( archive : Archive , destination : & Path , options : MountOptions ) -> Result < ( ) > {
462+ struct WindowsMountHandle {
463+ _projection : ProjectedFileSystem ,
464+ path : PathBuf ,
465+ cleanup : bool ,
466+ }
467+
468+ impl Drop for WindowsMountHandle {
469+ fn drop ( & mut self ) {
470+ if self . cleanup {
471+ debug ! ( "Removing destination {}" , self . path. display( ) ) ;
472+ let mut attempt_count = 0 ;
473+ while let Err ( err) = fs:: remove_dir_all ( & self . path ) {
474+ attempt_count += 1 ;
475+ if err. raw_os_error ( ) . unwrap_or_default ( )
476+ != ERROR_CODE_VIRTUALIZATION_TEMPORARILY_UNAVAILABLE
477+ || attempt_count > 5
478+ {
479+ warn ! ( "Failed to clean up projection destination: {}" , err) ;
480+ break ;
481+ }
482+ std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
483+ }
484+ }
485+ }
486+ }
487+
488+ impl MountHandle for WindowsMountHandle {
489+ fn mount_root ( & self ) -> & Path {
490+ & self . path
491+ }
492+ }
493+
494+ pub fn mount (
495+ archive : Archive ,
496+ destination : & Path ,
497+ options : MountOptions ,
498+ ) -> Result < Box < dyn MountHandle > > {
463499 if options. clean {
464500 if destination. exists ( ) {
465- error ! ( "The destination already exists." ) ;
466- error ! ( "Please ensure, that the destination does not exists." ) ;
467- return Ok ( ( ) ) ;
501+ return Err ( Error :: MountDestinationExists ) ;
468502 }
469503
470504 fs:: create_dir_all ( destination) ?;
471505 } else if !destination. exists ( ) {
472- error ! ( "The destination does not exists." ) ;
473- error ! ( "Please ensure, that the destination does exist prior mounting." ) ;
474- return Ok ( ( ) ) ;
506+ return Err ( Error :: MountDestinationDoesNotExists ) ;
475507 }
476508
477509 let source = ArchiveProjectionSource {
@@ -486,31 +518,12 @@ pub fn mount(archive: Archive, destination: &Path, options: MountOptions) -> Res
486518 } ;
487519
488520 let projection = ProjectedFileSystem :: new ( destination, source) ?;
489- info ! ( "Projection started at {}." , destination. display( ) ) ;
490- {
491- info ! ( "Press any key to stop the projection..." ) ;
492- let mut stdin = io:: stdin ( ) ;
493- let _ = stdin. read ( & mut [ 0u8 ] ) . unwrap ( ) ;
494- }
495-
496- info ! ( "Stopping projection." ) ;
497- drop ( projection) ;
521+ let handle: Box < dyn MountHandle > = Box :: new ( WindowsMountHandle {
522+ _projection : projection,
498523
499- if options. clean {
500- debug ! ( "Removing destination {}" , destination. display( ) ) ;
501- let mut attempt_count = 0 ;
502- while let Err ( err) = fs:: remove_dir_all ( destination) {
503- attempt_count += 1 ;
504- if err. raw_os_error ( ) . unwrap_or_default ( )
505- != ERROR_CODE_VIRTUALIZATION_TEMPORARILY_UNAVAILABLE
506- || attempt_count > 5
507- {
508- warn ! ( "Failed to clean up projection destination: {}" , err) ;
509- break ;
510- }
511- std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
512- }
513- }
524+ path : destination. to_owned ( ) ,
525+ cleanup : options. clean ,
526+ } ) ;
514527
515- Ok ( ( ) )
528+ Ok ( handle )
516529}
0 commit comments