Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/inotify/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/inotify/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"d0584f914aebf070e1be3ca96ef065b94f3234b13e7dcceec93249d8943db067","CONTRIBUTING.md":"63ec0b71cb5acafb22a3edbd1232d8886ed531544b241d956ca284e4163a05fc","Cargo.lock":"c7bbe32ee961e85c7695ed83d80408c14c91748710d857c724a807c1b34f29ee","Cargo.toml":"a3c3ebabfa79a6cf46009630a61911e94964d492cc4208366f49cbc365042d8f","LICENSE":"7f78b31de4e7a3e2ac8de40e2b409eda313f03637aa62b8416fbde9bdc5ce4c9","README.md":"1ea282e675f038a96381e6c77d2968e0a3850342f4155f8b6e2262a8f74a74b2","examples/stream.rs":"38732ec68508a8da91e27efb1f042228544b68744cc565a33a63afdb84b76689","examples/watch.rs":"4a7d222e6579b0ecaf9a9713f469a0d81bacbf294bdc88af657dfd1fd24cee21","src/events.rs":"c3e7e203aa6bf1cfab0865e629f69092e2dcfae97cd2c0ac76c69c04dcf006f5","src/fd_guard.rs":"40ce706cd2eecae278680512796c4b2890c6bd23c565d0ae06adca47ca1589a7","src/inotify.rs":"8843d08098d8ed85513c625be07dcadaf4de27eb7aaf2dec930d2d22efaa0c93","src/lib.rs":"3aca05bbd217d18a6f3b995e9d6e112b5e6dad5327f32058f60cc26f62005aea","src/stream.rs":"6bca1ae58003b3e5643bef13b0b1eb214c9027d9935ac7aacce0861cd24314d1","src/util.rs":"17d21c40a447181f5fb10646cb3e9bc996f93c6f50167db9a8e14086e9ea904d","src/watches.rs":"07e1a61eacb2dade17bc3de09d82f0cc453b7a36062b865916634145278ddb3f","tests/main.rs":"7914fb0d6a5e0991d47b77132744a90b5aa1bf20174df14da9c6395d1340b1e1"},"package":"f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"}
|
||||
141
third-party/vendor/inotify/CHANGELOG.md
vendored
Normal file
141
third-party/vendor/inotify/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
### v0.9.6 (2021-10-07)
|
||||
|
||||
- Fix build status badge in README ([#185])
|
||||
- Add `get_buffer_size`/`get_absolute_path_buffer_size` ([#187])
|
||||
|
||||
[#185]: https://github.com/hannobraun/inotify-rs/pull/185
|
||||
[#187]: https://github.com/hannobraun/inotify-rs/pull/187
|
||||
|
||||
|
||||
### v0.9.5 (2021-10-07)
|
||||
|
||||
- Implement `Ord`/`PartialOrd` for `WatchDescriptor` ([#183])
|
||||
|
||||
[#183]: https://github.com/hannobraun/inotify-rs/pull/183
|
||||
|
||||
|
||||
### v0.9.4 (2021-09-22)
|
||||
|
||||
- Make `Event::into_owned` always available ([#179])
|
||||
- Implement missing `Debug` implementations ([#180])
|
||||
|
||||
[#179]: https://github.com/hannobraun/inotify-rs/pull/179
|
||||
[#180]: https://github.com/hannobraun/inotify-rs/pull/180
|
||||
|
||||
|
||||
### v0.9.3 (2021-05-12)
|
||||
|
||||
- Improve documentation ([#167], [#169])
|
||||
- Add missing check for invalid file descriptor ([#168])
|
||||
- Fix unsound use of buffers due to misalignment ([#171])
|
||||
- Add missing error checks ([#173])
|
||||
|
||||
[#167]: https://github.com/hannobraun/inotify-rs/pull/167
|
||||
[#168]: https://github.com/hannobraun/inotify-rs/pull/168
|
||||
[#169]: https://github.com/hannobraun/inotify-rs/pull/169
|
||||
[#171]: https://github.com/hannobraun/inotify-rs/pull/171
|
||||
[#173]: https://github.com/hannobraun/inotify-rs/pull/173
|
||||
|
||||
|
||||
### v0.9.2 (2020-12-30)
|
||||
|
||||
- Upgrade to Tokio 1.0 ([#165])
|
||||
|
||||
[#165]: https://github.com/hannobraun/inotify/pull/165
|
||||
|
||||
|
||||
<a name="v0.9.1"></a>
|
||||
### v0.9.1 (2020-11-09)
|
||||
|
||||
- Fix take wake-up ([#161])
|
||||
|
||||
[#161]: https://github.com/hannobraun/inotify/pull/161
|
||||
|
||||
|
||||
<a name="v0.9.0"></a>
|
||||
### v0.9.0 (2020-11-06)
|
||||
|
||||
- Update minimum supported Rust version to version 1.47 ([#154])
|
||||
- Fix documentation: `Inotify::read_events` doesn't handle all events ([#157])
|
||||
- Update to tokio 0.3 ([#158])
|
||||
|
||||
[#154]: https://github.com/hannobraun/inotify/pull/154
|
||||
[#157]: https://github.com/hannobraun/inotify/pull/157
|
||||
[#158]: https://github.com/hannobraun/inotify/pull/158
|
||||
|
||||
|
||||
<a name="v0.8.3"></a>
|
||||
### v0.8.3 (2020-06-05)
|
||||
|
||||
- Avoid using `inotify_init1` ([#146])
|
||||
|
||||
[#146]: https://github.com/hannobraun/inotify/pull/146
|
||||
|
||||
|
||||
<a name="v0.8.2"></a>
|
||||
### v0.8.2 (2020-01-25)
|
||||
|
||||
- Ensure file descriptor is closed on drop ([#140])
|
||||
|
||||
[#140]: https://github.com/inotify-rs/inotify/pull/140
|
||||
|
||||
|
||||
<a name="v0.8.1"></a>
|
||||
### v0.8.1 (2020-01-23)
|
||||
|
||||
No changes, due to a mistake made while releasing this version.
|
||||
|
||||
|
||||
<a name="v0.8.0"></a>
|
||||
### v0.8.0 (2019-12-04)
|
||||
|
||||
- Update to tokio 0.2 and futures 0.3 ([#134])
|
||||
|
||||
[#134]: https://github.com/inotify-rs/inotify/pull/134
|
||||
|
||||
|
||||
<a name="v0.7.1"></a>
|
||||
### v0.7.1 (2020-06-05)
|
||||
|
||||
- backport: Avoid using `inotify_init1` ([#146])
|
||||
|
||||
[#146]: https://github.com/hannobraun/inotify/pull/146
|
||||
|
||||
|
||||
<a name="v0.7.0"></a>
|
||||
### v0.7.0 (2019-02-09)
|
||||
|
||||
#### Features
|
||||
|
||||
* Make stream API more flexible in regards to buffers ([ea3e7a394bf34a6ccce4f2136c0991fe7e8f1f42](ea3e7a394bf34a6ccce4f2136c0991fe7e8f1f42)) (breaking change)
|
||||
|
||||
<a name="v0.6.1"></a>
|
||||
### v0.6.1 (2018-08-28)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Don't return spurious filenames ([2f37560f](2f37560f))
|
||||
|
||||
|
||||
|
||||
<a name="v0.6.0"></a>
|
||||
## v0.6.0 (2018-08-16)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Handle closing of inotify instance better ([824160fe](824160fe))
|
||||
* Implement `EventStream` using `mio` ([ba4cb8c7](ba4cb8c7))
|
||||
|
||||
|
||||
|
||||
<a name="v0.5.1"></a>
|
||||
### v0.5.1 (2018-02-27)
|
||||
|
||||
#### Features
|
||||
|
||||
* Add future-based async API ([569e65a7](569e65a7), closes [#49](49))
|
||||
|
||||
|
||||
|
||||
25
third-party/vendor/inotify/CONTRIBUTING.md
vendored
Normal file
25
third-party/vendor/inotify/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Contributing to inotify-rs
|
||||
|
||||
Thank you for considering to work on inotify-rs. We're always happy to see outside contributions, small or large.
|
||||
|
||||
You probably found this document in the repository of either the [inotify] or [inotify-sys] crate. Both are part of the same project, so this guide is valid for both (in fact, the documents in either repository should be identical).
|
||||
|
||||
## Opening issues
|
||||
|
||||
If you found a problem with inotify-rs, please open an issue to let us know. If you're not sure whether you found a problem or not, just open an issue anyway. We'd rather close a few invalid issues than miss real problems.
|
||||
|
||||
Issues are tracked on GitHub, in the repository for the respective crate:
|
||||
- [Open an inotify issue](https://github.com/inotify-rs/inotify/issues/new)
|
||||
- [Open an inotify-sys issue](https://github.com/inotify-rs/inotify-sys/issues/new)
|
||||
|
||||
If you're unsure where to open your issue, just open it in the [inotify] repository.
|
||||
|
||||
## Contributing changes
|
||||
|
||||
If you want to make a change to the inotify-rs code, please open a pull request on the respective repository. The best way to open a pull request is usually to just push a branch to your fork, and click the button that should appear near the top of your fork's GitHub page.
|
||||
|
||||
If you're having any problems with completing your change, feel free to open a pull request anyway and ask any questions there. We're happy to help with getting changes across the finish line.
|
||||
|
||||
|
||||
[inotify]: https://github.com/hannobraun/inotify
|
||||
[inotify-sys]: https://github.com/hannobraun/inotify-sys
|
||||
357
third-party/vendor/inotify/Cargo.lock
generated
vendored
Normal file
357
third-party/vendor/inotify/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"ntapi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
66
third-party/vendor/inotify/Cargo.toml
vendored
Normal file
66
third-party/vendor/inotify/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
authors = ["Hanno Braun <mail@hannobraun.de>", "Félix Saparelli <me@passcod.name>", "Cristian Kubis <cristian.kubis@tsunix.de>", "Frank Denis <github@pureftpd.org>"]
|
||||
exclude = ["/.travis.yml", "/inotify-rs.sublime-project"]
|
||||
description = "Idiomatic wrapper for inotify"
|
||||
documentation = "https://docs.rs/inotify"
|
||||
readme = "README.md"
|
||||
keywords = ["inotify", "linux"]
|
||||
categories = ["api-bindings", "filesystem"]
|
||||
license = "ISC"
|
||||
repository = "https://github.com/hannobraun/inotify"
|
||||
|
||||
[[example]]
|
||||
name = "stream"
|
||||
required-features = ["stream"]
|
||||
|
||||
[[example]]
|
||||
name = "watch"
|
||||
[dependencies.bitflags]
|
||||
version = "1"
|
||||
|
||||
[dependencies.futures-core]
|
||||
version = "0.3.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.inotify-sys]
|
||||
version = "0.1.3"
|
||||
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.0.1"
|
||||
features = ["net"]
|
||||
optional = true
|
||||
[dev-dependencies.futures-util]
|
||||
version = "0.3.1"
|
||||
|
||||
[dev-dependencies.tempfile]
|
||||
version = "3.1.0"
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "1.0.1"
|
||||
features = ["macros", "rt-multi-thread"]
|
||||
|
||||
[features]
|
||||
default = ["stream"]
|
||||
stream = ["futures-core", "tokio"]
|
||||
[badges.maintenance]
|
||||
status = "actively-developed"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "inotify-rs/inotify"
|
||||
13
third-party/vendor/inotify/LICENSE
vendored
Normal file
13
third-party/vendor/inotify/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) Hanno Braun and contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
115
third-party/vendor/inotify/README.md
vendored
Normal file
115
third-party/vendor/inotify/README.md
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# inotify-rs [](https://crates.io/crates/inotify) [](https://docs.rs/inotify) [](https://github.com/hannobraun/inotify-rs/actions/workflows/rust.yml)
|
||||
|
||||
Idiomatic [inotify] wrapper for the [Rust programming language].
|
||||
|
||||
```Rust
|
||||
extern crate inotify;
|
||||
|
||||
|
||||
use std::env;
|
||||
|
||||
use inotify::{
|
||||
EventMask,
|
||||
WatchMask,
|
||||
Inotify,
|
||||
};
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut inotify = Inotify::init()
|
||||
.expect("Failed to initialize inotify");
|
||||
|
||||
let current_dir = env::current_dir()
|
||||
.expect("Failed to determine current directory");
|
||||
|
||||
inotify
|
||||
.add_watch(
|
||||
current_dir,
|
||||
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE,
|
||||
)
|
||||
.expect("Failed to add inotify watch");
|
||||
|
||||
println!("Watching current directory for activity...");
|
||||
|
||||
let mut buffer = [0u8; 4096];
|
||||
loop {
|
||||
let events = inotify
|
||||
.read_events_blocking(&mut buffer)
|
||||
.expect("Failed to read inotify events");
|
||||
|
||||
for event in events {
|
||||
if event.mask.contains(EventMask::CREATE) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory created: {:?}", event.name);
|
||||
} else {
|
||||
println!("File created: {:?}", event.name);
|
||||
}
|
||||
} else if event.mask.contains(EventMask::DELETE) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory deleted: {:?}", event.name);
|
||||
} else {
|
||||
println!("File deleted: {:?}", event.name);
|
||||
}
|
||||
} else if event.mask.contains(EventMask::MODIFY) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory modified: {:?}", event.name);
|
||||
} else {
|
||||
println!("File modified: {:?}", event.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Include it in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
inotify = "0.9"
|
||||
```
|
||||
|
||||
Please refer to the [documentation] and the example above, for information on how to use it in your code.
|
||||
|
||||
Please note that inotify-rs is a relatively low-level wrapper around the original inotify API. And, of course, it is Linux-specific, just like inotify itself. If you are looking for a higher-level and platform-independent file system notification library, please consider [notify].
|
||||
|
||||
If you need to access inotify in a way that this wrapper doesn't support, consider using [inotify-sys] instead.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
The most important piece of documentation for inotify-rs is the **[API reference]**, as it contains a thorough description of the complete API, as well as examples.
|
||||
|
||||
Additional examples can be found in the **[examples directory]**.
|
||||
|
||||
Please also make sure to read the **[inotify man page]**. Inotify use can be hard to get right, and this low-level wrapper won't protect you from all mistakes.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Hanno Braun and contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
|
||||
[inotify]: http://en.wikipedia.org/wiki/Inotify
|
||||
[Rust programming language]: http://rust-lang.org/
|
||||
[documentation]: https://docs.rs/inotify
|
||||
[notify]: https://crates.io/crates/notify
|
||||
[inotify-sys]: https://crates.io/crates/inotify-sys
|
||||
[API reference]: https://docs.rs/inotify
|
||||
[examples directory]: https://github.com/inotify-rs/inotify/tree/master/examples
|
||||
[inotify man page]: http://man7.org/linux/man-pages/man7/inotify.7.html
|
||||
39
third-party/vendor/inotify/examples/stream.rs
vendored
Normal file
39
third-party/vendor/inotify/examples/stream.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures_util::StreamExt;
|
||||
use inotify::{
|
||||
Inotify,
|
||||
WatchMask,
|
||||
};
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), io::Error> {
|
||||
let mut inotify = Inotify::init()
|
||||
.expect("Failed to initialize inotify");
|
||||
|
||||
let dir = TempDir::new()?;
|
||||
|
||||
inotify.add_watch(dir.path(), WatchMask::CREATE | WatchMask::MODIFY)?;
|
||||
|
||||
thread::spawn::<_, Result<(), io::Error>>(move || {
|
||||
loop {
|
||||
File::create(dir.path().join("file"))?;
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
});
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
let mut stream = inotify.event_stream(&mut buffer)?;
|
||||
|
||||
while let Some(event_or_error) = stream.next().await {
|
||||
println!("event: {:?}", event_or_error?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
54
third-party/vendor/inotify/examples/watch.rs
vendored
Normal file
54
third-party/vendor/inotify/examples/watch.rs
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use std::env;
|
||||
|
||||
use inotify::{
|
||||
EventMask,
|
||||
Inotify,
|
||||
WatchMask,
|
||||
};
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut inotify = Inotify::init()
|
||||
.expect("Failed to initialize inotify");
|
||||
|
||||
let current_dir = env::current_dir()
|
||||
.expect("Failed to determine current directory");
|
||||
|
||||
inotify
|
||||
.add_watch(
|
||||
current_dir,
|
||||
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE,
|
||||
)
|
||||
.expect("Failed to add inotify watch");
|
||||
|
||||
println!("Watching current directory for activity...");
|
||||
|
||||
let mut buffer = [0u8; 4096];
|
||||
loop {
|
||||
let events = inotify
|
||||
.read_events_blocking(&mut buffer)
|
||||
.expect("Failed to read inotify events");
|
||||
|
||||
for event in events {
|
||||
if event.mask.contains(EventMask::CREATE) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory created: {:?}", event.name);
|
||||
} else {
|
||||
println!("File created: {:?}", event.name);
|
||||
}
|
||||
} else if event.mask.contains(EventMask::DELETE) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory deleted: {:?}", event.name);
|
||||
} else {
|
||||
println!("File deleted: {:?}", event.name);
|
||||
}
|
||||
} else if event.mask.contains(EventMask::MODIFY) {
|
||||
if event.mask.contains(EventMask::ISDIR) {
|
||||
println!("Directory modified: {:?}", event.name);
|
||||
} else {
|
||||
println!("File modified: {:?}", event.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
445
third-party/vendor/inotify/src/events.rs
vendored
Normal file
445
third-party/vendor/inotify/src/events.rs
vendored
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
use std::{
|
||||
ffi::{
|
||||
OsStr,
|
||||
OsString,
|
||||
},
|
||||
mem,
|
||||
os::unix::ffi::OsStrExt,
|
||||
sync::Weak,
|
||||
};
|
||||
|
||||
use inotify_sys as ffi;
|
||||
|
||||
use crate::fd_guard::FdGuard;
|
||||
use crate::watches::WatchDescriptor;
|
||||
use crate::util::align_buffer;
|
||||
|
||||
|
||||
/// Iterator over inotify events
|
||||
///
|
||||
/// Allows for iteration over the events returned by
|
||||
/// [`Inotify::read_events_blocking`] or [`Inotify::read_events`].
|
||||
///
|
||||
/// [`Inotify::read_events_blocking`]: struct.Inotify.html#method.read_events_blocking
|
||||
/// [`Inotify::read_events`]: struct.Inotify.html#method.read_events
|
||||
#[derive(Debug)]
|
||||
pub struct Events<'a> {
|
||||
fd : Weak<FdGuard>,
|
||||
buffer : &'a [u8],
|
||||
num_bytes: usize,
|
||||
pos : usize,
|
||||
}
|
||||
|
||||
impl<'a> Events<'a> {
|
||||
pub(crate) fn new(fd: Weak<FdGuard>, buffer: &'a [u8], num_bytes: usize)
|
||||
-> Self
|
||||
{
|
||||
Events {
|
||||
fd : fd,
|
||||
buffer : buffer,
|
||||
num_bytes: num_bytes,
|
||||
pos : 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Events<'a> {
|
||||
type Item = Event<&'a OsStr>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pos < self.num_bytes {
|
||||
let (step, event) = Event::from_buffer(self.fd.clone(), &self.buffer[self.pos..]);
|
||||
self.pos += step;
|
||||
|
||||
Some(event)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An inotify event
|
||||
///
|
||||
/// A file system event that describes a change that the user previously
|
||||
/// registered interest in. To watch for events, call [`Inotify::add_watch`]. To
|
||||
/// retrieve events, call [`Inotify::read_events_blocking`] or
|
||||
/// [`Inotify::read_events`].
|
||||
///
|
||||
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
|
||||
/// [`Inotify::read_events_blocking`]: struct.Inotify.html#method.read_events_blocking
|
||||
/// [`Inotify::read_events`]: struct.Inotify.html#method.read_events
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Event<S> {
|
||||
/// Identifies the watch this event originates from
|
||||
///
|
||||
/// This [`WatchDescriptor`] is equal to the one that [`Inotify::add_watch`]
|
||||
/// returned when interest for this event was registered. The
|
||||
/// [`WatchDescriptor`] can be used to remove the watch using
|
||||
/// [`Inotify::rm_watch`], thereby preventing future events of this type
|
||||
/// from being created.
|
||||
///
|
||||
/// [`WatchDescriptor`]: struct.WatchDescriptor.html
|
||||
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
|
||||
/// [`Inotify::rm_watch`]: struct.Inotify.html#method.rm_watch
|
||||
pub wd: WatchDescriptor,
|
||||
|
||||
/// Indicates what kind of event this is
|
||||
pub mask: EventMask,
|
||||
|
||||
/// Connects related events to each other
|
||||
///
|
||||
/// When a file is renamed, this results two events: [`MOVED_FROM`] and
|
||||
/// [`MOVED_TO`]. The `cookie` field will be the same for both of them,
|
||||
/// thereby making is possible to connect the event pair.
|
||||
///
|
||||
/// [`MOVED_FROM`]: event_mask/constant.MOVED_FROM.html
|
||||
/// [`MOVED_TO`]: event_mask/constant.MOVED_TO.html
|
||||
pub cookie: u32,
|
||||
|
||||
/// The name of the file the event originates from
|
||||
///
|
||||
/// This field is set only if the subject of the event is a file or directory in a
|
||||
/// watched directory. If the event concerns a file or directory that is
|
||||
/// watched directly, `name` will be `None`.
|
||||
pub name: Option<S>,
|
||||
}
|
||||
|
||||
impl<'a> Event<&'a OsStr> {
|
||||
fn new(fd: Weak<FdGuard>, event: &ffi::inotify_event, name: &'a OsStr)
|
||||
-> Self
|
||||
{
|
||||
let mask = EventMask::from_bits(event.mask)
|
||||
.expect("Failed to convert event mask. This indicates a bug.");
|
||||
|
||||
let wd = crate::WatchDescriptor {
|
||||
id: event.wd,
|
||||
fd,
|
||||
};
|
||||
|
||||
let name = if name == "" {
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some(name)
|
||||
};
|
||||
|
||||
Event {
|
||||
wd,
|
||||
mask,
|
||||
cookie: event.cookie,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an `Event` from a buffer
|
||||
///
|
||||
/// Assumes that a full `inotify_event` plus its name is located at the
|
||||
/// beginning of `buffer`.
|
||||
///
|
||||
/// Returns the number of bytes used from the buffer, and the event.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the buffer does not contain a full event, including its name.
|
||||
pub(crate) fn from_buffer(
|
||||
fd : Weak<FdGuard>,
|
||||
buffer: &'a [u8],
|
||||
)
|
||||
-> (usize, Self)
|
||||
{
|
||||
let event_size = mem::size_of::<ffi::inotify_event>();
|
||||
let event_align = mem::align_of::<ffi::inotify_event>();
|
||||
|
||||
// Make sure that the buffer can satisfy the alignment requirements for `inotify_event`
|
||||
assert!(buffer.len() >= event_align);
|
||||
|
||||
// Discard the unaligned portion, if any, of the supplied buffer
|
||||
let buffer = align_buffer(buffer);
|
||||
|
||||
// Make sure that the aligned buffer is big enough to contain an event, without
|
||||
// the name. Otherwise we can't safely convert it to an `inotify_event`.
|
||||
assert!(buffer.len() >= event_size);
|
||||
|
||||
|
||||
let event = buffer.as_ptr() as *const ffi::inotify_event;
|
||||
|
||||
// We have a pointer to an `inotify_event`, pointing to the beginning of
|
||||
// `buffer`. Since we know, as per the assertion above, that there are
|
||||
// enough bytes in the buffer for at least one event, we can safely
|
||||
// convert that pointer into a reference.
|
||||
let event = unsafe { &*event };
|
||||
|
||||
// The name's length is given by `event.len`. There should always be
|
||||
// enough bytes left in the buffer to fit the name. Let's make sure that
|
||||
// is the case.
|
||||
let bytes_left_in_buffer = buffer.len() - event_size;
|
||||
assert!(bytes_left_in_buffer >= event.len as usize);
|
||||
|
||||
// Directly after the event struct should be a name, if there's one
|
||||
// associated with the event. Let's make a new slice that starts with
|
||||
// that name. If there's no name, this slice might have a length of `0`.
|
||||
let bytes_consumed = event_size + event.len as usize;
|
||||
let name = &buffer[event_size..bytes_consumed];
|
||||
|
||||
// Remove trailing '\0' bytes
|
||||
//
|
||||
// The events in the buffer are aligned, and `name` is filled up
|
||||
// with '\0' up to the alignment boundary. Here we remove those
|
||||
// additional bytes.
|
||||
//
|
||||
// The `unwrap` here is safe, because `splitn` always returns at
|
||||
// least one result, even if the original slice contains no '\0'.
|
||||
let name = name
|
||||
.splitn(2, |b| b == &0u8)
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let event = Event::new(
|
||||
fd,
|
||||
event,
|
||||
OsStr::from_bytes(name),
|
||||
);
|
||||
|
||||
(bytes_consumed, event)
|
||||
}
|
||||
|
||||
/// Returns an owned copy of the event.
|
||||
#[must_use = "cloning is often expensive and is not expected to have side effects"]
|
||||
pub fn into_owned(&self) -> EventOwned {
|
||||
Event {
|
||||
wd: self.wd.clone(),
|
||||
mask: self.mask,
|
||||
cookie: self.cookie,
|
||||
name: self.name.map(OsStr::to_os_string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An owned version of `Event`
|
||||
pub type EventOwned = Event<OsString>;
|
||||
|
||||
|
||||
bitflags! {
|
||||
/// Indicates the type of an event
|
||||
///
|
||||
/// This struct can be retrieved from an [`Event`] via its `mask` field.
|
||||
/// You can determine the [`Event`]'s type by comparing the `EventMask` to
|
||||
/// its associated constants.
|
||||
///
|
||||
/// Please refer to the documentation of [`Event`] for a usage example.
|
||||
///
|
||||
/// [`Event`]: struct.Event.html
|
||||
pub struct EventMask: u32 {
|
||||
/// File was accessed
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_ACCESS`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ACCESS`]: ../inotify_sys/constant.IN_ACCESS.html
|
||||
const ACCESS = ffi::IN_ACCESS;
|
||||
|
||||
/// Metadata (permissions, timestamps, ...) changed
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_ATTRIB`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ATTRIB`]: ../inotify_sys/constant.IN_ATTRIB.html
|
||||
const ATTRIB = ffi::IN_ATTRIB;
|
||||
|
||||
/// File opened for writing was closed
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CLOSE_WRITE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CLOSE_WRITE`]: ../inotify_sys/constant.IN_CLOSE_WRITE.html
|
||||
const CLOSE_WRITE = ffi::IN_CLOSE_WRITE;
|
||||
|
||||
/// File or directory not opened for writing was closed
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CLOSE_NOWRITE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CLOSE_NOWRITE`]: ../inotify_sys/constant.IN_CLOSE_NOWRITE.html
|
||||
const CLOSE_NOWRITE = ffi::IN_CLOSE_NOWRITE;
|
||||
|
||||
/// File/directory created in watched directory
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CREATE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CREATE`]: ../inotify_sys/constant.IN_CREATE.html
|
||||
const CREATE = ffi::IN_CREATE;
|
||||
|
||||
/// File/directory deleted from watched directory
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_DELETE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_DELETE`]: ../inotify_sys/constant.IN_DELETE.html
|
||||
const DELETE = ffi::IN_DELETE;
|
||||
|
||||
/// Watched file/directory was deleted
|
||||
///
|
||||
/// See [`inotify_sys::IN_DELETE_SELF`].
|
||||
///
|
||||
/// [`inotify_sys::IN_DELETE_SELF`]: ../inotify_sys/constant.IN_DELETE_SELF.html
|
||||
const DELETE_SELF = ffi::IN_DELETE_SELF;
|
||||
|
||||
/// File was modified
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MODIFY`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MODIFY`]: ../inotify_sys/constant.IN_MODIFY.html
|
||||
const MODIFY = ffi::IN_MODIFY;
|
||||
|
||||
/// Watched file/directory was moved
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVE_SELF`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVE_SELF`]: ../inotify_sys/constant.IN_MOVE_SELF.html
|
||||
const MOVE_SELF = ffi::IN_MOVE_SELF;
|
||||
|
||||
/// File was renamed/moved; watched directory contained old name
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVED_FROM`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVED_FROM`]: ../inotify_sys/constant.IN_MOVED_FROM.html
|
||||
const MOVED_FROM = ffi::IN_MOVED_FROM;
|
||||
|
||||
/// File was renamed/moved; watched directory contains new name
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVED_TO`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVED_TO`]: ../inotify_sys/constant.IN_MOVED_TO.html
|
||||
const MOVED_TO = ffi::IN_MOVED_TO;
|
||||
|
||||
/// File or directory was opened
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_OPEN`].
|
||||
///
|
||||
/// [`inotify_sys::IN_OPEN`]: ../inotify_sys/constant.IN_OPEN.html
|
||||
const OPEN = ffi::IN_OPEN;
|
||||
|
||||
/// Watch was removed
|
||||
///
|
||||
/// This event will be generated, if the watch was removed explicitly
|
||||
/// (via [`Inotify::rm_watch`]), or automatically (because the file was
|
||||
/// deleted or the file system was unmounted).
|
||||
///
|
||||
/// See [`inotify_sys::IN_IGNORED`].
|
||||
///
|
||||
/// [`inotify_sys::IN_IGNORED`]: ../inotify_sys/constant.IN_IGNORED.html
|
||||
const IGNORED = ffi::IN_IGNORED;
|
||||
|
||||
/// Event related to a directory
|
||||
///
|
||||
/// The subject of the event is a directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_ISDIR`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ISDIR`]: ../inotify_sys/constant.IN_ISDIR.html
|
||||
const ISDIR = ffi::IN_ISDIR;
|
||||
|
||||
/// Event queue overflowed
|
||||
///
|
||||
/// The event queue has overflowed and events have presumably been lost.
|
||||
///
|
||||
/// See [`inotify_sys::IN_Q_OVERFLOW`].
|
||||
///
|
||||
/// [`inotify_sys::IN_Q_OVERFLOW`]: ../inotify_sys/constant.IN_Q_OVERFLOW.html
|
||||
const Q_OVERFLOW = ffi::IN_Q_OVERFLOW;
|
||||
|
||||
/// File system containing watched object was unmounted.
|
||||
/// File system was unmounted
|
||||
///
|
||||
/// The file system that contained the watched object has been
|
||||
/// unmounted. An event with [`WatchMask::IGNORED`] will subsequently be
|
||||
/// generated for the same watch descriptor.
|
||||
///
|
||||
/// See [`inotify_sys::IN_UNMOUNT`].
|
||||
///
|
||||
/// [`WatchMask::IGNORED`]: #associatedconstant.IGNORED
|
||||
/// [`inotify_sys::IN_UNMOUNT`]: ../inotify_sys/constant.IN_UNMOUNT.html
|
||||
const UNMOUNT = ffi::IN_UNMOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{
|
||||
io::prelude::*,
|
||||
mem,
|
||||
slice,
|
||||
sync,
|
||||
};
|
||||
|
||||
use crate::util;
|
||||
|
||||
use inotify_sys as ffi;
|
||||
|
||||
use super::Event;
|
||||
|
||||
|
||||
#[test]
|
||||
fn from_buffer_should_not_mistake_next_event_for_name_of_previous_event() {
|
||||
let mut buffer = [0u8; 1024];
|
||||
|
||||
// Make sure the buffer is properly aligned before writing raw events into it
|
||||
let buffer = util::align_buffer_mut(&mut buffer);
|
||||
|
||||
// First, put a normal event into the buffer
|
||||
let event = ffi::inotify_event {
|
||||
wd: 0,
|
||||
mask: 0,
|
||||
cookie: 0,
|
||||
len: 0, // no name following after event
|
||||
};
|
||||
let event = unsafe {
|
||||
slice::from_raw_parts(
|
||||
&event as *const _ as *const u8,
|
||||
mem::size_of_val(&event),
|
||||
)
|
||||
};
|
||||
(&mut buffer[..]).write(event)
|
||||
.expect("Failed to write into buffer");
|
||||
|
||||
// After that event, simulate an event that starts with a non-zero byte.
|
||||
buffer[mem::size_of_val(&event)] = 1;
|
||||
|
||||
// Now create the event and verify that the name is actually `None`, as
|
||||
// dictated by the value `len` above.
|
||||
let (_, event) = Event::from_buffer(
|
||||
sync::Weak::new(),
|
||||
&buffer,
|
||||
);
|
||||
assert_eq!(event.name, None);
|
||||
}
|
||||
}
|
||||
84
third-party/vendor/inotify/src/fd_guard.rs
vendored
Normal file
84
third-party/vendor/inotify/src/fd_guard.rs
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use std::{
|
||||
ops::Deref,
|
||||
os::unix::io::{
|
||||
AsRawFd,
|
||||
FromRawFd,
|
||||
IntoRawFd,
|
||||
RawFd,
|
||||
},
|
||||
sync::atomic::{
|
||||
AtomicBool,
|
||||
Ordering,
|
||||
},
|
||||
};
|
||||
|
||||
use inotify_sys as ffi;
|
||||
|
||||
|
||||
/// A RAII guard around a `RawFd` that closes it automatically on drop.
|
||||
#[derive(Debug)]
|
||||
pub struct FdGuard {
|
||||
pub(crate) fd : RawFd,
|
||||
pub(crate) close_on_drop: AtomicBool,
|
||||
}
|
||||
|
||||
impl FdGuard {
|
||||
|
||||
/// Indicate that the wrapped file descriptor should _not_ be closed
|
||||
/// when the guard is dropped.
|
||||
///
|
||||
/// This should be called in cases where ownership of the wrapped file
|
||||
/// descriptor has been "moved" out of the guard.
|
||||
///
|
||||
/// This is factored out into a separate function to ensure that it's
|
||||
/// always used consistently.
|
||||
#[inline]
|
||||
pub fn should_not_close(&self) {
|
||||
self.close_on_drop.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for FdGuard {
|
||||
type Target = RawFd;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FdGuard {
|
||||
fn drop(&mut self) {
|
||||
if self.close_on_drop.load(Ordering::Acquire) {
|
||||
unsafe { ffi::close(self.fd); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for FdGuard {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
FdGuard {
|
||||
fd,
|
||||
close_on_drop: AtomicBool::new(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for FdGuard {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.should_not_close();
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for FdGuard {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FdGuard {
|
||||
fn eq(&self, other: &FdGuard) -> bool {
|
||||
self.fd == other.fd
|
||||
}
|
||||
}
|
||||
485
third-party/vendor/inotify/src/inotify.rs
vendored
Normal file
485
third-party/vendor/inotify/src/inotify.rs
vendored
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
use std::{
|
||||
ffi::CString,
|
||||
io,
|
||||
os::unix::ffi::OsStrExt,
|
||||
os::unix::io::{
|
||||
AsRawFd,
|
||||
FromRawFd,
|
||||
IntoRawFd,
|
||||
RawFd,
|
||||
},
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::AtomicBool,
|
||||
Arc,
|
||||
}
|
||||
};
|
||||
|
||||
use inotify_sys as ffi;
|
||||
use libc::{
|
||||
F_GETFL,
|
||||
F_SETFD,
|
||||
F_SETFL,
|
||||
FD_CLOEXEC,
|
||||
O_NONBLOCK,
|
||||
fcntl,
|
||||
};
|
||||
|
||||
use crate::events::Events;
|
||||
use crate::fd_guard::FdGuard;
|
||||
use crate::util::read_into_buffer;
|
||||
use crate::watches::{
|
||||
WatchDescriptor,
|
||||
WatchMask,
|
||||
};
|
||||
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
use crate::stream::EventStream;
|
||||
|
||||
|
||||
/// Idiomatic Rust wrapper around Linux's inotify API
|
||||
///
|
||||
/// `Inotify` is a wrapper around an inotify instance. It generally tries to
|
||||
/// adhere to the underlying inotify API closely, while making access to it
|
||||
/// safe and convenient.
|
||||
///
|
||||
/// Please refer to the [top-level documentation] for further details and a
|
||||
/// usage example.
|
||||
///
|
||||
/// [top-level documentation]: index.html
|
||||
#[derive(Debug)]
|
||||
pub struct Inotify {
|
||||
fd: Arc<FdGuard>,
|
||||
}
|
||||
|
||||
impl Inotify {
|
||||
/// Creates an [`Inotify`] instance
|
||||
///
|
||||
/// Initializes an inotify instance by calling [`inotify_init1`].
|
||||
///
|
||||
/// This method passes both flags accepted by [`inotify_init1`], not giving
|
||||
/// the user any choice in the matter, as not passing the flags would be
|
||||
/// inappropriate in the context of this wrapper:
|
||||
///
|
||||
/// - [`IN_CLOEXEC`] prevents leaking file descriptors to other processes.
|
||||
/// - [`IN_NONBLOCK`] controls the blocking behavior of the inotify API,
|
||||
/// which is entirely managed by this wrapper.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Directly returns the error from the call to [`inotify_init1`], without
|
||||
/// adding any error conditions of its own.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use inotify::Inotify;
|
||||
///
|
||||
/// let inotify = Inotify::init()
|
||||
/// .expect("Failed to initialize an inotify instance");
|
||||
/// ```
|
||||
///
|
||||
/// [`Inotify`]: struct.Inotify.html
|
||||
/// [`inotify_init1`]: ../inotify_sys/fn.inotify_init1.html
|
||||
/// [`IN_CLOEXEC`]: ../inotify_sys/constant.IN_CLOEXEC.html
|
||||
/// [`IN_NONBLOCK`]: ../inotify_sys/constant.IN_NONBLOCK.html
|
||||
pub fn init() -> io::Result<Inotify> {
|
||||
// Initialize inotify and set CLOEXEC and NONBLOCK flags.
|
||||
//
|
||||
// NONBLOCK is needed, because `Inotify` manages blocking behavior for
|
||||
// the API consumer, and the way we do that is to make everything non-
|
||||
// blocking by default and later override that as required.
|
||||
//
|
||||
// CLOEXEC prevents leaking file descriptors to processes executed by
|
||||
// this process and seems to be a best practice. I don't grasp this
|
||||
// issue completely and failed to find any authoritative sources on the
|
||||
// topic. There's some discussion in the open(2) and fcntl(2) man pages,
|
||||
// but I didn't find that helpful in understanding the issue of leaked
|
||||
// file descriptors. For what it's worth, there's a Rust issue about
|
||||
// this:
|
||||
// https://github.com/rust-lang/rust/issues/12148
|
||||
let fd = unsafe {
|
||||
let fd = ffi::inotify_init();
|
||||
if fd == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if fcntl(fd, F_SETFL, O_NONBLOCK) == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
fd
|
||||
};
|
||||
|
||||
Ok(Inotify {
|
||||
fd: Arc::new(FdGuard {
|
||||
fd,
|
||||
close_on_drop: AtomicBool::new(true),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds or updates a watch for the given path
|
||||
///
|
||||
/// Adds a new watch or updates an existing one for the file referred to by
|
||||
/// `path`. Returns a watch descriptor that can be used to refer to this
|
||||
/// watch later.
|
||||
///
|
||||
/// The `mask` argument defines what kind of changes the file should be
|
||||
/// watched for, and how to do that. See the documentation of [`WatchMask`]
|
||||
/// for details.
|
||||
///
|
||||
/// If this method is used to add a new watch, a new [`WatchDescriptor`] is
|
||||
/// returned. If it is used to update an existing watch, a
|
||||
/// [`WatchDescriptor`] that equals the previously returned
|
||||
/// [`WatchDescriptor`] for that watch is returned instead.
|
||||
///
|
||||
/// Under the hood, this method just calls [`inotify_add_watch`] and does
|
||||
/// some trivial translation between the types on the Rust side and the C
|
||||
/// side.
|
||||
///
|
||||
/// # Attention: Updating watches and hardlinks
|
||||
///
|
||||
/// As mentioned above, this method can be used to update an existing watch.
|
||||
/// This is usually done by calling this method with the same `path`
|
||||
/// argument that it has been called with before. But less obviously, it can
|
||||
/// also happen if the method is called with a different path that happens
|
||||
/// to link to the same inode.
|
||||
///
|
||||
/// You can detect this by keeping track of [`WatchDescriptor`]s and the
|
||||
/// paths they have been returned for. If the same [`WatchDescriptor`] is
|
||||
/// returned for a different path (and you haven't freed the
|
||||
/// [`WatchDescriptor`] by removing the watch), you know you have two paths
|
||||
/// pointing to the same inode, being watched by the same watch.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Directly returns the error from the call to
|
||||
/// [`inotify_add_watch`][`inotify_add_watch`] (translated into an
|
||||
/// `io::Error`), without adding any error conditions of
|
||||
/// its own.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use inotify::{
|
||||
/// Inotify,
|
||||
/// WatchMask,
|
||||
/// };
|
||||
///
|
||||
/// let mut inotify = Inotify::init()
|
||||
/// .expect("Failed to initialize an inotify instance");
|
||||
///
|
||||
/// # // Create a temporary file, so `add_watch` won't return an error.
|
||||
/// # use std::fs::File;
|
||||
/// # File::create("/tmp/inotify-rs-test-file")
|
||||
/// # .expect("Failed to create test file");
|
||||
/// #
|
||||
/// inotify.add_watch("/tmp/inotify-rs-test-file", WatchMask::MODIFY)
|
||||
/// .expect("Failed to add file watch");
|
||||
///
|
||||
/// // Handle events for the file here
|
||||
/// ```
|
||||
///
|
||||
/// [`inotify_add_watch`]: ../inotify_sys/fn.inotify_add_watch.html
|
||||
/// [`WatchMask`]: struct.WatchMask.html
|
||||
/// [`WatchDescriptor`]: struct.WatchDescriptor.html
|
||||
pub fn add_watch<P>(&mut self, path: P, mask: WatchMask)
|
||||
-> io::Result<WatchDescriptor>
|
||||
where P: AsRef<Path>
|
||||
{
|
||||
let path = CString::new(path.as_ref().as_os_str().as_bytes())?;
|
||||
|
||||
let wd = unsafe {
|
||||
ffi::inotify_add_watch(
|
||||
**self.fd,
|
||||
path.as_ptr() as *const _,
|
||||
mask.bits(),
|
||||
)
|
||||
};
|
||||
|
||||
match wd {
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(WatchDescriptor{ id: wd, fd: Arc::downgrade(&self.fd) }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stops watching a file
|
||||
///
|
||||
/// Removes the watch represented by the provided [`WatchDescriptor`] by
|
||||
/// calling [`inotify_rm_watch`]. [`WatchDescriptor`]s can be obtained via
|
||||
/// [`Inotify::add_watch`], or from the `wd` field of [`Event`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Directly returns the error from the call to [`inotify_rm_watch`].
|
||||
/// Returns an [`io::Error`] with [`ErrorKind`]`::InvalidInput`, if the given
|
||||
/// [`WatchDescriptor`] did not originate from this [`Inotify`] instance.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use inotify::Inotify;
|
||||
///
|
||||
/// let mut inotify = Inotify::init()
|
||||
/// .expect("Failed to initialize an inotify instance");
|
||||
///
|
||||
/// # // Create a temporary file, so `add_watch` won't return an error.
|
||||
/// # use std::fs::File;
|
||||
/// # let mut test_file = File::create("/tmp/inotify-rs-test-file")
|
||||
/// # .expect("Failed to create test file");
|
||||
/// #
|
||||
/// # // Add a watch and modify the file, so the code below doesn't block
|
||||
/// # // forever.
|
||||
/// # use inotify::WatchMask;
|
||||
/// # inotify.add_watch("/tmp/inotify-rs-test-file", WatchMask::MODIFY)
|
||||
/// # .expect("Failed to add file watch");
|
||||
/// # use std::io::Write;
|
||||
/// # write!(&mut test_file, "something\n")
|
||||
/// # .expect("Failed to write something to test file");
|
||||
/// #
|
||||
/// let mut buffer = [0; 1024];
|
||||
/// let events = inotify
|
||||
/// .read_events_blocking(&mut buffer)
|
||||
/// .expect("Error while waiting for events");
|
||||
///
|
||||
/// for event in events {
|
||||
/// inotify.rm_watch(event.wd);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`WatchDescriptor`]: struct.WatchDescriptor.html
|
||||
/// [`inotify_rm_watch`]: ../inotify_sys/fn.inotify_rm_watch.html
|
||||
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
|
||||
/// [`Event`]: struct.Event.html
|
||||
/// [`Inotify`]: struct.Inotify.html
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
/// [`ErrorKind`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html
|
||||
pub fn rm_watch(&mut self, wd: WatchDescriptor) -> io::Result<()> {
|
||||
if wd.fd.upgrade().as_ref() != Some(&self.fd) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid WatchDescriptor",
|
||||
));
|
||||
}
|
||||
|
||||
let result = unsafe { ffi::inotify_rm_watch(**self.fd, wd.id) };
|
||||
match result {
|
||||
0 => Ok(()),
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
_ => panic!(
|
||||
"unexpected return code from inotify_rm_watch ({})", result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until events are available, then returns them
|
||||
///
|
||||
/// Blocks the current thread until at least one event is available. If this
|
||||
/// is not desirable, please consider [`Inotify::read_events`].
|
||||
///
|
||||
/// This method calls [`Inotify::read_events`] internally and behaves
|
||||
/// essentially the same, apart from the blocking behavior. Please refer to
|
||||
/// the documentation of [`Inotify::read_events`] for more information.
|
||||
///
|
||||
/// [`Inotify::read_events`]: struct.Inotify.html#method.read_events
|
||||
/// [`read`]: ../libc/fn.read.html
|
||||
pub fn read_events_blocking<'a>(&mut self, buffer: &'a mut [u8])
|
||||
-> io::Result<Events<'a>>
|
||||
{
|
||||
unsafe {
|
||||
let res = fcntl(**self.fd, F_GETFL);
|
||||
if res == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if fcntl(**self.fd, F_SETFL, res & !O_NONBLOCK) == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
};
|
||||
let result = self.read_events(buffer);
|
||||
unsafe {
|
||||
let res = fcntl(**self.fd, F_GETFL);
|
||||
if res == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if fcntl(**self.fd, F_SETFL, res | O_NONBLOCK) == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns one buffer's worth of available events
|
||||
///
|
||||
/// Reads as many events as possible into `buffer`, and returns an iterator
|
||||
/// over them. If no events are available, an iterator is still returned. If
|
||||
/// you need a method that will block until at least one event is available,
|
||||
/// please consider [`read_events_blocking`].
|
||||
///
|
||||
/// Please note that inotify will merge identical successive unread events
|
||||
/// into a single event. This means this method can not be used to count the
|
||||
/// number of file system events.
|
||||
///
|
||||
/// The `buffer` argument, as the name indicates, is used as a buffer for
|
||||
/// the inotify events. Its contents may be overwritten.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function directly returns all errors from the call to [`read`]
|
||||
/// (except EGAIN/EWOULDBLOCK, which result in an empty iterator). In
|
||||
/// addition, [`ErrorKind::UnexpectedEof`] is returned, if the call to
|
||||
/// [`read`] returns `0`, signaling end-of-file.
|
||||
///
|
||||
/// If `buffer` is too small, this will result in an error with
|
||||
/// [`ErrorKind::InvalidInput`]. On very old Linux kernels,
|
||||
/// [`ErrorKind::UnexpectedEof`] will be returned instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use inotify::Inotify;
|
||||
///
|
||||
/// let mut inotify = Inotify::init()
|
||||
/// .expect("Failed to initialize an inotify instance");
|
||||
///
|
||||
/// let mut buffer = [0; 1024];
|
||||
/// let events = inotify.read_events(&mut buffer)
|
||||
/// .expect("Error while reading events");
|
||||
///
|
||||
/// for event in events {
|
||||
/// // Handle event
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`read_events_blocking`]: struct.Inotify.html#method.read_events_blocking
|
||||
/// [`read`]: ../libc/fn.read.html
|
||||
/// [`ErrorKind::UnexpectedEof`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.UnexpectedEof
|
||||
/// [`ErrorKind::InvalidInput`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.InvalidInput
|
||||
pub fn read_events<'a>(&mut self, buffer: &'a mut [u8])
|
||||
-> io::Result<Events<'a>>
|
||||
{
|
||||
let num_bytes = read_into_buffer(**self.fd, buffer);
|
||||
|
||||
let num_bytes = match num_bytes {
|
||||
0 => {
|
||||
return Err(
|
||||
io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"`read` return `0`, signaling end-of-file"
|
||||
)
|
||||
);
|
||||
}
|
||||
-1 => {
|
||||
let error = io::Error::last_os_error();
|
||||
if error.kind() == io::ErrorKind::WouldBlock {
|
||||
return Ok(Events::new(Arc::downgrade(&self.fd), buffer, 0));
|
||||
}
|
||||
else {
|
||||
return Err(error);
|
||||
}
|
||||
},
|
||||
_ if num_bytes < 0 => {
|
||||
panic!("{} {} {} {} {} {}",
|
||||
"Unexpected return value from `read`. Received a negative",
|
||||
"value that was not `-1`. According to the `read` man page",
|
||||
"this shouldn't happen, as either `-1` is returned on",
|
||||
"error, `0` on end-of-file, or a positive value for the",
|
||||
"number of bytes read. Returned value:",
|
||||
num_bytes,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// The value returned by `read` should be `isize`. Let's quickly
|
||||
// verify this with the following assignment, so we can be sure
|
||||
// our cast below is valid.
|
||||
let num_bytes: isize = num_bytes;
|
||||
|
||||
// The type returned by `read` is `isize`, and we've ruled out
|
||||
// all negative values with the match arms above. This means we
|
||||
// can safely cast to `usize`.
|
||||
debug_assert!(num_bytes > 0);
|
||||
num_bytes as usize
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Events::new(Arc::downgrade(&self.fd), buffer, num_bytes))
|
||||
}
|
||||
|
||||
/// Create a stream which collects events
|
||||
///
|
||||
/// Returns a `Stream` over all events that are available. This stream is an
|
||||
/// infinite source of events.
|
||||
///
|
||||
/// An internal buffer which can hold the largest possible event is used.
|
||||
#[cfg(feature = "stream")]
|
||||
pub fn event_stream<T>(&mut self, buffer: T)
|
||||
-> io::Result<EventStream<T>>
|
||||
where
|
||||
T: AsMut<[u8]> + AsRef<[u8]>,
|
||||
{
|
||||
EventStream::new(self.fd.clone(), buffer)
|
||||
}
|
||||
|
||||
/// Closes the inotify instance
|
||||
///
|
||||
/// Closes the file descriptor referring to the inotify instance. The user
|
||||
/// usually doesn't have to call this function, as the underlying inotify
|
||||
/// instance is closed automatically, when [`Inotify`] is dropped.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Directly returns the error from the call to [`close`], without adding any
|
||||
/// error conditions of its own.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use inotify::Inotify;
|
||||
///
|
||||
/// let mut inotify = Inotify::init()
|
||||
/// .expect("Failed to initialize an inotify instance");
|
||||
///
|
||||
/// inotify.close()
|
||||
/// .expect("Failed to close inotify instance");
|
||||
/// ```
|
||||
///
|
||||
/// [`Inotify`]: struct.Inotify.html
|
||||
/// [`close`]: ../libc/fn.close.html
|
||||
pub fn close(self) -> io::Result<()> {
|
||||
// `self` will be dropped when this method returns. If this is the only
|
||||
// owner of `fd`, the `Arc` will also be dropped. The `Drop`
|
||||
// implementation for `FdGuard` will attempt to close the file descriptor
|
||||
// again, unless this flag here is cleared.
|
||||
self.fd.should_not_close();
|
||||
|
||||
match unsafe { ffi::close(**self.fd) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Inotify {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Inotify {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Inotify {
|
||||
fd: Arc::new(FdGuard::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Inotify {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.fd.should_not_close();
|
||||
self.fd.fd
|
||||
}
|
||||
}
|
||||
104
third-party/vendor/inotify/src/lib.rs
vendored
Normal file
104
third-party/vendor/inotify/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
//! Idiomatic inotify wrapper for the Rust programming language
|
||||
//!
|
||||
//! # About
|
||||
//!
|
||||
//! [inotify-rs] is an idiomatic wrapper around the Linux kernel's [inotify] API
|
||||
//! for the Rust programming language. It can be used for monitoring changes to
|
||||
//! files or directories.
|
||||
//!
|
||||
//! The [`Inotify`] struct is the main entry point into the API.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use inotify::{
|
||||
//! Inotify,
|
||||
//! WatchMask,
|
||||
//! };
|
||||
//!
|
||||
//! let mut inotify = Inotify::init()
|
||||
//! .expect("Error while initializing inotify instance");
|
||||
//!
|
||||
//! # // Create a temporary file, so `add_watch` won't return an error.
|
||||
//! # use std::fs::File;
|
||||
//! # let mut test_file = File::create("/tmp/inotify-rs-test-file")
|
||||
//! # .expect("Failed to create test file");
|
||||
//! #
|
||||
//! // Watch for modify and close events.
|
||||
//! inotify
|
||||
//! .add_watch(
|
||||
//! "/tmp/inotify-rs-test-file",
|
||||
//! WatchMask::MODIFY | WatchMask::CLOSE,
|
||||
//! )
|
||||
//! .expect("Failed to add file watch");
|
||||
//!
|
||||
//! # // Modify file, so the following `read_events_blocking` won't block.
|
||||
//! # use std::io::Write;
|
||||
//! # write!(&mut test_file, "something\n")
|
||||
//! # .expect("Failed to write something to test file");
|
||||
//! #
|
||||
//! // Read events that were added with `add_watch` above.
|
||||
//! let mut buffer = [0; 1024];
|
||||
//! let events = inotify.read_events_blocking(&mut buffer)
|
||||
//! .expect("Error while reading events");
|
||||
//!
|
||||
//! for event in events {
|
||||
//! // Handle event
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Attention: inotify gotchas
|
||||
//!
|
||||
//! inotify (as in, the Linux API, not this wrapper) has many edge cases, making
|
||||
//! it hard to use correctly. This can lead to weird and hard to find bugs in
|
||||
//! applications that are based on it. inotify-rs does its best to fix these
|
||||
//! issues, but sometimes this would require an amount of runtime overhead that
|
||||
//! is just unacceptable for a low-level wrapper such as this.
|
||||
//!
|
||||
//! We've documented any issues that inotify-rs has inherited from inotify, as
|
||||
//! far as we are aware of them. Please watch out for any further warnings
|
||||
//! throughout this documentation. If you want to be on the safe side, in case
|
||||
//! we have missed something, please read the [inotify man pages] carefully.
|
||||
//!
|
||||
//! [inotify-rs]: https://crates.io/crates/inotify
|
||||
//! [inotify]: https://en.wikipedia.org/wiki/Inotify
|
||||
//! [`Inotify`]: struct.Inotify.html
|
||||
//! [inotify man pages]: http://man7.org/linux/man-pages/man7/inotify.7.html
|
||||
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
mod events;
|
||||
mod fd_guard;
|
||||
mod inotify;
|
||||
mod util;
|
||||
mod watches;
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
mod stream;
|
||||
|
||||
|
||||
pub use crate::events::{
|
||||
Event,
|
||||
EventMask,
|
||||
EventOwned,
|
||||
Events,
|
||||
};
|
||||
pub use crate::inotify::Inotify;
|
||||
pub use crate::util::{
|
||||
get_buffer_size,
|
||||
get_absolute_path_buffer_size,
|
||||
};
|
||||
pub use crate::watches::{
|
||||
WatchDescriptor,
|
||||
WatchMask,
|
||||
};
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
pub use self::stream::EventStream;
|
||||
108
third-party/vendor/inotify/src/stream.rs
vendored
Normal file
108
third-party/vendor/inotify/src/stream.rs
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
use std::{
|
||||
io,
|
||||
os::unix::io::{AsRawFd, RawFd},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use futures_core::{ready, Stream};
|
||||
use tokio::io::unix::AsyncFd;
|
||||
|
||||
use crate::events::{Event, EventOwned};
|
||||
use crate::fd_guard::FdGuard;
|
||||
use crate::util::read_into_buffer;
|
||||
|
||||
/// Stream of inotify events
|
||||
///
|
||||
/// Allows for streaming events returned by [`Inotify::event_stream`].
|
||||
///
|
||||
/// [`Inotify::event_stream`]: struct.Inotify.html#method.event_stream
|
||||
#[derive(Debug)]
|
||||
pub struct EventStream<T> {
|
||||
fd: AsyncFd<ArcFdGuard>,
|
||||
buffer: T,
|
||||
buffer_pos: usize,
|
||||
unused_bytes: usize,
|
||||
}
|
||||
|
||||
impl<T> EventStream<T>
|
||||
where
|
||||
T: AsMut<[u8]> + AsRef<[u8]>,
|
||||
{
|
||||
/// Returns a new `EventStream` associated with the default reactor.
|
||||
pub(crate) fn new(fd: Arc<FdGuard>, buffer: T) -> io::Result<Self> {
|
||||
Ok(EventStream {
|
||||
fd: AsyncFd::new(ArcFdGuard(fd))?,
|
||||
buffer: buffer,
|
||||
buffer_pos: 0,
|
||||
unused_bytes: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for EventStream<T>
|
||||
where
|
||||
T: AsMut<[u8]> + AsRef<[u8]>,
|
||||
{
|
||||
type Item = io::Result<EventOwned>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
// Safety: safe because we never move out of `self_`.
|
||||
let self_ = unsafe { self.get_unchecked_mut() };
|
||||
|
||||
if self_.unused_bytes == 0 {
|
||||
// Nothing usable in buffer. Need to reset and fill buffer.
|
||||
self_.buffer_pos = 0;
|
||||
self_.unused_bytes = ready!(read(&self_.fd, self_.buffer.as_mut(), cx))?;
|
||||
}
|
||||
|
||||
if self_.unused_bytes == 0 {
|
||||
// The previous read returned `0` signalling end-of-file. Let's
|
||||
// signal end-of-stream to the caller.
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
|
||||
// We have bytes in the buffer. inotify doesn't put partial events in
|
||||
// there, and we only take complete events out. That means we have at
|
||||
// least one event in there and can call `from_buffer` to take it out.
|
||||
let (bytes_consumed, event) = Event::from_buffer(
|
||||
Arc::downgrade(&self_.fd.get_ref().0),
|
||||
&self_.buffer.as_ref()[self_.buffer_pos..],
|
||||
);
|
||||
self_.buffer_pos += bytes_consumed;
|
||||
self_.unused_bytes -= bytes_consumed;
|
||||
|
||||
Poll::Ready(Some(Ok(event.into_owned())))
|
||||
}
|
||||
}
|
||||
|
||||
// Newtype wrapper because AsRawFd isn't implemented for Arc<T> where T: AsRawFd.
|
||||
#[derive(Debug)]
|
||||
struct ArcFdGuard(Arc<FdGuard>);
|
||||
|
||||
impl AsRawFd for ArcFdGuard {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
fn read(fd: &AsyncFd<ArcFdGuard>, buffer: &mut [u8], cx: &mut Context) -> Poll<io::Result<usize>> {
|
||||
let mut guard = ready!(fd.poll_read_ready(cx))?;
|
||||
let result = guard.try_io(|_| {
|
||||
let read = read_into_buffer(fd.as_raw_fd(), buffer);
|
||||
if read == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(read as usize)
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(result) => Poll::Ready(result),
|
||||
Err(_would_block) => {
|
||||
cx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
93
third-party/vendor/inotify/src/util.rs
vendored
Normal file
93
third-party/vendor/inotify/src/util.rs
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use std::{
|
||||
io,
|
||||
mem,
|
||||
os::unix::io::RawFd,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use inotify_sys as ffi;
|
||||
use libc::{
|
||||
c_void,
|
||||
size_t,
|
||||
};
|
||||
|
||||
const INOTIFY_EVENT_SIZE: usize = mem::size_of::<ffi::inotify_event>() + 257;
|
||||
|
||||
pub fn read_into_buffer(fd: RawFd, buffer: &mut [u8]) -> isize {
|
||||
unsafe {
|
||||
// Discard the unaligned portion, if any, of the supplied buffer
|
||||
let buffer = align_buffer_mut(buffer);
|
||||
|
||||
ffi::read(
|
||||
fd,
|
||||
buffer.as_mut_ptr() as *mut c_void,
|
||||
buffer.len() as size_t
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align_buffer(buffer: &[u8]) -> &[u8] {
|
||||
if buffer.len() >= mem::align_of::<ffi::inotify_event>() {
|
||||
let ptr = buffer.as_ptr();
|
||||
let offset = ptr.align_offset(mem::align_of::<ffi::inotify_event>());
|
||||
&buffer[offset..]
|
||||
} else {
|
||||
&buffer[0..0]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align_buffer_mut(buffer: &mut [u8]) -> &mut [u8] {
|
||||
if buffer.len() >= mem::align_of::<ffi::inotify_event>() {
|
||||
let ptr = buffer.as_mut_ptr();
|
||||
let offset = ptr.align_offset(mem::align_of::<ffi::inotify_event>());
|
||||
&mut buffer[offset..]
|
||||
} else {
|
||||
&mut buffer[0..0]
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the inotify event buffer size
|
||||
///
|
||||
/// The maximum size of an inotify event and thus the buffer size to hold it
|
||||
/// can be calculated using this formula:
|
||||
/// `sizeof(struct inotify_event) + NAME_MAX + 1`
|
||||
///
|
||||
/// See: [https://man7.org/linux/man-pages/man7/inotify.7.html](https://man7.org/linux/man-pages/man7/inotify.7.html)
|
||||
///
|
||||
/// The NAME_MAX size formula is:
|
||||
/// `ABSOLUTE_PARENT_PATH_LEN + 1 + 255`
|
||||
///
|
||||
/// - `ABSOLUTE_PARENT_PATH_LEN` will be calculated at runtime.
|
||||
/// - Add 1 to account for a `/`, either in between the parent path and a filename
|
||||
/// or for the root directory.
|
||||
/// - Add the maximum number of chars in a filename, 255.
|
||||
///
|
||||
/// See: [https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h](https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h)
|
||||
///
|
||||
/// Unfortunately, we can't just do the same with max path length itself.
|
||||
///
|
||||
/// See: [https://eklitzke.org/path-max-is-tricky](https://eklitzke.org/path-max-is-tricky)
|
||||
///
|
||||
/// This function is really just a fallible wrapper around `get_absolute_path_buffer_size()`.
|
||||
///
|
||||
/// path: A relative or absolute path for the inotify events.
|
||||
pub fn get_buffer_size(path: &Path) -> io::Result<usize> {
|
||||
Ok(get_absolute_path_buffer_size(&path.canonicalize()?))
|
||||
}
|
||||
|
||||
/// Get the inotify event buffer size for an absolute path
|
||||
///
|
||||
/// For relative paths, consider using `get_buffer_size()` which provides a fallible wrapper
|
||||
/// for this function.
|
||||
///
|
||||
/// path: An absolute path for the inotify events.
|
||||
pub fn get_absolute_path_buffer_size(path: &Path) -> usize {
|
||||
INOTIFY_EVENT_SIZE
|
||||
// Get the length of the absolute parent path, if the path is not the root directory.
|
||||
// Because we canonicalize the path, we do not need to worry about prefixes.
|
||||
+ if let Some(parent_path) = path.parent() {
|
||||
parent_path.as_os_str().len()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
327
third-party/vendor/inotify/src/watches.rs
vendored
Normal file
327
third-party/vendor/inotify/src/watches.rs
vendored
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
use std::{
|
||||
hash::{
|
||||
Hash,
|
||||
Hasher,
|
||||
},
|
||||
cmp::Ordering,
|
||||
os::raw::c_int,
|
||||
sync::Weak,
|
||||
};
|
||||
|
||||
use inotify_sys as ffi;
|
||||
|
||||
use crate::fd_guard::FdGuard;
|
||||
|
||||
|
||||
bitflags! {
|
||||
/// Describes a file system watch
|
||||
///
|
||||
/// Passed to [`Inotify::add_watch`], to describe what file system events
|
||||
/// to watch for, and how to do that.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// `WatchMask` constants can be passed to [`Inotify::add_watch`] as is. For
|
||||
/// example, here's how to create a watch that triggers an event when a file
|
||||
/// is accessed:
|
||||
///
|
||||
/// ``` rust
|
||||
/// # use inotify::{
|
||||
/// # Inotify,
|
||||
/// # WatchMask,
|
||||
/// # };
|
||||
/// #
|
||||
/// # let mut inotify = Inotify::init().unwrap();
|
||||
/// #
|
||||
/// # // Create a temporary file, so `add_watch` won't return an error.
|
||||
/// # use std::fs::File;
|
||||
/// # File::create("/tmp/inotify-rs-test-file")
|
||||
/// # .expect("Failed to create test file");
|
||||
/// #
|
||||
/// inotify.add_watch("/tmp/inotify-rs-test-file", WatchMask::ACCESS)
|
||||
/// .expect("Error adding watch");
|
||||
/// ```
|
||||
///
|
||||
/// You can also combine multiple `WatchMask` constants. Here we add a watch
|
||||
/// this is triggered both when files are created or deleted in a directory:
|
||||
///
|
||||
/// ``` rust
|
||||
/// # use inotify::{
|
||||
/// # Inotify,
|
||||
/// # WatchMask,
|
||||
/// # };
|
||||
/// #
|
||||
/// # let mut inotify = Inotify::init().unwrap();
|
||||
/// inotify.add_watch("/tmp/", WatchMask::CREATE | WatchMask::DELETE)
|
||||
/// .expect("Error adding watch");
|
||||
/// ```
|
||||
///
|
||||
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
|
||||
pub struct WatchMask: u32 {
|
||||
/// File was accessed
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_ACCESS`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ACCESS`]: ../inotify_sys/constant.IN_ACCESS.html
|
||||
const ACCESS = ffi::IN_ACCESS;
|
||||
|
||||
/// Metadata (permissions, timestamps, ...) changed
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_ATTRIB`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ATTRIB`]: ../inotify_sys/constant.IN_ATTRIB.html
|
||||
const ATTRIB = ffi::IN_ATTRIB;
|
||||
|
||||
/// File opened for writing was closed
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CLOSE_WRITE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CLOSE_WRITE`]: ../inotify_sys/constant.IN_CLOSE_WRITE.html
|
||||
const CLOSE_WRITE = ffi::IN_CLOSE_WRITE;
|
||||
|
||||
/// File or directory not opened for writing was closed
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CLOSE_NOWRITE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CLOSE_NOWRITE`]: ../inotify_sys/constant.IN_CLOSE_NOWRITE.html
|
||||
const CLOSE_NOWRITE = ffi::IN_CLOSE_NOWRITE;
|
||||
|
||||
/// File/directory created in watched directory
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_CREATE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_CREATE`]: ../inotify_sys/constant.IN_CREATE.html
|
||||
const CREATE = ffi::IN_CREATE;
|
||||
|
||||
/// File/directory deleted from watched directory
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_DELETE`].
|
||||
///
|
||||
/// [`inotify_sys::IN_DELETE`]: ../inotify_sys/constant.IN_DELETE.html
|
||||
const DELETE = ffi::IN_DELETE;
|
||||
|
||||
/// Watched file/directory was deleted
|
||||
///
|
||||
/// See [`inotify_sys::IN_DELETE_SELF`].
|
||||
///
|
||||
/// [`inotify_sys::IN_DELETE_SELF`]: ../inotify_sys/constant.IN_DELETE_SELF.html
|
||||
const DELETE_SELF = ffi::IN_DELETE_SELF;
|
||||
|
||||
/// File was modified
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MODIFY`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MODIFY`]: ../inotify_sys/constant.IN_MODIFY.html
|
||||
const MODIFY = ffi::IN_MODIFY;
|
||||
|
||||
/// Watched file/directory was moved
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVE_SELF`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVE_SELF`]: ../inotify_sys/constant.IN_MOVE_SELF.html
|
||||
const MOVE_SELF = ffi::IN_MOVE_SELF;
|
||||
|
||||
/// File was renamed/moved; watched directory contained old name
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVED_FROM`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVED_FROM`]: ../inotify_sys/constant.IN_MOVED_FROM.html
|
||||
const MOVED_FROM = ffi::IN_MOVED_FROM;
|
||||
|
||||
/// File was renamed/moved; watched directory contains new name
|
||||
///
|
||||
/// When watching a directory, this event is only triggered for objects
|
||||
/// inside the directory, not the directory itself.
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVED_TO`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MOVED_TO`]: ../inotify_sys/constant.IN_MOVED_TO.html
|
||||
const MOVED_TO = ffi::IN_MOVED_TO;
|
||||
|
||||
/// File or directory was opened
|
||||
///
|
||||
/// When watching a directory, this event can be triggered for the
|
||||
/// directory itself, as well as objects inside the directory.
|
||||
///
|
||||
/// See [`inotify_sys::IN_OPEN`].
|
||||
///
|
||||
/// [`inotify_sys::IN_OPEN`]: ../inotify_sys/constant.IN_OPEN.html
|
||||
const OPEN = ffi::IN_OPEN;
|
||||
|
||||
/// Watch for all events
|
||||
///
|
||||
/// This constant is simply a convenient combination of the following
|
||||
/// other constants:
|
||||
///
|
||||
/// - [`ACCESS`]
|
||||
/// - [`ATTRIB`]
|
||||
/// - [`CLOSE_WRITE`]
|
||||
/// - [`CLOSE_NOWRITE`]
|
||||
/// - [`CREATE`]
|
||||
/// - [`DELETE`]
|
||||
/// - [`DELETE_SELF`]
|
||||
/// - [`MODIFY`]
|
||||
/// - [`MOVE_SELF`]
|
||||
/// - [`MOVED_FROM`]
|
||||
/// - [`MOVED_TO`]
|
||||
/// - [`OPEN`]
|
||||
///
|
||||
/// See [`inotify_sys::IN_ALL_EVENTS`].
|
||||
///
|
||||
/// [`ACCESS`]: #associatedconstant.ACCESS
|
||||
/// [`ATTRIB`]: #associatedconstant.ATTRIB
|
||||
/// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
|
||||
/// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
|
||||
/// [`CREATE`]: #associatedconstant.CREATE
|
||||
/// [`DELETE`]: #associatedconstant.DELETE
|
||||
/// [`DELETE_SELF`]: #associatedconstant.DELETE_SELF
|
||||
/// [`MODIFY`]: #associatedconstant.MODIFY
|
||||
/// [`MOVE_SELF`]: #associatedconstant.MOVE_SELF
|
||||
/// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
|
||||
/// [`MOVED_TO`]: #associatedconstant.MOVED_TO
|
||||
/// [`OPEN`]: #associatedconstant.OPEN
|
||||
/// [`inotify_sys::IN_ALL_EVENTS`]: ../inotify_sys/constant.IN_ALL_EVENTS.html
|
||||
const ALL_EVENTS = ffi::IN_ALL_EVENTS;
|
||||
|
||||
/// Watch for all move events
|
||||
///
|
||||
/// This constant is simply a convenient combination of the following
|
||||
/// other constants:
|
||||
///
|
||||
/// - [`MOVED_FROM`]
|
||||
/// - [`MOVED_TO`]
|
||||
///
|
||||
/// See [`inotify_sys::IN_MOVE`].
|
||||
///
|
||||
/// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
|
||||
/// [`MOVED_TO`]: #associatedconstant.MOVED_TO
|
||||
/// [`inotify_sys::IN_MOVE`]: ../inotify_sys/constant.IN_MOVE.html
|
||||
const MOVE = ffi::IN_MOVE;
|
||||
|
||||
/// Watch for all close events
|
||||
///
|
||||
/// This constant is simply a convenient combination of the following
|
||||
/// other constants:
|
||||
///
|
||||
/// - [`CLOSE_WRITE`]
|
||||
/// - [`CLOSE_NOWRITE`]
|
||||
///
|
||||
/// See [`inotify_sys::IN_CLOSE`].
|
||||
///
|
||||
/// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
|
||||
/// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
|
||||
/// [`inotify_sys::IN_CLOSE`]: ../inotify_sys/constant.IN_CLOSE.html
|
||||
const CLOSE = ffi::IN_CLOSE;
|
||||
|
||||
/// Don't dereference the path if it is a symbolic link
|
||||
///
|
||||
/// See [`inotify_sys::IN_DONT_FOLLOW`].
|
||||
///
|
||||
/// [`inotify_sys::IN_DONT_FOLLOW`]: ../inotify_sys/constant.IN_DONT_FOLLOW.html
|
||||
const DONT_FOLLOW = ffi::IN_DONT_FOLLOW;
|
||||
|
||||
/// Filter events for directory entries that have been unlinked
|
||||
///
|
||||
/// See [`inotify_sys::IN_EXCL_UNLINK`].
|
||||
///
|
||||
/// [`inotify_sys::IN_EXCL_UNLINK`]: ../inotify_sys/constant.IN_EXCL_UNLINK.html
|
||||
const EXCL_UNLINK = ffi::IN_EXCL_UNLINK;
|
||||
|
||||
/// If a watch for the inode exists, amend it instead of replacing it
|
||||
///
|
||||
/// See [`inotify_sys::IN_MASK_ADD`].
|
||||
///
|
||||
/// [`inotify_sys::IN_MASK_ADD`]: ../inotify_sys/constant.IN_MASK_ADD.html
|
||||
const MASK_ADD = ffi::IN_MASK_ADD;
|
||||
|
||||
/// Only receive one event, then remove the watch
|
||||
///
|
||||
/// See [`inotify_sys::IN_ONESHOT`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ONESHOT`]: ../inotify_sys/constant.IN_ONESHOT.html
|
||||
const ONESHOT = ffi::IN_ONESHOT;
|
||||
|
||||
/// Only watch path, if it is a directory
|
||||
///
|
||||
/// See [`inotify_sys::IN_ONLYDIR`].
|
||||
///
|
||||
/// [`inotify_sys::IN_ONLYDIR`]: ../inotify_sys/constant.IN_ONLYDIR.html
|
||||
const ONLYDIR = ffi::IN_ONLYDIR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Represents a watch on an inode
|
||||
///
|
||||
/// Can be obtained from [`Inotify::add_watch`] or from an [`Event`]. A watch
|
||||
/// descriptor can be used to get inotify to stop watching an inode by passing
|
||||
/// it to [`Inotify::rm_watch`].
|
||||
///
|
||||
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
|
||||
/// [`Inotify::rm_watch`]: struct.Inotify.html#method.rm_watch
|
||||
/// [`Event`]: struct.Event.html
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WatchDescriptor{
|
||||
pub(crate) id: c_int,
|
||||
pub(crate) fd: Weak<FdGuard>,
|
||||
}
|
||||
|
||||
impl Eq for WatchDescriptor {}
|
||||
|
||||
impl PartialEq for WatchDescriptor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let self_fd = self.fd.upgrade();
|
||||
let other_fd = other.fd.upgrade();
|
||||
|
||||
self.id == other.id && self_fd.is_some() && self_fd == other_fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for WatchDescriptor {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.id.cmp(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for WatchDescriptor {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for WatchDescriptor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// This function only takes `self.id` into account, as `self.fd` is a
|
||||
// weak pointer that might no longer be available. Since neither
|
||||
// panicking nor changing the hash depending on whether it's available
|
||||
// is acceptable, we just don't look at it at all.
|
||||
// I don't think that this influences storage in a `HashMap` or
|
||||
// `HashSet` negatively, as storing `WatchDescriptor`s from different
|
||||
// `Inotify` instances seems like something of an anti-pattern anyway.
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
264
third-party/vendor/inotify/tests/main.rs
vendored
Normal file
264
third-party/vendor/inotify/tests/main.rs
vendored
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
#![deny(warnings)]
|
||||
|
||||
|
||||
// This test suite is incomplete and doesn't cover all available functionality.
|
||||
// Contributions to improve test coverage would be highly appreciated!
|
||||
|
||||
use inotify::{
|
||||
Inotify,
|
||||
WatchMask,
|
||||
};
|
||||
use std::fs::File;
|
||||
use std::io::{
|
||||
Write,
|
||||
ErrorKind,
|
||||
};
|
||||
use std::os::unix::io::{
|
||||
AsRawFd,
|
||||
FromRawFd,
|
||||
IntoRawFd,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
|
||||
|
||||
#[test]
|
||||
fn it_should_watch_a_file() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, mut file) = testdir.new_file();
|
||||
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
let watch = inotify.add_watch(&path, WatchMask::MODIFY).unwrap();
|
||||
|
||||
write_to(&mut file);
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
let events = inotify.read_events_blocking(&mut buffer).unwrap();
|
||||
|
||||
let mut num_events = 0;
|
||||
for event in events {
|
||||
assert_eq!(watch, event.wd);
|
||||
num_events += 1;
|
||||
}
|
||||
assert!(num_events > 0);
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
#[tokio::test]
|
||||
async fn it_should_watch_a_file_async() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, mut file) = testdir.new_file();
|
||||
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
let watch = inotify.add_watch(&path, WatchMask::MODIFY).unwrap();
|
||||
|
||||
write_to(&mut file);
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
|
||||
use futures_util::StreamExt;
|
||||
let events = inotify
|
||||
.event_stream(&mut buffer[..])
|
||||
.unwrap()
|
||||
.take(1)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
|
||||
let mut num_events = 0;
|
||||
for event in events {
|
||||
if let Ok(event) = event {
|
||||
assert_eq!(watch, event.wd);
|
||||
num_events += 1;
|
||||
}
|
||||
}
|
||||
assert!(num_events > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_return_immediately_if_no_events_are_available() {
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
assert_eq!(0, inotify.read_events(&mut buffer).unwrap().count());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_convert_the_name_into_an_os_str() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, mut file) = testdir.new_file();
|
||||
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
inotify.add_watch(&path.parent().unwrap(), WatchMask::MODIFY).unwrap();
|
||||
|
||||
write_to(&mut file);
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
let mut events = inotify.read_events_blocking(&mut buffer).unwrap();
|
||||
|
||||
if let Some(event) = events.next() {
|
||||
assert_eq!(path.file_name(), event.name);
|
||||
}
|
||||
else {
|
||||
panic!("Expected inotify event");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_set_name_to_none_if_it_is_empty() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, mut file) = testdir.new_file();
|
||||
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
inotify.add_watch(&path, WatchMask::MODIFY).unwrap();
|
||||
|
||||
write_to(&mut file);
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
let mut events = inotify.read_events_blocking(&mut buffer).unwrap();
|
||||
|
||||
if let Some(event) = events.next() {
|
||||
assert_eq!(event.name, None);
|
||||
}
|
||||
else {
|
||||
panic!("Expected inotify event");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_not_accept_watchdescriptors_from_other_instances() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, _) = testdir.new_file();
|
||||
|
||||
let mut inotify = Inotify::init().unwrap();
|
||||
let _ = inotify.add_watch(&path, WatchMask::ACCESS).unwrap();
|
||||
|
||||
let mut second_inotify = Inotify::init().unwrap();
|
||||
let wd2 = second_inotify.add_watch(&path, WatchMask::ACCESS).unwrap();
|
||||
|
||||
assert_eq!(inotify.rm_watch(wd2).unwrap_err().kind(), ErrorKind::InvalidInput);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watch_descriptors_from_different_inotify_instances_should_not_be_equal() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, _) = testdir.new_file();
|
||||
|
||||
let mut inotify_1 = Inotify::init()
|
||||
.unwrap();
|
||||
let mut inotify_2 = Inotify::init()
|
||||
.unwrap();
|
||||
|
||||
let wd_1 = inotify_1
|
||||
.add_watch(&path, WatchMask::ACCESS)
|
||||
.unwrap();
|
||||
let wd_2 = inotify_2
|
||||
.add_watch(&path, WatchMask::ACCESS)
|
||||
.unwrap();
|
||||
|
||||
// As far as inotify is concerned, watch descriptors are just integers that
|
||||
// are scoped per inotify instance. This means that multiple instances will
|
||||
// produce the same watch descriptor number, a case we want inotify-rs to
|
||||
// detect.
|
||||
assert!(wd_1 != wd_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watch_descriptor_equality_should_not_be_confused_by_reused_fds() {
|
||||
let mut testdir = TestDir::new();
|
||||
let (path, _) = testdir.new_file();
|
||||
|
||||
// When a new inotify instance is created directly after closing another
|
||||
// one, it is possible that the file descriptor is reused immediately, and
|
||||
// we end up with a new instance that has the same file descriptor as the
|
||||
// old one.
|
||||
// This is quite likely, but it doesn't happen every time. Therefore we may
|
||||
// need a few tries until we find two instances where that is the case.
|
||||
let (wd_1, mut inotify_2) = loop {
|
||||
let mut inotify_1 = Inotify::init()
|
||||
.unwrap();
|
||||
|
||||
let wd_1 = inotify_1
|
||||
.add_watch(&path, WatchMask::ACCESS)
|
||||
.unwrap();
|
||||
let fd_1 = inotify_1.as_raw_fd();
|
||||
|
||||
inotify_1
|
||||
.close()
|
||||
.unwrap();
|
||||
let inotify_2 = Inotify::init()
|
||||
.unwrap();
|
||||
|
||||
if fd_1 == inotify_2.as_raw_fd() {
|
||||
break (wd_1, inotify_2);
|
||||
}
|
||||
};
|
||||
|
||||
let wd_2 = inotify_2
|
||||
.add_watch(&path, WatchMask::ACCESS)
|
||||
.unwrap();
|
||||
|
||||
// The way we engineered this situation, both `WatchDescriptor` instances
|
||||
// have the same fields. They still come from different inotify instances
|
||||
// though, so they shouldn't be equal.
|
||||
assert!(wd_1 != wd_2);
|
||||
|
||||
inotify_2
|
||||
.close()
|
||||
.unwrap();
|
||||
|
||||
// A little extra gotcha: If both inotify instances are closed, and the `Eq`
|
||||
// implementation naively compares the weak pointers, both will be `None`,
|
||||
// making them equal. Let's make sure this isn't the case.
|
||||
assert!(wd_1 != wd_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_implement_raw_fd_traits_correctly() {
|
||||
let fd = Inotify::init()
|
||||
.expect("Failed to initialize inotify instance")
|
||||
.into_raw_fd();
|
||||
|
||||
// If `IntoRawFd` has been implemented naively, `Inotify`'s `Drop`
|
||||
// implementation will have closed the inotify instance at this point. Let's
|
||||
// make sure this didn't happen.
|
||||
let mut inotify = unsafe { <Inotify as FromRawFd>::from_raw_fd(fd) };
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
if let Err(error) = inotify.read_events(&mut buffer) {
|
||||
panic!("Failed to add watch: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct TestDir {
|
||||
dir: TempDir,
|
||||
counter: u32,
|
||||
}
|
||||
|
||||
impl TestDir {
|
||||
fn new() -> TestDir {
|
||||
TestDir {
|
||||
dir: TempDir::new().unwrap(),
|
||||
counter: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_file(&mut self) -> (PathBuf, File) {
|
||||
let id = self.counter;
|
||||
self.counter += 1;
|
||||
|
||||
let path = self.dir.path().join("file-".to_string() + &id.to_string());
|
||||
let file = File::create(&path)
|
||||
.unwrap_or_else(|error| panic!("Failed to create temporary file: {}", error));
|
||||
|
||||
(path, file)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to(file: &mut File) {
|
||||
file
|
||||
.write(b"This should trigger an inotify event.")
|
||||
.unwrap_or_else(|error|
|
||||
panic!("Failed to write to file: {}", error)
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue