diff options
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | openat/.gitignore | 4 | ||||
| -rw-r--r-- | openat/.travis.yml | 35 | ||||
| -rw-r--r-- | openat/Cargo.toml | 22 | ||||
| -rw-r--r-- | openat/LICENSE-APACHE | 202 | ||||
| -rw-r--r-- | openat/LICENSE-MIT | 19 | ||||
| -rw-r--r-- | openat/README.md | 36 | ||||
| -rw-r--r-- | openat/benches/count_processes.rs | 39 | ||||
| -rw-r--r-- | openat/bulk.yaml | 8 | ||||
| -rw-r--r-- | openat/examples/exchange.rs | 39 | ||||
| -rw-r--r-- | openat/src/dir.rs | 696 | ||||
| -rw-r--r-- | openat/src/filetype.rs | 33 | ||||
| -rw-r--r-- | openat/src/lib.rs | 95 | ||||
| -rw-r--r-- | openat/src/list.rs | 153 | ||||
| -rw-r--r-- | openat/src/metadata.rs | 75 | ||||
| -rw-r--r-- | openat/src/name.rs | 76 | ||||
| -rw-r--r-- | openat/tests/tmpfile.rs | 24 | ||||
| -rw-r--r-- | openat/vagga.yaml | 91 | ||||
| -rw-r--r-- | src/lib.rs | 26 | 
19 files changed, 15 insertions, 1660 deletions
| @@ -8,7 +8,7 @@ name = "pam_usercg"  crate-type = ["cdylib"]  [dependencies] +cap-std = "1.0.4"  libc = "0.2.139" -openat = { path = "openat" }  pam-bindings = "0.1.1"  users = "0.11.0" diff --git a/openat/.gitignore b/openat/.gitignore deleted file mode 100644 index afef0a7..0000000 --- a/openat/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/.vagga -Cargo.lock -/target -/tmp diff --git a/openat/.travis.yml b/openat/.travis.yml deleted file mode 100644 index 503b688..0000000 --- a/openat/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -sudo: false -dist: trusty -language: rust - -cache: -- cargo - -before_cache: -- rm -r $TRAVIS_BUILD_DIR/target/debug - -jobs: -  include: -  - os: linux -    rust: stable -  - os: linux -    rust: beta -  - os: linux -    rust: nightly -  - os: macos -    osx_image: xcode9.3 -    rust: stable - -  # deploy -  - stage: publish -    os: linux -    rust: stable -    env: -    install: true -    script: true - -    deploy: -    - provider: script -      script: 'cargo publish --verbose --token=$CARGO_TOKEN' -      on: -        tags: true diff --git a/openat/Cargo.toml b/openat/Cargo.toml deleted file mode 100644 index a5b5b3f..0000000 --- a/openat/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "openat" -description = """ -    A wrapper around openat, symlinkat, and similar system calls -""" -license = "MIT/Apache-2.0" -readme = "README.md" -keywords = ["open", "openat", "filesystem", "fs"] -categories = ["filesystem", "api-bindings"] -repository = "https://github.com/tailhook/openat" -homepage = "https://github.com/tailhook/openat" -documentation = "http://docs.rs/openat" -version = "0.1.21" -authors = ["paul@colomiets.name"] -edition = "2018" - -[dependencies] -libc = "0.2.34" - -[dev-dependencies] -argparse = "0.2.1" -tempfile = "3.0.3" diff --git a/openat/LICENSE-APACHE b/openat/LICENSE-APACHE deleted file mode 100644 index 8f71f43..0000000 --- a/openat/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ -                                 Apache License -                           Version 2.0, January 2004 -                        http://www.apache.org/licenses/ - -   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -   1. Definitions. - -      "License" shall mean the terms and conditions for use, reproduction, -      and distribution as defined by Sections 1 through 9 of this document. - -      "Licensor" shall mean the copyright owner or entity authorized by -      the copyright owner that is granting the License. - -      "Legal Entity" shall mean the union of the acting entity and all -      other entities that control, are controlled by, or are under common -      control with that entity. For the purposes of this definition, -      "control" means (i) the power, direct or indirect, to cause the -      direction or management of such entity, whether by contract or -      otherwise, or (ii) ownership of fifty percent (50%) or more of the -      outstanding shares, or (iii) beneficial ownership of such entity. - -      "You" (or "Your") shall mean an individual or Legal Entity -      exercising permissions granted by this License. - -      "Source" form shall mean the preferred form for making modifications, -      including but not limited to software source code, documentation -      source, and configuration files. - -      "Object" form shall mean any form resulting from mechanical -      transformation or translation of a Source form, including but -      not limited to compiled object code, generated documentation, -      and conversions to other media types. - -      "Work" shall mean the work of authorship, whether in Source or -      Object form, made available under the License, as indicated by a -      copyright notice that is included in or attached to the work -      (an example is provided in the Appendix below). - -      "Derivative Works" shall mean any work, whether in Source or Object -      form, that is based on (or derived from) the Work and for which the -      editorial revisions, annotations, elaborations, or other modifications -      represent, as a whole, an original work of authorship. For the purposes -      of this License, Derivative Works shall not include works that remain -      separable from, or merely link (or bind by name) to the interfaces of, -      the Work and Derivative Works thereof. - -      "Contribution" shall mean any work of authorship, including -      the original version of the Work and any modifications or additions -      to that Work or Derivative Works thereof, that is intentionally -      submitted to Licensor for inclusion in the Work by the copyright owner -      or by an individual or Legal Entity authorized to submit on behalf of -      the copyright owner. For the purposes of this definition, "submitted" -      means any form of electronic, verbal, or written communication sent -      to the Licensor or its representatives, including but not limited to -      communication on electronic mailing lists, source code control systems, -      and issue tracking systems that are managed by, or on behalf of, the -      Licensor for the purpose of discussing and improving the Work, but -      excluding communication that is conspicuously marked or otherwise -      designated in writing by the copyright owner as "Not a Contribution." - -      "Contributor" shall mean Licensor and any individual or Legal Entity -      on behalf of whom a Contribution has been received by Licensor and -      subsequently incorporated within the Work. - -   2. Grant of Copyright License. Subject to the terms and conditions of -      this License, each Contributor hereby grants to You a perpetual, -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable -      copyright license to reproduce, prepare Derivative Works of, -      publicly display, publicly perform, sublicense, and distribute the -      Work and such Derivative Works in Source or Object form. - -   3. Grant of Patent License. Subject to the terms and conditions of -      this License, each Contributor hereby grants to You a perpetual, -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable -      (except as stated in this section) patent license to make, have made, -      use, offer to sell, sell, import, and otherwise transfer the Work, -      where such license applies only to those patent claims licensable -      by such Contributor that are necessarily infringed by their -      Contribution(s) alone or by combination of their Contribution(s) -      with the Work to which such Contribution(s) was submitted. If You -      institute patent litigation against any entity (including a -      cross-claim or counterclaim in a lawsuit) alleging that the Work -      or a Contribution incorporated within the Work constitutes direct -      or contributory patent infringement, then any patent licenses -      granted to You under this License for that Work shall terminate -      as of the date such litigation is filed. - -   4. Redistribution. You may reproduce and distribute copies of the -      Work or Derivative Works thereof in any medium, with or without -      modifications, and in Source or Object form, provided that You -      meet the following conditions: - -      (a) You must give any other recipients of the Work or -          Derivative Works a copy of this License; and - -      (b) You must cause any modified files to carry prominent notices -          stating that You changed the files; and - -      (c) You must retain, in the Source form of any Derivative Works -          that You distribute, all copyright, patent, trademark, and -          attribution notices from the Source form of the Work, -          excluding those notices that do not pertain to any part of -          the Derivative Works; and - -      (d) If the Work includes a "NOTICE" text file as part of its -          distribution, then any Derivative Works that You distribute must -          include a readable copy of the attribution notices contained -          within such NOTICE file, excluding those notices that do not -          pertain to any part of the Derivative Works, in at least one -          of the following places: within a NOTICE text file distributed -          as part of the Derivative Works; within the Source form or -          documentation, if provided along with the Derivative Works; or, -          within a display generated by the Derivative Works, if and -          wherever such third-party notices normally appear. The contents -          of the NOTICE file are for informational purposes only and -          do not modify the License. You may add Your own attribution -          notices within Derivative Works that You distribute, alongside -          or as an addendum to the NOTICE text from the Work, provided -          that such additional attribution notices cannot be construed -          as modifying the License. - -      You may add Your own copyright statement to Your modifications and -      may provide additional or different license terms and conditions -      for use, reproduction, or distribution of Your modifications, or -      for any such Derivative Works as a whole, provided Your use, -      reproduction, and distribution of the Work otherwise complies with -      the conditions stated in this License. - -   5. Submission of Contributions. Unless You explicitly state otherwise, -      any Contribution intentionally submitted for inclusion in the Work -      by You to the Licensor shall be under the terms and conditions of -      this License, without any additional terms or conditions. -      Notwithstanding the above, nothing herein shall supersede or modify -      the terms of any separate license agreement you may have executed -      with Licensor regarding such Contributions. - -   6. Trademarks. This License does not grant permission to use the trade -      names, trademarks, service marks, or product names of the Licensor, -      except as required for reasonable and customary use in describing the -      origin of the Work and reproducing the content of the NOTICE file. - -   7. Disclaimer of Warranty. Unless required by applicable law or -      agreed to in writing, Licensor provides the Work (and each -      Contributor provides its Contributions) on an "AS IS" BASIS, -      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -      implied, including, without limitation, any warranties or conditions -      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -      PARTICULAR PURPOSE. You are solely responsible for determining the -      appropriateness of using or redistributing the Work and assume any -      risks associated with Your exercise of permissions under this License. - -   8. Limitation of Liability. In no event and under no legal theory, -      whether in tort (including negligence), contract, or otherwise, -      unless required by applicable law (such as deliberate and grossly -      negligent acts) or agreed to in writing, shall any Contributor be -      liable to You for damages, including any direct, indirect, special, -      incidental, or consequential damages of any character arising as a -      result of this License or out of the use or inability to use the -      Work (including but not limited to damages for loss of goodwill, -      work stoppage, computer failure or malfunction, or any and all -      other commercial damages or losses), even if such Contributor -      has been advised of the possibility of such damages. - -   9. Accepting Warranty or Additional Liability. While redistributing -      the Work or Derivative Works thereof, You may choose to offer, -      and charge a fee for, acceptance of support, warranty, indemnity, -      or other liability obligations and/or rights consistent with this -      License. However, in accepting such obligations, You may act only -      on Your own behalf and on Your sole responsibility, not on behalf -      of any other Contributor, and only if You agree to indemnify, -      defend, and hold each Contributor harmless for any liability -      incurred by, or claims asserted against, such Contributor by reason -      of your accepting any such warranty or additional liability. - -   END OF TERMS AND CONDITIONS - -   APPENDIX: How to apply the Apache License to your work. - -      To apply the Apache License to your work, attach the following -      boilerplate notice, with the fields enclosed by brackets "{}" -      replaced with your own identifying information. (Don't include -      the brackets!)  The text should be enclosed in the appropriate -      comment syntax for the file format. We also recommend that a -      file or class name and description of purpose be included on the -      same "printed page" as the copyright notice for easier -      identification within third-party archives. - -   Copyright {yyyy} {name of copyright owner} - -   Licensed under the Apache License, Version 2.0 (the "License"); -   you may not use this file except in compliance with the License. -   You may obtain a copy of the License at - -       http://www.apache.org/licenses/LICENSE-2.0 - -   Unless required by applicable law or agreed to in writing, software -   distributed under the License is distributed on an "AS IS" BASIS, -   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -   See the License for the specific language governing permissions and -   limitations under the License. - diff --git a/openat/LICENSE-MIT b/openat/LICENSE-MIT deleted file mode 100644 index dbd7f65..0000000 --- a/openat/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016 The openat Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/openat/README.md b/openat/README.md deleted file mode 100644 index bf82045..0000000 --- a/openat/README.md +++ /dev/null @@ -1,36 +0,0 @@ -Openat Crate -============ - -**Status: Beta** - -[Documentation](https://docs.rs/openat) | -[Github](https://github.com/tailhook/openat) | -[Crate](https://crates.io/crates/openat) - - -The interface to ``openat``, ``symlinkat``, and other functions in ``*at`` -family. - -Dependent crates -================ - -This crate is a thin wrapper for the underlying system calls. -You may find the extension methods in [openat-ext](https://crates.io/crates/openat-ext) useful. - -License -======= - -Licensed under either of - -* Apache License, Version 2.0, -  (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) -* MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT) -  at your option. - -Contribution ------------- - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/openat/benches/count_processes.rs b/openat/benches/count_processes.rs deleted file mode 100644 index aa9f856..0000000 --- a/openat/benches/count_processes.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![feature(test)] - -extern crate openat; -extern crate test; - - -use std::fs::read_dir; -use std::str::from_utf8; -use std::os::unix::ffi::OsStrExt; -use test::Bencher; - -use openat::Dir; - - -#[bench] -fn procs_stdlib(b: &mut Bencher) { -    b.iter(|| { -        read_dir("/proc").unwrap().filter(|r| { -            r.as_ref().ok() -            .and_then(|e| from_utf8(e.file_name().as_bytes()).ok() -            // pid is everything that can be parsed as a number -                .and_then(|s| s.parse::<u32>().ok())) -            .is_some() -        }).count() -    }); -} - -#[bench] -fn procs_openat(b: &mut Bencher) { -    b.iter(|| { -        Dir::open("/proc").unwrap().list_dir(".").unwrap().filter(|r| { -            r.as_ref().ok() -            .and_then(|e| from_utf8(e.file_name().as_bytes()).ok() -            // pid is everything that can be parsed as a number -                .and_then(|s| s.parse::<u32>().ok())) -            .is_some() -        }).count() -    }); -} diff --git a/openat/bulk.yaml b/openat/bulk.yaml deleted file mode 100644 index cdb9763..0000000 --- a/openat/bulk.yaml +++ /dev/null @@ -1,8 +0,0 @@ -minimum-bulk: v0.4.5 - -versions: - -- file: Cargo.toml -  block-start: ^\[package\] -  block-end: ^\[.*\] -  regex: ^version\s*=\s*"(\S+)" diff --git a/openat/examples/exchange.rs b/openat/examples/exchange.rs deleted file mode 100644 index 21fdf0a..0000000 --- a/openat/examples/exchange.rs +++ /dev/null @@ -1,39 +0,0 @@ -extern crate argparse; -extern crate openat; - -use std::process::exit; -use std::path::PathBuf; - -use argparse::{ArgumentParser, Parse}; -use openat::Dir; - -#[cfg(not(target_os="linux"))] -fn main() { -    println!("Atomic exchange is not supported on this platform") -} - -#[cfg(target_os="linux")] -fn main() { -    let mut path1 = PathBuf::new(); -    let mut path2 = PathBuf::new(); -    { -        let mut ap = ArgumentParser::new(); -        ap.refer(&mut path1) -            .add_argument("path1", Parse, "First path of exchange operation") -            .required(); -        ap.refer(&mut path2) -            .add_argument("path2", Parse, "Second path of exchange operation") -            .required(); -        ap.parse_args_or_exit(); -    } -    if path1.parent() != path2.parent() { -        println!("Paths must be in the same directory"); -        exit(1); -    } -    let parent = path1.parent().expect("path must have parent directory"); -    let dir = Dir::open(parent).expect("can open directory"); -    dir.local_exchange( -        path1.file_name().expect("path1 must have filename"), -        path2.file_name().expect("path2 must have filename"), -    ).expect("can rename"); -} diff --git a/openat/src/dir.rs b/openat/src/dir.rs deleted file mode 100644 index eac2f38..0000000 --- a/openat/src/dir.rs +++ /dev/null @@ -1,696 +0,0 @@ -use std::io; -use std::mem; -use std::ffi::{OsString, CStr}; -use std::fs::{File, read_link}; -use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, IntoRawFd}; -use std::os::unix::ffi::{OsStringExt}; -use std::path::{PathBuf}; - -use libc; -use crate::metadata::{self, Metadata}; -use crate::list::{DirIter, open_dir, open_dirfd}; - -use crate::{Dir, AsPath}; - -#[cfg(target_os="linux")] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_PATH|libc::O_CLOEXEC; -#[cfg(target_os="freebsd")] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_DIRECTORY|libc::O_CLOEXEC; -#[cfg(not(any(target_os="linux", target_os="freebsd")))] -const BASE_OPEN_FLAGS: libc::c_int = libc::O_CLOEXEC; - -impl Dir { -    /// Creates a directory descriptor that resolves paths relative to current -    /// working directory (AT_FDCWD) -    #[deprecated(since="0.1.15", note="\ -        Use `Dir::open(\".\")` instead. \ -        Dir::cwd() doesn't open actual file descriptor and uses magic value \ -        instead which resolves to current dir on any syscall invocation. \ -        This is usually counter-intuitive and yields a broken \ -        file descriptor when using `Dir::as_raw_fd`. \ -        Will be removed in version v0.2 of the library.")] -    pub fn cwd() -> Dir { -        Dir(libc::AT_FDCWD) -    } - -    /// Open a directory descriptor at specified path -    // TODO(tailhook) maybe accept only absolute paths? -    pub fn open<P: AsPath>(path: P) -> io::Result<Dir> { -        Dir::_open(to_cstr(path)?.as_ref()) -    } - -    fn _open(path: &CStr) -> io::Result<Dir> { -        let fd = unsafe { -            libc::open(path.as_ptr(), BASE_OPEN_FLAGS) -        }; -        if fd < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(Dir(fd)) -        } -    } - -    /// List subdirectory of this dir -    /// -    /// You can list directory itself with `list_self`. -    pub fn list_dir<P: AsPath>(&self, path: P) -> io::Result<DirIter> { -        open_dir(self, to_cstr(path)?.as_ref()) -    } - -    /// List this dir -    pub fn list_self(&self) -> io::Result<DirIter> { -        unsafe { -            open_dirfd(libc::dup(self.0)) -        } -    } - -    /// Open subdirectory -    /// -    /// Note that this method does not resolve symlinks by default, so you may have to call -    /// [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn sub_dir<P: AsPath>(&self, path: P) -> io::Result<Dir> { -        self._sub_dir(to_cstr(path)?.as_ref()) -    } - -    fn _sub_dir(&self, path: &CStr) -> io::Result<Dir> { -        let fd = unsafe { -            libc::openat(self.0, -                        path.as_ptr(), -                        BASE_OPEN_FLAGS|libc::O_NOFOLLOW) -        }; -        if fd < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(Dir(fd)) -        } -    } - -    /// Read link in this directory -    pub fn read_link<P: AsPath>(&self, path: P) -> io::Result<PathBuf> { -        self._read_link(to_cstr(path)?.as_ref()) -    } - -    fn _read_link(&self, path: &CStr) -> io::Result<PathBuf> { -        let mut buf = vec![0u8; 4096]; -        let res = unsafe { -            libc::readlinkat(self.0, -                        path.as_ptr(), -                        buf.as_mut_ptr() as *mut libc::c_char, buf.len()) -        }; -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            buf.truncate(res as usize); -            Ok(OsString::from_vec(buf).into()) -        } -    } - -    /// Open file for reading in this directory -    /// -    /// Note that this method does not resolve symlinks by default, so you may have to call -    /// [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn open_file<P: AsPath>(&self, path: P) -> io::Result<File> { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_RDONLY, 0) -    } - -    /// Open file with specified flags relative to this directory -    pub fn open_file_ex<P: AsPath>(&self, path: P, flags: libc::c_int, mode: libc::mode_t) -> io::Result<File> { -        self._open_file(to_cstr(path)?.as_ref(), flags, mode) -    } - -    /// Open file for writing, create if necessary, truncate on open -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to remove the symlink before calling this method. If you are on Linux, you can -    /// alternatively create an unnamed file with [`new_unnamed_file`] and then rename it, -    /// clobbering the symlink at the destination. -    /// -    /// [`new_unnamed_file`]: #method.new_unnamed_file -    pub fn write_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_TRUNC, -            mode) -    } - -    /// Open file for append, create if necessary -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn append_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_APPEND, -            mode) -    } - -    /// Create file for writing (and truncate) in this directory -    /// -    /// Deprecated alias for `write_file` -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to remove the symlink before calling this method. If you are on Linux, you can -    /// alternatively create an unnamed file with [`new_unnamed_file`] and then rename it, -    /// clobbering the symlink at the destination. -    /// -    /// [`new_unnamed_file`]: #method.new_unnamed_file -    #[deprecated(since="0.1.7", note="please use `write_file` instead")] -    pub fn create_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_WRONLY|libc::O_TRUNC, -            mode) -    } - -    /// Create a tmpfile in this directory which isn't linked to any filename -    /// -    /// This works by passing `O_TMPFILE` into the openat call. The flag is -    /// supported only on linux. So this function always returns error on -    /// such systems. -    /// -    /// **WARNING!** On glibc < 2.22 file permissions of the newly created file -    /// may be arbitrary. Consider chowning after creating a file. -    /// -    /// Note: It may be unclear why creating unnamed file requires a dir. There -    /// are two reasons: -    /// -    /// 1. It's created (and occupies space) on a real filesystem, so the -    ///    directory is a way to find out which filesystem to attach file to -    /// 2. This method is mostly needed to initialize the file then link it -    ///    using ``link_file_at`` to the real directory entry. When linking -    ///    it must be linked into the same filesystem. But because for most -    ///    programs finding out filesystem layout is an overkill the rule of -    ///    thumb is to create a file in the the target directory. -    /// -    /// Currently, we recommend to fallback on any error if this operation -    /// can't be accomplished rather than relying on specific error codes, -    /// because semantics of errors are very ugly. -    #[cfg(target_os="linux")] -    pub fn new_unnamed_file(&self, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(unsafe { CStr::from_bytes_with_nul_unchecked(b".\0") }, -            libc::O_TMPFILE|libc::O_WRONLY, -            mode) -    } - -    /// Create a tmpfile in this directory which isn't linked to any filename -    /// -    /// This works by passing `O_TMPFILE` into the openat call. The flag is -    /// supported only on linux. So this function always returns error on -    /// such systems. -    /// -    /// Note: It may be unclear why creating unnamed file requires a dir. There -    /// are two reasons: -    /// -    /// 1. It's created (and occupies space) on a real filesystem, so the -    ///    directory is a way to find out which filesystem to attach file to -    /// 2. This method is mostly needed to initialize the file then link it -    ///    using ``link_file_at`` to the real directory entry. When linking -    ///    it must be linked into the same filesystem. But because for most -    ///    programs finding out filesystem layout is an overkill the rule of -    ///    thumb is to create a file in the the target directory. -    /// -    /// Currently, we recommend to fallback on any error if this operation -    /// can't be accomplished rather than relying on specific error codes, -    /// because semantics of errors are very ugly. -    #[cfg(not(target_os="linux"))] -    pub fn new_unnamed_file<P: AsPath>(&self, _mode: libc::mode_t) -        -> io::Result<File> -    { -        Err(io::Error::new(io::ErrorKind::Other, -            "creating unnamed tmpfiles is only supported on linux")) -    } - -    /// Link open file to a specified path -    /// -    /// This is used with ``new_unnamed_file()`` to create and initialize the -    /// file before linking it into a filesystem. This requires `/proc` to be -    /// mounted and works **only on linux**. -    /// -    /// On systems other than linux this always returns error. It's expected -    /// that in most cases this methos is not called if ``new_unnamed_file`` -    /// fails. But in obscure scenarios where `/proc` is not mounted this -    /// method may fail even on linux. So your code should be able to fallback -    /// to a named file if this method fails too. -    #[cfg(target_os="linux")] -    pub fn link_file_at<F: AsRawFd, P: AsPath>(&self, file: &F, path: P) -        -> io::Result<()> -    { -        let fd_path = format!("/proc/self/fd/{}", file.as_raw_fd()); -        _hardlink(&Dir(libc::AT_FDCWD), to_cstr(fd_path)?.as_ref(), -            &self, to_cstr(path)?.as_ref(), -            libc::AT_SYMLINK_FOLLOW) -    } - -    /// Link open file to a specified path -    /// -    /// This is used with ``new_unnamed_file()`` to create and initialize the -    /// file before linking it into a filesystem. This requires `/proc` to be -    /// mounted and works **only on linux**. -    /// -    /// On systems other than linux this always returns error. It's expected -    /// that in most cases this methos is not called if ``new_unnamed_file`` -    /// fails. But in obscure scenarios where `/proc` is not mounted this -    /// method may fail even on linux. So your code should be able to fallback -    /// to a named file if this method fails too. -    #[cfg(not(target_os="linux"))] -    pub fn link_file_at<F: AsRawFd, P: AsPath>(&self, _file: F, _path: P) -        -> io::Result<()> -    { -        Err(io::Error::new(io::ErrorKind::Other, -            "linking unnamed fd to directories is only supported on linux")) -    } - -    /// Create file if not exists, fail if exists -    /// -    /// This function checks existence and creates file atomically with -    /// respect to other threads and processes. -    /// -    /// Technically it means passing `O_EXCL` flag to open. -    pub fn new_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_EXCL|libc::O_WRONLY, -            mode) -    } - -    /// Open file for reading and writing without truncation, create if needed -    /// -    /// If there exists a symlink at the destination path, this method will fail. In that case, you -    /// will need to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn update_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<File> -    { -        self._open_file(to_cstr(path)?.as_ref(), -            libc::O_CREAT|libc::O_RDWR, -            mode) -    } - -    fn _open_file(&self, path: &CStr, flags: libc::c_int, mode: libc::mode_t) -        -> io::Result<File> -    { -        unsafe { -            // Note: In below call to `openat`, *mode* must be cast to -            // `unsigned` because the optional `mode` argument to `openat` is -            // variadic in the signature. Since integers are not implicitly -            // promoted as they are in C this would break on Freebsd where -            // *mode_t* is an alias for `uint16_t`. -            let res = libc::openat(self.0, path.as_ptr(), -                            flags|libc::O_CLOEXEC|libc::O_NOFOLLOW, -                            mode as libc::c_uint); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(File::from_raw_fd(res)) -            } -        } -    } - -    /// Make a symlink in this directory -    /// -    /// Note: the order of arguments differ from `symlinkat` -    pub fn symlink<P: AsPath, R: AsPath>(&self, path: P, value: R) -        -> io::Result<()> -    { -        self._symlink(to_cstr(path)?.as_ref(), to_cstr(value)?.as_ref()) -    } -    fn _symlink(&self, path: &CStr, link: &CStr) -> io::Result<()> { -        unsafe { -            let res = libc::symlinkat(link.as_ptr(), -                self.0, path.as_ptr()); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Create a subdirectory in this directory -    pub fn create_dir<P: AsPath>(&self, path: P, mode: libc::mode_t) -        -> io::Result<()> -    { -        self._create_dir(to_cstr(path)?.as_ref(), mode) -    } -    fn _create_dir(&self, path: &CStr, mode: libc::mode_t) -> io::Result<()> { -        unsafe { -            let res = libc::mkdirat(self.0, path.as_ptr(), mode); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Rename a file in this directory to another name (keeping same dir) -    pub fn local_rename<P: AsPath, R: AsPath>(&self, old: P, new: R) -        -> io::Result<()> -    { -        rename(self, to_cstr(old)?.as_ref(), self, to_cstr(new)?.as_ref()) -    } - -    /// Similar to `local_rename` but atomically swaps both paths -    /// -    /// Only supported on Linux. -    #[cfg(target_os="linux")] -    pub fn local_exchange<P: AsPath, R: AsPath>(&self, old: P, new: R) -        -> io::Result<()> -    { -        // Workaround https://github.com/tailhook/openat/issues/35 -        // AKA https://github.com/rust-lang/libc/pull/2116 -        // Unfortunately since we made this libc::c_int in our -        // public API, we can't easily change it right now. -        let flags = libc::RENAME_EXCHANGE as libc::c_int; -        rename_flags(self, to_cstr(old)?.as_ref(), -            self, to_cstr(new)?.as_ref(), -            flags) -    } - -    /// Remove a subdirectory in this directory -    /// -    /// Note only empty directory may be removed -    pub fn remove_dir<P: AsPath>(&self, path: P) -        -> io::Result<()> -    { -        self._unlink(to_cstr(path)?.as_ref(), libc::AT_REMOVEDIR) -    } -    /// Remove a file in this directory -    pub fn remove_file<P: AsPath>(&self, path: P) -        -> io::Result<()> -    { -        self._unlink(to_cstr(path)?.as_ref(), 0) -    } -    fn _unlink(&self, path: &CStr, flags: libc::c_int) -> io::Result<()> { -        unsafe { -            let res = libc::unlinkat(self.0, path.as_ptr(), flags); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(()) -            } -        } -    } - -    /// Get the path of this directory (if possible) -    /// -    /// This uses symlinks in `/proc/self`, they sometimes may not be -    /// available so use with care. -    pub fn recover_path(&self) -> io::Result<PathBuf> { -        let fd = self.0; -        if fd != libc::AT_FDCWD { -            read_link(format!("/proc/self/fd/{}", fd)) -        } else { -            read_link("/proc/self/cwd") -        } -    } - -    /// Returns metadata of an entry in this directory -    /// -    /// If the destination path is a symlink, this will return the metadata of the symlink itself. -    /// If you would like to follow the symlink and return the metadata of the target, you will -    /// have to call [`read_link`] to resolve the real path first. -    /// -    /// [`read_link`]: #method.read_link -    pub fn metadata<P: AsPath>(&self, path: P) -> io::Result<Metadata> { -        self._stat(to_cstr(path)?.as_ref(), libc::AT_SYMLINK_NOFOLLOW) -    } -    fn _stat(&self, path: &CStr, flags: libc::c_int) -> io::Result<Metadata> { -        unsafe { -            let mut stat = mem::zeroed(); -            let res = libc::fstatat(self.0, path.as_ptr(), -                &mut stat, flags); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(metadata::new(stat)) -            } -        } -    } - -    /// Returns the metadata of the directory itself. -    pub fn self_metadata(&self) -> io::Result<Metadata> { -        unsafe { -            let mut stat = mem::zeroed(); -            let res = libc::fstat(self.0, &mut stat); -            if res < 0 { -                Err(io::Error::last_os_error()) -            } else { -                Ok(metadata::new(stat)) -            } -        } -    } - -    /// Constructs a new `Dir` from a given raw file descriptor, -    /// ensuring it is a directory file descriptor first. -    /// -    /// This function **consumes ownership** of the specified file -    /// descriptor. The returned `Dir` will take responsibility for -    /// closing it when it goes out of scope. -    pub unsafe fn from_raw_fd_checked(fd: RawFd) -> io::Result<Self> { -        let mut stat = mem::zeroed(); -        let res = libc::fstat(fd, &mut stat); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            match stat.st_mode & libc::S_IFMT { -                libc::S_IFDIR => Ok(Dir(fd)), -                _ => Err(io::Error::from_raw_os_error(libc::ENOTDIR)) -            } -        } -    } - -    /// Creates a new independently owned handle to the underlying directory. -    pub fn try_clone(&self) -> io::Result<Self> { -        let fd = unsafe { libc::dup(self.0) }; -        if fd == -1 { -            Err(io::Error::last_os_error()) -        } else { -            unsafe { Self::from_raw_fd_checked(fd) } -        } -    } -} - -/// Rename (move) a file between directories -/// -/// Files must be on a single filesystem anyway. This funtion does **not** -/// fallback to copying if needed. -pub fn rename<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _rename(old_dir, to_cstr(old)?.as_ref(), new_dir, to_cstr(new)?.as_ref()) -} - -fn _rename(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::renameat(old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr()); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -/// Create a hardlink to a file -/// -/// Files must be on a single filesystem even if they are in different -/// directories. -/// -/// Note: by default ``linkat`` syscall doesn't resolve symbolic links, and -/// it's also behavior of this function. It's recommended to resolve symlinks -/// manually if needed. -pub fn hardlink<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _hardlink(old_dir, to_cstr(old)?.as_ref(), -              new_dir, to_cstr(new)?.as_ref(), -              0) -} - -fn _hardlink(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr, -             flags: libc::c_int) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::linkat(old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr(), flags); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -/// Rename (move) a file between directories with flags -/// -/// Files must be on a single filesystem anyway. This funtion does **not** -/// fallback to copying if needed. -/// -/// Only supported on Linux. -#[cfg(target_os="linux")] -pub fn rename_flags<P, R>(old_dir: &Dir, old: P, new_dir: &Dir, new: R, -    flags: libc::c_int) -    -> io::Result<()> -    where P: AsPath, R: AsPath, -{ -    _rename_flags(old_dir, to_cstr(old)?.as_ref(), -        new_dir, to_cstr(new)?.as_ref(), -        flags) -} - -#[cfg(target_os="linux")] -fn _rename_flags(old_dir: &Dir, old: &CStr, new_dir: &Dir, new: &CStr, -    flags: libc::c_int) -    -> io::Result<()> -{ -    unsafe { -        let res = libc::syscall( -            libc::SYS_renameat2, -            old_dir.0, old.as_ptr(), -            new_dir.0, new.as_ptr(), flags); -        if res < 0 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(()) -        } -    } -} - -impl AsRawFd for Dir { -    #[inline] -    fn as_raw_fd(&self) -> RawFd { -        self.0 -    } -} - -impl FromRawFd for Dir { -    /// The user must guarantee that the passed in `RawFd` is in fact -    /// a directory file descriptor. -    #[inline] -    unsafe fn from_raw_fd(fd: RawFd) -> Dir { -        Dir(fd) -    } -} - -impl IntoRawFd for Dir { -    #[inline] -    fn into_raw_fd(self) -> RawFd { -        let result = self.0; -        mem::forget(self); -        return result; -    } -} - -impl Drop for Dir { -    fn drop(&mut self) { -        let fd = self.0; -        if fd != libc::AT_FDCWD { -            unsafe { -                libc::close(fd); -            } -        } -    } -} - -fn to_cstr<P: AsPath>(path: P) -> io::Result<P::Buffer> { -    path.to_path() -    .ok_or_else(|| { -        io::Error::new(io::ErrorKind::InvalidInput, -                       "nul byte in file name") -    }) -} - -#[cfg(test)] -mod test { -    use std::io::{Read}; -    use std::path::Path; -    use std::os::unix::io::{FromRawFd, IntoRawFd}; -    use crate::{Dir}; - -    #[test] -    fn test_open_ok() { -        assert!(Dir::open("src").is_ok()); -    } - -    #[test] -    #[cfg_attr(target_os="freebsd", should_panic(expected="Not a directory"))] -    fn test_open_file() { -        Dir::open("src/lib.rs").unwrap(); -    } - -    #[test] -    fn test_read_file() { -        let dir = Dir::open("src").unwrap(); -        let mut buf = String::new(); -        dir.open_file("lib.rs").unwrap() -            .read_to_string(&mut buf).unwrap(); -        assert!(buf.find("extern crate libc;").is_some()); -    } - -    #[test] -    fn test_from_into() { -        let dir = Dir::open("src").unwrap(); -        let dir = unsafe { Dir::from_raw_fd(dir.into_raw_fd()) }; -        let mut buf = String::new(); -        dir.open_file("lib.rs").unwrap() -            .read_to_string(&mut buf).unwrap(); -        assert!(buf.find("extern crate libc;").is_some()); -    } - -    #[test] -    #[should_panic(expected="No such file or directory")] -    fn test_open_no_dir() { -        Dir::open("src/some-non-existent-file").unwrap(); -    } - -    #[test] -    fn test_list() { -        let dir = Dir::open("src").unwrap(); -        let me = dir.list_dir(".").unwrap(); -        assert!(me.collect::<Result<Vec<_>, _>>().unwrap() -                .iter().find(|x| { -                    x.file_name() == Path::new("lib.rs").as_os_str() -                }) -                .is_some()); -    } - -    #[test] -    fn test_from_raw_fd_checked() { -        let fd = Dir::open(".").unwrap().into_raw_fd(); -        let dir = unsafe { Dir::from_raw_fd_checked(fd) }.unwrap(); -        let filefd = dir.open_file("src/lib.rs").unwrap().into_raw_fd(); -        match unsafe { Dir::from_raw_fd_checked(filefd) } { -            Ok(_) => assert!(false, "from_raw_fd_checked succeeded on a non-directory fd!"), -            Err(e) => assert_eq!(e.raw_os_error().unwrap(), libc::ENOTDIR) -        } -    } - -    #[test] -    fn test_try_clone() { -        let d = Dir::open(".").unwrap(); -        let d2 = d.try_clone().unwrap(); -        drop(d); -        let _file = d2.open_file("src/lib.rs").unwrap(); -    } -} diff --git a/openat/src/filetype.rs b/openat/src/filetype.rs deleted file mode 100644 index efaedbe..0000000 --- a/openat/src/filetype.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::fs::Metadata; - -/// This is a simplified file type enum that is easy to match -/// -/// It doesn't represent all the options, because that enum needs to extensible -/// but most application do not actually need that power, so we provide -/// this simplified enum that works for many appalications. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SimpleType { -    /// Entry is a symlink -    Symlink, -    /// Entry is a directory -    Dir, -    /// Entry is a regular file -    File, -    /// Entry is neither a symlink, directory nor a regular file -    Other, -} - -impl SimpleType { -    /// Find out a simple type from a file Metadata (stat) -    pub fn extract(stat: &Metadata) -> SimpleType { -        if stat.file_type().is_symlink() { -            SimpleType::Symlink -        } else if stat.is_dir() { -            SimpleType::Dir -        } else if stat.is_file() { -            SimpleType::File -        } else { -            SimpleType::Other -        } -    } -} diff --git a/openat/src/lib.rs b/openat/src/lib.rs deleted file mode 100644 index a1a2feb..0000000 --- a/openat/src/lib.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! # Handling Files Relative to File Descriptor -//! -//! Main concept here is a `Dir` which holds `O_PATH` file descriptor, you -//! can create it with: -//! -//! * `Dir::open("/some/path")` -- open this directory as a file descriptor -//! * `Dir::from_raw_fd(fd)` -- uses a file descriptor provided elsewhere -//! -//! *Note after opening file descriptors refer to same directory regardless of -//! where it's moved or mounted (with `pivot_root` or `mount --move`). It may -//! also be unmounted or be out of chroot and you will still be able to -//! access files relative to it.* -//! -//! *Note2: The constructor `Dir::cwd()` is deprecated, and it's recommended -//! to use `Dir::open(".")` instead.* -//! -//! *Note3: Some OS's (e.g., macOS) do not provide `O_PATH`, in which case the -//! file descriptor is of regular type.* -//! -//! Most other operations are done on `Dir` object and are executed relative -//! to it: -//! -//! * `Dir::list_dir()` -//! * `Dir::sub_dir()` -//! * `Dir::read_link()` -//! * `Dir::open_file()` -//! * `Dir::create_file()` -//! * `Dir::update_file()` -//! * `Dir::create_dir()` -//! * `Dir::symlink()` -//! * `Dir::local_rename()` -//! -//! Functions that expect path relative to the directory accept both the -//! traditional path-like objects, such as Path, PathBuf and &str, and -//! `Entry` type returned from `list_dir()`. The latter is faster as underlying -//! system call wants `CString` and we keep that in entry. -//! -//! Note that if path supplied to any method of dir is absolute the Dir file -//! descriptor is ignored. -//! -//! Also while all methods of dir accept any path if you want to prevent -//! certain symlink attacks and race condition you should only use -//! a single-component path. I.e. open one part of a chain at a time. -//! -#![warn(missing_docs)] - -extern crate libc; - -mod dir; -mod list; -mod name; -mod filetype; -mod metadata; - -pub use crate::list::DirIter; -pub use crate::name::AsPath; -pub use crate::dir::{rename, hardlink}; -pub use crate::filetype::SimpleType; -pub use crate::metadata::Metadata; - -use std::ffi::CString; -use std::os::unix::io::RawFd; - -/// A safe wrapper around directory file descriptor -/// -/// Construct it either with ``Dir::cwd()`` or ``Dir::open(path)`` -/// -#[derive(Debug)] -pub struct Dir(RawFd); - -/// Entry returned by iterating over `DirIter` iterator -#[derive(Debug)] -pub struct Entry { -    name: CString, -    file_type: Option<SimpleType>, -} - -#[cfg(test)] -mod test { -    use std::mem; -    use super::Dir; - -    fn assert_sync<T: Sync>(x: T) -> T { x } -    fn assert_send<T: Send>(x: T) -> T { x } - -    #[test] -    fn test() { -        let d = Dir(3); -        let d = assert_sync(d); -        let d = assert_send(d); -        // don't execute close for our fake RawFd -        mem::forget(d); -    } -} - diff --git a/openat/src/list.rs b/openat/src/list.rs deleted file mode 100644 index 5b4d3cd..0000000 --- a/openat/src/list.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::io; -use std::ptr; -use std::ffi::{CStr, OsStr}; -use std::os::unix::ffi::OsStrExt; - -use libc; - -use crate::{Dir, Entry, SimpleType}; - - -// We have such weird constants because C types are ugly -const DOT: [libc::c_char; 2] = [b'.' as libc::c_char, 0]; -const DOTDOT: [libc::c_char; 3] = [b'.' as libc::c_char, b'.' as libc::c_char, 0]; - - -/// Iterator over directory entries -/// -/// Created using `Dir::list_dir()` -#[derive(Debug)] -pub struct DirIter { -    dir: *mut libc::DIR, -} - -/// Position in a DirIter as obtained by 'DirIter::current_position()' -/// -/// The position is only valid for the DirIter it was retrieved from. -pub struct DirPosition { -    pos: libc::c_long, -} - -impl Entry { -    /// Returns the file name of this entry -    pub fn file_name(&self) -> &OsStr { -        OsStr::from_bytes(self.name.to_bytes()) -    } -    /// Returns the simplified type of this entry -    pub fn simple_type(&self) -> Option<SimpleType> { -        self.file_type -    } -} - -#[cfg(any(target_os="linux", target_os="fuchsia"))] -unsafe fn errno_location() -> *mut libc::c_int { -    libc::__errno_location() -} - -#[cfg(any(target_os="openbsd", target_os="netbsd", target_os="android"))] -unsafe fn errno_location() -> *mut libc::c_int { -    libc::__errno() -} - -#[cfg(not(any(target_os="linux", target_os="openbsd", target_os="netbsd", target_os="android", target_os="fuchsia")))] -unsafe fn errno_location() -> *mut libc::c_int { -    libc::__error() -} - -impl DirIter { - -    unsafe fn next_entry(&mut self) -> io::Result<Option<&libc::dirent>> -    { -        // Reset errno to detect if error occurred -        *errno_location() = 0; - -        let entry = libc::readdir(self.dir); -        if entry == ptr::null_mut() { -            if *errno_location() == 0 { -                return Ok(None) -            } else { -                return Err(io::Error::last_os_error()); -            } -        } -        return Ok(Some(&*entry)); -    } - -    /// Returns the current directory iterator position. The result should be handled as opaque value -    pub fn current_position(&self) -> io::Result<DirPosition> { -        let pos = unsafe { libc::telldir(self.dir) }; - -        if pos == -1 { -            Err(io::Error::last_os_error()) -        } else { -            Ok(DirPosition { pos }) -        } -    } - -    // note the C-API does not report errors for seekdir/rewinddir, thus we don't do as well. -    /// Sets the current directory iterator position to some location queried by 'current_position()' -    pub fn seek(&self, position: DirPosition) { -        unsafe { libc::seekdir(self.dir, position.pos) }; -    } - -    /// Resets the current directory iterator position to the beginning -    pub fn rewind(&self) { -        unsafe { libc::rewinddir(self.dir) }; -    } -} - -pub fn open_dirfd(fd: libc::c_int) -> io::Result<DirIter> { -    let dir = unsafe { libc::fdopendir(fd) }; -    if dir == std::ptr::null_mut() { -        Err(io::Error::last_os_error()) -    } else { -        Ok(DirIter { dir: dir }) -    } -} - -pub fn open_dir(dir: &Dir, path: &CStr) -> io::Result<DirIter> { -    let dir_fd = unsafe { -        libc::openat(dir.0, path.as_ptr(), libc::O_DIRECTORY|libc::O_CLOEXEC) -    }; -    if dir_fd < 0 { -        Err(io::Error::last_os_error()) -    } else { -        open_dirfd(dir_fd) -    } -} - -impl Iterator for DirIter { -    type Item = io::Result<Entry>; -    fn next(&mut self) -> Option<Self::Item> { -        unsafe { -            loop { -                match self.next_entry() { -                    Err(e) => return Some(Err(e)), -                    Ok(None) => return None, -                    Ok(Some(e)) if e.d_name[..2] == DOT => continue, -                    Ok(Some(e)) if e.d_name[..3] == DOTDOT => continue, -                    Ok(Some(e)) => { -                        return Some(Ok(Entry { -                            name: CStr::from_ptr((e.d_name).as_ptr()) -                                .to_owned(), -                            file_type: match e.d_type { -                                0 => None, -                                libc::DT_REG => Some(SimpleType::File), -                                libc::DT_DIR => Some(SimpleType::Dir), -                                libc::DT_LNK => Some(SimpleType::Symlink), -                                _ => Some(SimpleType::Other), -                            }, -                        })); -                    } -                } -            } -        } -    } -} - -impl Drop for DirIter { -    fn drop(&mut self) { -        unsafe { -            libc::closedir(self.dir); -        } -    } -} diff --git a/openat/src/metadata.rs b/openat/src/metadata.rs deleted file mode 100644 index de7cc22..0000000 --- a/openat/src/metadata.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::fs::Permissions; -use std::os::unix::fs::PermissionsExt; - -use libc; - -use crate::SimpleType; - - -/// A file metadata -/// -/// Because we can't freely create a `std::fs::Metadata` object we have to -/// implement our own structure. -pub struct Metadata { -    stat: libc::stat, -} - -impl Metadata { -    /// Returns simplified type of the directory entry -    pub fn simple_type(&self) -> SimpleType { -        let typ = self.stat.st_mode & libc::S_IFMT; -        match typ { -            libc::S_IFREG => SimpleType::File, -            libc::S_IFDIR => SimpleType::Dir, -            libc::S_IFLNK => SimpleType::Symlink, -            _ => SimpleType::Other, -        } -    } -    /// Returns underlying stat structure -    pub fn stat(&self) -> &libc::stat { -        &self.stat -    } -    /// Returns `true` if the entry is a regular file -    pub fn is_file(&self) -> bool { -        self.simple_type() == SimpleType::File -    } -    /// Returns `true` if the entry is a directory -    pub fn is_dir(&self) -> bool { -        self.simple_type() == SimpleType::Dir -    } -    /// Returns permissions of the entry -    pub fn permissions(&self) -> Permissions { -        Permissions::from_mode(self.stat.st_mode as u32) -    } -    /// Returns file size -    pub fn len(&self) -> u64 { -        self.stat.st_size as u64 -    } -} - -pub fn new(stat: libc::stat) -> Metadata { -    Metadata { stat: stat } -} - -#[cfg(test)] -mod test { -    use super::*; - -    #[test] -    fn dir() { -        let d = crate::Dir::open(".").unwrap(); -        let m = d.metadata("src").unwrap(); -        assert_eq!(m.simple_type(), SimpleType::Dir); -        assert!(m.is_dir()); -        assert!(!m.is_file()); -    } - -    #[test] -    fn file() { -        let d = crate::Dir::open("src").unwrap(); -        let m = d.metadata("lib.rs").unwrap(); -        assert_eq!(m.simple_type(), SimpleType::File); -        assert!(!m.is_dir()); -        assert!(m.is_file()); -    } -} diff --git a/openat/src/name.rs b/openat/src/name.rs deleted file mode 100644 index c181db1..0000000 --- a/openat/src/name.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::ffi::{OsStr, CStr, CString}; -use std::path::{Path, PathBuf}; -use std::os::unix::ffi::OsStrExt; - -use crate::{Entry}; - - -/// The purpose of this is similar to `AsRef<Path>` but it's optimized for -/// things that can be directly used as `CStr` (which is type passed to -/// the underlying system call). -/// -/// This trait should be implemented for everything for which `AsRef<Path>` -/// is implemented -pub trait AsPath { -    /// The return value of the `to_path` that holds data copied from the -    /// original path (if copy is needed, otherwise it's just a reference) -    type Buffer: AsRef<CStr>; -    /// Returns `None` when path contains a zero byte -    fn to_path(self) -> Option<Self::Buffer>; -} - -impl<'a> AsPath for &'a Path { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self.as_os_str().as_bytes()).ok() -    } -} - -impl<'a> AsPath for &'a PathBuf { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self.as_os_str().as_bytes()).ok() -    } -} - -impl<'a> AsPath for &'a OsStr { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self.as_bytes()).ok() -    } -} - -impl<'a> AsPath for &'a str { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self.as_bytes()).ok() -    } -} - -impl<'a> AsPath for &'a String { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self.as_bytes()).ok() -    } -} - -impl<'a> AsPath for String { -    type Buffer = CString; -    fn to_path(self) -> Option<CString> { -        CString::new(self).ok() -    } -} - -impl<'a> AsPath for &'a CStr { -    type Buffer = &'a CStr; -    fn to_path(self) -> Option<&'a CStr> { -        Some(self) -    } -} - -impl<'a> AsPath for &'a Entry { -    type Buffer = &'a CStr; -    fn to_path(self) -> Option<&'a CStr> { -        Some(&self.name) -    } -} diff --git a/openat/tests/tmpfile.rs b/openat/tests/tmpfile.rs deleted file mode 100644 index 4fa0f0d..0000000 --- a/openat/tests/tmpfile.rs +++ /dev/null @@ -1,24 +0,0 @@ -extern crate tempfile; -extern crate openat; - -use std::io::{self, Read, Write}; -use std::os::unix::fs::PermissionsExt; -use openat::Dir; - -#[test] -#[cfg(target_os="linux")] -fn unnamed_tmp_file_link() -> Result<(), io::Error> { -    let tmp = tempfile::tempdir()?; -    let dir = Dir::open(tmp.path())?; -    let mut f = dir.new_unnamed_file(0o777)?; -    f.write(b"hello\n")?; -    // In glibc <= 2.22 permissions aren't set when using O_TMPFILE -    // This includes ubuntu trusty on travis CI -    f.set_permissions(PermissionsExt::from_mode(0o644))?; -    dir.link_file_at(&f, "hello.txt")?; -    let mut f = dir.open_file("hello.txt")?; -    let mut buf = String::with_capacity(10); -    f.read_to_string(&mut buf)?; -    assert_eq!(buf, "hello\n"); -    Ok(()) -} diff --git a/openat/vagga.yaml b/openat/vagga.yaml deleted file mode 100644 index 568a80d..0000000 --- a/openat/vagga.yaml +++ /dev/null @@ -1,91 +0,0 @@ -commands: - -  make: !Command -    description: Build the library -    container: ubuntu -    run: [cargo, build] - -  build-musl: !Command -    description: Build the library with musl libc -    container: ubuntu -    run: [cargo, build, --target=x86_64-unknown-linux-musl] - -  cargo: !Command -    description: Run arbitrary cargo command -    container: ubuntu -    run: [cargo] - -  test: !Command -    description: Run tests -    container: ubuntu -    run: [cargo, test] - -  bench: !Command -    description: Run benchmarks -    container: nightly -    run: [cargo, bench] - -  _bulk: !Command -    description: Run `bulk` command (for version bookkeeping) -    container: ubuntu -    run: [bulk] - -containers: - -  ubuntu: -    setup: -    - !Ubuntu xenial -    - !UbuntuUniverse -    - !Install [ca-certificates, git, build-essential, vim, musl-tools] - -    - !TarInstall -      url: "https://static.rust-lang.org/dist/rust-1.32.0-x86_64-unknown-linux-gnu.tar.gz" -      script: "./install.sh --prefix=/usr \ -                --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo" -    - !TarInstall -      url: "https://static.rust-lang.org/dist/rust-std-1.32.0-x86_64-unknown-linux-musl.tar.gz" -      script: "./install.sh --prefix=/musl \ -               --components=rust-std-x86_64-unknown-linux-musl" -    - !Sh 'ln -s /musl/lib/rustlib/x86_64-unknown-linux-musl /usr/lib/rustlib/x86_64-unknown-linux-musl' -    - &bulk !Tar -      url: "https://github.com/tailhook/bulk/releases/download/v0.4.10/bulk-v0.4.10.tar.gz" -      sha256: 481513f8a0306a9857d045497fb5b50b50a51e9ff748909ecf7d2bda1de275ab -      path: / - -    environ: -      HOME: /work/target -      LD_LIBRARY_PATH: /musl/lib/rustlib/x86_64-unknown-linux-musl/lib -      PATH: /musl/bin:/usr/local/bin:/usr/bin:/bin -      RUST_BACKTRACE: 1 - -  nightly: -    setup: -    - !Ubuntu xenial -    - !Install [ca-certificates, git, build-essential] - -    - !TarInstall -      url: "https://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz" -      script: "./install.sh --prefix=/usr \ -                --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo" - -    environ: -      HOME: /work/target -      RUST_BACKTRACE: 1 - -  aarch64: -    setup: -    - !Ubuntu xenial -    - !Install [ca-certificates, git, build-essential] - -    - !TarInstall -      url: "https://static.rust-lang.org/dist/rust-1.31.0-x86_64-unknown-linux-gnu.tar.gz" -      script: "./install.sh --prefix=/usr \ -                --components=rustc,cargo" -    - !TarInstall -      url: "https://static.rust-lang.org/dist/rust-std-1.31.0-aarch64-linux-android.tar.gz" -      script: "./install.sh --prefix=/usr \ -                --components=rust-std-aarch64-linux-android" - -    environ: -      HOME: /work/target -      RUST_BACKTRACE: 1 @@ -1,9 +1,9 @@ -use libc::mode_t; -use openat::{Dir, AsPath}; +use cap_std::fs::{Dir, OpenOptions};  use pam::constants::{PamFlag, PamResultCode};  use pam::module::{PamHandle, PamHooks};  use std::ffi::CStr;  use std::io::{ErrorKind, Write}; +use std::path::Path;  use std::process;  const CG_MOUNT: &str = "/sys/fs/cgroup"; @@ -11,17 +11,17 @@ const CG_MOUNT: &str = "/sys/fs/cgroup";  struct PAMUserCG;  pam::pam_hooks!(PAMUserCG); -fn create_and_open_dir<P: AsPath + Copy>( -        d: &Dir, path: P, mode: mode_t, +fn create_and_open_dir<P: AsRef<Path> + Copy>( +        d: &Dir, path: P,      ) -> std::io::Result<Dir> { -    match d.create_dir(path, mode) { +    match d.create_dir(path) {          Ok(()) => Ok(()),          Err(e) => match e.kind() {              ErrorKind::AlreadyExists => Ok(()),              _ => Err(e),          }      }?; -    d.sub_dir(path) +    d.open_dir(path)  }  struct SessionError; @@ -29,14 +29,16 @@ struct SessionError;  fn open_session(h: &mut PamHandle) -> Result<(), SessionError> {      let user = h.get_user(None).or(Err(SessionError))?;      let user = users::get_user_by_name(&user).ok_or(SessionError)?; -    let d = Dir::open(CG_MOUNT).or(Err(SessionError))?; -    let d = create_and_open_dir(&d, "user", 0o777).or(Err(SessionError))?; -    let d = create_and_open_dir(&d, &user.uid().to_string(), 0o777) +    let aa = cap_std::ambient_authority(); +    let d = Dir::open_ambient_dir(CG_MOUNT, aa).or(Err(SessionError))?; +    let d = create_and_open_dir(&d, "user").or(Err(SessionError))?; +    let d = create_and_open_dir(&d, &user.uid().to_string())          .or(Err(SessionError))?; -    let d = create_and_open_dir(&d, "leaf", 0o777).or(Err(SessionError))?; +    let d = create_and_open_dir(&d, "leaf").or(Err(SessionError))?;      let pid = process::id().to_string(); -    let mut procs = d.open_file_ex("cgroup.procs", libc::O_WRONLY, 0) -        .or(Err(SessionError))?; +    let mut options = OpenOptions::new(); +    options.write(true); +    let mut procs = d.open_with("cgroup.procs", &options).or(Err(SessionError))?;      procs.write_all(pid.as_bytes()).or(Err(SessionError))?;      Ok(())  } | 
