about summary refs log tree commit diff
path: root/src/librustc_data_structures
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo.net>2016-08-15 13:52:38 -0400
committerMichael Woerister <michaelwoerister@posteo.net>2016-08-29 14:27:40 -0400
commit206e7b6fc704c53b2a7174e8bec7b5f575d9bc93 (patch)
treeac840e1e35bec3accc44fbc96d850ddca19cb874 /src/librustc_data_structures
parent6ef8198406af9ba18787e0fd50ae2e25f78b7e4f (diff)
downloadrust-206e7b6fc704c53b2a7174e8bec7b5f575d9bc93.tar.gz
rust-206e7b6fc704c53b2a7174e8bec7b5f575d9bc93.zip
Add some features to flock.
Diffstat (limited to 'src/librustc_data_structures')
-rw-r--r--src/librustc_data_structures/flock.rs126
1 files changed, 105 insertions, 21 deletions
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
index 41bcfdb7cb0..adfeaae8475 100644
--- a/src/librustc_data_structures/flock.rs
+++ b/src/librustc_data_structures/flock.rs
@@ -15,6 +15,7 @@
 //! librustdoc, it is not production quality at all.
 
 #![allow(non_camel_case_types)]
+use std::path::Path;
 
 pub use self::imp::Lock;
 
@@ -41,6 +42,7 @@ mod imp {
             pub l_sysid: libc::c_int,
         }
 
+        pub const F_RDLCK: libc::c_short = 0;
         pub const F_WRLCK: libc::c_short = 1;
         pub const F_UNLCK: libc::c_short = 2;
         pub const F_SETLK: libc::c_int = 6;
@@ -60,6 +62,7 @@ mod imp {
             pub l_sysid: libc::c_int,
         }
 
+        pub const F_RDLCK: libc::c_short = 1;
         pub const F_UNLCK: libc::c_short = 2;
         pub const F_WRLCK: libc::c_short = 3;
         pub const F_SETLK: libc::c_int = 12;
@@ -84,6 +87,7 @@ mod imp {
             pub l_sysid: libc::c_int,
         }
 
+        pub const F_RDLCK: libc::c_short = 1;
         pub const F_UNLCK: libc::c_short = 2;
         pub const F_WRLCK: libc::c_short = 3;
         pub const F_SETLK: libc::c_int = 8;
@@ -105,6 +109,7 @@ mod imp {
             pub l_sysid: libc::c_int,
         }
 
+        pub const F_RDLCK: libc::c_short = 1;
         pub const F_UNLCK: libc::c_short = 2;
         pub const F_WRLCK: libc::c_short = 3;
         pub const F_SETLK: libc::c_int = 8;
@@ -124,6 +129,7 @@ mod imp {
             pub l_pid: libc::pid_t,
         }
 
+        pub const F_RDLCK: libc::c_short = 1;
         pub const F_WRLCK: libc::c_short = 2;
         pub const F_UNLCK: libc::c_short = 3;
         pub const F_SETLK: libc::c_int = 6;
@@ -135,32 +141,53 @@ mod imp {
     }
 
     impl Lock {
-        pub fn new(p: &Path) -> Lock {
+        pub fn new(p: &Path,
+                   wait: bool,
+                   create: bool,
+                   exclusive: bool)
+                   -> io::Result<Lock> {
             let os: &OsStr = p.as_ref();
             let buf = CString::new(os.as_bytes()).unwrap();
+            let open_flags = if create {
+                libc::O_RDWR | libc::O_CREAT
+            } else {
+                libc::O_RDWR
+            };
+
             let fd = unsafe {
-                libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
+                libc::open(buf.as_ptr(), open_flags,
                            libc::S_IRWXU as libc::c_int)
             };
-            assert!(fd > 0, "failed to open lockfile: {}",
-                    io::Error::last_os_error());
+
+            if fd < 0 {
+                return Err(io::Error::last_os_error());
+            }
+
+            let lock_type = if exclusive {
+                os::F_WRLCK
+            } else {
+                os::F_RDLCK
+            };
+
             let flock = os::flock {
                 l_start: 0,
                 l_len: 0,
                 l_pid: 0,
                 l_whence: libc::SEEK_SET as libc::c_short,
-                l_type: os::F_WRLCK,
+                l_type: lock_type,
                 l_sysid: 0,
             };
+            let cmd = if wait { os::F_SETLKW } else { os::F_SETLK };
             let ret = unsafe {
-                libc::fcntl(fd, os::F_SETLKW, &flock)
+                libc::fcntl(fd, cmd, &flock)
             };
             if ret == -1 {
                 let err = io::Error::last_os_error();
                 unsafe { libc::close(fd); }
-                panic!("could not lock `{}`: {}", p.display(), err);
+                Err(err)
+            } else {
+                Ok(Lock { fd: fd })
             }
-            Lock { fd: fd }
         }
     }
 
@@ -191,18 +218,28 @@ mod imp {
     use std::os::windows::raw::HANDLE;
     use std::path::Path;
     use std::fs::{File, OpenOptions};
+    use std::os::raw::{c_ulong, c_ulonglong, c_int};
+    use std::os::windows::fs::OpenOptionsExt;
+
+    pub type DWORD = c_ulong;
+    pub type BOOL = c_int;
+    pub type ULONG_PTR = c_ulonglong;
 
-    type DWORD = u32;
     type LPOVERLAPPED = *mut OVERLAPPED;
-    type BOOL = i32;
     const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
+    const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001;
+
+    pub const FILE_SHARE_DELETE: DWORD = 0x4;
+    pub const FILE_SHARE_READ: DWORD = 0x1;
+    pub const FILE_SHARE_WRITE: DWORD = 0x2;
 
     #[repr(C)]
     struct OVERLAPPED {
-        Internal: usize,
-        InternalHigh: usize,
-        Pointer: *mut u8,
-        hEvent: *mut u8,
+        Internal: ULONG_PTR,
+        InternalHigh: ULONG_PTR,
+        Offset: DWORD,
+        OffsetHigh: DWORD,
+        hEvent: HANDLE,
     }
 
     extern "system" {
@@ -219,19 +256,66 @@ mod imp {
     }
 
     impl Lock {
-        pub fn new(p: &Path) -> Lock {
-            let f = OpenOptions::new().read(true).write(true).create(true)
-                                      .open(p).unwrap();
+        pub fn new(p: &Path,
+                   wait: bool,
+                   create: bool,
+                   exclusive: bool)
+                   -> io::Result<Lock> {
+
+            let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+            let f = {
+                let mut open_options = OpenOptions::new().read(true)
+                                                         .share_mode(share_mode);
+                if create {
+                    open_options.create(true);
+                }
+
+                match open_options.open(p) {
+                    Ok(file) => file,
+                    Err(err) => return Err(err),
+                }
+            };
+
             let ret = unsafe {
                 let mut overlapped: OVERLAPPED = mem::zeroed();
-                LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
+
+                let mut dwFlags = 0;
+                if !wait {
+                    dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
+                }
+
+                if exclusive {
+                    dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+                }
+
+                LockFileEx(f.as_raw_handle(),
+                           dwFlags,
+                           0,
+                           0xFFFF_FFFF,
+                           0xFFFF_FFFF,
                            &mut overlapped)
             };
             if ret == 0 {
-                let err = io::Error::last_os_error();
-                panic!("could not lock `{}`: {}", p.display(), err);
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(Lock { _file: f })
             }
-            Lock { _file: f }
         }
     }
+
+    // Note that we don't need a Drop impl on the Windows: The file is unlocked
+    // automatically when it's closed.
+}
+
+impl imp::Lock {
+    pub fn panicking_new(p: &Path,
+                         wait: bool,
+                         create: bool,
+                         exclusive: bool)
+                         -> Lock {
+        Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| {
+            panic!("could not lock `{}`: {}", p.display(), err);
+        })
+    }
 }