]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/fd.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / libstd / sys / unix / fd.rs
CommitLineData
85aaf69f
SL
1// Copyright 2015 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
54a0048b
SL
11#![unstable(reason = "not public", issue = "0", feature = "fd")]
12
54a0048b 13use io::{self, Read};
85aaf69f
SL
14use libc::{self, c_int, size_t, c_void};
15use mem;
54a0048b 16use sync::atomic::{AtomicBool, Ordering};
85aaf69f
SL
17use sys::cvt;
18use sys_common::AsInner;
54a0048b 19use sys_common::io::read_to_end_uninitialized;
85aaf69f
SL
20
21pub struct FileDesc {
22 fd: c_int,
23}
24
25impl FileDesc {
26 pub fn new(fd: c_int) -> FileDesc {
27 FileDesc { fd: fd }
28 }
29
30 pub fn raw(&self) -> c_int { self.fd }
31
9346a6ac 32 /// Extracts the actual filedescriptor without closing it.
85aaf69f
SL
33 pub fn into_raw(self) -> c_int {
34 let fd = self.fd;
bd371182 35 mem::forget(self);
85aaf69f
SL
36 fd
37 }
38
39 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
54a0048b 40 let ret = cvt(unsafe {
85aaf69f
SL
41 libc::read(self.fd,
42 buf.as_mut_ptr() as *mut c_void,
43 buf.len() as size_t)
54a0048b 44 })?;
85aaf69f
SL
45 Ok(ret as usize)
46 }
47
54a0048b
SL
48 pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
49 let mut me = self;
50 (&mut me).read_to_end(buf)
51 }
52
85aaf69f 53 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
54a0048b 54 let ret = cvt(unsafe {
85aaf69f
SL
55 libc::write(self.fd,
56 buf.as_ptr() as *const c_void,
57 buf.len() as size_t)
54a0048b 58 })?;
85aaf69f
SL
59 Ok(ret as usize)
60 }
9346a6ac 61
9e0c209e
SL
62 #[cfg(not(any(target_env = "newlib",
63 target_os = "solaris",
64 target_os = "emscripten",
65 target_os = "haiku")))]
3157f602 66 pub fn set_cloexec(&self) -> io::Result<()> {
9346a6ac 67 unsafe {
3157f602
XL
68 cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
69 Ok(())
92a42be0
SL
70 }
71 }
9e0c209e
SL
72 #[cfg(any(target_env = "newlib",
73 target_os = "solaris",
74 target_os = "emscripten",
75 target_os = "haiku"))]
3157f602 76 pub fn set_cloexec(&self) -> io::Result<()> {
92a42be0 77 unsafe {
3157f602
XL
78 let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
79 cvt(libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC))?;
80 Ok(())
9346a6ac
AL
81 }
82 }
7453a54e 83
3157f602 84 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
54a0048b 85 unsafe {
3157f602 86 let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
54a0048b
SL
87 let new = if nonblocking {
88 previous | libc::O_NONBLOCK
89 } else {
90 previous & !libc::O_NONBLOCK
91 };
3157f602
XL
92 cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
93 Ok(())
54a0048b
SL
94 }
95 }
96
7453a54e
SL
97 pub fn duplicate(&self) -> io::Result<FileDesc> {
98 // We want to atomically duplicate this file descriptor and set the
99 // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
100 // flag, however, isn't supported on older Linux kernels (earlier than
101 // 2.6.24).
102 //
103 // To detect this and ensure that CLOEXEC is still set, we
104 // follow a strategy similar to musl [1] where if passing
105 // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
106 // supported (the third parameter, 0, is always valid), so we stop
107 // trying that.
108 //
109 // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
110 // resolve so we at least compile this.
111 //
112 // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
9e0c209e 113 #[cfg(any(target_os = "android", target_os = "haiku"))]
7453a54e 114 use libc::F_DUPFD as F_DUPFD_CLOEXEC;
9e0c209e 115 #[cfg(not(any(target_os = "android", target_os="haiku")))]
7453a54e
SL
116 use libc::F_DUPFD_CLOEXEC;
117
118 let make_filedesc = |fd| {
119 let fd = FileDesc::new(fd);
3157f602
XL
120 fd.set_cloexec()?;
121 Ok(fd)
7453a54e
SL
122 };
123 static TRY_CLOEXEC: AtomicBool =
124 AtomicBool::new(!cfg!(target_os = "android"));
125 let fd = self.raw();
126 if TRY_CLOEXEC.load(Ordering::Relaxed) {
127 match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
128 // We *still* call the `set_cloexec` method as apparently some
129 // linux kernel at some point stopped setting CLOEXEC even
130 // though it reported doing so on F_DUPFD_CLOEXEC.
131 Ok(fd) => {
132 return Ok(if cfg!(target_os = "linux") {
3157f602 133 make_filedesc(fd)?
7453a54e
SL
134 } else {
135 FileDesc::new(fd)
136 })
137 }
138 Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
139 TRY_CLOEXEC.store(false, Ordering::Relaxed);
140 }
141 Err(e) => return Err(e),
142 }
143 }
3157f602 144 cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
7453a54e 145 }
85aaf69f
SL
146}
147
54a0048b
SL
148impl<'a> Read for &'a FileDesc {
149 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
150 (**self).read(buf)
151 }
152
153 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
154 unsafe { read_to_end_uninitialized(self, buf) }
155 }
156}
157
85aaf69f
SL
158impl AsInner<c_int> for FileDesc {
159 fn as_inner(&self) -> &c_int { &self.fd }
160}
161
162impl Drop for FileDesc {
163 fn drop(&mut self) {
9346a6ac
AL
164 // Note that errors are ignored when closing a file descriptor. The
165 // reason for this is that if an error occurs we don't actually know if
166 // the file descriptor was closed or not, and if we retried (for
167 // something like EINTR), we might close another valid file descriptor
168 // (opened after we closed ours.
169 let _ = unsafe { libc::close(self.fd) };
85aaf69f
SL
170 }
171}