Skip to content

Commit

Permalink
Changes requested by @asomers on nix-rust#1231
Browse files Browse the repository at this point in the history
  • Loading branch information
SolraBizna committed May 3, 2020
1 parent ba2685b commit 6e00c73
Showing 1 changed file with 37 additions and 24 deletions.
61 changes: 37 additions & 24 deletions src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: Option<Ra
Errno::result(res).map(drop)
}

fn wrap_readlink_result(v: &mut Vec<u8>, res: ssize_t) -> Result<OsString> {
fn wrap_readlink_result(mut v: Vec<u8>, res: ssize_t) -> Result<OsString> {
match Errno::result(res) {
Err(err) => Err(err),
Ok(len) => {
Expand All @@ -191,48 +191,60 @@ fn wrap_readlink_result(v: &mut Vec<u8>, res: ssize_t) -> Result<OsString> {
}
}

fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
// simple case: result is strictly less than `PATH_MAX`
let res = path.with_nix_path(|cstr| {
fn readlink_maybe_at<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P,
v: &mut Vec<u8>)
-> Result<libc::ssize_t> {
path.with_nix_path(|cstr| {
unsafe {
match dirfd {
Some(dirfd) => libc::readlinkat(dirfd, cstr.as_ptr(), v.as_mut_ptr() as *mut c_char, v.capacity() as size_t),
None => libc::readlink(cstr.as_ptr(), v.as_mut_ptr() as *mut c_char, v.capacity() as size_t),
Some(dirfd) => libc::readlinkat(dirfd, cstr.as_ptr(),
v.as_mut_ptr() as *mut c_char,
v.capacity() as size_t),
None => libc::readlink(cstr.as_ptr(),
v.as_mut_ptr() as *mut c_char,
v.capacity() as size_t),
}
}
})?;
})
}

fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P)
-> Result<OsString> {
let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
// simple case: result is strictly less than `PATH_MAX`
let res = readlink_maybe_at(dirfd, path, &mut v)?;
let len = Errno::result(res)?;
debug_assert!(len >= 0);
if (len as usize) < v.capacity() {
return wrap_readlink_result(&mut v, res);
return wrap_readlink_result(v, res);
}
// Uh oh, the result is too long...
// Let's try to ask lstat how many bytes to allocate.
let reported_size = super::sys::stat::lstat(path).and_then(|x| Ok(x.st_size)).unwrap_or(0);
let mut try_size = if reported_size > 0 { reported_size as usize + 1 }
// If lstat doesn't cooperate, or reports an error, be a little less precise.
else { (libc::PATH_MAX as usize).max(128) << 1 };
let reported_size = super::sys::stat::lstat(path)
.and_then(|x| Ok(x.st_size)).unwrap_or(0);
let mut try_size = if reported_size > 0 {
// Note: even if `lstat`'s apparently valid answer turns out to be
// wrong, we will still read the full symlink no matter what.
reported_size as usize + 1
} else {
// If lstat doesn't cooperate, or reports an error, be a little less
// precise.
(libc::PATH_MAX as usize).max(128) << 1
};
loop {
v.reserve_exact(try_size);
let res = path.with_nix_path(|cstr| {
unsafe {
match dirfd {
Some(dirfd) => libc::readlinkat(dirfd, cstr.as_ptr(), v.as_mut_ptr() as *mut c_char, v.capacity() as size_t),
None => libc::readlink(cstr.as_ptr(), v.as_mut_ptr() as *mut c_char, v.capacity() as size_t),
}
}
})?;
let res = readlink_maybe_at(dirfd, path, &mut v)?;
let len = Errno::result(res)?;
debug_assert!(len >= 0);
if (len as usize) < v.capacity() {
break wrap_readlink_result(&mut v, res);
break wrap_readlink_result(v, res);
}
else {
// Ugh! Still not big enough!
let next_size = try_size << 1;
if next_size < try_size {
// It's absurd that this would happen, but handle it sanely anyway.
// It's absurd that this would happen, but handle it sanely
// anyway.
break Err(super::Error::Sys(Errno::ENAMETOOLONG))
}
else {
Expand All @@ -247,7 +259,8 @@ pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
}


pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P)
-> Result<OsString> {
inner_readlink(Some(dirfd), path)
}

Expand Down

0 comments on commit 6e00c73

Please sign in to comment.