Full Code of alexcrichton/ssh2-rs for AI

master d25991dd76dc cached
36 files
234.0 KB
60.7k tokens
584 symbols
1 requests
Download .txt
Showing preview only (245K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexcrichton/ssh2-rs
Branch: master
Commit: d25991dd76dc
Files: 36
Total size: 234.0 KB

Directory structure:
gitextract_dmgnez8a/

├── .github/
│   └── workflows/
│       ├── linux.yml
│       ├── macos.yml
│       └── windows.yml
├── .gitignore
├── .gitmodules
├── .mailmap
├── .travis.yml
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── libssh2-sys/
│   ├── .gitattributes
│   ├── Cargo.toml
│   ├── LICENSE-APACHE
│   ├── LICENSE-MIT
│   ├── build.rs
│   └── lib.rs
├── src/
│   ├── agent.rs
│   ├── channel.rs
│   ├── error.rs
│   ├── knownhosts.rs
│   ├── lib.rs
│   ├── listener.rs
│   ├── session.rs
│   ├── sftp.rs
│   └── util.rs
├── systest/
│   ├── Cargo.toml
│   ├── build.rs
│   └── src/
│       └── main.rs
└── tests/
    ├── all/
    │   ├── agent.rs
    │   ├── channel.rs
    │   ├── knownhosts.rs
    │   ├── main.rs
    │   ├── session.rs
    │   └── sftp.rs
    └── run_integration_tests.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/linux.yml
================================================
name: linux

on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04, ubuntu-24.04]
        rust_toolchain: [stable, beta]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v1
    - name: Install Rust
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: ${{ matrix.rust_toolchain }}
    - name: Build and test
      run: |
        rustc -V
        cargo -V
        cargo build
        tests/run_integration_tests.sh
        rustdoc --test README.md -L target
        cargo run --manifest-path systest/Cargo.toml


================================================
FILE: .github/workflows/macos.yml
================================================
name: macOS

on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        os: [macos-14, macos-15, macos-26]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v1
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    - name: Build and test
      run: |
        rustc -V
        cargo -V
        cargo build
        tests/run_integration_tests.sh
        rustdoc --test README.md -L target
        cargo run --manifest-path systest/Cargo.toml


================================================
FILE: .github/workflows/windows.yml
================================================
name: Windows

on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        os: [windows-2022, windows-2025]
        env:
        - TARGET: x86_64-pc-windows-msvc
        - TARGET: i686-pc-windows-msvc
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v1
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        target: ${{ matrix.env.TARGET }}
    - name: Build and test
      env:
        TARGET: ${{ matrix.env.TARGET }}
      run: |
        rustc -V
        cargo -V
        cargo test --no-run --target %TARGET%
        cargo run --manifest-path systest/Cargo.toml --target %TARGET%
        cargo test --no-run --target %TARGET% --features openssl-on-win32,vendored-openssl
      shell: cmd


================================================
FILE: .gitignore
================================================
.*.sw*
/target/
libssh2-sys/target/
/Cargo.lock
/tests/sshd


================================================
FILE: .gitmodules
================================================
[submodule "libssh2-sys/libssh2"]
	path = libssh2-sys/libssh2
	url = https://github.com/libssh2/libssh2
	branch = master


================================================
FILE: .mailmap
================================================
<ga29smith@gmail.com> <gabriel.smith@precisionot.com>


================================================
FILE: .travis.yml
================================================
language: rust
sudo: required

matrix:
  include:
    - rust: 1.36.0
    - rust: stable
    - rust: beta
    - rust: nightly

#    - name: "master doc to gh-pages"
#     rust: nightly
#     script:
#       - cargo doc --no-deps
#       - cargo doc --no-deps --manifest-path libssh2-sys/Cargo.toml
#     deploy:
#       provider: script
#       script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out)
#       skip_cleanup: true
#       on:
#         branch: master

script:
  - cargo build
  - tests/run_integration_tests.sh
  - rustdoc --test README.md -L target
  - cargo run --manifest-path systest/Cargo.toml

notifications:
  email:
    on_success: never


================================================
FILE: Cargo.toml
================================================
[package]
name = "ssh2"
version = "0.9.5"
authors = ["Alex Crichton <alex@alexcrichton.com>", "Wez Furlong <wez@wezfurlong.org>", "Matteo Bigoi <bigo@crisidev.org>"]
license = "MIT OR Apache-2.0"
keywords = ["ssh"]
readme = "README.md"
repository = "https://github.com/alexcrichton/ssh2-rs"
homepage = "https://github.com/alexcrichton/ssh2-rs"
documentation = "https://docs.rs/ssh2"
description = """
Bindings to libssh2 for interacting with SSH servers and executing remote
commands, forwarding local ports, etc.
"""

[features]
vendored-openssl = ["libssh2-sys/vendored-openssl"]
openssl-on-win32 = ["libssh2-sys/openssl-on-win32"]

[dependencies]
bitflags = "2"
libc = "0.2"
libssh2-sys = { path = "libssh2-sys", version = "0.3.1" }
parking_lot = "0.12"

[dev-dependencies]
tempfile = "3"

[workspace]
members = ['systest']


================================================
FILE: LICENSE-APACHE
================================================
                              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.


================================================
FILE: LICENSE-MIT
================================================
Copyright (c) 2014 Alex Crichton

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.


================================================
FILE: README.md
================================================
# ssh2-rs

