Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test_fcntl.rs   Sprache: unbekannt

 
#[cfg(not(target_os = "redox"))]
use nix::errno::*;
#[cfg(not(target_os = "redox"))]
use nix::fcntl::{open, readlink, OFlag};
#[cfg(not(target_os = "redox"))]
use nix::fcntl::{openat, readlinkat, renameat};

#[cfg(target_os = "linux")]
use nix::fcntl::{openat2, OpenHow, ResolveFlag};

#[cfg(all(
    target_os = "linux",
    target_env = "gnu",
    any(
        target_arch = "x86_64",
        target_arch = "powerpc",
        target_arch = "s390x"
    )
))]
use nix::fcntl::{renameat2, RenameFlags};
#[cfg(not(target_os = "redox"))]
use nix::sys::stat::Mode;
#[cfg(not(target_os = "redox"))]
use nix::unistd::{close, read};
#[cfg(not(target_os = "redox"))]
use std::fs::File;
#[cfg(not(target_os = "redox"))]
use std::io::prelude::*;
#[cfg(not(target_os = "redox"))]
use std::os::unix::fs;
#[cfg(not(target_os = "redox"))]
use tempfile::NamedTempFile;

#[test]
#[cfg(not(target_os = "redox"))]
// QEMU does not handle openat well enough to satisfy this test
// https://gitlab.com/qemu-project/qemu/-/issues/829
#[cfg_attr(qemu, ignore)]
fn test_openat() {
    const CONTENTS: &[u8] = b"abcd";
    let mut tmp = NamedTempFile::new().unwrap();
    tmp.write_all(CONTENTS).unwrap();

    let dirfd =
        open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty())
            .unwrap();
    let fd = openat(
        Some(dirfd),
        tmp.path().file_name().unwrap(),
        OFlag::O_RDONLY,
        Mode::empty(),
    )
    .unwrap();

    let mut buf = [0u8; 1024];
    assert_eq!(4, read(fd, &mut buf).unwrap());
    assert_eq!(CONTENTS, &buf[0..4]);

    close(fd).unwrap();
    close(dirfd).unwrap();
}

#[test]
#[cfg(target_os = "linux")]
// QEMU does not handle openat well enough to satisfy this test
// https://gitlab.com/qemu-project/qemu/-/issues/829
#[cfg_attr(qemu, ignore)]
fn test_openat2() {
    const CONTENTS: &[u8] = b"abcd";
    let mut tmp = NamedTempFile::new().unwrap();
    tmp.write_all(CONTENTS).unwrap();

    let dirfd =
        open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty())
            .unwrap();

    let fd = openat2(
        dirfd,
        tmp.path().file_name().unwrap(),
        OpenHow::new()
            .flags(OFlag::O_RDONLY)
            .mode(Mode::empty())
            .resolve(ResolveFlag::RESOLVE_BENEATH),
    )
    .unwrap();

    let mut buf = [0u8; 1024];
    assert_eq!(4, read(fd, &mut buf).unwrap());
    assert_eq!(CONTENTS, &buf[0..4]);

    close(fd).unwrap();
    close(dirfd).unwrap();
}

#[test]
#[cfg(target_os = "linux")]
// QEMU does not handle openat well enough to satisfy this test
// https://gitlab.com/qemu-project/qemu/-/issues/829
#[cfg_attr(qemu, ignore)]
fn test_openat2_forbidden() {
    let mut tmp = NamedTempFile::new().unwrap();
    tmp.write_all(b"let me out").unwrap();

    let dirfd =
        open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty())
            .unwrap();

    let escape_attempt =
        tmp.path().parent().unwrap().join("../../../hello.txt");

    let res = openat2(
        dirfd,
        &escape_attempt,
        OpenHow::new()
            .flags(OFlag::O_RDONLY)
            .resolve(ResolveFlag::RESOLVE_BENEATH),
    );
    assert_eq!(Err(Errno::EXDEV), res);
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_renameat() {
    let old_dir = tempfile::tempdir().unwrap();
    let old_dirfd =
        open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let old_path = old_dir.path().join("old");
    File::create(old_path).unwrap();
    let new_dir = tempfile::tempdir().unwrap();
    let new_dirfd =
        open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
    assert_eq!(
        renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
        Errno::ENOENT
    );
    close(old_dirfd).unwrap();
    close(new_dirfd).unwrap();
    assert!(new_dir.path().join("new").exists());
}

