@@ -65,13 +65,15 @@ fn test_readlink() {
65
65
66
66
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
67
67
mod linux_android {
68
+ use std:: fs:: File ;
68
69
use std:: io:: prelude:: * ;
69
- use std:: io:: SeekFrom ;
70
+ use std:: io:: { BufRead , BufReader , SeekFrom } ;
70
71
use std:: os:: unix:: prelude:: * ;
71
72
72
73
use libc:: loff_t;
73
74
74
75
use nix:: fcntl:: * ;
76
+ use nix:: sys:: stat:: fstat;
75
77
use nix:: sys:: uio:: IoVec ;
76
78
use nix:: unistd:: { close, pipe, read, write} ;
77
79
@@ -197,6 +199,97 @@ mod linux_android {
197
199
let mut buf = [ 0u8 ; 200 ] ;
198
200
assert_eq ! ( 100 , read( fd, & mut buf) . unwrap( ) ) ;
199
201
}
202
+
203
+ // The tests below are disabled for the listed targets
204
+ // due to OFD locks not being available in the kernel/libc
205
+ // versions used in the CI environment, probably because
206
+ // they run under QEMU.
207
+
208
+ #[ test]
209
+ #[ cfg( not( any( target_arch = "aarch64" ,
210
+ target_arch = "arm" ,
211
+ target_arch = "armv7" ,
212
+ target_arch = "x86" ,
213
+ target_arch = "mips" ,
214
+ target_arch = "mips64" ,
215
+ target_arch = "mips64el" ,
216
+ target_arch = "powerpc64" ,
217
+ target_arch = "powerpc64le" ) ) ) ]
218
+ fn test_ofd_write_lock ( ) {
219
+ let tmp = NamedTempFile :: new ( ) . unwrap ( ) ;
220
+
221
+ let fd = tmp. as_raw_fd ( ) ;
222
+ let inode = fstat ( fd) . expect ( "fstat failed" ) . st_ino as usize ;
223
+
224
+ let mut flock = libc:: flock {
225
+ l_type : libc:: F_WRLCK as libc:: c_short ,
226
+ l_whence : libc:: SEEK_SET as libc:: c_short ,
227
+ l_start : 0 ,
228
+ l_len : 0 ,
229
+ l_pid : 0 ,
230
+ } ;
231
+ fcntl ( fd, FcntlArg :: F_OFD_SETLKW ( & flock) ) . expect ( "write lock failed" ) ;
232
+ assert_eq ! (
233
+ Some ( ( "OFDLCK" . to_string( ) , "WRITE" . to_string( ) ) ) ,
234
+ lock_info( inode)
235
+ ) ;
236
+
237
+ flock. l_type = libc:: F_UNLCK as libc:: c_short ;
238
+ fcntl ( fd, FcntlArg :: F_OFD_SETLKW ( & flock) ) . expect ( "write unlock failed" ) ;
239
+ assert_eq ! ( None , lock_info( inode) ) ;
240
+ }
241
+
242
+ #[ test]
243
+ #[ cfg( not( any( target_arch = "aarch64" ,
244
+ target_arch = "arm" ,
245
+ target_arch = "armv7" ,
246
+ target_arch = "x86" ,
247
+ target_arch = "mips" ,
248
+ target_arch = "mips64" ,
249
+ target_arch = "mips64el" ,
250
+ target_arch = "powerpc64" ,
251
+ target_arch = "powerpc64le" ) ) ) ]
252
+ fn test_ofd_read_lock ( ) {
253
+ let tmp = NamedTempFile :: new ( ) . unwrap ( ) ;
254
+
255
+ let fd = tmp. as_raw_fd ( ) ;
256
+ let inode = fstat ( fd) . expect ( "fstat failed" ) . st_ino as usize ;
257
+
258
+ let mut flock = libc:: flock {
259
+ l_type : libc:: F_RDLCK as libc:: c_short ,
260
+ l_whence : libc:: SEEK_SET as libc:: c_short ,
261
+ l_start : 0 ,
262
+ l_len : 0 ,
263
+ l_pid : 0 ,
264
+ } ;
265
+ fcntl ( fd, FcntlArg :: F_OFD_SETLKW ( & flock) ) . expect ( "read lock failed" ) ;
266
+ assert_eq ! (
267
+ Some ( ( "OFDLCK" . to_string( ) , "READ" . to_string( ) ) ) ,
268
+ lock_info( inode)
269
+ ) ;
270
+
271
+ flock. l_type = libc:: F_UNLCK as libc:: c_short ;
272
+ fcntl ( fd, FcntlArg :: F_OFD_SETLKW ( & flock) ) . expect ( "read unlock failed" ) ;
273
+ assert_eq ! ( None , lock_info( inode) ) ;
274
+ }
275
+
276
+ fn lock_info ( inode : usize ) -> Option < ( String , String ) > {
277
+ let file = File :: open ( "/proc/locks" ) . expect ( "open /proc/locks failed" ) ;
278
+ let buf = BufReader :: new ( file) ;
279
+
280
+ for line in buf. lines ( ) {
281
+ let line = line. unwrap ( ) ;
282
+ let parts: Vec < _ > = line. split_whitespace ( ) . collect ( ) ;
283
+ let lock_type = parts[ 1 ] ;
284
+ let lock_access = parts[ 3 ] ;
285
+ let ino_parts: Vec < _ > = parts[ 5 ] . split ( ':' ) . collect ( ) ;
286
+ let ino: usize = ino_parts[ 2 ] . parse ( ) . unwrap ( ) ;
287
+ if ino == inode {
288
+ return Some ( ( lock_type. to_string ( ) , lock_access. to_string ( ) ) ) ;
289
+ }
290
+ }
291
+ None
292
+ }
200
293
}
201
294
202
295
#[ cfg( any( target_os = "linux" ,
0 commit comments