Skip to content

Commit 756210a

Browse files
committed
std: Ensure fs::{DirEntry, ReadDir} are Send/Sync
The windows/unix modules were currently inconsistent about the traits being implemented for `DirEntry` and there isn't much particular reason why the traits *couldn't* be implemented for `ReadDir` and `DirEntry`, so this commit ensures that they are implemented. Closes #22577
1 parent 522d09d commit 756210a

File tree

3 files changed

+76
-25
lines changed

3 files changed

+76
-25
lines changed

src/libstd/sys/unix/fs2.rs

+20-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t};
1818
use mem;
1919
use path::{Path, PathBuf};
2020
use ptr;
21-
use rc::Rc;
21+
use sync::Arc;
2222
use sys::fd::FileDesc;
2323
use sys::{c, cvt, cvt_r};
2424
use sys_common::FromInner;
@@ -31,14 +31,18 @@ pub struct FileAttr {
3131
}
3232

3333
pub struct ReadDir {
34-
dirp: *mut libc::DIR,
35-
root: Rc<PathBuf>,
34+
dirp: Dir,
35+
root: Arc<PathBuf>,
3636
}
3737

38+
struct Dir(*mut libc::DIR);
39+
40+
unsafe impl Send for Dir {}
41+
unsafe impl Sync for Dir {}
42+
3843
pub struct DirEntry {
39-
buf: Vec<u8>,
40-
dirent: *mut libc::dirent_t,
41-
root: Rc<PathBuf>,
44+
buf: Vec<u8>, // actually *mut libc::dirent_t
45+
root: Arc<PathBuf>,
4246
}
4347