#[test]
#[cfg(all(
    target_os = "linux",
    target_env = "gnu",
    any(
        target_arch = "x86_64",
        target_arch = "powerpc",
        target_arch = "s390x"
    )
))]
fn test_renameat2_behaves_like_renameat_with_no_flags() {
    let old_dir = tempfile::tempdir().unwrap();
    let old_dirfd =
        open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let old_path = old_dir.path().join("old");
    File::create(old_path).unwrap();
    let new_dir = tempfile::tempdir().unwrap();
    let new_dirfd =
        open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    renameat2(
        Some(old_dirfd),
        "old",
        Some(new_dirfd),
        "new",
        RenameFlags::empty(),
    )
    .unwrap();
    assert_eq!(
        renameat2(
            Some(old_dirfd),
            "old",
            Some(new_dirfd),
            "new",
            RenameFlags::empty()
        )
        .unwrap_err(),
        Errno::ENOENT
    );
    close(old_dirfd).unwrap();
    close(new_dirfd).unwrap();
    assert!(new_dir.path().join("new").exists());
}

#[test]
#[cfg(all(
    target_os = "linux",
    target_env = "gnu",
    any(
        target_arch = "x86_64",
        target_arch = "powerpc",
        target_arch = "s390x"
    )
))]
fn test_renameat2_exchange() {
    let old_dir = tempfile::tempdir().unwrap();
    let old_dirfd =
        open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let old_path = old_dir.path().join("old");
    {
        let mut old_f = File::create(&old_path).unwrap();
        old_f.write_all(b"old").unwrap();
    }
    let new_dir = tempfile::tempdir().unwrap();
    let new_dirfd =
        open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let new_path = new_dir.path().join("new");
    {
        let mut new_f = File::create(&new_path).unwrap();
        new_f.write_all(b"new").unwrap();
    }
    renameat2(
        Some(old_dirfd),
        "old",
        Some(new_dirfd),
        "new",
        RenameFlags::RENAME_EXCHANGE,
    )
    .unwrap();
    let mut buf = String::new();
    let mut new_f = File::open(&new_path).unwrap();
    new_f.read_to_string(&mut buf).unwrap();
    assert_eq!(buf, "old");
    buf = "".to_string();
    let mut old_f = File::open(&old_path).unwrap();
    old_f.read_to_string(&mut buf).unwrap();
    assert_eq!(buf, "new");
    close(old_dirfd).unwrap();
    close(new_dirfd).unwrap();
}