[![Build Status](https://github.com/alexcrichton/ssh2-rs/workflows/linux/badge.svg)](https://github.com/alexcrichton/ssh2-rs/actions?workflow=linux)
[![Build Status](https://github.com/alexcrichton/ssh2-rs/workflows/Windows/badge.svg)](https://github.com/alexcrichton/ssh2-rs/actions?workflow=Windows)
[![Build Status](https://github.com/alexcrichton/ssh2-rs/workflows/macOS/badge.svg)](https://github.com/alexcrichton/ssh2-rs/actions?workflow=macOS)

[Documentation](https://docs.rs/ssh2)

Rust bindings to libssh2, an ssh client library.

## Usage

```toml
# Cargo.toml
[dependencies]
ssh2 = "0.9"
```

## Building on OSX 10.10+

This library depends on OpenSSL. To get OpenSSL working follow the
[`openssl` crate's instructions](https://github.com/sfackler/rust-openssl#macos).

Starting with version `0.4` of `ssh2`, you can enable the `vendored-openssl` feature
to have `libssh2` built against a statically built version of openssl as [described
here](https://docs.rs/openssl/0.10.24/openssl/#vendored)

# License

This project is licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
   http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or
   http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.


================================================
FILE: libssh2-sys/.gitattributes
================================================
# apparently libssh2 has trouble with CRLF, but of course only on windows
* text eol=lf


================================================
FILE: libssh2-sys/Cargo.toml
================================================
[package]
name = "libssh2-sys"
version = "0.3.1"
authors = ["Alex Crichton <alex@alexcrichton.com>", "Wez Furlong <wez@wezfurlong.org>", "Matteo Bigoi <bigo@crisidev.org>"]
links = "ssh2"
build = "build.rs"
license = "MIT OR Apache-2.0"
repository = "https://github.com/alexcrichton/ssh2-rs"
documentation = "https://docs.rs/libssh2-sys"
description = "Native bindings to the libssh2 library"

[lib]
name = "libssh2_sys"
path = "lib.rs"

[features]
vendored-openssl = ["openssl-sys/vendored"]
zlib-ng-compat = ["libz-sys/zlib-ng"]
openssl-on-win32 = ["openssl-sys"]

[dependencies]
libc = "0.2"
libz-sys = { version = "1.1.0", default-features = false, features = ["libc"] }

[target."cfg(unix)".dependencies]
openssl-sys = "0.9.35"

[target."cfg(windows)".dependencies]
openssl-sys = { version="0.9.35", optional = true }

[build-dependencies]
pkg-config = "0.3.11"
cc = "1.0.25"

[target.'cfg(target_env = "msvc")'.build-dependencies]
vcpkg = "0.2"


================================================
FILE: libssh2-sys/LICENSE-APACHE
================================================
                              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.


================================================
FILE: libssh2-sys/LICENSE-MIT
================================================
Copyright (c) 2014 Alex Crichton

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.


================================================
FILE: libssh2-sys/build.rs
================================================
extern crate cc;
extern crate pkg_config;

#[cfg(target_env = "msvc")]
extern crate vcpkg;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    let zlib_ng_compat = env::var("CARGO_FEATURE_ZLIB_NG_COMPAT").is_ok();

    if !zlib_ng_compat && try_vcpkg() {
        return;
    }

    // The system copy of libssh2 is not used by default because it
    // can lead to having two copies of libssl loaded at once.
    // See https://github.com/alexcrichton/ssh2-rs/pull/88
    println!("cargo:rerun-if-env-changed=LIBSSH2_SYS_USE_PKG_CONFIG");
    if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() {
        if zlib_ng_compat {
            panic!("LIBSSH2_SYS_USE_PKG_CONFIG set, but cannot use zlib-ng-compat with system libssh2");
        }
        if let Ok(lib) = pkg_config::find_library("libssh2") {
            for path in &lib.include_paths {
                println!("cargo:include={}", path.display());
            }
            return;
        }
    }

    if !Path::new("libssh2/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init"])
            .status();
    }

    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let mut cfg = cc::Build::new();

    let include = dst.join("include");
    println!("cargo:include={}", include.display());
    println!("cargo:root={}", dst.display());
    let build = dst.join("build");
    cfg.out_dir(&build);
    fs::create_dir_all(&build).unwrap();
    fs::create_dir_all(&include).unwrap();

    fs::copy("libssh2/include/libssh2.h", include.join("libssh2.h")).unwrap();
    fs::copy(
        "libssh2/include/libssh2_publickey.h",
        include.join("libssh2_publickey.h"),
    )
    .unwrap();
    fs::copy(
        "libssh2/include/libssh2_sftp.h",
        include.join("libssh2_sftp.h"),
    )
    .unwrap();

    cfg.file("libssh2/src/agent.c")
        .file("libssh2/src/bcrypt_pbkdf.c")
        .file("libssh2/src/blowfish.c")
        .file("libssh2/src/chacha.c")
        .file("libssh2/src/channel.c")
        .file("libssh2/src/cipher-chachapoly.c")
        .file("libssh2/src/comp.c")
        .file("libssh2/src/crypt.c")
        .file("libssh2/src/crypto.c")
        .file("libssh2/src/global.c")
        .file("libssh2/src/hostkey.c")
        .file("libssh2/src/keepalive.c")
        .file("libssh2/src/kex.c")
        .file("libssh2/src/knownhost.c")
        .file("libssh2/src/mac.c")
        .file("libssh2/src/misc.c")
        .file("libssh2/src/packet.c")
        .file("libssh2/src/pem.c")
        .file("libssh2/src/poly1305.c")
        .file("libssh2/src/publickey.c")
        .file("libssh2/src/scp.c")
        .file("libssh2/src/session.c")
        .file("libssh2/src/sftp.c")
        .file("libssh2/src/transport.c")
        .file("libssh2/src/userauth.c")
        .file("libssh2/src/userauth_kbd_packet.c")
        .include(&include)
        .include("libssh2/src");

    cfg.define("HAVE_LONGLONG", None);

    if target.contains("windows") {
        cfg.include("libssh2/win32");
        cfg.define("LIBSSH2_WIN32", None);
        cfg.file("libssh2/src/agent_win.c");

        if env::var_os("CARGO_FEATURE_OPENSSL_ON_WIN32").is_some() {
            cfg.define("LIBSSH2_OPENSSL", None);
            cfg.define("HAVE_EVP_AES_128_CTR", None);
            let lib_prefix = if target.contains("windows-msvc") {
                "lib"
            } else {
                ""
            };
            println!("cargo:rustc-link-lib=static={lib_prefix}ssl");
            println!("cargo:rustc-link-lib=static={lib_prefix}crypto");
            println!("cargo:rustc-link-lib=advapi32");
        } else {
            cfg.define("LIBSSH2_WINCNG", None);
        }
    } else {
        cfg.flag("-fvisibility=hidden");
        cfg.define("HAVE_SNPRINTF", None);
        cfg.define("HAVE_UNISTD_H", None);
        cfg.define("HAVE_INTTYPES_H", None);
        cfg.define("HAVE_STDLIB_H", None);
        cfg.define("HAVE_SYS_SELECT_H", None);
        cfg.define("HAVE_SYS_SOCKET_H", None);
        cfg.define("HAVE_SYS_IOCTL_H", None);
        cfg.define("HAVE_SYS_TIME_H", None);
        cfg.define("HAVE_SYS_UN_H", None);
        cfg.define("HAVE_O_NONBLOCK", None);
        cfg.define("LIBSSH2_OPENSSL", None);
        cfg.define("HAVE_LIBCRYPT32", None);
        cfg.define("HAVE_EVP_AES_128_CTR", None);
        cfg.define("HAVE_POLL", None);
        cfg.define("HAVE_GETTIMEOFDAY", None);

        // Create `libssh2_config.h`
        let config = fs::read_to_string("libssh2/src/libssh2_config_cmake.h.in").unwrap();
        let config = config
            .lines()
            .filter(|l| !l.contains("#cmakedefine"))
            .collect::<Vec<_>>()
            .join("\n");
        fs::write(build.join("libssh2_config.h"), &config).unwrap();
        cfg.include(&build);
    }

    /* Enable newer diffie-hellman-group-exchange-sha1 syntax */
    cfg.define("LIBSSH2_DH_GEX_NEW", None);

    cfg.define("LIBSSH2_HAVE_ZLIB", None);

    if profile.contains("debug") {
        cfg.define("LIBSSH2DEBUG", None);
    }

    println!("cargo:rerun-if-env-changed=DEP_Z_INCLUDE");
    if let Some(path) = env::var_os("DEP_Z_INCLUDE") {
        cfg.include(path);
    }

    println!("cargo:rerun-if-env-changed=DEP_OPENSSL_INCLUDE");
    if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") {
        if let Some(path) = env::split_paths(&path).next() {
            if let Some(path) = path.to_str() {
                if path.len() > 0 {
                    cfg.include(path);
                }
            }
        }
    }

    let libssh2h = fs::read_to_string("libssh2/include/libssh2.h").unwrap();
    let version_line = libssh2h
        .lines()
        .find(|l| l.contains("LIBSSH2_VERSION"))
        .unwrap();
    let version = &version_line[version_line.find('"').unwrap() + 1..version_line.len() - 1];

    let pkgconfig = dst.join("lib/pkgconfig");
    fs::create_dir_all(&pkgconfig).unwrap();
    fs::write(
        pkgconfig.join("libssh2.pc"),
        fs::read_to_string("libssh2/libssh2.pc.in")
            .unwrap()
            .replace("@prefix@", dst.to_str().unwrap())
            .replace("@exec_prefix@", "")
            .replace("@libdir@", dst.join("lib").to_str().unwrap())
            .replace("@includedir@", include.to_str().unwrap())
            .replace("@LIBS@", "")
            .replace("@LIBSREQUIRED@", "")
            .replace("@LIBSSH2VER@", version),
    )
    .unwrap();

    cfg.warnings(false);
    cfg.compile("ssh2");

    if target.contains("windows") {
        println!("cargo:rustc-link-lib=bcrypt");
        println!("cargo:rustc-link-lib=crypt32");
        println!("cargo:rustc-link-lib=user32");
        println!("cargo:rustc-link-lib=ntdll");
    }
}

#[cfg(not(target_env = "msvc"))]
fn try_vcpkg() -> bool {
    false
}

#[cfg(target_env = "msvc")]
fn try_vcpkg() -> bool {
    vcpkg::Config::new()
        .emit_includes(true)
        .probe("libssh2")
        .map(|_| {
            // found libssh2 which depends on openssl and zlib
            vcpkg::Config::new()
                .lib_name("libssl")
                .lib_name("libcrypto")
                .probe("openssl")
                .or_else(|_| {
                    // openssl 1.1 was not found, try openssl 1.0
                    vcpkg::Config::new()
                        .lib_name("libeay32")
                        .lib_name("ssleay32")
                        .probe("openssl")
                })
                .expect(
                    "configured libssh2 from vcpkg but could not \
                     find openssl libraries that it depends on",
                );

            vcpkg::Config::new()
                .lib_names("zlib", "zlib1")
                .probe("zlib")
                .expect(
                    "configured libssh2 from vcpkg but could not \
                     find the zlib library that it depends on",
                );

            println!("cargo:rustc-link-lib=crypt32");
            println!("cargo:rustc-link-lib=gdi32");
            println!("cargo:rustc-link-lib=user32");
        })
        .is_ok()
}


================================================
FILE: libssh2-sys/lib.rs
================================================
#![doc(html_root_url = "http://alexcrichton.com/ssh2-rs")]
#![allow(bad_style)]
#![allow(unused_extern_crates)]

extern crate libc;

extern crate libz_sys;
#[cfg(unix)]
extern crate openssl_sys;

use libc::ssize_t;
use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t};

pub const SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT: c_int = 1;
pub const SSH_DISCONNECT_PROTOCOL_ERROR: c_int = 2;
pub const SSH_DISCONNECT_KEY_EXCHANGE_FAILED: c_int = 3;
pub const SSH_DISCONNECT_RESERVED: c_int = 4;
pub const SSH_DISCONNECT_MAC_ERROR: c_int = 5;
pub const SSH_DISCONNECT_COMPRESSION_ERROR: c_int = 6;
pub const SSH_DISCONNECT_SERVICE_NOT_AVAILABLE: c_int = 7;
pub const SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED: c_int = 8;
pub const SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE: c_int = 9;
pub const SSH_DISCONNECT_CONNECTION_LOST: c_int = 10;
pub const SSH_DISCONNECT_BY_APPLICATION: c_int = 11;
pub const SSH_DISCONNECT_TOO_MANY_CONNECTIONS: c_int = 12;
pub const SSH_DISCONNECT_AUTH_CANCELLED_BY_USER: c_int = 13;
pub const SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE: c_int = 14;
pub const SSH_DISCONNECT_ILLEGAL_USER_NAME: c_int = 15;

pub const LIBSSH2_FLAG_SIGPIPE: c_int = 1;
pub const LIBSSH2_FLAG_COMPRESS: c_int = 2;

pub const LIBSSH2_HOSTKEY_TYPE_UNKNOWN: c_int = 0;
pub const LIBSSH2_HOSTKEY_TYPE_RSA: c_int = 1;
pub const LIBSSH2_HOSTKEY_TYPE_DSS: c_int = 2;
pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_256: c_int = 3;
pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_384: c_int = 4;
pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_521: c_int = 5;
pub const LIBSSH2_HOSTKEY_TYPE_ED25519: c_int = 6;

pub const LIBSSH2_METHOD_KEX: c_int = 0;
pub const LIBSSH2_METHOD_HOSTKEY: c_int = 1;
pub const LIBSSH2_METHOD_CRYPT_CS: c_int = 2;
pub const LIBSSH2_METHOD_CRYPT_SC: c_int = 3;
pub const LIBSSH2_METHOD_MAC_CS: c_int = 4;
pub const LIBSSH2_METHOD_MAC_SC: c_int = 5;
pub const LIBSSH2_METHOD_COMP_CS: c_int = 6;
pub const LIBSSH2_METHOD_COMP_SC: c_int = 7;
pub const LIBSSH2_METHOD_LANG_CS: c_int = 8;
pub const LIBSSH2_METHOD_LANG_SC: c_int = 9;
pub const LIBSSH2_METHOD_SIGN_ALGO: c_int = 10;

pub const LIBSSH2_CHANNEL_PACKET_DEFAULT: c_uint = 32768;
pub const LIBSSH2_CHANNEL_WINDOW_DEFAULT: c_uint = 2 * 1024 * 1024;

pub const LIBSSH2_ERROR_BANNER_RECV: c_int = -2;
pub const LIBSSH2_ERROR_BANNER_SEND: c_int = -3;
pub const LIBSSH2_ERROR_INVALID_MAC: c_int = -4;
pub const LIBSSH2_ERROR_KEX_FAILURE: c_int = -5;
pub const LIBSSH2_ERROR_ALLOC: c_int = -6;
pub const LIBSSH2_ERROR_SOCKET_SEND: c_int = -7;
pub const LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE: c_int = -8;
pub const LIBSSH2_ERROR_TIMEOUT: c_int = -9;
pub const LIBSSH2_ERROR_HOSTKEY_INIT: c_int = -10;
pub const LIBSSH2_ERROR_HOSTKEY_SIGN: c_int = -11;
pub const LIBSSH2_ERROR_DECRYPT: c_int = -12;
pub const LIBSSH2_ERROR_SOCKET_DISCONNECT: c_int = -13;
pub const LIBSSH2_ERROR_PROTO: c_int = -14;
pub const LIBSSH2_ERROR_PASSWORD_EXPIRED: c_int = -15;
pub const LIBSSH2_ERROR_FILE: c_int = -16;
pub const LIBSSH2_ERROR_METHOD_NONE: c_int = -17;
pub const LIBSSH2_ERROR_AUTHENTICATION_FAILED: c_int = -18;
pub const LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: c_int = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
pub const LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: c_int = -19;
pub const LIBSSH2_ERROR_CHANNEL_OUTOFORDER: c_int = -20;
pub const LIBSSH2_ERROR_CHANNEL_FAILURE: c_int = -21;
pub const LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED: c_int = -22;
pub const LIBSSH2_ERROR_CHANNEL_UNKNOWN: c_int = -23;
pub const LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED: c_int = -24;
pub const LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED: c_int = -25;
pub const LIBSSH2_ERROR_CHANNEL_CLOSED: c_int = -26;
pub const LIBSSH2_ERROR_CHANNEL_EOF_SENT: c_int = -27;
pub const LIBSSH2_ERROR_SCP_PROTOCOL: c_int = -28;
pub const LIBSSH2_ERROR_ZLIB: c_int = -29;
pub const LIBSSH2_ERROR_SOCKET_TIMEOUT: c_int = -30;
pub const LIBSSH2_ERROR_SFTP_PROTOCOL: c_int = -31;
pub const LIBSSH2_ERROR_REQUEST_DENIED: c_int = -32;
pub const LIBSSH2_ERROR_METHOD_NOT_SUPPORTED: c_int = -33;
pub const LIBSSH2_ERROR_INVAL: c_int = -34;
pub const LIBSSH2_ERROR_INVALID_POLL_TYPE: c_int = -35;
pub const LIBSSH2_ERROR_PUBLICKEY_PROTOCOL: c_int = -36;
pub const LIBSSH2_ERROR_EAGAIN: c_int = -37;
pub const LIBSSH2_ERROR_BUFFER_TOO_SMALL: c_int = -38;
pub const LIBSSH2_ERROR_BAD_USE: c_int = -39;
pub const LIBSSH2_ERROR_COMPRESS: c_int = -40;
pub const LIBSSH2_ERROR_OUT_OF_BOUNDARY: c_int = -41;
pub const LIBSSH2_ERROR_AGENT_PROTOCOL: c_int = -42;
pub const LIBSSH2_ERROR_SOCKET_RECV: c_int = -43;
pub const LIBSSH2_ERROR_ENCRYPT: c_int = -44;
pub const LIBSSH2_ERROR_BAD_SOCKET: c_int = -45;
pub const LIBSSH2_ERROR_KNOWN_HOSTS: c_int = -46;
pub const LIBSSH2_ERROR_CHANNEL_WINDOW_FULL: c_int = -47;
pub const LIBSSH2_ERROR_KEYFILE_AUTH_FAILED: c_int = -48;
pub const LIBSSH2_ERROR_RANDGEN: c_int = -49;
pub const LIBSSH2_ERROR_MISSING_USERAUTH_BANNER: c_int = -50;
pub const LIBSSH2_ERROR_ALGO_UNSUPPORTED: c_int = -51;

pub const LIBSSH2_FX_EOF: c_int = 1;
pub const LIBSSH2_FX_NO_SUCH_FILE: c_int = 2;
pub const LIBSSH2_FX_PERMISSION_DENIED: c_int = 3;
pub const LIBSSH2_FX_FAILURE: c_int = 4;
pub const LIBSSH2_FX_BAD_MESSAGE: c_int = 5;
pub const LIBSSH2_FX_NO_CONNECTION: c_int = 6;
pub const LIBSSH2_FX_CONNECTION_LOST: c_int = 7;
pub const LIBSSH2_FX_OP_UNSUPPORTED: c_int = 8;
pub const LIBSSH2_FX_INVALID_HANDLE: c_int = 9;
pub const LIBSSH2_FX_NO_SUCH_PATH: c_int = 10;
pub const LIBSSH2_FX_FILE_ALREADY_EXISTS: c_int = 11;
pub const LIBSSH2_FX_WRITE_PROTECT: c_int = 12;
pub const LIBSSH2_FX_NO_MEDIA: c_int = 13;
pub const LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: c_int = 14;
pub const LIBSSH2_FX_QUOTA_EXCEEDED: c_int = 15;
pub const LIBSSH2_FX_UNKNOWN_PRINCIPAL: c_int = 16;
pub const LIBSSH2_FX_LOCK_CONFLICT: c_int = 17;
pub const LIBSSH2_FX_DIR_NOT_EMPTY: c_int = 18;
pub const LIBSSH2_FX_NOT_A_DIRECTORY: c_int = 19;
pub const LIBSSH2_FX_INVALID_FILENAME: c_int = 20;
pub const LIBSSH2_FX_LINK_LOOP: c_int = 21;

pub const LIBSSH2_HOSTKEY_HASH_MD5: c_int = 1;
pub const LIBSSH2_HOSTKEY_HASH_SHA1: c_int = 2;
pub const LIBSSH2_HOSTKEY_HASH_SHA256: c_int = 3;

pub const LIBSSH2_KNOWNHOST_FILE_OPENSSH: c_int = 1;

pub const LIBSSH2_KNOWNHOST_CHECK_MATCH: c_int = 0;
pub const LIBSSH2_KNOWNHOST_CHECK_MISMATCH: c_int = 1;
pub const LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: c_int = 2;
pub const LIBSSH2_KNOWNHOST_CHECK_FAILURE: c_int = 3;

pub const LIBSSH2_KNOWNHOST_TYPE_PLAIN: c_int = 1;
pub const LIBSSH2_KNOWNHOST_TYPE_SHA1: c_int = 2;
pub const LIBSSH2_KNOWNHOST_TYPE_CUSTOM: c_int = 3;
pub const LIBSSH2_KNOWNHOST_KEYENC_RAW: c_int = 1 << 16;
pub const LIBSSH2_KNOWNHOST_KEYENC_BASE64: c_int = 2 << 16;
pub const LIBSSH2_KNOWNHOST_KEY_RSA1: c_int = 1 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_SSHRSA: c_int = 2 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_SSHDSS: c_int = 3 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_256: c_int = 4 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_384: c_int = 5 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_521: c_int = 6 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_ED25519: c_int = 7 << 18;
pub const LIBSSH2_KNOWNHOST_KEY_UNKNOWN: c_int = 15 << 18;

pub const LIBSSH2_FXF_READ: c_ulong = 0x00000001;
pub const LIBSSH2_FXF_WRITE: c_ulong = 0x00000002;
pub const LIBSSH2_FXF_APPEND: c_ulong = 0x00000004;
pub const LIBSSH2_FXF_CREAT: c_ulong = 0x00000008;
pub const LIBSSH2_FXF_TRUNC: c_ulong = 0x00000010;
pub const LIBSSH2_FXF_EXCL: c_ulong = 0x00000020;

pub const LIBSSH2_SFTP_OPENFILE: c_int = 0;
pub const LIBSSH2_SFTP_OPENDIR: c_int = 1;

pub const LIBSSH2_SFTP_ATTR_SIZE: c_ulong = 0x00000001;
pub const LIBSSH2_SFTP_ATTR_UIDGID: c_ulong = 0x00000002;
pub const LIBSSH2_SFTP_ATTR_PERMISSIONS: c_ulong = 0x00000004;
pub const LIBSSH2_SFTP_ATTR_ACMODTIME: c_ulong = 0x00000008;
pub const LIBSSH2_SFTP_ATTR_EXTENDED: c_ulong = 0x80000000;

pub const LIBSSH2_SFTP_STAT: c_int = 0;
pub const LIBSSH2_SFTP_LSTAT: c_int = 1;
pub const LIBSSH2_SFTP_SETSTAT: c_int = 2;

pub const LIBSSH2_SFTP_SYMLINK: c_int = 0;
pub const LIBSSH2_SFTP_READLINK: c_int = 1;
pub const LIBSSH2_SFTP_REALPATH: c_int = 2;

pub const LIBSSH2_SFTP_RENAME_OVERWRITE: c_long = 0x1;
pub const LIBSSH2_SFTP_RENAME_ATOMIC: c_long = 0x2;
pub const LIBSSH2_SFTP_RENAME_NATIVE: c_long = 0x4;

pub const LIBSSH2_INIT_NO_CRYPTO: c_int = 0x1;

pub const LIBSSH2_SFTP_S_IFMT: c_ulong = 0o170000;
pub const LIBSSH2_SFTP_S_IFIFO: c_ulong = 0o010000;
pub const LIBSSH2_SFTP_S_IFCHR: c_ulong = 0o020000;
pub const LIBSSH2_SFTP_S_IFDIR: c_ulong = 0o040000;
pub const LIBSSH2_SFTP_S_IFBLK: c_ulong = 0o060000;
pub const LIBSSH2_SFTP_S_IFREG: c_ulong = 0o100000;
pub const LIBSSH2_SFTP_S_IFLNK: c_ulong = 0o120000;
pub const LIBSSH2_SFTP_S_IFSOCK: c_ulong = 0o140000;

pub const LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL: c_int = 0;
pub const LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE: c_int = 1;
pub const LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE: c_int = 2;

pub const LIBSSH2_SESSION_BLOCK_INBOUND: c_int = 1;
pub const LIBSSH2_SESSION_BLOCK_OUTBOUND: c_int = 2;

pub const  LIBSSH2_TRACE_TRANS : c_int = 1<<1;
pub const  LIBSSH2_TRACE_KEX   : c_int = 1<<2;
pub const  LIBSSH2_TRACE_AUTH  : c_int = 1<<3;
pub const  LIBSSH2_TRACE_CONN  : c_int = 1<<4;
pub const  LIBSSH2_TRACE_SCP   : c_int = 1<<5;
pub const  LIBSSH2_TRACE_SFTP  : c_int = 1<<6;
pub const  LIBSSH2_TRACE_ERROR : c_int = 1<<7;
pub const  LIBSSH2_TRACE_PUBLICKEY : c_int = 1<<8;
pub const  LIBSSH2_TRACE_SOCKET : c_int = 1<<9;
pub enum LIBSSH2_SESSION {}
pub enum LIBSSH2_AGENT {}
pub enum LIBSSH2_CHANNEL {}
pub enum LIBSSH2_LISTENER {}
pub enum LIBSSH2_KNOWNHOSTS {}
pub enum LIBSSH2_SFTP {}
pub enum LIBSSH2_SFTP_HANDLE {}

pub type libssh2_int64_t = i64;
pub type libssh2_uint64_t = u64;

// libssh2_struct_stat is a typedef for libc::stat on all platforms, however,
// Windows has a bunch of legacy around struct stat that makes things more
// complicated to validate with systest.
// The most reasonable looking solution to this is a newtype that derefs
// to libc::stat.
// We cannot use `pub struct libssh2_struct_stat(pub libc::stat)` because
// that triggers a `no tuple structs in FFI` error.
#[repr(C)]
pub struct libssh2_struct_stat(libc::stat);

impl std::ops::Deref for libssh2_struct_stat {
    type Target = libc::stat;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[repr(C)]
pub struct libssh2_agent_publickey {
    pub magic: c_uint,
    pub node: *mut c_void,
    pub blob: *mut c_uchar,
    pub blob_len: size_t,
    pub comment: *mut c_char,
}

#[repr(C)]
pub struct libssh2_knownhost {
    pub magic: c_uint,
    pub node: *mut c_void,
    pub name: *mut c_char,
    pub key: *mut c_char,
    pub typemask: c_int,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct LIBSSH2_SFTP_ATTRIBUTES {
    pub flags: c_ulong,
    pub filesize: libssh2_uint64_t,
    pub uid: c_ulong,
    pub gid: c_ulong,
    pub permissions: c_ulong,
    pub atime: c_ulong,
    pub mtime: c_ulong,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct LIBSSH2_SFTP_STATVFS {
    pub f_bsize: libssh2_uint64_t,
    pub f_frsize: libssh2_uint64_t,
    pub f_blocks: libssh2_uint64_t,
    pub f_bfree: libssh2_uint64_t,
    pub f_bavail: libssh2_uint64_t,
    pub f_files: libssh2_uint64_t,
    pub f_ffree: libssh2_uint64_t,
    pub f_favail: libssh2_uint64_t,
    pub f_fsid: libssh2_uint64_t,
    pub f_flag: libssh2_uint64_t,
    pub f_namemax: libssh2_uint64_t,
}

pub type LIBSSH2_ALLOC_FUNC = extern "C" fn(size_t, *mut *mut c_void) -> *mut c_void;
pub type LIBSSH2_FREE_FUNC = extern "C" fn(*mut c_void, *mut *mut c_void);
pub type LIBSSH2_REALLOC_FUNC = extern "C" fn(*mut c_void, size_t, *mut *mut c_void) -> *mut c_void;
pub type LIBSSH2_PASSWD_CHANGEREQ_FUNC = extern "C" fn(
    sess: *mut LIBSSH2_SESSION,
    newpw: *mut *mut c_char,
    newpw_len: *mut c_int,
    abstrakt: *mut *mut c_void,
);

pub type LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC = extern "C" fn(
    username: *const c_char,
    username_len: c_int,
    instruction: *const c_char,
    instruction_len: c_int,
    num_prompts: c_int,
    prompts: *const LIBSSH2_USERAUTH_KBDINT_PROMPT,
    responses: *mut LIBSSH2_USERAUTH_KBDINT_RESPONSE,
    abstrakt: *mut *mut c_void,
);

#[repr(C)]
pub struct LIBSSH2_USERAUTH_KBDINT_PROMPT {
    pub text: *mut c_uchar,
    pub length: size_t,
    pub echo: c_uchar,
}

#[repr(C)]
pub struct LIBSSH2_USERAUTH_KBDINT_RESPONSE {
    pub text: *mut c_char,
    pub length: c_uint,
}

#[cfg(unix)]
pub type libssh2_socket_t = c_int;
#[cfg(all(windows, target_pointer_width = "32"))]
pub type libssh2_socket_t = u32;
#[cfg(all(windows, target_pointer_width = "64"))]
pub type libssh2_socket_t = u64;

extern "C" {
    // misc
    pub fn libssh2_init(flag: c_int) -> c_int;
    pub fn libssh2_exit();
    pub fn libssh2_free(sess: *mut LIBSSH2_SESSION, ptr: *mut c_void);
    pub fn libssh2_hostkey_hash(session: *mut LIBSSH2_SESSION, hash_type: c_int) -> *const c_char;
    pub fn libssh2_trace(session: *mut LIBSSH2_SESSION, bitmask: c_int) -> c_int;

    // session
    pub fn libssh2_session_init_ex(
        alloc: Option<LIBSSH2_ALLOC_FUNC>,
        free: Option<LIBSSH2_FREE_FUNC>,
        realloc: Option<LIBSSH2_REALLOC_FUNC>,
        abstrakt: *mut c_void,
    ) -> *mut LIBSSH2_SESSION;
    pub fn libssh2_session_abstract(session: *mut LIBSSH2_SESSION) -> *mut *mut c_void;
    pub fn libssh2_session_free(sess: *mut LIBSSH2_SESSION) -> c_int;
    pub fn libssh2_session_banner_get(sess: *mut LIBSSH2_SESSION) -> *const c_char;
    pub fn libssh2_session_banner_set(sess: *mut LIBSSH2_SESSION, banner: *const c_char) -> c_int;
    pub fn libssh2_session_disconnect_ex(
        sess: *mut LIBSSH2_SESSION,
        reason: c_int,
        description: *const c_char,
        lang: *const c_char,
    ) -> c_int;
    pub fn libssh2_session_flag(sess: *mut LIBSSH2_SESSION, flag: c_int, value: c_int) -> c_int;
    pub fn libssh2_session_get_blocking(session: *mut LIBSSH2_SESSION) -> c_int;
    pub fn libssh2_session_get_timeout(sess: *mut LIBSSH2_SESSION) -> c_long;
    pub fn libssh2_session_hostkey(
        sess: *mut LIBSSH2_SESSION,
        len: *mut size_t,
        kind: *mut c_int,
    ) -> *const c_char;
    pub fn libssh2_session_method_pref(
        sess: *mut LIBSSH2_SESSION,
        method_type: c_int,
        prefs: *const c_char,
    ) -> c_int;
    pub fn libssh2_session_methods(sess: *mut LIBSSH2_SESSION, method_type: c_int)
        -> *const c_char;
    pub fn libssh2_session_set_blocking(session: *mut LIBSSH2_SESSION, blocking: c_int);
    pub fn libssh2_session_set_timeout(session: *mut LIBSSH2_SESSION, timeout: c_long);
    pub fn libssh2_session_supported_algs(
        session: *mut LIBSSH2_SESSION,
        method_type: c_int,
        algs: *mut *mut *const c_char,
    ) -> c_int;
    pub fn libssh2_session_last_errno(sess: *mut LIBSSH2_SESSION) -> c_int;
    pub fn libssh2_session_last_error(
        sess: *mut LIBSSH2_SESSION,
        msg: *mut *mut c_char,
        len: *mut c_int,
        want_buf: c_int,
    ) -> c_int;
    pub fn libssh2_session_handshake(sess: *mut LIBSSH2_SESSION, socket: libssh2_socket_t)
        -> c_int;
    pub fn libssh2_keepalive_config(
        sess: *mut LIBSSH2_SESSION,
        want_reply: c_int,
        interval: c_uint,
    );
    pub fn libssh2_keepalive_send(sess: *mut LIBSSH2_SESSION, seconds_to_next: *mut c_int)
        -> c_int;
    pub fn libssh2_session_block_directions(sess: *mut LIBSSH2_SESSION) -> c_int;

    // agent
    pub fn libssh2_agent_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_AGENT;
    pub fn libssh2_agent_free(agent: *mut LIBSSH2_AGENT);
    pub fn libssh2_agent_connect(agent: *mut LIBSSH2_AGENT) -> c_int;
    pub fn libssh2_agent_disconnect(agent: *mut LIBSSH2_AGENT) -> c_int;
    pub fn libssh2_agent_list_identities(agent: *mut LIBSSH2_AGENT) -> c_int;
    pub fn libssh2_agent_get_identity(
        agent: *mut LIBSSH2_AGENT,
        store: *mut *mut libssh2_agent_publickey,
        prev: *mut libssh2_agent_publickey,
    ) -> c_int;
    pub fn libssh2_agent_userauth(
        agent: *mut LIBSSH2_AGENT,
        username: *const c_char,
        identity: *mut libssh2_agent_publickey,
    ) -> c_int;

    // channels
    pub fn libssh2_channel_free(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_close(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_wait_closed(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_wait_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_process_startup(
        chan: *mut LIBSSH2_CHANNEL,
        req: *const c_char,
        req_len: c_uint,
        msg: *const c_char,
        msg_len: c_uint,
    ) -> c_int;
    pub fn libssh2_channel_flush_ex(chan: *mut LIBSSH2_CHANNEL, streamid: c_int) -> c_int;
    pub fn libssh2_channel_write_ex(
        chan: *mut LIBSSH2_CHANNEL,
        stream_id: c_int,
        buf: *const c_char,
        buflen: size_t,
    ) -> ssize_t;
    pub fn libssh2_channel_get_exit_signal(
        chan: *mut LIBSSH2_CHANNEL,
        exitsignal: *mut *mut c_char,
        exitsignal_len: *mut size_t,
        errmsg: *mut *mut c_char,
        errmsg_len: *mut size_t,
        langtag: *mut *mut c_char,
        langtag_len: *mut size_t,
    ) -> c_int;
    pub fn libssh2_channel_get_exit_status(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_open_ex(
        sess: *mut LIBSSH2_SESSION,
        channel_type: *const c_char,
        channel_type_len: c_uint,
        window_size: c_uint,
        packet_size: c_uint,
        message: *const c_char,
        message_len: c_uint,
    ) -> *mut LIBSSH2_CHANNEL;
    pub fn libssh2_channel_read_ex(
        chan: *mut LIBSSH2_CHANNEL,
        stream_id: c_int,
        buf: *mut c_char,
        buflen: size_t,
    ) -> ssize_t;
    pub fn libssh2_channel_setenv_ex(
        chan: *mut LIBSSH2_CHANNEL,
        var: *const c_char,
        varlen: c_uint,
        val: *const c_char,
        vallen: c_uint,
    ) -> c_int;
    pub fn libssh2_channel_send_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
    pub fn libssh2_channel_request_pty_ex(
        chan: *mut LIBSSH2_CHANNEL,
        term: *const c_char,
        termlen: c_uint,
        modes: *const c_char,
        modeslen: c_uint,
        width: c_int,
        height: c_int,
        width_px: c_int,
        height_px: c_int,
    ) -> c_int;
    pub fn libssh2_channel_request_pty_size_ex(
        chan: *mut LIBSSH2_CHANNEL,
        width: c_int,
        height: c_int,
        width_px: c_int,
        height_px: c_int,
    ) -> c_int;
    pub fn libssh2_channel_window_read_ex(
        chan: *mut LIBSSH2_CHANNEL,
        read_avail: *mut c_ulong,
        window_size_initial: *mut c_ulong,
    ) -> c_ulong;
    pub fn libssh2_channel_window_write_ex(
        chan: *mut LIBSSH2_CHANNEL,
        window_size_initial: *mut c_ulong,
    ) -> c_ulong;
    pub fn libssh2_channel_receive_window_adjust2(
        chan: *mut LIBSSH2_CHANNEL,
        adjust: c_ulong,
        force: c_uchar,
        window: *mut c_uint,
    ) -> c_int;
    pub fn libssh2_channel_direct_tcpip_ex(
        ses: *mut LIBSSH2_SESSION,
        host: *const c_char,
        port: c_int,
        shost: *const c_char,
        sport: c_int,
    ) -> *mut LIBSSH2_CHANNEL;
    pub fn libssh2_channel_direct_streamlocal_ex(
        ses: *mut LIBSSH2_SESSION,
        socket_path: *const c_char,
        shost: *const c_char,
        sport: c_int,
    ) -> *mut LIBSSH2_CHANNEL;
    pub fn libssh2_channel_forward_accept(listener: *mut LIBSSH2_LISTENER) -> *mut LIBSSH2_CHANNEL;
    pub fn libssh2_channel_forward_cancel(listener: *mut LIBSSH2_LISTENER) -> c_int;
    pub fn libssh2_channel_forward_listen_ex(
        sess: *mut LIBSSH2_SESSION,
        host: *const c_char,
        port: c_int,
        bound_port: *mut c_int,
        queue_maxsize: c_int,
    ) -> *mut LIBSSH2_LISTENER;
    pub fn libssh2_channel_handle_extended_data2(
        channel: *mut LIBSSH2_CHANNEL,
        mode: c_int,
    ) -> c_int;
    pub fn libssh2_channel_request_auth_agent(channel: *mut LIBSSH2_CHANNEL) -> c_int;

    // userauth
    pub fn libssh2_userauth_banner(sess: *mut LIBSSH2_SESSION, banner: *mut *mut c_char) -> c_int;
    pub fn libssh2_userauth_authenticated(sess: *mut LIBSSH2_SESSION) -> c_int;
    pub fn libssh2_userauth_list(
        sess: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: c_uint,
    ) -> *mut c_char;
    pub fn libssh2_userauth_hostbased_fromfile_ex(
        sess: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: c_uint,
        publickey: *const c_char,
        privatekey: *const c_char,
        passphrase: *const c_char,
        hostname: *const c_char,
        hostname_len: c_uint,
        local_username: *const c_char,
        local_len: c_uint,
    ) -> c_int;
    pub fn libssh2_userauth_publickey_fromfile_ex(
        sess: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: c_uint,
        publickey: *const c_char,
        privatekey: *const c_char,
        passphrase: *const c_char,
    ) -> c_int;
    pub fn libssh2_userauth_publickey_frommemory(
        sess: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: size_t,
        publickeydata: *const c_char,
        publickeydata_len: size_t,
        privatekeydata: *const c_char,
        privatekeydata_len: size_t,
        passphrase: *const c_char,
    ) -> c_int;
    pub fn libssh2_userauth_password_ex(
        session: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: c_uint,
        password: *const c_char,
        password_len: c_uint,
        password_change_cb: Option<LIBSSH2_PASSWD_CHANGEREQ_FUNC>,
    ) -> c_int;
    pub fn libssh2_userauth_keyboard_interactive_ex(
        session: *mut LIBSSH2_SESSION,
        username: *const c_char,
        username_len: c_uint,
        callback: Option<LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC>,
    ) -> c_int;

    // knownhost
    pub fn libssh2_knownhost_free(hosts: *mut LIBSSH2_KNOWNHOSTS);
    pub fn libssh2_knownhost_addc(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        host: *const c_char,
        salt: *const c_char,
        key: *const c_char,
        keylen: size_t,
        comment: *const c_char,
        commentlen: size_t,
        typemask: c_int,
        store: *mut *mut libssh2_knownhost,
    ) -> c_int;
    pub fn libssh2_knownhost_check(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        host: *const c_char,
        key: *const c_char,
        keylen: size_t,
        typemask: c_int,
        knownhost: *mut *mut libssh2_knownhost,
    ) -> c_int;
    pub fn libssh2_knownhost_checkp(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        host: *const c_char,
        port: c_int,
        key: *const c_char,
        keylen: size_t,
        typemask: c_int,
        knownhost: *mut *mut libssh2_knownhost,
    ) -> c_int;
    pub fn libssh2_knownhost_del(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        entry: *mut libssh2_knownhost,
    ) -> c_int;
    pub fn libssh2_knownhost_get(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        store: *mut *mut libssh2_knownhost,
        prev: *mut libssh2_knownhost,
    ) -> c_int;
    pub fn libssh2_knownhost_readfile(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        filename: *const c_char,
        kind: c_int,
    ) -> c_int;
    pub fn libssh2_knownhost_readline(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        line: *const c_char,
        len: size_t,
        kind: c_int,
    ) -> c_int;
    pub fn libssh2_knownhost_writefile(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        filename: *const c_char,
        kind: c_int,
    ) -> c_int;
    pub fn libssh2_knownhost_writeline(
        hosts: *mut LIBSSH2_KNOWNHOSTS,
        known: *mut libssh2_knownhost,
        buffer: *mut c_char,
        buflen: size_t,
        outlen: *mut size_t,
        kind: c_int,
    ) -> c_int;
    pub fn libssh2_knownhost_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_KNOWNHOSTS;

    // scp
    #[deprecated(note = "dangerously unsafe on windows, use libssh2_scp_recv2 instead")]
    pub fn libssh2_scp_recv(
        sess: *mut LIBSSH2_SESSION,
        path: *const c_char,
        sb: *mut libc::stat,
    ) -> *mut LIBSSH2_CHANNEL;

    pub fn libssh2_scp_recv2(
        sess: *mut LIBSSH2_SESSION,
        path: *const c_char,
        sb: *mut libssh2_struct_stat,
    ) -> *mut LIBSSH2_CHANNEL;

    pub fn libssh2_scp_send64(
        sess: *mut LIBSSH2_SESSION,
        path: *const c_char,
        mode: c_int,
        size: libssh2_int64_t,
        mtime: libc::time_t,
        atime: libc::time_t,
    ) -> *mut LIBSSH2_CHANNEL;

    // sftp
    pub fn libssh2_sftp_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_SFTP;
    pub fn libssh2_sftp_shutdown(sftp: *mut LIBSSH2_SFTP) -> c_int;
    pub fn libssh2_sftp_last_error(sftp: *mut LIBSSH2_SFTP) -> c_ulong;
    pub fn libssh2_sftp_open_ex(
        sftp: *mut LIBSSH2_SFTP,
        filename: *const c_char,
        filename_len: c_uint,
        flags: c_ulong,
        mode: c_long,
        open_type: c_int,
    ) -> *mut LIBSSH2_SFTP_HANDLE;
    pub fn libssh2_sftp_close_handle(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_int;
    pub fn libssh2_sftp_mkdir_ex(
        sftp: *mut LIBSSH2_SFTP,
        path: *const c_char,
        path_len: c_uint,
        mode: c_long,
    ) -> c_int;
    pub fn libssh2_sftp_fsync(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_int;
    pub fn libssh2_sftp_fstat_ex(
        handle: *mut LIBSSH2_SFTP_HANDLE,
        attrs: *mut LIBSSH2_SFTP_ATTRIBUTES,
        setstat: c_int,
    ) -> c_int;
    pub fn libssh2_sftp_fstatvfs(
        handle: *mut LIBSSH2_SFTP_HANDLE,
        attrs: *mut LIBSSH2_SFTP_STATVFS,
    ) -> c_int;
    pub fn libssh2_sftp_stat_ex(
        sftp: *mut LIBSSH2_SFTP,
        path: *const c_char,
        path_len: c_uint,
        stat_type: c_int,
        attrs: *mut LIBSSH2_SFTP_ATTRIBUTES,
    ) -> c_int;
    pub fn libssh2_sftp_read(
        handle: *mut LIBSSH2_SFTP_HANDLE,
        buf: *mut c_char,
        len: size_t,
    ) -> ssize_t;
    pub fn libssh2_sftp_symlink_ex(
        sftp: *mut LIBSSH2_SFTP,
        path: *const c_char,
        path_len: c_uint,
        target: *mut c_char,
        target_len: c_uint,
        link_type: c_int,
    ) -> c_int;
    pub fn libssh2_sftp_rename_ex(
        sftp: *mut LIBSSH2_SFTP,
        src: *const c_char,
        src_len: c_uint,
        dst: *const c_char,
        dst_len: c_uint,
        flags: c_long,
    ) -> c_int;
    pub fn libssh2_sftp_rmdir_ex(
        sftp: *mut LIBSSH2_SFTP,
        path: *const c_char,
        path_len: c_uint,
    ) -> c_int;
    pub fn libssh2_sftp_write(
        handle: *mut LIBSSH2_SFTP_HANDLE,
        buffer: *const c_char,
        len: size_t,
    ) -> ssize_t;
    pub fn libssh2_sftp_tell64(handle: *mut LIBSSH2_SFTP_HANDLE) -> libssh2_uint64_t;
    pub fn libssh2_sftp_seek64(handle: *mut LIBSSH2_SFTP_HANDLE, off: libssh2_uint64_t);
    pub fn libssh2_sftp_readdir_ex(
        handle: *mut LIBSSH2_SFTP_HANDLE,
        buffer: *mut c_char,
        buffer_len: size_t,
        longentry: *mut c_char,
        longentry_len: size_t,
        attrs: *mut LIBSSH2_SFTP_ATTRIBUTES,
    ) -> c_int;
    pub fn libssh2_sftp_unlink_ex(
        sftp: *mut LIBSSH2_SFTP,
        filename: *const c_char,
        filename_len: c_uint,
    ) -> c_int;
}

#[test]
fn smoke() {
    unsafe { libssh2_init(0) };
}

#[doc(hidden)]
pub fn issue_14344_workaround() {}

pub fn init() {
    use std::sync::Once;

    static INIT: Once = Once::new();
    INIT.call_once(|| unsafe {
        platform_init();
        assert_eq!(libc::atexit(shutdown), 0);
    });
    extern "C" fn shutdown() {
        unsafe {
            libssh2_exit();
        }
    }

    #[cfg(unix)]
    unsafe fn platform_init() {
        // On Unix we want to funnel through openssl_sys to initialize OpenSSL,
        // so be sure to tell libssh2 to not do its own thing as we've already
        // taken care of it.
        openssl_sys::init();
        assert_eq!(libssh2_init(LIBSSH2_INIT_NO_CRYPTO), 0);
    }

    #[cfg(windows)]
    unsafe fn platform_init() {
        // On Windows we want to be sure to tell libssh2 to initialize
        // everything, as we're not managing crypto elsewhere ourselves. Also to
        // fix alexcrichton/git2-rs#202
        assert_eq!(libssh2_init(0), 0);
    }
}


================================================
FILE: src/agent.rs
================================================
use parking_lot::{Mutex, MutexGuard};
use std::ffi::{CStr, CString};
use std::ptr::null_mut;
use std::slice;
use std::str;
use std::sync::Arc;

use {raw, Error, ErrorCode, SessionInner};

/// A structure representing a connection to an SSH agent.
///
/// Agents can be used to authenticate a session.
pub struct Agent {
    raw: *mut raw::LIBSSH2_AGENT,
    sess: Arc<Mutex<SessionInner>>,
}

// Agent is both Send and Sync; the compiler can't see it because it
// is pessimistic about the raw pointer.  We use Arc/Mutex to guard accessing
// the raw pointer so we are safe for both.
unsafe impl Send for Agent {}
unsafe impl Sync for Agent {}

/// A public key which is extracted from an SSH agent.
#[derive(Debug, PartialEq, Eq)]
pub struct PublicKey {
    blob: Vec<u8>,
    comment: String,
}

impl Agent {
    pub(crate) fn from_raw_opt(
        raw: *mut raw::LIBSSH2_AGENT,
        err: Option<Error>,
        sess: &Arc<Mutex<SessionInner>>,
    ) -> Result<Self, Error> {
        if raw.is_null() {
            Err(err.unwrap_or_else(Error::unknown))
        } else {
            Ok(Self {
                raw,
                sess: Arc::clone(sess),
            })
        }
    }

    /// Connect to an ssh-agent running on the system.
    pub fn connect(&mut self) -> Result<(), Error> {
        let sess = self.sess.lock();
        unsafe { sess.rc(raw::libssh2_agent_connect(self.raw)) }
    }

    /// Close a connection to an ssh-agent.
    pub fn disconnect(&mut self) -> Result<(), Error> {
        let sess = self.sess.lock();
        unsafe { sess.rc(raw::libssh2_agent_disconnect(self.raw)) }
    }

    /// Request an ssh-agent to list of public keys, and stores them in the
    /// internal collection of the handle.
    ///
    /// Call `identities` to get the public keys.
    pub fn list_identities(&mut self) -> Result<(), Error> {
        let sess = self.sess.lock();
        unsafe { sess.rc(raw::libssh2_agent_list_identities(self.raw)) }
    }

    /// Get list of the identities of this agent.
    pub fn identities(&self) -> Result<Vec<PublicKey>, Error> {
        let sess = self.sess.lock();
        let mut res = vec![];
        let mut prev = null_mut();
        let mut next = null_mut();
        loop {
            match unsafe { raw::libssh2_agent_get_identity(self.raw, &mut next, prev) } {
                0 => {
                    prev = next;
                    res.push(unsafe { PublicKey::from_raw(next) });
                }
                1 => break,
                rc => return Err(Error::from_session_error_raw(sess.raw, rc)),
            }
        }
        Ok(res)
    }

    fn resolve_raw_identity(
        &self,
        sess: &MutexGuard<SessionInner>,
        identity: &PublicKey,
    ) -> Result<Option<*mut raw::libssh2_agent_publickey>, Error> {
        let mut prev = null_mut();
        let mut next = null_mut();
        loop {
            match unsafe { raw::libssh2_agent_get_identity(self.raw, &mut next, prev) } {
                0 => {
                    prev = next;
                    let this_ident = unsafe { PublicKey::from_raw(next) };
                    if this_ident == *identity {
                        return Ok(Some(next));
                    }
                }
                1 => break,
                rc => return Err(Error::from_session_error_raw(sess.raw, rc)),
            }
        }
        Ok(None)
    }

    /// Attempt public key authentication with the help of ssh-agent.
    pub fn userauth(&self, username: &str, identity: &PublicKey) -> Result<(), Error> {
        let username = CString::new(username)?;
        let sess = self.sess.lock();
        let raw_ident = self.resolve_raw_identity(&sess, identity)?.ok_or_else(|| {
            Error::new(
                ErrorCode::Session(raw::LIBSSH2_ERROR_BAD_USE),
                "Identity not found in agent",
            )
        })?;
        unsafe {
            sess.rc(raw::libssh2_agent_userauth(
                self.raw,
                username.as_ptr(),
                raw_ident,
            ))
        }
    }
}

impl Drop for Agent {
    fn drop(&mut self) {
        unsafe { raw::libssh2_agent_free(self.raw) }
    }
}

impl PublicKey {
    unsafe fn from_raw(raw: *mut raw::libssh2_agent_publickey) -> Self {
        let blob = slice::from_raw_parts_mut((*raw).blob, (*raw).blob_len as usize);
        let comment = (*raw).comment;
        let comment = if comment.is_null() {
            String::new()
        } else {
            CStr::from_ptr(comment).to_string_lossy().into_owned()
        };
        Self {
            blob: blob.to_vec(),
            comment,
        }
    }

    /// Return the data of this public key.
    pub fn blob(&self) -> &[u8] {
        &self.blob
    }

    /// Returns the comment in a printable format
    pub fn comment(&self) -> &str {
        &self.comment
    }
}


================================================
FILE: src/channel.rs
================================================
use libc::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void, size_t};
use parking_lot::{Mutex, MutexGuard};
use std::cmp;
use std::ffi::CString;
use std::ptr::{null, null_mut};
use std::io;
use std::io::prelude::*;
use std::slice;
use std::sync::Arc;

use {raw, Error, ExtendedData, PtyModes, SessionInner};

struct ChannelInner {
    unsafe_raw: *mut raw::LIBSSH2_CHANNEL,
    sess: Arc<Mutex<SessionInner>>,
    read_limit: Mutex<Option<u64>>,
}

// ChannelInner is both Send and Sync; the compiler can't see it because it
// is pessimistic about the raw pointer.  We use Arc/Mutex to guard accessing
// the raw pointer so we are safe for both.
unsafe impl Send for ChannelInner {}
unsafe impl Sync for ChannelInner {}

struct LockedChannel<'a> {
    raw: *mut raw::LIBSSH2_CHANNEL,
    sess: MutexGuard<'a, SessionInner>,
}

/// A channel represents a portion of an SSH connection on which data can be
/// read and written.
///
/// Channels denote all of SCP uploads and downloads, shell sessions, remote
/// process executions, and other general-purpose sessions. Each channel
/// implements the `Reader` and `Writer` traits to send and receive data.
/// Whether or not I/O operations are blocking is mandated by the `blocking`
/// flag on a channel's corresponding `Session`.
///
/// You may clone a `Channel` to obtain another handle to the same underlying
/// channel, but note that all clones will share the same underlying SSH
/// session and will be subject to the same blocking behavior. For more details
/// on the implications of cloning and blocking operations, refer to the
/// `Session` documentation.
#[derive(Clone)]
pub struct Channel {
    channel_inner: Arc<ChannelInner>,
}

impl Channel {
    pub(crate) fn from_raw_opt(
        raw: *mut raw::LIBSSH2_CHANNEL,
        err: Option<Error>,
        sess: &Arc<Mutex<SessionInner>>,
    ) -> Result<Self, Error> {
        if raw.is_null() {
            Err(err.unwrap_or_else(Error::unknown))
        } else {
            Ok(Self {
                channel_inner: Arc::new(ChannelInner {
                    unsafe_raw: raw,
                    sess: Arc::clone(sess),
                    read_limit: Mutex::new(None),
                }),
            })
        }
    }

    fn lock(&self) -> LockedChannel<'_> {
        let sess = self.channel_inner.sess.lock();
        LockedChannel {
            sess,
            raw: self.channel_inner.unsafe_raw,
        }
    }
}

/// A channel can have a number of streams, each identified by an id, each of
/// which implements the `Read` and `Write` traits.
///
/// You may clone a `Stream` to obtain another handle to the same underlying
/// stream, but note that all clones will share the same underlying SSH
/// session and will be subject to the same blocking behavior. For more details
/// on the implications of cloning and blocking operations, refer to the
/// `Session` documentation.
#[derive(Clone)]
pub struct Stream {
    channel_inner: Arc<ChannelInner>,
    id: i32,
}

struct LockedStream<'a> {
    raw: *mut raw::LIBSSH2_CHANNEL,
    sess: MutexGuard<'a, SessionInner>,
    id: i32,
    read_limit: MutexGuard<'a, Option<u64>>,
}

impl<'a> LockedStream<'a> {
    pub fn eof(&self) -> bool {
        *self.read_limit == Some(0) || unsafe { raw::libssh2_channel_eof(self.raw) != 0 }
    }
}

/// Data received from when a program exits with a signal.
pub struct ExitSignal {
    /// The exit signal received, if the program did not exit cleanly. Does not
    /// contain a SIG prefix
    pub exit_signal: Option<String>,
    /// Error message provided by the remote server (if any)
    pub error_message: Option<String>,
    /// Language tag provided by the remote server (if any)
    pub lang_tag: Option<String>,
}

/// Description of the read window as returned by `Channel::read_window`
#[derive(Copy, Clone)]
pub struct ReadWindow {
    /// The number of bytes which the remote end may send without overflowing
    /// the window limit.
    pub remaining: u32,
    /// The number of bytes actually available to be read.
    pub available: u32,
    /// The window_size_initial as defined by the channel open request
    pub window_size_initial: u32,
}

/// Description of the write window as returned by `Channel::write_window`
#[derive(Copy, Clone)]
pub struct WriteWindow {
    /// The number of bytes which may be safely written on the channel without
    /// blocking.
    pub remaining: u32,
    /// The window_size_initial as defined by the channel open request
    pub window_size_initial: u32,
}

impl Channel {
    /// Set an environment variable in the remote channel's process space.
    ///
    /// Note that this does not make sense for all channel types and may be
    /// ignored by the server despite returning success.
    pub fn setenv(&mut self, var: &str, val: &str) -> Result<(), Error> {
        let var = CString::new(var)?;
        let var = var.as_bytes();
        let val = CString::new(val)?;
        let val = val.as_bytes();
        let locked = self.lock();
        unsafe {
            locked.sess.rc(raw::libssh2_channel_setenv_ex(
                locked.raw,
                var.as_ptr() as *const _,
                var.len() as c_uint,
                val.as_ptr() as *const _,
                val.len() as c_uint,
            ))
        }
    }

    /// Request a PTY on an established channel.
    ///
    /// Note that this does not make sense for all channel types and may be
    /// ignored by the server despite returning success.
    ///
    /// The dimensions argument is a tuple of (width, height, width_px,
    /// height_px)
    ///
    /// The mode parameter is optional and specifies modes to apply to
    /// the pty.  Use the `PtyModes` type construct these modes.
    /// A contrived example of this is below:
    ///
    /// ```
    /// let mut mode = ssh2::PtyModes::new();
    /// // Set the interrupt character to CTRL-C (ASCII 3: ETX).
    /// // This is typically the default, but we're showing how to
    /// // set a relatable option for the sake of example!
    /// mode.set_character(ssh2::PtyModeOpcode::VINTR, Some(3 as char));
    /// ```
    pub fn request_pty(
        &mut self,
        term: &str,
        mode: Option<PtyModes>,
        dim: Option<(u32, u32, u32, u32)>,
    ) -> Result<(), Error> {
        let term = CString::new(term)?;
        let term = term.as_bytes();
        let locked = self.lock();
        let mode = mode.map(PtyModes::finish);
        let mode = mode.as_ref().map(Vec::as_slice).unwrap_or(&[]);
        locked.sess.rc(unsafe {
            let (width, height, width_px, height_px) = dim.unwrap_or((80, 24, 0, 0));
            raw::libssh2_channel_request_pty_ex(
                locked.raw,
                term.as_ptr() as *const _,
                term.len() as c_uint,
                mode.as_ptr() as *const _,
                mode.len() as c_uint,
                width as c_int,
                height as c_int,
                width_px as c_int,
                height_px as c_int,
            )
        })
    }

    /// Request that the PTY size be changed to the specified size.
    /// width and height are the number of character cells, and you
    /// may optionally include the size specified in pixels.
    pub fn request_pty_size(
        &mut self,
        width: u32,
        height: u32,
        width_px: Option<u32>,
        height_px: Option<u32>,
    ) -> Result<(), Error> {
        let locked = self.lock();
        let width_px = width_px.unwrap_or(0);
        let height_px = height_px.unwrap_or(0);
        locked.sess.rc(unsafe {
            raw::libssh2_channel_request_pty_size_ex(
                locked.raw,
                width as c_int,
                height as c_int,
                width_px as c_int,
                height_px as c_int,
            )
        })
    }

    /// Requests that the remote host start an authentication agent;
    /// if successful requests to that agent will be forwarded from
    /// the server back to the local authentication agent on the client side.
    ///
    /// Note that some hosts are configured to disallow agent forwarding,
    /// and that even if enabled, there is a possibility that starting
    /// the agent on the remote system can fail.
    pub fn request_auth_agent_forwarding(&mut self) -> Result<(), Error> {
        let locked = self.lock();
        locked
            .sess
            .rc(unsafe { raw::libssh2_channel_request_auth_agent(locked.raw) })
    }

    /// Execute a command
    ///
    /// An execution is one of the standard process services defined by the SSH2
    /// protocol.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use std::io::prelude::*;
    /// # use ssh2::Session;
    /// # let session: Session = panic!();
    /// let mut channel = session.channel_session().unwrap();
    /// channel.exec("ls").unwrap();
    /// let mut s = String::new();
    /// channel.read_to_string(&mut s).unwrap();
    /// println!("{}", s);
    /// ```
    pub fn exec(&mut self, command: &str) -> Result<(), Error> {
        self.process_startup("exec", Some(command))
    }

    /// Start a shell
    ///
    /// A shell is one of the standard process services defined by the SSH2
    /// protocol.
    pub fn shell(&mut self) -> Result<(), Error> {
        self.process_startup("shell", None)
    }

    /// Request a subsystem be started.
    ///
    /// A subsystem is one of the standard process services defined by the SSH2
    /// protocol.
    pub fn subsystem(&mut self, system: &str) -> Result<(), Error> {
        self.process_startup("subsystem", Some(system))
    }

    /// Initiate a request on a session type channel.
    ///
    /// The SSH2 protocol currently defines shell, exec, and subsystem as
    /// standard process services.
    pub fn process_startup(&mut self, request: &str, message: Option<&str>) -> Result<(), Error> {
        let message = message.map(|s| CString::new(s)).transpose()?;
        let (message, message_len) = message
            .as_ref()
            .map(|s| (s.as_ptr(), s.as_bytes().len()))
            .unwrap_or((null(), 0));
        let locked = self.lock();
        unsafe {
            let rc = raw::libssh2_channel_process_startup(
                locked.raw,
                request.as_ptr() as *const _,
                request.len() as c_uint,
                message,
                message_len as c_uint,
            );
            locked.sess.rc(rc)
        }
    }

    /// Get a handle to the stderr stream of this channel.
    ///
    /// The returned handle implements the `Read` and `Write` traits.
    pub fn stderr(&self) -> Stream {
        self.stream(::EXTENDED_DATA_STDERR)
    }

    /// Get a handle to a particular stream for this channel.
    ///
    /// The returned handle implements the `Read` and `Write` traits.
    ///
    /// Groups of substreams may be flushed by passing one of the following
    /// constants and then calling `flush()`.
    ///
    /// * FLUSH_EXTENDED_DATA - Flush all extended data substreams
    /// * FLUSH_ALL - Flush all substreams
    pub fn stream(&self, stream_id: i32) -> Stream {
        Stream {
            channel_inner: Arc::clone(&self.channel_inner),
            id: stream_id,
        }
    }

    /// Change how extended data (such as stderr) is handled
    pub fn handle_extended_data(&mut self, mode: ExtendedData) -> Result<(), Error> {
        let locked = self.lock();
        unsafe {
            let rc = raw::libssh2_channel_handle_extended_data2(locked.raw, mode as c_int);
            locked.sess.rc(rc)
        }
    }

    /// Returns the exit code raised by the process running on the remote host
    /// at the other end of the named channel.
    ///
    /// Note that the exit status may not be available if the remote end has not
    /// yet set its status to closed.
    pub fn exit_status(&self) -> Result<i32, Error> {
        let locked = self.lock();
        // Should really store existing error, call function, check for error
        // after and restore previous error if no new one...but the only error
        // condition right now is a NULL pointer check on self.raw, so let's
        // assume that's not the case.
        Ok(unsafe { raw::libssh2_channel_get_exit_status(locked.raw) })
    }

    /// Get the remote exit signal.
    pub fn exit_signal(&self) -> Result<ExitSignal, Error> {
        let locked = self.lock();
        unsafe {
            let mut sig = null_mut();
            let mut siglen = 0;
            let mut msg = null_mut();
            let mut msglen = 0;
            let mut lang = null_mut();
            let mut langlen = 0;
            let rc = raw::libssh2_channel_get_exit_signal(
                locked.raw,
                &mut sig,
                &mut siglen,
                &mut msg,
                &mut msglen,
                &mut lang,
                &mut langlen,
            );
            locked.sess.rc(rc)?;
            return Ok(ExitSignal {
                exit_signal: convert(&locked, sig, siglen),
                error_message: convert(&locked, msg, msglen),
                lang_tag: convert(&locked, lang, langlen),
            });
        }

        unsafe fn convert(locked: &LockedChannel, ptr: *mut c_char, len: size_t) -> Option<String> {
            if ptr.is_null() {
                return None;
            }
            let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
            let ret = slice.to_vec();
            raw::libssh2_free(locked.sess.raw, ptr as *mut c_void);
            String::from_utf8(ret).ok()
        }
    }

    /// Check the status of the read window.
    pub fn read_window(&self) -> ReadWindow {
        let locked = self.lock();
        unsafe {
            let mut avail = 0;
            let mut init = 0;
            let remaining = raw::libssh2_channel_window_read_ex(locked.raw, &mut avail, &mut init);
            ReadWindow {
                remaining: remaining as u32,
                available: avail as u32,
                window_size_initial: init as u32,
            }
        }
    }

    /// Check the status of the write window.
    pub fn write_window(&self) -> WriteWindow {
        let locked = self.lock();
        unsafe {
            let mut init = 0;
            let remaining = raw::libssh2_channel_window_write_ex(locked.raw, &mut init);
            WriteWindow {
                remaining: remaining as u32,
                window_size_initial: init as u32,
            }
        }
    }

    /// Adjust the receive window for a channel by adjustment bytes.
    ///
    /// If the amount to be adjusted is less than the minimum adjustment and
    /// force is false, the adjustment amount will be queued for a later packet.
    ///
    /// This function returns the new size of the receive window (as understood
    /// by remote end) on success.
    pub fn adjust_receive_window(&mut self, adjust: u64, force: bool) -> Result<u64, Error> {
        let locked = self.lock();
        let mut ret = 0;
        let rc = unsafe {
            raw::libssh2_channel_receive_window_adjust2(
                locked.raw,
                adjust as c_ulong,
                force as c_uchar,
                &mut ret,
            )
        };
        locked.sess.rc(rc)?;
        Ok(ret as u64)
    }

    /// Artificially limit the number of bytes that will be read from this
    /// channel. Hack intended for use by scp_recv only.
    #[doc(hidden)]
    pub(crate) fn limit_read(&mut self, limit: u64) {
        *self.channel_inner.read_limit.lock() = Some(limit);
    }

    /// Check if the remote host has sent an EOF status for the channel.
    /// Take care: the EOF status is for the entire channel which can be confusing
    /// because the reading from the channel reads only the stdout stream.
    /// unread, buffered, stderr data will cause eof() to return false.
    pub fn eof(&self) -> bool {
        let locked = self.lock();
        *self.channel_inner.read_limit.lock() == Some(0)
            || unsafe { raw::libssh2_channel_eof(locked.raw) != 0 }
    }

    /// Tell the remote host that no further data will be sent on the specified
    /// channel.
    ///
    /// Processes typically interpret this as a closed stdin descriptor.
    pub fn send_eof(&mut self) -> Result<(), Error> {
        let locked = self.lock();
        unsafe { locked.sess.rc(raw::libssh2_channel_send_eof(locked.raw)) }
    }

    /// Wait for the remote end to send EOF.
    /// Note that unread buffered stdout and stderr will cause this function
    /// to return `Ok(())` without waiting.
    /// You should call the eof() function after calling this to check the
    /// status of the channel.
    pub fn wait_eof(&mut self) -> Result<(), Error> {
        let locked = self.lock();
        unsafe { locked.sess.rc(raw::libssh2_channel_wait_eof(locked.raw)) }
    }

    /// Close an active data channel.
    ///
    /// In practice this means sending an SSH_MSG_CLOSE packet to the remote
    /// host which serves as instruction that no further data will be sent to
    /// it. The remote host may still send data back until it sends its own
    /// close message in response.
    ///
    /// To wait for the remote end to close its connection as well, follow this
    /// command with `wait_close`
    pub fn close(&mut self) -> Result<(), Error> {
        let locked = self.lock();
        unsafe { locked.sess.rc(raw::libssh2_channel_close(locked.raw)) }
    }

    /// Enter a temporary blocking state until the remote host closes the named
    /// channel.
    ///
    /// Typically sent after `close` in order to examine the exit status.
    pub fn wait_close(&mut self) -> Result<(), Error> {
        let locked = self.lock();
        unsafe { locked.sess.rc(raw::libssh2_channel_wait_closed(locked.raw)) }
    }
}

impl Write for Channel {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stream(0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stream(0).flush()
    }
}

impl Read for Channel {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream(0).read(buf)
    }
}

impl Drop for ChannelInner {
    fn drop(&mut self) {
        unsafe {
            let _ = raw::libssh2_channel_free(self.unsafe_raw);
        }
    }
}

impl Stream {
    fn lock(&self) -> LockedStream<'_> {
        let sess = self.channel_inner.sess.lock();
        LockedStream {
            sess,
            raw: self.channel_inner.unsafe_raw,
            id: self.id,
            read_limit: self.channel_inner.read_limit.lock(),
        }
    }
}

impl Read for Stream {
    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
        let mut locked = self.lock();
        if locked.eof() {
            return Ok(0);
        }

        let data = match locked.read_limit.as_mut() {
            Some(amt) => {
                let len = data.len();
                &mut data[..cmp::min(*amt as usize, len)]
            }
            None => data,
        };
        let ret = unsafe {
            let rc = raw::libssh2_channel_read_ex(
                locked.raw,
                locked.id as c_int,
                data.as_mut_ptr() as *mut _,
                data.len() as size_t,
            );
            locked.sess.rc(rc as c_int).map(|()| rc as usize)
        };
        match ret {
            Ok(n) => {
                if let Some(ref mut amt) = locked.read_limit.as_mut() {
                    **amt -= n as u64;
                }
                Ok(n)
            }
            Err(e) => Err(e.into()),
        }
    }
}

impl Write for Stream {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let locked = self.lock();
        unsafe {
            let rc = raw::libssh2_channel_write_ex(
                locked.raw,
                locked.id as c_int,
                data.as_ptr() as *mut _,
                data.len() as size_t,
            );
            locked.sess.rc(rc as c_int).map(|()| rc as usize)
        }
        .map_err(Into::into)
    }

    fn flush(&mut self) -> io::Result<()> {
        let locked = self.lock();
        unsafe {
            let rc = raw::libssh2_channel_flush_ex(locked.raw, locked.id as c_int);
            locked.sess.rc(rc)
        }
        .map_err(Into::into)
    }
}


================================================
FILE: src/error.rs
================================================
use libc;
use std::borrow::Cow;
use std::error;
use std::ffi::NulError;
use std::fmt;
use std::io;
use std::ptr::null_mut;
use std::str;

use {raw, Session};

/// An error code originating from a particular source.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ErrorCode {
    /// Codes for errors that originate in libssh2.
    /// Can be one of  `LIBSSH2_ERROR_*` constants.
    Session(libc::c_int),

    /// Codes for errors that originate in the SFTP subsystem.
    /// Can be one of `LIBSSH2_FX_*` constants.
    //
    // TODO: This should be `c_ulong` instead of `c_int` because these constants
    // are only returned by `libssh2_sftp_last_error()` which returns `c_ulong`.
    SFTP(libc::c_int),
}

impl fmt::Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// Representation of an error that can occur within libssh2
#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub struct Error {
    code: ErrorCode,
    msg: Cow<'static, str>,
}

impl Error {
    #[doc(hidden)]
    pub fn last_session_error_raw(raw: *mut raw::LIBSSH2_SESSION) -> Option<Error> {
        unsafe {
            let mut msg = null_mut();
            let rc = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
            if rc == 0 {
                return None;
            }

            // The pointer stored in `msg` points to the internal buffer of
            // LIBSSH2_SESSION, so the error message should be copied before
            // it is overwritten by the next API call.
            Some(Self {
                code: ErrorCode::Session(rc),
                msg: make_error_message(msg),
            })
        }
    }

    /// Given a libssh2 error return code, generate an Error object that
    /// encapsulates that error code and the error reason.
    /// The error reason is extracted from the Session and is used if the
    /// session contains the same error code as that provided.
    /// If the error code doesn't match then an approximation of the error
    /// reason is used instead of the error message stored in the Session.
    pub fn from_session_error(sess: &Session, rc: libc::c_int) -> Error {
        Self::from_session_error_raw(&mut *sess.raw(), rc)
    }

    #[doc(hidden)]
    pub fn from_session_error_raw(raw: *mut raw::LIBSSH2_SESSION, rc: libc::c_int) -> Error {
        unsafe {
            let mut msg = null_mut();
            let res = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
            if res != rc {
                return Self::from_errno(ErrorCode::Session(rc));
            }

            // The pointer stored in `msg` points to the internal buffer of
            // LIBSSH2_SESSION, so the error message should be copied before
            // it is overwritten by the next API call.
            Self {
                code: ErrorCode::Session(rc),
                msg: make_error_message(msg),
            }
        }
    }

    /// Generate the last error that occurred for a `Session`.
    ///
    /// Returns `None` if there was no last error.
    pub fn last_session_error(sess: &Session) -> Option<Error> {
        Self::last_session_error_raw(&mut *sess.raw())
    }

    /// Create a new error for the given code and message
    pub fn new(code: ErrorCode, msg: &'static str) -> Error {
        Error {
            code,
            msg: Cow::Borrowed(msg),
        }
    }

    /// Generate an error that represents EOF
    pub fn eof() -> Error {
        Error::new(
            ErrorCode::Session(raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT),
            "end of file",
        )
    }

    /// Generate an error for unknown failure
    pub fn unknown() -> Error {
        Error::new(
            ErrorCode::Session(libc::c_int::min_value()),
            "no other error listed",
        )
    }

    /// Construct an error from an error code from libssh2
    pub fn from_errno(code: ErrorCode) -> Error {
        let msg = match code {
            ErrorCode::Session(code) => match code {
                raw::LIBSSH2_ERROR_BANNER_RECV => "banner recv failure",
                raw::LIBSSH2_ERROR_BANNER_SEND => "banner send failure",
                raw::LIBSSH2_ERROR_INVALID_MAC => "invalid mac",
                raw::LIBSSH2_ERROR_KEX_FAILURE => "kex failure",
                raw::LIBSSH2_ERROR_ALLOC => "alloc failure",
                raw::LIBSSH2_ERROR_SOCKET_SEND => "socket send failure",
                raw::LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE => "key exchange failure",
                raw::LIBSSH2_ERROR_TIMEOUT => "timed out",
                raw::LIBSSH2_ERROR_HOSTKEY_INIT => "hostkey init error",
                raw::LIBSSH2_ERROR_HOSTKEY_SIGN => "hostkey sign error",
                raw::LIBSSH2_ERROR_DECRYPT => "decrypt error",
                raw::LIBSSH2_ERROR_SOCKET_DISCONNECT => "socket disconnected",
                raw::LIBSSH2_ERROR_PROTO => "protocol error",
                raw::LIBSSH2_ERROR_PASSWORD_EXPIRED => "password expired",
                raw::LIBSSH2_ERROR_FILE => "file error",
                raw::LIBSSH2_ERROR_METHOD_NONE => "bad method name",
                raw::LIBSSH2_ERROR_AUTHENTICATION_FAILED => "authentication failed",
                raw::LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED => "public key unverified",
                raw::LIBSSH2_ERROR_CHANNEL_OUTOFORDER => "channel out of order",
                raw::LIBSSH2_ERROR_CHANNEL_FAILURE => "channel failure",
                raw::LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED => "request denied",
                raw::LIBSSH2_ERROR_CHANNEL_UNKNOWN => "unknown channel error",
                raw::LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED => "window exceeded",
                raw::LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED => "packet exceeded",
                raw::LIBSSH2_ERROR_CHANNEL_CLOSED => "closed channel",
                raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT => "eof sent",
                raw::LIBSSH2_ERROR_SCP_PROTOCOL => "scp protocol error",
                raw::LIBSSH2_ERROR_ZLIB => "zlib error",
                raw::LIBSSH2_ERROR_SOCKET_TIMEOUT => "socket timeout",
                raw::LIBSSH2_ERROR_SFTP_PROTOCOL => "sftp protocol error",
                raw::LIBSSH2_ERROR_REQUEST_DENIED => "request denied",
                raw::LIBSSH2_ERROR_METHOD_NOT_SUPPORTED => "method not supported",
                raw::LIBSSH2_ERROR_INVAL => "invalid",
                raw::LIBSSH2_ERROR_INVALID_POLL_TYPE => "invalid poll type",
                raw::LIBSSH2_ERROR_PUBLICKEY_PROTOCOL => "public key protocol error",
                raw::LIBSSH2_ERROR_EAGAIN => "operation would block",
                raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL => "buffer too small",
                raw::LIBSSH2_ERROR_BAD_USE => "bad use error",
                raw::LIBSSH2_ERROR_COMPRESS => "compression error",
                raw::LIBSSH2_ERROR_OUT_OF_BOUNDARY => "out of bounds",
                raw::LIBSSH2_ERROR_AGENT_PROTOCOL => "invalid agent protocol",
                raw::LIBSSH2_ERROR_SOCKET_RECV => "error receiving on socket",
                raw::LIBSSH2_ERROR_ENCRYPT => "bad encrypt",
                raw::LIBSSH2_ERROR_BAD_SOCKET => "bad socket",
                raw::LIBSSH2_ERROR_KNOWN_HOSTS => "known hosts error",
                raw::LIBSSH2_ERROR_CHANNEL_WINDOW_FULL => "channel window full",
                raw::LIBSSH2_ERROR_KEYFILE_AUTH_FAILED => "keyfile auth failed",
                raw::LIBSSH2_ERROR_RANDGEN => "unable to get random bytes",
                raw::LIBSSH2_ERROR_MISSING_USERAUTH_BANNER => "missing userauth banner",
                raw::LIBSSH2_ERROR_ALGO_UNSUPPORTED => "algorithm unsupported",
                _ => "unknown error",
            },
            ErrorCode::SFTP(code) => match code {
                raw::LIBSSH2_FX_EOF => "end of file",
                raw::LIBSSH2_FX_NO_SUCH_FILE => "no such file",
                raw::LIBSSH2_FX_PERMISSION_DENIED => "permission denied",
                raw::LIBSSH2_FX_FAILURE => "failure",
                raw::LIBSSH2_FX_BAD_MESSAGE => "bad message",
                raw::LIBSSH2_FX_NO_CONNECTION => "no connection",
                raw::LIBSSH2_FX_CONNECTION_LOST => "connection lost",
                raw::LIBSSH2_FX_OP_UNSUPPORTED => "operation unsupported",
                raw::LIBSSH2_FX_INVALID_HANDLE => "invalid handle",
                raw::LIBSSH2_FX_NO_SUCH_PATH => "no such path",
                raw::LIBSSH2_FX_FILE_ALREADY_EXISTS => "file already exists",
                raw::LIBSSH2_FX_WRITE_PROTECT => "file is write protected",
                raw::LIBSSH2_FX_NO_MEDIA => "no media available",
                raw::LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM => "no space on filesystem",
                raw::LIBSSH2_FX_QUOTA_EXCEEDED => "quota exceeded",
                raw::LIBSSH2_FX_UNKNOWN_PRINCIPAL => "unknown principal",
                raw::LIBSSH2_FX_LOCK_CONFLICT => "lock conflict",
                raw::LIBSSH2_FX_DIR_NOT_EMPTY => "directory not empty",
                raw::LIBSSH2_FX_NOT_A_DIRECTORY => "not a directory",
                raw::LIBSSH2_FX_INVALID_FILENAME => "invalid filename",
                raw::LIBSSH2_FX_LINK_LOOP => "link loop",
                _ => "unknown error",
            },
        };
        Error::new(code, msg)
    }

    /// Get the message corresponding to this error
    pub fn message(&self) -> &str {
        &*self.msg
    }

    /// Return the code for this error
    pub fn code(&self) -> ErrorCode {
        self.code
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> io::Error {
        let kind = match err.code {
            ErrorCode::Session(raw::LIBSSH2_ERROR_EAGAIN) => io::ErrorKind::WouldBlock,
            ErrorCode::Session(raw::LIBSSH2_ERROR_TIMEOUT) => io::ErrorKind::TimedOut,
            ErrorCode::SFTP(raw::LIBSSH2_FX_NO_SUCH_FILE)
            | ErrorCode::SFTP(raw::LIBSSH2_FX_NO_SUCH_PATH) => io::ErrorKind::NotFound,
            _ => io::ErrorKind::Other,
        };
        io::Error::new(kind, err.msg)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}] {}", self.code, self.msg)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.message()
    }
}

impl From<NulError> for Error {
    fn from(_: NulError) -> Error {
        Error::new(
            ErrorCode::Session(raw::LIBSSH2_ERROR_INVAL),
            "provided data contained a nul byte and could not be used \
             as as string",
        )
    }
}

unsafe fn make_error_message(msg: *mut libc::c_char) -> Cow<'static, str> {
    const FALLBACK: Cow<'_, str> = Cow::Borrowed("<failed to fetch the error message>");
    ::opt_bytes(&(), msg)
        .and_then(|msg| {
            str::from_utf8(msg)
                .map(|msg| Cow::Owned(msg.to_owned()))
                .ok()
        })
        .unwrap_or_else(|| FALLBACK)
}


================================================
FILE: src/knownhosts.rs
================================================
use libc::{c_int, size_t};
use parking_lot::{Mutex, MutexGuard};
use std::ffi::CString;
use std::path::Path;
use std::ptr::null_mut;
use std::str;
use std::sync::Arc;

use util;
use {raw, CheckResult, Error, ErrorCode, KnownHostFileKind, SessionInner};

/// A set of known hosts which can be used to verify the identity of a remote
/// server.
///
/// # Example
///
/// ```no_run
/// use std::env;
/// use std::path::Path;
/// use ssh2::{self, CheckResult, HostKeyType, KnownHostKeyFormat};
/// use ssh2::KnownHostFileKind;
///
/// fn check_known_host(session: &ssh2::Session, host: &str) {
///     let mut known_hosts = session.known_hosts().unwrap();
///
///     // Initialize the known hosts with a global known hosts file
///     let file = Path::new(&env::var("HOME").unwrap()).join(".ssh/known_hosts");
///     known_hosts.read_file(&file, KnownHostFileKind::OpenSSH).unwrap();
///
///     // Now check to see if the seesion's host key is anywhere in the known
///     // hosts file
///     let (key, key_type) = session.host_key().unwrap();
///     match known_hosts.check(host, key) {
///         CheckResult::Match => return, // all good!
///         CheckResult::NotFound => {}   // ok, we'll add it
///         CheckResult::Mismatch => {
///             panic!("host mismatch, man in the middle attack?!")
///         }
///         CheckResult::Failure => panic!("failed to check the known hosts"),
///     }
///
///     println!("adding {} to the known hosts", host);
///
///     known_hosts.add(host, key, host, key_type.into()).unwrap();
///     known_hosts.write_file(&file, KnownHostFileKind::OpenSSH).unwrap();
/// }
/// ```
pub struct KnownHosts {
    raw: *mut raw::LIBSSH2_KNOWNHOSTS,
    sess: Arc<Mutex<SessionInner>>,
}

/// Structure representing a known host as part of a `KnownHosts` structure.
#[derive(Debug, PartialEq, Eq)]
pub struct Host {
    name: Option<String>,
    key: String,
}

impl KnownHosts {
    pub(crate) fn from_raw_opt(
        raw: *mut raw::LIBSSH2_KNOWNHOSTS,
        err: Option<Error>,
        sess: &Arc<Mutex<SessionInner>>,
    ) -> Result<Self, Error> {
        if raw.is_null() {
            Err(err.unwrap_or_else(Error::unknown))
        } else {
            Ok(Self {
                raw,
                sess: Arc::clone(sess),
            })
        }
    }

    /// Reads a collection of known hosts from a specified file and adds them to
    /// the collection of known hosts.
    pub fn read_file(&mut self, file: &Path, kind: KnownHostFileKind) -> Result<u32, Error> {
        let file = CString::new(util::path2bytes(file)?)?;
        let sess = self.sess.lock();
        let n = unsafe { raw::libssh2_knownhost_readfile(self.raw, file.as_ptr(), kind as c_int) };
        if n < 0 {
            sess.rc(n)?
        }
        Ok(n as u32)
    }

    /// Read a line as if it were from a known hosts file.
    pub fn read_str(&mut self, s: &str, kind: KnownHostFileKind) -> Result<(), Error> {
        let s = CString::new(s)?;
        let s = s.as_bytes();
        let sess = self.sess.lock();
        sess.rc(unsafe {
            raw::libssh2_knownhost_readline(
                self.raw,
                s.as_ptr() as *const _,
                s.len() as size_t,
                kind as c_int,
            )
        })
    }

    /// Writes all the known hosts to the specified file using the specified
    /// file format.
    pub fn write_file(&self, file: &Path, kind: KnownHostFileKind) -> Result<(), Error> {
        let file = CString::new(util::path2bytes(file)?)?;
        let sess = self.sess.lock();
        let n = unsafe { raw::libssh2_knownhost_writefile(self.raw, file.as_ptr(), kind as c_int) };
        sess.rc(n)
    }

    /// Converts a single known host to a single line of output for storage,
    /// using the 'type' output format.
    pub fn write_string(&self, host: &Host, kind: KnownHostFileKind) -> Result<String, Error> {
        let mut v = Vec::with_capacity(128);
        let sess = self.sess.lock();
        let raw_host = self.resolve_to_raw_host(&sess, host)?.ok_or_else(|| {
            Error::new(
                ErrorCode::Session(raw::LIBSSH2_ERROR_BAD_USE),
                "Host is not in the set of known hosts",
            )
        })?;
        loop {
            let mut outlen = 0;
            unsafe {
                let rc = raw::libssh2_knownhost_writeline(
                    self.raw,
                    raw_host,
                    v.as_mut_ptr() as *mut _,
                    v.capacity() as size_t,
                    &mut outlen,
                    kind as c_int,
                );
                if rc == raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL {
                    // + 1 for the trailing zero
                    v.reserve(outlen as usize + 1);
                } else {
                    sess.rc(rc)?;
                    v.set_len(outlen as usize);
                    break;
                }
            }
        }
        Ok(String::from_utf8(v).unwrap())
    }

    /// Create an iterator over all of the known hosts in this structure.
    pub fn iter(&self) -> Result<Vec<Host>, Error> {
        self.hosts()
    }

    /// Retrieves the list of known hosts
    pub fn hosts(&self) -> Result<Vec<Host>, Error> {
        let mut next = null_mut();
        let mut prev = null_mut();
        let sess = self.sess.lock();
        let mut hosts = vec![];

        loop {
            match unsafe { raw::libssh2_knownhost_get(self.raw, &mut next, prev) } {
                0 => {
                    prev = next;
                    hosts.push(unsafe { Host::from_raw(next) });
                }
                1 => break,
                rc => return Err(Error::from_session_error_raw(sess.raw, rc)),
            }
        }

        Ok(hosts)
    }

    /// Given a Host object, find the matching raw node in the internal list.
    /// The returned value is only valid while the session is locked.
    fn resolve_to_raw_host(
        &self,
        sess: &MutexGuard<SessionInner>,
        host: &Host,
    ) -> Result<Option<*mut raw::libssh2_knownhost>, Error> {
        let mut next = null_mut();
        let mut prev = null_mut();

        loop {
            match unsafe { raw::libssh2_knownhost_get(self.raw, &mut next, prev) } {
                0 => {
                    prev = next;
                    let current = unsafe { Host::from_raw(next) };
                    if current == *host {
                        return Ok(Some(next));
                    }
                }
                1 => break,
                rc => return Err(Error::from_session_error_raw(sess.raw, rc)),
            }
        }
        Ok(None)
    }

    /// Delete a known host entry from the collection of known hosts.
    pub fn remove(&self, host: &Host) -> Result<(), Error> {
        let sess = self.sess.lock();

        if let Some(raw_host) = self.resolve_to_raw_host(&sess, host)? {
            return sess.rc(unsafe { raw::libssh2_knownhost_del(self.raw, raw_host) });
        } else {
            Ok(())
        }
    }

    /// Checks a host and its associated key against the collection of known
    /// hosts, and returns info back about the (partially) matched entry.
    ///
    /// The host name can be the IP numerical address of the host or the full
    /// name. The key must be the raw data of the key.
    pub fn check(&self, host: &str, key: &[u8]) -> CheckResult {
        self.check_port_(host, -1, key)
    }

    /// Same as `check`, but takes a port as well.
    pub fn check_port(&self, host: &str, port: u16, key: &[u8]) -> CheckResult {
        self.check_port_(host, port as i32, key)
    }

    fn check_port_(&self, host: &str, port: i32, key: &[u8]) -> CheckResult {
        let host = CString::new(host).unwrap();
        let flags = raw::LIBSSH2_KNOWNHOST_TYPE_PLAIN | raw::LIBSSH2_KNOWNHOST_KEYENC_RAW;
        unsafe {
            let rc = raw::libssh2_knownhost_checkp(
                self.raw,
                host.as_ptr(),
                port as c_int,
                key.as_ptr() as *const _,
                key.len() as size_t,
                flags,
                null_mut(),
            );
            match rc {
                raw::LIBSSH2_KNOWNHOST_CHECK_MATCH => CheckResult::Match,
                raw::LIBSSH2_KNOWNHOST_CHECK_MISMATCH => CheckResult::Mismatch,
                raw::LIBSSH2_KNOWNHOST_CHECK_NOTFOUND => CheckResult::NotFound,
                _ => CheckResult::Failure,
            }
        }
    }

    /// Adds a known host to the collection of known hosts.
    ///
    /// The host is the host name in plain text. The host name can be the IP
    /// numerical address of the host or the full name. If you want to add a key
    /// for a specific port number for the given host, you must provide the host
    /// name like `"[host]:port"` with the actual characters `[` and `]` enclosing
    /// the host name and a colon separating the host part from the port number.
    /// For example: `"[host.example.com]:222"`.
    ///
    /// The key provided must be the raw key for the host.
    pub fn add(
        &mut self,
        host: &str,
        key: &[u8],
        comment: &str,
        fmt: ::KnownHostKeyFormat,
    ) -> Result<(), Error> {
        let host = CString::new(host)?;
        let comment = CString::new(comment)?;
        let flags =
            raw::LIBSSH2_KNOWNHOST_TYPE_PLAIN | raw::LIBSSH2_KNOWNHOST_KEYENC_RAW | (fmt as c_int);
        let sess = self.sess.lock();
        unsafe {
            let rc = raw::libssh2_knownhost_addc(
                self.raw,
                host.as_ptr() as *mut _,
                null_mut(),
                key.as_ptr() as *mut _,
                key.len() as size_t,
                comment.as_ptr() as *const _,
                comment.as_bytes().len() as size_t,
                flags,
                null_mut(),
            );
            sess.rc(rc)
        }
    }
}

impl Drop for KnownHosts {
    fn drop(&mut self) {
        let _sess = self.sess.lock();
        unsafe { raw::libssh2_knownhost_free(self.raw) }
    }
}

impl Host {
    /// This is `None` if no plain text host name exists.
    pub fn name(&self) -> Option<&str> {
        self.name.as_ref().map(String::as_str)
    }

    /// Returns the key in base64/printable format
    pub fn key(&self) -> &str {
        &self.key
    }

    unsafe fn from_raw(raw: *mut raw::libssh2_knownhost) -> Self {
        let name = ::opt_bytes(&raw, (*raw).name).and_then(|s| String::from_utf8(s.to_vec()).ok());
        let key = ::opt_bytes(&raw, (*raw).key).unwrap();
        let key = String::from_utf8(key.to_vec()).unwrap();
        Self { name, key }
    }
}


================================================
FILE: src/lib.rs
================================================
//! Rust bindings to libssh2, an SSH client library.
//!
//! This library intends to provide a safe interface to the libssh2 library. It
//! will build the library if it's not available on the local system, and
//! otherwise link to an installed copy.
//!
//! Note that libssh2 only supports SSH *clients*, not SSH *servers*.
//! Additionally it only supports protocol v2, not protocol v1.
//!
//! # Examples
//!
//! ## Inspecting ssh-agent
//!
//! ```no_run
//! use ssh2::Session;
//!
//! // Almost all APIs require a `Session` to be available
//! let sess = Session::new().unwrap();
//! let mut agent = sess.agent().unwrap();
//!
//! // Connect the agent and request a list of identities
//! agent.connect().unwrap();
//! agent.list_identities().unwrap();
//!
//! for identity in agent.identities().unwrap() {
//!     println!("{}", identity.comment());
//!     let pubkey = identity.blob();
//! }
//! ```
//!
//! ## Authenticating with ssh-agent
//!
//! ```no_run
//! use std::net::TcpStream;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
//! let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
//! let mut sess = Session::new().unwrap();
//! sess.set_tcp_stream(tcp);
//! sess.handshake().unwrap();
//!
//! // Try to authenticate with the first identity in the agent.
//! sess.userauth_agent("username").unwrap();
//!
//! // Make sure we succeeded
//! assert!(sess.authenticated());
//! ```
//!
//! ## Authenticating with a password
//!
//! ```no_run
//! use std::net::TcpStream;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
//! let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
//! let mut sess = Session::new().unwrap();
//! sess.set_tcp_stream(tcp);
//! sess.handshake().unwrap();
//!
//! sess.userauth_password("username", "password").unwrap();
//! assert!(sess.authenticated());
//! ```
//!
//! ## Run a command
//!
//! ```no_run
//! use std::io::prelude::*;
//! use std::net::TcpStream;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
//! let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
//! let mut sess = Session::new().unwrap();
//! sess.set_tcp_stream(tcp);
//! sess.handshake().unwrap();
//! sess.userauth_agent("username").unwrap();
//!
//! let mut channel = sess.channel_session().unwrap();
//! channel.exec("ls").unwrap();
//! let mut s = String::new();
//! channel.read_to_string(&mut s).unwrap();
//! println!("{}", s);
//! channel.wait_close().unwrap();
//! println!("{}", channel.exit_status().unwrap());
//! ```
//!
//! ## Upload a file
//!
//! ```no_run
//! use std::io::prelude::*;
//! use std::net::TcpStream;
//! use std::path::Path;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
//! let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
//! let mut sess = Session::new().unwrap();
//! sess.set_tcp_stream(tcp);
//! sess.handshake().unwrap();
//! sess.userauth_agent("username").unwrap();
//!
//! // Write the file
//! let mut remote_file = sess.scp_send(Path::new("remote"),
//!                                     0o644, 10, None).unwrap();
//! remote_file.write(b"1234567890").unwrap();
//! // Close the channel and wait for the whole content to be transferred
//! remote_file.send_eof().unwrap();
//! remote_file.wait_eof().unwrap();
//! remote_file.close().unwrap();
//! remote_file.wait_close().unwrap();
//! ```
//!
//! ## Download a file
//!
//! ```no_run
//! use std::io::prelude::*;
//! use std::net::TcpStream;
//! use std::path::Path;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
//! let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
//! let mut sess = Session::new().unwrap();
//! sess.set_tcp_stream(tcp);
//! sess.handshake().unwrap();
//! sess.userauth_agent("username").unwrap();
//!
//! let (mut remote_file, stat) = sess.scp_recv(Path::new("remote")).unwrap();
//! println!("remote file size: {}", stat.size());
//! let mut contents = Vec::new();
//! remote_file.read_to_end(&mut contents).unwrap();
//!
//! // Close the channel and wait for the whole content to be tranferred
//! remote_file.send_eof().unwrap();
//! remote_file.wait_eof().unwrap();
//! remote_file.close().unwrap();
//! remote_file.wait_close().unwrap();
//! ```
//!
//! ## Execute a Netconf XML payload
//!
//! ```no_run
//! use ssh2::{Channel, Session};
//! use std::error::Error;
//! use std::io::prelude::*;
//! use std::net::TcpStream;
//!
//! const HELLO: &str = "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
//!   <capabilities>
//!     <capability>urn:ietf:params:netconf:base:1.1</capability>
//!   </capabilities>
//! </hello>
//! ]]>]]>";
//!
//! const PAYLOAD: &str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
//!     <rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.1\" message-id=\"2\">
//!     <cli xmlns=\"http://cisco.com/ns/yang/cisco-nx-os-device\"><mode>EXEC</mode><cmdline>show version</cmdline></cli>
//! </rpc>";
//!
//! fn read(channel: &mut Channel) -> Result<String, Box<dyn Error>> {
//!     let mut result = String::new();
//!     loop {
//!         // If you plan to use this, be aware that reading 1 byte at a time is terribly
//!         // inefficient and should be optimized for your usecase. This is just an example.
//!         let mut buffer = [1u8; 1];
//!         let bytes_read = channel.read(&mut buffer[..])?;
//!         let s = String::from_utf8_lossy(&buffer[..bytes_read]);
//!         result.push_str(&s);
//!         if result.ends_with("]]>]]>") {
//!             println!("Found netconf 1.0 terminator, breaking read loop");
//!             break;
//!         }
//!         if result.ends_with("##") {
//!             println!("Found netconf 1.1 terminator, breaking read loop");
//!             break;
//!         }
//!         if bytes_read == 0 || channel.eof() {
//!             println!("Buffer is empty, SSH channel read terminated");
//!             break;
//!         }
//!     }
//!     Ok(result)
//! }
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//!     let tcp = TcpStream::connect("127.0.0.1:830")?;
//!     let mut sess = Session::new()?;
//!     sess.set_tcp_stream(tcp);
//!     sess.handshake().unwrap();
//!     sess.userauth_password("user", "pass")?;
//!
//!     let mut channel = sess.channel_session()?;
//!     channel.subsystem("netconf")?;
//!     let result = read(&mut channel)?;
//!     println!("Result from connection:\n{}", result);
//!
//!     let payload = format!("{}\n#{}\n{}\n##\n", HELLO, PAYLOAD.len(), PAYLOAD);
//!     let a = channel.write(payload.as_bytes())?;
//!     println!("Written {} bytes payload", a);
//!     let result = read(&mut channel)?;
//!     println!("Result from payload execution:\n{}", result);
//!
//!     channel.send_eof()?;
//!     channel.wait_eof()?;
//!     channel.close()?;
//!     channel.wait_close()?;
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/ssh2")]
#![allow(trivial_numeric_casts)]
#![deny(missing_docs, unused_results)]
#![cfg_attr(test, deny(warnings))]

extern crate libc;
extern crate libssh2_sys as raw;
#[macro_use]
extern crate bitflags;
extern crate parking_lot;

use std::ffi::CStr;

pub use agent::{Agent, PublicKey};
pub use channel::{Channel, ExitSignal, ReadWindow, Stream, WriteWindow};
pub use error::{Error, ErrorCode};
pub use knownhosts::{Host, KnownHosts};
pub use listener::Listener;
use session::SessionInner;
pub use session::{BlockDirections, KeyboardInteractivePrompt, Prompt, ScpFileStat, Session, TraceFlags};
pub use sftp::{File, FileStat, FileType, OpenType};
pub use sftp::{OpenFlags, RenameFlags, Sftp};
pub use DisconnectCode::{AuthCancelledByUser, TooManyConnections};
pub use DisconnectCode::{ByApplication, ConnectionLost, HostKeyNotVerifiable};
pub use DisconnectCode::{CompressionError, KeyExchangeFailed, MacError, Reserved};
pub use DisconnectCode::{HostNotAllowedToConnect, ProtocolError};
pub use DisconnectCode::{IllegalUserName, NoMoreAuthMethodsAvailable};
pub use DisconnectCode::{ProtocolVersionNotSupported, ServiceNotAvailable};

mod agent;
mod channel;
mod error;
mod knownhosts;
mod listener;
mod session;
mod sftp;
mod util;

/// Initialize the libssh2 library.
///
/// This is optional, it is lazily invoked.
pub fn init() {
    raw::init();
}

unsafe fn opt_bytes<'a, T>(_: &'a T, c: *const libc::c_char) -> Option<&'a [u8]> {
    if c.is_null() {
        None
    } else {
        Some(CStr::from_ptr(c).to_bytes())
    }
}

