1
Fork 0

std: Implement CString-related RFCs

This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These
two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type
to the module.

[r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md
[r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md

The new `CStr` type is only constructable via two methods:

1. By `deref`'ing from a `CString`
2. Unsafely via `CStr::from_ptr`

The purpose of `CStr` is to be an unsized type which is a thin pointer to a
`libc::c_char` (currently it is a fat pointer slice due to implementation
limitations). Strings from C can be safely represented with a `CStr` and an
appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr`
instead to allow producers to pass in C-originating strings instead of just
Rust-allocated strings.

A new constructor was added to `CString`, `new`, which takes `T: IntoBytes`
instead of separate `from_slice` and `from_vec` methods (both have been
deprecated in favor of `new`). The `new` method returns a `Result` instead of
panicking.  The error variant contains the relevant information about where the
error happened and bytes (if present). Conversions are provided to the
`io::Error` and `old_io::IoError` types via the `FromError` trait which
translate to `InvalidInput`.

This is a breaking change due to the modification of existing `#[unstable]` APIs
and new deprecation, and more detailed information can be found in the two RFCs.
Notable breakage includes:

* All construction of `CString` now needs to use `new` and handle the outgoing
  `Result`.
* Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call.
* The `as_slice*` methods have been removed in favor of just having the
  `as_bytes*` methods.

Closes #22469
Closes #22470
[breaking-change]
This commit is contained in:
Alex Crichton 2015-02-17 22:47:40 -08:00
parent dfc5c0f1e8
commit 1860ee521a
40 changed files with 555 additions and 290 deletions

View file

@ -12,7 +12,7 @@
use prelude::v1::*;
use ffi::{self, CString};
use ffi::{CString, CStr};
use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use old_io::{IoResult, FileStat, SeekStyle};
use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
@ -151,8 +151,8 @@ impl Drop for FileDesc {
}
}
fn cstr(path: &Path) -> CString {
CString::from_slice(path.as_vec())
fn cstr(path: &Path) -> IoResult<CString> {
Ok(try!(CString::new(path.as_vec())))
}
pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
@ -170,7 +170,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
libc::S_IRUSR | libc::S_IWUSR),
};
let path = cstr(path);
let path = try!(cstr(path));
match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
-1 => Err(super::last_error()),
fd => Ok(FileDesc::new(fd, true)),
@ -178,7 +178,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
}
pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
}
@ -203,7 +203,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
let mut buf = Vec::<u8>::with_capacity(size as uint);
let ptr = buf.as_mut_ptr() as *mut dirent_t;
let p = CString::from_slice(p.as_vec());
let p = try!(CString::new(p.as_vec()));
let dir_ptr = unsafe {opendir(p.as_ptr())};
if dir_ptr as uint != 0 {
@ -212,7 +212,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
if entry_ptr.is_null() { break }
paths.push(unsafe {
Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr)))
Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes())
});
}
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
@ -223,39 +223,39 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
}
pub fn unlink(p: &Path) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
}
pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
let old = cstr(old);
let new = cstr(new);
let old = try!(cstr(old));
let new = try!(cstr(new));
mkerr_libc(unsafe {
libc::rename(old.as_ptr(), new.as_ptr())
})
}
pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
mkerr_libc(retry(|| unsafe {
libc::chmod(p.as_ptr(), mode as libc::mode_t)
}))
}
pub fn rmdir(p: &Path) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
}
pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
mkerr_libc(retry(|| unsafe {
libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
}))
}
pub fn readlink(p: &Path) -> IoResult<Path> {
let c_path = cstr(p);
let c_path = try!(cstr(p));
let p = c_path.as_ptr();
let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
if len == -1 {
@ -276,14 +276,14 @@ pub fn readlink(p: &Path) -> IoResult<Path> {
}
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
let src = cstr(src);
let dst = cstr(dst);
let src = try!(cstr(src));
let dst = try!(cstr(dst));
mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
}
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
let src = cstr(src);
let dst = cstr(dst);
let src = try!(cstr(src));
let dst = try!(cstr(dst));
mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
}
@ -331,7 +331,7 @@ fn mkstat(stat: &libc::stat) -> FileStat {
}
pub fn stat(p: &Path) -> IoResult<FileStat> {
let p = cstr(p);
let p = try!(cstr(p));
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
@ -340,7 +340,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> {
}
pub fn lstat(p: &Path) -> IoResult<FileStat> {
let p = cstr(p);
let p = try!(cstr(p));
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
0 => Ok(mkstat(&stat)),
@ -349,7 +349,7 @@ pub fn lstat(p: &Path) -> IoResult<FileStat> {
}
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
let p = cstr(p);
let p = try!(cstr(p));
let buf = libc::utimbuf {
actime: (atime / 1000) as libc::time_t,
modtime: (mtime / 1000) as libc::time_t,