#[test]
#[cfg(all(
    target_os = "linux",
    target_env = "gnu",
    any(
        target_arch = "x86_64",
        target_arch = "powerpc",
        target_arch = "s390x"
    )
))]
fn test_renameat2_noreplace() {
    let old_dir = tempfile::tempdir().unwrap();
    let old_dirfd =
        open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let old_path = old_dir.path().join("old");
    File::create(old_path).unwrap();
    let new_dir = tempfile::tempdir().unwrap();
    let new_dirfd =
        open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let new_path = new_dir.path().join("new");
    File::create(new_path).unwrap();
    assert_eq!(
        renameat2(
            Some(old_dirfd),
            "old",
            Some(new_dirfd),
            "new",
            RenameFlags::RENAME_NOREPLACE
        )
        .unwrap_err(),
        Errno::EEXIST
    );
    close(old_dirfd).unwrap();
    close(new_dirfd).unwrap();
    assert!(new_dir.path().join("new").exists());
    assert!(old_dir.path().join("old").exists());
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_readlink() {
    let tempdir = tempfile::tempdir().unwrap();
    let src = tempdir.path().join("a");
    let dst = tempdir.path().join("b");
    println!("a: {:?}, b: {:?}", &src, &dst);
    fs::symlink(src.as_path(), dst.as_path()).unwrap();
    let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
    let expected_dir = src.to_str().unwrap();

    assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
    assert_eq!(
        readlinkat(Some(dirfd), "b").unwrap().to_str().unwrap(),
        expected_dir
    );
}

/// This test creates a temporary file containing the contents
/// 'foobarbaz' and uses the `copy_file_range` call to transfer
/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
/// resulting file is read and should contain the contents `bar`.
/// The from_offset should be updated by the call to reflect
/// the 3 bytes read (6).
#[cfg(any(
        linux_android,
        // Not available until FreeBSD 13.0
        all(target_os = "freebsd", fbsd14),
))]
#[test]
// QEMU does not support copy_file_range. Skip under qemu
#[cfg_attr(qemu, ignore)]
fn test_copy_file_range() {
    use nix::fcntl::copy_file_range;
    use std::os::unix::io::AsFd;

    const CONTENTS: &[u8] = b"foobarbaz";

    let mut tmp1 = tempfile::tempfile().unwrap();
    let mut tmp2 = tempfile::tempfile().unwrap();

    tmp1.write_all(CONTENTS).unwrap();
    tmp1.flush().unwrap();

    let mut from_offset: i64 = 3;
    copy_file_range(
        tmp1.as_fd(),
        Some(&mut from_offset),
        tmp2.as_fd(),
        None,
        3,
    )
    .unwrap();

    let mut res: String = String::new();
    tmp2.rewind().unwrap();
    tmp2.read_to_string(&mut res).unwrap();

    assert_eq!(res, String::from("bar"));
    assert_eq!(from_offset, 6);
}

#[cfg(linux_android)]
mod linux_android {
    use libc::loff_t;
    use std::io::prelude::*;
    use std::io::IoSlice;
    use std::os::unix::prelude::*;

    use nix::fcntl::*;
    use nix::unistd::{pipe, read, write};

    use tempfile::tempfile;
    #[cfg(target_os = "linux")]
    use tempfile::NamedTempFile;

    use crate::*;

    #[test]
    fn test_splice() {
        const CONTENTS: &[u8] = b"abcdef123456";
        let mut tmp = tempfile().unwrap();
        tmp.write_all(CONTENTS).unwrap();

        let (rd, wr) = pipe().unwrap();
        let mut offset: loff_t = 5;
        let res =
            splice(tmp, Some(&mut offset), wr, None, 2, SpliceFFlags::empty())
                .unwrap();

        assert_eq!(2, res);

        let mut buf = [0u8; 1024];
        assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
        assert_eq!(b"f1", &buf[0..2]);
        assert_eq!(7, offset);
    }

    #[test]
    fn test_tee() {
        let (rd1, wr1) = pipe().unwrap();
        let (rd2, wr2) = pipe().unwrap();

        write(wr1, b"abc").unwrap();
        let res = tee(rd1.try_clone().unwrap(), wr2, 2, SpliceFFlags::empty())
            .unwrap();

        assert_eq!(2, res);

        let mut buf = [0u8; 1024];

        // Check the tee'd bytes are at rd2.
        assert_eq!(2, read(rd2.as_raw_fd(), &mut buf).unwrap());
        assert_eq!(b"ab", &buf[0..2]);

        // Check all the bytes are still at rd1.
        assert_eq!(3, read(rd1.as_raw_fd(), &mut buf).unwrap());
        assert_eq!(b"abc", &buf[0..3]);
    }

