77//! The [`FileLock`] type represents a locked file, and provides access to the 
88//! file. 
99
10+ use  std:: fs:: TryLockError ; 
1011use  std:: fs:: { File ,  OpenOptions } ; 
1112use  std:: io; 
1213use  std:: io:: { Read ,  Seek ,  SeekFrom ,  Write } ; 
@@ -17,7 +18,6 @@ use crate::util::errors::CargoResult;
1718use  crate :: util:: style; 
1819use  anyhow:: Context  as  _; 
1920use  cargo_util:: paths; 
20- use  sys:: * ; 
2121
2222/// A locked file. 
2323/// 
@@ -103,7 +103,7 @@ impl Write for FileLock {
103103impl  Drop  for  FileLock  { 
104104    fn  drop ( & mut  self )  { 
105105        if  let  Some ( f)  = self . f . take ( )  { 
106-             if  let  Err ( e)  = unlock ( & f )  { 
106+             if  let  Err ( e)  = f . unlock ( )  { 
107107                tracing:: warn!( "failed to release lock: {e:?}" ) ; 
108108            } 
109109        } 
@@ -216,9 +216,7 @@ impl Filesystem {
216216        let  mut  opts = OpenOptions :: new ( ) ; 
217217        opts. read ( true ) . write ( true ) . create ( true ) ; 
218218        let  ( path,  f)  = self . open ( path. as_ref ( ) ,  & opts,  true ) ?; 
219-         acquire ( gctx,  msg,  & path,  & || try_lock_exclusive ( & f) ,  & || { 
220-             lock_exclusive ( & f) 
221-         } ) ?; 
219+         acquire ( gctx,  msg,  & path,  & || f. try_lock ( ) ,  & || f. lock ( ) ) ?; 
222220        Ok ( FileLock  {  f :  Some ( f) ,  path } ) 
223221    } 
224222
@@ -233,7 +231,7 @@ impl Filesystem {
233231        let  mut  opts = OpenOptions :: new ( ) ; 
234232        opts. read ( true ) . write ( true ) . create ( true ) ; 
235233        let  ( path,  f)  = self . open ( path. as_ref ( ) ,  & opts,  true ) ?; 
236-         if  try_acquire ( & path,  & || try_lock_exclusive ( & f ) ) ? { 
234+         if  try_acquire ( & path,  & || f . try_lock ( ) ) ? { 
237235            Ok ( Some ( FileLock  {  f :  Some ( f) ,  path } ) ) 
238236        }  else  { 
239237            Ok ( None ) 
@@ -259,8 +257,8 @@ impl Filesystem {
259257        P :  AsRef < Path > , 
260258    { 
261259        let  ( path,  f)  = self . open ( path. as_ref ( ) ,  & OpenOptions :: new ( ) . read ( true ) ,  false ) ?; 
262-         acquire ( gctx,  msg,  & path,  & || try_lock_shared ( & f ) ,  & || { 
263-             lock_shared ( & f ) 
260+         acquire ( gctx,  msg,  & path,  & || f . try_lock_shared ( ) ,  & || { 
261+             f . lock_shared ( ) 
264262        } ) ?; 
265263        Ok ( FileLock  {  f :  Some ( f) ,  path } ) 
266264    } 
@@ -279,8 +277,8 @@ impl Filesystem {
279277        let  mut  opts = OpenOptions :: new ( ) ; 
280278        opts. read ( true ) . write ( true ) . create ( true ) ; 
281279        let  ( path,  f)  = self . open ( path. as_ref ( ) ,  & opts,  true ) ?; 
282-         acquire ( gctx,  msg,  & path,  & || try_lock_shared ( & f ) ,  & || { 
283-             lock_shared ( & f ) 
280+         acquire ( gctx,  msg,  & path,  & || f . try_lock_shared ( ) ,  & || { 
281+             f . lock_shared ( ) 
284282        } ) ?; 
285283        Ok ( FileLock  {  f :  Some ( f) ,  path } ) 
286284    } 
@@ -296,7 +294,7 @@ impl Filesystem {
296294        let  mut  opts = OpenOptions :: new ( ) ; 
297295        opts. read ( true ) . write ( true ) . create ( true ) ; 
298296        let  ( path,  f)  = self . open ( path. as_ref ( ) ,  & opts,  true ) ?; 
299-         if  try_acquire ( & path,  & || try_lock_shared ( & f ) ) ? { 
297+         if  try_acquire ( & path,  & || f . try_lock_shared ( ) ) ? { 
300298            Ok ( Some ( FileLock  {  f :  Some ( f) ,  path } ) ) 
301299        }  else  { 
302300            Ok ( None ) 
@@ -335,7 +333,7 @@ impl PartialEq<Filesystem> for Path {
335333    } 
336334} 
337335
338- fn  try_acquire ( path :  & Path ,  lock_try :  & dyn  Fn ( )  -> io :: Result < ( ) > )  -> CargoResult < bool >  { 
336+ fn  try_acquire ( path :  & Path ,  lock_try :  & dyn  Fn ( )  -> Result < ( ) ,   TryLockError > )  -> CargoResult < bool >  { 
339337    // File locking on Unix is currently implemented via `flock`, which is known 
340338    // to be broken on NFS. We could in theory just ignore errors that happen on 
341339    // NFS, but apparently the failure mode [1] for `flock` on NFS is **blocking 
@@ -352,22 +350,21 @@ fn try_acquire(path: &Path, lock_try: &dyn Fn() -> io::Result<()>) -> CargoResul
352350    } 
353351
354352    match  lock_try ( )  { 
355-         Ok ( ( ) )  => return   Ok ( true ) , 
353+         Ok ( ( ) )  => Ok ( true ) , 
356354
357355        // In addition to ignoring NFS which is commonly not working we also 
358356        // just ignore locking on filesystems that look like they don't 
359357        // implement file locking. 
360-         Err ( e )  if  error_unsupported ( & e)  =>  return  Ok ( true ) , 
358+         Err ( TryLockError :: Error ( e ) )  if  error_unsupported ( & e)  => Ok ( true ) , 
361359
362-         Err ( e)  => { 
363-             if  !error_contended ( & e)  { 
364-                 let  e = anyhow:: Error :: from ( e) ; 
365-                 let  cx = format ! ( "failed to lock file: {}" ,  path. display( ) ) ; 
366-                 return  Err ( e. context ( cx) ) ; 
367-             } 
360+         Err ( TryLockError :: Error ( e) )  => { 
361+             let  e = anyhow:: Error :: from ( e) ; 
362+             let  cx = format ! ( "failed to lock file: {}" ,  path. display( ) ) ; 
363+             Err ( e. context ( cx) ) 
368364        } 
365+ 
366+         Err ( TryLockError :: WouldBlock )  => Ok ( false ) , 
369367    } 
370-     Ok ( false ) 
371368} 
372369
373370/// Acquires a lock on a file in a "nice" manner. 
@@ -389,7 +386,7 @@ fn acquire(
389386    gctx :  & GlobalContext , 
390387    msg :  & str , 
391388    path :  & Path , 
392-     lock_try :  & dyn  Fn ( )  -> io :: Result < ( ) > , 
389+     lock_try :  & dyn  Fn ( )  -> Result < ( ) ,   TryLockError > , 
393390    lock_block :  & dyn  Fn ( )  -> io:: Result < ( ) > , 
394391)  -> CargoResult < ( ) >  { 
395392    if  cfg ! ( debug_assertions)  { 
@@ -431,176 +428,20 @@ fn is_on_nfs_mount(_path: &Path) -> bool {
431428} 
432429
433430#[ cfg( unix) ]  
434- mod  sys { 
435-     use  std:: fs:: File ; 
436-     use  std:: io:: { Error ,  Result } ; 
437-     use  std:: os:: unix:: io:: AsRawFd ; 
438- 
439-     #[ cfg( not( target_os = "solaris" ) ) ]  
440-     const  LOCK_SH :  i32  = libc:: LOCK_SH ; 
441-     #[ cfg( target_os = "solaris" ) ]  
442-     const  LOCK_SH :  i32  = 1 ; 
443-     #[ cfg( not( target_os = "solaris" ) ) ]  
444-     const  LOCK_EX :  i32  = libc:: LOCK_EX ; 
445-     #[ cfg( target_os = "solaris" ) ]  
446-     const  LOCK_EX :  i32  = 2 ; 
447-     #[ cfg( not( target_os = "solaris" ) ) ]  
448-     const  LOCK_NB :  i32  = libc:: LOCK_NB ; 
449-     #[ cfg( target_os = "solaris" ) ]  
450-     const  LOCK_NB :  i32  = 4 ; 
451-     #[ cfg( not( target_os = "solaris" ) ) ]  
452-     const  LOCK_UN :  i32  = libc:: LOCK_UN ; 
453-     #[ cfg( target_os = "solaris" ) ]  
454-     const  LOCK_UN :  i32  = 8 ; 
455- 
456-     pub ( super )  fn  lock_shared ( file :  & File )  -> Result < ( ) >  { 
457-         flock ( file,  LOCK_SH ) 
458-     } 
459- 
460-     pub ( super )  fn  lock_exclusive ( file :  & File )  -> Result < ( ) >  { 
461-         flock ( file,  LOCK_EX ) 
462-     } 
463- 
464-     pub ( super )  fn  try_lock_shared ( file :  & File )  -> Result < ( ) >  { 
465-         flock ( file,  LOCK_SH  | LOCK_NB ) 
466-     } 
467- 
468-     pub ( super )  fn  try_lock_exclusive ( file :  & File )  -> Result < ( ) >  { 
469-         flock ( file,  LOCK_EX  | LOCK_NB ) 
470-     } 
471- 
472-     pub ( super )  fn  unlock ( file :  & File )  -> Result < ( ) >  { 
473-         flock ( file,  LOCK_UN ) 
474-     } 
475- 
476-     pub ( super )  fn  error_contended ( err :  & Error )  -> bool  { 
477-         err. raw_os_error ( ) . map_or ( false ,  |x| x == libc:: EWOULDBLOCK ) 
478-     } 
479- 
480-     pub ( super )  fn  error_unsupported ( err :  & Error )  -> bool  { 
481-         match  err. raw_os_error ( )  { 
482-             // Unfortunately, depending on the target, these may or may not be the same. 
483-             // For targets in which they are the same, the duplicate pattern causes a warning. 
484-             #[ allow( unreachable_patterns) ]  
485-             Some ( libc:: ENOTSUP  | libc:: EOPNOTSUPP )  => true , 
486-             Some ( libc:: ENOSYS )  => true , 
487-             _ => false , 
488-         } 
489-     } 
490- 
491-     #[ cfg( not( target_os = "solaris" ) ) ]  
492-     fn  flock ( file :  & File ,  flag :  libc:: c_int )  -> Result < ( ) >  { 
493-         let  ret = unsafe  {  libc:: flock ( file. as_raw_fd ( ) ,  flag)  } ; 
494-         if  ret < 0  { 
495-             Err ( Error :: last_os_error ( ) ) 
496-         }  else  { 
497-             Ok ( ( ) ) 
498-         } 
499-     } 
500- 
501-     #[ cfg( target_os = "solaris" ) ]  
502-     fn  flock ( file :  & File ,  flag :  libc:: c_int )  -> Result < ( ) >  { 
503-         // Solaris lacks flock(), so try to emulate using fcntl() 
504-         let  mut  flock = libc:: flock  { 
505-             l_type :  0 , 
506-             l_whence :  0 , 
507-             l_start :  0 , 
508-             l_len :  0 , 
509-             l_sysid :  0 , 
510-             l_pid :  0 , 
511-             l_pad :  [ 0 ,  0 ,  0 ,  0 ] , 
512-         } ; 
513-         flock. l_type  = if  flag &  LOCK_UN  != 0  { 
514-             libc:: F_UNLCK 
515-         }  else  if  flag &  LOCK_EX  != 0  { 
516-             libc:: F_WRLCK 
517-         }  else  if  flag &  LOCK_SH  != 0  { 
518-             libc:: F_RDLCK 
519-         }  else  { 
520-             panic ! ( "unexpected flock() operation" ) 
521-         } ; 
522- 
523-         let  mut  cmd = libc:: F_SETLKW ; 
524-         if  ( flag &  LOCK_NB )  != 0  { 
525-             cmd = libc:: F_SETLK ; 
526-         } 
527- 
528-         let  ret = unsafe  {  libc:: fcntl ( file. as_raw_fd ( ) ,  cmd,  & flock)  } ; 
529- 
530-         if  ret < 0  { 
531-             Err ( Error :: last_os_error ( ) ) 
532-         }  else  { 
533-             Ok ( ( ) ) 
534-         } 
431+ fn  error_unsupported ( err :  & std:: io:: Error )  -> bool  { 
432+     match  err. raw_os_error ( )  { 
433+         // Unfortunately, depending on the target, these may or may not be the same. 
434+         // For targets in which they are the same, the duplicate pattern causes a warning. 
435+         #[ allow( unreachable_patterns) ]  
436+         Some ( libc:: ENOTSUP  | libc:: EOPNOTSUPP )  => true , 
437+         Some ( libc:: ENOSYS )  => true , 
438+         _ => false , 
535439    } 
536440} 
537441
538442#[ cfg( windows) ]  
539- mod  sys { 
540-     use  std:: fs:: File ; 
541-     use  std:: io:: { Error ,  Result } ; 
542-     use  std:: mem; 
543-     use  std:: os:: windows:: io:: AsRawHandle ; 
544- 
545-     use  windows_sys:: Win32 :: Foundation :: HANDLE ; 
546-     use  windows_sys:: Win32 :: Foundation :: { ERROR_INVALID_FUNCTION ,  ERROR_LOCK_VIOLATION } ; 
547-     use  windows_sys:: Win32 :: Storage :: FileSystem :: { 
548-         LOCKFILE_EXCLUSIVE_LOCK ,  LOCKFILE_FAIL_IMMEDIATELY ,  LockFileEx ,  UnlockFile , 
549-     } ; 
550- 
551-     pub ( super )  fn  lock_shared ( file :  & File )  -> Result < ( ) >  { 
552-         lock_file ( file,  0 ) 
553-     } 
554- 
555-     pub ( super )  fn  lock_exclusive ( file :  & File )  -> Result < ( ) >  { 
556-         lock_file ( file,  LOCKFILE_EXCLUSIVE_LOCK ) 
557-     } 
558- 
559-     pub ( super )  fn  try_lock_shared ( file :  & File )  -> Result < ( ) >  { 
560-         lock_file ( file,  LOCKFILE_FAIL_IMMEDIATELY ) 
561-     } 
562- 
563-     pub ( super )  fn  try_lock_exclusive ( file :  & File )  -> Result < ( ) >  { 
564-         lock_file ( file,  LOCKFILE_EXCLUSIVE_LOCK  | LOCKFILE_FAIL_IMMEDIATELY ) 
565-     } 
566- 
567-     pub ( super )  fn  error_contended ( err :  & Error )  -> bool  { 
568-         err. raw_os_error ( ) 
569-             . map_or ( false ,  |x| x == ERROR_LOCK_VIOLATION  as  i32 ) 
570-     } 
571- 
572-     pub ( super )  fn  error_unsupported ( err :  & Error )  -> bool  { 
573-         err. raw_os_error ( ) 
574-             . map_or ( false ,  |x| x == ERROR_INVALID_FUNCTION  as  i32 ) 
575-     } 
576- 
577-     pub ( super )  fn  unlock ( file :  & File )  -> Result < ( ) >  { 
578-         unsafe  { 
579-             let  ret = UnlockFile ( file. as_raw_handle ( )  as  HANDLE ,  0 ,  0 ,  !0 ,  !0 ) ; 
580-             if  ret == 0  { 
581-                 Err ( Error :: last_os_error ( ) ) 
582-             }  else  { 
583-                 Ok ( ( ) ) 
584-             } 
585-         } 
586-     } 
587- 
588-     fn  lock_file ( file :  & File ,  flags :  u32 )  -> Result < ( ) >  { 
589-         unsafe  { 
590-             let  mut  overlapped = mem:: zeroed ( ) ; 
591-             let  ret = LockFileEx ( 
592-                 file. as_raw_handle ( )  as  HANDLE , 
593-                 flags, 
594-                 0 , 
595-                 !0 , 
596-                 !0 , 
597-                 & mut  overlapped, 
598-             ) ; 
599-             if  ret == 0  { 
600-                 Err ( Error :: last_os_error ( ) ) 
601-             }  else  { 
602-                 Ok ( ( ) ) 
603-             } 
604-         } 
605-     } 
443+ fn  error_unsupported ( err :  & std:: io:: Error )  -> bool  { 
444+     use  windows_sys:: Win32 :: Foundation :: ERROR_INVALID_FUNCTION ; 
445+     err. raw_os_error ( ) 
446+         . map_or ( false ,  |x| x == ERROR_INVALID_FUNCTION  as  i32 ) 
606447} 
0 commit comments