(index<- )        ./librustdoc/flock.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Wed Apr  9 17:27:02 2014
   1  // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! Simple file-locking apis for each OS.
  12  //!
  13  //! This is not meant to be in the standard library, it does nothing with
  14  //! green/native threading. This is just a bare-bones enough solution for
  15  //! librustdoc, it is not production quality at all.
  16  
  17  #![allow(non_camel_case_types)]
  18  
  19  pub use self::imp::Lock;
  20  
  21  
  22  #[cfg(unix)]
  23  mod imp {
  24      use libc;
  25  
  26      #[cfg(target_os = "linux")]
  27      mod os {
  28          use libc;
  29  
  30          pub struct flock {
  31              pub l_type: libc::c_short,
  32              pub l_whence: libc::c_short,
  33              pub l_start: libc::off_t,
  34              pub l_len: libc::off_t,
  35              pub l_pid: libc::pid_t,
  36  
  37              // not actually here, but brings in line with freebsd
  38              pub l_sysid: libc::c_int,
  39          }
  40  
  41          pub static F_WRLCK: libc::c_short = 1;
  42          pub static F_UNLCK: libc::c_short = 2;
  43          pub static F_SETLK: libc::c_int = 6;
  44          pub static F_SETLKW: libc::c_int = 7;
  45      }
  46  
  47      #[cfg(target_os = "freebsd")]
  48      mod os {
  49          use libc;
  50  
  51          pub struct flock {
  52              pub l_start: libc::off_t,
  53              pub l_len: libc::off_t,
  54              pub l_pid: libc::pid_t,
  55              pub l_type: libc::c_short,
  56              pub l_whence: libc::c_short,
  57              pub l_sysid: libc::c_int,
  58          }
  59  
  60          pub static F_UNLCK: libc::c_short = 2;
  61          pub static F_WRLCK: libc::c_short = 3;
  62          pub static F_SETLK: libc::c_int = 12;
  63          pub static F_SETLKW: libc::c_int = 13;
  64      }
  65  
  66      #[cfg(target_os = "macos")]
  67      mod os {
  68          use libc;
  69  
  70          pub struct flock {
  71              pub l_start: libc::off_t,
  72              pub l_len: libc::off_t,
  73              pub l_pid: libc::pid_t,
  74              pub l_type: libc::c_short,
  75              pub l_whence: libc::c_short,
  76  
  77              // not actually here, but brings in line with freebsd
  78              pub l_sysid: libc::c_int,
  79          }
  80  
  81          pub static F_UNLCK: libc::c_short = 2;
  82          pub static F_WRLCK: libc::c_short = 3;
  83          pub static F_SETLK: libc::c_int = 8;
  84          pub static F_SETLKW: libc::c_int = 9;
  85      }
  86  
  87      pub struct Lock {
  88          fd: libc::c_int,
  89      }
  90  
  91      impl Lock {
  92          pub fn new(p&Path) -> Lock {
  93              let fd = p.with_c_str(|s| unsafe {
  94                  libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
  95              });
  96              assert!(fd > 0);
  97              let flock = os::flock {
  98                  l_start: 0,
  99                  l_len: 0,
 100                  l_pid: 0,
 101                  l_whence: libc::SEEK_SET as libc::c_short,
 102                  l_type: os::F_WRLCK,
 103                  l_sysid: 0,
 104              };
 105              let ret = unsafe {
 106                  libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
 107              };
 108              if ret == -1 {
 109                  unsafe { libc::close(fd); }
 110                  fail!("could not lock `{}`", p.display())
 111              }
 112              Lock { fd: fd }
 113          }
 114      }
 115  
 116      impl Drop for Lock {
 117          fn drop(&mut self) {
 118              let flock = os::flock {
 119                  l_start: 0,
 120                  l_len: 0,
 121                  l_pid: 0,
 122                  l_whence: libc::SEEK_SET as libc::c_short,
 123                  l_type: os::F_UNLCK,
 124                  l_sysid: 0,
 125              };
 126              unsafe {
 127                  libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
 128                  libc::close(self.fd);
 129              }
 130          }
 131      }
 132  }
 133  
 134  #[cfg(windows)]
 135  mod imp {
 136      use libc;
 137      use std::mem;
 138      use std::os::win32::as_utf16_p;
 139      use std::os;
 140      use std::ptr;
 141  
 142      static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;
 143  
 144      extern "system" {
 145          fn LockFileEx(hFile: libc::HANDLE,
 146                        dwFlags: libc::DWORD,
 147                        dwReserved: libc::DWORD,
 148                        nNumberOfBytesToLockLow: libc::DWORD,
 149                        nNumberOfBytesToLockHigh: libc::DWORD,
 150                        lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
 151          fn UnlockFileEx(hFile: libc::HANDLE,
 152                          dwReserved: libc::DWORD,
 153                          nNumberOfBytesToLockLow: libc::DWORD,
 154                          nNumberOfBytesToLockHigh: libc::DWORD,
 155                          lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
 156      }
 157  
 158      pub struct Lock {
 159          handle: libc::HANDLE,
 160      }
 161  
 162      impl Lock {
 163          pub fn new(p: &Path) -> Lock {
 164              let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
 165                  libc::CreateFileW(p,
 166                                    libc::FILE_GENERIC_READ |
 167                                      libc::FILE_GENERIC_WRITE,
 168                                    libc::FILE_SHARE_READ |
 169                                      libc::FILE_SHARE_DELETE |
 170                                      libc::FILE_SHARE_WRITE,
 171                                    ptr::mut_null(),
 172                                    libc::CREATE_ALWAYS,
 173                                    libc::FILE_ATTRIBUTE_NORMAL,
 174                                    ptr::mut_null())
 175              });
 176              if handle as uint == libc::INVALID_HANDLE_VALUE as uint {
 177                  fail!("create file error: {}", os::last_os_error());
 178              }
 179              let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
 180              let ret = unsafe {
 181                  LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
 182                             &mut overlapped)
 183              };
 184              if ret == 0 {
 185                  unsafe { libc::CloseHandle(handle); }
 186                  fail!("could not lock `{}`: {}", p.display(),
 187                        os::last_os_error())
 188              }
 189              Lock { handle: handle }
 190          }
 191      }
 192  
 193      impl Drop for Lock {
 194          fn drop(&mut self) {
 195              let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
 196              unsafe {
 197                  UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
 198                  libc::CloseHandle(self.handle);
 199              }
 200          }
 201      }
 202  }