#[allow(missing_docs)]
#[derive(Copy, Clone)]
pub enum DisconnectCode {
    HostNotAllowedToConnect = raw::SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT as isize,
    ProtocolError = raw::SSH_DISCONNECT_PROTOCOL_ERROR as isize,
    KeyExchangeFailed = raw::SSH_DISCONNECT_KEY_EXCHANGE_FAILED as isize,
    Reserved = raw::SSH_DISCONNECT_RESERVED as isize,
    MacError = raw::SSH_DISCONNECT_MAC_ERROR as isize,
    CompressionError = raw::SSH_DISCONNECT_COMPRESSION_ERROR as isize,
    ServiceNotAvailable = raw::SSH_DISCONNECT_SERVICE_NOT_AVAILABLE as isize,
    ProtocolVersionNotSupported = raw::SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED as isize,
    HostKeyNotVerifiable = raw::SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE as isize,
    ConnectionLost = raw::SSH_DISCONNECT_CONNECTION_LOST as isize,
    ByApplication = raw::SSH_DISCONNECT_BY_APPLICATION as isize,
    TooManyConnections = raw::SSH_DISCONNECT_TOO_MANY_CONNECTIONS as isize,
    AuthCancelledByUser = raw::SSH_DISCONNECT_AUTH_CANCELLED_BY_USER as isize,
    NoMoreAuthMethodsAvailable = raw::SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE as isize,
    IllegalUserName = raw::SSH_DISCONNECT_ILLEGAL_USER_NAME as isize,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum HostKeyType {
    Unknown = raw::LIBSSH2_HOSTKEY_TYPE_UNKNOWN as isize,
    Rsa = raw::LIBSSH2_HOSTKEY_TYPE_RSA as isize,
    Dss = raw::LIBSSH2_HOSTKEY_TYPE_DSS as isize,
    Ecdsa256 = raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_256 as isize,
    Ecdsa384 = raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_384 as isize,
    Ecdsa521 = raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_521 as isize,
    Ed25519 = raw::LIBSSH2_HOSTKEY_TYPE_ED25519 as isize,
}

#[allow(missing_docs)]
#[derive(Copy, Clone)]
pub enum MethodType {
    Kex = raw::LIBSSH2_METHOD_KEX as isize,
    HostKey = raw::LIBSSH2_METHOD_HOSTKEY as isize,
    CryptCs = raw::LIBSSH2_METHOD_CRYPT_CS as isize,
    CryptSc = raw::LIBSSH2_METHOD_CRYPT_SC as isize,
    MacCs = raw::LIBSSH2_METHOD_MAC_CS as isize,
    MacSc = raw::LIBSSH2_METHOD_MAC_SC as isize,
    CompCs = raw::LIBSSH2_METHOD_COMP_CS as isize,
    CompSc = raw::LIBSSH2_METHOD_COMP_SC as isize,
    LangCs = raw::LIBSSH2_METHOD_LANG_CS as isize,
    LangSc = raw::LIBSSH2_METHOD_LANG_SC as isize,
    SignAlgo = raw::LIBSSH2_METHOD_SIGN_ALGO as isize,
}

/// When passed to `Channel::flush_stream`, flushes all extended data
/// substreams.
pub static FLUSH_EXTENDED_DATA: i32 = -1;
/// When passed to `Channel::flush_stream`, flushes all substream.
pub static FLUSH_ALL: i32 = -2;
/// Stream ID of the stderr channel for stream-related methods on `Channel`
pub static EXTENDED_DATA_STDERR: i32 = 1;

#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum HashType {
    Md5 = raw::LIBSSH2_HOSTKEY_HASH_MD5 as isize,
    Sha1 = raw::LIBSSH2_HOSTKEY_HASH_SHA1 as isize,
    Sha256 = raw::LIBSSH2_HOSTKEY_HASH_SHA256 as isize,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum KnownHostFileKind {
    OpenSSH = raw::LIBSSH2_KNOWNHOST_FILE_OPENSSH as isize,
}

/// Possible results of a call to `KnownHosts::check`
#[derive(Copy, Clone, Debug)]
pub enum CheckResult {
    /// Hosts and keys match
    Match = raw::LIBSSH2_KNOWNHOST_CHECK_MATCH as isize,
    /// Host was found, but the keys didn't match!
    Mismatch = raw::LIBSSH2_KNOWNHOST_CHECK_MISMATCH as isize,
    /// No host match was found
    NotFound = raw::LIBSSH2_KNOWNHOST_CHECK_NOTFOUND as isize,
    /// Something prevented the check to be made
    Failure = raw::LIBSSH2_KNOWNHOST_CHECK_FAILURE as isize,
}

#[allow(missing_docs)]
#[derive(Copy, Clone, Debug)]
pub enum KnownHostKeyFormat {
    Unknown = raw::LIBSSH2_KNOWNHOST_KEY_UNKNOWN as isize,
    Rsa1 = raw::LIBSSH2_KNOWNHOST_KEY_RSA1 as isize,
    SshRsa = raw::LIBSSH2_KNOWNHOST_KEY_SSHRSA as isize,
    SshDss = raw::LIBSSH2_KNOWNHOST_KEY_SSHDSS as isize,
    Ecdsa256 = raw::LIBSSH2_KNOWNHOST_KEY_ECDSA_256 as isize,
    Ecdsa384 = raw::LIBSSH2_KNOWNHOST_KEY_ECDSA_384 as isize,
    Ecdsa521 = raw::LIBSSH2_KNOWNHOST_KEY_ECDSA_521 as isize,
    Ed25519 = raw::LIBSSH2_KNOWNHOST_KEY_ED25519 as isize,
}

impl From<HostKeyType> for KnownHostKeyFormat {
    fn from(host_type: HostKeyType) -> KnownHostKeyFormat {
        match host_type {
            HostKeyType::Unknown => KnownHostKeyFormat::Unknown,
            HostKeyType::Rsa => KnownHostKeyFormat::SshRsa,
            HostKeyType::Dss => KnownHostKeyFormat::SshDss,
            HostKeyType::Ecdsa256 => KnownHostKeyFormat::Ecdsa256,
            HostKeyType::Ecdsa384 => KnownHostKeyFormat::Ecdsa384,
            HostKeyType::Ecdsa521 => KnownHostKeyFormat::Ecdsa521,
            HostKeyType::Ed25519 => KnownHostKeyFormat::Ed25519,
        }
    }
}

/// How to handle extended data streams, such as stderr
#[derive(Copy, Clone, Debug)]
pub enum ExtendedData {
    /// Queue extended data for eventual reading
    Normal = raw::LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL as isize,
    /// Treat extended data and ordinary data the same. Merge all substreams such that calls to
    /// read will pull from all substreams on a first-in/first-out basis.
    Merge = raw::LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE as isize,
    /// Discard all extended data as it arrives.
    Ignore = raw::LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE as isize,
}

/// The modes described in <https://tools.ietf.org/html/rfc4250#section-4.5.2>
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum PtyModeOpcode {
    /// Indicates end of options.
    TTY_OP_END = 0,
    /// Interrupt character; 255 if none.  Similarly for the other characters.  Not all of these characters are supported on all systems.
    VINTR = 1,
    /// The quit character (sends SIGQUIT signal on POSIX systems).
    VQUIT = 2,
    /// Erase the character to left of the cursor.
    VERASE = 3,
    /// Kill the current input line.
    VKILL = 4,
    /// End-of-file character (sends EOF from the terminal).
    VEOF = 5,
    /// End-of-line character in addition to carriage return and/or linefeed.
    VEOL = 6,
    /// Additional end-of-line character.
    VEOL2 = 7,
    /// Continues paused output (normally control-Q).
    VSTART = 8,
    /// Pauses output (normally control-S).
    VSTOP = 9,
    /// Suspends the current program.
    VSUSP = 10,
    /// Another suspend character.
    VDSUSP = 11,
    /// Reprints the current input line.
    VREPRINT = 12,
    /// Erases a word left of cursor.
    VWERASE = 13,
    /// Enter the next character typed literally, even if it is a special character
    VLNEXT = 14,
    /// Character to flush output.
    VFLUSH = 15,
    /// Switch to a different shell layer.
    VSWTCH = 16,
    /// Prints system status line (load, command, pid, etc).
    VSTATUS = 17,
    /// Toggles the flushing of terminal output.
    VDISCARD = 18,
    /// The ignore parity flag.  The parameter SHOULD be 0 if this flag is FALSE, and 1 if it is TRUE.
    IGNPAR = 30,
    /// Mark parity and framing errors.
    PARMRK = 31,
    /// Enable checking of parity errors.
    INPCK = 32,
    /// Strip 8th bit off characters.
    ISTRIP = 33,
    /// Map NL into CR on input.
    INLCR = 34,
    /// Ignore CR on input.
    IGNCR = 35,
    /// Map CR to NL on input.
    ICRNL = 36,
    /// Translate uppercase characters to lowercase.
    IUCLC = 37,
    /// Enable output flow control.
    IXON = 38,
    /// Any char will restart after stop.
    IXANY = 39,
    /// Enable input flow control.
    IXOFF = 49,
    /// Ring bell on input queue full.
    IMAXBEL = 41,
    /// Enable signals INTR, QUIT, [D]SUSP.
    ISIG = 50,
    /// Canonicalize input lines.
    ICANON = 51,

    /// Enable input and output of uppercase characters by preceding their lowercase equivalents with "\".
    XCASE = 52,
    /// Enable echoing.
    ECHO = 53,
    /// Visually erase chars.
    ECHOE = 54,
    /// Kill character discards current line.
    ECHOK = 55,
    /// Echo NL even if ECHO is off.
    ECHONL = 56,
    /// Don't flush after interrupt.
    NOFLSH = 57,
    /// Stop background jobs from output.
    TOSTOP = 58,
    /// Enable extensions.
    IEXTEN = 59,
    /// Echo control characters as ^(Char).
    ECHOCTL = 60,
    /// Visual erase for line kill.
    ECHOKE = 61,
    /// Retype pending input.
    PENDIN = 62,
    /// Enable output processing.
    OPOST = 70,
    /// Convert lowercase to uppercase.
    OLCUC = 71,
    /// Map NL to CR-NL.
    ONLCR = 72,
    /// Translate carriage return to newline (output).
    OCRNL = 73,
    /// Translate newline to carriage return-newline (output).
    ONOCR = 74,
    /// Newline performs a carriage return (output).
    ONLRET = 75,
    /// 7 bit mode.
    CS7 = 90,
    /// 8 bit mode.
    CS8 = 91,
    /// Parity enable.
    PARENB = 92,
    /// Odd parity, else even.
    PARODD = 93,

    /// Specifies the input baud rate in bits per second.
    TTY_OP_ISPEED = 128,
    /// Specifies the output baud rate in bits per second.
    TTY_OP_OSPEED = 129,
}

/// An opcode for setting a Pty terminal mode
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ExtensiblePtyModeOpcode {
    /// Use one of the modes specified by RFC 4250
    Mode(PtyModeOpcode),
    /// Use a mode not reflected by RFC 4250
    Extended(u8),
}

impl From<PtyModeOpcode> for ExtensiblePtyModeOpcode {
    fn from(op: PtyModeOpcode) -> ExtensiblePtyModeOpcode {
        ExtensiblePtyModeOpcode::Mode(op)
    }
}

impl From<u8> for ExtensiblePtyModeOpcode {
    fn from(op: u8) -> ExtensiblePtyModeOpcode {
        ExtensiblePtyModeOpcode::Extended(op)
    }
}

impl ExtensiblePtyModeOpcode {
    fn as_opcode(&self) -> u8 {
        match self {
            ExtensiblePtyModeOpcode::Mode(m) => *m as u8,
            ExtensiblePtyModeOpcode::Extended(op) => *op,
        }
    }
}

/// Encodes modes for Pty allocation requests.
/// The modes documented in <https://tools.ietf.org/html/rfc4250#section-4.5>
/// are supported.
#[derive(Debug, Clone)]
pub struct PtyModes {
    data: Vec<u8>,
}

impl PtyModes {
    /// Construct a PtyModes instance so that you can specify values for
    /// various modes
    pub fn new() -> Self {
        Self { data: vec![] }
    }