    #[test]
    fn test_vmsplice() {
        let (rd, wr) = pipe().unwrap();

        let buf1 = b"abcdef";
        let buf2 = b"defghi";
        let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])];

        let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();

        assert_eq!(6, res);

        // Check the bytes can be read at rd.
        let mut buf = [0u8; 32];
        assert_eq!(6, read(rd.as_raw_fd(), &mut buf).unwrap());
        assert_eq!(b"abcdef", &buf[0..6]);
    }

    #[cfg(target_os = "linux")]
    #[test]
    fn test_fallocate() {
        let tmp = NamedTempFile::new().unwrap();

        let fd = tmp.as_raw_fd();
        fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();

        // Check if we read exactly 100 bytes
        let mut buf = [0u8; 200];
        assert_eq!(100, read(fd, &mut buf).unwrap());
    }

    // The tests below are disabled for the listed targets
    // due to OFD locks not being available in the kernel/libc
    // versions used in the CI environment, probably because
    // they run under QEMU.

    #[test]
    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile
    fn test_ofd_write_lock() {
        use nix::sys::stat::fstat;
        use std::mem;

        let tmp = NamedTempFile::new().unwrap();

        let fd = tmp.as_raw_fd();
        let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap();
        if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
            // OverlayFS is a union file system.  It returns one inode value in
            // stat(2), but a different one shows up in /proc/locks.  So we must
            // skip the test.
            skip!("/proc/locks does not work on overlayfs");
        }
        let inode = fstat(fd).expect("fstat failed").st_ino as usize;

        let mut flock: libc::flock = unsafe {
            mem::zeroed() // required for Linux/mips
        };
        flock.l_type = libc::F_WRLCK as libc::c_short;
        flock.l_whence = libc::SEEK_SET as libc::c_short;
        flock.l_start = 0;
        flock.l_len = 0;
        flock.l_pid = 0;
        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed");
        assert_eq!(
            Some(("OFDLCK".to_string(), "WRITE".to_string())),
            lock_info(inode)
        );

        flock.l_type = libc::F_UNLCK as libc::c_short;
        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
        assert_eq!(None, lock_info(inode));
    }

    #[test]
    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile
    fn test_ofd_read_lock() {
        use nix::sys::stat::fstat;
        use std::mem;

        let tmp = NamedTempFile::new().unwrap();

        let fd = tmp.as_raw_fd();
        let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap();
        if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
            // OverlayFS is a union file system.  It returns one inode value in
            // stat(2), but a different one shows up in /proc/locks.  So we must
            // skip the test.
            skip!("/proc/locks does not work on overlayfs");
        }
        let inode = fstat(fd).expect("fstat failed").st_ino as usize;

        let mut flock: libc::flock = unsafe {
            mem::zeroed() // required for Linux/mips
        };
        flock.l_type = libc::F_RDLCK as libc::c_short;
        flock.l_whence = libc::SEEK_SET as libc::c_short;
        flock.l_start = 0;
        flock.l_len = 0;
        flock.l_pid = 0;
        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed");
        assert_eq!(
            Some(("OFDLCK".to_string(), "READ".to_string())),
            lock_info(inode)
        );

        flock.l_type = libc::F_UNLCK as libc::c_short;
        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
        assert_eq!(None, lock_info(inode));
    }

    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    fn lock_info(inode: usize) -> Option<(String, String)> {
        use std::{fs::File, io::BufReader};

        let file = File::open("/proc/locks").expect("open /proc/locks failed");
        let buf = BufReader::new(file);

        for line in buf.lines() {
            let line = line.unwrap();
            let parts: Vec<_> = line.split_whitespace().collect();
            let lock_type = parts[1];
            let lock_access = parts[3];
            let ino_parts: Vec<_> = parts[5].split(':').collect();
            let ino: usize = ino_parts[2].parse().unwrap();
            if ino == inode {
                return Some((lock_type.to_string(), lock_access.to_string()));
            }
        }
        None
    }
}

