]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #31655 - ollie27:patch-4, r=steveklabnik
authorSteve Klabnik <steve@steveklabnik.com>
Sun, 14 Feb 2016 23:02:32 +0000 (18:02 -0500)
committerSteve Klabnik <steve@steveklabnik.com>
Sun, 14 Feb 2016 23:02:32 +0000 (18:02 -0500)
r? @steveklabnik

src/doc/book/strings.md
src/etc/regex-match-tests.py [deleted file]
src/libcore/ptr.rs
src/librustc_typeck/check/mod.rs
src/libstd/fs.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/fs.rs
src/test/run-pass/coerce-expect-unsized.rs

index 751619d544a4af57746c31b0acf734bd6dab6adf..68c7235975e8c39a1b68ee4ca43fb1d49def0de0 100644 (file)
@@ -39,7 +39,7 @@ The second, with a `\`, trims the spaces and the newline:
 
 ```rust
 let s = "foo\
-    bar"; 
+    bar";
 
 assert_eq!("foobar", s);
 ```
diff --git a/src/etc/regex-match-tests.py b/src/etc/regex-match-tests.py
deleted file mode 100755 (executable)
index ea7f51c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python2
-
-# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-from __future__ import absolute_import, division, print_function
-import argparse
-import datetime
-import os.path as path
-
-
-def print_tests(tests):
-    print('\n'.join([test_tostr(t) for t in tests]))
-
-
-def read_tests(f):
-    basename, _ = path.splitext(path.basename(f))
-    tests = []
-    for lineno, line in enumerate(open(f), 1):
-        fields = filter(None, map(str.strip, line.split('\t')))
-        if not (4 <= len(fields) <= 5) \
-           or 'E' not in fields[0] or fields[0][0] == '#':
-            continue
-
-        opts, pat, text, sgroups = fields[0:4]
-        groups = []  # groups as integer ranges
-        if sgroups == 'NOMATCH':
-            groups = [None]
-        elif ',' in sgroups:
-            noparen = map(lambda s: s.strip('()'), sgroups.split(')('))
-            for g in noparen:
-                s, e = map(str.strip, g.split(','))
-                if s == '?' and e == '?':
-                    groups.append(None)
-                else:
-                    groups.append((int(s), int(e)))
-        else:
-            # This skips tests that should result in an error.
-            # There aren't many, so I think we can just capture those
-            # manually. Possibly fix this in future.
-            continue
-
-        if pat == 'SAME':
-            pat = tests[-1][1]
-        if '$' in opts:
-            pat = pat.decode('string_escape')
-            text = text.decode('string_escape')
-        if 'i' in opts:
-            pat = '(?i)%s' % pat
-
-        name = '%s_%d' % (basename, lineno)
-        tests.append((name, pat, text, groups))
-    return tests
-
-
-def test_tostr(t):
-    lineno, pat, text, groups = t
-    options = map(group_tostr, groups)
-    return 'mat!{match_%s, r"%s", r"%s", %s}' \
-           % (lineno, pat, '' if text == "NULL" else text, ', '.join(options))
-
-
-def group_tostr(g):
-    if g is None:
-        return 'None'
-    else:
-        return 'Some((%d, %d))' % (g[0], g[1])
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(
-        description='Generate match tests from an AT&T POSIX test file.')
-    aa = parser.add_argument
-    aa('files', nargs='+',
-       help='A list of dat AT&T POSIX test files. See src/libregexp/testdata')
-    args = parser.parse_args()
-
-    tests = []
-    for f in args.files:
-        tests += read_tests(f)
-
-    tpl = '''// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-tidy-linelength
-
-// DO NOT EDIT. Automatically generated by 'src/etc/regexp-match-tests'
-// on {date}.
-'''
-    print(tpl.format(date=str(datetime.datetime.now())))
-
-    for f in args.files:
-        print('// Tests from %s' % path.basename(f))
-        print_tests(read_tests(f))
-        print('')
index a826f2bb4440f9e4d344fa29d2886bab8b01584a..3cbb2f17be78b0343aa63d42c9596343df5e18b5 100644 (file)
@@ -127,8 +127,7 @@ pub unsafe fn read<T>(src: *const T) -> T {
     tmp
 }
 
-/// Variant of read_and_zero that writes the specific drop-flag byte
-/// (which may be more appropriate than zero).
+#[allow(missing_docs)]
 #[inline(always)]
 #[unstable(feature = "filling_drop",
            reason = "may play a larger role in std::ptr future extensions",
index 6a7bc9b61116d8a18b91f0ecb3654ce344c798ce..f890e087573b5ceb3f21563c47550a0932bc1ca0 100644 (file)
@@ -3828,7 +3828,7 @@ impl<'tcx> Expectation<'tcx> {
     /// for examples of where this comes up,.
     fn rvalue_hint(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
         match tcx.struct_tail(ty).sty {
-            ty::TySlice(_) | ty::TyTrait(..) => {
+            ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
                 ExpectRvalueLikeUnsized(ty)
             }
             _ => ExpectHasType(ty)
index d42b948918049ba2291048438e8eb82dad97252a..badbba21d55cc9ddfbf7c55f266a7be4760550ea 100644 (file)
@@ -2151,6 +2151,26 @@ fn symlink_noexist() {
                    "foo");
     }
 
+    #[test]
+    fn read_link() {
+        if cfg!(windows) {
+            // directory symlink
+            assert_eq!(check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
+                       r"C:\ProgramData");
+            // junction
+            assert_eq!(check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
+                       r"C:\Users\Default");
+            // junction with special permissions
+            assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
+                       r"C:\Users");
+        }
+        let tmpdir = tmpdir();
+        let link = tmpdir.join("link");
+        if !got_symlink_permission(&tmpdir) { return };
+        check!(symlink_file(&"foo", &link));
+        assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
+    }
+
     #[test]
     fn readlink_not_symlink() {
         let tmpdir = tmpdir();
index 9fdeb0aef14c8317527531f07ee8b12ee8ecb584..d25d8e0b8048d9ba6f9b7ef03759312d2df8f376 100644 (file)
@@ -240,6 +240,7 @@ fn clone(&self) -> Self { *self }
 pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8;
 pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xa000000c;
 pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003;
+pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001;
 pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
 pub const FSCTL_DELETE_REPARSE_POINT: DWORD = 0x900ac;
 
@@ -533,6 +534,15 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
     pub PathBuffer: WCHAR,
 }
 
+#[repr(C)]
+pub struct MOUNT_POINT_REPARSE_BUFFER {
+    pub SubstituteNameOffset: c_ushort,
+    pub SubstituteNameLength: c_ushort,
+    pub PrintNameOffset: c_ushort,
+    pub PrintNameLength: c_ushort,
+    pub PathBuffer: WCHAR,
+}
+
 pub type LPPROGRESS_ROUTINE = ::option::Option<unsafe extern "system" fn(
     TotalFileSize: LARGE_INTEGER,
     TotalBytesTransferred: LARGE_INTEGER,
index 3062d38f8c259ae4245378151a3b818d0b3b9ccc..d4d95a12f81c42a00be3d76007f6ff2e6990df4e 100644 (file)
@@ -150,7 +150,12 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
                 nFileSizeHigh: self.data.nFileSizeHigh,
                 nFileSizeLow: self.data.nFileSizeLow,
             },
-            reparse_tag: self.data.dwReserved0,
+            reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+                    // reserved unless this is a reparse point
+                    self.data.dwReserved0
+                } else {
+                    0
+                },
         })
     }
 }
@@ -240,15 +245,6 @@ fn get_flags_and_attributes(&self) -> c::DWORD {
 }
 
 impl File {
-    fn open_reparse_point(path: &Path, write: bool) -> io::Result<File> {
-        let mut opts = OpenOptions::new();
-        opts.read(!write);
-        opts.write(write);
-        opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
-                          c::FILE_FLAG_BACKUP_SEMANTICS);
-        File::open(path, &opts)
-    }
-
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
         let path = try!(to_u16s(path));
         let handle = unsafe {
@@ -371,19 +367,34 @@ fn reparse_point<'a>(&self,
     fn readlink(&self) -> io::Result<PathBuf> {
         let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
         let (_bytes, buf) = try!(self.reparse_point(&mut space));
-        if buf.ReparseTag != c::IO_REPARSE_TAG_SYMLINK {
-            return Err(io::Error::new(io::ErrorKind::Other, "not a symlink"))
-        }
-
         unsafe {
-            let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                    &buf.rest as *const _ as *const _;
-            let path_buffer = &(*info).PathBuffer as *const _ as *const u16;
-            let subst_off = (*info).SubstituteNameOffset / 2;
+            let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag {
+                c::IO_REPARSE_TAG_SYMLINK => {
+                    let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
+                        &buf.rest as *const _ as *const _;
+                    (&(*info).PathBuffer as *const _ as *const u16,
+                     (*info).SubstituteNameOffset / 2,
+                     (*info).SubstituteNameLength / 2,
+                     (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0)
+                },
+                c::IO_REPARSE_TAG_MOUNT_POINT => {
+                    let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
+                        &buf.rest as *const _ as *const _;
+                    (&(*info).PathBuffer as *const _ as *const u16,
+                     (*info).SubstituteNameOffset / 2,
+                     (*info).SubstituteNameLength / 2,
+                     false)
+                },
+                _ => return Err(io::Error::new(io::ErrorKind::Other,
+                                               "Unsupported reparse point type"))
+            };
             let subst_ptr = path_buffer.offset(subst_off as isize);
-            let subst_len = (*info).SubstituteNameLength / 2;
-            let subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
-
+            let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
+            // Absolute paths start with an NT internal namespace prefix `\??\`
+            // We should not let it leak through.
+            if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) {
+                subst = &subst[4..];
+            }
             Ok(PathBuf::from(OsString::from_wide(subst)))
         }
     }
@@ -577,8 +588,15 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
     rmdir(path)
 }
 
-pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let file = try!(File::open_reparse_point(p, false));
+pub fn readlink(path: &Path) -> io::Result<PathBuf> {
+    // Open the link with no access mode, instead of generic read.
+    // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
+    // this is needed for a common case.
+    let mut opts = OpenOptions::new();
+    opts.access_mode(0);
+    opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+                      c::FILE_FLAG_BACKUP_SEMANTICS);
+    let file = try!(File::open(&path, &opts));
     file.readlink()
 }
 
@@ -605,42 +623,23 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     Ok(())
 }
 
-pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let attr = try!(lstat(p));
-
-    // If this is a reparse point, then we need to reopen the file to get the
-    // actual destination. We also pass the FILE_FLAG_BACKUP_SEMANTICS flag to
-    // ensure that we can open directories (this path may be a directory
-    // junction). Once the file is opened we ask the opened handle what its
-    // metadata information is.
-    if attr.is_reparse_point() {
-        let mut opts = OpenOptions::new();
-        // No read or write permissions are necessary
-        opts.access_mode(0);
-        // This flag is so we can open directories too
-        opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
-        let file = try!(File::open(p, &opts));
-        file.file_attr()
-    } else {
-        Ok(attr)
-    }
+pub fn stat(path: &Path) -> io::Result<FileAttr> {
+    let mut opts = OpenOptions::new();
+    // No read or write permissions are necessary
+    opts.access_mode(0);
+    // This flag is so we can open directories too
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
+    let file = try!(File::open(path, &opts));
+    file.file_attr()
 }
 
-pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let u16s = try!(to_u16s(p));
-    unsafe {
-        let mut attr: FileAttr = mem::zeroed();
-        try!(cvt(c::GetFileAttributesExW(u16s.as_ptr(),
-                                         c::GetFileExInfoStandard,
-                                         &mut attr.data as *mut _ as *mut _)));
-        if attr.is_reparse_point() {
-            attr.reparse_tag = File::open_reparse_point(p, false).and_then(|f| {
-                let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-                f.reparse_point(&mut b).map(|(_, b)| b.ReparseTag)
-            }).unwrap_or(0);
-        }
-        Ok(attr)
-    }
+pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+    let mut opts = OpenOptions::new();
+    // No read or write permissions are necessary
+    opts.access_mode(0);
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
+    let file = try!(File::open(path, &opts));
+    file.file_attr()
 }
 
 pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
@@ -709,7 +708,12 @@ pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::R
 fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
     let d = DirBuilder::new();
     try!(d.mkdir(&junction));
-    let f = try!(File::open_reparse_point(junction, true));
+
+    let mut opts = OpenOptions::new();
+    opts.write(true);
+    opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+                      c::FILE_FLAG_BACKUP_SEMANTICS);
+    let f = try!(File::open(junction, &opts));
     let h = f.handle().raw();
 
     unsafe {
index ee4ec24b7e3dad97370ca4831ad9d57806656861..f846ee8f3d0b924035886db8f93ecda1c4464404 100644 (file)
@@ -44,6 +44,13 @@ pub fn main() {
     let _: &Debug = &if true { false } else { true };
     let _: &Debug = &match true { true => 'a', false => 'b' };
 
+    let _: &str = &{ String::new() };
+    let _: &str = &if true { String::from("...") } else { 5.to_string() };
+    let _: &str = &match true {
+        true => format!("{}", false),
+        false => ["x", "y"].join("+")
+    };
+
     let _: Box<[isize]> = Box::new([1, 2, 3]);
     let _: Box<Fn(isize) -> _> = Box::new(|x| (x as u8));