    /// Set a mode to an arbitrary u32 value
    pub fn set_u32<O: Into<ExtensiblePtyModeOpcode>>(&mut self, option: O, value: u32) {
        let data = [
            option.into().as_opcode(),
            ((value >> 24) & 0xff) as u8,
            ((value >> 16) & 0xff) as u8,
            ((value >> 8) & 0xff) as u8,
            (value & 0xff) as u8,
        ];
        self.data.extend_from_slice(&data);
    }

    /// Set a mode to a boolean value
    pub fn set_boolean<O: Into<ExtensiblePtyModeOpcode>>(&mut self, option: O, value: bool) {
        self.set_u32(option, if value { 1 } else { 0 })
    }

    /// Set a mode to a character value.
    /// If the character is None it is set to 255 to indicate that it
    /// is disabled.
    /// While this interface and the protocol accept unicode characters
    /// of up to 32 bits in width, these options likely only work for
    /// characters in the 7-bit ascii range.
    pub fn set_character<O: Into<ExtensiblePtyModeOpcode>>(&mut self, option: O, c: Option<char>) {
        self.set_u32(option, c.map(|c| c as u32).unwrap_or(255))
    }

    /// Finish accumulating modes and return the encoded
    /// byte stream suitable for use in the ssh2 protocol
    pub fn finish(mut self) -> Vec<u8> {
        self.data.push(PtyModeOpcode::TTY_OP_END as u8);
        self.data
    }
}


================================================
FILE: src/listener.rs
================================================
use parking_lot::Mutex;
use std::sync::Arc;
use {raw, Channel, Error, SessionInner};

/// A listener represents a forwarding port from the remote server.
///
/// New channels can be accepted from a listener which represent connections on
/// the remote server's port.
pub struct Listener {
    raw: *mut raw::LIBSSH2_LISTENER,
    sess: Arc<Mutex<SessionInner>>,
}

// Listener is both Send and Sync; the compiler can't see it because it
// is pessimistic about the raw pointer.  We use Arc/Mutex to guard accessing
// the raw pointer so we are safe for both.
unsafe impl Send for Listener {}
unsafe impl Sync for Listener {}

impl Listener {
    /// Accept a queued connection from this listener.
    pub fn accept(&mut self) -> Result<Channel, Error> {
        let sess = self.sess.lock();
        unsafe {
            let chan = raw::libssh2_channel_forward_accept(self.raw);
            let err = sess.last_error();
            Channel::from_raw_opt(chan, err, &self.sess)
        }
    }

    pub(crate) fn from_raw_opt(
        raw: *mut raw::LIBSSH2_LISTENER,
        err: Option<Error>,
        sess: &Arc<Mutex<SessionInner>>,
    ) -> Result<Self, Error> {
        if raw.is_null() {
            Err(err.unwrap_or_else(Error::unknown))
        } else {
            Ok(Self {
                raw,
                sess: Arc::clone(sess),
            })
        }
    }
}

impl Drop for Listener {
    fn drop(&mut self) {
        let _sess = self.sess.lock();
        unsafe {
            let _ = raw::libssh2_channel_forward_cancel(self.raw);
        }
    }
}


================================================
FILE: src/session.rs
================================================
// Usings for openssl function userauth_pubkey_memory()
#[cfg(any(unix, feature = "vendored-openssl", feature = "openssl-on-win32"))]
use libc::size_t;
use libc::{self, c_char, c_int, c_long, c_uint, c_void};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use std::borrow::Cow;
use std::ffi::CString;
use std::ptr::{null, null_mut};
use std::mem;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};
use std::path::Path;
use std::slice;
use std::str;
use std::sync::Arc;

use util;
use {raw, ByApplication, DisconnectCode, Error, ErrorCode, HostKeyType};
use {Agent, Channel, HashType, KnownHosts, Listener, MethodType, Sftp};

bitflags! {
    /// Flags which can be used with the session trace method to set
    /// the trace level.
    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
    pub struct TraceFlags: c_int {
        /// Authentication debugging
        const AUTH      = raw::LIBSSH2_TRACE_AUTH;
        /// Connection layer debugging
        const CONN      = raw::LIBSSH2_TRACE_CONN;
        /// Error debugging
        const ERROR     = raw::LIBSSH2_TRACE_ERROR;
        /// Key exchange debugging
        const KEX       = raw::LIBSSH2_TRACE_KEX;
        /// Public Key Debugging
        const PUBLICKEY = raw::LIBSSH2_TRACE_PUBLICKEY;
        /// SCP debugging
        const SCP       = raw::LIBSSH2_TRACE_SCP;
        /// SFTP debugging
        const SFTP      = raw::LIBSSH2_TRACE_SFTP;
        /// Socket low-level debugging
        const SOCKET    = raw::LIBSSH2_TRACE_SOCKET;
        /// Transport layer debugging
        const TRANS     = raw::LIBSSH2_TRACE_TRANS;
    }
}

/// Called by libssh2 to respond to some number of challenges as part of
/// keyboard interactive authentication.
pub trait KeyboardInteractivePrompt {
    /// `username` is the user name to be authenticated. It may not be the
    /// same as the username passed to `Session::userauth_keyboard_interactive`,
    /// and may be empty.
    /// `instructions` is some informational text to be displayed to the user.
    /// `prompts` is a series of prompts (or challenges) that must be responded
    /// to.
    /// The return value should be a Vec that holds one response for each prompt.
    fn prompt<'a>(
        &mut self,
        username: &str,
        instructions: &str,
        prompts: &[Prompt<'a>],
    ) -> Vec<String>;
}

/// A prompt/challenge returned as part of keyboard-interactive authentication
#[derive(Debug)]
pub struct Prompt<'a> {
    /// The label to show when prompting the user
    pub text: Cow<'a, str>,
    /// If true, the response that the user inputs should be displayed
    /// as they type.  If false then treat it as a password entry and
    /// do not display what is typed in response to this prompt.
    pub echo: bool,
}

/// This is a little helper function that is perhaps slightly overkill for the
/// current needs.
/// It saves the current sess->abstract pointer and replaces it with a
/// different values for the duration of the call to the supplied lambda.
/// When the lambda returns, the original abstract value is restored
/// and the result of the lambda is returned.
unsafe fn with_abstract<R, F: FnOnce() -> R>(
    sess: *mut raw::LIBSSH2_SESSION,
    new_value: *mut c_void,
    f: F,
) -> R {
    let abstrakt = raw::libssh2_session_abstract(sess);
    let old_value = *abstrakt;
    *abstrakt = new_value;
    let res = f();
    *abstrakt = old_value;
    res
}

pub(crate) struct SessionInner {
    pub(crate) raw: *mut raw::LIBSSH2_SESSION,
    #[cfg(unix)]
    tcp: Option<Box<dyn AsRawFd>>,
    #[cfg(windows)]
    tcp: Option<Box<dyn AsRawSocket>>,
}

// The compiler doesn't know that it is Send safe because of the raw
// pointer inside.  We know that the way that it is used by libssh2
// and this crate is Send safe.
unsafe impl Send for SessionInner {}

/// An SSH session, typically representing one TCP connection.
///
/// All other structures are based on an SSH session and cannot outlive a
/// session. Sessions are created and then have the TCP socket handed to them
/// (via the `set_tcp_stream` method).
///
/// `Session`, and any objects its methods return, hold a reference to the underlying
/// SSH session.  You may clone `Session` to obtain another handle referencing
/// the same session, and create multiple `Channel` and `Stream` objects
/// from that same underlying session, which can all be passed across thread
/// boundaries (they are `Send` and `Sync`).  These are all related objects and
/// are internally synchronized via a `Mutex` to make it safe to pass them
/// around in this way.
///
/// This means that a blocking read from a `Channel` or `Stream` will block
/// all other calls on objects created from the same underlying `Session`.
/// If you need the ability to perform concurrent operations then you will
/// need to create separate `Session` instances, or employ non-blocking mode.
#[derive(Clone)]
pub struct Session {
    inner: Arc<Mutex<SessionInner>>,
}

/// Metadata returned about a remote file when received via `scp`.
pub struct ScpFileStat {
    stat: libc::stat,
}