#[cfg(any(
    linux_android,
    target_os = "emscripten",
    target_os = "fuchsia",
    target_os = "wasi",
    target_env = "uclibc",
    target_os = "freebsd"
))]
mod test_posix_fadvise {

    use nix::errno::Errno;
    use nix::fcntl::*;
    use nix::unistd::pipe;
    use std::os::unix::io::AsRawFd;
    use tempfile::NamedTempFile;

    #[test]
    fn test_success() {
        let tmp = NamedTempFile::new().unwrap();
        let fd = tmp.as_raw_fd();
        posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED)
            .expect("posix_fadvise failed");
    }

    #[test]
    fn test_errno() {
        let (rd, _wr) = pipe().unwrap();
        let res = posix_fadvise(
            rd.as_raw_fd(),
            0,
            100,
            PosixFadviseAdvice::POSIX_FADV_WILLNEED,
        );
        assert_eq!(res, Err(Errno::ESPIPE));
    }
}

#[cfg(any(
    linux_android,
    freebsdlike,
    target_os = "emscripten",
    target_os = "fuchsia",
    target_os = "wasi",
))]
mod test_posix_fallocate {

    use nix::errno::Errno;
    use nix::fcntl::*;
    use nix::unistd::pipe;
    use std::{io::Read, os::unix::io::AsRawFd};
    use tempfile::NamedTempFile;

    #[test]
    fn success() {
        const LEN: usize = 100;
        let mut tmp = NamedTempFile::new().unwrap();
        let fd = tmp.as_raw_fd();
        let res = posix_fallocate(fd, 0, LEN as libc::off_t);
        match res {
            Ok(_) => {
                let mut data = [1u8; LEN];
                assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
                assert_eq!(&data[..], &[0u8; LEN][..]);
            }
            Err(Errno::EINVAL) => {
                // POSIX requires posix_fallocate to return EINVAL both for
                // invalid arguments (i.e. len < 0) and if the operation is not
                // supported by the file system.
                // There's no way to tell for sure whether the file system
                // supports posix_fallocate, so we must pass the test if it
                // returns EINVAL.
            }
            _ => res.unwrap(),
        }
    }

    #[test]
    fn errno() {
        let (rd, _wr) = pipe().unwrap();
        let err = posix_fallocate(rd.as_raw_fd(), 0, 100).unwrap_err();
        match err {
            Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
            errno => panic!("unexpected errno {errno}",),
        }
    }
}

#[cfg(any(target_os = "dragonfly", target_os = "netbsd", apple_targets))]
#[test]
fn test_f_get_path() {
    use nix::fcntl::*;
    use std::{os::unix::io::AsRawFd, path::PathBuf};

    let tmp = NamedTempFile::new().unwrap();
    let fd = tmp.as_raw_fd();
    let mut path = PathBuf::new();
    let res =
        fcntl(fd, FcntlArg::F_GETPATH(&mut path)).expect("get path failed");
    assert_ne!(res, -1);
    assert_eq!(
        path.as_path().canonicalize().unwrap(),
        tmp.path().canonicalize().unwrap()
    );
}

#[cfg(apple_targets)]
#[test]
fn test_f_get_path_nofirmlink() {
    use nix::fcntl::*;
    use std::{os::unix::io::AsRawFd, path::PathBuf};

    let tmp = NamedTempFile::new().unwrap();
    let fd = tmp.as_raw_fd();
    let mut path = PathBuf::new();
    let res = fcntl(fd, FcntlArg::F_GETPATH_NOFIRMLINK(&mut path))
        .expect("get path failed");
    let mut tmpstr = String::from("/System/Volumes/Data");
    tmpstr.push_str(
        &tmp.path()
            .canonicalize()
            .unwrap()
            .into_os_string()
            .into_string()
            .unwrap(),
    );
    assert_ne!(res, -1);
    assert_eq!(
        path.as_path()
            .canonicalize()
            .unwrap()
            .into_os_string()
            .into_string()
            .unwrap(),
        tmpstr
    );
}

