+++ /dev/null
-#!/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('')
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
+ },
})
}
}
}
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 {
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)))
}
}
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()
}
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<()> {
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 {