4448
#[derive(Clone)]
@@ -109,7 +113,7 @@ impl Iterator for ReadDir {
109113

110114
let mut entry_ptr = ptr::null_mut();
111115
loop {
112-
if unsafe { libc::readdir_r(self.dirp, ptr, &mut entry_ptr) != 0 } {
116+
if unsafe { libc::readdir_r(self.dirp.0, ptr, &mut entry_ptr) != 0 } {
113117
return Some(Err(Error::last_os_error()))
114118
}
115119
if entry_ptr.is_null() {
@@ -118,7 +122,6 @@ impl Iterator for ReadDir {
118122

119123
let entry = DirEntry {
120124
buf: buf,
121-
dirent: entry_ptr,
122125
root: self.root.clone()
123126
};
124127
if entry.name_bytes() == b"." || entry.name_bytes() == b".." {
@@ -130,9 +133,9 @@ impl Iterator for ReadDir {
130133
}
131134
}
132135

133-
impl Drop for ReadDir {
136+
impl Drop for Dir {
134137
fn drop(&mut self) {
135-
let r = unsafe { libc::closedir(self.dirp) };
138+
let r = unsafe { libc::closedir(self.0) };
136139
debug_assert_eq!(r, 0);
137140
}
138141
}
@@ -147,9 +150,13 @@ impl DirEntry {
147150
fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
148151
}
149152
unsafe {
150-
CStr::from_ptr(rust_list_dir_val(self.dirent)).to_bytes()
153+
CStr::from_ptr(rust_list_dir_val(self.dirent())).to_bytes()
151154
}
152155
}
156+
157+
fn dirent(&self) -> *mut libc::dirent_t {
158+
self.buf.as_ptr() as *mut _
159+
}
153160
}
154161

155162
impl OpenOptions {
@@ -279,14 +286,14 @@ pub fn mkdir(p: &Path) -> io::Result<()> {
279286
}
280287

281288
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
282-
let root = Rc::new(p.to_path_buf());
289+
let root = Arc::new(p.to_path_buf());
283290
let p = try!(cstr(p));
284291
unsafe {
285292
let ptr = libc::opendir(p.as_ptr());
286293
if ptr.is_null() {
287294
Err(Error::last_os_error())
288295
} else {
289-
Ok(ReadDir { dirp: ptr, root: root })
296+
Ok(ReadDir { dirp: Dir(ptr), root: root })
290297
}
291298
}
292299
}

src/libstd/sys/windows/fs2.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use libc::{self, HANDLE};
1919
use mem;
2020
use path::{Path, PathBuf};
2121
use ptr;
22+
use sync::Arc;
2223
use sys::handle::Handle as RawHandle;
2324
use sys::{c, cvt};
2425
use vec::Vec;
@@ -27,12 +28,20 @@ pub struct File { handle: RawHandle }
2728
pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA }
2829

2930
pub struct ReadDir {
30-
handle: libc::HANDLE,
31-
root: PathBuf,
31+
handle: FindNextFileHandle,
32+
root: Arc<PathBuf>,
3233
first: Option<libc::WIN32_FIND_DATAW>,
3334
}
3435

35-
pub struct DirEntry { path: PathBuf }
36+
struct FindNextFileHandle(libc::HANDLE);
37+
38+
unsafe impl Send for FindNextFileHandle {}
39+
unsafe impl Sync for FindNextFileHandle {}
40+
41+
pub struct DirEntry {
42+
root: Arc<PathBuf>,
43+
data: libc::WIN32_FIND_DATAW,
44+
}
3645

3746
#[derive(Clone, Default)]
3847
pub struct OpenOptions {
@@ -61,7 +70,7 @@ impl Iterator for ReadDir {
6170
unsafe {
6271
let mut wfd = mem::zeroed();
6372
loop {
64-
if libc::FindNextFileW(self.handle, &mut wfd) == 0 {
73+
if libc::FindNextFileW(self.handle.0, &mut wfd) == 0 {
6574
if libc::GetLastError() ==
6675
c::ERROR_NO_MORE_FILES as libc::DWORD {
6776
return None
@@ -77,29 +86,31 @@ impl Iterator for ReadDir {
7786
}
7887
}
7988

80-
impl Drop for ReadDir {
89+
impl Drop for FindNextFileHandle {
8190
fn drop(&mut self) {
82-
let r = unsafe { libc::FindClose(self.handle) };
91+
let r = unsafe { libc::FindClose(self.0) };
8392
debug_assert!(r != 0);
8493
}
8594
}
8695

8796
impl DirEntry {
88-
fn new(root: &Path, wfd: &libc::WIN32_FIND_DATAW) -> Option<DirEntry> {
97+
fn new(root: &Arc<PathBuf>, wfd: &libc::WIN32_FIND_DATAW) -> Option<DirEntry> {
8998
match &wfd.cFileName[0..3] {
9099
// check for '.' and '..'
91100
[46, 0, ..] |
92101
[46, 46, 0, ..] => return None,
93102
_ => {}
94103
}
95104

96-
let filename = super::truncate_utf16_at_nul(&wfd.cFileName);
97-
let filename: OsString = OsStringExt::from_wide(filename);
98-
Some(DirEntry { path: root.join(&filename) })
105+
Some(DirEntry {
106+
root: root.clone(),
107+
data: *wfd,
108+
})
99109
}
100110

101111
pub fn path(&self) -> PathBuf {
102-
self.path.clone()
112+
let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
113+
self.root.join(&<OsString as OsStringExt>::from_wide(filename))
103114
}
104115
}
105116

@@ -312,7 +323,11 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
312323
let mut wfd = mem::zeroed();
313324
let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
314325
if find_handle != libc::INVALID_HANDLE_VALUE {
315-
Ok(ReadDir { handle: find_handle, root: root, first: Some(wfd) })
326+
Ok(ReadDir {
327+
handle: FindNextFileHandle(find_handle),
328+
root: Arc::new(root),
329+
first: Some(wfd),
330+
})
316331
} else {
317332
Err(Error::last_os_error())
318333
}

src/test/run-pass/issue-22577.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
11+
use std::{fs, net};
12+
13+
fn assert_both<T: Send + Sync>() {}
14+
15+
fn main() {
16+
assert_both::<fs::File>();
17+
assert_both::<fs::Metadata>();
18+
assert_both::<fs::ReadDir>();
19+
assert_both::<fs::DirEntry>();
20+
assert_both::<fs::WalkDir>();
21+
assert_both::<fs::OpenOptions>();
22+
assert_both::<fs::Permissions>();
23+
24+
assert_both::<net::TcpStream>();
25+
assert_both::<net::TcpListener>();
26+
assert_both::<net::UdpSocket>();
27+
assert_both::<net::SocketAddr>();
28+
assert_both::<net::IpAddr>();
29+
}

0 commit comments

Comments
 (0)