/// The io direction an application has to wait for in order not to block.
#[derive(Debug, PartialEq)]
pub enum BlockDirections {
    /// No direction blocked.
    None,
    /// Inbound direction blocked.
    Inbound,
    /// Outbound direction blockd.
    Outbound,
    /// Inbound and Outbound direction blocked.
    Both,
}

impl Session {
    /// Initializes an SSH session object.
    ///
    /// This function does not associate the session with a remote connection
    /// just yet. Various configuration options can be set such as the blocking
    /// mode, compression, sigpipe, the banner, etc. To associate this session
    /// with a TCP connection, use the `set_tcp_stream` method pass in an
    /// already-established TCP socket, and then follow up with a call to
    /// `handshake` to perform the ssh protocol handshake.
    pub fn new() -> Result<Session, Error> {
        ::init();
        unsafe {
            let ret = raw::libssh2_session_init_ex(None, None, None, null_mut());
            if ret.is_null() {
                Err(Error::unknown())
            } else {
                Ok(Session {
                    inner: Arc::new(Mutex::new(SessionInner {
                        raw: ret,
                        tcp: None,
                    })),
                })
            }
        }
    }

    #[doc(hidden)]
    pub fn raw(&self) -> MappedMutexGuard<'_, raw::LIBSSH2_SESSION> {
        let inner = self.inner();
        MutexGuard::map(inner, |inner| unsafe { &mut *inner.raw })
    }

    /// Set the SSH protocol banner for the local client
    ///
    /// Set the banner that will be sent to the remote host when the SSH session
    /// is started with handshake(). This is optional; a banner
    /// corresponding to the protocol and libssh2 version will be sent by
    /// default.
    pub fn set_banner(&self, banner: &str) -> Result<(), Error> {
        let banner = CString::new(banner)?;
        let inner = self.inner();
        unsafe { inner.rc(raw::libssh2_session_banner_set(inner.raw, banner.as_ptr())) }
    }

    /// Flag indicating whether SIGPIPE signals will be allowed or blocked.
    ///
    /// By default (on relevant platforms) this library will attempt to block
    /// and catch SIGPIPE signals. Setting this flag to `true` will cause
    /// the library to not attempt to block SIGPIPE from the underlying socket
    /// layer.
    pub fn set_allow_sigpipe(&self, block: bool) {
        let inner = self.inner();
        let res = unsafe {
            inner.rc(raw::libssh2_session_flag(
                inner.raw,
                raw::LIBSSH2_FLAG_SIGPIPE as c_int,
                block as c_int,
            ))
        };
        res.unwrap();
    }

    /// Flag indicating whether this library will attempt to negotiate
    /// compression.
    ///
    /// If set - before the connection negotiation is performed - libssh2 will
    /// try to negotiate compression enabling for this connection. By default
    /// libssh2 will not attempt to use compression.
    pub fn set_compress(&self, compress: bool) {
        let inner = self.inner();
        let res = unsafe {
            inner.rc(raw::libssh2_session_flag(
                inner.raw,
                raw::LIBSSH2_FLAG_COMPRESS as c_int,
                compress as c_int,
            ))
        };
        res.unwrap();
    }

    /// Set or clear blocking mode on session
    ///
    /// This will instantly affect any channels associated with this session. If
    /// a read is performed on a session with no data currently available, a
    /// blocking session will wait for data to arrive and return what it
    /// receives. A non-blocking session will return immediately with an empty
    /// buffer. If a write is performed on a session with no room for more data,
    /// a blocking session will wait for room. A non-blocking session will
    /// return immediately without writing anything.
    pub fn set_blocking(&self, blocking: bool) {
        self.inner().set_blocking(blocking);
    }

    /// Returns whether the session was previously set to nonblocking.
    pub fn is_blocking(&self) -> bool {
        self.inner().is_blocking()
    }

    /// Set timeout for blocking functions.
    ///
    /// Set the timeout in milliseconds for how long a blocking the libssh2
    /// function calls may wait until they consider the situation an error and
    /// return an error.
    ///
    /// By default or if you set the timeout to zero, libssh2 has no timeout
    /// for blocking functions.
    pub fn set_timeout(&self, timeout_ms: u32) {
        let timeout_ms = timeout_ms as c_long;
        let inner = self.inner();
        unsafe { raw::libssh2_session_set_timeout(inner.raw, timeout_ms) }
    }

    /// Returns the timeout, in milliseconds, for how long blocking calls may
    /// wait until they time out.
    ///
    /// A timeout of 0 signifies no timeout.
    pub fn timeout(&self) -> u32 {
        let inner = self.inner();
        unsafe { raw::libssh2_session_get_timeout(inner.raw) as u32 }
    }

    /// Begin transport layer protocol negotiation with the connected host.
    ///
    /// You must call this after associating the session with a tcp stream
    /// via the `set_tcp_stream` function.
    pub fn handshake(&mut self) -> Result<(), Error> {
        #[cfg(windows)]
        unsafe fn handshake(
            raw: *mut raw::LIBSSH2_SESSION,
            stream: &dyn AsRawSocket,
        ) -> libc::c_int {
            raw::libssh2_session_handshake(raw, stream.as_raw_socket())
        }

        #[cfg(unix)]
        unsafe fn handshake(raw: *mut raw::LIBSSH2_SESSION, stream: &dyn AsRawFd) -> libc::c_int {
            raw::libssh2_session_handshake(raw, stream.as_raw_fd())
        }

        let inner = self.inner();

        unsafe {
            let stream = inner.tcp.as_ref().ok_or_else(|| {
                Error::new(
                    ErrorCode::Session(raw::LIBSSH2_ERROR_BAD_SOCKET),
                    "use set_tcp_stream() to associate with a TcpStream",
                )
            })?;

            inner.rc(handshake(inner.raw, stream.as_ref()))
        }
    }

    /// The session takes ownership of the stream provided.
    /// You may use the `AsRawFd` (unix) or `AsRawSocket` (windows) traits
    /// to obtain the raw fd later if required.
    ///
    /// It is also highly recommended that the stream provided is not used
    /// concurrently elsewhere for the duration of this session as it may
    /// interfere with the protocol.
    #[cfg(unix)]
    pub fn set_tcp_stream<S: 'static + AsRawFd>(&mut self, stream: S) {
        let mut inner = self.inner();
        let _ = inner.tcp.replace(Box::new(stream));
    }

    /// The session takes ownership of the stream provided.
    /// You may use the tcp_stream() method to obtain the raw socket later.
    ///
    /// It is also highly recommended that the stream provided is not used
    /// concurrently elsewhere for the duration of this session as it may
    /// interfere with the protocol.
    #[cfg(windows)]
    pub fn set_tcp_stream<S: 'static + AsRawSocket>(&mut self, stream: S) {
        let mut inner = self.inner();
        let _ = inner.tcp.replace(Box::new(stream));
    }

    /// Attempt basic password authentication.
    ///
    /// Note that many SSH servers which appear to support ordinary password
    /// authentication actually have it disabled and use Keyboard Interactive
    /// authentication (routed via PAM or another authentication backed)
    /// instead.
    pub fn userauth_password(&self, username: &str, password: &str) -> Result<(), Error> {
        let username = CString::new(username)?;
        let username = username.as_bytes();
        let password = CString::new(password)?;
        let password = password.as_bytes();
        let inner = self.inner();
        inner.rc(unsafe {
            raw::libssh2_userauth_password_ex(
                inner.raw,
                username.as_ptr() as *const _,
                username.len() as c_uint,
                password.as_ptr() as *const _,
                password.len() as c_uint,
                None,
            )
        })
    }

    /// Attempt keyboard interactive authentication.
    ///
    /// You must supply a callback function to
    pub fn userauth_keyboard_interactive<P: KeyboardInteractivePrompt>(
        &self,
        username: &str,
        prompter: &mut P,
    ) -> Result<(), Error> {
        // hold on to your hats, this is a bit involved.
        // The keyboard interactive callback is a bit tricksy, and we want to wrap the
        // raw C types with something a bit safer and more ergonomic.
        // Since the interface is defined in terms of a simple function pointer, wrapping
        // is a bit awkward.
        //
        // The session struct has an abstrakt pointer reserved for
        // the user of the embedding application, and that pointer is passed to the
        // prompt callback. We can use this to store a pointer to some state so that
        // we can manage the conversion.
        //
        // The prompts and responses are defined to be UTF-8, but we use from_utf8_lossy
        // to avoid panics in case the server isn't conformant for whatever reason.
        extern "C" fn prompt<P: KeyboardInteractivePrompt>(
            username: *const c_char,
            username_len: c_int,
            instruction: *const c_char,
            instruction_len: c_int,
            num_prompts: c_int,
            prompts: *const raw::LIBSSH2_USERAUTH_KBDINT_PROMPT,
            responses: *mut raw::LIBSSH2_USERAUTH_KBDINT_RESPONSE,
            abstrakt: *mut *mut c_void,
        ) {
            use std::panic::{catch_unwind, AssertUnwindSafe};
            // Catch panics; we can't let them unwind to C code.
            // There's not much to be done with them though because the
            // signature of the callback doesn't allow reporting an error.
            let _ = catch_unwind(AssertUnwindSafe(|| {
                if prompts.is_null() || responses.is_null() || num_prompts < 0 {
                    return;
                }

                let prompter = unsafe { &mut **(abstrakt as *mut *mut P) };

                let username = if !username.is_null() && username_len >= 0 {
                    let username = unsafe {
                        slice::from_raw_parts(username as *const u8, username_len as usize)
                    };
                    String::from_utf8_lossy(username)
                } else {
                    Cow::Borrowed("")
                };

                let instruction = if !instruction.is_null() && instruction_len >= 0 {
                    let instruction = unsafe {
                        slice::from_raw_parts(instruction as *const u8, instruction_len as usize)
                    };
                    String::from_utf8_lossy(instruction)
                } else {
                    Cow::Borrowed("")
                };

                let prompts = unsafe { slice::from_raw_parts(prompts, num_prompts as usize) };
                let responses =
                    unsafe { slice::from_raw_parts_mut(responses, num_prompts as usize) };

                let prompts: Vec<Prompt> = prompts
                    .iter()
                    .map(|item| {
                        let data = unsafe {
                            slice::from_raw_parts(item.text as *const u8, item.length as usize)
                        };
                        Prompt {
                            text: String::from_utf8_lossy(data),
                            echo: item.echo != 0,
                        }
                    })
                    .collect();

                // libssh2 wants to be able to free(3) the response strings, so allocate
                // storage and copy the responses into appropriately owned memory.
                // We can't simply call strdup(3) here because the rust string types
                // are not NUL terminated.
                fn strdup_string(s: &str) -> *mut c_char {
                    let len = s.len();
                    let ptr = unsafe { libc::malloc(len + 1) as *mut c_char };
                    if !ptr.is_null() {
                        unsafe {
                            ::std::ptr::copy_nonoverlapping(
                                s.as_bytes().as_ptr() as *const c_char,
                                ptr,
                                len,
                            );
                            *ptr.offset(len as isize) = 0;
                        }
                    }
                    ptr
                }

                for (i, response) in (*prompter)
                    .prompt(&username, &instruction, &prompts)
                    .into_iter()
                    .take(prompts.len())
                    .enumerate()
                {
                    let ptr = strdup_string(&response);
                    if !ptr.is_null() {
                        responses[i].length = response.len() as c_uint;
                    } else {
                        responses[i].length = 0;
                    }
                    responses[i].text = ptr;
                }
            }));
        }

        let username = CString::new(username)?;
        let username = username.as_bytes();
        let inner = self.inner();
        unsafe {
            with_abstract(inner.raw, prompter as *mut P as *mut c_void, || {
                inner.rc(raw::libssh2_userauth_keyboard_interactive_ex(
                    inner.raw,
                    username.as_ptr() as *const _,
                    username.len() as c_uint,
                    Some(prompt::<P>),
                ))
            })
        }
    }

    /// Attempt to perform SSH agent authentication.
    ///
    /// This is a helper method for attempting to authenticate the current
    /// connection with the first public key found in an SSH agent. If more
    /// control is needed than this method offers, it is recommended to use
    /// `agent` directly to control how the identity is found.
    pub fn userauth_agent(&self, username: &str) -> Result<(), Error> {
        let mut agent = self.agent()?;
        agent.connect()?;
        agent.list_identities()?;
        let identities = agent.identities()?;
        let identity = match identities.get(0) {
            Some(identity) => identity,
            None => {
                return Err(Error::new(
                    ErrorCode::Session(raw::LIBSSH2_ERROR_INVAL),
                    "no identities found in the ssh agent",
                ))
            }
        };
        agent.userauth(username, &identity)
    }

    /// Attempt public key authentication using a PEM encoded private key file
    /// stored on disk.
    pub fn userauth_pubkey_file(
        &self,
        username: &str,
        pubkey: Option<&Path>,
        privatekey: &Path,
        passphrase: Option<&str>,
    ) -> Result<(), Error> {
        let username = CString::new(username)?;
        let username = username.as_bytes();
        let pubkey = match pubkey {
            Some(s) => Some(CString::new(util::path2bytes(s)?)?),
            None => None,
        };
        let privatekey = CString::new(util::path2bytes(privatekey)?)?;
        let passphrase = match passphrase {
            Some(s) => Some(CString::new(s)?),
            None => None,
        };
        let inner = self.inner();
        inner.rc(unsafe {
            raw::libssh2_userauth_publickey_fromfile_ex(
                inner.raw,
                username.as_ptr() as *const _,
                username.len() as c_uint,
                pubkey.as_ref().map(|s| s.as_ptr()).unwrap_or(null()),
                privatekey.as_ptr(),
                passphrase
                    .as_ref()
                    .map(|s| s.as_ptr())
                    .unwrap_or(null()),
            )
        })
    }

    /// Attempt public key authentication using a PEM encoded private key from
    /// memory. Public key is computed from private key if none passed.
    /// This is available with openssl enabled (Required for Unix, or with vendored-openssl or openssl-on-win32 features).
    #[cfg(any(unix, feature = "vendored-openssl", feature = "openssl-on-win32"))]
    pub fn userauth_pubkey_memory(
        &self,
        username: &str,
        pubkeydata: Option<&str>,
        privatekeydata: &str,
        passphrase: Option<&str>,
    ) -> Result<(), Error> {
        let username = CString::new(username)?;
        let username = username.as_bytes();
        let (pubkeydata, pubkeydata_len) = match pubkeydata {
            Some(s) => (Some(CString::new(s)?), s.len()),
            None => (None, 0),
        };
        let privatekeydata_len = privatekeydata.len();
        let privatekeydata = CString::new(privatekeydata)?;
        let passphrase = match passphrase {
            Some(s) => Some(CString::new(s)?),
            None => None,
        };
        let inner = self.inner();
        inner.rc(unsafe {
            raw::libssh2_userauth_publickey_frommemory(
                inner.raw,
                username.as_ptr() as *const _,
                username.len() as size_t,
                pubkeydata
                    .as_ref()
                    .map(|s| s.as_ptr())
                    .unwrap_or(null()),
                pubkeydata_len as size_t,
                privatekeydata.as_ptr(),
                privatekeydata_len as size_t,
                passphrase
                    .as_ref()
                    .map(|s| s.as_ptr())
                    .unwrap_or(null()),
            )
        })
    }

    // Umm... I wish this were documented in libssh2?
    #[allow(missing_docs)]
    pub fn userauth_hostbased_file(
        &self,
        username: &str,
        publickey: &Path,
        privatekey: &Path,
        passphrase: Option<&str>,
        hostname: &str,
        local_username: Option<&str>,
    ) -> Result<(), Error> {
        let publickey = CString::new(util::path2bytes(publickey)?)?;
        let privatekey = CString::new(util::path2bytes(privatekey)?)?;
        let passphrase = match passphrase {
            Some(s) => Some(CString::new(s)?),
            None => None,
        };
        let local_username = match local_username {
            Some(local) => local,
            None => username,
        };
        let username = CString::new(username)?;
        let username = username.as_bytes();
        let local_username = CString::new(local_username)?;
        let local_username = local_username.as_bytes();
        let inner = self.inner();
        inner.rc(unsafe {
            raw::libssh2_userauth_hostbased_fromfile_ex(
                inner.raw,
                username.as_ptr() as *const _,
                username.len() as c_uint,
                publickey.as_ptr(),
                privatekey.as_ptr(),
                passphrase
                    .as_ref()
                    .map(|s| s.as_ptr())
                    .unwrap_or(null()),
                hostname.as_ptr() as *const _,
                hostname.len() as c_uint,
                local_username.as_ptr() as *const _,
                local_username.len() as c_uint,
            )
        })
    }

    /// Indicates whether or not the named session has been successfully
    /// authenticated.
    pub fn authenticated(&self) -> bool {
        let inner = self.inner();
        unsafe { raw::libssh2_userauth_authenticated(inner.raw) != 0 }
    }

    /// Send a SSH_USERAUTH_NONE request to the remote host.
    ///
    /// Unless the remote host is configured to accept none as a viable
    /// authentication scheme (unlikely), it will return SSH_USERAUTH_FAILURE
    /// along with a listing of what authentication schemes it does support. In
    /// the unlikely event that none authentication succeeds, this method with
    /// return an error. This case may be distinguished from a failing case by
    /// examining the return value of the `authenticated` method.
    ///
    /// The return value is a comma-separated string of supported auth schemes,
    /// and may be an empty string.
    pub fn auth_methods(&self, username: &str) -> Result<&str, Error> {
        let len = username.len();
        let username = CString::new(username)?;
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_userauth_list(inner.raw, username.as_ptr(), len as c_uint);
            if ret.is_null() {
                match inner.last_error() {
                    Some(err) => Err(err),
                    None => Ok(""),
                }
            } else {
                Ok(str::from_utf8(::opt_bytes(self, ret).unwrap()).unwrap())
            }
        }
    }

    /// Retrieve banner message from server, if available.
    ///
    /// When no such message is sent by server or if no authentication attempt has
    /// been made, this function returns LIBSSH2_ERROR_MISSING_AUTH_BANNER.
    ///
    /// The return value is the userauth banner or None or an Error
    pub fn userauth_banner(&self) -> Result<Option<&str>, Error> {
        let mut userauth_banner = null_mut();
        let inner = self.inner();
        match unsafe { raw::libssh2_userauth_banner(inner.raw, &mut userauth_banner)} {
            0 => {
                unsafe {
                    Ok(::opt_bytes(self, userauth_banner).and_then(|s| str::from_utf8(s).ok()))
                }
            },
            rc => {
                Err(Error::from_errno(ErrorCode::Session(rc)))
            }
        }
    }

    /// Set preferred key exchange method
    ///
    /// The preferences provided are a comma delimited list of preferred methods
    /// to use with the most preferred listed first and the least preferred
    /// listed last. If a method is listed which is not supported by libssh2 it
    /// will be ignored and not sent to the remote host during protocol
    /// negotiation.
    pub fn method_pref(&self, method_type: MethodType, prefs: &str) -> Result<(), Error> {
        let prefs = CString::new(prefs)?;
        let inner = self.inner();
        unsafe {
            inner.rc(raw::libssh2_session_method_pref(
                inner.raw,
                method_type as c_int,
                prefs.as_ptr(),
            ))
        }
    }

    /// Return the currently active algorithms.
    ///
    /// Returns the actual method negotiated for a particular transport
    /// parameter. May return `None` if the session has not yet been started.
    pub fn methods(&self, method_type: MethodType) -> Option<&str> {
        let inner = self.inner();
        unsafe {
            let ptr = raw::libssh2_session_methods(inner.raw, method_type as c_int);
            ::opt_bytes(self, ptr).and_then(|s| str::from_utf8(s).ok())
        }
    }

    /// Get list of supported algorithms.
    pub fn supported_algs(&self, method_type: MethodType) -> Result<Vec<&'static str>, Error> {
        static STATIC: () = ();
        let method_type = method_type as c_int;
        let mut ret = Vec::new();
        let inner = self.inner();
        unsafe {
            let mut ptr = null_mut();
            let rc = raw::libssh2_session_supported_algs(inner.raw, method_type, &mut ptr);
            if rc <= 0 {
                inner.rc(rc)?;
            }
            for i in 0..(rc as isize) {
                let s = ::opt_bytes(&STATIC, *ptr.offset(i)).unwrap();
                let s = str::from_utf8(s).unwrap();
                ret.push(s);
            }
            raw::libssh2_free(inner.raw, ptr as *mut c_void);
        }
        Ok(ret)
    }

    /// Init an ssh-agent handle.
    ///
    /// The returned agent will still need to be connected manually before use.
    pub fn agent(&self) -> Result<Agent, Error> {
        let inner = self.inner();
        unsafe {
            let agent = raw::libssh2_agent_init(inner.raw);
            let err = inner.last_error();
            Agent::from_raw_opt(agent, err, &self.inner)
        }
    }

    /// Init a collection of known hosts for this session.
    ///
    /// Returns the handle to an internal representation of a known host
    /// collection.
    pub fn known_hosts(&self) -> Result<KnownHosts, Error> {
        let inner = self.inner();
        unsafe {
            let ptr = raw::libssh2_knownhost_init(inner.raw);
            let err = inner.last_error();
            KnownHosts::from_raw_opt(ptr, err, &self.inner)
        }
    }

    /// Establish a new session-based channel.
    ///
    /// This method is commonly used to create a channel to execute commands
    /// over or create a new login shell.
    pub fn channel_session(&self) -> Result<Channel, Error> {
        self.channel_open(
            "session",
            raw::LIBSSH2_CHANNEL_WINDOW_DEFAULT as u32,
            raw::LIBSSH2_CHANNEL_PACKET_DEFAULT as u32,
            None,
        )
    }

    /// Tunnel a TCP connection through an SSH session.
    ///
    /// Tunnel a TCP/IP connection through the SSH transport via the remote host
    /// to a third party. Communication from the client to the SSH server
    /// remains encrypted, communication from the server to the 3rd party host
    /// travels in cleartext.
    ///
    /// The optional `src` argument is the host/port to tell the SSH server
    /// where the connection originated from.
    ///
    /// The `Channel` returned represents a connection between this host and the
    /// specified remote host.
    pub fn channel_direct_tcpip(
        &self,
        host: &str,
        port: u16,
        src: Option<(&str, u16)>,
    ) -> Result<Channel, Error> {
        let (shost, sport) = src.unwrap_or(("127.0.0.1", 22));
        let host = CString::new(host)?;
        let shost = CString::new(shost)?;
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_channel_direct_tcpip_ex(
                inner.raw,
                host.as_ptr(),
                port as c_int,
                shost.as_ptr(),
                sport as c_int,
            );
            let err = inner.last_error();
            Channel::from_raw_opt(ret, err, &self.inner)
        }
    }

    /// Tunnel a Unix domain socket connection through an SSH session.
    ///
    /// Tunnel a UNIX socket connection through the SSH transport via the remote
    /// host to a third party. Communication from the client to the SSH server
    /// remains encrypted, communication from the server to the 3rd party host
    /// travels in cleartext.
    ///
    /// The optional `src` argument is the host/port to tell the SSH server
    /// where the connection originated from.
    ///
    /// The `Channel` returned represents a connection between this host and the
    /// specified remote host.
    pub fn channel_direct_streamlocal(
        &self,
        socket_path: &str,
        src: Option<(&str, u16)>,
    ) -> Result<Channel, Error> {
        let (shost, sport) = src.unwrap_or(("127.0.0.1", 22));
        let path = CString::new(socket_path)?;
        let shost = CString::new(shost)?;
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_channel_direct_streamlocal_ex(
                inner.raw,
                path.as_ptr(),
                shost.as_ptr(),
                sport as c_int,
            );
            let err = inner.last_error();
            Channel::from_raw_opt(ret, err, &self.inner)
        }
    }

    /// Instruct the remote SSH server to begin listening for inbound TCP/IP
    /// connections.
    ///
    /// New connections will be queued by the library until accepted by the
    /// `accept` method on the returned `Listener`.
    pub fn channel_forward_listen(
        &self,
        remote_port: u16,
        host: Option<&str>,
        queue_maxsize: Option<u32>,
    ) -> Result<(Listener, u16), Error> {
        let mut bound_port = 0;
        let host = host.map(|s| CString::new(s)).transpose()?;
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_channel_forward_listen_ex(
                inner.raw,
                host
                    .as_ref()
                    .map(|s| s.as_ptr())
                    .unwrap_or(null()),
                remote_port as c_int,
                &mut bound_port,
                queue_maxsize.unwrap_or(0) as c_int,
            );
            let err = inner.last_error();
            Listener::from_raw_opt(ret, err, &self.inner).map(|l| (l, bound_port as u16))
        }
    }

    /// Request a file from the remote host via SCP.
    ///
    /// The path specified is a path on the remote host which will attempt to be
    /// sent over the returned channel. Some stat information is also returned
    /// about the remote file to prepare for receiving the file.
    pub fn scp_recv(&self, path: &Path) -> Result<(Channel, ScpFileStat), Error> {
        let path = CString::new(util::path2bytes(path)?)?;
        let inner = self.inner();
        unsafe {
            let mut sb: raw::libssh2_struct_stat = mem::zeroed();
            let ret = raw::libssh2_scp_recv2(inner.raw, path.as_ptr(), &mut sb);
            let err = inner.last_error();
            let mut c = Channel::from_raw_opt(ret, err, &self.inner)?;

            // Hm, apparently when we scp_recv() a file the actual channel
            // itself does not respond well to read_to_end(), and it also sends
            // an extra 0 byte (or so it seems). To work around this we
            // artificially limit the channel to a certain amount of bytes that
            // can be read.
            c.limit_read(sb.st_size as u64);
            Ok((c, ScpFileStat { stat: *sb }))
        }
    }

    /// Send a file to the remote host via SCP.
    ///
    /// The `remote_path` provided will be the remote file name. The `times`
    /// argument is a tuple of (mtime, atime), and will default to the remote
    /// host's current time if not specified.
    ///
    /// The size of the file, `size`, must be known ahead of time before
    /// transmission.
    pub fn scp_send(
        &self,
        remote_path: &Path,
        mode: i32,
        size: u64,
        times: Option<(u64, u64)>,
    ) -> Result<Channel, Error> {
        let path = CString::new(util::path2bytes(remote_path)?)?;
        let (mtime, atime) = times.unwrap_or((0, 0));
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_scp_send64(
                inner.raw,
                path.as_ptr(),
                mode as c_int,
                size as i64,
                mtime as libc::time_t,
                atime as libc::time_t,
            );
            let err = inner.last_error();
            Channel::from_raw_opt(ret, err, &self.inner)
        }
    }

    /// Open a channel and initialize the SFTP subsystem.
    ///
    /// Although the SFTP subsystem operates over the same type of channel as
    /// those exported by the Channel API, the protocol itself implements its
    /// own unique binary packet protocol which must be managed with the
    /// methods on `Sftp`.
    pub fn sftp(&self) -> Result<Sftp, Error> {
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_sftp_init(inner.raw);
            let err = inner.last_error();
            Sftp::from_raw_opt(ret, err, &self.inner)
        }
    }

    /// Allocate a new channel for exchanging data with the server.
    ///
    /// This is typically not called directly but rather through
    /// `channel_session`, `channel_direct_tcpip`, or `channel_forward_listen`.
    pub fn channel_open(
        &self,
        channel_type: &str,
        window_size: u32,
        packet_size: u32,
        message: Option<&str>,
    ) -> Result<Channel, Error> {
        let channel_type = CString::new(channel_type)?;
        let channel_type = channel_type.as_bytes();
        let message = message.map(|s| CString::new(s)).transpose()?;
        let (message, message_len) = message
            .as_ref()
            .map(|s| (s.as_ptr(), s.as_bytes().len()))
            .unwrap_or((null(), 0));
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_channel_open_ex(
                inner.raw,
                channel_type.as_ptr() as *const _,
                channel_type.len() as c_uint,
                window_size as c_uint,
                packet_size as c_uint,
                message,
                message_len as c_uint,
            );
            let err = inner.last_error();
            Channel::from_raw_opt(ret, err, &self.inner)
        }
    }

    /// Get the remote banner
    ///
    /// Once the session has been setup and handshake() has completed
    /// successfully, this function can be used to get the server id from the
    /// banner each server presents.
    ///
    /// May return `None` on invalid utf-8 or if an error has occurred.
    pub fn banner(&self) -> Option<&str> {
        self.banner_bytes().and_then(|s| str::from_utf8(s).ok())
    }

    /// See `banner`.
    ///
    /// Will only return `None` if an error has occurred.
    pub fn banner_bytes(&self) -> Option<&[u8]> {
        let inner = self.inner();
        unsafe { ::opt_bytes(self, raw::libssh2_session_banner_get(inner.raw)) }
    }

    /// Get the remote key.
    ///
    /// Returns `None` if something went wrong.
    pub fn host_key(&self) -> Option<(&[u8], HostKeyType)> {
        let mut len = 0;
        let mut kind = 0;
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_session_hostkey(inner.raw, &mut len, &mut kind);
            if ret.is_null() {
                return None;
            }
            let data = slice::from_raw_parts(ret as *const u8, len as usize);
            let kind = match kind {
                raw::LIBSSH2_HOSTKEY_TYPE_RSA => HostKeyType::Rsa,
                raw::LIBSSH2_HOSTKEY_TYPE_DSS => HostKeyType::Dss,
                raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_256 => HostKeyType::Ecdsa256,
                raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_384 => HostKeyType::Ecdsa384,
                raw::LIBSSH2_HOSTKEY_TYPE_ECDSA_521 => HostKeyType::Ecdsa521,
                raw::LIBSSH2_HOSTKEY_TYPE_ED25519 => HostKeyType::Ed25519,
                raw::LIBSSH2_HOSTKEY_TYPE_UNKNOWN => HostKeyType::Unknown,
                _ => HostKeyType::Unknown,
            };
            Some((data, kind))
        }
    }

    /// Returns the computed digest of the remote system's hostkey.
    ///
    /// The bytes returned are the raw hash, and are not printable. If the hash
    /// is not yet available `None` is returned.
    pub fn host_key_hash(&self, hash: HashType) -> Option<&[u8]> {
        let len = match hash {
            HashType::Md5 => 16,
            HashType::Sha1 => 20,
            HashType::Sha256 => 32,
        };
        let inner = self.inner();
        unsafe {
            let ret = raw::libssh2_hostkey_hash(inner.raw, hash as c_int);
            if ret.is_null() {
                None
            } else {
                let ret = ret as *const u8;
                Some(slice::from_raw_parts(ret, len))
            }
        }
    }

    /// Set how often keepalive messages should be sent.
    ///
    /// The want_reply argument indicates whether the keepalive messages should
    /// request a response from the server.
    ///
    /// The interval argument is number of seconds that can pass without any
    /// I/O, use 0 (the default) to disable keepalives. To avoid some busy-loop
    /// corner-cases, if you specify an interval of 1 it will be treated as 2.
    pub fn set_keepalive(&self, want_reply: bool, interval: u32) {
        let inner = self.inner();
        unsafe { raw::libssh2_keepalive_config(inner.raw, want_reply as c_int, interval as c_uint) }
    }

    /// Send a keepalive message if needed.
    ///
    /// Returns how many seconds you can sleep after this call before you need
    /// to call it again.
    pub fn keepalive_send(&self) -> Result<u32, Error> {
        let mut ret = 0;
        let inner = self.inner();
        let rc = unsafe { raw::libssh2_keepalive_send(inner.raw, &mut ret) };
        inner.rc(rc)?;
        Ok(ret as u32)
    }

    /// Terminate the transport layer.
    ///
    /// Send a disconnect message to the remote host associated with session,
    /// along with a reason symbol and a verbose description.
    ///
    /// Note that this does *not* close the underlying socket.
    pub fn disconnect(
        &self,
        reason: Option<DisconnectCode>,
        description: &str,
        lang: Option<&str>,
    ) -> Result<(), Error> {
        let reason = reason.unwrap_or(ByApplication) as c_int;
        let description = CString::new(description)?;
        let lang = CString::new(lang.unwrap_or(""))?;
        let inner = self.inner();
        unsafe {
            inner.rc(raw::libssh2_session_disconnect_ex(
                inner.raw,
                reason,
                description.as_ptr(),
                lang.as_ptr(),
            ))
        }
    }

    /// Returns the blocked io directions that the application needs to wait for.
    ///
    /// This function should be used after an error of type `WouldBlock` is returned to
    /// find out the socket events the application has to wait for.
    pub fn block_directions(&self) -> BlockDirections {
        let inner = self.inner();
        let dir = unsafe { raw::libssh2_session_block_directions(inner.raw) };
        match dir {
            raw::LIBSSH2_SESSION_BLOCK_INBOUND => BlockDirections::Inbound,
            raw::LIBSSH2_SESSION_BLOCK_OUTBOUND => BlockDirections::Outbound,
            x if x == raw::LIBSSH2_SESSION_BLOCK_INBOUND | raw::LIBSSH2_SESSION_BLOCK_OUTBOUND => {
                BlockDirections::Both
            }
            _ => BlockDirections::None,
        }
    }

    fn inner(&self) -> MutexGuard<'_, SessionInner> {
        self.inner.lock()
    }

    /// Sets the trace level for the session.
    ///
    pub fn trace(&self, bitmask: TraceFlags) {
        let inner = self.inner();
        unsafe { let _ = raw::libssh2_trace(inner.raw, bitmask.bits() as c_int); }
    }
}

