From db3d84fbf0dfbbe9c9b943c53e5037917e284360 Mon Sep 17 00:00:00 2001 From: Ray Kraesig Date: Tue, 3 Jan 2023 06:25:38 +0000 Subject: [PATCH] Bug 1807981 - Audit winreg 0.10.1 as safe-to-run, and upgrade to it r=supply-chain-reviewers,webdriver-reviewers,whimboo Upgrade winreg (currently used only by mozrunner) to 0.10.1. As winreg 0.5.1 is currently listed as an exemption in `supply-chain`, audit the new version as a blank slate, rather than performing an audit of the diffs; this is both simpler and allows removing the exemption. (There are some uses of `unsafe` that would be concerning in deployment (more for reasons of stability than security), but the crate does qualify as `safe-to-run`.) winreg 0.5.1 is currently only used by mozrunner, which requires no source changes for this upgrade. Differential Revision: https://phabricator.services.mozilla.com/D165723 --- Cargo.lock | 4 +- supply-chain/audits.toml | 12 + supply-chain/config.toml | 4 - testing/mozbase/rust/mozrunner/Cargo.toml | 2 +- third_party/rust/winreg/.cargo-checksum.json | 2 +- third_party/rust/winreg/Cargo.lock | 350 +++++++ third_party/rust/winreg/Cargo.toml | 28 +- third_party/rust/winreg/README.md | 224 +++-- third_party/rust/winreg/appveyor.yml | 15 +- third_party/rust/winreg/build.rs | 11 + .../rust/winreg/examples/basic_usage.rs | 59 +- third_party/rust/winreg/examples/enum.rs | 16 +- .../rust/winreg/examples/installed_apps.rs | 23 +- .../rust/winreg/examples/load_app_key.rs | 26 + .../winreg/examples/map_key_serialization.rs | 57 ++ .../rust/winreg/examples/serialization.rs | 46 +- .../rust/winreg/examples/transactions.rs | 31 +- third_party/rust/winreg/src/decoder/mod.rs | 58 +- .../winreg/src/decoder/serialization_serde.rs | 220 +++- third_party/rust/winreg/src/encoder/mod.rs | 58 +- .../winreg/src/encoder/serialization_serde.rs | 355 +++++-- third_party/rust/winreg/src/enums.rs | 39 +- third_party/rust/winreg/src/lib.rs | 941 +++++++++--------- third_party/rust/winreg/src/transaction.rs | 16 +- third_party/rust/winreg/src/types.rs | 174 ++-- third_party/rust/winreg/tests/reg_key.rs | 364 +++++++ 26 files changed, 2221 insertions(+), 914 deletions(-) create mode 100644 third_party/rust/winreg/Cargo.lock create mode 100644 third_party/rust/winreg/build.rs create mode 100644 third_party/rust/winreg/examples/load_app_key.rs create mode 100644 third_party/rust/winreg/examples/map_key_serialization.rs create mode 100644 third_party/rust/winreg/tests/reg_key.rs diff --git a/Cargo.lock b/Cargo.lock index 3532bd815edb..3c0063cd1a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6411,9 +6411,9 @@ dependencies = [ [[package]] name = "winreg" -version = "0.5.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 23d9d3525642..20a918ebb65b 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2458,6 +2458,18 @@ also contains a small C file compiled at build-time. I audited all of it and it looks correct. """ +[[audits.winreg]] +who = "Ray Kraesig " +criteria = "safe-to-run" +version = "0.10.1" +notes = """ +This crate uses a lot of `unsafe`; not all of it is necessary, and not all of it +is correct. (In particular, the alignment of data buffers does not seem to be +correctly ensured at type-conversion time.) However, the code is not deceptive, +and any more subtle issues do not appear to be exploitable -- certainly not from +a test environment. +""" + [[audits.wpf-gpu-raster]] who = "Lee Salzman " criteria = "safe-to-deploy" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index dd1e5ae4b55b..a4b4680a3f4d 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -1381,10 +1381,6 @@ criteria = "safe-to-deploy" version = "0.4.0" criteria = "safe-to-deploy" -[[exemptions.winreg]] -version = "0.5.1" -criteria = "safe-to-run" - [[exemptions.wio]] version = "0.2.2" criteria = "safe-to-deploy" diff --git a/testing/mozbase/rust/mozrunner/Cargo.toml b/testing/mozbase/rust/mozrunner/Cargo.toml index 48fe9fe205e6..6cd682a06c4c 100644 --- a/testing/mozbase/rust/mozrunner/Cargo.toml +++ b/testing/mozbase/rust/mozrunner/Cargo.toml @@ -18,7 +18,7 @@ mozprofile = { path = "../mozprofile", version = "0.9" } plist = "1.0" [target.'cfg(target_os = "windows")'.dependencies] -winreg = "0.5" +winreg = "0.10.1" [target.'cfg(target_os = "macos")'.dependencies] dirs = "4" diff --git a/third_party/rust/winreg/.cargo-checksum.json b/third_party/rust/winreg/.cargo-checksum.json index e5f1631b1f51..c0feadd1a025 100644 --- a/third_party/rust/winreg/.cargo-checksum.json +++ b/third_party/rust/winreg/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"a1e8f0c4b5eab990649c6963190f190a033bca7035b85f88ea0836bfb10c9348","LICENSE":"ea021d8c6383c84d19c15ce90d3b1602cf448fdcc0bf3772c98e43c7bf1bf1d1","README.md":"137d72ca6c03e6876abb162733b305718591e28ab42f00689cb1bec7dbc38409","appveyor.yml":"986d99d18ffd511d6d4a357109d2b3ded4eea7449f49c339c6ca221064bb3bb0","examples/basic_usage.rs":"de70cb705ab3ccbf3681df106656b6398f9df27d0e7d21f7ef9a1ea51335b0cf","examples/enum.rs":"7e18a35960c824f88a122a4ae67020b44579379c0268fa7f37641b03aacb55cc","examples/installed_apps.rs":"0e210f33218649182276824f6cb461c2085ca9f8ca7c687318405b7896fd4d42","examples/serialization.rs":"b82553788bef12a9164c2a42d9ae99fceaef1e752286219ee8b24374cb5a8b19","examples/transactions.rs":"6fb7d7c7811aadab840b5ba36dfef9e8c19c0f874e02f54f90b73b16f455be70","src/decoder/mod.rs":"68064e7d0312be72152f008593377ac56bdad45fa5a007446a4358fbae17cfd0","src/decoder/serialization_serde.rs":"4fc46761f5139661bdc5fa2c490000701c5df71d1b4803ae41823acad0d0ded6","src/encoder/mod.rs":"2614013d7be54f5f39a21b8e75511e950d703e4571f9a63292ae51507a21c612","src/encoder/serialization_serde.rs":"a03fceb693761257a8bc4f72984e2a551f5a1d86e57fee6acdcc39934b8a9ee4","src/enums.rs":"8117cd8281018e092bb756836a1cc5d2bd826a87f20d9ead67a09c94296649f5","src/lib.rs":"ab3d8696a09a027a784b6baf7a3bbf852a6f029eb3914015c800f2761992f65c","src/transaction.rs":"e6c9d5ae895b3d397ce0436c7dd9562ad60405c8fedd6730e3801d69a9e84e74","src/types.rs":"c16db1ab91b1250ca1c510f20977d5046987764395c0f545a950c5a049428183"},"package":"a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"} \ No newline at end of file +{"files":{"Cargo.lock":"818308f83f82333925a5c79a33070576296820a9ca6f619b3be3b89918916f22","Cargo.toml":"7462003029eaddf0220e48731744d83b9e91b40a71c33ee13543b65995c4fb52","LICENSE":"ea021d8c6383c84d19c15ce90d3b1602cf448fdcc0bf3772c98e43c7bf1bf1d1","README.md":"37ad193ded0a105eecea15743a76249c6ec735b82a06b78312052648564eccb5","appveyor.yml":"92f6bab3b9609448c48983d6c418fb9061dbd851a9d804ccd923f7e34ab742f1","build.rs":"3d34e0c23f6c21e6da11fb0fc3aff792b8f30f3ecfbb6b4f536d0a70394e13e7","examples/basic_usage.rs":"e7dd3af233d3aca6a92676eab2ac55414af1477d4214e7c1c2cdbdf583c83fa1","examples/enum.rs":"9be94d7dde12fc49a3fbe5c7810a6a9ad28eaac9319271e1cabda121301e08f3","examples/installed_apps.rs":"595709b6453b1efb5c613e69795d6f6576d45762867de1ee7247f2c3e988edbb","examples/load_app_key.rs":"16275c44efa22519101c199903c53e0cdca5ad4ebdcb39939c5a285de2fa006c","examples/map_key_serialization.rs":"82b102a36c91f99e8eeb2d1cfde13131f087457de1c84db3af31097fdb4541b0","examples/serialization.rs":"7f5c0e7e50872c9655cf4e54b4efb54a8bc19113dc645279496b8e3d20109295","examples/transactions.rs":"8094aa5dcecedae3acef58ece3ed264a44e908c12cfd4a65ff8c90254dbc7225","src/decoder/mod.rs":"75318907ca32ff0aa3af9bf63be9d728a76d7a75f7d1fdb88bcb3a9df4abeb01","src/decoder/serialization_serde.rs":"3f7cc4249dbff8255ed40cd4a3b4416779ddbad4bd476032094259a8668d0cd2","src/encoder/mod.rs":"a5331802cbe374e0c511aa1335fa32d7bbb3aa972cb136df3fc585b3f3855cf5","src/encoder/serialization_serde.rs":"d63037eb017fd2ece03ed4a140baf2a75516a3ef0315bf10a3eb16d5455880d6","src/enums.rs":"d69acf7106672a1cf2b43091faa12de98d5cf400872e1fcbe6e1891ba5d185ae","src/lib.rs":"130872ae9e213c8705592f3e1eac3245029f93e2c22c8f2337e3ecea25152d49","src/transaction.rs":"adaeecac01dc5886b90ab4ef03889ddd136ce26206dfa8f8da7410f0db80a742","src/types.rs":"d0c3ebc2aaab2f0fac426e60701acefa435c91812540d52dba1532664a0301ee","tests/reg_key.rs":"8a59b554230545e15a3affa82fb6d9061b45ac15e777df6cc383b725b8f4ad93"},"package":"80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"} \ No newline at end of file diff --git a/third_party/rust/winreg/Cargo.lock b/third_party/rust/winreg/Cargo.lock new file mode 100644 index 000000000000..e021632fd1e7 --- /dev/null +++ b/third_party/rust/winreg/Cargo.lock @@ -0,0 +1,350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "libc" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg 1.0.1", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +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.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[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 = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +dependencies = [ + "cfg-if", + "libc", + "rand 0.6.5", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[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.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[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" + +[[package]] +name = "winreg" +version = "0.10.1" +dependencies = [ + "chrono", + "rand 0.3.23", + "serde", + "serde_derive", + "tempfile", + "winapi", +] diff --git a/third_party/rust/winreg/Cargo.toml b/third_party/rust/winreg/Cargo.toml index c5fd6511164a..adb2e88655c9 100644 --- a/third_party/rust/winreg/Cargo.toml +++ b/third_party/rust/winreg/Cargo.toml @@ -3,7 +3,7 @@ # 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 +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,22 +12,29 @@ [package] name = "winreg" -version = "0.5.1" +version = "0.10.1" authors = ["Igor Shaula "] description = "Rust bindings to MS Windows Registry API" -documentation = "https://gentoo90.github.io/winreg-rs/v0.5.1/winreg" +documentation = "https://docs.rs/winreg" readme = "README.md" keywords = ["Windows", "WinSDK", "Registry"] categories = ["api-bindings", "os::windows-apis"] license = "MIT" repository = "https://github.com/gentoo90/winreg-rs" +[package.metadata.docs.rs] +all-features = true +targets = ["x86_64-pc-windows-msvc", "i686-pc-windows-msvc"] [[example]] name = "basic_usage" +required-features = ["chrono"] [[example]] name = "enum" +[[example]] +name = "load_app_key" + [[example]] name = "transactions" required-features = ["transactions"] @@ -36,11 +43,15 @@ required-features = ["transactions"] name = "serialization" required-features = ["serialization-serde"] +[[example]] +name = "map_key_serialization" +required-features = ["serialization-serde"] + [[example]] name = "installed_apps" required-features = ["serialization-serde"] -[dependencies.clippy] -version = "^0" +[dependencies.chrono] +version = "0.4.6" optional = true [dependencies.serde] @@ -48,14 +59,17 @@ version = "1" optional = true [dependencies.winapi] -version = "0.3" -features = ["minwindef", "winerror", "winnt", "winreg", "handleapi"] +version = "0.3.9" +features = ["impl-default", "impl-debug", "minwindef", "minwinbase", "timezoneapi", "winerror", "winnt", "winreg", "handleapi"] [dev-dependencies.rand] version = "0.3" [dev-dependencies.serde_derive] version = "1" +[dev-dependencies.tempfile] +version = "~3.0" + [features] serialization-serde = ["transactions", "serde"] transactions = ["winapi/ktmw32"] diff --git a/third_party/rust/winreg/README.md b/third_party/rust/winreg/README.md index 52b1807c5b9d..2683a0619f7b 100644 --- a/third_party/rust/winreg/README.md +++ b/third_party/rust/winreg/README.md @@ -1,20 +1,33 @@ -winreg [![Crates.io](https://img.shields.io/crates/v/winreg.svg)](https://crates.io/crates/winreg) [![Build status](https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true)](https://ci.appveyor.com/project/gentoo90/winreg-rs) +winreg +[![Winreg on Appveyor][appveyor-image]][appveyor] +[![Winreg on crates.io][cratesio-image]][cratesio] +[![Winreg on docs.rs][docsrs-image]][docsrs] ====== +[appveyor-image]: https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true +[appveyor]: https://ci.appveyor.com/project/gentoo90/winreg-rs +[cratesio-image]: https://img.shields.io/crates/v/winreg.svg +[cratesio]: https://crates.io/crates/winreg +[docsrs-image]: https://docs.rs/winreg/badge.svg +[docsrs]: https://docs.rs/winreg + Rust bindings to MS Windows Registry API. Work in progress. Current features: * Basic registry operations: * open/create/delete keys + * load application hive from a file * read and write values * seamless conversion between `REG_*` types and rust primitives * `String` and `OsString` <= `REG_SZ`, `REG_EXPAND_SZ` or `REG_MULTI_SZ` - * `String`, `&str` and `OsStr` => `REG_SZ` + * `String`, `&str`, `OsString`, `&OsStr` => `REG_SZ` + * `Vec`, `Vec` <= `REG_MULTI_SZ` + * `Vec`, `Vec<&str>`, `Vec`, `Vec<&OsStr>` => `REG_MULTI_SZ` * `u32` <=> `REG_DWORD` * `u64` <=> `REG_QWORD` * Iteration through key names and through values * Transactions -* Transacted serialization of rust types into/from registry (only primitives and structures for now) +* Transacted serialization of rust types into/from registry (only primitives, structures and maps for now) ## Usage @@ -23,54 +36,75 @@ Current features: ```toml # Cargo.toml [dependencies] -winreg = "0.5" +winreg = "0.10" ``` ```rust extern crate winreg; -use std::path::Path; use std::io; -use winreg::RegKey; +use std::path::Path; use winreg::enums::*; +use winreg::RegKey; -fn main() { +fn main() -> io::Result<()> { println!("Reading some system info..."); let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion").unwrap(); - let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap(); - let dp: String = cur_ver.get_value("DevicePath").unwrap(); + let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; + let pf: String = cur_ver.get_value("ProgramFilesDir")?; + let dp: String = cur_ver.get_value("DevicePath")?; println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); - let info = cur_ver.query_info().unwrap(); + let info = cur_ver.query_info()?; println!("info = {:?}", info); + let mt = info.get_last_write_time_system(); + println!( + "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", + mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond + ); + + // enable `chrono` feature on `winreg` to make this work + // println!( + // "last_write_time as chrono::NaiveDateTime = {}", + // info.get_last_write_time_chrono() + // ); println!("And now lets write something..."); let hkcu = RegKey::predef(HKEY_CURRENT_USER); let path = Path::new("Software").join("WinregRsExample1"); - let key = hkcu.create_subkey(&path).unwrap(); + let (key, disp) = hkcu.create_subkey(&path)?; - key.set_value("TestSZ", &"written by Rust").unwrap(); - let sz_val: String = key.get_value("TestSZ").unwrap(); - key.delete_value("TestSZ").unwrap(); + match disp { + REG_CREATED_NEW_KEY => println!("A new key has been created"), + REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), + } + + key.set_value("TestSZ", &"written by Rust")?; + let sz_val: String = key.get_value("TestSZ")?; + key.delete_value("TestSZ")?; println!("TestSZ = {}", sz_val); - key.set_value("TestDWORD", &1234567890u32).unwrap(); - let dword_val: u32 = key.get_value("TestDWORD").unwrap(); + key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; + let multi_sz_val: Vec = key.get_value("TestMultiSZ")?; + key.delete_value("TestMultiSZ")?; + println!("TestMultiSZ = {:?}", multi_sz_val); + + key.set_value("TestDWORD", &1234567890u32)?; + let dword_val: u32 = key.get_value("TestDWORD")?; println!("TestDWORD = {}", dword_val); - key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); - let qword_val: u64 = key.get_value("TestQWORD").unwrap(); + key.set_value("TestQWORD", &1234567891011121314u64)?; + let qword_val: u64 = key.get_value("TestQWORD")?; println!("TestQWORD = {}", qword_val); - key.create_subkey("sub\\key").unwrap(); - hkcu.delete_subkey_all(&path).unwrap(); + key.create_subkey("sub\\key")?; + hkcu.delete_subkey_all(&path)?; println!("Trying to open nonexistent key..."); - let key2 = hkcu.open_subkey(&path) - .unwrap_or_else(|e| match e.kind() { + hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() { io::ErrorKind::NotFound => panic!("Key doesn't exist"), io::ErrorKind::PermissionDenied => panic!("Access denied"), - _ => panic!("{:?}", e) + _ => panic!("{:?}", e), }); + Ok(()) } ``` @@ -78,10 +112,11 @@ fn main() { ```rust extern crate winreg; +use std::io; use winreg::RegKey; use winreg::enums::*; -fn main() { +fn main() -> io::Result<()> { println!("File extensions, registered in system:"); for i in RegKey::predef(HKEY_CLASSES_ROOT) .enum_keys().map(|x| x.unwrap()) @@ -91,11 +126,12 @@ fn main() { } let system = RegKey::predef(HKEY_LOCAL_MACHINE) - .open_subkey("HARDWARE\\DESCRIPTION\\System") - .unwrap(); + .open_subkey("HARDWARE\\DESCRIPTION\\System")?; for (name, value) in system.enum_values().map(|x| x.unwrap()) { println!("{} = {:?}", name, value); } + + Ok(()) } ``` @@ -104,7 +140,7 @@ fn main() { ```toml # Cargo.toml [dependencies] -winreg = { version = "0.5", features = ["transactions"] } +winreg = { version = "0.10", features = ["transactions"] } ``` ```rust @@ -114,28 +150,30 @@ use winreg::RegKey; use winreg::enums::*; use winreg::transaction::Transaction; -fn main() { - let t = Transaction::new().unwrap(); +fn main() -> io::Result<()> { + let t = Transaction::new()?; let hkcu = RegKey::predef(HKEY_CURRENT_USER); - let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); - key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); - key.set_value("TestDWORD", &1234567890u32).unwrap(); + let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; + key.set_value("TestQWORD", &1234567891011121314u64)?; + key.set_value("TestDWORD", &1234567890u32)?; println!("Commit transaction? [y/N]:"); let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); + io::stdin().read_line(&mut input)?; input = input.trim_right().to_owned(); if input == "y" || input == "Y" { - t.commit().unwrap(); + t.commit()?; println!("Transaction committed."); } else { // this is optional, if transaction wasn't committed, // it will be rolled back on disposal - t.rollback().unwrap(); + t.rollback()?; println!("Transaction wasn't committed, it will be rolled back."); } + + Ok(()) } ``` @@ -144,7 +182,7 @@ fn main() { ```toml # Cargo.toml [dependencies] -winreg = { version = "0.5", features = ["serialization-serde"] } +winreg = { version = "0.10", features = ["serialization-serde"] } serde = "1" serde_derive = "1" ``` @@ -152,18 +190,29 @@ serde_derive = "1" ```rust #[macro_use] extern crate serde_derive; -extern crate serde; extern crate winreg; +use std::collections::HashMap; +use std::error::Error; use winreg::enums::*; #[derive(Debug, Serialize, Deserialize, PartialEq)] -struct Rectangle{ +struct Coords { x: u32, y: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Size { w: u32, h: u32, } +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Rectangle { + coords: Coords, + size: Size, +} + #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Test { t_bool: bool, @@ -173,7 +222,10 @@ struct Test { t_u64: u64, t_usize: usize, t_struct: Rectangle, + t_map: HashMap, t_string: String, + #[serde(rename = "")] // empty name becomes the (Default) value in the registry + t_char: char, t_i8: i8, t_i16: i16, t_i32: i32, @@ -183,44 +235,102 @@ struct Test { t_f32: f32, } -fn main() { +fn main() -> Result<(), Box> { let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); - let key = hkcu.create_subkey("Software\\RustEncode").unwrap(); - let v1 = Test{ + let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; + + let mut map = HashMap::new(); + map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry + map.insert("v1".to_owned(), 1); + map.insert("v2".to_owned(), 2); + map.insert("v3".to_owned(), 3); + + let v1 = Test { t_bool: false, t_u8: 127, t_u16: 32768, - t_u32: 123456789, - t_u64: 123456789101112, - t_usize: 123456789101112, - t_struct: Rectangle{ - x: 55, - y: 77, - w: 500, - h: 300, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, }, + t_map: map, t_string: "test 123!".to_owned(), + t_char: 'a', t_i8: -123, t_i16: -2049, t_i32: 20100, - t_i64: -12345678910, - t_isize: -1234567890, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, t_f64: -0.01, - t_f32: 3.14, + t_f32: 3.15, }; - key.encode(&v1).unwrap(); + key.encode(&v1)?; - let v2: Test = key.decode().unwrap(); + let v2: Test = key.decode()?; println!("Decoded {:?}", v2); - // This shows `false` because f32 and f64 encoding/decoding is NOT precise println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) } ``` ## Changelog +### 0.10.1 + +* Bump minimal required version of `winapi` to `0.3.9` (required for `load_app_key`) +* Reexport `REG_PROCESS_APPKEY` and use it in the `load_app_key` example + +### 0.10.0 + +* Add `RegKey::load_app_key()` and `RegKey::load_app_key_with_flags()` ([#30](https://github.com/gentoo90/winreg-rs/issues/30)) +* Update dev dependency `rand` to `0.8` +* Add Github actions +* Fix some clippy warnings + +### 0.9.0 + +* Breaking change: `OsStr` and `OsString` registry values are not `NULL`-terminated any more ([#34](https://github.com/gentoo90/winreg-rs/issues/34), [#42](https://github.com/gentoo90/winreg-rs/issues/42)) +* Refactoring: use macros for `ToRegValue` impls and tests for string values +* Fix `bare_trait_objects` warning in the doctests +* Add `impl ToRegValue for OsString` +* Add conversion between `REG_MULTI_SZ` and vectors of strings ([#16](https://github.com/gentoo90/winreg-rs/issues/16)) +* Fix: set minimal `winapi` version to 0.3.7 (earlier versions don't have `impl-default` and `impl-debug` features which we use) +* Appveyor now checks the crate against `rust-1.31.1` too + +### 0.8.0 + +* Implement serialization of `char` and maps +* Implement `std::fmt::Display` for `RegValue` +* Make `RegKey::{predef,raw_handle,enum_keys,enum_values}` functions `const` +* Give a better error message when compiling on platforms other than Windows ([#38](https://github.com/gentoo90/winreg-rs/pull/38)) +* Tests are moved from `src/lib.rs` to `tests/reg_key.rs` + +### 0.7.0 + +* Breaking change: remove deprecated `Error::description` ([#28](https://github.com/gentoo90/winreg-rs/pull/28)) +* Optimize `Iterator::nth()` for the `Enum*` iterators ([#29](https://github.com/gentoo90/winreg-rs/pull/29)) + +### 0.6.2 + +* Add `RegKey::delete_subkey_with_flags()` ([#27](https://github.com/gentoo90/winreg-rs/pull/27)) + +### 0.6.1 + +* Add `last_write_time` field to `RegKeyMetadata` (returned by `RegKey::query_info()`) ([#25](https://github.com/gentoo90/winreg-rs/pull/25)). +* Add `get_last_write_time_system()` and `get_last_write_time_chrono()` (under `chrono` feature) methods to `RegKeyMetadata`. + +### 0.6.0 + +* Breaking change: `create_subkey`, `create_subkey_with_flags`, `create_subkey_transacted` and +`create_subkey_transacted_with_flags` now return a tuple which contains the subkey and its disposition +which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY` ([#21](https://github.com/gentoo90/winreg-rs/issues/21)). +* Examples fixed to not use `unwrap` according to [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/documentation.html#examples-use--not-try-not-unwrap-c-question-mark). + ### 0.5.1 * Reexport `HKEY` ([#15](https://github.com/gentoo90/winreg-rs/issues/15)). @@ -232,7 +342,7 @@ fn main() { Use `create_subkey` or `open_subkey_with_flags` to open with read-write permissins. * Breaking change: features `transactions` and `serialization-serde` are now disabled by default. * Breaking change: serialization now uses `serde` instead of `rustc-serialize`. -* `winreg` updated to `0.3`. +* `winapi` updated to `0.3`. * Documentation fixes ([#14](https://github.com/gentoo90/winreg-rs/pull/14)) ### 0.4.0 diff --git a/third_party/rust/winreg/appveyor.yml b/third_party/rust/winreg/appveyor.yml index 24aaf3e27980..b690b6a0cb54 100644 --- a/third_party/rust/winreg/appveyor.yml +++ b/third_party/rust/winreg/appveyor.yml @@ -1,11 +1,17 @@ -version: 0.5.{build} +version: 0.10.{build} pull_requests: do_not_increment_build_number: true +branches: + except: + - github-actions + os: Visual Studio 2015 environment: matrix: + - TARGET: x86_64-pc-windows-msvc + CHANNEL: 1.31.1 - TARGET: x86_64-pc-windows-gnu CHANNEL: stable - TARGET: x86_64-pc-windows-msvc @@ -17,7 +23,7 @@ environment: install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y + - rustup-init.exe --profile=minimal --component rustfmt,clippy --default-host %TARGET% --default-toolchain %CHANNEL% -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -Vv - cargo -V @@ -25,4 +31,7 @@ install: build: false test_script: - - cargo test --features=serialization-serde + - if not "%CHANNEL%"=="1.31.1" cargo fmt --all -- --check + - if not "%CHANNEL%"=="1.31.1" cargo clippy --all-features --all-targets + - cargo test --release --no-default-features + - cargo test --release --all-features diff --git a/third_party/rust/winreg/build.rs b/third_party/rust/winreg/build.rs new file mode 100644 index 000000000000..7acab766409a --- /dev/null +++ b/third_party/rust/winreg/build.rs @@ -0,0 +1,11 @@ +fn main() { + if std::env::var("CARGO_CFG_WINDOWS").is_err() { + eprintln!("error: winreg is only supported on Windows platforms"); + eprintln!( + "help: if your application is multi-platform, use \ + `[target.'cfg(windows)'.dependencies] winreg = \"...\"`" + ); + eprintln!("help: if your application is only supported on Windows, use `--target x86_64-pc-windows-gnu` or some other windows platform"); + std::process::exit(1); + } +} diff --git a/third_party/rust/winreg/examples/basic_usage.rs b/third_party/rust/winreg/examples/basic_usage.rs index 2a7a8c02d35d..6422e9eeb29c 100644 --- a/third_party/rust/winreg/examples/basic_usage.rs +++ b/third_party/rust/winreg/examples/basic_usage.rs @@ -4,47 +4,66 @@ // may not be copied, modified, or distributed // except according to those terms. extern crate winreg; -use std::path::Path; use std::io; -use winreg::RegKey; +use std::path::Path; use winreg::enums::*; +use winreg::RegKey; -fn main() { +fn main() -> io::Result<()> { println!("Reading some system info..."); let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion").unwrap(); - let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap(); - let dp: String = cur_ver.get_value("DevicePath").unwrap(); + let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; + let pf: String = cur_ver.get_value("ProgramFilesDir")?; + let dp: String = cur_ver.get_value("DevicePath")?; println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); - let info = cur_ver.query_info().unwrap(); + let info = cur_ver.query_info()?; println!("info = {:?}", info); + let mt = info.get_last_write_time_system(); + println!( + "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", + mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond + ); + println!( + "last_write_time as chrono::NaiveDateTime = {}", + info.get_last_write_time_chrono() + ); println!("And now lets write something..."); let hkcu = RegKey::predef(HKEY_CURRENT_USER); let path = Path::new("Software").join("WinregRsExample1"); - let key = hkcu.create_subkey(&path).unwrap(); + let (key, disp) = hkcu.create_subkey(&path)?; - key.set_value("TestSZ", &"written by Rust").unwrap(); - let sz_val: String = key.get_value("TestSZ").unwrap(); - key.delete_value("TestSZ").unwrap(); + match disp { + REG_CREATED_NEW_KEY => println!("A new key has been created"), + REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), + } + + key.set_value("TestSZ", &"written by Rust")?; + let sz_val: String = key.get_value("TestSZ")?; + key.delete_value("TestSZ")?; println!("TestSZ = {}", sz_val); - key.set_value("TestDWORD", &1234567890u32).unwrap(); - let dword_val: u32 = key.get_value("TestDWORD").unwrap(); + key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; + let multi_sz_val: Vec = key.get_value("TestMultiSZ")?; + key.delete_value("TestMultiSZ")?; + println!("TestMultiSZ = {:?}", multi_sz_val); + + key.set_value("TestDWORD", &1_234_567_890u32)?; + let dword_val: u32 = key.get_value("TestDWORD")?; println!("TestDWORD = {}", dword_val); - key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); - let qword_val: u64 = key.get_value("TestQWORD").unwrap(); + key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?; + let qword_val: u64 = key.get_value("TestQWORD")?; println!("TestQWORD = {}", qword_val); - key.create_subkey("sub\\key").unwrap(); - hkcu.delete_subkey_all(&path).unwrap(); + key.create_subkey("sub\\key")?; + hkcu.delete_subkey_all(&path)?; println!("Trying to open nonexistent key..."); - hkcu.open_subkey(&path) - .unwrap_or_else(|e| match e.kind() { + hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() { io::ErrorKind::NotFound => panic!("Key doesn't exist"), io::ErrorKind::PermissionDenied => panic!("Access denied"), - _ => panic!("{:?}", e) + _ => panic!("{:?}", e), }); + Ok(()) } diff --git a/third_party/rust/winreg/examples/enum.rs b/third_party/rust/winreg/examples/enum.rs index 9940cfc477fc..dd1a78d8702f 100644 --- a/third_party/rust/winreg/examples/enum.rs +++ b/third_party/rust/winreg/examples/enum.rs @@ -4,22 +4,24 @@ // may not be copied, modified, or distributed // except according to those terms. extern crate winreg; -use winreg::RegKey; +use std::io; use winreg::enums::*; +use winreg::RegKey; -fn main() { +fn main() -> io::Result<()> { println!("File extensions, registered in system:"); for i in RegKey::predef(HKEY_CLASSES_ROOT) - .enum_keys().map(|x| x.unwrap()) - .filter(|x| x.starts_with(".")) + .enum_keys() + .map(|x| x.unwrap()) + .filter(|x| x.starts_with('.')) { println!("{}", i); } - let system = RegKey::predef(HKEY_LOCAL_MACHINE) - .open_subkey("HARDWARE\\DESCRIPTION\\System") - .unwrap(); + let system = RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey("HARDWARE\\DESCRIPTION\\System")?; for (name, value) in system.enum_values().map(|x| x.unwrap()) { println!("{} = {:?}", name, value); } + + Ok(()) } diff --git a/third_party/rust/winreg/examples/installed_apps.rs b/third_party/rust/winreg/examples/installed_apps.rs index f7d555b90da2..a7546847db77 100644 --- a/third_party/rust/winreg/examples/installed_apps.rs +++ b/third_party/rust/winreg/examples/installed_apps.rs @@ -6,38 +6,45 @@ #[macro_use] extern crate serde_derive; extern crate winreg; -use winreg::enums::*; use std::collections::HashMap; use std::fmt; +use winreg::enums::*; #[allow(non_snake_case)] #[derive(Debug, Serialize, Deserialize)] struct InstalledApp { DisplayName: Option, DisplayVersion: Option, - UninstallString: Option + UninstallString: Option, } macro_rules! str_from_opt { - ($s:expr) => { $s.as_ref().map(|x| &**x).unwrap_or("") } + ($s:expr) => { + $s.as_ref().map(|x| &**x).unwrap_or("") + }; } impl fmt::Display for InstalledApp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}-{}", + write!( + f, + "{}-{}", str_from_opt!(self.DisplayName), - str_from_opt!(self.DisplayVersion)) + str_from_opt!(self.DisplayVersion) + ) } } fn main() { let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); - let uninstall_key = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") + let uninstall_key = hklm + .open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") .expect("key is missing"); - let apps: HashMap = uninstall_key.decode().expect("deserialization failed"); + let apps: HashMap = + uninstall_key.decode().expect("deserialization failed"); - for (_k, v) in &apps { + for v in apps.values() { println!("{}", v); } } diff --git a/third_party/rust/winreg/examples/load_app_key.rs b/third_party/rust/winreg/examples/load_app_key.rs new file mode 100644 index 000000000000..2340c82b591f --- /dev/null +++ b/third_party/rust/winreg/examples/load_app_key.rs @@ -0,0 +1,26 @@ +// Copyright 2021, Igor Shaula +// Licensed under the MIT License . This file +// may not be copied, modified, or distributed +// except according to those terms. +extern crate winreg; +use std::io; +use winreg::enums::*; +use winreg::RegKey; + +fn main() -> io::Result<()> { + { + // put this in a block so app_key_1 gets out of scope and doesn't prevent us + // from loading the key again later + let app_key_1 = RegKey::load_app_key("myhive.dat", true)?; + app_key_1.set_value("answer", &42u32)?; + } + let answer: u32 = { + // NOTE: on Windows 7 this fails with ERROR_ALREADY_EXISTS + let app_key_2 = + RegKey::load_app_key_with_flags("myhive.dat", KEY_READ, REG_PROCESS_APPKEY)?; + app_key_2.get_value("answer")? + }; + println!("The Answer is {}", answer); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/map_key_serialization.rs b/third_party/rust/winreg/examples/map_key_serialization.rs new file mode 100644 index 000000000000..c0be70491345 --- /dev/null +++ b/third_party/rust/winreg/examples/map_key_serialization.rs @@ -0,0 +1,57 @@ +// Copyright 2020, Igor Shaula +// Licensed under the MIT License . This file +// may not be copied, modified, or distributed +// except according to those terms. +#[macro_use] +extern crate serde_derive; +extern crate winreg; +use std::collections::HashMap; +use std::error::Error; +use winreg::enums::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Coords { + x: u32, + y: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Size { + w: u32, + h: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Rectangle { + coords: Coords, + size: Size, +} + +fn main() -> Result<(), Box> { + let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey("Software\\RustEncodeMapKey")?; + let mut v1 = HashMap::new(); + v1.insert( + "first".to_owned(), + Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, + }, + ); + v1.insert( + "second".to_owned(), + Rectangle { + coords: Coords { x: 11, y: 22 }, + size: Size { w: 1000, h: 600 }, + }, + ); + + key.encode(&v1)?; + + let v2: HashMap = key.decode()?; + println!("Decoded {:?}", v2); + + println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/serialization.rs b/third_party/rust/winreg/examples/serialization.rs index bc8c5c7ee9ae..462813291af3 100644 --- a/third_party/rust/winreg/examples/serialization.rs +++ b/third_party/rust/winreg/examples/serialization.rs @@ -6,6 +6,8 @@ #[macro_use] extern crate serde_derive; extern crate winreg; +use std::collections::HashMap; +use std::error::Error; use winreg::enums::*; #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -35,7 +37,10 @@ struct Test { t_u64: u64, t_usize: usize, t_struct: Rectangle, + t_map: HashMap, t_string: String, + #[serde(rename = "")] // empty name becomes the (Default) value in the registry + t_char: char, t_i8: i8, t_i16: i16, t_i32: i32, @@ -43,39 +48,46 @@ struct Test { t_isize: isize, t_f64: f64, t_f32: f32, - // t_char: char, } -fn main() { +fn main() -> Result<(), Box> { let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); - let key = hkcu.create_subkey("Software\\RustEncode").unwrap(); - let v1 = Test{ + let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; + + let mut map = HashMap::new(); + map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry + map.insert("v1".to_owned(), 1); + map.insert("v2".to_owned(), 2); + map.insert("v3".to_owned(), 3); + + let v1 = Test { t_bool: false, t_u8: 127, t_u16: 32768, - t_u32: 123456789, - t_u64: 123456789101112, - t_usize: 1234567891, - t_struct: Rectangle{ - coords: Coords{ x: 55, y: 77 }, - size: Size{ w: 500, h: 300 }, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, }, + t_map: map, t_string: "test 123!".to_owned(), + t_char: 'a', t_i8: -123, t_i16: -2049, t_i32: 20100, - t_i64: -12345678910, - t_isize: -1234567890, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, t_f64: -0.01, - t_f32: 3.14, - // t_char: 'a', + t_f32: 3.15, }; - key.encode(&v1).unwrap(); + key.encode(&v1)?; - let v2: Test = key.decode().unwrap(); + let v2: Test = key.decode()?; println!("Decoded {:?}", v2); - // This shows `false` because f32 and f64 encoding/decoding is NOT precise println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) } diff --git a/third_party/rust/winreg/examples/transactions.rs b/third_party/rust/winreg/examples/transactions.rs index 9824f1b62e05..4cc91b7c9fd4 100644 --- a/third_party/rust/winreg/examples/transactions.rs +++ b/third_party/rust/winreg/examples/transactions.rs @@ -5,30 +5,31 @@ // except according to those terms. extern crate winreg; use std::io; -use winreg::RegKey; use winreg::enums::*; use winreg::transaction::Transaction; +use winreg::RegKey; -fn main() { - let t = Transaction::new().unwrap(); +fn main() -> io::Result<()> { + let t = Transaction::new()?; let hkcu = RegKey::predef(HKEY_CURRENT_USER); - let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); - key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); - key.set_value("TestDWORD", &1234567890u32).unwrap(); + let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; + key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?; + key.set_value("TestDWORD", &1_234_567_890u32)?; println!("Commit transaction? [y/N]:"); let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - input = input.trim_right().to_owned(); + io::stdin().read_line(&mut input)?; + input = input.trim_end().to_owned(); if input == "y" || input == "Y" { - t.commit().unwrap(); - println!("Transaction commited."); - } - else { - // this is optional, if transaction wasn't commited, + t.commit()?; + println!("Transaction committed."); + } else { + // this is optional, if transaction wasn't committed, // it will be rolled back on disposal - t.rollback().unwrap(); + t.rollback()?; - println!("Transaction wasn't commited, it will be rolled back."); + println!("Transaction wasn't committed, it will be rolled back."); } + + Ok(()) } diff --git a/third_party/rust/winreg/src/decoder/mod.rs b/third_party/rust/winreg/src/decoder/mod.rs index e832050a7e79..82493b846d01 100644 --- a/third_party/rust/winreg/src/decoder/mod.rs +++ b/third_party/rust/winreg/src/decoder/mod.rs @@ -3,42 +3,41 @@ // http://opensource.org/licenses/MIT>. This file // may not be copied, modified, or distributed // except according to those terms. -use std::io; -use std::fmt; -use std::error::Error; -use winapi::shared::minwindef::DWORD; -use super::{RegKey}; use super::enums::*; +use super::RegKey; +use std::error::Error; +use std::fmt; +use std::io; +use winapi::shared::minwindef::DWORD; -macro_rules! read_value{ - ($s:ident) => ( +macro_rules! read_value { + ($s:ident) => { match mem::replace(&mut $s.f_name, None) { - Some(ref s) => { - $s.key.get_value(s) - .map_err(DecoderError::IoError) - }, - None => Err(DecoderError::NoFieldName) + Some(ref s) => $s.key.get_value(s).map_err(DecoderError::IoError), + None => Err(DecoderError::NoFieldName), } - ) + }; } -macro_rules! parse_string{ - ($s:ident) => ({ +macro_rules! parse_string { + ($s:ident) => {{ let s: String = read_value!($s)?; - s.parse().map_err(|e| DecoderError::ParseError(format!("{:?}", e))) - }) + s.parse() + .map_err(|e| DecoderError::ParseError(format!("{:?}", e))) + }}; } macro_rules! no_impl { - ($e:expr) => ( + ($e:expr) => { Err(DecoderError::DecodeNotImplemented($e.to_owned())) - ) + }; } -#[cfg(feature = "serialization-serde")] mod serialization_serde; +#[cfg(feature = "serialization-serde")] +mod serialization_serde; #[derive(Debug)] -pub enum DecoderError{ +pub enum DecoderError { DecodeNotImplemented(String), DeserializerError(String), IoError(io::Error), @@ -52,16 +51,7 @@ impl fmt::Display for DecoderError { } } -impl Error for DecoderError { - fn description(&self) -> &str { - use self::DecoderError::*; - match *self { - DecodeNotImplemented(ref s) | DeserializerError(ref s) | ParseError(ref s) => s, - IoError(ref e) => e.description(), - NoFieldName => "No field name" - } - } -} +impl Error for DecoderError {} impl From for DecoderError { fn from(err: io::Error) -> DecoderError { @@ -101,11 +91,11 @@ impl Decoder { } fn new(key: RegKey) -> Decoder { - Decoder{ - key: key, + Decoder { + key, f_name: None, reading_state: DecoderReadingState::WaitingForKey, - enumeration_state: DecoderEnumerationState::EnumeratingKeys(0) + enumeration_state: DecoderEnumerationState::EnumeratingKeys(0), } } } diff --git a/third_party/rust/winreg/src/decoder/serialization_serde.rs b/third_party/rust/winreg/src/decoder/serialization_serde.rs index 0c8aec5984b7..1287540448f9 100644 --- a/third_party/rust/winreg/src/decoder/serialization_serde.rs +++ b/third_party/rust/winreg/src/decoder/serialization_serde.rs @@ -3,11 +3,13 @@ // http://opensource.org/licenses/MIT>. This file // may not be copied, modified, or distributed // except according to those terms. -use std::mem; -use std::fmt; -use serde::de::*; -use super::{DecoderError, DecodeResult, DecoderReadingState, DecoderEnumerationState, Decoder, DECODER_SAM}; use super::super::FromRegValue; +use super::{ + DecodeResult, Decoder, DecoderEnumerationState, DecoderError, DecoderReadingState, DECODER_SAM, +}; +use serde::de::*; +use std::fmt; +use std::mem; impl Error for DecoderError { fn custom(msg: T) -> Self { @@ -17,7 +19,10 @@ impl Error for DecoderError { impl<'de, 'a> Deserializer<'de> for &'a mut Decoder { type Error = DecoderError; - fn deserialize_any(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_any(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { use self::DecoderEnumerationState::*; match self.enumeration_state { EnumeratingKeys(..) => no_impl!("deserialize_any for keys"), @@ -26,138 +31,245 @@ impl<'de, 'a> Deserializer<'de> for &'a mut Decoder { let v = self.key.get_raw_value(s)?; use RegType::*; match v.vtype { - REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => visitor.visit_string(String::from_reg_value(&v)?), + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { + visitor.visit_string(String::from_reg_value(&v)?) + } REG_DWORD => visitor.visit_u32(u32::from_reg_value(&v)?), REG_QWORD => visitor.visit_u64(u64::from_reg_value(&v)?), - _ => Err(DecoderError::DecodeNotImplemented("value type deserialization not implemented".to_owned())) + _ => Err(DecoderError::DecodeNotImplemented( + "value type deserialization not implemented".to_owned(), + )), } } } } - fn deserialize_bool(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_bool(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_bool(read_value!(self).map(|v: u32| v > 0)?) } - fn deserialize_u8(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_u8(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { self.deserialize_u32(visitor) } - fn deserialize_u16(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_u16(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { self.deserialize_u32(visitor) } - fn deserialize_u32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_u32(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_u32(read_value!(self)?) } - fn deserialize_u64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_u64(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_u64(read_value!(self)?) } - fn deserialize_i8(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_i8(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_i8(parse_string!(self)?) } - fn deserialize_i16(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_i16(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_i16(parse_string!(self)?) } - fn deserialize_i32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_i32(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_i32(parse_string!(self)?) } - fn deserialize_i64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_i64(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_i64(parse_string!(self)?) } - fn deserialize_f32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_f32(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_f32(parse_string!(self)?) } - fn deserialize_f64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_f64(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_f64(parse_string!(self)?) } - fn deserialize_char(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { - no_impl!("deserialize_char") + fn deserialize_char(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) } - fn deserialize_str(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_str(self, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_str") } - fn deserialize_string(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_string(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { use self::DecoderReadingState::*; match self.reading_state { WaitingForKey => { let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; visitor.visit_string(s.clone()) } - WaitingForValue => visitor.visit_string(read_value!(self)?) + WaitingForValue => visitor.visit_string(read_value!(self)?), } } - fn deserialize_bytes(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_bytes(self, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_bytes") } - fn deserialize_byte_buf(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_byte_buf(self, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_byte_buf") } - fn deserialize_option(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_option(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { let v = { let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; self.key.get_raw_value(s) }; match v { Ok(..) => visitor.visit_some(&mut *self), - Err(..) => visitor.visit_none() + Err(..) => visitor.visit_none(), } } - fn deserialize_unit(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_unit(self, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_unit") } - fn deserialize_unit_struct(self, _name: &'static str, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_unit_struct(self, _name: &'static str, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_unit_struct") } - fn deserialize_newtype_struct(self, _name: &'static str, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_newtype_struct( + self, + _name: &'static str, + _visitor: V, + ) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_newtype_struct") } - fn deserialize_seq(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_seq(self, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_seq") } - fn deserialize_tuple(self, _len: usize, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_tuple(self, _len: usize, _visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_tuple") } - fn deserialize_tuple_struct(self, _name: &'static str, _len: usize, _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + _visitor: V, + ) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_tuple_struct") } - fn deserialize_map(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_map(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_map(self) } - fn deserialize_struct(self, _name: &'static str, _fields: &'static [&'static str], visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> DecodeResult + where + V: Visitor<'de>, + { visitor.visit_map(self) } - fn deserialize_identifier(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_identifier(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { self.deserialize_string(visitor) } - fn deserialize_enum(self, _name: &'static str, _variants: &'static [&'static str], _visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + _visitor: V, + ) -> DecodeResult + where + V: Visitor<'de>, + { no_impl!("deserialize_enum") } - fn deserialize_ignored_any(self, visitor: V) -> DecodeResult where V: Visitor<'de> { + fn deserialize_ignored_any(self, visitor: V) -> DecodeResult + where + V: Visitor<'de>, + { self.deserialize_any(visitor) } } @@ -165,24 +277,23 @@ impl<'de, 'a> Deserializer<'de> for &'a mut Decoder { impl<'de, 'a> MapAccess<'de> for Decoder { type Error = DecoderError; fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> - where K: DeserializeSeed<'de> + where + K: DeserializeSeed<'de>, { self.reading_state = DecoderReadingState::WaitingForKey; use self::DecoderEnumerationState::*; match self.enumeration_state { - EnumeratingKeys(index) => { - match self.key.enum_key(index) { - Some(res) => { - self.f_name = Some(res?); - self.enumeration_state = EnumeratingKeys(index + 1); - seed.deserialize(&mut *self).map(Some) - } - None => { - self.enumeration_state = EnumeratingValues(0); - self.next_key_seed(seed) - } + EnumeratingKeys(index) => match self.key.enum_key(index) { + Some(res) => { + self.f_name = Some(res?); + self.enumeration_state = EnumeratingKeys(index + 1); + seed.deserialize(&mut *self).map(Some) } - } + None => { + self.enumeration_state = EnumeratingValues(0); + self.next_key_seed(seed) + } + }, EnumeratingValues(index) => { let next_value = self.key.enum_value(index); match next_value { @@ -198,7 +309,8 @@ impl<'de, 'a> MapAccess<'de> for Decoder { } fn next_value_seed(&mut self, seed: V) -> Result - where V: DeserializeSeed<'de> + where + V: DeserializeSeed<'de>, { self.reading_state = DecoderReadingState::WaitingForValue; use self::DecoderEnumerationState::*; @@ -212,10 +324,8 @@ impl<'de, 'a> MapAccess<'de> for Decoder { } Err(err) => Err(DecoderError::IoError(err)), } - }, - EnumeratingValues(..) => { - seed.deserialize(&mut *self) } + EnumeratingValues(..) => seed.deserialize(&mut *self), } } } diff --git a/third_party/rust/winreg/src/encoder/mod.rs b/third_party/rust/winreg/src/encoder/mod.rs index dcb178397bba..f552dc05df7c 100644 --- a/third_party/rust/winreg/src/encoder/mod.rs +++ b/third_party/rust/winreg/src/encoder/mod.rs @@ -3,41 +3,42 @@ // http://opensource.org/licenses/MIT>. This file // may not be copied, modified, or distributed // except according to those terms. -use std::io; -use std::fmt; -use std::error::Error; -use winapi::shared::minwindef::DWORD; -use super::RegKey; +use self::EncoderState::*; use super::enums::*; use super::transaction::Transaction; -use self::EncoderState::*; +use super::RegKey; +use std::error::Error; +use std::fmt; +use std::io; +use winapi::shared::minwindef::DWORD; -macro_rules! emit_value{ - ($s:ident, $v:ident) => ( +macro_rules! emit_value { + ($s:ident, $v:ident) => { match mem::replace(&mut $s.state, Start) { - NextKey(ref s) => { - $s.keys[$s.keys.len()-1].set_value(s, &$v) - .map_err(EncoderError::IoError) - }, - Start => Err(EncoderError::NoFieldName) + NextKey(ref s) => $s.keys[$s.keys.len() - 1] + .set_value(s, &$v) + .map_err(EncoderError::IoError), + Start => Err(EncoderError::NoFieldName), } - ) + }; } macro_rules! no_impl { - ($e:expr) => ( + ($e:expr) => { Err(EncoderError::EncodeNotImplemented($e.to_owned())) - ) + }; } -#[cfg(feature = "serialization-serde")] mod serialization_serde; +#[cfg(feature = "serialization-serde")] +mod serialization_serde; #[derive(Debug)] -pub enum EncoderError{ +pub enum EncoderError { EncodeNotImplemented(String), SerializerError(String), IoError(io::Error), NoFieldName, + KeyMustBeAString, } impl fmt::Display for EncoderError { @@ -46,16 +47,7 @@ impl fmt::Display for EncoderError { } } -impl Error for EncoderError { - fn description(&self) -> &str { - use self::EncoderError::*; - match *self { - EncodeNotImplemented(ref s) | SerializerError(ref s) => s, - IoError(ref e) => e.description(), - NoFieldName => "No field name" - } - } -} +impl Error for EncoderError {} pub type EncodeResult = Result; @@ -79,11 +71,11 @@ pub struct Encoder { state: EncoderState, } -const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY|KEY_SET_VALUE; +const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY | KEY_SET_VALUE; impl Encoder { pub fn from_key(key: &RegKey) -> EncodeResult { - let tr = try!(Transaction::new()); + let tr = Transaction::new()?; key.open_subkey_transacted_with_flags("", &tr, ENCODER_SAM) .map(|k| Encoder::new(k, tr)) .map_err(EncoderError::IoError) @@ -92,9 +84,9 @@ impl Encoder { fn new(key: RegKey, tr: Transaction) -> Encoder { let mut keys = Vec::with_capacity(5); keys.push(key); - Encoder{ - keys: keys, - tr: tr, + Encoder { + keys, + tr, state: Start, } } diff --git a/third_party/rust/winreg/src/encoder/serialization_serde.rs b/third_party/rust/winreg/src/encoder/serialization_serde.rs index d46ba318369d..f764cce6ec0c 100644 --- a/third_party/rust/winreg/src/encoder/serialization_serde.rs +++ b/third_party/rust/winreg/src/encoder/serialization_serde.rs @@ -3,11 +3,11 @@ // http://opensource.org/licenses/MIT>. This file // may not be copied, modified, or distributed // except according to those terms. +use super::EncoderState::*; +use super::{EncodeResult, Encoder, EncoderError, ENCODER_SAM}; +use serde::ser::*; use std::fmt; use std::mem; -use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM}; -use super::EncoderState::*; -use serde::ser::*; impl Error for EncoderError { fn custom(msg: T) -> Self { @@ -15,7 +15,6 @@ impl Error for EncoderError { } } - impl<'a> Serializer for &'a mut Encoder { type Ok = (); type Error = EncoderError; @@ -24,8 +23,8 @@ impl<'a> Serializer for &'a mut Encoder { type SerializeTuple = TupleEncoder; type SerializeTupleStruct = TupleStructEncoder; type SerializeTupleVariant = TupleVariantEncoder; - type SerializeMap = MapEncoder<'a>; - type SerializeStruct = StructEncoder<'a>; + type SerializeMap = StructMapEncoder<'a>; + type SerializeStruct = StructMapEncoder<'a>; type SerializeStructVariant = StructVariantEncoder; fn serialize_bool(self, value: bool) -> EncodeResult { @@ -75,8 +74,10 @@ impl<'a> Serializer for &'a mut Encoder { emit_value!(self, s) } - fn serialize_char(self, _value: char) -> EncodeResult { - no_impl!("serialize_char") + fn serialize_char(self, value: char) -> EncodeResult { + let mut s = String::new(); + s.push(value); + emit_value!(self, s) } fn serialize_str(self, value: &str) -> EncodeResult { @@ -103,27 +104,30 @@ impl<'a> Serializer for &'a mut Encoder { no_impl!("serialize_unit_struct") } - fn serialize_unit_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str) - -> EncodeResult { + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> EncodeResult { no_impl!("serialize_unit_variant") } - fn serialize_newtype_struct(self, - _name: &'static str, - _value: &T) - -> EncodeResult { + fn serialize_newtype_struct( + self, + _name: &'static str, + _value: &T, + ) -> EncodeResult { no_impl!("serialize_newtype_struct") } - fn serialize_newtype_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T) - -> EncodeResult { + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> EncodeResult { no_impl!("serialize_newtype_variant") } @@ -135,42 +139,47 @@ impl<'a> Serializer for &'a mut Encoder { no_impl!("serialize_tuple") } - fn serialize_tuple_struct(self, - _name: &'static str, - _len: usize) - -> EncodeResult { + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult { no_impl!("serialize_tuple_struct") } - fn serialize_tuple_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> EncodeResult { + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult { no_impl!("serialize_tuple_variant") } fn serialize_map(self, _len: Option) -> EncodeResult { - Ok(MapEncoder { _enc: self }) - } - - fn serialize_struct(self, - _name: &'static str, - _len: usize) - -> EncodeResult { match mem::replace(&mut self.state, Start) { + // --- Start => { // root structure - Ok(StructEncoder { enc: self, is_root: true }) + Ok(StructMapEncoder { + enc: self, + is_root: true, + }) } NextKey(ref s) => { // nested structure - match self.keys[self.keys.len() - 1] - .create_subkey_transacted_with_flags(&s, &self.tr, ENCODER_SAM) { - Ok(subkey) => { + match self.keys[self.keys.len() - 1].create_subkey_transacted_with_flags( + &s, + &self.tr, + ENCODER_SAM, + ) { + Ok((subkey, _disp)) => { self.keys.push(subkey); - Ok(StructEncoder { enc: self, is_root: true }) + Ok(StructMapEncoder { + enc: self, + is_root: true, + }) } Err(err) => Err(EncoderError::IoError(err)), } @@ -178,12 +187,21 @@ impl<'a> Serializer for &'a mut Encoder { } } - fn serialize_struct_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> EncodeResult { + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult { + self.serialize_map(Some(_len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult { no_impl!("serialize_struct_variant") } } @@ -246,41 +264,224 @@ impl SerializeTupleVariant for TupleVariantEncoder { } } -pub struct MapEncoder<'a> { - _enc: &'a mut Encoder, +struct MapKeySerializer; + +impl serde::Serializer for MapKeySerializer { + type Ok = String; + type Error = EncoderError; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> EncodeResult { + Ok(variant.to_owned()) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> EncodeResult + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_i8(self, value: i8) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_i16(self, value: i16) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_i32(self, value: i32) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_i64(self, value: i64) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_u8(self, value: u8) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_u16(self, value: u16) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_u32(self, value: u32) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_u64(self, value: u64) -> EncodeResult { + Ok(value.to_string()) + } + + fn serialize_f32(self, _value: f32) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_f64(self, _value: f64) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + #[inline] + fn serialize_char(self, value: char) -> EncodeResult { + Ok({ + let mut s = String::new(); + s.push(value); + s + }) + } + + #[inline] + fn serialize_str(self, value: &str) -> EncodeResult { + Ok(value.to_owned()) + } + + fn serialize_bytes(self, _value: &[u8]) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_unit(self) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> EncodeResult + where + T: ?Sized + Serialize, + { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_none(self) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_some(self, _value: &T) -> EncodeResult + where + T: ?Sized + Serialize, + { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_seq(self, _len: Option) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple(self, _len: usize) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_map(self, _len: Option) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult { + Err(EncoderError::KeyMustBeAString) + } + + fn collect_str(self, value: &T) -> EncodeResult + where + T: fmt::Display, + { + Ok(value.to_string()) + } } -impl<'a> SerializeMap for MapEncoder<'a> { +pub struct StructMapEncoder<'a> { + enc: &'a mut Encoder, + is_root: bool, +} + +impl<'a> SerializeStruct for StructMapEncoder<'a> { type Ok = (); type Error = EncoderError; - fn serialize_key(&mut self, _key: &T) -> EncodeResult { - no_impl!("SerializeMap::serialize_key") - } - - fn serialize_value(&mut self, _value: &T) -> EncodeResult { - no_impl!("SerializeMap::serialize_value") + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> EncodeResult { + self.enc.state = NextKey(String::from(key)); + value.serialize(&mut *self.enc) } fn end(self) -> EncodeResult { - no_impl!("SerializeMap::end") + if self.is_root { + self.enc.keys.pop(); + } + Ok(()) } } -pub struct StructEncoder<'a> { - enc: &'a mut Encoder, - is_root: bool -} - -impl<'a> SerializeStruct for StructEncoder<'a> { +impl<'a> SerializeMap for StructMapEncoder<'a> { type Ok = (); type Error = EncoderError; - fn serialize_field(&mut self, - key: &'static str, - value: &T) - -> EncodeResult { - self.enc.state = NextKey(String::from(key)); + fn serialize_key(&mut self, key: &T) -> EncodeResult { + self.enc.state = NextKey(key.serialize(MapKeySerializer)?); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> EncodeResult { value.serialize(&mut *self.enc) } @@ -298,10 +499,11 @@ impl SerializeStructVariant for StructVariantEncoder { type Ok = (); type Error = EncoderError; - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> EncodeResult { + fn serialize_field( + &mut self, + _key: &'static str, + _value: &T, + ) -> EncodeResult { no_impl!("SerializeStructVariant::serialize_field") } @@ -309,4 +511,3 @@ impl SerializeStructVariant for StructVariantEncoder { no_impl!("SerializeStructVariant::end") } } - diff --git a/third_party/rust/winreg/src/enums.rs b/third_party/rust/winreg/src/enums.rs index 00518cb4475d..b537b287c200 100644 --- a/third_party/rust/winreg/src/enums.rs +++ b/third_party/rust/winreg/src/enums.rs @@ -6,29 +6,16 @@ //! `use winreg::enums::*;` to import all needed enumerations and constants use super::winapi; -pub use winapi::um::winreg::{HKEY_CLASSES_ROOT, - HKEY_CURRENT_USER, - HKEY_LOCAL_MACHINE, - HKEY_USERS, - HKEY_PERFORMANCE_DATA, - HKEY_PERFORMANCE_TEXT, - HKEY_PERFORMANCE_NLSTEXT, - HKEY_CURRENT_CONFIG, - HKEY_DYN_DATA, - HKEY_CURRENT_USER_LOCAL_SETTINGS}; -pub use winapi::um::winnt::{KEY_QUERY_VALUE, - KEY_SET_VALUE, - KEY_CREATE_SUB_KEY, - KEY_ENUMERATE_SUB_KEYS, - KEY_NOTIFY, - KEY_CREATE_LINK, - KEY_WOW64_32KEY, - KEY_WOW64_64KEY, - KEY_WOW64_RES, - KEY_READ, - KEY_WRITE, - KEY_EXECUTE, - KEY_ALL_ACCESS}; +pub use winapi::um::winnt::{ + KEY_ALL_ACCESS, KEY_CREATE_LINK, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_EXECUTE, + KEY_NOTIFY, KEY_QUERY_VALUE, KEY_READ, KEY_SET_VALUE, KEY_WOW64_32KEY, KEY_WOW64_64KEY, + KEY_WOW64_RES, KEY_WRITE, +}; +pub use winapi::um::winreg::{ + HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_CURRENT_USER_LOCAL_SETTINGS, + HKEY_DYN_DATA, HKEY_LOCAL_MACHINE, HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_NLSTEXT, + HKEY_PERFORMANCE_TEXT, HKEY_USERS, REG_PROCESS_APPKEY, +}; macro_rules! winapi_enum{ ($t:ident, $doc:expr => [$($v:ident),*]) => ( @@ -56,3 +43,9 @@ REG_RESOURCE_REQUIREMENTS_LIST, REG_QWORD ]); pub use self::RegType::*; + +winapi_enum!(RegDisposition, "Enumeration of possible disposition values" => [ +REG_CREATED_NEW_KEY, +REG_OPENED_EXISTING_KEY +]); +pub use self::RegDisposition::*; diff --git a/third_party/rust/winreg/src/lib.rs b/third_party/rust/winreg/src/lib.rs index 285259f8223d..784976c5c84b 100644 --- a/third_party/rust/winreg/src/lib.rs +++ b/third_party/rust/winreg/src/lib.rs @@ -13,54 +13,75 @@ //!```toml,ignore //!# Cargo.toml //![dependencies] -//!winreg = "0.5" +//!winreg = "0.10" //!``` //! //!```no_run //!extern crate winreg; -//!use std::path::Path; //!use std::io; -//!use winreg::RegKey; +//!use std::path::Path; //!use winreg::enums::*; +//!use winreg::RegKey; //! -//!fn main() { +//!fn main() -> io::Result<()> { //! println!("Reading some system info..."); //! let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); -//! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion").unwrap(); -//! let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap(); -//! let dp: String = cur_ver.get_value("DevicePath").unwrap(); +//! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; +//! let pf: String = cur_ver.get_value("ProgramFilesDir")?; +//! let dp: String = cur_ver.get_value("DevicePath")?; //! println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); -//! let info = cur_ver.query_info().unwrap(); +//! let info = cur_ver.query_info()?; //! println!("info = {:?}", info); +//! let mt = info.get_last_write_time_system(); +//! println!( +//! "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", +//! mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond +//! ); +//! +//! // enable `chrono` feature on `winreg` to make this work +//! // println!( +//! // "last_write_time as chrono::NaiveDateTime = {}", +//! // info.get_last_write_time_chrono() +//! // ); //! //! println!("And now lets write something..."); //! let hkcu = RegKey::predef(HKEY_CURRENT_USER); //! let path = Path::new("Software").join("WinregRsExample1"); -//! let key = hkcu.create_subkey(&path).unwrap(); +//! let (key, disp) = hkcu.create_subkey(&path)?; //! -//! key.set_value("TestSZ", &"written by Rust").unwrap(); -//! let sz_val: String = key.get_value("TestSZ").unwrap(); -//! key.delete_value("TestSZ").unwrap(); +//! match disp { +//! REG_CREATED_NEW_KEY => println!("A new key has been created"), +//! REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), +//! } +//! +//! key.set_value("TestSZ", &"written by Rust")?; +//! let sz_val: String = key.get_value("TestSZ")?; +//! key.delete_value("TestSZ")?; //! println!("TestSZ = {}", sz_val); //! -//! key.set_value("TestDWORD", &1234567890u32).unwrap(); -//! let dword_val: u32 = key.get_value("TestDWORD").unwrap(); +//! key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; +//! let multi_sz_val: Vec = key.get_value("TestMultiSZ")?; +//! key.delete_value("TestMultiSZ")?; +//! println!("TestMultiSZ = {:?}", multi_sz_val); +//! +//! key.set_value("TestDWORD", &1234567890u32)?; +//! let dword_val: u32 = key.get_value("TestDWORD")?; //! println!("TestDWORD = {}", dword_val); //! -//! key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); -//! let qword_val: u64 = key.get_value("TestQWORD").unwrap(); +//! key.set_value("TestQWORD", &1234567891011121314u64)?; +//! let qword_val: u64 = key.get_value("TestQWORD")?; //! println!("TestQWORD = {}", qword_val); //! -//! key.create_subkey("sub\\key").unwrap(); -//! hkcu.delete_subkey_all(&path).unwrap(); +//! key.create_subkey("sub\\key")?; +//! hkcu.delete_subkey_all(&path)?; //! //! println!("Trying to open nonexistent key..."); -//! let key2 = hkcu.open_subkey(&path) -//! .unwrap_or_else(|e| match e.kind() { +//! hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() { //! io::ErrorKind::NotFound => panic!("Key doesn't exist"), //! io::ErrorKind::PermissionDenied => panic!("Access denied"), -//! _ => panic!("{:?}", e) +//! _ => panic!("{:?}", e), //! }); +//! Ok(()) //!} //!``` //! @@ -68,10 +89,11 @@ //! //!```no_run //!extern crate winreg; +//!use std::io; //!use winreg::RegKey; //!use winreg::enums::*; //! -//!fn main() { +//!fn main() -> io::Result<()> { //! println!("File extensions, registered in system:"); //! for i in RegKey::predef(HKEY_CLASSES_ROOT) //! .enum_keys().map(|x| x.unwrap()) @@ -81,55 +103,57 @@ //! } //! //! let system = RegKey::predef(HKEY_LOCAL_MACHINE) -//! .open_subkey("HARDWARE\\DESCRIPTION\\System").unwrap(); +//! .open_subkey("HARDWARE\\DESCRIPTION\\System")?; //! for (name, value) in system.enum_values().map(|x| x.unwrap()) { //! println!("{} = {:?}", name, value); //! } +//! +//! Ok(()) //!} //!``` //! -#![cfg_attr(feature="clippy", feature(plugin))] -#![cfg_attr(feature="clippy", plugin(clippy))] -#![cfg_attr(feature="clippy", warn(option_unwrap_used))] -#![cfg_attr(feature="clippy", warn(result_unwrap_used))] -extern crate winapi; +#[cfg(feature = "chrono")] +extern crate chrono; #[cfg(feature = "serialization-serde")] extern crate serde; -use std::ptr; -use std::slice; -use std::fmt; +extern crate winapi; +use enums::*; use std::default::Default; use std::ffi::OsStr; -use std::os::windows::ffi::OsStrExt; -use std::mem::transmute; +use std::fmt; use std::io; -use winapi::shared::winerror; -pub use winapi::shared::minwindef::HKEY; -use winapi::shared::minwindef::{DWORD, BYTE, LPBYTE}; -use winapi::um::winnt::{self, WCHAR}; -use winapi::um::winreg as winapi_reg; -use enums::*; -use types::{FromRegValue, ToRegValue}; +use std::mem::transmute; +use std::os::windows::ffi::OsStrExt; +use std::ptr; +use std::slice; #[cfg(feature = "transactions")] use transaction::Transaction; +use types::{FromRegValue, ToRegValue}; +pub use winapi::shared::minwindef::HKEY; +use winapi::shared::minwindef::{BYTE, DWORD, FILETIME, LPBYTE}; +use winapi::shared::winerror; +use winapi::um::minwinbase::SYSTEMTIME; +use winapi::um::timezoneapi::FileTimeToSystemTime; +use winapi::um::winnt::{self, WCHAR}; +use winapi::um::winreg as winapi_reg; macro_rules! werr { - ($e:expr) => ( + ($e:expr) => { Err(io::Error::from_raw_os_error($e as i32)) - ) + }; } -pub mod enums; -pub mod types; -#[cfg(feature = "transactions")] -pub mod transaction; -#[cfg(feature = "serialization-serde")] -mod encoder; #[cfg(feature = "serialization-serde")] mod decoder; +#[cfg(feature = "serialization-serde")] +mod encoder; +pub mod enums; +#[cfg(feature = "transactions")] +pub mod transaction; +pub mod types; /// Metadata returned by `RegKey::query_info` -#[derive(Debug,Default)] +#[derive(Debug, Default)] pub struct RegKeyMetadata { // pub Class: winapi::LPWSTR, // pub ClassLen: DWORD, @@ -140,7 +164,31 @@ pub struct RegKeyMetadata { pub max_value_name_len: DWORD, pub max_value_len: DWORD, // pub SecurityDescriptor: DWORD, - // pub LastWriteTime: winapi::PFILETIME, + pub last_write_time: FILETIME, +} + +impl RegKeyMetadata { + /// Returns `last_write_time` field as `winapi::um::minwinbase::SYSTEMTIME` + pub fn get_last_write_time_system(&self) -> SYSTEMTIME { + let mut st: SYSTEMTIME = unsafe { ::std::mem::zeroed() }; + unsafe { + FileTimeToSystemTime(&self.last_write_time, &mut st); + } + st + } + + /// Returns `last_write_time` field as `chrono::NaiveDateTime`. + /// Part of `chrono` feature. + #[cfg(feature = "chrono")] + pub fn get_last_write_time_chrono(&self) -> chrono::NaiveDateTime { + let st = self.get_last_write_time_system(); + + chrono::NaiveDate::from_ymd(st.wYear.into(), st.wMonth.into(), st.wDay.into()).and_hms( + st.wHour.into(), + st.wMinute.into(), + st.wSecond.into(), + ) + } } /// Raw registry value @@ -151,29 +199,29 @@ pub struct RegValue { } macro_rules! format_reg_value { - ($e:expr => $t:ident) => ( + ($e:expr => $t:ident) => { match $t::from_reg_value($e) { Ok(val) => format!("{:?}", val), Err(_) => return Err(fmt::Error), } - ) + }; +} + +impl fmt::Display for RegValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f_val = match self.vtype { + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => format_reg_value!(self => String), + REG_DWORD => format_reg_value!(self => u32), + REG_QWORD => format_reg_value!(self => u64), + _ => format!("{:?}", self.bytes), //TODO: implement more types + }; + write!(f, "{}", f_val) + } } impl fmt::Debug for RegValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let f_val = match self.vtype { - REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { - format_reg_value!(self => String) - }, - REG_DWORD => { - format_reg_value!(self => u32) - }, - REG_QWORD => { - format_reg_value!(self => u64) - }, - _ => format!("{:?}", self.bytes) //TODO: implement more types - }; - write!(f, "RegValue({:?}: {})", self.vtype, f_val) + write!(f, "RegValue({:?}: {})", self.vtype, self) } } @@ -206,8 +254,63 @@ impl RegKey { /// # use winreg::enums::*; /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); /// ``` - pub fn predef(hkey: HKEY) -> RegKey { - RegKey{ hkey: hkey } + pub const fn predef(hkey: HKEY) -> RegKey { + RegKey { hkey } + } + + /// Load a registry hive from a file as an application hive. + /// If `lock` is set to `true`, then the hive cannot be loaded again until + /// it's unloaded (i.e. all keys from it go out of scope). + /// + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { + /// let handle = RegKey::load_app_key("C:\\myhive.dat", false)?; + /// # Ok(()) + /// # } + /// ``` + pub fn load_app_key>(filename: N, lock: bool) -> io::Result { + let options = if lock { + winapi_reg::REG_PROCESS_APPKEY + } else { + 0 + }; + RegKey::load_app_key_with_flags(filename, enums::KEY_ALL_ACCESS, options) + } + + /// Load a registry hive from a file as an application hive with desired + /// permissions and options. If `options` is set to `REG_PROCESS_APPKEY`, + /// then the hive cannot be loaded again until it's unloaded (i.e. all keys + /// from it go out of scope). + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { + /// let handle = RegKey::load_app_key_with_flags("C:\\myhive.dat", KEY_READ, 0)?; + /// # Ok(()) + /// # } + /// ``` + pub fn load_app_key_with_flags>( + filename: N, + perms: winapi_reg::REGSAM, + options: DWORD, + ) -> io::Result { + let c_filename = to_utf16(filename); + let mut new_hkey: HKEY = ptr::null_mut(); + match unsafe { + winapi_reg::RegLoadAppKeyW(c_filename.as_ptr(), &mut new_hkey, perms, options, 0) + as DWORD + } { + 0 => Ok(RegKey { hkey: new_hkey }), + err => werr!(err), + } } /// Return inner winapi HKEY of a key: @@ -215,13 +318,17 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - /// let soft = hklm.open_subkey("SOFTWARE").unwrap(); + /// let soft = hklm.open_subkey("SOFTWARE")?; /// let handle = soft.raw_handle(); + /// # Ok(()) + /// # } /// ``` - pub fn raw_handle(&self) -> HKEY { + pub const fn raw_handle(&self) -> HKEY { self.hkey } @@ -233,10 +340,14 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let soft = RegKey::predef(HKEY_CURRENT_USER) - /// .open_subkey("Software").unwrap(); + /// .open_subkey("Software")?; + /// # Ok(()) + /// # } /// ``` pub fn open_subkey>(&self, path: P) -> io::Result { self.open_subkey_with_flags(path, enums::KEY_READ) @@ -248,39 +359,48 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ).unwrap(); + /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ)?; + /// # Ok(()) + /// # } /// ``` - pub fn open_subkey_with_flags>(&self, path: P, perms: winapi_reg::REGSAM) -> io::Result { + pub fn open_subkey_with_flags>( + &self, + path: P, + perms: winapi_reg::REGSAM, + ) -> io::Result { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); match unsafe { - winapi_reg::RegOpenKeyExW( - self.hkey, - c_path.as_ptr(), - 0, - perms, - &mut new_hkey, - ) as DWORD + winapi_reg::RegOpenKeyExW(self.hkey, c_path.as_ptr(), 0, perms, &mut new_hkey) as DWORD } { - 0 => Ok(RegKey{ hkey: new_hkey }), - err => werr!(err) + 0 => Ok(RegKey { hkey: new_hkey }), + err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] - pub fn open_subkey_transacted>(&self, path: P, t: &Transaction) -> io::Result { + pub fn open_subkey_transacted>( + &self, + path: P, + t: &Transaction, + ) -> io::Result { self.open_subkey_transacted_with_flags(path, t, winnt::KEY_READ) } /// Part of `transactions` feature. #[cfg(feature = "transactions")] - pub fn open_subkey_transacted_with_flags>(&self, path: P, t: &Transaction, perms: winapi_reg::REGSAM) - -> io::Result - { + pub fn open_subkey_transacted_with_flags>( + &self, + path: P, + t: &Transaction, + perms: winapi_reg::REGSAM, + ) -> io::Result { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); match unsafe { @@ -294,33 +414,48 @@ impl RegKey { ptr::null_mut(), ) as DWORD } { - 0 => Ok(RegKey{ hkey: new_hkey }), - err => werr!(err) + 0 => Ok(RegKey { hkey: new_hkey }), + err => werr!(err), } } /// Create subkey (and all missing parent keys) /// and open it with `KEY_ALL_ACCESS` permissions. /// Will just open key if it already exists. + /// If succeeds returns a tuple with the created subkey and its disposition, + /// which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY`. /// Will open another handle to itself if `path` is an empty string. /// To create with different permissions use `create_subkey_with_flags`. /// /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; - /// # use winreg::enums::*; + /// use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.create_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; + /// + /// match disp { + /// REG_CREATED_NEW_KEY => println!("A new key has been created"), + /// REG_OPENED_EXISTING_KEY => println!("An existing key has been opened") + /// } + /// # Ok(()) + /// # } /// ``` - pub fn create_subkey>(&self, path: P) -> io::Result { + pub fn create_subkey>(&self, path: P) -> io::Result<(RegKey, RegDisposition)> { self.create_subkey_with_flags(path, enums::KEY_ALL_ACCESS) } - pub fn create_subkey_with_flags>(&self, path: P, perms: winapi_reg::REGSAM) -> io::Result { + pub fn create_subkey_with_flags>( + &self, + path: P, + perms: winapi_reg::REGSAM, + ) -> io::Result<(RegKey, RegDisposition)> { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); - let mut disp: DWORD = 0; + let mut disp_buf: DWORD = 0; match unsafe { winapi_reg::RegCreateKeyExW( self.hkey, @@ -331,28 +466,38 @@ impl RegKey { perms, ptr::null_mut(), &mut new_hkey, - &mut disp // TODO: return this somehow + &mut disp_buf, ) } { - 0 => Ok(RegKey{ hkey: new_hkey }), - err => werr!(err) + 0 => { + let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; + Ok((RegKey { hkey: new_hkey }, disp)) + } + err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] - pub fn create_subkey_transacted>(&self, path: P, t: &Transaction) -> io::Result { + pub fn create_subkey_transacted>( + &self, + path: P, + t: &Transaction, + ) -> io::Result<(RegKey, RegDisposition)> { self.create_subkey_transacted_with_flags(path, t, winnt::KEY_ALL_ACCESS) } /// Part of `transactions` feature. #[cfg(feature = "transactions")] - pub fn create_subkey_transacted_with_flags>(&self, path: P, t: &Transaction, perms: winapi_reg::REGSAM) - -> io::Result - { + pub fn create_subkey_transacted_with_flags>( + &self, + path: P, + t: &Transaction, + perms: winapi_reg::REGSAM, + ) -> io::Result<(RegKey, RegDisposition)> { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); - let mut disp: DWORD = 0; + let mut disp_buf: DWORD = 0; match unsafe { winapi_reg::RegCreateKeyTransactedW( self.hkey, @@ -363,13 +508,16 @@ impl RegKey { perms, ptr::null_mut(), &mut new_hkey, - &mut disp, // TODO: return this somehow + &mut disp_buf, t.handle, ptr::null_mut(), ) as DWORD } { - 0 => Ok(RegKey{ hkey: new_hkey }), - err => werr!(err) + 0 => { + let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; + Ok((RegKey { hkey: new_hkey }, disp)) + } + err => werr!(err), } } @@ -379,24 +527,22 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ).unwrap(); - /// let dst = hkcu.create_subkey("Software\\MyProduct\\Section2").unwrap(); - /// src.copy_tree("Section1", &dst).unwrap(); + /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ)?; + /// let (dst, dst_disp) = hkcu.create_subkey("Software\\MyProduct\\Section2")?; + /// src.copy_tree("Section1", &dst)?; + /// # Ok(()) + /// # } /// ``` pub fn copy_tree>(&self, path: P, dest: &RegKey) -> io::Result<()> { let c_path = to_utf16(path); - match unsafe { - winapi_reg::RegCopyTreeW( - self.hkey, - c_path.as_ptr(), - dest.hkey, - ) - } { + match unsafe { winapi_reg::RegCopyTreeW(self.hkey, c_path.as_ptr(), dest.hkey) } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } @@ -415,11 +561,11 @@ impl RegKey { &mut info.max_value_name_len, &mut info.max_value_len, ptr::null_mut(), // lpcbSecurityDescriptor: winapi::LPDWORD, - ptr::null_mut(), // lpftLastWriteTime: winapi::PFILETIME, + &mut info.last_write_time, ) as DWORD } { 0 => Ok(info), - err => werr!(err) + err => werr!(err), } } @@ -438,8 +584,11 @@ impl RegKey { /// println!("{}", i); /// } /// ``` - pub fn enum_keys(&self) -> EnumKeys { - EnumKeys{key: self, index: 0} + pub const fn enum_keys(&self) -> EnumKeys { + EnumKeys { + key: self, + index: 0, + } } /// Return an iterator over values. @@ -447,60 +596,110 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let system = RegKey::predef(HKEY_LOCAL_MACHINE) - /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ) - /// .unwrap(); + /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ)?; /// for (name, value) in system.enum_values().map(|x| x.unwrap()) { /// println!("{} = {:?}", name, value); /// } + /// # Ok(()) + /// # } /// ``` - pub fn enum_values(&self) -> EnumValues { - EnumValues{key: self, index: 0} + pub const fn enum_values(&self) -> EnumValues { + EnumValues { + key: self, + index: 0, + } } - /// Delete key.Key names are not case sensitive. + /// Delete key. Key names are not case sensitive. /// Cannot delete if it has subkeys. /// Use `delete_subkey_all` for that. /// /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// RegKey::predef(HKEY_CURRENT_USER) - /// .delete_subkey(r"Software\MyProduct\History").unwrap(); + /// .delete_subkey(r"Software\MyProduct\History")?; + /// # Ok(()) + /// # } /// ``` pub fn delete_subkey>(&self, path: P) -> io::Result<()> { + self.delete_subkey_with_flags(path, 0) + } + + /// Delete key from the desired platform-specific view of the registry. + /// Key names are not case sensitive. + /// + /// # Examples + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { + /// // delete the key from the 32-bit registry view + /// RegKey::predef(HKEY_LOCAL_MACHINE) + /// .delete_subkey_with_flags(r"Software\MyProduct\History", KEY_WOW64_32KEY)?; + /// # Ok(()) + /// # } + /// ``` + pub fn delete_subkey_with_flags>( + &self, + path: P, + perms: winapi_reg::REGSAM, + ) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { - winapi_reg::RegDeleteKeyW( + winapi_reg::RegDeleteKeyExW( self.hkey, - c_path.as_ptr(), //This parameter cannot be NULL. - ) as DWORD + c_path.as_ptr(), // This parameter cannot be NULL. + perms, + 0, + ) } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] - pub fn delete_subkey_transacted>(&self, path: P, t: &Transaction) -> io::Result<()> { + pub fn delete_subkey_transacted>( + &self, + path: P, + t: &Transaction, + ) -> io::Result<()> { + self.delete_subkey_transacted_with_flags(path, t, 0) + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn delete_subkey_transacted_with_flags>( + &self, + path: P, + t: &Transaction, + perms: winapi_reg::REGSAM, + ) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegDeleteKeyTransactedW( self.hkey, - c_path.as_ptr(), //The value of this parameter cannot be NULL. - 0, + c_path.as_ptr(), // This parameter cannot be NULL. + perms, 0, t.handle, ptr::null_mut(), - ) as DWORD + ) } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } @@ -510,28 +709,31 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// RegKey::predef(HKEY_CURRENT_USER) - /// .delete_subkey_all("Software\\MyProduct").unwrap(); + /// .delete_subkey_all("Software\\MyProduct")?; + /// # Ok(()) + /// # } /// ``` pub fn delete_subkey_all>(&self, path: P) -> io::Result<()> { let c_path; - let path_ptr; - if path.as_ref().is_empty(){ - path_ptr = ptr::null(); - }else{ + let path_ptr = if path.as_ref().is_empty() { + ptr::null() + } else { c_path = to_utf16(path); - path_ptr = c_path.as_ptr(); - } - match unsafe{ + c_path.as_ptr() + }; + match unsafe { winapi_reg::RegDeleteTreeW( self.hkey, - path_ptr,//If this parameter is NULL, the subkeys and values of this key are deleted. + path_ptr, //If this parameter is NULL, the subkeys and values of this key are deleted. ) as DWORD } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } @@ -542,17 +744,21 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; - /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); - /// let server: String = settings.get_value("server").unwrap(); - /// let port: u32 = settings.get_value("port").unwrap(); + /// # fn main() -> Result<(), Box> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// let server: String = settings.get_value("server")?; + /// let port: u32 = settings.get_value("port")?; + /// # Ok(()) + /// # } /// ``` pub fn get_value>(&self, name: N) -> io::Result { match self.get_raw_value(name) { Ok(ref val) => FromRegValue::from_reg_value(val), - Err(err) => Err(err) + Err(err) => Err(err), } } @@ -562,12 +768,16 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; - /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); - /// let data = settings.get_raw_value("data").unwrap(); + /// # fn main() -> Result<(), Box> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// let data = settings.get_raw_value("data")?; /// println!("Bytes: {:?}", data.bytes); + /// # Ok(()) + /// # } /// ``` pub fn get_raw_value>(&self, name: N) -> io::Result { let c_name = to_utf16(name); @@ -582,21 +792,26 @@ impl RegKey { ptr::null_mut(), &mut buf_type, buf.as_mut_ptr() as LPBYTE, - &mut buf_len + &mut buf_len, ) as DWORD } { 0 => { - unsafe{ buf.set_len(buf_len as usize); } + unsafe { + buf.set_len(buf_len as usize); + } // minimal check before transmute to RegType if buf_type > winnt::REG_QWORD { return werr!(winerror::ERROR_BAD_FILE_TYPE); } - let t: RegType = unsafe{ transmute(buf_type as u8) }; - return Ok(RegValue{ bytes: buf, vtype: t }) - }, + let t: RegType = unsafe { transmute(buf_type as u8) }; + return Ok(RegValue { + bytes: buf, + vtype: t, + }); + } winerror::ERROR_MORE_DATA => { buf.reserve(buf_len as usize); - }, + } err => return werr!(err), } } @@ -609,12 +824,16 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; - /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.create_subkey("Software\\MyProduct\\Settings").unwrap(); - /// settings.set_value("server", &"www.example.com").unwrap(); - /// settings.set_value("port", &8080u32).unwrap(); + /// # fn main() -> Result<(), Box> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; + /// settings.set_value("server", &"www.example.com")?; + /// settings.set_value("port", &8080u32)?; + /// # Ok(()) + /// # } /// ``` pub fn set_value>(&self, name: N, value: &T) -> io::Result<()> { self.set_raw_value(name, &value.to_reg_value()) @@ -626,30 +845,34 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// use winreg::{RegKey, RegValue}; /// use winreg::enums::*; + /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; /// let bytes: Vec = vec![1, 2, 3, 5, 8, 13, 21, 34, 55, 89]; /// let data = RegValue{ vtype: REG_BINARY, bytes: bytes}; - /// settings.set_raw_value("data", &data).unwrap(); - /// println!("Bytes: {:?}", data.bytes) + /// settings.set_raw_value("data", &data)?; + /// println!("Bytes: {:?}", data.bytes); + /// # Ok(()) + /// # } /// ``` pub fn set_raw_value>(&self, name: N, value: &RegValue) -> io::Result<()> { let c_name = to_utf16(name); let t = value.vtype.clone() as DWORD; - match unsafe{ + match unsafe { winapi_reg::RegSetValueExW( self.hkey, c_name.as_ptr(), 0, t, value.bytes.as_ptr() as *const BYTE, - value.bytes.len() as u32 + value.bytes.len() as u32, ) as DWORD } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } @@ -659,22 +882,21 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; - /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); - /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); - /// settings.delete_value("data").unwrap(); + /// # fn main() -> Result<(), Box> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// settings.delete_value("data")?; + /// # Ok(()) + /// # } /// ``` pub fn delete_value>(&self, name: N) -> io::Result<()> { let c_name = to_utf16(name); - match unsafe { - winapi_reg::RegDeleteValueW( - self.hkey, - c_name.as_ptr(), - ) as DWORD - } { + match unsafe { winapi_reg::RegDeleteValueW(self.hkey, c_name.as_ptr()) as DWORD } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } @@ -684,10 +906,10 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// #[macro_use] /// extern crate serde_derive; /// extern crate winreg; - /// # fn main() { /// use winreg::RegKey; /// use winreg::enums::*; /// @@ -706,24 +928,22 @@ impl RegKey { /// show_in_tray: bool, /// } /// + /// # fn main() -> Result<(), Box> { /// let s: Settings = Settings{ /// current_dir: "C:\\".to_owned(), /// window_pos: Rectangle{ x:200, y: 100, w: 800, h: 500 }, /// show_in_tray: false, /// }; /// let s_key = RegKey::predef(HKEY_CURRENT_USER) - /// .open_subkey("Software\\MyProduct\\Settings").unwrap(); - /// s_key.encode(&s).unwrap(); + /// .open_subkey("Software\\MyProduct\\Settings")?; + /// s_key.encode(&s)?; + /// # Ok(()) /// # } /// ``` #[cfg(feature = "serialization-serde")] - pub fn encode(&self, value: &T) - -> encoder::EncodeResult<()> - { - let mut encoder = try!( - encoder::Encoder::from_key(self) - ); - try!(value.serialize(&mut encoder)); + pub fn encode(&self, value: &T) -> encoder::EncodeResult<()> { + let mut encoder = encoder::Encoder::from_key(self)?; + value.serialize(&mut encoder)?; encoder.commit() } @@ -733,10 +953,10 @@ impl RegKey { /// # Examples /// /// ```no_run + /// # use std::error::Error; /// #[macro_use] /// extern crate serde_derive; /// extern crate winreg; - /// # fn main() { /// use winreg::RegKey; /// use winreg::enums::*; /// @@ -755,34 +975,33 @@ impl RegKey { /// show_in_tray: bool, /// } /// + /// # fn main() -> Result<(), Box> { /// let s_key = RegKey::predef(HKEY_CURRENT_USER) - /// .open_subkey("Software\\MyProduct\\Settings").unwrap(); - /// let s: Settings = s_key.decode().unwrap(); + /// .open_subkey("Software\\MyProduct\\Settings")?; + /// let s: Settings = s_key.decode()?; + /// # Ok(()) /// # } /// ``` #[cfg(feature = "serialization-serde")] - pub fn decode<'de, T: serde::Deserialize<'de>>(&self) - -> decoder::DecodeResult - { - let mut decoder = try!( - decoder::Decoder::from_key(self) - ); + pub fn decode<'de, T: serde::Deserialize<'de>>(&self) -> decoder::DecodeResult { + let mut decoder = decoder::Decoder::from_key(self)?; T::deserialize(&mut decoder) } fn close_(&mut self) -> io::Result<()> { // don't try to close predefined keys - if self.hkey >= enums::HKEY_CLASSES_ROOT { return Ok(()) }; - match unsafe { - winapi_reg::RegCloseKey(self.hkey) as DWORD - } { + if self.hkey >= enums::HKEY_CLASSES_ROOT { + return Ok(()); + }; + match unsafe { winapi_reg::RegCloseKey(self.hkey) as DWORD } { 0 => Ok(()), - err => werr!(err) + err => werr!(err), } } fn enum_key(&self, index: DWORD) -> Option> { let mut name_len = 2048; + #[allow(clippy::unnecessary_cast)] let mut name = [0 as WCHAR; 2048]; match unsafe { winapi_reg::RegEnumKeyExW( @@ -796,21 +1015,18 @@ impl RegKey { ptr::null_mut(), // lpftLastWriteTime: PFILETIME, ) as DWORD } { - 0 => { - match String::from_utf16(&name[..name_len as usize]) { - Ok(s) => Some(Ok(s)), - Err(_) => Some(werr!(winerror::ERROR_INVALID_BLOCK)) - } + 0 => match String::from_utf16(&name[..name_len as usize]) { + Ok(s) => Some(Ok(s)), + Err(_) => Some(werr!(winerror::ERROR_INVALID_BLOCK)), }, winerror::ERROR_NO_MORE_ITEMS => None, - err => { - Some(werr!(err)) - } + err => Some(werr!(err)), } } fn enum_value(&self, index: DWORD) -> Option> { let mut name_len = 2048; + #[allow(clippy::unnecessary_cast)] let mut name = [0 as WCHAR; 2048]; let mut buf_len: DWORD = 2048; @@ -832,23 +1048,28 @@ impl RegKey { 0 => { let name = match String::from_utf16(&name[..name_len as usize]) { Ok(s) => s, - Err(_) => return Some(werr!(winerror::ERROR_INVALID_DATA)) + Err(_) => return Some(werr!(winerror::ERROR_INVALID_DATA)), }; - unsafe{ buf.set_len(buf_len as usize); } + unsafe { + buf.set_len(buf_len as usize); + } // minimal check before transmute to RegType if buf_type > winnt::REG_QWORD { return Some(werr!(winerror::ERROR_BAD_FILE_TYPE)); } - let t: RegType = unsafe{ transmute(buf_type as u8) }; - let value = RegValue{ bytes: buf, vtype: t }; - return Some(Ok((name, value))) - }, + let t: RegType = unsafe { transmute(buf_type as u8) }; + let value = RegValue { + bytes: buf, + vtype: t, + }; + return Some(Ok((name, value))); + } winerror::ERROR_MORE_DATA => { name_len += 1; //for NULL char buf.reserve(buf_len as usize); - }, + } winerror::ERROR_NO_MORE_ITEMS => return None, - err => return Some(werr!(err)) + err => return Some(werr!(err)), } } } @@ -874,10 +1095,15 @@ impl<'key> Iterator for EnumKeys<'key> { v @ Some(_) => { self.index += 1; v - }, - e @ None => e + } + e @ None => e, } } + + fn nth(&mut self, n: usize) -> Option { + self.index += n as DWORD; + self.next() + } } /// Iterator over values @@ -894,277 +1120,24 @@ impl<'key> Iterator for EnumValues<'key> { v @ Some(_) => { self.index += 1; v - }, - e @ None => e + } + e @ None => e, } } + + fn nth(&mut self, n: usize) -> Option { + self.index += n as DWORD; + self.next() + } } fn to_utf16>(s: P) -> Vec { - s.as_ref().encode_wide().chain(Some(0).into_iter()).collect() + s.as_ref() + .encode_wide() + .chain(Some(0).into_iter()) + .collect() } fn v16_to_v8(v: &[u16]) -> Vec { - unsafe { - slice::from_raw_parts(v.as_ptr() as *const u8, v.len()*2).to_vec() - } -} - -#[cfg(all(test, feature = "serialization-serde"))] -#[macro_use] -extern crate serde_derive; - -#[cfg(test)] -#[cfg_attr(feature="clippy", allow(option_unwrap_used))] -#[cfg_attr(feature="clippy", allow(result_unwrap_used))] -mod test { - extern crate rand; - use super::*; - use std::collections::HashMap; - use self::rand::Rng; - use std::ffi::{OsStr,OsString}; - - #[test] - fn test_raw_handle() { - let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let handle = hklm.raw_handle(); - assert_eq!(HKEY_LOCAL_MACHINE, handle); - } - - #[test] - fn test_open_subkey_with_flags_query_info() { - let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let win = hklm.open_subkey_with_flags("Software\\Microsoft\\Windows", KEY_READ).unwrap(); - assert!(win.query_info().is_ok()); - assert!(win.open_subkey_with_flags("CurrentVersion\\", KEY_READ).is_ok()); - assert!(hklm.open_subkey_with_flags("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ).is_err()); - } - - macro_rules! with_key { - ($k:ident, $path:expr => $b:block) => {{ - let mut path = "Software\\WinRegRsTest".to_owned(); - path.push_str($path); - let $k = RegKey::predef(HKEY_CURRENT_USER) - .create_subkey(&path).unwrap(); - $b - RegKey::predef(HKEY_CURRENT_USER) - .delete_subkey_all(path).unwrap(); - }} - } - - #[test] - fn test_delete_subkey() { - let path = "Software\\WinRegRsTestDeleteSubkey"; - RegKey::predef(HKEY_CURRENT_USER).create_subkey(path).unwrap(); - assert!(RegKey::predef(HKEY_CURRENT_USER) - .delete_subkey(path).is_ok()); - } - - #[test] - fn test_copy_tree() { - with_key!(key, "CopyTree" => { - let sub_tree = key.create_subkey("Src\\Sub\\Tree").unwrap(); - for v in &["one", "two", "three"] { - sub_tree.set_value(v, v).unwrap(); - } - let dst = key.create_subkey("Dst").unwrap(); - assert!(key.copy_tree("Src", &dst).is_ok()); - }); - } - - #[test] - fn test_long_value() { - with_key!(key, "LongValue" => { - let name = "RustLongVal"; - let val1 = RegValue { vtype: REG_BINARY, bytes: (0..6000).map(|_| rand::random::()).collect() }; - key.set_raw_value(name, &val1).unwrap(); - let val2 = key.get_raw_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_string_value() { - with_key!(key, "StringValue" => { - let name = "RustStringVal"; - let val1 = "Test123 \n$%^&|+-*/\\()".to_owned(); - key.set_value(name, &val1).unwrap(); - let val2: String = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_long_string_value() { - with_key!(key, "LongStringValue" => { - let name = "RustLongStringVal"; - let val1 : String = rand::thread_rng().gen_ascii_chars().take(7000).collect(); - key.set_value(name, &val1).unwrap(); - let val2: String = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_os_string_value() { - with_key!(key, "OsStringValue" => { - let name = "RustOsStringVal"; - let val1 = OsStr::new("Test123 \n$%^&|+-*/\\()\u{0}"); - key.set_value(name, &val1).unwrap(); - let val2: OsString = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_long_os_string_value() { - with_key!(key, "LongOsStringValue" => { - let name = "RustLongOsStringVal"; - let mut val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::(); - val1.push('\u{0}'); - let val1 = OsStr::new(&val1); - key.set_value(name, &val1).unwrap(); - let val2: OsString = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_u32_value() { - with_key!(key, "U32Value" => { - let name = "RustU32Val"; - let val1 = 1234567890u32; - key.set_value(name, &val1).unwrap(); - let val2: u32 = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_u64_value() { - with_key!(key, "U64Value" => { - let name = "RustU64Val"; - let val1 = 1234567891011121314u64; - key.set_value(name, &val1).unwrap(); - let val2: u64 = key.get_value(name).unwrap(); - assert_eq!(val1, val2); - }); - } - - #[test] - fn test_delete_value() { - with_key!(key, "DeleteValue" => { - let name = "WinregRsTestVal"; - key.set_value(name, &"Qwerty123").unwrap(); - assert!(key.delete_value(name).is_ok()); - }); - } - - #[test] - fn test_enum_keys() { - with_key!(key, "EnumKeys" => { - let mut keys1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); - keys1.sort(); - for i in &keys1 { - key.create_subkey(i).unwrap(); - } - let keys2: Vec<_> = key.enum_keys().map(|x| x.unwrap()).collect(); - assert_eq!(keys1, keys2); - }); - } - - #[test] - fn test_enum_values() { - with_key!(key, "EnumValues" => { - let mut vals1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); - vals1.sort(); - for i in &vals1 { - key.set_value(i,i).unwrap(); - } - let mut vals2: Vec = Vec::with_capacity(vals1.len()); - let mut vals3: Vec = Vec::with_capacity(vals1.len()); - for (name, val) in key.enum_values() - .map(|x| x.unwrap()) - { - vals2.push(name); - vals3.push(String::from_reg_value(&val).unwrap()); - } - assert_eq!(vals1, vals2); - assert_eq!(vals1, vals3); - }); - } - - #[test] - fn test_enum_long_values() { - with_key!(key, "EnumLongValues" => { - let mut vals = HashMap::with_capacity(3); - - for i in &[5500, 9500, 15000] { - let name: String = format!("val{}", i); - let val = RegValue { vtype: REG_BINARY, bytes: (0..*i).map(|_| rand::random::()).collect() }; - vals.insert(name, val); - } - - for (name, val) in key.enum_values() - .map(|x| x.unwrap()) - { - assert_eq!(val.bytes, vals[&name].bytes); - } - }); - } - - #[cfg(feature = "serialization-serde")] - #[test] - fn test_serialization() { - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Rectangle{ - x: u32, - y: u32, - w: u32, - h: u32, - } - - #[derive(Debug, PartialEq, Serialize, Deserialize)] - struct Test { - t_bool: bool, - t_u8: u8, - t_u16: u16, - t_u32: u32, - t_u64: u64, - t_usize: usize, - t_struct: Rectangle, - t_string: String, - t_i8: i8, - t_i16: i16, - t_i32: i32, - t_i64: i64, - t_isize: isize, - t_f64: f64, - t_f32: f32, - } - - let v1 = Test{ - t_bool: false, - t_u8: 127, - t_u16: 32768, - t_u32: 123456789, - t_u64: 123456789101112, - t_usize: 1234567891, - t_struct: Rectangle{ x: 55, y: 77, w: 500, h: 300 }, - t_string: "Test123 \n$%^&|+-*/\\()".to_owned(), - t_i8: -123, - t_i16: -2049, - t_i32: 20100, - t_i64: -12345678910, - t_isize: -1234567890, - t_f64: -0.01, - t_f32: 3.14, - }; - - with_key!(key, "Serialization" => { - key.encode(&v1).unwrap(); - let v2: Test = key.decode().unwrap(); - assert_eq!(v1, v2); - }); - } + unsafe { slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() } } diff --git a/third_party/rust/winreg/src/transaction.rs b/third_party/rust/winreg/src/transaction.rs index 5686e96b324d..e63e3ea17ca9 100644 --- a/third_party/rust/winreg/src/transaction.rs +++ b/third_party/rust/winreg/src/transaction.rs @@ -17,7 +17,7 @@ //!fn main() { //! let t = Transaction::new().unwrap(); //! let hkcu = RegKey::predef(HKEY_CURRENT_USER); -//! let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); +//! let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); //! key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); //! key.set_value("TestDWORD", &1234567890u32).unwrap(); //! @@ -39,11 +39,11 @@ //!} //!``` #![cfg(feature = "transactions")] -use std::ptr; use std::io; -use winapi::um::winnt; +use std::ptr; use winapi::um::handleapi; use winapi::um::ktmw32; +use winapi::um::winnt; #[derive(Debug)] pub struct Transaction { @@ -64,9 +64,9 @@ impl Transaction { ptr::null_mut(), ); if handle == handleapi::INVALID_HANDLE_VALUE { - return Err(io::Error::last_os_error()) + return Err(io::Error::last_os_error()); }; - Ok(Transaction{ handle: handle }) + Ok(Transaction { handle }) } } @@ -74,7 +74,7 @@ impl Transaction { unsafe { match ktmw32::CommitTransaction(self.handle) { 0 => Err(io::Error::last_os_error()), - _ => Ok(()) + _ => Ok(()), } } } @@ -83,7 +83,7 @@ impl Transaction { unsafe { match ktmw32::RollbackTransaction(self.handle) { 0 => Err(io::Error::last_os_error()), - _ => Ok(()) + _ => Ok(()), } } } @@ -92,7 +92,7 @@ impl Transaction { unsafe { match handleapi::CloseHandle(self.handle) { 0 => Err(io::Error::last_os_error()), - _ => Ok(()) + _ => Ok(()), } } } diff --git a/third_party/rust/winreg/src/types.rs b/third_party/rust/winreg/src/types.rs index fd605fa85564..37439354eb32 100644 --- a/third_party/rust/winreg/src/types.rs +++ b/third_party/rust/winreg/src/types.rs @@ -5,23 +5,24 @@ // except according to those terms. //! Traits for loading/saving Registry values -use std::slice; -use std::io; -use std::ffi::{OsStr,OsString}; -use std::os::windows::ffi::{OsStrExt,OsStringExt}; -use super::winapi::shared::winerror; -use super::{RegValue}; use super::enums::*; -use super::{to_utf16,v16_to_v8}; +use super::winapi::shared::winerror; +use super::RegValue; +use super::{to_utf16, v16_to_v8}; +use std::ffi::{OsStr, OsString}; +use std::io; +use std::os::windows::ffi::OsStringExt; +use std::slice; /// A trait for types that can be loaded from registry values. /// /// **NOTE:** Uses `from_utf16_lossy` when converting to `String`. /// -/// **NOTE:** When converting to `String`, trailing `NULL` characters are trimmed -/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`. -/// When converting to `OsString`, all `NULL` characters are left as is. -pub trait FromRegValue : Sized { +/// **NOTE:** When converting to `String` or `OsString`, trailing `NULL` characters are trimmed +/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n` +/// effectively representing the value as a multiline string. +/// When converting to `Vec` or `Vec` `NULL` is used as a strings separator. +pub trait FromRegValue: Sized { fn from_reg_value(val: &RegValue) -> io::Result; } @@ -30,16 +31,38 @@ impl FromRegValue for String { match val.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { let words = unsafe { + #[allow(clippy::cast_ptr_alignment)] slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) }; let mut s = String::from_utf16_lossy(words); - while s.ends_with('\u{0}') {s.pop();} + while s.ends_with('\u{0}') { + s.pop(); + } if val.vtype == REG_MULTI_SZ { - return Ok(s.replace("\u{0}", "\n")) + return Ok(s.replace("\u{0}", "\n")); } Ok(s) - }, - _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), + } + } +} + +impl FromRegValue for Vec { + fn from_reg_value(val: &RegValue) -> io::Result> { + match val.vtype { + REG_MULTI_SZ => { + let words = unsafe { + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + let mut s = String::from_utf16_lossy(words); + while s.ends_with('\u{0}') { + s.pop(); + } + let v: Vec = s.split('\u{0}').map(|x| x.to_owned()).collect(); + Ok(v) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), } } } @@ -48,13 +71,38 @@ impl FromRegValue for OsString { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { - let words = unsafe { + let mut words = unsafe { + #[allow(clippy::cast_ptr_alignment)] slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) }; + while let Some(0) = words.last() { + words = &words[0..words.len() - 1]; + } let s = OsString::from_wide(words); Ok(s) - }, - _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), + } + } +} + +impl FromRegValue for Vec { + fn from_reg_value(val: &RegValue) -> io::Result> { + match val.vtype { + REG_MULTI_SZ => { + let mut words = unsafe { + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + while let Some(0) = words.last() { + words = &words[0..words.len() - 1]; + } + let v: Vec = words + .split(|ch| *ch == 0u16) + .map(|x| OsString::from_wide(x)) + .collect(); + Ok(v) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), } } } @@ -62,10 +110,9 @@ impl FromRegValue for OsString { impl FromRegValue for u32 { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { - REG_DWORD => { - Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) }) - }, - _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + #[allow(clippy::cast_ptr_alignment)] + REG_DWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u32) }), + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), } } } @@ -73,69 +120,80 @@ impl FromRegValue for u32 { impl FromRegValue for u64 { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { - REG_QWORD => { - Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) }) - }, - _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + #[allow(clippy::cast_ptr_alignment)] + REG_QWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u64) }), + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), } } } /// A trait for types that can be written into registry values. /// -/// **NOTE:** Adds trailing `NULL` character to `str` and `String` values -/// but **not** to `OsStr` values. +/// **NOTE:** Adds trailing `NULL` character to `str`, `String`, `OsStr` and `OsString` values pub trait ToRegValue { fn to_reg_value(&self) -> RegValue; } -impl ToRegValue for String { - fn to_reg_value(&self) -> RegValue { - RegValue{ - bytes: v16_to_v8(&to_utf16(self)), - vtype: REG_SZ +macro_rules! to_reg_value_sz { + ($t:ty$(, $l:lifetime)*) => { + impl<$($l,)*> ToRegValue for $t { + fn to_reg_value(&self) -> RegValue { + RegValue { + bytes: v16_to_v8(&to_utf16(self)), + vtype: REG_SZ, + } + } } } } -impl<'a> ToRegValue for &'a str { - fn to_reg_value(&self) -> RegValue { - RegValue{ - bytes: v16_to_v8(&to_utf16(self)), - vtype: REG_SZ +to_reg_value_sz!(String); +to_reg_value_sz!(&'a str, 'a); +to_reg_value_sz!(OsString); +to_reg_value_sz!(&'a OsStr, 'a); + +macro_rules! to_reg_value_multi_sz { + ($t:ty$(, $l:lifetime)*) => { + impl<$($l,)*> ToRegValue for Vec<$t> { + fn to_reg_value(&self) -> RegValue { + let mut os_strings = self + .into_iter() + .map(to_utf16) + .collect::>() + .concat(); + os_strings.push(0); + RegValue { + bytes: v16_to_v8(&os_strings), + vtype: REG_MULTI_SZ, + } + } } } } -impl<'a> ToRegValue for &'a OsStr { - fn to_reg_value(&self) -> RegValue { - RegValue{ - bytes: v16_to_v8(&(self.encode_wide().collect::>())), - vtype: REG_SZ - } - } -} +to_reg_value_multi_sz!(String); +to_reg_value_multi_sz!(&'a str, 'a); +to_reg_value_multi_sz!(OsString); +to_reg_value_multi_sz!(&'a OsStr, 'a); impl ToRegValue for u32 { fn to_reg_value(&self) -> RegValue { - let bytes: Vec = unsafe { - slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() - }; - RegValue{ - bytes: bytes, - vtype: REG_DWORD + let bytes: Vec = + unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() }; + RegValue { + bytes, + vtype: REG_DWORD, } } } impl ToRegValue for u64 { fn to_reg_value(&self) -> RegValue { - let bytes: Vec = unsafe { - slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() - }; - RegValue{ - bytes: bytes, - vtype: REG_QWORD + let bytes: Vec = + unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() }; + RegValue { + bytes, + vtype: REG_QWORD, } } } diff --git a/third_party/rust/winreg/tests/reg_key.rs b/third_party/rust/winreg/tests/reg_key.rs new file mode 100644 index 000000000000..0a7930042441 --- /dev/null +++ b/third_party/rust/winreg/tests/reg_key.rs @@ -0,0 +1,364 @@ +extern crate rand; +extern crate tempfile; +extern crate winapi; +extern crate winreg; +#[cfg(feature = "serialization-serde")] +#[macro_use] +extern crate serde_derive; +use self::rand::Rng; +use std::collections::HashMap; +use std::ffi::{OsStr, OsString}; +use tempfile::tempdir; +use winapi::shared::winerror; +use winreg::enums::*; +use winreg::types::FromRegValue; +use winreg::{RegKey, RegValue}; + +#[test] +fn test_raw_handle() { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let handle = hklm.raw_handle(); + assert_eq!(HKEY_LOCAL_MACHINE, handle); +} + +#[test] +fn test_load_appkey() { + let val_name = "LoadKeyTest"; + let dir = tempdir().unwrap(); + let file_path = dir.path().join("RustLoadAppkeyTest.dat"); + let val1 = "Test123".to_owned(); + { + let key1 = RegKey::load_app_key(&file_path, true).unwrap(); + key1.set_value(val_name, &val1).unwrap(); + // this fails on Windows 7 with ERROR_ALREADY_EXISTS + let key_err = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 0).unwrap_err(); + assert_eq!( + key_err.raw_os_error(), + Some(winerror::ERROR_SHARING_VIOLATION as i32) + ); + } + let val2: String = { + // this fails on Windows 7 with ERROR_ALREADY_EXISTS + let key2 = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 1).unwrap(); + key2.get_value(val_name).unwrap() + }; + assert_eq!(val1, val2); +} + +#[test] +fn test_open_subkey_with_flags_query_info() { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let win = hklm + .open_subkey_with_flags("Software\\Microsoft\\Windows", KEY_READ) + .unwrap(); + + let info = win.query_info().unwrap(); + info.get_last_write_time_system(); + #[cfg(feature = "chrono")] + info.get_last_write_time_chrono(); + + assert!(win + .open_subkey_with_flags("CurrentVersion\\", KEY_READ) + .is_ok()); + assert!(hklm + .open_subkey_with_flags("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ) + .is_err()); +} + +#[test] +fn test_create_subkey_disposition() { + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let path = "Software\\WinRegRsTestCreateSubkey"; + let (_subkey, disp) = hkcu.create_subkey(path).unwrap(); + assert_eq!(disp, REG_CREATED_NEW_KEY); + let (_subkey2, disp2) = hkcu.create_subkey(path).unwrap(); + assert_eq!(disp2, REG_OPENED_EXISTING_KEY); + hkcu.delete_subkey_all(&path).unwrap(); +} + +macro_rules! with_key { + ($k:ident, $path:expr => $b:block) => {{ + let mut path = "Software\\WinRegRsTest".to_owned(); + path.push_str($path); + let ($k, _disp) = RegKey::predef(HKEY_CURRENT_USER) + .create_subkey(&path).unwrap(); + $b + RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey_all(path).unwrap(); + }} +} + +#[test] +fn test_delete_subkey() { + let path = "Software\\WinRegRsTestDeleteSubkey"; + RegKey::predef(HKEY_CURRENT_USER) + .create_subkey(path) + .unwrap(); + assert!(RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey(path) + .is_ok()); +} + +#[test] +fn test_delete_subkey_with_flags() { + let path = "Software\\Classes\\WinRegRsTestDeleteSubkeyWithFlags"; + RegKey::predef(HKEY_CURRENT_USER) + .create_subkey_with_flags(path, KEY_WOW64_32KEY) + .unwrap(); + assert!(RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey_with_flags(path, KEY_WOW64_32KEY) + .is_ok()); +} + +#[test] +fn test_copy_tree() { + with_key!(key, "CopyTree" => { + let (sub_tree, _sub_tree_disp) = key.create_subkey("Src\\Sub\\Tree").unwrap(); + for v in &["one", "two", "three"] { + sub_tree.set_value(v, v).unwrap(); + } + let (dst, _dst_disp) = key.create_subkey("Dst").unwrap(); + assert!(key.copy_tree("Src", &dst).is_ok()); + }); +} + +#[test] +fn test_long_value() { + with_key!(key, "LongValue" => { + let name = "RustLongVal"; + let val1 = RegValue { vtype: REG_BINARY, bytes: (0..6000).map(|_| rand::random::()).collect() }; + key.set_raw_value(name, &val1).unwrap(); + let val2 = key.get_raw_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +macro_rules! test_value_sz { + ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => { + #[test] + fn $fname() { + with_key!(key, $kname => { + let name = "RustSzVal"; + let val1 = $conv("Test123 \n$%^&|+-*/\\()"); + key.set_value(name, &val1).unwrap(); + let val2: $tout = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + } +} + +test_value_sz!(test_string_value, "StringValue", str::to_owned => String); +test_value_sz!(test_str_value, "StrValue", |x|x => String); +test_value_sz!(test_os_string_value, "OsStringValue", OsString::from => OsString); +test_value_sz!(test_os_str_value, "OsStrValue", OsStr::new => OsString); + +#[test] +fn test_long_string_value() { + with_key!(key, "LongStringValue" => { + let name = "RustLongStringVal"; + let val1 : String = rand::thread_rng().gen_ascii_chars().take(7000).collect(); + key.set_value(name, &val1).unwrap(); + let val2: String = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +#[test] +fn test_long_os_string_value() { + with_key!(key, "LongOsStringValue" => { + let name = "RustLongOsStringVal"; + let val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::(); + let val1 = OsStr::new(&val1); + key.set_value(name, &val1).unwrap(); + let val2: OsString = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +macro_rules! test_value_multi_sz { + ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => { + #[test] + fn $fname() { + with_key!(key, $kname => { + let name = "RustMultiSzVal"; + + let val1 = vec![ + $conv("lorem ipsum\ndolor"), + $conv("sit amet") + ]; + key.set_value(name, &val1).unwrap(); + let val2: Vec<$tout> = key.get_value(name).unwrap(); + + assert_eq!(val1, val2); + }); + } + } +} + +test_value_multi_sz!(test_vec_string_value, "StringVectorValue", str::to_owned => String); +test_value_multi_sz!(test_vec_str_value, "StrVectorValue", |x|x => String); +test_value_multi_sz!(test_vec_os_string_value, "OsStringVectorValue", OsString::from => OsString); +test_value_multi_sz!(test_vec_os_str_value, "OsStrVectorValue", OsStr::new => OsString); + +#[test] +fn test_u32_value() { + with_key!(key, "U32Value" => { + let name = "RustU32Val"; + let val1 = 1_234_567_890u32; + key.set_value(name, &val1).unwrap(); + let val2: u32 = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +#[test] +fn test_u64_value() { + with_key!(key, "U64Value" => { + let name = "RustU64Val"; + let val1 = 1_234_567_891_011_121_314u64; + key.set_value(name, &val1).unwrap(); + let val2: u64 = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +#[test] +fn test_delete_value() { + with_key!(key, "DeleteValue" => { + let name = "WinregRsTestVal"; + key.set_value(name, &"Qwerty123").unwrap(); + assert!(key.delete_value(name).is_ok()); + }); +} + +#[test] +fn test_enum_keys() { + with_key!(key, "EnumKeys" => { + let mut keys1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); + keys1.sort_unstable(); + for i in &keys1 { + key.create_subkey(i).unwrap(); + } + let keys2: Vec<_> = key.enum_keys().map(|x| x.unwrap()).collect(); + assert_eq!(keys1, keys2); + }); +} + +#[test] +fn test_enum_values() { + with_key!(key, "EnumValues" => { + let mut vals1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); + vals1.sort_unstable(); + for i in &vals1 { + key.set_value(i,i).unwrap(); + } + let mut vals2: Vec = Vec::with_capacity(vals1.len()); + let mut vals3: Vec = Vec::with_capacity(vals1.len()); + for (name, val) in key.enum_values() + .map(|x| x.unwrap()) + { + vals2.push(name); + vals3.push(String::from_reg_value(&val).unwrap()); + } + assert_eq!(vals1, vals2); + assert_eq!(vals1, vals3); + }); +} + +#[test] +fn test_enum_long_values() { + with_key!(key, "EnumLongValues" => { + let mut vals = HashMap::with_capacity(3); + + for i in &[5500, 9500, 15000] { + let name: String = format!("val{}", i); + let val = RegValue { vtype: REG_BINARY, bytes: (0..*i).map(|_| rand::random::()).collect() }; + vals.insert(name, val); + } + + for (name, val) in key.enum_values() + .map(|x| x.unwrap()) + { + assert_eq!(val.bytes, vals[&name].bytes); + } + }); +} + +#[cfg(feature = "serialization-serde")] +#[test] +fn test_serialization() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Rectangle { + x: u32, + y: u32, + w: u32, + h: u32, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Test { + t_bool: bool, + t_u8: u8, + t_u16: u16, + t_u32: u32, + t_u64: u64, + t_usize: usize, + t_struct: Rectangle, + t_string: String, + t_map: HashMap>, + t_i8: i8, + t_i16: i16, + t_i32: i32, + t_i64: i64, + t_isize: isize, + t_f64: f64, + t_f32: f32, + t_char: char, + } + + let mut k1 = HashMap::new(); + k1.insert("val1".to_owned(), 32); + k1.insert("val2".to_owned(), 64); + k1.insert("val3".to_owned(), 128); + + let mut k2 = HashMap::new(); + k2.insert("val1".to_owned(), 256); + k2.insert("val2".to_owned(), 512); + k2.insert("val3".to_owned(), 1024); + + let mut map = HashMap::new(); + map.insert("key1".to_owned(), k1); + map.insert("key2".to_owned(), k2); + + let v1 = Test { + t_bool: false, + t_u8: 127, + t_u16: 32768, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + x: 55, + y: 77, + w: 500, + h: 300, + }, + t_map: map, + t_string: "Test123 \n$%^&|+-*/\\()".to_owned(), + t_i8: -123, + t_i16: -2049, + t_i32: 20100, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, + t_f64: -0.01, + t_f32: 3.15, + t_char: 'a', + }; + + with_key!(key, "Serialization" => { + key.encode(&v1).unwrap(); + let v2: Test = key.decode().unwrap(); + assert_eq!(v1, v2); + }); +}