@@ -16,7 +16,7 @@ use crate::shims::unix::*;
1616use crate :: * ;
1717use shims:: time:: system_time_to_duration;
1818
19- use self :: fd:: FileDescriptor ;
19+ use self :: fd:: { FileDescriptor , FlockOp } ;
2020
2121#[ derive( Debug ) ]
2222struct FileHandle {
@@ -81,6 +81,89 @@ impl FileDescription for FileHandle {
8181 }
8282 }
8383
84+ fn flock < ' tcx > (
85+ & self ,
86+ communicate_allowed : bool ,
87+ op : FlockOp ,
88+ ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
89+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
90+ #[ cfg( target_family = "unix" ) ]
91+ {
92+ use std:: os:: fd:: AsRawFd ;
93+
94+ // Transform `op` into host's flags
95+ use FlockOp :: * ;
96+ let host_op = match op {
97+ SharedLock { nonblocking : false } => libc:: LOCK_SH ,
98+ SharedLock { nonblocking : true } => libc:: LOCK_SH | libc:: LOCK_NB ,
99+ ExclusiveLock { nonblocking : false } => libc:: LOCK_EX ,
100+ ExclusiveLock { nonblocking : true } => libc:: LOCK_EX | libc:: LOCK_NB ,
101+ Unlock => libc:: LOCK_UN ,
102+ } ;
103+
104+ let fd = self . file . as_raw_fd ( ) ;
105+ let ret = unsafe { libc:: flock ( fd, host_op) } ;
106+ let res = match ret {
107+ 0 => Ok ( ( ) ) ,
108+ -1 => Err ( io:: Error :: last_os_error ( ) ) ,
109+ ret => panic ! ( "Unexpected return value from flock: {ret}" ) ,
110+ } ;
111+ Ok ( res)
112+ }
113+
114+ #[ cfg( target_family = "windows" ) ]
115+ {
116+ use std:: os:: windows:: io:: AsRawHandle ;
117+ use windows_sys:: Win32 :: {
118+ Foundation :: { ERROR_IO_PENDING , ERROR_LOCK_VIOLATION , FALSE , HANDLE , TRUE } ,
119+ Storage :: FileSystem :: {
120+ LockFileEx , UnlockFile , LOCKFILE_EXCLUSIVE_LOCK , LOCKFILE_FAIL_IMMEDIATELY ,
121+ } ,
122+ } ;
123+ let handle = self . file . as_raw_handle ( ) as HANDLE ;
124+
125+ use FlockOp :: * ;
126+ let mut lock_nb = false ;
127+ let ret = match op {
128+ SharedLock { nonblocking } | ExclusiveLock { nonblocking } => {
129+ lock_nb = nonblocking;
130+ let mut flags = 0 ;
131+ if nonblocking {
132+ flags |= LOCKFILE_FAIL_IMMEDIATELY ;
133+ }
134+ if let ExclusiveLock { .. } = op {
135+ flags |= LOCKFILE_EXCLUSIVE_LOCK ;
136+ }
137+ unsafe { LockFileEx ( handle, flags, 0 , !0 , !0 , & mut std:: mem:: zeroed ( ) ) }
138+ }
139+ Unlock => unsafe { UnlockFile ( handle, 0 , 0 , !0 , !0 ) } ,
140+ } ;
141+
142+ let res = match ret {
143+ TRUE => Ok ( ( ) ) ,
144+ FALSE => {
145+ let mut err = io:: Error :: last_os_error ( ) ;
146+ let code: u32 = err. raw_os_error ( ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;
147+ // Replace error with a custom WouldBlock error, which later will be mapped
148+ // in the `helpers` module
149+ if lock_nb && matches ! ( code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION ) {
150+ let desc = format ! ( "LockFileEx wouldblock error: {err}" ) ;
151+ err = io:: Error :: new ( io:: ErrorKind :: WouldBlock , desc) ;
152+ }
153+ Err ( err)
154+ }
155+ _ => panic ! ( "Unexpected return value: {ret}" ) ,
156+ } ;
157+ Ok ( res)
158+ }
159+
160+ #[ cfg( not( any( target_family = "unix" , target_family = "windows" ) ) ) ]
161+ {
162+ let _ = op;
163+ throw_unsup_format ! ( "flock is supported only on UNIX and Windows hosts" ) ;
164+ }
165+ }
166+
84167 fn is_tty ( & self , communicate_allowed : bool ) -> bool {
85168 communicate_allowed && self . file . is_terminal ( )
86169 }
0 commit comments