#[cfg(unix)]
impl AsRawFd for Session {
    fn as_raw_fd(&self) -> RawFd {
        let inner = self.inner();
        match inner.tcp.as_ref() {
            Some(tcp) => tcp.as_raw_fd(),
            None => panic!("tried to obtain raw fd without tcp stream set"),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Session {
    fn as_raw_socket(&self) -> RawSocket {
        let inner = self.inner();
        match inner.tcp.as_ref() {
            Some(tcp) => tcp.as_raw_socket(),
            None => panic!("tried to obtain raw socket without tcp stream set"),
        }
    }
}

impl SessionInner {
    /// Translate a return code into a Rust-`Result`.
    pub fn rc(&self, rc: c_int) -> Result<(), Error> {
        if rc >= 0 {
            Ok(())
        } else {
            Err(Error::from_session_error_raw(self.raw, rc))
        }
    }

    pub fn last_error(&self) -> Option<Error> {
        Error::last_session_error_raw(self.raw)
    }

    /// Set or clear blocking mode on session
    pub fn set_blocking(&self, blocking: bool) {
        unsafe { raw::libssh2_session_set_blocking(self.raw, blocking as c_int) }
    }

    /// Returns whether the session was previously set to nonblocking.
    pub fn is_blocking(&self) -> bool {
        unsafe { raw::libssh2_session_get_blocking(self.raw) != 0 }
    }
}

impl Drop for SessionInner {
    fn drop(&mut self) {
        unsafe {
            let _rc = raw::libssh2_session_free(self.raw);
        }
    }
}

impl ScpFileStat {
    /// Returns the size of the remote file.
    pub fn size(&self) -> u64 {
        self.stat.st_size as u64
    }
    /// Returns the listed mode of the remote file.
    pub fn mode(&self) -> i32 {
        self.stat.st_mode as i32
    }
    /// Returns whether the remote file is a directory.
    pub fn is_dir(&self) -> bool {
        self.mode() & (libc::S_IFMT as i32) == (libc::S_IFDIR as i32)
    }
    /// Returns whether the remote file is a regular file.
    pub fn is_file(&self) -> bool {
        self.mode() & (libc::S_IFMT as i32) == (libc::S_IFREG as i32)
    }
}


================================================
FILE: src/sftp.rs
================================================
use libc::{c_int, c_long, c_uint, c_ulong, size_t};
use parking_lot::{Mutex, MutexGuard};
use std::convert::TryFrom;
use std::ffi::CString;
use std::io::prelude::*;
use std::io::{self, ErrorKind, SeekFrom};
use std::mem;
use std::path::{Path, PathBuf};
use std::ptr::null_mut;
use std::sync::Arc;

use util;
use {raw, Error, ErrorCode, SessionInner};

/// A handle to a remote filesystem over SFTP.
///
/// Instances are created through the `sftp` method on a `Session`.
pub struct Sftp {
    inner: Option<Arc<SftpInnerDropWrapper>>,
}
/// This contains an Option so that we're able to disable the Drop hook when dropping manually,
/// while still dropping all the fields of SftpInner (which we couldn't do with `mem::forget`)
struct SftpInnerDropWrapper(Option<SftpInner>);
struct SftpInner {
    raw: *mut raw::LIBSSH2_SFTP,
    sess: Arc<Mutex<SessionInner>>,
}

// Sftp is both Send and Sync; the compiler can't see it because it
// is pessimistic about the raw pointer.  We use Arc/Mutex to guard accessing
// the raw pointer so we are safe for both.
unsafe impl Send for Sftp {}
unsafe impl Sync for Sftp {}

struct LockedSftp<'sftp> {
    raw: *mut raw::LIBSSH2_SFTP,
    sess: MutexGuard<'sftp, SessionInner>,
}

/// A file handle to an SFTP connection.
///
/// Files behave similarly to `std::old_io::File` in that they are readable and
/// writable and support operations like stat and seek.
///
/// Files are created through `open`, `create`, and `open_mode` on an instance
/// of `Sftp`.
pub struct File {
    inner: Option<FileInner>,
}
struct FileInner {
    raw: *mut raw::LIBSSH2_SFTP_HANDLE,
    sftp: Arc<SftpInnerDropWrapper>,
}

// File is both Send and Sync; the compiler can't see it because it
// is pessimistic about the raw pointer.  We use Arc/Mutex to guard accessing
// the raw pointer so we are safe for both.
unsafe impl Send for File {}
unsafe impl Sync for File {}

struct LockedFile<'file> {
    raw: *mut raw::LIBSSH2_SFTP_HANDLE,
    sess: MutexGuard<'file, SessionInner>,
}

/// Metadata information about a remote file.
///
/// Fields are not necessarily all provided
#[derive(Debug, Clone, Eq, PartialEq)]
#[allow(missing_copy_implementations)]
pub struct FileStat {
    /// File size, in bytes of the file.
    pub size: Option<u64>,
    /// Owner ID of the file
    pub uid: Option<u32>,
    /// Owning group of the file
    pub gid: Option<u32>,
    /// Permissions (mode) of the file
    pub perm: Option<u32>,
    /// Last access time of the file
    pub atime: Option<u64>,
    /// Last modification time of the file
    pub mtime: Option<u64>,
}

/// An enum representing a type of file.
#[derive(PartialEq)]
pub enum FileType {
    /// Named pipe (S_IFIFO)
    NamedPipe,
    /// Character device (S_IFCHR)
    CharDevice,
    /// Block device (S_IFBLK)
    BlockDevice,
    /// Directory (S_IFDIR)
    Directory,
    /// Regular file (S_IFREG)
    RegularFile,
    /// Symbolic link (S_IFLNK)
    Symlink,
    /// Unix domain socket (S_IFSOCK)
    Socket,
    /// Other filetype (does not correspond to any of the other ones)
    Other(c_ulong),
}

bitflags! {
    /// Options that can be used to configure how a file is opened
    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
    pub struct OpenFlags: c_ulong {
        /// Open the file for reading.
        const READ = raw::LIBSSH2_FXF_READ;
        /// Open the file for writing. If both this and `Read` are specified,
        /// the file is opened for both reading and writing.
        const WRITE = raw::LIBSSH2_FXF_WRITE;
        /// Force all writes to append data at the end of the file.
        const APPEND = raw::LIBSSH2_FXF_APPEND;
        /// If this flag is specified, then a new file will be created if one
        /// does not already exist (if `Truncate` is specified, the new file
        /// will be truncated to zero length if it previously exists).
        const CREATE = raw::LIBSSH2_FXF_CREAT;
        /// Forces an existing file with the same name to be truncated to zero
        /// length when creating a file by specifying `Create`. Using this flag
        /// implies the `Create` flag.
        const TRUNCATE = raw::LIBSSH2_FXF_TRUNC | Self::CREATE.bits();
        /// Causes the request to fail if the named file already exists. Using
        /// this flag implies the `Create` flag.
        const EXCLUSIVE = raw::LIBSSH2_FXF_EXCL | Self::CREATE.bits();
    }
}

bitflags! {
    /// Options to `Sftp::rename`.
    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
    pub struct RenameFlags: c_long {
        /// In a rename operation, overwrite the destination if it already
        /// exists. If this flag is not present then it is an error if the
        /// destination already exists.
        const OVERWRITE = raw::LIBSSH2_SFTP_RENAME_OVERWRITE;
        /// Inform the remote that an atomic rename operation is desired if
        /// available.
        const ATOMIC = raw::LIBSSH2_SFTP_RENAME_ATOMIC;
        /// Inform the remote end that the native system calls for renaming
        /// should be used.
        const NATIVE = raw::LIBSSH2_SFTP_RENAME_NATIVE;
    }
}

/// How to open a file handle with libssh2.
#[derive(Copy, Clone)]
pub enum OpenType {
    /// Specify that a file shoud be opened.
    File = raw::LIBSSH2_SFTP_OPENFILE as isize,
    /// Specify that a directory should be opened.
    Dir = raw::LIBSSH2_SFTP_OPENDIR as isize,
}

impl Sftp {
    pub(crate) fn from_raw_opt(
        raw: *mut raw::LIBSSH2_SFTP,
        err: Option<Error>,
        sess: &Arc<Mutex<SessionInner>>,
    ) -> Result<Self, Error> {
        if raw.is_null() {
            Err(err.unwrap_or_else(Error::unknown))
        } else {
            Ok(Self {
                inner: Some(Arc::new(SftpInnerDropWrapper(Some(SftpInner {
                    raw,
                    sess: Arc::clone(sess),
                })))),
            })
        }
    }

    /// Open a handle to a file.
    ///
    /// The mode will represent the permissions for the file ([Wikipedia](<https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation>)).
    pub fn open_mode<T: AsRef<Path>>(
        &self,
        filename: T,
        flags: OpenFlags,
        mode: i32,
        open_type: OpenType,
    ) -> Result<File, Error> {
        let filename = CString::new(util::path2bytes(filename.as_ref())?)?;

        let locked = self.lock()?;
        unsafe {
            let ret = raw::libssh2_sftp_open_ex(
                locked.raw,
                filename.as_ptr() as *const _,
                filename.as_bytes().len() as c_uint,
                flags.bits() as c_ulong,
                mode as c_long,
                open_type as c_int,
            );
            if ret.is_null() {
                let rc = raw::libssh2_session_last_errno(locked.sess.raw);
                Err(Self::error_code_into_error(locked.sess.raw, locked.raw, rc))
            } else {
                Ok(File::from_raw(self, ret))
            }
        }
    }

    /// Helper to open a file in the `Read` mode.
    pub fn open<T: AsRef<Path>>(&self, filename: T) -> Result<File, Error> {
        self.open_mode(filename, OpenFlags::READ, 0o644, OpenType::File)
    }

    /// Helper to create a file in write-only mode with truncation.
    pub fn create(&self, filename: &Path) -> Result<File, Error> {
        self.open_mode(
            filename,
            OpenFlags::WRITE | OpenFlags::TRUNCATE,
            0o644,
            OpenType::File,
        )
    }

    /// Helper to open a directory for reading its contents.
    pub fn opendir<T: AsRef<Path>>(&self, dirname: T) -> Result<File, Error> {
        self.open_mode(dirname, OpenFlags::READ, 0, OpenType::Dir)
    }

    /// Convenience function to read the files in a directory.
    ///
    /// The returned paths are all joined with `dirname` when returned, and the
    /// paths `.` and `..` are filtered out of the returned list.
    pub fn readdir<T: AsRef<Path>>(&self, dirname: T) -> Result<Vec<(PathBuf, FileStat)>, Error> {
        let mut dir = self.opendir(dirname.as_ref())?;
        let mut ret = Vec::new();
        loop {
            match dir.readdir() {
                Ok((filename, stat)) => {
                    if &*filename == Path::new(".") || &*filename == Path::new("..") {
                        continue;
                    }

                    ret.push((dirname.as_ref().join(&filename), stat))
                }
                Err(ref e) if e.code() == ErrorCode::Session(raw::LIBSSH2_ERROR_FILE) => break,
                Err(e) => {
                    if e.code() != ErrorCode::Session(raw::LIBSSH2_ERROR_EAGAIN) {
                        return Err(e);
                    }
                }
            }
        }
        Ok(ret)
    }

    /// Create a directory on the remote file system.
    ///
    /// The mode will set the permissions of the new directory ([Wikipedia](<https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation>)).
    pub fn mkdir(&self, filename: &Path, mode: i32) -> Result<(), Error> {
        let filename = CString::new(util::path2bytes(filename)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            raw::libssh2_sftp_mkdir_ex(
                locked.raw,
                filename.as_ptr() as *const _,
                filename.as_bytes().len() as c_uint,
                mode as c_long,
            )
        })
    }

    /// Remove a directory from the remote file system.
    pub fn rmdir(&self, filename: &Path) -> Result<(), Error> {
        let filename = CString::new(util::path2bytes(filename)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            raw::libssh2_sftp_rmdir_ex(
                locked.raw,
                filename.as_ptr() as *const _,
                filename.as_bytes().len() as c_uint,
            )
        })
    }

    /// Get the metadata for a file, performed by stat(2)
    pub fn stat(&self, filename: &Path) -> Result<FileStat, Error> {
        let filename = CString::new(util::path2bytes(filename)?)?;
        let locked = self.lock()?;
        unsafe {
            let mut ret = mem::zeroed();
            Self::rc(
                &locked,
                raw::libssh2_sftp_stat_ex(
                    locked.raw,
                    filename.as_ptr() as *const _,
                    filename.as_bytes().len() as c_uint,
                    raw::LIBSSH2_SFTP_STAT,
                    &mut ret,
                ),
            )
            .map(|_| FileStat::from_raw(&ret))
        }
    }

    /// Get the metadata for a file, performed by lstat(2)
    pub fn lstat(&self, filename: &Path) -> Result<FileStat, Error> {
        let filename = CString::new(util::path2bytes(filename)?)?;
        let locked = self.lock()?;
        unsafe {
            let mut ret = mem::zeroed();
            Self::rc(
                &locked,
                raw::libssh2_sftp_stat_ex(
                    locked.raw,
                    filename.as_ptr() as *const _,
                    filename.as_bytes().len() as c_uint,
                    raw::LIBSSH2_SFTP_LSTAT,
                    &mut ret,
                ),
            )
            .map(|_| FileStat::from_raw(&ret))
        }
    }

    /// Set the metadata for a file.
    pub fn setstat(&self, filename: &Path, stat: FileStat) -> Result<(), Error> {
        let filename = CString::new(util::path2bytes(filename)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            let mut raw = stat.raw();
            raw::libssh2_sftp_stat_ex(
                locked.raw,
                filename.as_ptr() as *const _,
                filename.as_bytes().len() as c_uint,
                raw::LIBSSH2_SFTP_SETSTAT,
                &mut raw,
            )
        })
    }

    /// Create a symlink at `target` pointing at `path`.
    pub fn symlink(&self, path: &Path, target: &Path) -> Result<(), Error> {
        let path = CString::new(util::path2bytes(path)?)?;
        let target = CString::new(util::path2bytes(target)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            raw::libssh2_sftp_symlink_ex(
                locked.raw,
                path.as_ptr() as *const _,
                path.as_bytes().len() as c_uint,
                target.as_ptr() as *mut _,
                target.as_bytes().len() as c_uint,
                raw::LIBSSH2_SFTP_SYMLINK,
            )
        })
    }

    /// Read a symlink at `path`.
    pub fn readlink(&self, path: &Path) -> Result<PathBuf, Error> {
        self.readlink_op(path, raw::LIBSSH2_SFTP_READLINK)
    }

    /// Resolve the real path for `path`.
    pub fn realpath(&self, path: &Path) -> Result<PathBuf, Error> {
        self.readlink_op(path, raw::LIBSSH2_SFTP_REALPATH)
    }

    fn readlink_op(&self, path: &Path, op: c_int) -> Result<PathBuf, Error> {
        let path = CString::new(util::path2bytes(path)?)?;
        let mut ret = Vec::<u8>::with_capacity(128);
        let mut rc;
        let locked = self.lock()?;
        loop {
            rc = unsafe {
                raw::libssh2_sftp_symlink_ex(
                    locked.raw,
                    path.as_ptr() as *const _,
                    path.as_bytes().len() as c_uint,
                    ret.as_ptr() as *mut _,
                    ret.capacity() as c_uint,
                    op,
                )
            };
            if rc == raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL {
                let cap = ret.capacity();
                ret.reserve(cap * 2);
            } else {
                break;
            }
        }
        Self::rc(&locked, rc).map(move |_| {
            unsafe { ret.set_len(rc as usize) }
            mkpath(ret)
        })
    }

    /// Rename a filesystem object on the remote filesystem.
    ///
    /// The semantics of this command typically include the ability to move a
    /// filesystem object between folders and/or filesystem mounts. If the
    /// `Overwrite` flag is not set and the destfile entry already exists, the
    /// operation will fail.
    ///
    /// Use of the other flags (Native or Atomic) indicate a preference (but
    /// not a requirement) for the remote end to perform an atomic rename
    /// operation and/or using native system calls when possible.
    ///
    /// If no flags are specified then all flags are used.
    pub fn rename(&self, src: &Path, dst: &Path, flags: Option<RenameFlags>) -> Result<(), Error> {
        let flags =
            flags.unwrap_or(RenameFlags::ATOMIC | RenameFlags::OVERWRITE | RenameFlags::NATIVE);
        let src = CString::new(util::path2bytes(src)?)?;
        let dst = CString::new(util::path2bytes(dst)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            raw::libssh2_sftp_rename_ex(
                locked.raw,
                src.as_ptr() as *const _,
                src.as_bytes().len() as c_uint,
                dst.as_ptr() as *const _,
                dst.as_bytes().len() as c_uint,
                flags.bits(),
            )
        })
    }

    /// Remove a file on the remote filesystem
    pub fn unlink(&self, file: &Path) -> Result<(), Error> {
        let file = CString::new(util::path2bytes(file)?)?;
        let locked = self.lock()?;
        Self::rc(&locked, unsafe {
            raw::libssh2_sftp_unlink_ex(
                locked.raw,
                file.as_ptr() as *const _,
                file.as_bytes().len() as c_uint,
            )
        })
    }

    fn lock(&self) -> Result<LockedSftp<'_>, Error> {
        match self.inner.as_ref() {
            Some(sftp_inner_drop_wrapper) => {
                let sftp_inner = sftp_inner_drop_wrapper
                    .0
                    .as_ref()
                    .expect("Never unset until shutdown, in which case inner is also unset");
                let sess = sftp_inner.sess.lock();
                Ok(LockedSftp {
                    sess,
                    raw: sftp_inner.raw,
                })
            }
            None => Err(Error::from_errno(ErrorCode::Session(
                raw::LIBSSH2_ERROR_BAD_USE,
            ))),
        }
    }

    // This method is used by
Download .txt
gitextract_dmgnez8a/

├── .github/
│   └── workflows/
│       ├── linux.yml
│       ├── macos.yml
│       └── windows.yml
├── .gitignore
├── .gitmodules
├── .mailmap
├── .travis.yml
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── libssh2-sys/
│   ├── .gitattributes
│   ├── Cargo.toml
│   ├── LICENSE-APACHE
│   ├── LICENSE-MIT
│   ├── build.rs
│   └── lib.rs
├── src/
│   ├── agent.rs
│   ├── channel.rs
│   ├── error.rs
│   ├── knownhosts.rs
│   ├── lib.rs
│   ├── listener.rs
│   ├── session.rs
│   ├── sftp.rs
│   └── util.rs
├── systest/
│   ├── Cargo.toml
│   ├── build.rs
│   └── src/
│       └── main.rs
└── tests/
    ├── all/
    │   ├── agent.rs
    │   ├── channel.rs
    │   ├── knownhosts.rs
    │   ├── main.rs
    │   ├── session.rs
    │   └── sftp.rs
    └── run_integration_tests.sh
Download .txt
SYMBOL INDEX (584 symbols across 18 files)