#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
#[test]
fn test_f_kinfo() {
    use nix::fcntl::*;
    use std::{os::unix::io::AsRawFd, path::PathBuf};

    let tmp = NamedTempFile::new().unwrap();
    // With TMPDIR set with UFS, the vnode name is not entered
    // into the name cache thus path is always empty.
    // Therefore, we reopen the tempfile a second time for the test
    // to pass.
    let tmp2 = File::open(tmp.path()).unwrap();
    let fd = tmp2.as_raw_fd();
    let mut path = PathBuf::new();
    let res = fcntl(fd, FcntlArg::F_KINFO(&mut path)).expect("get path failed");
    assert_ne!(res, -1);
    assert_eq!(path, tmp.path());
}

/// Test `Flock` and associated functions.
///
#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
mod test_flock {
    use nix::fcntl::*;
    use tempfile::NamedTempFile;

    /// Verify that `Flock::lock()` correctly obtains a lock, and subsequently unlocks upon drop.
    #[test]
    fn lock_and_drop() {
        // Get 2 `File` handles to same underlying file.
        let file1 = NamedTempFile::new().unwrap();
        let file2 = file1.reopen().unwrap();
        let file1 = file1.into_file();

        // Lock first handle
        let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();

        // Attempt to lock second handle
        let file2 = match Flock::lock(file2, FlockArg::LockExclusiveNonblock) {
            Ok(_) => panic!("Expected second exclusive lock to fail."),
            Err((f, _)) => f,
        };

        // Drop first lock
        std::mem::drop(lock1);

        // Attempt to lock second handle again (but successfully)
        if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() {
            panic!("Expected locking to be successful.");
        }
    }

    /// An exclusive lock can be downgraded
    #[test]
    fn downgrade() {
        let file1 = NamedTempFile::new().unwrap();
        let file2 = file1.reopen().unwrap();
        let file1 = file1.into_file();

        // Lock first handle
        let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();

        // Attempt to lock second handle
        let file2 = Flock::lock(file2, FlockArg::LockSharedNonblock)
            .unwrap_err()
            .0;

        // Downgrade the lock
        lock1.relock(FlockArg::LockShared).unwrap();

        // Attempt to lock second handle again (but successfully)
        Flock::lock(file2, FlockArg::LockSharedNonblock)
            .expect("Expected locking to be successful.");
    }

    /// Verify that `Flock::unlock()` correctly obtains unlocks.
    #[test]
    fn unlock() {
        // Get 2 `File` handles to same underlying file.
        let file1 = NamedTempFile::new().unwrap();
        let file2 = file1.reopen().unwrap();
        let file1 = file1.into_file();

        // Lock first handle
        let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();

        // Unlock and retain file so any erroneous flocks also remain present.
        let _file1 = lock1.unlock().unwrap();

        // Attempt to lock second handle.
        if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() {
            panic!("Expected locking to be successful.");
        }
    }

    /// A shared lock can be upgraded
    #[test]
    fn upgrade() {
        let file1 = NamedTempFile::new().unwrap();
        let file2 = file1.reopen().unwrap();
        let file3 = file1.reopen().unwrap();
        let file1 = file1.into_file();

        // Lock first handle
        let lock1 = Flock::lock(file1, FlockArg::LockShared).unwrap();

        // Attempt to lock second handle
        {
            Flock::lock(file2, FlockArg::LockSharedNonblock)
                .expect("Locking should've succeeded");
        }

        // Upgrade the lock
        lock1.relock(FlockArg::LockExclusive).unwrap();

        // Acquiring an additional shared lock should fail
        Flock::lock(file3, FlockArg::LockSharedNonblock)
            .expect_err("Should not have been able to lock the file");
    }
}

[ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge