pub async fn can(
        &mut self,
        mode: Mode,
        path: impl AsRef<std::path::Path>,
    ) -> Result<(), Error> {
        let path = path.as_ref();

        // okay, so, I know it's weird to use dd for this, but hear me out here.
        // we need a command that:
        //
        //  - will error if you try to read from or write to a directory
        //  - will error if you try to read from or write to a file you do not have access to
        //  - disinguishes between the two former cases
        //  - does not create the file if it does not exist
        //  - will succeed otherwise
        //
        // cat would work for read, but would read the entire file (no good)
        // stat would not tell us if we can actually read or write the file
        // touch won't work, as it also works on directories (no error)
        // ls won't work unless we want to parse its output (which we don't)
        // test won't work because it doesn't tell us _which_ test failed
        //
        // dd does everything we need!
        let mut cmd = self.session.command("dd");
        if mode.is_write() {
            cmd.arg("if=/dev/null")
                .arg(&format!("of={}", path.display()))
                .arg("bs=1")
                .arg("count=0")
                .arg("conv=nocreat,notrunc");
        } else {
            cmd.arg(&format!("if={}", path.display()))
                .arg("of=/dev/null")
                .arg("bs=1")
                .arg("count=1");
        }

        let test = cmd.output().await?;
        if test.status.success() {
            return Ok(());
        }

        // we _could_ fail here because the file does not exist.
        // if this is a write, we still need to check that the parent dir is writeable.

        // let's find out _why_ it failed
        let stderr = String::from_utf8_lossy(&test.stderr);
        let stderr = stderr.trim().trim_start_matches("dd: ");
        if stderr.contains("No such file or directory") {
            if !mode.is_write() {
                // a file that does not exist cannot be read
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::NotFound,
                    &*stderr,
                )));
            } else {
                // fall-through
            }
        } else if stderr.contains("Is a directory") {
            if mode.is_write() {
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::AlreadyExists,
                    &*stderr,
                )));
            } else {
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::Other,
                    &*stderr,
                )));
            }
        } else {
            return Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                &*stderr,
            )));
        }

        // file does not exist, but a write may be able to create it
        // we need to check if the target parent is a writeable dir
        let dir = if let Some(dir) = path.parent() {
            if dir == std::path::Path::new("") {
                std::path::Path::new(".")
            } else {
                dir
            }
        } else {
            // they're trying to write to / itself?
            return Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "trying to write to root as a file",
            )));
        };

        // https://github.com/sfackler/shell-escape/issues/5
        let dir = dir.to_string_lossy();

        let test = self
            .session
            .command("test")
            .arg("(")
            .arg("-d")
            .arg(&dir)
            .arg(")")
            .arg("-a")
            .arg("(")
            .arg("-w")
            .arg(&dir)
            .arg(")")
            .output()
            .await?;

        if test.status.success() {
            Ok(())
        } else if self
            .session
            .command("test")
            .arg("-e")
            .arg(&dir)
            .status()
            .await?
            .success()
        {
            Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "parent directory not writeable",
            )))
        } else {
            Err(Error::Remote(io::Error::new(
                io::ErrorKind::NotFound,
                "parent directory does not exist",
            )))
        }
    }
/// Check that the given file can be opened in the given mode.
///
/// This method does not change the remote file system, except where opening a file for
/// read/write alone causes changes (like the "last accessed" timestamp).
///
/// Note that this function is potentially racy. The permissions on the server could change
/// between when you check and when you start a subsequent operation, causing it to fail. It
/// can also produce false positives, such as if you are checking whether you can write to a
/// file on a read-only file system that you still have write permissions on.
///
/// Operations like [`read_from`](Sftp::read_from) and [`write_to`](Sftp::write_to) internally
/// perform similar checking to this method, so you do not need to call `can` before calling
/// those methods. The checking performed by `write_to` can also test its permissions by
/// actually attemping to create the remote file (since it is about to create one anyway), so
/// its checking is more reliable than what `can` can provide.
Check that the given file can be opened in the given mode.
This method does not change the remote file system, except where opening a file for
read/write alone causes changes (like the "last accessed" timestamp).

Note that this function is potentially racy. The permissions on the server could change
between when you check and when you start a subsequent operation, causing it to fail. It
can also produce false positives, such as if you are checking whether you can write to a
file on a read-only file system that you still have write permissions on.


Check that the given file can be opened in the given mode . This method does not change the remote file system except where opening a file for read / write alone causes changes ( like the " last accessed " timestamp ) . Note that this function is potentially racy . The permissions on the server could change between when you check and when you start a subsequent operation causing it to fail . It can also produce false positives such as if you are checking whether you can write to a file on a read - only file system that you still have write permissions on .
pub async fn can(
        &mut self,
        mode: Mode,
        path: impl AsRef<std::path::Path>,
    ) -> Result<(), Error> {
        let path = path.as_ref();
        // okay, so, I know it's weird to use dd for this, but hear me out here.
        // we need a command that:
        //
        //  - will error if you try to read from or write to a directory
        //  - will error if you try to read from or write to a file you do not have access to
        //  - disinguishes between the two former cases
        //  - does not create the file if it does not exist
        //  - will succeed otherwise
        //
        // cat would work for read, but would read the entire file (no good)
        // stat would not tell us if we can actually read or write the file
        // touch won't work, as it also works on directories (no error)
        // ls won't work unless we want to parse its output (which we don't)
        // test won't work because it doesn't tell us _which_ test failed
        //
        // dd does everything we need!
        let mut cmd = self.session.command("dd");
        if mode.is_write() {
            cmd.arg("if=/dev/null")
                .arg(&format!("of={}", path.display()))
                .arg("bs=1")
                .arg("count=0")
                .arg("conv=nocreat,notrunc");
        } else {
            cmd.arg(&format!("if={}", path.display()))
                .arg("of=/dev/null")
                .arg("bs=1")
                .arg("count=1");
        }
        let test = cmd.output().await?;
        if test.status.success() {
            return Ok(());
        }
        // we _could_ fail here because the file does not exist.
        // if this is a write, we still need to check that the parent dir is writeable.
        // let's find out _why_ it failed
        let stderr = String::from_utf8_lossy(&test.stderr);
        let stderr = stderr.trim().trim_start_matches("dd: ");
        if stderr.contains("No such file or directory") {
            if !mode.is_write() {
                // a file that does not exist cannot be read
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::NotFound,
                    &*stderr,
                )));
            } else {
                // fall-through
            }
        } else if stderr.contains("Is a directory") {
            if mode.is_write() {
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::AlreadyExists,
                    &*stderr,
                )));
            } else {
                return Err(Error::Remote(io::Error::new(
                    io::ErrorKind::Other,
                    &*stderr,
                )));
            }
        } else {
            return Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                &*stderr,
            )));
        }
        // file does not exist, but a write may be able to create it
        // we need to check if the target parent is a writeable dir
        let dir = if let Some(dir) = path.parent() {
            if dir == std::path::Path::new("") {
                std::path::Path::new(".")
            } else {
                dir
            }
        } else {
            // they're trying to write to / itself?
            return Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "trying to write to root as a file",
            )));
        };
        // https://github.com/sfackler/shell-escape/issues/5
        let dir = dir.to_string_lossy();
        let test = self
            .session
            .command("test")
            .arg("(")
            .arg("-d")
            .arg(&dir)
            .arg(")")
            .arg("-a")
            .arg("(")
            .arg("-w")
            .arg(&dir)
            .arg(")")
            .output()
            .await?;
        if test.status.success() {
            Ok(())
        } else if self
            .session
            .command("test")
            .arg("-e")
            .arg(&dir)
            .status()
            .await?
            .success()
        {
            Err(Error::Remote(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "parent directory not writeable",
            )))
        } else {
            Err(Error::Remote(io::Error::new(
                io::ErrorKind::NotFound,
                "parent directory does not exist",
            )))
        }
    }
pub async fn can ( & mut self , mode : Mode , path : impl AsRef < std :: path :: Path > , ) -> Result < ( ) , Error > { let path = path . as_ref ( ) ; // okay, so, I know it's weird to use dd for this, but hear me out here. // we need a command that: // //  - will error if you try to read from or write to a directory //  - will error if you try to read from or write to a file you do not have access to //  - disinguishes between the two former cases //  - does not create the file if it does not exist //  - will succeed otherwise // // cat would work for read, but would read the entire file (no good) // stat would not tell us if we can actually read or write the file // touch won't work, as it also works on directories (no error) // ls won't work unless we want to parse its output (which we don't) // test won't work because it doesn't tell us _which_ test failed // // dd does everything we need! let mut cmd = self . session . command ( " " ) ; if mode . is_write ( ) { cmd . arg ( " " ) . arg ( & format ! ( " " path display ( ) ) ) . arg ( " " ) . arg ( " " ) . arg ( " " ) ; } else { cmd . arg ( & format ! ( " " path display ( ) ) ) . arg ( " " ) . arg ( " " ) . arg ( " " ) ; } let test = cmd . output ( ) . await ? ; if test . status . success ( ) { return Ok ( ( ) ) ; } // we _could_ fail here because the file does not exist. // if this is a write, we still need to check that the parent dir is writeable. // let's find out _why_ it failed let stderr = String :: from_utf8_lossy ( & test . stderr ) ; let stderr = stderr . trim ( ) . trim_start_matches ( " " ) ; if stderr . contains ( " " ) { if ! mode . is_write ( ) { // a file that does not exist cannot be read return Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: NotFound , & * stderr , ) ) ) ; } else { // fall-through } } else if stderr . contains ( " " ) { if mode . is_write ( ) { return Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: AlreadyExists , & * stderr , ) ) ) ; } else { return Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: Other , & * stderr , ) ) ) ; } } else { return Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: PermissionDenied , & * stderr , ) ) ) ; } // file does not exist, but a write may be able to create it // we need to check if the target parent is a writeable dir let dir = if let Some ( dir ) = path . parent ( ) { if dir == std :: path :: Path :: new ( " " ) { std :: path :: Path :: new ( " " ) } else { dir } } else { // they're trying to write to / itself? return Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: PermissionDenied , " " , ) ) ) ; } ; // https://github.com/sfackler/shell-escape/issues/5 let dir = dir . to_string_lossy ( ) ; let test = self . session . command ( " " ) . arg ( " " ) . arg ( " " ) . arg ( & dir ) . arg ( " " ) . arg ( " " ) . arg ( " " ) . arg ( " " ) . arg ( & dir ) . arg ( " " ) . output ( ) . await ? ; if test . status . success ( ) { Ok ( ( ) ) } else if self . session . command ( " " ) . arg ( " " ) . arg ( & dir ) . status ( ) . await ? . success ( ) { Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: PermissionDenied , " " , ) ) ) } else { Err ( Error :: Remote ( io :: Error :: new ( io :: ErrorKind :: NotFound , " " , ) ) ) } }
Check that the given file can be opened in the given mode.
Check that the given file can be opened in the given mode .
&mut self
mode
Mode
path
impl AsRef<std::path::Path>
&mut self
mode
Mode
path
impl AsRef<std::path::Path>