FILE: libssh2-sys/build.rs
  function main (line 12) | fn main() {
  function try_vcpkg (line 205) | fn try_vcpkg() -> bool {
  function try_vcpkg (line 210) | fn try_vcpkg() -> bool {

FILE: libssh2-sys/lib.rs
  constant SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT (line 14) | pub const SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT: c_int = 1;
  constant SSH_DISCONNECT_PROTOCOL_ERROR (line 15) | pub const SSH_DISCONNECT_PROTOCOL_ERROR: c_int = 2;
  constant SSH_DISCONNECT_KEY_EXCHANGE_FAILED (line 16) | pub const SSH_DISCONNECT_KEY_EXCHANGE_FAILED: c_int = 3;
  constant SSH_DISCONNECT_RESERVED (line 17) | pub const SSH_DISCONNECT_RESERVED: c_int = 4;
  constant SSH_DISCONNECT_MAC_ERROR (line 18) | pub const SSH_DISCONNECT_MAC_ERROR: c_int = 5;
  constant SSH_DISCONNECT_COMPRESSION_ERROR (line 19) | pub const SSH_DISCONNECT_COMPRESSION_ERROR: c_int = 6;
  constant SSH_DISCONNECT_SERVICE_NOT_AVAILABLE (line 20) | pub const SSH_DISCONNECT_SERVICE_NOT_AVAILABLE: c_int = 7;
  constant SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED (line 21) | pub const SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED: c_int = 8;
  constant SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE (line 22) | pub const SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE: c_int = 9;
  constant SSH_DISCONNECT_CONNECTION_LOST (line 23) | pub const SSH_DISCONNECT_CONNECTION_LOST: c_int = 10;
  constant SSH_DISCONNECT_BY_APPLICATION (line 24) | pub const SSH_DISCONNECT_BY_APPLICATION: c_int = 11;
  constant SSH_DISCONNECT_TOO_MANY_CONNECTIONS (line 25) | pub const SSH_DISCONNECT_TOO_MANY_CONNECTIONS: c_int = 12;
  constant SSH_DISCONNECT_AUTH_CANCELLED_BY_USER (line 26) | pub const SSH_DISCONNECT_AUTH_CANCELLED_BY_USER: c_int = 13;
  constant SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE (line 27) | pub const SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE: c_int = 14;
  constant SSH_DISCONNECT_ILLEGAL_USER_NAME (line 28) | pub const SSH_DISCONNECT_ILLEGAL_USER_NAME: c_int = 15;
  constant LIBSSH2_FLAG_SIGPIPE (line 30) | pub const LIBSSH2_FLAG_SIGPIPE: c_int = 1;
  constant LIBSSH2_FLAG_COMPRESS (line 31) | pub const LIBSSH2_FLAG_COMPRESS: c_int = 2;
  constant LIBSSH2_HOSTKEY_TYPE_UNKNOWN (line 33) | pub const LIBSSH2_HOSTKEY_TYPE_UNKNOWN: c_int = 0;
  constant LIBSSH2_HOSTKEY_TYPE_RSA (line 34) | pub const LIBSSH2_HOSTKEY_TYPE_RSA: c_int = 1;
  constant LIBSSH2_HOSTKEY_TYPE_DSS (line 35) | pub const LIBSSH2_HOSTKEY_TYPE_DSS: c_int = 2;
  constant LIBSSH2_HOSTKEY_TYPE_ECDSA_256 (line 36) | pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_256: c_int = 3;
  constant LIBSSH2_HOSTKEY_TYPE_ECDSA_384 (line 37) | pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_384: c_int = 4;
  constant LIBSSH2_HOSTKEY_TYPE_ECDSA_521 (line 38) | pub const LIBSSH2_HOSTKEY_TYPE_ECDSA_521: c_int = 5;
  constant LIBSSH2_HOSTKEY_TYPE_ED25519 (line 39) | pub const LIBSSH2_HOSTKEY_TYPE_ED25519: c_int = 6;
  constant LIBSSH2_METHOD_KEX (line 41) | pub const LIBSSH2_METHOD_KEX: c_int = 0;
  constant LIBSSH2_METHOD_HOSTKEY (line 42) | pub const LIBSSH2_METHOD_HOSTKEY: c_int = 1;
  constant LIBSSH2_METHOD_CRYPT_CS (line 43) | pub const LIBSSH2_METHOD_CRYPT_CS: c_int = 2;
  constant LIBSSH2_METHOD_CRYPT_SC (line 44) | pub const LIBSSH2_METHOD_CRYPT_SC: c_int = 3;
  constant LIBSSH2_METHOD_MAC_CS (line 45) | pub const LIBSSH2_METHOD_MAC_CS: c_int = 4;
  constant LIBSSH2_METHOD_MAC_SC (line 46) | pub const LIBSSH2_METHOD_MAC_SC: c_int = 5;
  constant LIBSSH2_METHOD_COMP_CS (line 47) | pub const LIBSSH2_METHOD_COMP_CS: c_int = 6;
  constant LIBSSH2_METHOD_COMP_SC (line 48) | pub const LIBSSH2_METHOD_COMP_SC: c_int = 7;
  constant LIBSSH2_METHOD_LANG_CS (line 49) | pub const LIBSSH2_METHOD_LANG_CS: c_int = 8;
  constant LIBSSH2_METHOD_LANG_SC (line 50) | pub const LIBSSH2_METHOD_LANG_SC: c_int = 9;
  constant LIBSSH2_METHOD_SIGN_ALGO (line 51) | pub const LIBSSH2_METHOD_SIGN_ALGO: c_int = 10;
  constant LIBSSH2_CHANNEL_PACKET_DEFAULT (line 53) | pub const LIBSSH2_CHANNEL_PACKET_DEFAULT: c_uint = 32768;
  constant LIBSSH2_CHANNEL_WINDOW_DEFAULT (line 54) | pub const LIBSSH2_CHANNEL_WINDOW_DEFAULT: c_uint = 2 * 1024 * 1024;
  constant LIBSSH2_ERROR_BANNER_RECV (line 56) | pub const LIBSSH2_ERROR_BANNER_RECV: c_int = -2;
  constant LIBSSH2_ERROR_BANNER_SEND (line 57) | pub const LIBSSH2_ERROR_BANNER_SEND: c_int = -3;
  constant LIBSSH2_ERROR_INVALID_MAC (line 58) | pub const LIBSSH2_ERROR_INVALID_MAC: c_int = -4;
  constant LIBSSH2_ERROR_KEX_FAILURE (line 59) | pub const LIBSSH2_ERROR_KEX_FAILURE: c_int = -5;
  constant LIBSSH2_ERROR_ALLOC (line 60) | pub const LIBSSH2_ERROR_ALLOC: c_int = -6;
  constant LIBSSH2_ERROR_SOCKET_SEND (line 61) | pub const LIBSSH2_ERROR_SOCKET_SEND: c_int = -7;
  constant LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE (line 62) | pub const LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE: c_int = -8;
  constant LIBSSH2_ERROR_TIMEOUT (line 63) | pub const LIBSSH2_ERROR_TIMEOUT: c_int = -9;
  constant LIBSSH2_ERROR_HOSTKEY_INIT (line 64) | pub const LIBSSH2_ERROR_HOSTKEY_INIT: c_int = -10;
  constant LIBSSH2_ERROR_HOSTKEY_SIGN (line 65) | pub const LIBSSH2_ERROR_HOSTKEY_SIGN: c_int = -11;
  constant LIBSSH2_ERROR_DECRYPT (line 66) | pub const LIBSSH2_ERROR_DECRYPT: c_int = -12;
  constant LIBSSH2_ERROR_SOCKET_DISCONNECT (line 67) | pub const LIBSSH2_ERROR_SOCKET_DISCONNECT: c_int = -13;
  constant LIBSSH2_ERROR_PROTO (line 68) | pub const LIBSSH2_ERROR_PROTO: c_int = -14;
  constant LIBSSH2_ERROR_PASSWORD_EXPIRED (line 69) | pub const LIBSSH2_ERROR_PASSWORD_EXPIRED: c_int = -15;
  constant LIBSSH2_ERROR_FILE (line 70) | pub const LIBSSH2_ERROR_FILE: c_int = -16;
  constant LIBSSH2_ERROR_METHOD_NONE (line 71) | pub const LIBSSH2_ERROR_METHOD_NONE: c_int = -17;
  constant LIBSSH2_ERROR_AUTHENTICATION_FAILED (line 72) | pub const LIBSSH2_ERROR_AUTHENTICATION_FAILED: c_int = -18;
  constant LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED (line 73) | pub const LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: c_int = LIBSSH2_ERROR_AU...
  constant LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED (line 74) | pub const LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: c_int = -19;
  constant LIBSSH2_ERROR_CHANNEL_OUTOFORDER (line 75) | pub const LIBSSH2_ERROR_CHANNEL_OUTOFORDER: c_int = -20;
  constant LIBSSH2_ERROR_CHANNEL_FAILURE (line 76) | pub const LIBSSH2_ERROR_CHANNEL_FAILURE: c_int = -21;
  constant LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED (line 77) | pub const LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED: c_int = -22;
  constant LIBSSH2_ERROR_CHANNEL_UNKNOWN (line 78) | pub const LIBSSH2_ERROR_CHANNEL_UNKNOWN: c_int = -23;
  constant LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED (line 79) | pub const LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED: c_int = -24;
  constant LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED (line 80) | pub const LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED: c_int = -25;
  constant LIBSSH2_ERROR_CHANNEL_CLOSED (line 81) | pub const LIBSSH2_ERROR_CHANNEL_CLOSED: c_int = -26;
  constant LIBSSH2_ERROR_CHANNEL_EOF_SENT (line 82) | pub const LIBSSH2_ERROR_CHANNEL_EOF_SENT: c_int = -27;
  constant LIBSSH2_ERROR_SCP_PROTOCOL (line 83) | pub const LIBSSH2_ERROR_SCP_PROTOCOL: c_int = -28;
  constant LIBSSH2_ERROR_ZLIB (line 84) | pub const LIBSSH2_ERROR_ZLIB: c_int = -29;
  constant LIBSSH2_ERROR_SOCKET_TIMEOUT (line 85) | pub const LIBSSH2_ERROR_SOCKET_TIMEOUT: c_int = -30;
  constant LIBSSH2_ERROR_SFTP_PROTOCOL (line 86) | pub const LIBSSH2_ERROR_SFTP_PROTOCOL: c_int = -31;
  constant LIBSSH2_ERROR_REQUEST_DENIED (line 87) | pub const LIBSSH2_ERROR_REQUEST_DENIED: c_int = -32;
  constant LIBSSH2_ERROR_METHOD_NOT_SUPPORTED (line 88) | pub const LIBSSH2_ERROR_METHOD_NOT_SUPPORTED: c_int = -33;
  constant LIBSSH2_ERROR_INVAL (line 89) | pub const LIBSSH2_ERROR_INVAL: c_int = -34;
  constant LIBSSH2_ERROR_INVALID_POLL_TYPE (line 90) | pub const LIBSSH2_ERROR_INVALID_POLL_TYPE: c_int = -35;
  constant LIBSSH2_ERROR_PUBLICKEY_PROTOCOL (line 91) | pub const LIBSSH2_ERROR_PUBLICKEY_PROTOCOL: c_int = -36;
  constant LIBSSH2_ERROR_EAGAIN (line 92) | pub const LIBSSH2_ERROR_EAGAIN: c_int = -37;
  constant LIBSSH2_ERROR_BUFFER_TOO_SMALL (line 93) | pub const LIBSSH2_ERROR_BUFFER_TOO_SMALL: c_int = -38;
  constant LIBSSH2_ERROR_BAD_USE (line 94) | pub const LIBSSH2_ERROR_BAD_USE: c_int = -39;
  constant LIBSSH2_ERROR_COMPRESS (line 95) | pub const LIBSSH2_ERROR_COMPRESS: c_int = -40;
  constant LIBSSH2_ERROR_OUT_OF_BOUNDARY (line 96) | pub const LIBSSH2_ERROR_OUT_OF_BOUNDARY: c_int = -41;
  constant LIBSSH2_ERROR_AGENT_PROTOCOL (line 97) | pub const LIBSSH2_ERROR_AGENT_PROTOCOL: c_int = -42;
  constant LIBSSH2_ERROR_SOCKET_RECV (line 98) | pub const LIBSSH2_ERROR_SOCKET_RECV: c_int = -43;
  constant LIBSSH2_ERROR_ENCRYPT (line 99) | pub const LIBSSH2_ERROR_ENCRYPT: c_int = -44;
  constant LIBSSH2_ERROR_BAD_SOCKET (line 100) | pub const LIBSSH2_ERROR_BAD_SOCKET: c_int = -45;
  constant LIBSSH2_ERROR_KNOWN_HOSTS (line 101) | pub const LIBSSH2_ERROR_KNOWN_HOSTS: c_int = -46;
  constant LIBSSH2_ERROR_CHANNEL_WINDOW_FULL (line 102) | pub const LIBSSH2_ERROR_CHANNEL_WINDOW_FULL: c_int = -47;
  constant LIBSSH2_ERROR_KEYFILE_AUTH_FAILED (line 103) | pub const LIBSSH2_ERROR_KEYFILE_AUTH_FAILED: c_int = -48;
  constant LIBSSH2_ERROR_RANDGEN (line 104) | pub const LIBSSH2_ERROR_RANDGEN: c_int = -49;
  constant LIBSSH2_ERROR_MISSING_USERAUTH_BANNER (line 105) | pub const LIBSSH2_ERROR_MISSING_USERAUTH_BANNER: c_int = -50;
  constant LIBSSH2_ERROR_ALGO_UNSUPPORTED (line 106) | pub const LIBSSH2_ERROR_ALGO_UNSUPPORTED: c_int = -51;
  constant LIBSSH2_FX_EOF (line 108) | pub const LIBSSH2_FX_EOF: c_int = 1;
  constant LIBSSH2_FX_NO_SUCH_FILE (line 109) | pub const LIBSSH2_FX_NO_SUCH_FILE: c_int = 2;
  constant LIBSSH2_FX_PERMISSION_DENIED (line 110) | pub const LIBSSH2_FX_PERMISSION_DENIED: c_int = 3;
  constant LIBSSH2_FX_FAILURE (line 111) | pub const LIBSSH2_FX_FAILURE: c_int = 4;
  constant LIBSSH2_FX_BAD_MESSAGE (line 112) | pub const LIBSSH2_FX_BAD_MESSAGE: c_int = 5;
  constant LIBSSH2_FX_NO_CONNECTION (line 113) | pub const LIBSSH2_FX_NO_CONNECTION: c_int = 6;
  constant LIBSSH2_FX_CONNECTION_LOST (line 114) | pub const LIBSSH2_FX_CONNECTION_LOST: c_int = 7;
  constant LIBSSH2_FX_OP_UNSUPPORTED (line 115) | pub const LIBSSH2_FX_OP_UNSUPPORTED: c_int = 8;
  constant LIBSSH2_FX_INVALID_HANDLE (line 116) | pub const LIBSSH2_FX_INVALID_HANDLE: c_int = 9;
  constant LIBSSH2_FX_NO_SUCH_PATH (line 117) | pub const LIBSSH2_FX_NO_SUCH_PATH: c_int = 10;
  constant LIBSSH2_FX_FILE_ALREADY_EXISTS (line 118) | pub const LIBSSH2_FX_FILE_ALREADY_EXISTS: c_int = 11;
  constant LIBSSH2_FX_WRITE_PROTECT (line 119) | pub const LIBSSH2_FX_WRITE_PROTECT: c_int = 12;
  constant LIBSSH2_FX_NO_MEDIA (line 120) | pub const LIBSSH2_FX_NO_MEDIA: c_int = 13;
  constant LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM (line 121) | pub const LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: c_int = 14;
  constant LIBSSH2_FX_QUOTA_EXCEEDED (line 122) | pub const LIBSSH2_FX_QUOTA_EXCEEDED: c_int = 15;
  constant LIBSSH2_FX_UNKNOWN_PRINCIPAL (line 123) | pub const LIBSSH2_FX_UNKNOWN_PRINCIPAL: c_int = 16;
  constant LIBSSH2_FX_LOCK_CONFLICT (line 124) | pub const LIBSSH2_FX_LOCK_CONFLICT: c_int = 17;
  constant LIBSSH2_FX_DIR_NOT_EMPTY (line 125) | pub const LIBSSH2_FX_DIR_NOT_EMPTY: c_int = 18;
  constant LIBSSH2_FX_NOT_A_DIRECTORY (line 126) | pub const LIBSSH2_FX_NOT_A_DIRECTORY: c_int = 19;
  constant LIBSSH2_FX_INVALID_FILENAME (line 127) | pub const LIBSSH2_FX_INVALID_FILENAME: c_int = 20;
  constant LIBSSH2_FX_LINK_LOOP (line 128) | pub const LIBSSH2_FX_LINK_LOOP: c_int = 21;
  constant LIBSSH2_HOSTKEY_HASH_MD5 (line 130) | pub const LIBSSH2_HOSTKEY_HASH_MD5: c_int = 1;
  constant LIBSSH2_HOSTKEY_HASH_SHA1 (line 131) | pub const LIBSSH2_HOSTKEY_HASH_SHA1: c_int = 2;
  constant LIBSSH2_HOSTKEY_HASH_SHA256 (line 132) | pub const LIBSSH2_HOSTKEY_HASH_SHA256: c_int = 3;
  constant LIBSSH2_KNOWNHOST_FILE_OPENSSH (line 134) | pub const LIBSSH2_KNOWNHOST_FILE_OPENSSH: c_int = 1;
  constant LIBSSH2_KNOWNHOST_CHECK_MATCH (line 136) | pub const LIBSSH2_KNOWNHOST_CHECK_MATCH: c_int = 0;
  constant LIBSSH2_KNOWNHOST_CHECK_MISMATCH (line 137) | pub const LIBSSH2_KNOWNHOST_CHECK_MISMATCH: c_int = 1;
  constant LIBSSH2_KNOWNHOST_CHECK_NOTFOUND (line 138) | pub const LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: c_int = 2;
  constant LIBSSH2_KNOWNHOST_CHECK_FAILURE (line 139) | pub const LIBSSH2_KNOWNHOST_CHECK_FAILURE: c_int = 3;
  constant LIBSSH2_KNOWNHOST_TYPE_PLAIN (line 141) | pub const LIBSSH2_KNOWNHOST_TYPE_PLAIN: c_int = 1;
  constant LIBSSH2_KNOWNHOST_TYPE_SHA1 (line 142) | pub const LIBSSH2_KNOWNHOST_TYPE_SHA1: c_int = 2;
  constant LIBSSH2_KNOWNHOST_TYPE_CUSTOM (line 143) | pub const LIBSSH2_KNOWNHOST_TYPE_CUSTOM: c_int = 3;
  constant LIBSSH2_KNOWNHOST_KEYENC_RAW (line 144) | pub const LIBSSH2_KNOWNHOST_KEYENC_RAW: c_int = 1 << 16;
  constant LIBSSH2_KNOWNHOST_KEYENC_BASE64 (line 145) | pub const LIBSSH2_KNOWNHOST_KEYENC_BASE64: c_int = 2 << 16;
  constant LIBSSH2_KNOWNHOST_KEY_RSA1 (line 146) | pub const LIBSSH2_KNOWNHOST_KEY_RSA1: c_int = 1 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_SSHRSA (line 147) | pub const LIBSSH2_KNOWNHOST_KEY_SSHRSA: c_int = 2 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_SSHDSS (line 148) | pub const LIBSSH2_KNOWNHOST_KEY_SSHDSS: c_int = 3 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_ECDSA_256 (line 149) | pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_256: c_int = 4 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_ECDSA_384 (line 150) | pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_384: c_int = 5 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_ECDSA_521 (line 151) | pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_521: c_int = 6 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_ED25519 (line 152) | pub const LIBSSH2_KNOWNHOST_KEY_ED25519: c_int = 7 << 18;
  constant LIBSSH2_KNOWNHOST_KEY_UNKNOWN (line 153) | pub const LIBSSH2_KNOWNHOST_KEY_UNKNOWN: c_int = 15 << 18;
  constant LIBSSH2_FXF_READ (line 155) | pub const LIBSSH2_FXF_READ: c_ulong = 0x00000001;
  constant LIBSSH2_FXF_WRITE (line 156) | pub const LIBSSH2_FXF_WRITE: c_ulong = 0x00000002;
  constant LIBSSH2_FXF_APPEND (line 157) | pub const LIBSSH2_FXF_APPEND: c_ulong = 0x00000004;
  constant LIBSSH2_FXF_CREAT (line 158) | pub const LIBSSH2_FXF_CREAT: c_ulong = 0x00000008;
  constant LIBSSH2_FXF_TRUNC (line 159) | pub const LIBSSH2_FXF_TRUNC: c_ulong = 0x00000010;
  constant LIBSSH2_FXF_EXCL (line 160) | pub const LIBSSH2_FXF_EXCL: c_ulong = 0x00000020;
  constant LIBSSH2_SFTP_OPENFILE (line 162) | pub const LIBSSH2_SFTP_OPENFILE: c_int = 0;
  constant LIBSSH2_SFTP_OPENDIR (line 163) | pub const LIBSSH2_SFTP_OPENDIR: c_int = 1;
  constant LIBSSH2_SFTP_ATTR_SIZE (line 165) | pub const LIBSSH2_SFTP_ATTR_SIZE: c_ulong = 0x00000001;
  constant LIBSSH2_SFTP_ATTR_UIDGID (line 166) | pub const LIBSSH2_SFTP_ATTR_UIDGID: c_ulong = 0x00000002;
  constant LIBSSH2_SFTP_ATTR_PERMISSIONS (line 167) | pub const LIBSSH2_SFTP_ATTR_PERMISSIONS: c_ulong = 0x00000004;
  constant LIBSSH2_SFTP_ATTR_ACMODTIME (line 168) | pub const LIBSSH2_SFTP_ATTR_ACMODTIME: c_ulong = 0x00000008;
  constant LIBSSH2_SFTP_ATTR_EXTENDED (line 169) | pub const LIBSSH2_SFTP_ATTR_EXTENDED: c_ulong = 0x80000000;
  constant LIBSSH2_SFTP_STAT (line 171) | pub const LIBSSH2_SFTP_STAT: c_int = 0;
  constant LIBSSH2_SFTP_LSTAT (line 172) | pub const LIBSSH2_SFTP_LSTAT: c_int = 1;
  constant LIBSSH2_SFTP_SETSTAT (line 173) | pub const LIBSSH2_SFTP_SETSTAT: c_int = 2;
  constant LIBSSH2_SFTP_SYMLINK (line 175) | pub const LIBSSH2_SFTP_SYMLINK: c_int = 0;
  constant LIBSSH2_SFTP_READLINK (line 176) | pub const LIBSSH2_SFTP_READLINK: c_int = 1;
  constant LIBSSH2_SFTP_REALPATH (line 177) | pub const LIBSSH2_SFTP_REALPATH: c_int = 2;
  constant LIBSSH2_SFTP_RENAME_OVERWRITE (line 179) | pub const LIBSSH2_SFTP_RENAME_OVERWRITE: c_long = 0x1;
  constant LIBSSH2_SFTP_RENAME_ATOMIC (line 180) | pub const LIBSSH2_SFTP_RENAME_ATOMIC: c_long = 0x2;
  constant LIBSSH2_SFTP_RENAME_NATIVE (line 181) | pub const LIBSSH2_SFTP_RENAME_NATIVE: c_long = 0x4;
  constant LIBSSH2_INIT_NO_CRYPTO (line 183) | pub const LIBSSH2_INIT_NO_CRYPTO: c_int = 0x1;
  constant LIBSSH2_SFTP_S_IFMT (line 185) | pub const LIBSSH2_SFTP_S_IFMT: c_ulong = 0o170000;
  constant LIBSSH2_SFTP_S_IFIFO (line 186) | pub const LIBSSH2_SFTP_S_IFIFO: c_ulong = 0o010000;
  constant LIBSSH2_SFTP_S_IFCHR (line 187) | pub const LIBSSH2_SFTP_S_IFCHR: c_ulong = 0o020000;
  constant LIBSSH2_SFTP_S_IFDIR (line 188) | pub const LIBSSH2_SFTP_S_IFDIR: c_ulong = 0o040000;
  constant LIBSSH2_SFTP_S_IFBLK (line 189) | pub const LIBSSH2_SFTP_S_IFBLK: c_ulong = 0o060000;
  constant LIBSSH2_SFTP_S_IFREG (line 190) | pub const LIBSSH2_SFTP_S_IFREG: c_ulong = 0o100000;
  constant LIBSSH2_SFTP_S_IFLNK (line 191) | pub const LIBSSH2_SFTP_S_IFLNK: c_ulong = 0o120000;
  constant LIBSSH2_SFTP_S_IFSOCK (line 192) | pub const LIBSSH2_SFTP_S_IFSOCK: c_ulong = 0o140000;
  constant LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL (line 194) | pub const LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL: c_int = 0;
  constant LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE (line 195) | pub const LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE: c_int = 1;
  constant LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE (line 196) | pub const LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE: c_int = 2;
  constant LIBSSH2_SESSION_BLOCK_INBOUND (line 198) | pub const LIBSSH2_SESSION_BLOCK_INBOUND: c_int = 1;
  constant LIBSSH2_SESSION_BLOCK_OUTBOUND (line 199) | pub const LIBSSH2_SESSION_BLOCK_OUTBOUND: c_int = 2;
  constant LIBSSH2_TRACE_TRANS (line 201) | pub const  LIBSSH2_TRACE_TRANS : c_int = 1<<1;
  constant LIBSSH2_TRACE_KEX (line 202) | pub const  LIBSSH2_TRACE_KEX   : c_int = 1<<2;
  constant LIBSSH2_TRACE_AUTH (line 203) | pub const  LIBSSH2_TRACE_AUTH  : c_int = 1<<3;
  constant LIBSSH2_TRACE_CONN (line 204) | pub const  LIBSSH2_TRACE_CONN  : c_int = 1<<4;
  constant LIBSSH2_TRACE_SCP (line 205) | pub const  LIBSSH2_TRACE_SCP   : c_int = 1<<5;
  constant LIBSSH2_TRACE_SFTP (line 206) | pub const  LIBSSH2_TRACE_SFTP  : c_int = 1<<6;
  constant LIBSSH2_TRACE_ERROR (line 207) | pub const  LIBSSH2_TRACE_ERROR : c_int = 1<<7;
  constant LIBSSH2_TRACE_PUBLICKEY (line 208) | pub const  LIBSSH2_TRACE_PUBLICKEY : c_int = 1<<8;
  constant LIBSSH2_TRACE_SOCKET (line 209) | pub const  LIBSSH2_TRACE_SOCKET : c_int = 1<<9;
  type LIBSSH2_SESSION (line 210) | pub enum LIBSSH2_SESSION {}
  type LIBSSH2_AGENT (line 211) | pub enum LIBSSH2_AGENT {}
  type LIBSSH2_CHANNEL (line 212) | pub enum LIBSSH2_CHANNEL {}
  type LIBSSH2_LISTENER (line 213) | pub enum LIBSSH2_LISTENER {}
  type LIBSSH2_KNOWNHOSTS (line 214) | pub enum LIBSSH2_KNOWNHOSTS {}
  type LIBSSH2_SFTP (line 215) | pub enum LIBSSH2_SFTP {}
  type LIBSSH2_SFTP_HANDLE (line 216) | pub enum LIBSSH2_SFTP_HANDLE {}
  type libssh2_int64_t (line 218) | pub type libssh2_int64_t = i64;
  type libssh2_uint64_t (line 219) | pub type libssh2_uint64_t = u64;
  type libssh2_struct_stat (line 229) | pub struct libssh2_struct_stat(libc::stat);
    type Target (line 232) | type Target = libc::stat;
    method deref (line 234) | fn deref(&self) -> &Self::Target {
  type libssh2_agent_publickey (line 240) | pub struct libssh2_agent_publickey {
  type libssh2_knownhost (line 249) | pub struct libssh2_knownhost {
  type LIBSSH2_SFTP_ATTRIBUTES (line 259) | pub struct LIBSSH2_SFTP_ATTRIBUTES {
  type LIBSSH2_SFTP_STATVFS (line 271) | pub struct LIBSSH2_SFTP_STATVFS {
  type LIBSSH2_ALLOC_FUNC (line 285) | pub type LIBSSH2_ALLOC_FUNC = extern "C" fn(size_t, *mut *mut c_void) ->...
  type LIBSSH2_FREE_FUNC (line 286) | pub type LIBSSH2_FREE_FUNC = extern "C" fn(*mut c_void, *mut *mut c_void);
  type LIBSSH2_REALLOC_FUNC (line 287) | pub type LIBSSH2_REALLOC_FUNC = extern "C" fn(*mut c_void, size_t, *mut ...
  type LIBSSH2_PASSWD_CHANGEREQ_FUNC (line 288) | pub type LIBSSH2_PASSWD_CHANGEREQ_FUNC = extern "C" fn(
  type LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC (line 295) | pub type LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC = extern "C" fn(
  type LIBSSH2_USERAUTH_KBDINT_PROMPT (line 307) | pub struct LIBSSH2_USERAUTH_KBDINT_PROMPT {
  type LIBSSH2_USERAUTH_KBDINT_RESPONSE (line 314) | pub struct LIBSSH2_USERAUTH_KBDINT_RESPONSE {
  type libssh2_socket_t (line 320) | pub type libssh2_socket_t = c_int;
  type libssh2_socket_t (line 322) | pub type libssh2_socket_t = u32;
  type libssh2_socket_t (line 324) | pub type libssh2_socket_t = u64;
  function libssh2_init (line 328) | pub fn libssh2_init(flag: c_int) -> c_int;
  function libssh2_exit (line 329) | pub fn libssh2_exit();
  function libssh2_free (line 330) | pub fn libssh2_free(sess: *mut LIBSSH2_SESSION, ptr: *mut c_void);
  function libssh2_hostkey_hash (line 331) | pub fn libssh2_hostkey_hash(session: *mut LIBSSH2_SESSION, hash_type: c_...
  function libssh2_trace (line 332) | pub fn libssh2_trace(session: *mut LIBSSH2_SESSION, bitmask: c_int) -> c...
  function libssh2_session_init_ex (line 335) | pub fn libssh2_session_init_ex(
  function libssh2_session_abstract (line 341) | pub fn libssh2_session_abstract(session: *mut LIBSSH2_SESSION) -> *mut *...
  function libssh2_session_free (line 342) | pub fn libssh2_session_free(sess: *mut LIBSSH2_SESSION) -> c_int;
  function libssh2_session_banner_get (line 343) | pub fn libssh2_session_banner_get(sess: *mut LIBSSH2_SESSION) -> *const ...
  function libssh2_session_banner_set (line 344) | pub fn libssh2_session_banner_set(sess: *mut LIBSSH2_SESSION, banner: *c...
  function libssh2_session_disconnect_ex (line 345) | pub fn libssh2_session_disconnect_ex(
  function libssh2_session_flag (line 351) | pub fn libssh2_session_flag(sess: *mut LIBSSH2_SESSION, flag: c_int, val...
  function libssh2_session_get_blocking (line 352) | pub fn libssh2_session_get_blocking(session: *mut LIBSSH2_SESSION) -> c_...
  function libssh2_session_get_timeout (line 353) | pub fn libssh2_session_get_timeout(sess: *mut LIBSSH2_SESSION) -> c_long;
  function libssh2_session_hostkey (line 354) | pub fn libssh2_session_hostkey(
  function libssh2_session_method_pref (line 359) | pub fn libssh2_session_method_pref(
  function libssh2_session_methods (line 364) | pub fn libssh2_session_methods(sess: *mut LIBSSH2_SESSION, method_type: ...
  function libssh2_session_set_blocking (line 366) | pub fn libssh2_session_set_blocking(session: *mut LIBSSH2_SESSION, block...
  function libssh2_session_set_timeout (line 367) | pub fn libssh2_session_set_timeout(session: *mut LIBSSH2_SESSION, timeou...
  function libssh2_session_supported_algs (line 368) | pub fn libssh2_session_supported_algs(
  function libssh2_session_last_errno (line 373) | pub fn libssh2_session_last_errno(sess: *mut LIBSSH2_SESSION) -> c_int;
  function libssh2_session_last_error (line 374) | pub fn libssh2_session_last_error(
  function libssh2_session_handshake (line 380) | pub fn libssh2_session_handshake(sess: *mut LIBSSH2_SESSION, socket: lib...
  function libssh2_keepalive_config (line 382) | pub fn libssh2_keepalive_config(
  function libssh2_keepalive_send (line 387) | pub fn libssh2_keepalive_send(sess: *mut LIBSSH2_SESSION, seconds_to_nex...
  function libssh2_session_block_directions (line 389) | pub fn libssh2_session_block_directions(sess: *mut LIBSSH2_SESSION) -> c...
  function libssh2_agent_init (line 392) | pub fn libssh2_agent_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_AG...
  function libssh2_agent_free (line 393) | pub fn libssh2_agent_free(agent: *mut LIBSSH2_AGENT);
  function libssh2_agent_connect (line 394) | pub fn libssh2_agent_connect(agent: *mut LIBSSH2_AGENT) -> c_int;
  function libssh2_agent_disconnect (line 395) | pub fn libssh2_agent_disconnect(agent: *mut LIBSSH2_AGENT) -> c_int;
  function libssh2_agent_list_identities (line 396) | pub fn libssh2_agent_list_identities(agent: *mut LIBSSH2_AGENT) -> c_int;
  function libssh2_agent_get_identity (line 397) | pub fn libssh2_agent_get_identity(
  function libssh2_agent_userauth (line 402) | pub fn libssh2_agent_userauth(
  function libssh2_channel_free (line 409) | pub fn libssh2_channel_free(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_close (line 410) | pub fn libssh2_channel_close(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_wait_closed (line 411) | pub fn libssh2_channel_wait_closed(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_wait_eof (line 412) | pub fn libssh2_channel_wait_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_eof (line 413) | pub fn libssh2_channel_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_process_startup (line 414) | pub fn libssh2_channel_process_startup(
  function libssh2_channel_flush_ex (line 421) | pub fn libssh2_channel_flush_ex(chan: *mut LIBSSH2_CHANNEL, streamid: c_...
  function libssh2_channel_write_ex (line 422) | pub fn libssh2_channel_write_ex(
  function libssh2_channel_get_exit_signal (line 428) | pub fn libssh2_channel_get_exit_signal(
  function libssh2_channel_get_exit_status (line 437) | pub fn libssh2_channel_get_exit_status(chan: *mut LIBSSH2_CHANNEL) -> c_...
  function libssh2_channel_open_ex (line 438) | pub fn libssh2_channel_open_ex(
  function libssh2_channel_read_ex (line 447) | pub fn libssh2_channel_read_ex(
  function libssh2_channel_setenv_ex (line 453) | pub fn libssh2_channel_setenv_ex(
  function libssh2_channel_send_eof (line 460) | pub fn libssh2_channel_send_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int;
  function libssh2_channel_request_pty_ex (line 461) | pub fn libssh2_channel_request_pty_ex(
  function libssh2_channel_request_pty_size_ex (line 472) | pub fn libssh2_channel_request_pty_size_ex(
  function libssh2_channel_window_read_ex (line 479) | pub fn libssh2_channel_window_read_ex(
  function libssh2_channel_window_write_ex (line 484) | pub fn libssh2_channel_window_write_ex(
  function libssh2_channel_receive_window_adjust2 (line 488) | pub fn libssh2_channel_receive_window_adjust2(
  function libssh2_channel_direct_tcpip_ex (line 494) | pub fn libssh2_channel_direct_tcpip_ex(
  function libssh2_channel_direct_streamlocal_ex (line 501) | pub fn libssh2_channel_direct_streamlocal_ex(
  function libssh2_channel_forward_accept (line 507) | pub fn libssh2_channel_forward_accept(listener: *mut LIBSSH2_LISTENER) -...
  function libssh2_channel_forward_cancel (line 508) | pub fn libssh2_channel_forward_cancel(listener: *mut LIBSSH2_LISTENER) -...
  function libssh2_channel_forward_listen_ex (line 509) | pub fn libssh2_channel_forward_listen_ex(
  function libssh2_channel_handle_extended_data2 (line 516) | pub fn libssh2_channel_handle_extended_data2(
  function libssh2_channel_request_auth_agent (line 520) | pub fn libssh2_channel_request_auth_agent(channel: *mut LIBSSH2_CHANNEL)...
  function libssh2_userauth_banner (line 523) | pub fn libssh2_userauth_banner(sess: *mut LIBSSH2_SESSION, banner: *mut ...
  function libssh2_userauth_authenticated (line 524) | pub fn libssh2_userauth_authenticated(sess: *mut LIBSSH2_SESSION) -> c_int;
  function libssh2_userauth_list (line 525) | pub fn libssh2_userauth_list(
  function libssh2_userauth_hostbased_fromfile_ex (line 530) | pub fn libssh2_userauth_hostbased_fromfile_ex(
  function libssh2_userauth_publickey_fromfile_ex (line 542) | pub fn libssh2_userauth_publickey_fromfile_ex(
  function libssh2_userauth_publickey_frommemory (line 550) | pub fn libssh2_userauth_publickey_frommemory(
  function libssh2_userauth_password_ex (line 560) | pub fn libssh2_userauth_password_ex(
  function libssh2_userauth_keyboard_interactive_ex (line 568) | pub fn libssh2_userauth_keyboard_interactive_ex(
  function libssh2_knownhost_free (line 576) | pub fn libssh2_knownhost_free(hosts: *mut LIBSSH2_KNOWNHOSTS);
  function libssh2_knownhost_addc (line 577) | pub fn libssh2_knownhost_addc(
  function libssh2_knownhost_check (line 588) | pub fn libssh2_knownhost_check(
  function libssh2_knownhost_checkp (line 596) | pub fn libssh2_knownhost_checkp(
  function libssh2_knownhost_del (line 605) | pub fn libssh2_knownhost_del(
  function libssh2_knownhost_get (line 609) | pub fn libssh2_knownhost_get(
  function libssh2_knownhost_readfile (line 614) | pub fn libssh2_knownhost_readfile(
  function libssh2_knownhost_readline (line 619) | pub fn libssh2_knownhost_readline(
  function libssh2_knownhost_writefile (line 625) | pub fn libssh2_knownhost_writefile(
  function libssh2_knownhost_writeline (line 630) | pub fn libssh2_knownhost_writeline(
  function libssh2_knownhost_init (line 638) | pub fn libssh2_knownhost_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH...
  function libssh2_scp_recv (line 642) | pub fn libssh2_scp_recv(
  function libssh2_scp_recv2 (line 648) | pub fn libssh2_scp_recv2(
  function libssh2_scp_send64 (line 654) | pub fn libssh2_scp_send64(
  function libssh2_sftp_init (line 664) | pub fn libssh2_sftp_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_SFTP;
  function libssh2_sftp_shutdown (line 665) | pub fn libssh2_sftp_shutdown(sftp: *mut LIBSSH2_SFTP) -> c_int;
  function libssh2_sftp_last_error (line 666) | pub fn libssh2_sftp_last_error(sftp: *mut LIBSSH2_SFTP) -> c_ulong;
  function libssh2_sftp_open_ex (line 667) | pub fn libssh2_sftp_open_ex(
  function libssh2_sftp_close_handle (line 675) | pub fn libssh2_sftp_close_handle(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_...
  function libssh2_sftp_mkdir_ex (line 676) | pub fn libssh2_sftp_mkdir_ex(
  function libssh2_sftp_fsync (line 682) | pub fn libssh2_sftp_fsync(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_int;
  function libssh2_sftp_fstat_ex (line 683) | pub fn libssh2_sftp_fstat_ex(
  function libssh2_sftp_fstatvfs (line 688) | pub fn libssh2_sftp_fstatvfs(
  function libssh2_sftp_stat_ex (line 692) | pub fn libssh2_sftp_stat_ex(
  function libssh2_sftp_read (line 699) | pub fn libssh2_sftp_read(
  function libssh2_sftp_symlink_ex (line 704) | pub fn libssh2_sftp_symlink_ex(
  function libssh2_sftp_rename_ex (line 712) | pub fn libssh2_sftp_rename_ex(
  function libssh2_sftp_rmdir_ex (line 720) | pub fn libssh2_sftp_rmdir_ex(
  function libssh2_sftp_write (line 725) | pub fn libssh2_sftp_write(
  function libssh2_sftp_tell64 (line 730) | pub fn libssh2_sftp_tell64(handle: *mut LIBSSH2_SFTP_HANDLE) -> libssh2_...
  function libssh2_sftp_seek64 (line 731) | pub fn libssh2_sftp_seek64(handle: *mut LIBSSH2_SFTP_HANDLE, off: libssh...
  function libssh2_sftp_readdir_ex (line 732) | pub fn libssh2_sftp_readdir_ex(
  function libssh2_sftp_unlink_ex (line 740) | pub fn libssh2_sftp_unlink_ex(
  function smoke (line 748) | fn smoke() {
  function issue_14344_workaround (line 753) | pub fn issue_14344_workaround() {}
  function init (line 755) | pub fn init() {

FILE: src/agent.rs
  type Agent (line 13) | pub struct Agent {
    method from_raw_opt (line 32) | pub(crate) fn from_raw_opt(
    method connect (line 48) | pub fn connect(&mut self) -> Result<(), Error> {
    method disconnect (line 54) | pub fn disconnect(&mut self) -> Result<(), Error> {
    method list_identities (line 63) | pub fn list_identities(&mut self) -> Result<(), Error> {
    method identities (line 69) | pub fn identities(&self) -> Result<Vec<PublicKey>, Error> {
    method resolve_raw_identity (line 87) | fn resolve_raw_identity(
    method userauth (line 111) | pub fn userauth(&self, username: &str, identity: &PublicKey) -> Result...
  type PublicKey (line 26) | pub struct PublicKey {
    method from_raw (line 137) | unsafe fn from_raw(raw: *mut raw::libssh2_agent_publickey) -> Self {
    method blob (line 152) | pub fn blob(&self) -> &[u8] {
    method comment (line 157) | pub fn comment(&self) -> &str {
  method drop (line 131) | fn drop(&mut self) {

FILE: src/channel.rs
  type ChannelInner (line 13) | struct ChannelInner {
  type LockedChannel (line 25) | struct LockedChannel<'a> {
  type Channel (line 45) | pub struct Channel {
    method from_raw_opt (line 50) | pub(crate) fn from_raw_opt(
    method lock (line 68) | fn lock(&self) -> LockedChannel<'_> {
    method setenv (line 142) | pub fn setenv(&mut self, var: &str, val: &str) -> Result<(), Error> {
    method request_pty (line 178) | pub fn request_pty(
    method request_pty_size (line 208) | pub fn request_pty_size(
    method request_auth_agent_forwarding (line 236) | pub fn request_auth_agent_forwarding(&mut self) -> Result<(), Error> {
    method exec (line 260) | pub fn exec(&mut self, command: &str) -> Result<(), Error> {
    method shell (line 268) | pub fn shell(&mut self) -> Result<(), Error> {
    method subsystem (line 276) | pub fn subsystem(&mut self, system: &str) -> Result<(), Error> {
    method process_startup (line 284) | pub fn process_startup(&mut self, request: &str, message: Option<&str>...
    method stderr (line 306) | pub fn stderr(&self) -> Stream {
    method stream (line 319) | pub fn stream(&self, stream_id: i32) -> Stream {
    method handle_extended_data (line 327) | pub fn handle_extended_data(&mut self, mode: ExtendedData) -> Result<(...
    method exit_status (line 340) | pub fn exit_status(&self) -> Result<i32, Error> {
    method exit_signal (line 350) | pub fn exit_signal(&self) -> Result<ExitSignal, Error> {
    method read_window (line 388) | pub fn read_window(&self) -> ReadWindow {
    method write_window (line 403) | pub fn write_window(&self) -> WriteWindow {
    method adjust_receive_window (line 422) | pub fn adjust_receive_window(&mut self, adjust: u64, force: bool) -> R...
    method limit_read (line 440) | pub(crate) fn limit_read(&mut self, limit: u64) {
    method eof (line 448) | pub fn eof(&self) -> bool {
    method send_eof (line 458) | pub fn send_eof(&mut self) -> Result<(), Error> {
    method wait_eof (line 468) | pub fn wait_eof(&mut self) -> Result<(), Error> {
    method close (line 482) | pub fn close(&mut self) -> Result<(), Error> {
    method wait_close (line 491) | pub fn wait_close(&mut self) -> Result<(), Error> {
  type Stream (line 86) | pub struct Stream {
    method lock (line 522) | fn lock(&self) -> LockedStream<'_> {
  type LockedStream (line 91) | struct LockedStream<'a> {
  function eof (line 99) | pub fn eof(&self) -> bool {
  type ExitSignal (line 105) | pub struct ExitSignal {
  type ReadWindow (line 117) | pub struct ReadWindow {
  type WriteWindow (line 129) | pub struct WriteWindow {
  method write (line 498) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  method flush (line 502) | fn flush(&mut self) -> io::Result<()> {
  method read (line 508) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  method drop (line 514) | fn drop(&mut self) {
  method read (line 534) | fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
  method write (line 569) | fn write(&mut self, data: &[u8]) -> io::Result<usize> {
  method flush (line 583) | fn flush(&mut self) -> io::Result<()> {

FILE: src/error.rs
  type ErrorCode (line 14) | pub enum ErrorCode {
    method fmt (line 28) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  type Error (line 36) | pub struct Error {
    method last_session_error_raw (line 43) | pub fn last_session_error_raw(raw: *mut raw::LIBSSH2_SESSION) -> Optio...
    method from_session_error (line 67) | pub fn from_session_error(sess: &Session, rc: libc::c_int) -> Error {
    method from_session_error_raw (line 72) | pub fn from_session_error_raw(raw: *mut raw::LIBSSH2_SESSION, rc: libc...
    method last_session_error (line 93) | pub fn last_session_error(sess: &Session) -> Option<Error> {
    method new (line 98) | pub fn new(code: ErrorCode, msg: &'static str) -> Error {
    method eof (line 106) | pub fn eof() -> Error {
    method unknown (line 114) | pub fn unknown() -> Error {
    method from_errno (line 122) | pub fn from_errno(code: ErrorCode) -> Error {
    method message (line 206) | pub fn message(&self) -> &str {
    method code (line 211) | pub fn code(&self) -> ErrorCode {
    method fmt (line 230) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    method description (line 236) | fn description(&self) -> &str {
    method from (line 242) | fn from(_: NulError) -> Error {
  function from (line 217) | fn from(err: Error) -> io::Error {
  function make_error_message (line 251) | unsafe fn make_error_message(msg: *mut libc::c_char) -> Cow<'static, str> {

FILE: src/knownhosts.rs
  type KnownHosts (line 48) | pub struct KnownHosts {
    method from_raw_opt (line 61) | pub(crate) fn from_raw_opt(
    method read_file (line 78) | pub fn read_file(&mut self, file: &Path, kind: KnownHostFileKind) -> R...
    method read_str (line 89) | pub fn read_str(&mut self, s: &str, kind: KnownHostFileKind) -> Result...
    method write_file (line 105) | pub fn write_file(&self, file: &Path, kind: KnownHostFileKind) -> Resu...
    method write_string (line 114) | pub fn write_string(&self, host: &Host, kind: KnownHostFileKind) -> Re...
    method iter (line 148) | pub fn iter(&self) -> Result<Vec<Host>, Error> {
    method hosts (line 153) | pub fn hosts(&self) -> Result<Vec<Host>, Error> {
    method resolve_to_raw_host (line 175) | fn resolve_to_raw_host(
    method remove (line 200) | pub fn remove(&self, host: &Host) -> Result<(), Error> {
    method check (line 215) | pub fn check(&self, host: &str, key: &[u8]) -> CheckResult {
    method check_port (line 220) | pub fn check_port(&self, host: &str, port: u16, key: &[u8]) -> CheckRe...
    method check_port_ (line 224) | fn check_port_(&self, host: &str, port: i32, key: &[u8]) -> CheckResult {
    method add (line 256) | pub fn add(
  type Host (line 55) | pub struct Host {
    method name (line 294) | pub fn name(&self) -> Option<&str> {
    method key (line 299) | pub fn key(&self) -> &str {
    method from_raw (line 303) | unsafe fn from_raw(raw: *mut raw::libssh2_knownhost) -> Self {
  method drop (line 286) | fn drop(&mut self) {

FILE: src/lib.rs
  function init (line 254) | pub fn init() {
  function opt_bytes (line 258) | unsafe fn opt_bytes<'a, T>(_: &'a T, c: *const libc::c_char) -> Option<&...
  type DisconnectCode (line 268) | pub enum DisconnectCode {
  type HostKeyType (line 288) | pub enum HostKeyType {
  type MethodType (line 300) | pub enum MethodType {
  type HashType (line 324) | pub enum HashType {
  type KnownHostFileKind (line 332) | pub enum KnownHostFileKind {
  type CheckResult (line 338) | pub enum CheckResult {
  type KnownHostKeyFormat (line 351) | pub enum KnownHostKeyFormat {
    method from (line 363) | fn from(host_type: HostKeyType) -> KnownHostKeyFormat {
  type ExtendedData (line 378) | pub enum ExtendedData {
  type PtyModeOpcode (line 391) | pub enum PtyModeOpcode {
  type ExtensiblePtyModeOpcode (line 510) | pub enum ExtensiblePtyModeOpcode {
    method from (line 518) | fn from(op: PtyModeOpcode) -> ExtensiblePtyModeOpcode {
    method from (line 524) | fn from(op: u8) -> ExtensiblePtyModeOpcode {
    method as_opcode (line 530) | fn as_opcode(&self) -> u8 {
  type PtyModes (line 542) | pub struct PtyModes {
    method new (line 549) | pub fn new() -> Self {
    method set_u32 (line 554) | pub fn set_u32<O: Into<ExtensiblePtyModeOpcode>>(&mut self, option: O,...
    method set_boolean (line 566) | pub fn set_boolean<O: Into<ExtensiblePtyModeOpcode>>(&mut self, option...
    method set_character (line 576) | pub fn set_character<O: Into<ExtensiblePtyModeOpcode>>(&mut self, opti...
    method finish (line 582) | pub fn finish(mut self) -> Vec<u8> {

FILE: src/listener.rs
  type Listener (line 9) | pub struct Listener {
    method accept (line 22) | pub fn accept(&mut self) -> Result<Channel, Error> {
    method from_raw_opt (line 31) | pub(crate) fn from_raw_opt(
  method drop (line 48) | fn drop(&mut self) {

FILE: src/session.rs
  type KeyboardInteractivePrompt (line 51) | pub trait KeyboardInteractivePrompt {
    method prompt (line 59) | fn prompt<'a>(
  type Prompt (line 69) | pub struct Prompt<'a> {
  function with_abstract (line 84) | unsafe fn with_abstract<R, F: FnOnce() -> R>(
  type SessionInner (line 97) | pub(crate) struct SessionInner {
    method rc (line 1152) | pub fn rc(&self, rc: c_int) -> Result<(), Error> {
    method last_error (line 1160) | pub fn last_error(&self) -> Option<Error> {
    method set_blocking (line 1165) | pub fn set_blocking(&self, blocking: bool) {
    method is_blocking (line 1170) | pub fn is_blocking(&self) -> bool {
  type Session (line 129) | pub struct Session {
    method new (line 160) | pub fn new() -> Result<Session, Error> {
    method raw (line 178) | pub fn raw(&self) -> MappedMutexGuard<'_, raw::LIBSSH2_SESSION> {
    method set_banner (line 189) | pub fn set_banner(&self, banner: &str) -> Result<(), Error> {
    method set_allow_sigpipe (line 201) | pub fn set_allow_sigpipe(&self, block: bool) {
    method set_compress (line 219) | pub fn set_compress(&self, compress: bool) {
    method set_blocking (line 240) | pub fn set_blocking(&self, blocking: bool) {
    method is_blocking (line 245) | pub fn is_blocking(&self) -> bool {
    method set_timeout (line 257) | pub fn set_timeout(&self, timeout_ms: u32) {
    method timeout (line 267) | pub fn timeout(&self) -> u32 {
    method handshake (line 276) | pub fn handshake(&mut self) -> Result<(), Error> {
    method set_tcp_stream (line 312) | pub fn set_tcp_stream<S: 'static + AsRawFd>(&mut self, stream: S) {
    method set_tcp_stream (line 324) | pub fn set_tcp_stream<S: 'static + AsRawSocket>(&mut self, stream: S) {
    method userauth_password (line 335) | pub fn userauth_password(&self, username: &str, password: &str) -> Res...
    method userauth_keyboard_interactive (line 356) | pub fn userauth_keyboard_interactive<P: KeyboardInteractivePrompt>(
    method userauth_agent (line 488) | pub fn userauth_agent(&self, username: &str) -> Result<(), Error> {
    method userauth_pubkey_file (line 507) | pub fn userauth_pubkey_file(
    method userauth_pubkey_memory (line 545) | pub fn userauth_pubkey_memory(
    method userauth_hostbased_file (line 587) | pub fn userauth_hostbased_file(
    method authenticated (line 632) | pub fn authenticated(&self) -> bool {
    method auth_methods (line 648) | pub fn auth_methods(&self, username: &str) -> Result<&str, Error> {
    method userauth_banner (line 671) | pub fn userauth_banner(&self) -> Result<Option<&str>, Error> {
    method method_pref (line 693) | pub fn method_pref(&self, method_type: MethodType, prefs: &str) -> Res...
    method methods (line 709) | pub fn methods(&self, method_type: MethodType) -> Option<&str> {
    method supported_algs (line 718) | pub fn supported_algs(&self, method_type: MethodType) -> Result<Vec<&'...
    method agent (line 742) | pub fn agent(&self) -> Result<Agent, Error> {
    method known_hosts (line 755) | pub fn known_hosts(&self) -> Result<KnownHosts, Error> {
    method channel_session (line 768) | pub fn channel_session(&self) -> Result<Channel, Error> {
    method channel_direct_tcpip (line 789) | pub fn channel_direct_tcpip(
    method channel_direct_streamlocal (line 824) | pub fn channel_direct_streamlocal(
    method channel_forward_listen (line 850) | pub fn channel_forward_listen(
    method scp_recv (line 880) | pub fn scp_recv(&self, path: &Path) -> Result<(Channel, ScpFileStat), ...
    method scp_send (line 907) | pub fn scp_send(
    method sftp (line 937) | pub fn sftp(&self) -> Result<Sftp, Error> {
    method channel_open (line 950) | pub fn channel_open(
    method banner (line 987) | pub fn banner(&self) -> Option<&str> {
    method banner_bytes (line 994) | pub fn banner_bytes(&self) -> Option<&[u8]> {
    method host_key (line 1002) | pub fn host_key(&self) -> Option<(&[u8], HostKeyType)> {
    method host_key_hash (line 1030) | pub fn host_key_hash(&self, hash: HashType) -> Option<&[u8]> {
    method set_keepalive (line 1056) | pub fn set_keepalive(&self, want_reply: bool, interval: u32) {
    method keepalive_send (line 1065) | pub fn keepalive_send(&self) -> Result<u32, Error> {
    method disconnect (line 1079) | pub fn disconnect(
    method block_directions (line 1103) | pub fn block_directions(&self) -> BlockDirections {
    method inner (line 1116) | fn inner(&self) -> MutexGuard<'_, SessionInner> {
    method trace (line 1122) | pub fn trace(&self, bitmask: TraceFlags) {
  type ScpFileStat (line 134) | pub struct ScpFileStat {
    method size (line 1185) | pub fn size(&self) -> u64 {
    method mode (line 1189) | pub fn mode(&self) -> i32 {
    method is_dir (line 1193) | pub fn is_dir(&self) -> bool {
    method is_file (line 1197) | pub fn is_file(&self) -> bool {
  type BlockDirections (line 140) | pub enum BlockDirections {
  method as_raw_fd (line 1130) | fn as_raw_fd(&self) -> RawFd {
  method as_raw_socket (line 1141) | fn as_raw_socket(&self) -> RawSocket {
  method drop (line 1176) | fn drop(&mut self) {

FILE: src/sftp.rs
  type Sftp (line 18) | pub struct Sftp {
    method from_raw_opt (line 159) | pub(crate) fn from_raw_opt(
    method open_mode (line 179) | pub fn open_mode<T: AsRef<Path>>(
    method open (line 208) | pub fn open<T: AsRef<Path>>(&self, filename: T) -> Result<File, Error> {
    method create (line 213) | pub fn create(&self, filename: &Path) -> Result<File, Error> {
    method opendir (line 223) | pub fn opendir<T: AsRef<Path>>(&self, dirname: T) -> Result<File, Erro...
    method readdir (line 231) | pub fn readdir<T: AsRef<Path>>(&self, dirname: T) -> Result<Vec<(PathB...
    method mkdir (line 257) | pub fn mkdir(&self, filename: &Path, mode: i32) -> Result<(), Error> {
    method rmdir (line 271) | pub fn rmdir(&self, filename: &Path) -> Result<(), Error> {
    method stat (line 284) | pub fn stat(&self, filename: &Path) -> Result<FileStat, Error> {
    method lstat (line 304) | pub fn lstat(&self, filename: &Path) -> Result<FileStat, Error> {
    method setstat (line 324) | pub fn setstat(&self, filename: &Path, stat: FileStat) -> Result<(), E...
    method symlink (line 340) | pub fn symlink(&self, path: &Path, target: &Path) -> Result<(), Error> {
    method readlink (line 357) | pub fn readlink(&self, path: &Path) -> Result<PathBuf, Error> {
    method realpath (line 362) | pub fn realpath(&self, path: &Path) -> Result<PathBuf, Error> {
    method readlink_op (line 366) | fn readlink_op(&self, path: &Path, op: c_int) -> Result<PathBuf, Error> {
    method rename (line 407) | pub fn rename(&self, src: &Path, dst: &Path, flags: Option<RenameFlags...
    method unlink (line 426) | pub fn unlink(&self, file: &Path) -> Result<(), Error> {
    method lock (line 438) | fn lock(&self) -> Result<LockedSftp<'_>, Error> {
    method shutdown (line 459) | pub fn shutdown(&mut self) -> Result<(), Error> {
    method error_code_into_error (line 496) | fn error_code_into_error(
    method error_code_into_result (line 518) | fn error_code_into_result(
    method rc (line 530) | fn rc(locked: &LockedSftp, rc: libc::c_int) -> Result<(), Error> {
  type SftpInnerDropWrapper (line 23) | struct SftpInnerDropWrapper(Option<SftpInner>);
  type SftpInner (line 24) | struct SftpInner {
  type LockedSftp (line 35) | struct LockedSftp<'sftp> {
  type File (line 47) | pub struct File {
    method from_raw (line 556) | unsafe fn from_raw(sftp: &Sftp, raw: *mut raw::LIBSSH2_SFTP_HANDLE) ->...
    method setstat (line 571) | pub fn setstat(&mut self, stat: FileStat) -> Result<(), Error> {
    method stat (line 580) | pub fn stat(&mut self) -> Result<FileStat, Error> {
    method statvfs (line 590) | pub fn statvfs(&mut self) -> Result<raw::LIBSSH2_SFTP_STATVFS, Error> {
    method readdir (line 609) | pub fn readdir(&mut self) -> Result<(PathBuf, FileStat), Error> {
    method fsync (line 656) | pub fn fsync(&mut self) -> Result<(), Error> {
    method lock (line 661) | fn lock(&self) -> Result<LockedFile<'_>, Error> {
    method close (line 681) | pub fn close(&mut self) -> Result<(), Error> {
    method rc (line 701) | fn rc(&self, locked: &LockedFile, rc: libc::c_int) -> Result<(), Error> {
  type FileInner (line 50) | struct FileInner {
  type LockedFile (line 61) | struct LockedFile<'file> {
  type FileStat (line 71) | pub struct FileStat {
    method file_type (line 820) | pub fn file_type(&self) -> FileType {
    method is_dir (line 825) | pub fn is_dir(&self) -> bool {
    method is_file (line 830) | pub fn is_file(&self) -> bool {
    method from_raw (line 835) | pub fn from_raw(raw: &raw::LIBSSH2_SFTP_ATTRIBUTES) -> FileStat {
    method raw (line 855) | pub fn raw(&self) -> raw::LIBSSH2_SFTP_ATTRIBUTES {
  type FileType (line 88) | pub enum FileType {
    method is_dir (line 883) | pub fn is_dir(&self) -> bool {
    method is_file (line 888) | pub fn is_file(&self) -> bool {
    method is_symlink (line 893) | pub fn is_symlink(&self) -> bool {
    method from_perm (line 897) | fn from_perm(perm: c_ulong) -> Self {
  type OpenType (line 151) | pub enum OpenType {
  method drop (line 536) | fn drop(&mut self) {
  method read (line 717) | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
  method write (line 740) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  method flush (line 761) | fn flush(&mut self) -> io::Result<()> {
  method seek (line 777) | fn seek(&mut self, how: SeekFrom) -> io::Result<u64> {
  method drop (line 800) | fn drop(&mut self) {
  function mkpath (line 912) | fn mkpath(v: Vec<u8>) -> PathBuf {
  function mkpath (line 918) | fn mkpath(v: Vec<u8>) -> PathBuf {

FILE: src/util.rs
  function path2bytes (line 7) | pub fn path2bytes(p: &Path) -> Result<Cow<'_, [u8]>, Error> {
  function path2bytes (line 14) | pub fn path2bytes(p: &Path) -> Result<Cow<'_, [u8]>, Error> {
  function check (line 40) | fn check(b: Cow<[u8]>) -> Result<Cow<[u8]>, Error> {

FILE: systest/build.rs
  function main (line 5) | fn main() {

FILE: tests/all/agent.rs
  function smoke (line 4) | fn smoke() {

FILE: tests/all/channel.rs
  function consume_stdio (line 10) | fn consume_stdio(channel: &mut Channel) -> (String, String) {
  function smoke (line 24) | fn smoke() {
  function agent_forward (line 48) | fn agent_forward() {
  function bad_smoke (line 64) | fn bad_smoke() {
  function reading_data (line 81) | fn reading_data() {
  function handle_extended_data (line 91) | fn handle_extended_data() {
  function writing_data (line 107) | fn writing_data() {
  function eof (line 118) | fn eof() {
  function shell (line 130) | fn shell() {
  function setenv (line 144) | fn setenv() {
  function direct (line 152) | fn direct() {
  function direct_stream_local (line 175) | fn direct_stream_local() {
  function forward (line 200) | fn forward() {
  function drop_nonblocking (line 220) | fn drop_nonblocking() {
  function nonblocking_before_exit_code (line 236) | fn nonblocking_before_exit_code() {
  function exit_code_ignores_other_errors (line 261) | fn exit_code_ignores_other_errors() {
  function pty_modes_are_propagated (line 274) | fn pty_modes_are_propagated() {

FILE: tests/all/knownhosts.rs
  function smoke (line 4) | fn smoke() {
  function reading (line 12) | fn reading() {

FILE: tests/all/main.rs
  function test_addr (line 15) | pub fn test_addr() -> String {
  function socket (line 23) | pub fn socket() -> TcpStream {
  function authed_session (line 27) | pub fn authed_session() -> ssh2::Session {

FILE: tests/all/session.rs
  function session_is_send (line 10) | fn session_is_send() {
  function smoke (line 20) | fn smoke() {
  function smoke_handshake (line 39) | fn smoke_handshake() {
  function smoke_userauth_banner (line 62) | fn smoke_userauth_banner() {
  function keyboard_interactive (line 75) | fn keyboard_interactive() {
  function keepalive (line 152) | fn keepalive() {
  function scp_recv (line 159) | fn scp_recv() {
  function scp_send (line 178) | fn scp_send() {
  function block_directions (line 195) | fn block_directions() {

FILE: tests/all/sftp.rs
  function smoke (line 6) | fn smoke() {
  function ops (line 12) | fn ops() {
  function not_found (line 63) | fn not_found() {
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (249K chars).
[
  {
    "path": ".github/workflows/linux.yml",
    "chars": 671,
    "preview": "name: linux\n\non:\n  push:\n    branches:\n    - master\n  pull_request:\n    branches:\n    - master\n\njobs:\n  build:\n    strat"
  },
  {
    "path": ".github/workflows/macos.yml",
    "chars": 574,
    "preview": "name: macOS\n\non:\n  push:\n    branches:\n    - master\n  pull_request:\n    branches:\n    - master\n\njobs:\n  build:\n    strat"
  },
  {
    "path": ".github/workflows/windows.yml",
    "chars": 842,
    "preview": "name: Windows\n\non:\n  push:\n    branches:\n    - master\n  pull_request:\n    branches:\n    - master\n\njobs:\n  build:\n    str"
  },
  {
    "path": ".gitignore",
    "chars": 60,
    "preview": ".*.sw*\n/target/\nlibssh2-sys/target/\n/Cargo.lock\n/tests/sshd\n"
  },
  {
    "path": ".gitmodules",
    "chars": 121,
    "preview": "[submodule \"libssh2-sys/libssh2\"]\n\tpath = libssh2-sys/libssh2\n\turl = https://github.com/libssh2/libssh2\n\tbranch = master"
  },
  {
    "path": ".mailmap",
    "chars": 54,
    "preview": "<ga29smith@gmail.com> <gabriel.smith@precisionot.com>\n"
  },
  {
    "path": ".travis.yml",
    "chars": 690,
    "preview": "language: rust\nsudo: required\n\nmatrix:\n  include:\n    - rust: 1.36.0\n    - rust: stable\n    - rust: beta\n    - rust: nig"
  },
  {
    "path": "Cargo.toml",
    "chars": 827,
    "preview": "[package]\nname = \"ssh2\"\nversion = \"0.9.5\"\nauthors = [\"Alex Crichton <alex@alexcrichton.com>\", \"Wez Furlong <wez@wezfurlo"
  },
  {
    "path": "LICENSE-APACHE",
    "chars": 10847,
    "preview": "                              Apache License\n                        Version 2.0, January 2004\n                     http"
  },
  {
    "path": "LICENSE-MIT",
    "chars": 1057,
    "preview": "Copyright (c) 2014 Alex Crichton\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this s"
  },
  {
    "path": "README.md",
    "chars": 1543,
    "preview": "# ssh2-rs\n\n[![Build Status](https://github.com/alexcrichton/ssh2-rs/workflows/linux/badge.svg)](https://github.com/alexc"
  },
  {
    "path": "libssh2-sys/.gitattributes",
    "chars": 88,
    "preview": "# apparently libssh2 has trouble with CRLF, but of course only on windows\n* text eol=lf\n"
  },
  {
    "path": "libssh2-sys/Cargo.toml",
    "chars": 951,
    "preview": "[package]\nname = \"libssh2-sys\"\nversion = \"0.3.1\"\nauthors = [\"Alex Crichton <alex@alexcrichton.com>\", \"Wez Furlong <wez@w"
  },
  {
    "path": "libssh2-sys/LICENSE-APACHE",
    "chars": 10847,
    "preview": "                              Apache License\n                        Version 2.0, January 2004\n                     http"
  },
  {
    "path": "libssh2-sys/LICENSE-MIT",
    "chars": 1057,
    "preview": "Copyright (c) 2014 Alex Crichton\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this s"
  },
  {
    "path": "libssh2-sys/build.rs",
    "chars": 8254,
    "preview": "extern crate cc;\nextern crate pkg_config;\n\n#[cfg(target_env = \"msvc\")]\nextern crate vcpkg;\n\nuse std::env;\nuse std::fs;\nu"
  },
  {
    "path": "libssh2-sys/lib.rs",
    "chars": 28392,
    "preview": "#![doc(html_root_url = \"http://alexcrichton.com/ssh2-rs\")]\n#![allow(bad_style)]\n#![allow(unused_extern_crates)]\n\nextern "
  },
  {
    "path": "src/agent.rs",
    "chars": 4879,
    "preview": "use parking_lot::{Mutex, MutexGuard};\nuse std::ffi::{CStr, CString};\nuse std::ptr::null_mut;\nuse std::slice;\nuse std::st"
  },
  {
    "path": "src/channel.rs",
    "chars": 20349,
    "preview": "use libc::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void, size_t};\nuse parking_lot::{Mutex, MutexGuard};\nuse std::cmp;"
  },
  {
    "path": "src/error.rs",
    "chars": 10966,
    "preview": "use libc;\nuse std::borrow::Cow;\nuse std::error;\nuse std::ffi::NulError;\nuse std::fmt;\nuse std::io;\nuse std::ptr::null_mu"
  },
  {
    "path": "src/knownhosts.rs",
    "chars": 10694,
    "preview": "use libc::{c_int, size_t};\nuse parking_lot::{Mutex, MutexGuard};\nuse std::ffi::CString;\nuse std::path::Path;\nuse std::pt"
  },
  {
    "path": "src/lib.rs",
    "chars": 19877,
    "preview": "//! Rust bindings to libssh2, an SSH client library.\n//!\n//! This library intends to provide a safe interface to the lib"
  },
  {
    "path": "src/listener.rs",
    "chars": 1570,
    "preview": "use parking_lot::Mutex;\nuse std::sync::Arc;\nuse {raw, Channel, Error, SessionInner};\n\n/// A listener represents a forwar"
  },
  {
    "path": "src/session.rs",
    "chars": 45449,
    "preview": "// Usings for openssl function userauth_pubkey_memory()\n#[cfg(any(unix, feature = \"vendored-openssl\", feature = \"openssl"
  },
  {
    "path": "src/sftp.rs",
    "chars": 33613,
    "preview": "use libc::{c_int, c_long, c_uint, c_ulong, size_t};\nuse parking_lot::{Mutex, MutexGuard};\nuse std::convert::TryFrom;\nuse"
  },
  {
    "path": "src/util.rs",
    "chars": 1333,
    "preview": "use std::borrow::Cow;\nuse std::path::Path;\n\nuse {raw, Error, ErrorCode};\n\n#[cfg(unix)]\npub fn path2bytes(p: &Path) -> Re"
  },
  {
    "path": "systest/Cargo.toml",
    "chars": 224,
    "preview": "[package]\nname = \"systest\"\nversion = \"0.1.0\"\nauthors = [\"Alex Crichton <alex@alexcrichton.com>\"]\nbuild = \"build.rs\"\n\n[de"
  },
  {
    "path": "systest/build.rs",
    "chars": 1340,
    "preview": "extern crate ctest2;\n\nuse std::env;\n\nfn main() {\n    let mut cfg = ctest2::TestGenerator::new();\n    cfg.header(\"libssh2"
  },
  {
    "path": "systest/src/main.rs",
    "chars": 166,
    "preview": "#![allow(bad_style, improper_ctypes)]\n\nextern crate libc;\nextern crate libssh2_sys;\n\nuse libc::*;\nuse libssh2_sys::*;\n\ni"
  },
  {
    "path": "tests/all/agent.rs",
    "chars": 362,
    "preview": "use ssh2::Session;\n\n#[test]\nfn smoke() {\n    let sess = Session::new().unwrap();\n    let mut agent = sess.agent().unwrap"
  },
  {
    "path": "tests/all/channel.rs",
    "chars": 8497,
    "preview": "use ssh2::Channel;\nuse std::io::prelude::*;\nuse std::net::{TcpListener, TcpStream};\nuse std::thread;\n\n/// Consume all av"
  },
  {
    "path": "tests/all/knownhosts.rs",
    "chars": 1749,
    "preview": "use ssh2::{KnownHostFileKind, Session};\n\n#[test]\nfn smoke() {\n    let sess = Session::new().unwrap();\n    let known_host"
  },
  {
    "path": "tests/all/main.rs",
    "chars": 1035,
    "preview": "#![deny(warnings)]\n\nextern crate ssh2;\nextern crate tempfile;\n\nuse std::env;\nuse std::net::TcpStream;\n\nmod agent;\nmod ch"
  },
  {
    "path": "tests/all/session.rs",
    "chars": 6303,
    "preview": "use std::env;\nuse std::fs::File;\nuse std::io::{self, prelude::*};\nuse std::path::Path;\nuse tempfile::TempDir;\n\nuse ssh2:"
  },
  {
    "path": "tests/all/sftp.rs",
    "chars": 2761,
    "preview": "use std::fs::{self, File};\nuse std::io::prelude::*;\nuse tempfile::TempDir;\n\n#[test]\nfn smoke() {\n    let sess = ::authed"
  },
  {
    "path": "tests/run_integration_tests.sh",
    "chars": 1547,
    "preview": "#!/bin/bash\nset -e\nset -x\n\n# This script spawns an ssh daemon with a known configuration so that we can\n# test various f"
  }
]

About this extraction

This page contains the full source code of the alexcrichton/ssh2-rs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (234.0 KB), approximately 60.7k tokens, and a symbol index with 584 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!